KB-7B3F
02 — Reusable Runner Safety Patterns (Runner Safety Contract)
3 min read Revision 1
dot-agent-apirunner-patternssafety-contract2026-06-04
02 — Reusable Runner Safety Patterns → Runner Safety Contract
Extracted from the three verified runners already in production (see prior macro doc 02). The agent_api dispatcher reuses these proven patterns rather than inventing a new ad-hoc script.
Source runners and what each contributes
| Runner | Layer | Reusable pattern |
|---|---|---|
iu-cutter-v0.6 + o7_live_dryrun_runner.py (job:cut) |
host Python | Mode.DRYRUN enum; __execution_enabled__ is False kill-switch asserted-never-assigned; RO DB role; Mode.LIVE → ProductionExecutionNotAuthorized; in-memory simulator; 366/366 regression baseline |
dot_iu_command_run |
IU-command DB | plan/apply/verify run_mode; mutating flag; gate_snapshot; gate refusals fire; idempotency via params_digest |
dot-hc-executor |
host bash | --dry-run/--only-check/--self-test; dispatch by executor_type (no per-code switch); RO-SQL-only token denylist; lockfile + heartbeat |
Standard Runner Safety Contract (the 9 rules)
- Mode enum — explicit {PLAN_ONLY, VERIFY_ONLY, DRY_RUN, (REAL_RUN gated off)}.
- Kill-switch — runtime toggle re-read every call; refuse unless dry-run-only.
- Dry-run isolation — output only to a fixture/test namespace (
DRYRUN-NS:). - Read-only guard — no mutation of business tables; observation tables only.
- Idempotency — stable idempotency key; re-call returns same id, inserts 0 rows.
- Output namespace — enforced prefix; production namespaces refused.
- Fail-closed — every missing precondition raises; no silent pass.
- Preflight guard — contract + fixture + DOT-existence checked before any write.
- Observation/log write — record via the existing fail-closed observe functions.
What is reusable for agent_api vs not
- Reusable: all 9 rules above; the
dot-hc-executor"dispatch by type, not by code" generality;dot_iu_command_runplan/verify/gate-snapshot grain; the kill-switch + RO posture. - Not reusable: the execution body. iu-cutter executes a real (simulated) cut; dot-hc-executor runs real RO SQL. The agent_api layer has no invocation body at all (no endpoint), so the dispatcher can only validate + prepare — it cannot supply the missing execution.
Conclusion
fn_process_agent_api_dispatch implements rules 1–9 server-side (a CLI cannot bypass them). The single gap the contract layer cannot close itself is rule-0: a real no-mutation invocation entrypoint. That is the endpoint blocker.