{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://getzero.dev/contracts/zero.genesis.evidence.v1.schema.json",
  "title": "Genesis Evidence Bundle v1",
  "description": "Machine-readable proof of one Genesis self-mutation cycle. Built by zero.genesis.evidence.build_bundle() by folding a stream of journal events sharing the same cycle_id. Lets an Admin UI / MCP tool / public proof surface render the cycle without parsing raw JSONL.",
  "type": "object",
  "required": [
    "schema",
    "built_at",
    "cycle_id",
    "first_event_at",
    "last_event_at",
    "event_count",
    "schema_violations",
    "stages",
    "status",
    "terminal"
  ],
  "properties": {
    "schema": {
      "type": "string",
      "const": "zero.genesis.evidence.v1"
    },
    "built_at": {
      "type": "string",
      "format": "date-time",
      "description": "When the bundle was assembled (not when the cycle ran)."
    },
    "cycle_id": {
      "type": "string",
      "description": "Genesis cycle identifier (e.g. gen_cycle_20260416_0200). Empty string when the input events disagreed on cycle_id."
    },
    "proposal_id": {
      "type": "string",
      "description": "The proposal this cycle considered. Empty when no proposal stage fired."
    },
    "first_event_at": {
      "type": ["string", "null"],
      "format": "date-time",
      "description": "Earliest journal event timestamp in this cycle."
    },
    "last_event_at": {
      "type": ["string", "null"],
      "format": "date-time",
      "description": "Latest journal event timestamp in this cycle."
    },
    "event_count": {
      "type": "integer",
      "minimum": 0,
      "description": "Number of valid events folded into this bundle."
    },
    "schema_violations": {
      "type": "integer",
      "minimum": 0,
      "description": "Number of input entries that were skipped because they didn't match the journal event schema (missing 'event' key, unknown event type, not a dict)."
    },
    "stages": {
      "type": "object",
      "description": "Per-stage record. Each maps to a Genesis pipeline stage. 'present: false' means no event of that type was observed in this cycle.",
      "required": ["init", "proposal", "guardian", "build", "red_team", "canary", "calibration", "promote", "rollback", "complete", "error"],
      "$defs": {
        "stageRecord": {
          "type": "object",
          "required": ["present", "ts", "data"],
          "properties": {
            "present": {"type": "boolean"},
            "ts": {"type": ["string", "null"], "format": "date-time"},
            "data": {
              "type": "object",
              "description": "Stage-specific payload from the journal event. Schemas of these payloads are defined by their producers (strategist.py, guardian_gate.py, builder.py, etc.)."
            }
          }
        }
      },
      "additionalProperties": {"$ref": "#/properties/stages/$defs/stageRecord"},
      "properties": {
        "init": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "cycle_start event"},
        "proposal": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "Strategist proposal"},
        "guardian": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "Guardian-gate verdict (APPROVE | REJECT | ESCALATE)"},
        "build": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "Builder result (worktree, branch, commit)"},
        "red_team": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "Red-team verdict (PASS | BLOCK | WARNING | ERROR)"},
        "canary": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "Canary lifecycle state"},
        "calibration": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "Calibration verdict (PROMOTE | HOLD | ROLLBACK | INSUFFICIENT)"},
        "promote": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "Local main merge result"},
        "rollback": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "Rollback action"},
        "complete": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "cycle_complete event"},
        "error": {"$ref": "#/properties/stages/$defs/stageRecord", "description": "error event — surfaced as overall status=errored"}
      }
    },
    "status": {
      "type": "string",
      "enum": [
        "empty",
        "errored",
        "rolled_back",
        "promoted",
        "in_progress:init",
        "in_progress:proposal",
        "in_progress:guardian",
        "in_progress:build",
        "in_progress:red_team",
        "in_progress:canary",
        "in_progress:calibration"
      ],
      "description": "Overall cycle status. Severity order (most → least severe): errored, rolled_back, promoted, in_progress:<stage>, empty. UI / MCP can color-code from this single field."
    },
    "terminal": {
      "type": "boolean",
      "description": "True when status is one of {promoted, rolled_back, errored, complete}. In-progress cycles are not terminal."
    }
  }
}
