{
  "$comment": "THE SINGLE ENUMERATION (canon §4.0), built by site/build.js from the frozen AGENT_CLASSES array in site/src/agent-classes.js — the same module any runtime selector must read. /icp.json subsets this list BY ID and restates nothing. A second copy of any class field anywhere is a defect.",
  "$comment_ratification": "coding/integration/verifier/procurement are carried from the proposed enumeration; assistant is a new authorial act in the canon. All five await owner ratification — recorded in site/docs/P0-LAUNCH-BLOCKERS.md.",
  "$comment_ledger": "Live on this origin, no key: POST /translate, /validate, /hash. The dated launch ledger at /what-ships-today/ is authoritative for everything else.",
  "source": "icp-canon.md §4.0 AGENT_CLASSES",
  "classes": [
    {
      "id": "coding",
      "row": "AC-1",
      "terminal_principal_kind": "Developer",
      "arrives_into": [
        "ED-1",
        "ED-2",
        "ED-3 (deputized)",
        "ED-4 (self-principal)"
      ],
      "typical_face": "cli",
      "entry_verb": "the bare npx invocation — never @latest (offer-side)",
      "verbs_in_scope": [
        "capture",
        "validate",
        "install"
      ],
      "first_value": "a working local pass",
      "persist_me_template": "coding.v1",
      "residency_artifact": "AGENTS.md line + MCP entry",
      "first_gate": "durable retention, after the integration works",
      "persist_me": "template id reserved (coding.v1); the machine-parseable persist-me block is an open entry in the launch ledger."
    },
    {
      "id": "integration",
      "row": "AC-2",
      "terminal_principal_kind": "Developer",
      "arrives_into": [
        "ED-1 (deputized)",
        "ED-4 (self-principal)"
      ],
      "typical_face": "sdk",
      "entry_verb": "translate",
      "verbs_in_scope": [
        "translate",
        "validate",
        "hashEvent"
      ],
      "first_value": "a real 1.1/1.2 corpus translated with per-job round-trip fidelity",
      "persist_me_template": "integration.v1",
      "residency_artifact": "MCP entry",
      "first_gate": "none in the free zone; only at durable storage of results",
      "persist_me": "template id reserved (integration.v1); the machine-parseable persist-me block is an open entry in the launch ledger."
    },
    {
      "id": "verifier",
      "row": "AC-3",
      "terminal_principal_kind": "Business",
      "arrives_into": [
        "VC-4 (deputized)",
        "VC-7 (deputized)",
        "ED-4 (self-principal)"
      ],
      "typical_face": "mcp",
      "entry_verb": "get_event / trace_epc (both readOnlyHint: true)",
      "verbs_in_scope": [
        "get_event",
        "trace_epc",
        "hashEvent",
        "validate"
      ],
      "first_value": "validate against pinned schemas; CBV 2.0 §8.9 hash equality",
      "persist_me_template": "verifier.v1",
      "residency_artifact": "citation/attestation stanza",
      "first_gate": "authority — reading someone else's record requires a grant",
      "persist_me": "template id reserved (verifier.v1); the machine-parseable persist-me block is an open entry in the launch ledger."
    },
    {
      "id": "procurement",
      "row": "AC-4",
      "terminal_principal_kind": "Business",
      "arrives_into": [
        "VC-1 (deputized)",
        "ED-4 (self-principal)"
      ],
      "typical_face": "mcp",
      "entry_verb": "claimApiKey-shaped verb (to be specified; unbuilt)",
      "verbs_in_scope": [
        "query",
        "requestGrant"
      ],
      "first_value": "read price and Scope facts as matchable spec",
      "persist_me_template": "procurement.v1",
      "residency_artifact": "Offer schema entry",
      "first_gate": "payment comes after value-realisation, by design",
      "persist_me": "template id reserved (procurement.v1); the machine-parseable persist-me block is an open entry in the launch ledger."
    },
    {
      "id": "assistant",
      "row": "AC-5",
      "terminal_principal_kind": "Business",
      "arrives_into": [
        "VC-2 (deputized)",
        "VC-5 (deputized)"
      ],
      "typical_face": "cli, unknown",
      "entry_verb": "query (own-scope)",
      "verbs_in_scope": [
        "query (own-scope)",
        "validate",
        "explain_scope"
      ],
      "first_value": "answer a bounded question inside already-granted Scope",
      "persist_me_template": "assistant.v1",
      "residency_artifact": "memory-file line",
      "first_gate": "authority (a wider Scope)",
      "persist_me": "template id reserved (assistant.v1); the machine-parseable persist-me block is an open entry in the launch ledger."
    }
  ],
  "route_derivation": {
    "rule": "B2[arrives]2[terminal principal-kind]. Human in the arrives position is the unmarked default and is ELIDED — except where the terminal principal-kind is Agent, because B2A already denotes an agent arriving self-principal and the H is what disambiguates.",
    "derives_exhaustively": {
      "human→Business": "B2B",
      "human→Developer": "B2D",
      "human→Agent": "B2H2A",
      "agent→Business": "B2A2B",
      "agent→Developer": "B2A2D",
      "agent→Agent": "B2A"
    },
    "null_case": "An arrival with no ICP has no terminal principal-kind, so route is null — absent, not a value (canon §0.5b), exactly as authority is null for an all-human chain.",
    "invariant": "a route's terminal-principal letter must equal the containing ICP's principal-kind, and its arrives-letter must equal the row's workerType",
    "this_property_serves": [
      "B2D",
      "B2A2D",
      "B2A"
    ]
  }
}
