{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://github.com/mmerterden/multi-agent-pipeline/pipeline/schemas/plan-critique.schema.json",
  "title": "Multi-Agent Pipeline  -  plan critique (one round)",
  "description": "The plan critic's objections to a Phase 1 plan and the planner's one reply to each, in one file: <worktree>/.pipeline/plan-critique.json (multi-agent-refs/features/plan-critic.md). The plan-critic persona writes version, round and objections[]; the planner adds replies[]. plan-critique-gate.mjs checks this shape without a dependency, resolves every anchor, and judges by constitution rule id. There is exactly one round: round is always 1, each objection gets exactly one reply, and a critique the gate has already judged for the run cannot be replaced. An anchor is file (ref `path:line`, optional quote, resolved like verify-citations.mjs in the working tree), plan (ref a task id of the plan), analysis (ref a requirement id the analysis defines, or text of one of its headings) or inference (ref the one-line reasoning, never checkable). An objection none of whose anchors resolves is labelled inference.",
  "type": "object",
  "additionalProperties": false,
  "required": ["version", "round", "objections", "replies"],
  "$defs": {
    "anchor": {
      "type": "object",
      "additionalProperties": false,
      "required": ["kind", "ref"],
      "properties": {
        "kind": { "enum": ["file", "plan", "analysis", "inference"] },
        "ref": { "type": "string", "minLength": 1 },
        "quote": {
          "type": "string",
          "minLength": 1,
          "description": "file anchors only: text that must appear on the cited line, whitespace collapsed."
        }
      }
    }
  },
  "properties": {
    "version": { "type": "integer", "const": 1 },
    "round": {
      "type": "integer",
      "const": 1,
      "description": "Always 1. A second critique round is refused, not scored."
    },
    "critic": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "persona": { "type": "string", "minLength": 1 },
        "rung": { "type": "string", "minLength": 1 }
      },
      "description": "Who wrote the objections: the persona and the model rung model-dispatch.sh returned."
    },
    "objections": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "lens", "claim", "evidence"],
        "properties": {
          "id": { "type": "string", "pattern": "^OBJ-[0-9]{2,3}$" },
          "lens": {
            "enum": ["scope", "feasibility", "security", "alternative"],
            "description": "scope: the plan does more or less than the analysis asks. feasibility: a step cannot work as planned. security: a step opens a hole. alternative: a cheaper plan reaches the same result."
          },
          "claim": {
            "type": "string",
            "minLength": 1,
            "description": "Why the plan will fail, in one or two sentences."
          },
          "rule": {
            "type": "string",
            "pattern": "^CON-(SEC|A11Y|ARCH|LIC)-[0-9]{2,3}$",
            "description": "The constitution rule the plan breaks, when there is one. Only an objection citing a binding rule can block."
          },
          "evidence": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/anchor" } }
        }
      }
    },
    "replies": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["objection", "action"],
        "properties": {
          "objection": { "type": "string", "pattern": "^OBJ-[0-9]{2,3}$" },
          "action": {
            "enum": ["accept", "rebut"],
            "description": "accept: the plan was revised; revision says how and a plan anchor names the task. rebut: the objection does not hold, shown by evidence."
          },
          "revision": { "type": "string", "minLength": 1 },
          "note": { "type": "string" },
          "evidence": { "type": "array", "items": { "$ref": "#/$defs/anchor" } }
        },
        "allOf": [
          {
            "if": { "properties": { "action": { "const": "accept" } } },
            "then": { "required": ["revision"] }
          },
          {
            "if": { "properties": { "action": { "const": "rebut" } } },
            "then": {
              "required": ["evidence"],
              "properties": { "evidence": { "minItems": 1 } }
            }
          }
        ]
      }
    }
  }
}
