{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://archer.local/rig-eval/plan.schema.json",
  "title": "ARCHER run-plan",
  "description": "Declarative run-plan for ARCHER-Live eval sweeps (#1160/#1161). A plan is a matrix of backends x models x objective-sets x ablations x runs that the compiler (#1162) turns into whitelisted testenv/eval_harness.py invocations. The compiler only ever emits parameters enumerated here — this file is the RCE whitelist. Parsed with yaml.safe_load only. NOTE: runtime validation is pure-Python (testenv/plan_schema.py); this file is the canonical documented contract and the source the drift test checks the Python enums against.",
  "type": "object",
  "additionalProperties": false,
  "required": ["plan", "run_sets"],
  "properties": {
    "plan": {
      "type": "string",
      "minLength": 1,
      "description": "Human-readable plan name."
    },
    "run_sets": {
      "type": "array",
      "minItems": 1,
      "description": "One or more run sets; each expands to a backends x models matrix.",
      "items": { "$ref": "#/definitions/run_set" }
    }
  },
  "definitions": {
    "run_set": {
      "type": "object",
      "additionalProperties": false,
      "required": ["name", "backends", "models", "objectives"],
      "properties": {
        "name": { "type": "string", "minLength": 1 },
        "backends": {
          "type": "array",
          "minItems": 1,
          "items": { "enum": ["rig", "rog"] },
          "description": "One backend -> sequential; two -> --parallel only when parallel:true (compiler, #1162)."
        },
        "models": {
          "type": "array",
          "minItems": 1,
          "items": { "type": "string", "minLength": 1 },
          "description": "Ollama model tags, e.g. [qwen3:8b, qwen3:32b]. Matrix axis. QUOTE tags containing a ':' if needed; keep bare 'no'/'yes'-like values quoted (YAML Norway trap)."
        },
        "objectives": {
          "description": "Either an explicit list of objective IDs, or a selector object.",
          "oneOf": [
            {
              "type": "array",
              "minItems": 1,
              "items": { "type": "string", "minLength": 1 }
            },
            { "$ref": "#/definitions/objective_selector" }
          ]
        },
        "runs": { "type": "integer", "minimum": 1, "default": 3 },
        "parallel": {
          "type": "boolean",
          "default": false,
          "description": "Opt-in to the concurrent two-backend path (--parallel --backends a,b). Gated on #1159; default false -> two backends compile to sequential invocations with a warning."
        },
        "ablations": {
          "type": "array",
          "items": { "enum": ["hint-ablation", "phrasing-sensitivity", "decoy-injection", "with-playbook"] },
          "description": "Fixed enum -> harness ablation flags."
        },
        "flags": {
          "type": "array",
          "items": { "enum": ["no-seed-playbook", "no-compare", "clarify", "strict-preflight", "grammar-json"] },
          "description": "Whitelisted passthrough flags only. No free-text flags (RCE guard)."
        },
        "playbook_db": {
          "type": "string",
          "description": "Isolated playbook DB path -> ARCHER_PLAYBOOK_DB env (cf. combined_ablation.sh). Never point at production ~/.archer_playbook.db."
        }
      }
    },
    "objective_selector": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "strategy": { "enum": ["all", "sparse"] },
        "confidence-gate": { "type": "number" },
        "ambiguous": { "type": "boolean" },
        "skip": {
          "type": "array",
          "items": { "type": "string", "minLength": 1 }
        }
      }
    }
  }
}
