{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://ecc.tools/schemas/capsule-envelope.schema.json",
  "title": "Capsule Envelope v1",
  "description": "One append-only journal entry recorded by the ECC eval-harness capsule. Mirrors scripts/lib/eval-harness/envelope.js, which is the enforcing implementation.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "schema",
    "run_id",
    "capsule_id",
    "seq",
    "ts",
    "lineage",
    "kind",
    "effect_class",
    "harness_version",
    "task_family",
    "parent_hash",
    "entry_hash",
    "payload"
  ],
  "properties": {
    "schema": { "const": "capsule-envelope/v1" },
    "run_id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" },
    "capsule_id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" },
    "seq": { "type": "integer", "minimum": 0, "description": "Zero-based position in the journal. Must equal the line index." },
    "ts": { "type": "string", "format": "date-time" },
    "lineage": { "type": "string", "enum": ["plan", "attempt", "interaction", "environment", "strategy"] },
    "kind": { "type": "string", "pattern": "^[a-z][a-z0-9_.-]{0,63}$" },
    "effect_class": {
      "type": "string",
      "enum": ["SE0", "SE1", "SE2", "SE3", "SE4"],
      "description": "SE0 read-only; SE1 reversible local write in the capsule root; SE2 sandboxed mutation, no live network writes; SE3 append-only remote evidence; SE4 economic or external effect."
    },
    "harness_version": { "type": "string", "minLength": 1 },
    "task_family": { "type": "string", "minLength": 1 },
    "parent_hash": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "entry_hash of the previous entry, or 64 zeros for the first entry." },
    "entry_hash": { "type": "string", "pattern": "^[0-9a-f]{64}$", "description": "sha256 of the canonical JSON of this entry with entry_hash removed." },
    "payload": {
      "type": "object",
      "description": "Default-deny allowlisted properties only. No secrets, credentials, or raw reasoning text.",
      "additionalProperties": false,
      "properties": {
        "task_id": { "type": "string" },
        "task_family": { "type": "string" },
        "tool": { "type": "string" },
        "tool_call_id": { "type": "string" },
        "args_hash": { "type": "string" },
        "response_hash": { "type": "string" },
        "status": { "type": "string" },
        "exit_code": { "type": ["integer", "null"] },
        "duration_ms": { "type": "number" },
        "tokens_in": { "type": "integer" },
        "tokens_out": { "type": "integer" },
        "cost_usd": { "type": "number" },
        "model": { "type": "string" },
        "message": { "type": "string" },
        "note": { "type": "string" },
        "decision": { "type": "string" },
        "reason": { "type": "string" },
        "score": { "type": "number" },
        "passed": { "type": "integer" },
        "failed": { "type": "integer" },
        "total": { "type": "integer" },
        "variant": { "type": "string" },
        "digest": { "type": "string" },
        "path": { "type": "string" },
        "fixture_key": { "type": "string" },
        "stage": { "type": "string" },
        "verdict": { "type": "string" },
        "hits": { "type": "integer" },
        "branch_id": { "type": "string" },
        "parent_branch_id": { "type": "string" },
        "summary": { "type": "string" }
      }
    }
  }
}
