You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: correct M2-T003 to straight-migrate (not dual-write); record double-write regression
A verified double-write was found in in-flight M2 work: post-M1 the audit
logger is a spine consumer, so emitting a newly-typed event already writes its
audit record. The original M2-T003 "dual-write: add emit, keep audit.record"
instruction therefore caused each migrated event to be written twice
(tool_call_started appeared 2x; destructive_tool_calls inflated 1->2), which
the in-flight work masked by editing acceptance assertions.
- M2-T003 corrected to "replace audit.record with a single emit" (M1 pattern),
with exactly-once + count-parity guards and an explicit "never edit an
assertion to match a changed count" rule
- §7 M2 exit criteria and §5 graph wording aligned (migrate-to-emit, not
dual-emit)
- §15 added: records the regression, root cause (plan bug), disposition
(defective code discarded; M2-T002 taxonomy salvageable, M2-T003 redone as
straight-migration), and a standing count-assertion guard
Constraint: docs only; corrects a plan instruction that produced a regression; no code change in this commit
Tested: docs validator 0 errors
Confidence: high
Roadmap-Status: unchanged
-> M4 approval gate then budget gate (parity-first)
@@ -158,7 +159,7 @@ consumers by M6.
158
159
| Milestone | Exit criteria |
159
160
| --- | --- |
160
161
| 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. |
161
-
| ADR-0032-M2 (REDEFINED) | Every audit event the evidence bundle reads is typed in `RunEventType`, dual-emitted alongside the existing `audit.record`call, and mapped both directions — verified by M1-style byte-equivalence. Covers routes, git-sandbox, skills, tests, undo, provenance, the approval/tool-call decision events, and the cancelled/pending lifecycle. Read side (`read_run_events_from_*`) surfaces them. Zero behavior change. (Old M2 "evidence/receipt fold" moved to M6 — see §14.) |
162
+
| ADR-0032-M2 (REDEFINED) | Every audit event the evidence bundle reads is typed in `RunEventType`, mapped both directions, and its call site **migrated** from `audit.record`to a single spine `emit` (replace, not dual-write — §15) so the consumer writes it exactly once; verified by M1-style byte-equivalence and per-event-type count parity. Covers routes, git-sandbox, skills, tests, undo, provenance, the approval/tool-call decision events, and the cancelled/pending lifecycle. Read side (`read_run_events_from_*`) surfaces them. Zero behavior change. (Old M2 "evidence/receipt fold" moved to M6 — see §14.) |
162
163
| 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. |
163
164
| 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. |
164
165
| ADR-0032-M5 | HookRegistry subscribes through the spine; Claude-Code-compatible hook names remain aliases; public hook API docs and tests pass. |
0 commit comments