Skip to content

Commit 76828f0

Browse files
committed
docs: M4 revised — approval stays inline (owner decision B); M4 = budget gate only
Owner chose option B: the approval gate's enforcement stays inline because it is runtime-stateful (live JIT/session state, tool handler, auto-mode-swappable policy) and a poor fit for the pure-interceptor model — the three coupling gaps found were each invisible to a unit parity test. Approval observability is already covered by M2 (approval audit events typed + reader-surfaced; M6 fold reads them), so no new emit is needed. The approval Slice A interceptor + tests were reverted as now-unused (commit 6907253). PlanGateError retained (benign, cleaner plan-block messaging). M4 redefined to budget gate only. Constraint: docs only; records owner decision B; plan gate remains the one gate moved to an interceptor; approval enforcement unchanged from its proven inline path Tested: lifecycle 30 (post-revert), mypy clean (runner), docs validator 0 errors Confidence: high Roadmap-Status: unchanged
1 parent 6907253 commit 76828f0

3 files changed

Lines changed: 31 additions & 4 deletions

File tree

docs/generated/docs-inventory.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ Do not edit this file manually — regenerate instead.
414414
| `ops/security-hardening.md` | working | 11733 | `0a385c7dab82` |
415415
| `ops/troubleshooting.md` | working | 9127 | `4921b6d50f5c` |
416416
| `permission-and-approval-playbook.md` | working | 6560 | `813bc74bb156` |
417-
| `plans/adr-0032-m1-m6-work-plan-2026-06-13.md` | archive | 49129 | `c1afb6a5bde8` |
417+
| `plans/adr-0032-m1-m6-work-plan-2026-06-13.md` | archive | 49574 | `fd53521a53fa` |
418418
| `plans/agent-ecosystem-acceptance-roadmap-2026-05-31.md` | archive | 29099 | `7c4a4972cfeb` |
419419
| `plans/community-pain-points-response-plan-2026-06-05.md` | archive | 7276 | `571d010133ad` |
420420
| `plans/competitive-positioning-plan-2026-05-31.md` | archive | 8726 | `d16dfd2bdd99` |
@@ -589,7 +589,7 @@ Do not edit this file manually — regenerate instead.
589589
| `ux-stability-contract.md` | working | 2238 | `1c5511e10ede` |
590590
| `wasm-skill-ci.md` | working | 974 | `8340d6f1e5c1` |
591591
| `work-log/documentation-optimization-work-items-2026-06-04.md` | archive | 11750 | `9233b40b0bce` |
592-
| `work-log/m4-approval-sliceB-blocked-2026-06-13.md` | archive | 6038 | `a69b3abac821` |
592+
| `work-log/m4-approval-sliceB-blocked-2026-06-13.md` | archive | 7347 | `3981ed82bc08` |
593593
| `work-log/operator-friction-log.md` | working | 2560 | `fe79899db10f` |
594594
| `work-log/p0-p1-governance-implementation-ledger-2026-06-11.md` | archive | 5212 | `0b72cd69de32` |
595595
| `work-log/parallel-phase-0-implementation-report-2026-06-04.md` | archive | 13181 | `098186167459` |

