Blake adopts the runtime rails — auto + interactive

Blake (the Document Registrar) accepts the runtime-control axes off agent_invoke.v1, declares a both-modes mode matrix, routes run_mode, and participates in Auto-batch run-control. Rails plumbing + mode matrix only — no tools, no new architecture.
Story-1563 · EPIC-1559 / EPIC-1536 · adopter (updates Blake = agents/registrar/) · branch issue-1563-blake-adopt-rails · 2026-06-21

pramaan-docs ADR-129 ratified three orthogonal axes — run_mode, thinking_level, authority_mode — plus authorized_scope and capabilities[], and named Blake the first adopter that proves the rails (§D12). The contracts landed in Story-1561; the broker-resident resolvers, floors, and effective_* computation landed in Story-1562; Atlas adopted thinly in Story-1564. This Story makes Blake consume that posture and join the rails — so the later capabilities (#1538 classify, #1539 govern) run inside it. Blake owns no resolver and no floor; every mutation stays broker-mediated (ADR-128). It mirrors the Atlas adoption shape, with two additions Blake needs that Atlas does not: both run-modes and run-control participation.

What to review

AreaWhereWhat it does
Axis readeragents/registrar/runtime_axes.pyClosed StrEnums mirroring the contract VERBATIM + parse_posture() — reads the broker-resolved axes off the envelope, defaults authority_mode to review_exceptions, carries authorized_scope opaque, fails closed on an illegal value. No resolver, no floor.
Mode matrixagents/registrar/registrar.yaml mode_matrix:Blake's self-declared envelope: supported_modes:[auto, interactive], default_mode:auto, per-mode default_thinking, pause_stop (auto=pause_resume_stop, interactive=stop_cancel_turn), and declared floors (privilege/vocabulary at High+). Broker copy authoritative; parity test keeps them locked.
Thinking → tier mapagents/registrar/model.json thinking_tiersMaps low/medium→quick, high/extra_high→advisory onto Blake's existing tiers — no new tier system. The seam where the floored High+ steps land on a stronger model later.
Per-invoke resolutionagents/registrar/config.py RegistrarConfig.for_invoke()Reads the posture, points model_id at the level's tier, carries run_mode/thinking_level/authority_mode/authorized_scope + the matrix accessors (supports_mode, pause_stop_for, floored_steps). REGISTRAR_MODEL_ID override still wins.
run_mode routing + run-controlagents/registrar/runtime.pyhandle_request resolves run_mode (auto batch vs interactive turn — skeleton), stamps the posture + the auto→interactive transition link onto the wire, and short-circuits a {"control": pause/resume/stop} signal to the matching lifecycle event (pause/resume Auto-only, fail-closed in interactive).
Run-control eventsagents/registrar/events.pyrun_paused/resumed/stopped_event builders — byte-identical to the canonical agent_contracts shapes (self-contained CodeZip can't import the sibling package yet).
Teststests/test_registrar_runtime_axes.py, test_registrar_mode_matrix.py, test_registrar_run_control.pyAxis parity + fail-closed + content fence; both-modes matrix + floors; run-control emission, auto/interactive routing, pause/resume-rejected-in-interactive, transition link.

The thin seam — same shape as Atlas, plus two Blake-only joins

# Broker (Story-1562) resolves + floors the level, then invokes Blake:
agent_invoke.v1 { …, run_mode:"auto", thinking_level:"high", authority_mode:"review_exceptions" }

# Blake (this Story) READS it — and only SELECTS its own tier. No resolver, no floor.
config   = RegistrarConfig.for_invoke(request)          # high → advisory tier → DeepSeek
run_mode = _resolve_run_mode(config, request)           # auto vs interactive entry path

# JOIN 1 — run-control participation (Auto-batch only; ADR-129 §D6):
if request.get("control"):                          # pause | resume | stop
    yield events.run_paused_event(run_id, batch_id=…, posture=pinned)
    return                                              # pause/resume rejected in interactive

# JOIN 2 — auto→interactive transition link (ADR-129 §D1):
stamp += { run_mode, thinking_level, authority_mode,
           batch_id, linked_run_id }                    # "rerun these N at Extra-High" → original run + ledger
# authority_mode is carried, NEVER branched on — Blake proposes; the broker mutates (ADR-128).
Why Blake owns no resolver or floor: ADR-129 §D2/§D3 put the level→model map, the safety floors, and effective_authority in one place — the broker rails — so a cost-cutting matter default can't silently de-floor privilege detection or vocabulary creation for any agent. Blake's mode_matrix.floored_steps only declares those steps (privilege/vocabulary at High+) so the broker enforces effective_level = max(default, floor) and audit can prove the floor fired — Blake never floors a step itself.
Why pause/resume is Auto-only: run-control is durable execution over the existing document_status_events checkpoint stream (§D6) — a long-running batch concept. An interactive chat turn has nothing to pause; it gets stop/cancel-turn. Blake's brain only reports the lifecycle on its event stream; the broker drives the checkpoints, idempotency, and undo-batch. A pause/resume in interactive is a malformed invoke and fails closed before any frame.
Why the default invoke is byte-identical: an omitted thinking_level falls back to the matrix default medium → the quick tier → deepseek/deepseek-v3.2, exactly what the Blake scaffold ran before Story-1563. A legacy invoke that sends no axes parses unchanged and runs the same model. Behaviour unchanged at default settings, by test.

How to verify

# Blake's own unit suite (the adopter)
cd agents/registrar && python -m pytest tests -q              # 92 passed

# lint + brain-purity egress gate stay clean (no DB/ORM/boto leak in the brain)
ruff check agents/
python scripts/check_brain_egress.py                         # clean

# repo-governance lane unchanged
ruff check agent_contracts/ tests/ scripts/
python -m pytest tests/ -q -m unit                           # 101 passed

Scope & boundaries honoured