mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-15 10:38:35 +02:00
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>
118 lines
7.0 KiB
Markdown
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 |
|