docs/plans/adr-0032-m1-m6-work-plan-2026-06-13.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ M0 accepted ADR + dual-write spine [done]
9494
git-sandbox, skills, tests, undo, provenance, approval/tool-call
9595
decision events, cancelled/pending lifecycle
9696
-> M3 plan gate interceptor (parity-first)
97-
-> M4 approval gate then budget gate (parity-first)
97+
-> M4 budget gate only (parity-first); approval STAYS INLINE
98+
(owner decision B, 2026-06-13 — approval is runtime-stateful;
99+
see m4-approval-sliceB-blocked report)
98100
-> M5 HookRegistry on spine
99101
-> M6 evidence + receipt FOLD (was M2; corrected
100102
scope A) — now genuinely event-typed because M2 completed
@@ -162,7 +164,7 @@ consumers by M6.
162164
| ADR-0032-M1 | AuditLogger can consume RunEvents and produce byte-equivalent JSONL for golden proof runs; legacy call sites delegate instead of directly owning serialization decisions. |
163165
| ADR-0032-M2 (REDEFINED, taxonomy-only §16) | Every audit event the evidence bundle reads is typed in `RunEventType` and mapped both directions, so the M2-T001 reader surfaces it **from the audit JSONL** (mapper is sufficient; emit-site migration is NOT in M2 — it is deferred to the component milestones, §16). Covers routes, git-sandbox, skills, tests, undo, provenance, approval/tool-call decision events, cancelled/pending lifecycle. Pure additive; zero behavior change. (Old M2 "evidence/receipt fold" moved to M6 — §14.) |
164166
| ADR-0032-M3 | Plan gate is an interceptor using `PlanValidator`, landed parity-first (§13.3): a shadow-parity test asserting interceptor==inline per reason code went green before the inline branch was deleted in a separate commit. Denials and reason codes match current behavior; adversarial and first-hour tests remain green. |
165-
| ADR-0032-M4 | Approval gate then budget gate are interceptors, each landed parity-first in two commits (shadow parity green → enforce+delete); budget done last and alone. `pending_approval`, resume, scoped approvals, budget warnings, and budget-exhausted behavior remain unchanged. Decision events keep the contract typed in M2. |
167+
| ADR-0032-M4 (REVISED — owner decision B, 2026-06-13) | Budget gate ONLY moves to an interceptor, parity-first in two commits (shadow parity green → enforce+delete), done alone. **Approval enforcement STAYS INLINE** — it is runtime-stateful (live JIT/session state, tool handler, auto-mode-swappable policy), a poor fit for the pure-interceptor model (every coupling gap was invisible to a unit parity test; see `docs/work-log/m4-approval-sliceB-blocked-2026-06-13.md`). Approval observability is already provided by M2 (approval audit events are typed + reader-surfaced); the M6 fold reads them. Budget warnings/exhausted behavior unchanged. |
166168
| ADR-0032-M5 | HookRegistry subscribes through the spine; Claude-Code-compatible hook names remain aliases; public hook API docs and tests pass. |
167169
| ADR-0032-M6 (was M2 fold; corrected scope A) | Evidence and receipts are folded from the typed event stream and equal the legacy builder on success/failure/pending fixtures (cancelled once emitted in M2); the fold reads the full stream (no fallback flag, per Q1); synthetic receipt-only fixtures are retired or relabeled legacy. Runs only after M2 coverage + M3/M4 decision events exist. |
168170
| ADR-0032-M7 (was M6) | ContextBus and webhook sinks consume the spine; inline emission paths are deleted; validator shows no orphaned eventing modules. |

docs/work-log/m4-approval-sliceB-blocked-2026-06-13.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,28 @@ this decision.
116116
`bcd9369` is HEAD-ish for this thread: PlanGateError (`5b5f007`) + approval
117117
Slice A (`2da5d6c`, interceptor + unit parity, NOT wired) + this report. No
118118
enforce cutover landed. Working tree clean.
119+
120+
---
121+
122+
## RESOLVED — Owner chose (B), 2026-06-13
123+
124+
The owner chose **option (B): approval enforcement stays inline.** The approval
125+
gate is legitimately runtime-stateful (live JIT/session state, tool handler,
126+
auto-mode-swappable policy) and is NOT moved to an EventSpine interceptor.
127+
128+
Actions taken:
129+
- Reverted approval Slice A (`2da5d6c`) — the `ApprovalGateInterceptor` and its
130+
unit/parity tests — via revert commit, since under (B) it is unused code and
131+
unused code is drift. Approval enforcement is back to its proven inline path,
132+
unchanged.
133+
- **Approval observability needs no new code:** the approval audit events
134+
(`tool_call_approved`, `tool_call_denied`, `tool_call_pending_approval`,
135+
`approval_*`) were already typed in M2-T002 and are surfaced by the M2-T001
136+
reader from the audit JSONL. So the spine carries approval *observability*
137+
(for evidence/receipts via the M6 fold) without moving enforcement.
138+
- `PlanGateError` (`5b5f007`) is retained: harmless under (B) and a small
139+
improvement (plan blocks no longer show the misleading "approve this" hint).
140+
Its original approval-coexistence justification no longer applies.
141+
142+
**Net M4 redefinition:** M4 = budget gate only. The plan gate (M3) is the one
143+
governance gate that moved to an interceptor; approval stays inline by design.

0 commit comments

Comments
 (0)