Research — Verdict-matrix RMW preservation (#4858 + #4868)
All decisions grounded on baseline skupstream/main == 45df0b61d5 (the acceptance path is byte-identical to the #4858 grounding baseline 32cfc272ee). Sources: research/grounding-4858.md, research/grounding-4868.md, two post-spec adversarial squads (tracer-squad-findings.md).
Decision A1 — #4858 fix locus: locked re-read + single-row splice at the command seam (Option A)
OUTSIDE the lock; then inside feature_status_lock(repo_root, matrix_dir.name) re-read the on-disk matrix, splice in only the owned entry (criterion id / invariant id), and write+commit. matrix_dir is resolved once and reused as both re-read base and write target.
it; minimal blast radius; the slow check stays out of the critical section. The architecture lens confirmed the lock key is layout-invariant and composes cleanly with the write-seam.
for all writers, but must re-contract the function to disambiguate criterion vs invariant, and would serialize non-verdict writers we deliberately keep out of scope (C-010). Rejected as heavier for a P0.
and doesn't match the existing status/locking.py doctrine. Rejected.
- Decision: In
acceptance_verdict.py, run the slowenforce_negative_invariantscheck - Rationale: Keeps the criterion-vs-invariant disambiguation where the caller already knows
- Alternatives considered:
- Option B — push the locked RMW into
write_and_commit_acceptance_matrix: one chokepoint - Option C — content hash CAS with retry: more moving parts, still needs the per-row merge,
Decision A2 — #4858 atomic write via kernel.atomic.atomic_write
with kernel.atomic.atomic_write (tempfile + rename). Assert via a call-spy (US1 Scenario 6).
(C-003). Confirmed atomic_write is a live symbol; write_if_changed is absent, so it is NOT activated (avoids the C-007 dead-symbol trap).
or trip test_no_dead_symbols.py; unnecessary).
- Decision: Replace the bare
path.write_textinwrite_acceptance_matrix(matrix.py) - Rationale: Prevents torn reads at the shared writer for ALL callers; sanctioned door
- Alternatives: activating
write_if_changed— rejected (would need a real caller in-change
Decision A3 — #4858 lock primitive: existing feature_status_lock
matrix_dir.name; no new primitive, no change to that module.
bounded-timeout, and routes through kernel.locks (C-001/C-002 satisfied). The architecture lens verified both primary and coord roots collapse to the same common-dir lock path.
- Decision: Reuse
status/locking.py::feature_status_lock, keyed on the git common dir + - Rationale: It already spans primary + coord worktrees (one lock file), is cross-process and
Decision B1 — #4868 fix: coord-aware migration read source
migrate_issue_matrix_to_json; read the legacy matrix from read_dir or feature_dir; keep write_issue_matrix(feature_dir=feature_dir) unchanged. Pass read_dir=read_dir from _migrate_if_needed (issue_verdict.py:166).
write stays on primary so the write-seam still materializes coord and cleans residue (C-011). Backward-compatible: the bulk caller _migrate_one_mission and unit callers pass keyword args after feature_dir (signature already *-separated), so nothing breaks (NFR-005).
migrated=False, never write a canonical JSON, and re-trigger every call. Rejected — the migrated is True assertion in US4 exists specifically to reject this pseudo-fix.
write but breaks the write-seam residue-cleanup contract. Rejected and explicitly guarded by C-011 + the US4 primary-residue assertion.
- Decision: Add an optional keyword-only
read_dir: Path | None = Noneto - Rationale: Minimal (2-line) fix at the true root — the migration read source — while the
- Alternatives considered:
- Make
_load_raw_rowsfailover-read the coord.md: would preserve rows but leave - Pass
read_diras the writefeature_dir: gets both rows into coord JSON via the main
Decision B2 — #4868 malformed legacy coord .md: fail loudly
being silently ignored (as on base). This is intended, safer behaviour; a guard test pins it.
mission closes; failing loudly on a corrupt authoritative matrix is the correct posture.
- Decision: After the fix, a malformed coord
.mdsurfaces the validation error rather than - Rationale: Silent success that drops the authoritative matrix is the very defect class this
Decision C1 — Test strategy: deterministic, no real threads/flake
...acceptance_verdict.enforce_negative_invariants (import-by-name), one-shot nonlocal guard; disk-reload assertions; lock spy + call-order spy + atomic-write spy; flat + coord (two worktree roots) + criterion-mode.
JSON and would mask the fix); reuse _build_coord_mission_for_matrix; flat control cited.
- #4858: serialized
read1→run2→finish1harness; patch the COMMAND-module binding - #4868: integration test with the REAL write-seam (a fake seam won't materialize the coord
Supply-chain
N/A — no dependency add/upgrade/remove. Nothing to vet under DIRECTIVE_051.
Adversarial evidence (dispositions — no contested finding dropped)
Per contracts/adversarial-evidence-contract.md. Two post-spec squads; every finding folded:
| Finding (lens) | Disposition |
|---|---|
| Deterministic harness can't gate the lock (debugger, #4858) | changed — added lock-acquisition spy (FR-007) + call-order (FR-008) |
| Monkeypatch must target command-module binding + one-shot reentrancy (debugger, #4858) | changed — pinned in US1 Independent Test |
| Scenario "reports committed" is a decoy; use disk-reload + fail→pass (debugger, #4858) | changed — US1 Scenario 1 pinned |
| Mid-point "B persisted" provenance checkpoint (debugger, #4858) | changed — US1 Scenario 2 |
| Coord must drive two worktree roots (debugger+architect, #4858) | changed — US2 Independent Test |
| Criterion-mode has its own seam (debugger+reviewer, #4858) | changed — US3 |
| Lock scope is verdict-vs-verdict only; state it (architect, #4858) | changed — C-010 + Scope Boundaries |
| NFR-004 over-promised (coord copy non-atomic) (architect, #4858) | changed — NFR-004 scoped to the door |
| Atomic-write door not test-gated (reviewer, fold) | changed — US1 Scenario 6 spy + FR-009 |
| C-011 not falsified by the test (debugger, #4868) | changed — US4 Scenario 2 primary-residue assertion |
Malformed coord .md behaviour change (debugger, #4868) | accepted — decision: fail loudly + guard test |
| Defer atomic door on issue writer — record it (reviewer, fold) | accepted — Scope Boundaries line |
| Fold is "thin" (shared signature+fixtures, not code) (reviewer, fold) | accepted — disclosed honestly; not a defect |
Adversarial evidence — POST-PLAN squad (2026-09-21)
Three lenses (architect-alphonso, debugger-debbie, python-pedro). All findings folded into spec/plan/contract; none dropped. Verdicts: architect "sound — needs changes"; debugger "sound, two HIGH structural gaps"; pedro "feasible as planned".
| Finding (lens) | Disposition |
|---|---|
| Lock-timeout unspecified; fail-open would re-introduce P0 (debugger HIGH, architect Q2) | changed — FR-015/C-012 fail-closed + US1 Scenario 8 |
| FR-003 re-read-inside-lock not pinned; "re-read outside lock" mutant survives serial harness (debugger HIGH) | changed — US1 Scenario 7 strict ordering + C-4858-reread-in-lock |
Reported overall_verdict from stale in-memory matrix (debugger MED, pedro MED) | changed — FR-016 + US1 Scenario 9 |
Criterion index/_resolve_criterion_update must run on re-read (pedro HIGH, debugger MED) | changed — US3 note + C-4858-modes + plan step |
NI splice must not reuse _register_negative_invariant (resets to pending) (pedro MED) | changed — US3 note + C-4858-modes (replace-or-append-judged helper) |
| Read surface vs commit surface can diverge; materialize worktree before lock (architect Q1/Q2) | changed — FR-017/C-013 + edge case |
| #4868 C-011 guard doesn't kill the wrong fix; residue-only check insufficient (architect Q4) | changed — US4 Scenario 2 now spies feature_dir==primary, mutation-tested |
#4868 malformed .md may raise raw traceback (architect Q4) | changed — FR-018 structured IssueVerdictError |
| #4868 unmaterialized-coord degradation (architect Q4) | accepted — precondition documented (edge case) |
| #4868 no 2nd-call idempotency coverage (debugger MED) | changed — US4 Scenario 3 |
| atomic tempfile in matrix_dir, no residue (architect LOW, debugger LOW) | accepted — noted in plan/contract |
| lock re-entrancy vs commit path — safe, no deadlock (architect Q2, pedro LOW) | accepted — confirmed no finding |
shared fixture _build_coord_mission_for_matrix cross-lane coupling (architect Q5) | accepted — freeze return contract; site A's coord test in the file already importing it |
| same-entry-id race — no sibling loss, no delete path (debugger Q2) | accepted — no finding |