{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://raw.githubusercontent.com/BourbonDog/amicus/main/schemas/council-verdict.schema.json",
  "title": "amicus council-verdict document",
  "description": "Verdict record (`council verdict --json`, amicus_verdict, verdict.json). overallVerdict is the chair's parsed VERDICT line — null in every Stage-4 manual path, populated by the headless engine.",
  "type": "object",
  "required": [
    "schemaVersion",
    "type",
    "runId",
    "council",
    "overallVerdict",
    "findings",
    "streetCred",
    "runStats",
    "tierCounts"
  ],
  "properties": {
    "schemaVersion": {
      "const": 2
    },
    "type": {
      "const": "council-verdict"
    },
    "runId": {
      "type": "string"
    },
    "runType": {
      "type": [
        "string",
        "null"
      ]
    },
    "date": {
      "type": [
        "string",
        "null"
      ]
    },
    "chair": {
      "type": [
        "string",
        "null"
      ]
    },
    "council": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "seats": {
      "type": "array",
      "description": "v4.8, optional. The tally record's meta.seats promoted to the top level beside seatLoss — one {id, alias, role, lens, position} entry per BENCH seat in bench order. Present only when the tally record carried one, i.e. only when the bench repeated an alias. It is what makes the `alias#N` ids on findings[].raiserSeat, adjudications[].seat and runStats[].seat resolvable from the verdict ALONE. Bench-only: 'claude' is never a seat, so this must never be joined positionally to `council`. ABSENCE DOES NOT MEAN the bench had no repeated alias — it means no seat table is available; a verdict written before v4.8, or assembled by hand, has none. `items` is deliberately unconstrained: `council report` accepts any array here and falls back to alias space WHOLE unless every element is an object carrying a string `id`, rather than failing to render."
    },
    "claudeInCouncil": {
      "type": "boolean"
    },
    "overallVerdict": {
      "oneOf": [
        {
          "enum": [
            "Ship it",
            "Fix these first",
            "Fundamental rethink"
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "findings": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "tier",
          "decision",
          "applied"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "raiser": {
            "type": [
              "string",
              "null"
            ]
          },
          "severity": {
            "type": [
              "string",
              "null"
            ]
          },
          "tier": {
            "enum": [
              "Confirmed",
              "Contested",
              "Singleton",
              "Disputed"
            ]
          },
          "basis": {
            "type": "object"
          },
          "confidence": {
            "enum": [
              "thin",
              "solid"
            ]
          },
          "tierOverride": {
            "type": [
              "object",
              "null"
            ]
          },
          "duplicateOf": {
            "type": [
              "string",
              "null"
            ]
          },
          "adjudications": {
            "type": "array"
          },
          "raiserSeat": {
            "type": [
              "string",
              "null"
            ],
            "description": "v4.8, optional. The raising SEAT's id (e.g. 'deepseek#1'), carried through from the tally record. Emitted only when it differs from the raiser's alias, so a bench with no repeated alias never carries it; `raiser` stays the alias in every case. Resolve it against the top-level `seats` table. Before v4.8 the verdict named seats it could not resolve — a reader holding only the verdict could not tell which of two same-alias seats raised a finding."
          },
          "sameModelCorroboration": {
            "const": true,
            "description": "v4.8, optional, TRUE ONLY (never emitted as false, so a document without it is byte-identical to a pre-v4.8 one). Carried through from the tally record: after the seat-aware raiser exclusion, at least one AGREEING peer of this finding shares the raiser's alias — corroboration that is real but came from another seat of the same model, so it is not independent. WRONG IN BOTH DIRECTIONS, by construction: the comparison is on the ALIAS only. It MISSES one model reached under two aliases (e.g. --models gpt-5,openai/gpt-5), because votes carry no resolved-executable id. And it FIRES FALSELY on a SPLIT alias — one alias whose two seats resolved to different executables — telling a reader to discount a genuinely independent cross-executable corroboration. The reliability ledger keys identity on (alias, resolvedModel) for the same run, so the two documents can disagree about what 'the same model' means. Treat this as 'worth a second look', never as proof."
          },
          "decision": {
            "type": [
              "string",
              "null"
            ]
          },
          "applied": {
            "type": "boolean"
          },
          "debate": {
            "type": "object",
            "properties": {
              "action": {
                "enum": [
                  "defended",
                  "amended",
                  "withdrawn",
                  "no-response"
                ]
              },
              "previousTier": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "action"
            ],
            "additionalProperties": false
          }
        }
      }
    },
    "streetCred": {
      "type": "array",
      "items": {
        "type": "object"
      }
    },
    "runStats": {
      "type": "array",
      "items": {
        "type": "object"
      }
    },
    "tierCounts": {
      "type": "object"
    },
    "seatLoss": {
      "type": "object",
      "description": "Present only when --critic was requested. Records whether the adversarial seat actually reviewed: a dead critic wave is survivable (the quorum gate guards only the bench), so a run can otherwise reach a full verdict with the critic silently absent.",
      "properties": {
        "criticRequested": {
          "type": "string",
          "description": "The model asked for as critic."
        },
        "criticSeated": {
          "type": "boolean",
          "description": "False when the critic wave died before producing legs."
        },
        "reason": {
          "type": [
            "string",
            "null"
          ],
          "description": "Why the critic wave died, when it did."
        },
        "deadBenchSeats": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Bench models lost to dead waves, excluding the critic."
        }
      },
      "required": [
        "criticRequested",
        "criticSeated"
      ]
    },
    "degrades": {
      "description": "v4.6 Plan 2: what this run lost — copied verbatim from the sink at verdict assembly. Additive; absent on a clean run.",
      "type": "array",
      "items": {
        "type": "object",
        "required": ["kind", "channel", "what", "why", "effect"],
        "properties": {
          "kind": { "enum": ["degrade", "heal"] },
          "channel": { "type": "string" },
          "what": { "type": "string" },
          "why": { "type": "string" },
          "effect": { "type": "string" },
          "remedy": { "type": "string" },
          "data": {
            "type": "object",
            "description": "v4.6 Plan 2: optional structured facts for derivations (e.g. dead-leg {seat,status,reason}, dead-wave {waveId,models,reason}). Prose fields stay the human surface."
          }
        }
      }
    }
  }
}
