# A5-A8 Acceptance Traceability Date: 2026-03-29 Status: historical evidence traceability ## Purpose Map each acceptance criterion to specific executable evidence. Two evidence layers: - **Simulator** (distsim): protocol-level proof - **Prototype** (enginev2): ownership/session-level proof --- ## A5: Non-Convergent Catch-Up Escalates Explicitly **Must prove**: tail-chasing or failed catch-up does not pretend success. **Pass condition**: explicit `CatchingUp → NeedsRebuild` transition. | Evidence | Test | File | Layer | Status | |----------|------|------|-------|--------| | Tail-chasing converges or aborts | `TestS6_TailChasing_ConvergesOrAborts` | `cluster_test.go` | distsim | PASS | | Tail-chasing non-convergent → NeedsRebuild | `TestS6_TailChasing_NonConvergent_EscalatesToNeedsRebuild` | `phase02_advanced_test.go` | distsim | PASS | | Catch-up timeout → NeedsRebuild | `TestP03_CatchupTimeout_EscalatesToNeedsRebuild` | `phase03_timeout_test.go` | distsim | PASS | | Reservation expiry aborts catch-up | `TestReservationExpiryAbortsCatchup` | `cluster_test.go` | distsim | PASS | | Flapping budget exceeded → NeedsRebuild | `TestP02_S5_FlappingExceedsBudget_EscalatesToNeedsRebuild` | `phase02_advanced_test.go` | distsim | PASS | | Catch-up converges or escalates (I3) | `TestI3_CatchUpConvergesOrEscalates` | `phase045_crash_test.go` | distsim | PASS | | Catch-up timeout in enginev2 | `TestE2E_NeedsRebuild_Escalation` | `p2_test.go` | enginev2 | PASS | **Verdict**: A5 is well-covered. Both simulator and prototype prove explicit escalation. No pretend-success path exists. --- ## A6: Recoverability Boundary Is Explicit **Must prove**: recoverable vs unrecoverable gap is decided explicitly. **Pass condition**: recovery aborts when reservation/payload availability is lost; rebuild is explicit fallback. | Evidence | Test | File | Layer | Status | |----------|------|------|-------|--------| | Reservation expiry aborts catch-up | `TestReservationExpiryAbortsCatchup` | `cluster_test.go` | distsim | PASS | | WAL GC beyond replica → NeedsRebuild | `TestI5_CheckpointGC_PreservesAckedBoundary` | `phase045_crash_test.go` | distsim | PASS | | Rebuild from snapshot + tail | `TestReplicaRebuildFromSnapshotAndTail` | `cluster_test.go` | distsim | PASS | | Smart WAL: resolvable → unresolvable | `TestP02_SmartWAL_RecoverableThenUnrecoverable` | `phase02_advanced_test.go` | distsim | PASS | | Time-varying payload availability | `TestP02_SmartWAL_TimeVaryingAvailability` | `phase02_advanced_test.go` | distsim | PASS | | RecoverableLSN is replayability proof | `RecoverableLSN()` in `storage.go` | `storage.go` | distsim | Implemented | | Handshake outcome: NeedsRebuild | `TestExec_HandshakeOutcome_NeedsRebuild_InvalidatesSession` | `execution_test.go` | enginev2 | PASS | **Verdict**: A6 is covered. Recovery boundary is decided by explicit reservation + recoverability check, not by optimistic assumption. `RecoverableLSN()` verifies contiguous WAL coverage. --- ## A7: Historical Data Correctness Holds **Must prove**: recovered data for target LSN is historically correct; current extent cannot fake old history. **Pass condition**: snapshot + tail rebuild matches reference; current-extent reconstruction of old LSN fails correctness. | Evidence | Test | File | Layer | Status | |----------|------|------|-------|--------| | Snapshot + tail matches reference | `TestReplicaRebuildFromSnapshotAndTail` | `cluster_test.go` | distsim | PASS | | Historical state not reconstructable after GC | `TestA7_HistoricalState_NotReconstructableAfterGC` | `phase045_crash_test.go` | distsim | PASS | | `CanReconstructAt()` rejects faked history | `CanReconstructAt()` in `storage.go` | `storage.go` | distsim | Implemented | | Checkpoint does not leak applied state | `TestI2_CheckpointDoesNotLeakAppliedState` | `phase045_crash_test.go` | distsim | PASS | | Extent-referenced resolvable records | `TestExtentReferencedResolvableRecordsAreRecoverable` | `cluster_test.go` | distsim | PASS | | Extent-referenced unresolvable → rebuild | `TestExtentReferencedUnresolvableForcesRebuild` | `cluster_test.go` | distsim | PASS | | ACK'd flush recoverable after crash (I1) | `TestI1_AckedFlush_RecoverableAfterPrimaryCrash` | `phase045_crash_test.go` | distsim | PASS | **Verdict**: A7 is now covered with the Phase 4.5 crash-consistency additions. The critical gap ("current extent cannot fake old history") is proven by `CanReconstructAt()` + `TestA7_HistoricalState_NotReconstructableAfterGC`. --- ## A8: Durability Mode Semantics Are Correct **Must prove**: best_effort, sync_all, sync_quorum behave as intended under mixed replica states. **Pass condition**: sync_all strict, sync_quorum commits only with true durable quorum, invalid topology rejected. | Evidence | Test | File | Layer | Status | |----------|------|------|-------|--------| | sync_quorum continues with one lagging | `TestSyncQuorumContinuesWithOneLaggingReplica` | `cluster_test.go` | distsim | PASS | | sync_all blocks with one lagging | `TestSyncAllBlocksWithOneLaggingReplica` | `cluster_test.go` | distsim | PASS | | sync_quorum mixed states | `TestSyncQuorumWithMixedReplicaStates` | `cluster_test.go` | distsim | PASS | | sync_all mixed states | `TestSyncAllBlocksWithMixedReplicaStates` | `cluster_test.go` | distsim | PASS | | Barrier timeout: sync_all blocked | `TestP03_BarrierTimeout_SyncAll_Blocked` | `phase03_timeout_test.go` | distsim | PASS | | Barrier timeout: sync_quorum commits | `TestP03_BarrierTimeout_SyncQuorum_StillCommits` | `phase03_timeout_test.go` | distsim | PASS | | Promotion uses RecoverableLSN | `EvaluateCandidateEligibility()` | `cluster.go` | distsim | Implemented | | Promoted replica has committed prefix (I4) | `TestI4_PromotedReplica_HasCommittedPrefix` | `phase045_crash_test.go` | distsim | PASS | **Verdict**: A8 is well-covered. sync_all is strict (blocks on lagging), sync_quorum uses true durable quorum (not connection count). Promotion now uses `RecoverableLSN()` for committed-prefix check. --- ## Summary | Criterion | Simulator Evidence | Prototype Evidence | Status | |-----------|-------------------|-------------------|--------| | A5 (catch-up escalation) | 6 tests | 1 test | **Strong** | | A6 (recoverability boundary) | 6 tests + RecoverableLSN() | 1 test | **Strong** | | A7 (historical correctness) | 7 tests + CanReconstructAt() | — | **Strong** (new in Phase 4.5) | | A8 (durability modes) | 7 tests + RecoverableLSN() | — | **Strong** | **Total executable evidence**: 26 simulator tests + 2 prototype tests + 2 new storage methods. All A5-A8 acceptance criteria have direct test evidence. No criterion depends solely on design-doc claims. --- ## Still Open (Not Blocking) | Item | Priority | Why not blocking | |------|----------|-----------------| | Predicate exploration / adversarial search | P2 | Manual scenarios already cover known failure classes | | Catch-up convergence under sustained load | P2 | I3 proves escalation; load-rate modeling is optimization | | A5-A8 in a single grouped runner view | P3 | Traceability doc serves as grouped evidence for now |