Runtime-capability contract extensions

The shared agent_invoke.v1 / agent_event_stream.v1 contracts gain the three runtime-control axes + the run-control events. One central shape; Blake and Atlas both consume it.
Story-1561 · EPIC-1559 · Track-B Wave-1 keystone · branch issue-1561-extend-agent-contracts · 2026-06-21

pramaan-docs ADR-129 ratified three orthogonal runtime-control axes — who triggers (run_mode), how hard it thinks (thinking_level), how much it may do before asking (authority_mode) — plus run-control (pause/resume/stop) and capabilities. This Story does exactly one thing: extend the two frozen wire contracts (ADR-129 §D5) to carry them, centrally, with no per-agent dialect. No resolvers, no floors — that is the broker rails work (pramaan-spec#1562). This is the shape every agent stands on.

What to review

AreaWhereWhat it does
The axes (closed enums)agent_contracts/enums.pyRunMode, ThinkingLevel (low·medium·high·extra_high), AuthorityMode (default review_exceptions), AuthorizedScopeKind. Closed StrEnums — an illegal value fails at the boundary.
Invoke envelopeagent_contracts/agent_invoke.pyAgentInvokeV1 gains run_mode·thinking_level·authority_mode·authorized_scope·capabilities[]. All optional + back-compat-safe; authorized requires authorized_scope (§D4).
Event languageagent_contracts/agent_event_stream.pyThe closed event-type set gains run.paused·run.resumed·run.stopped; RunPosture carries the pinned effective_level (§D7) — never effective_tier.
Boundary validatorsagent_contracts/validation.pyparse_agent_invoke / parse_agent_event — parse-against-schema before trust (ADR-061).
Schema custodyagent_contracts/schema.py + schemas/*.jsonJSON Schema generated from the Pydantic source, checked in, drift-gated (ADR-074 custody pattern).
Teststests/test_agent_*_contract.py, test_contract_schema_custody.pyEnum validity, default resolution, new events serialize/parse, schema-drift gate, Atlas-golden parity.

The extension (ADR-129 §D5)

// agent_invoke.v1 — gains the three CALLER-SET axes (content can never move them, §D9)
{ schema:"agent_invoke.v1", mode, meta:{run_id,firm_id,…}, input:{…},
  run_mode:        "auto" | "interactive" | null,        // null ⇒ agent matrix decides
  thinking_level:  "low|medium|high|extra_high" | null,   // null ⇒ matter/firm default
  authority_mode:  "review_exceptions" (default) | …,   // browser REQUESTS; broker resolves
  authorized_scope:{scope, expires_at?} | null,         // REQUIRED iff authorized (§D4)
  capabilities:    string[] }                             // pre-registered "+" menu (§D10)

// agent_event_stream.v1 — gains the Auto-batch run-control lifecycle (§D6)
run.paused   { batch_id, reason?, posture:{effective_level,…}, checkpoint_seq? }
run.resumed  { batch_id, posture, resumed_from_seq? }   // pinned posture, not re-governed (§D7)
run.stopped  { batch_id, reason?, undo_batch_available? }    // stop ≠ rollback (§D6)
Why central, not per-agent: ADR-110 froze ONE invoke contract and ONE event language for every agent. If Blake and Atlas each grew their own run_mode JSON, the broker's one safety control-plane would have to speak N dialects — exactly the drift ADR-110 forbids. So the shape lives once, in agent_contracts/, and the custody test parses Atlas's real golden event stream through this validator to prove it accepts the shipped output unchanged. No dialect, by test.
Why authorized needs a scope: ADR-129 §D4 deliberately rejects the coding-agent "Full access" model. "Do it" means this job — so authority_mode: "authorized" without an authorized_scope (scope + expiry) is a validation error, not a silent blank cheque. The contract enforces the bound; it cannot be forgotten.

How to verify

# lint + the full contract suite (governance lane)
ruff check agent_contracts/ tests/ scripts/
python -m pytest tests/ -q -m unit            # contract tests green

# brain-purity egress gate stays clean (no DB/ORM/boto leak)
python scripts/check_brain_egress.py

# regenerate the JSON Schema artifacts under custody (drift-gated)
python -m agent_contracts.schema

Scope & boundaries honoured