Contracts

adversarial-evidence.md

Adversarial Evidence Ledger — Terminus Integrity Follow-ups

Per contracts/adversarial-evidence-contract.md: every contested finding from an adversarial squad is recorded here with a disposition — accepted, changed, or deferred_with_rationale. No contested finding is silently dropped.

Supply-chain adversarial pass: N/A — the mission adds/upgrades/removes no dependency.

Pre-plan research & grounding squad (3 lenses, 2026-09-24)

FindingLensDispositionNote
Default squash disables content gate (P0)architectaccepted→ WS1 / INV-1; blob-attribution axis.
MergeState.strategy is a fully dead fielddebbieaccepted→ WS2(a) / INV-2.
Lane-tip loss is distinct from strategy (proven)debbieaccepted→ WS2(b) / INV-2.
SafeCommitHeadMismatch = fixture or product gap?debbiechangedAdjudicated: real gap, already closed by #5012 FIX A; removed from scope as blocker.
Stale-local-head self-materialization clobberpaulaaccepted→ WS3(a) / INV-3.
issue-verdict on degrading read resolverpaulaaccepted→ WS3(b) / INV-3.
Blanket terminus_write flippauladeferred_with_rationaleRejected as scope: would regress high-frequency fail-open writers (C-003). Only issue-verdict chain rerouted.
3-way merge-resolution content residualarchitectdeferred_with_rationaleBounded, file-disjoint-lane-mitigated; tracked follow-up, honest xfail if surfaced (C-003).

Post-plan brownfield squad (3 lenses, 2026-09-24)

All three lenses: PROCEED to tasks after folding — no re-architecture, no scope change.

