Files
seaweedfs/sw-block/docs/archive/design/a5-a8-traceability.md
T
pingqiuandClaude Opus 4.6 c0a805184f chore: archive superseded V2 design docs
Copies of design docs removed in Phase 09, preserved in sw-block/docs/archive/
for historical reference.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 16:26:34 -07:00

118 lines
7.0 KiB
Markdown

# 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 |