FindingLensDispositionFold
A — strategy-persist leaks WP04↔WP05 (resolve.py called only from executor)architectchangedPersist via WP05 executor reseed; WP04↔WP05 stays additive MergeState fields.
B/C — test-file ownership; git_probes.py under merge/architectacceptedWP03 owns test_git_probes_seam.py + test_reconciliation.py; WP04 owns test_merge_state_*.py.
D/F8 — H3 lane-tip CAS false-REFUSEs behind-HEAD (the #4982 window); branch may be gonearchitect+debbiechangedAccept ancestor; compare SHA as git object; REFUSE only true divergence.
F1 — blob_id_at "" conflates deleted vs git-error (fail-open)debbieacceptedLoop off git diff --name-status B..T, A/M only, REFUSE on unexpected "".
F2 — WS3 probe fail-open on path-driftdebbieacceptedDerive probed path from placement authority / ls-tree subtree.
F3/F9 — resume anchors re-poison every resume; two checkpoint capturesdebbieacceptedRead-persisted-first (mirror _resolve_pre_mutation_target_sha); persist at first capture, consume persisted.
F4 — default-squash repros vacuously green on patch_ids_in_windowdebbie+renataacceptedBlob/tree-presence observable + pin FAIL cause; hard-couple clean-squash positive.
F5 — authored_blobs union admits superseded intermediate blobs (false-PASS)debbieacceptedAttribute against the FINAL authored blob per (lane,path). Makes the 3-way defer sound.
F6 — changed_paths_in_range rename asymmetrydebbieacceptedUse --no-renames to match _collect_authored.
F7 — first_parent_commits_in_range fail-open on git errordebbieacceptedPropagate GitProbeError.
F14 — persisted strategy must equal attempt-1's executed valuedebbieacceptedPersist the resolved strategy attempt-1 actually runs.
WP05 must not strip enforce_closed_world in replace()architectacceptedWP05 constraint recorded.
ATDD per-WP: each fix WP carries its own red-first test; WP06 not the reviewerrenatachangedMarker removal at integration WITH captured before/after; WP06 → non-reviewer.
Positive-only INVs need companions (clean-squash, first-write, H1 flip, #4982/97 still-xfail-after-(a))renataacceptedEnumerated as explicit tasks.
Per-REFUSE-branch unit tests (NFR-001)renata+debbieacceptedOne direct error-injection test per REFUSE branch.
F10 — same-path byte-identical canceled≡approved PASSdebbiedeferred_with_rationaleFair concession (shipped bytes are approved); keep (path,blob) tuple, never blob-only.
F11 — file-existence vs row-level write-gate: blast-radius unrundebbie+pauladeferred_with_rationaleWP02 MUST run tests/coordination+status+cli+issue_matrix and record; switch to row-level if any committed-empty-scaffold first-write path exists.
F12 — issue-verdict reroute changes unmaterialized-coord behaviordebbieacceptedIntended; verify flat/no-coord missions don't false-refuse.
F13 — issue-verdict probe→write TOCTOU (unlocked path)debbiedeferred_with_rationaleInherent, needs a lock; out of scope.
3-way merge-resolution residualarchitect+renatadeferred_with_rationaleLand as a dedicated xfail(strict, reason=…), not "leave uncovered". C-003.
#4945/#4977/#4981 "fully closed" claim scoperenataacceptedLegit only at the integrity-gate level; the positional lane re-lettering ROOT is untouched — PR must not overclaim.

HELD (could not break): vacuous-manifest REFUSE catches the empty-claim squash; H1 flip-REFUSE + H2 legacy-marker fence correctly ordered before strategy consumption; the verify→FAIL→CAS-rollback→exit-1 transaction boundary is preserved by every proposed change.

Post-tasks brownfield squad (2 lenses, 2026-09-24)

Both lenses: READY TO IMPLEMENT after minor edits. All folded post-plan findings traceably encoded.

FindingLensDispositionFold
All F1–F14 + A–D operationalized in owning WPsrenataacceptedTraceability confirmed.
#4982/#4997 (a)-only red-isolation missingrenataacceptedAdded as integration checkpoint step 2 (after WP04, before WP05, confirm still xfail).
None-window-base REFUSE untested (last NFR-001 branch)renataacceptedAdded to WP03 T014.
3-way residual floats as bare markerrenataacceptedWP03 T014 now requires a real conflict-resolving-squash xfail(strict).
WP03 T014/T015 not labelled red-firstrenataacceptedLabelled.
Zero write_scope overlap; all production wiring fully-owned; resolve.py needs no edit; WS1 axis reachable with no executor editpaulaacceptedConfirmed — no production out-of-map edit.
tests/terminus marker-removal ownership gap (plan.md attributed to WP06)paulachangedKept orchestrator-at-consolidation model (a WP owning it would statically overlap WP01); corrected plan.md self-contradiction; nine tracked files listed in integration step 1.
M1 tests/integration/conftest.py unownedpaulaacceptedWP02 uses local fixtures.
M2 merge/__init__.py __all__ unownedpaulaacceptedWP04 imports CAS helper from the submodule directly.

Pre-merge brownfield squad (pending, MANDATORY)

_To be filled before opening the PR; must adversarially attempt to break every new guard/revert path._

Pre-merge brownfield squad (3 lenses, 2026-09-24) — MANDATORY

All three lenses: SAFE TO PR. No BLOCKERs.

FindingLensDisposition
Closure claim honest + non-fakeable; removed markers genuinely green; #4997 honest xfailrenataaccepted — Closes(8): #5013 #4945 #4977 #4981 #4970 #4985 #4991 #4982; ref-not-closed: #4997, 3-way, #4990, #4972
No new exit-0 data-loss path; WP03 DEFER unbreakable in production; WP05 H3/H4 unbreakable; WP02 widening safe; #4997 honestly distinctdebbieaccepted
Transaction boundary holds; WP02 widening strictly-more-correct (partition-respecting); single-authority holds; dead-symbol red pre-existing at basearchitectaccepted
mypy-strict error reconciliation.py:756architectFIXED (explicit list[str])
stale squash pass-message + 2 docstrings say "defers content"architectFIXED (blob-attribution axis runs; only per-SHA reachability deferred)
FU-2b mid-teardown-crash resume could false-FAIL a legit squash (fails CLOSED, no data loss)debbiedeferred_with_rationale — new follow-up, errs safe
FU-5b / 3-way merge-resolution residual (blob != either parent)debbie/architectdeferred_with_rationale — honest xfail
#4997 resume SHA-preservation over staged-deletion/LOCAL_CHANGES behind-HEAD windowalldeferred_with_rationale — honest xfail, distinct from #4982; follow-up

invariants.md

Behavioral Invariant Contracts — Terminus Integrity Follow-ups

Executable-intent contracts. Each invariant names its verifying tests/terminus/ repro (red-first) and the fail-closed rule. These are the ATDD contract the WPs deliver.

INV-1 — Squash content soundness (WS1 / FR-001, FR-002)

> After an exit-0 spec-kitty merge on the default squash strategy, no content path on the target is authored solely by a removed/canceled WP.

  • Given a mission where a canceled WP authored src/pkg/<wp>_removed.py that rode a carrier lane, When spec-kitty merge runs with no --strategy, Then the gate FAILs, the target is CAS-rolled-back, the command exits non-zero, and <wp>_removed.py is absent from the target tree.
  • Given a clean mission (all approved present, nothing excluded), When the default squash merge runs, Then the content axis PASSes (no false-refusal).
  • Fail-closed: GitProbeError from blob_id_at/changed_paths_in_range, or a None window base, ⇒ REFUSE (never PASS).
  • Honest reporting: the squash success message must not assert excluded-commit reachability was verified beyond what the axis computed.
  • Verifies: test_terminus_reconciliation_property::no_excluded_commit_reachable[squash] (xfail→green); default-squash variants of test_repro_{4945,4977,4981}.py (blob/tree-presence observable); a new clean-squash no-false-fail param.
  • Residual (deferred): 3-way merge-resolution content (blob ≠ either parent) — tracked follow-up, honest xfail if surfaced.

INV-2 — Resume fidelity (WS2 / FR-003, FR-004, FR-005)

> A resumed merge behaves identically to the uninterrupted one: same strategy, same landed tree.

  • Given an interrupted merge --strategy merge, When merge --resume runs with no --strategy, Then the resumed run uses the persisted merge strategy, not squash.
  • Given a resume with an explicit --strategy differing from persisted, When it runs, Then it REFUSEs (H1 strategy-flip guard).
  • Given an interrupted merge whose pre-interrupt lane tips carried approved commits, When resumed, Then the reconciliation claim's coord base is the persisted pre_mutation_coord_sha (not the live checkpoint) and every pre-interrupt approved commit is reachable from the target.
  • Given an interrupted non-default-target merge, When resumed, Then it lands on that target with no SafeCommitHeadMismatch.
  • Fail-closed: absent persisted coord base / lane tips where required ⇒ REFUSE (H4); a live lane tip that is neither equal to nor a descendant of the persisted tip ⇒ REFUSE (H3).
  • Verifies: test_repro_{4985,4991}.py (green after strategy fix); test_repro_{4982,4997}.py (green after strategy + lane-tip preservation).

INV-3 — Coordination write integrity (WS3 / FR-006, FR-007)

> A coord-routed write never clobbers committed coordination content by mistaking a stale local head for a first-write window.

  • Given an UNMATERIALIZED local-head coord branch already carrying committed issue-matrix content, When a coord-routed write attempts self-materialization, Then the gate REFUSEs.
  • Given a genuine first-write (no committed matrix content), When it self-materializes, Then it succeeds (no false-refusal).
  • Given an issue-verdict write, When it resolves its write surface, Then it uses resolve_for_write (fail-closed), not the degrading read resolver.
  • Fail-closed: unreadable git during the committed-content probe ⇒ treat as content-present ⇒ REFUSE.
  • Verifies: test_repro_4970.py (xfail→green).

Cross-cutting (C-004)

Every INV runs its check before any branch/worktree teardown, push, or exit-0; the existing verify→FAIL→CAS-rollback→exit-1 boundary and 3-arg update-ref CAS discipline are preserved.