Files
seaweedfs/sw-block/design/v2-first-migration-task-pack.md
T
pingqiuandClaude Opus 4.6 11c6aaf316 feat: Batch 7 + Phase 16C-E — command dispatch extraction + engine refinements
Batch 7: Command dispatch binding extraction
- New weed/server/blockcmd package: CommandHandler interface + DispatchCommands
- volume_server_block.go applyCoreCommandsWithAssignment delegates to dispatcher
- weed/server still owns RecordCommand, EmitCoreEvent, PublishProjection
- v2bridge NOT given command-switch or event-emission semantics

Phase 16C: Rebuilding assignment enters core command path
Phase 16D: Rebuild recovery-task startup is command-driven
Phase 16E: Catch-up recovery-task startup is command-driven

Engine refinements:
- RecoveryTarget on AssignmentDelivered event
- shouldStartRecoveryTask / shouldStartReceiver guards
- bootstrapReason: awaiting_rebuild_start

Bridge/contract updates:
- control_adapter.go: refined translation helpers
- contract.go: executor port alignment

Migration design docs (Batch 1-3 delivered, design artifacts):
- v2-first/second/third-migration-batch.md + task-pack.md
- v2-assignment-translation-unification.md
- v2-execution-muscles-inventory.md
- v2-separation-port-layer-audit.md
- v2-legacy-runtime-exit-criteria.md

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

309 lines
8.1 KiB
Markdown

# V2 First Migration Task Pack
Date: 2026-04-04
Status: delivered
## Purpose
This note turns the first separation batch into validate-able engineering tasks.
Each task must name:
1. source
2. destination
3. authority rule
4. adapter boundary
5. acceptance criteria
6. validation proof
The goal is to make separation work parallelizable without letting `V1`
runtime-owner behavior silently leak back in.
## Shared Rules
All tasks in this pack inherit these rules:
1. `sw-block` must not directly import `weed/storage/blockvol`
2. `weed/` may implement ports, but must not redefine semantic truth
3. each task must move one boundary, not redesign the whole runtime
4. compatibility guards may stay, but must not be treated as semantic-authority
proof
Existing landing zones already exist:
1. `sw-block/bridge/blockvol`
2. `sw-block/bridge/blockvol/control_adapter.go`
3. `sw-block/bridge/blockvol/contract.go`
So Task A does not begin with package creation. It begins with canonical-rule
consolidation into the existing `sw-block` bridge layer.
## Task A: Canonical Assignment Translation
### Goal
Make `sw-block` own the canonical helper rules for:
1. replica identity
2. recovery-target mapping
3. engine replica-assignment packaging
### Source
1. `weed/storage/blockvol/v2bridge/control.go`
2. `weed/server/volume_server_block.go`
### Destination
1. `sw-block/bridge/blockvol/control_adapter.go`
### Authority Rule
This is semantic translation logic, so the canonical rule belongs in
`sw-block`, not in product adapters.
### Adapter Boundary
`weed/` may still:
1. parse `BlockVolumeAssignment`
2. decide which source fields exist on the wire/runtime side
`weed/` must not separately redefine:
1. `ReplicaID = <volume>/<server>`
2. `replica -> catchup`
3. `rebuilding -> rebuild`
### Acceptance
1. `sw-block` exports canonical helpers for identity and recovery-target mapping
2. `weed/storage/blockvol/v2bridge/control.go` and
`weed/server/volume_server_block.go` both use those helpers
3. no direct address-derived identity logic remains in adapter code
### Validation
1. `go test ./sw-block/bridge/blockvol`
2. `go test ./weed/storage/blockvol/v2bridge -run "TestControl_|TestBridge_"`
3. focused server path still passes:
- `go test ./weed/server -run "TestBlockService_ApplyAssignments_(PrimaryRole_UsesCoreStartRecoveryTaskForCatchUp|RebuildingRole_UsesCoreRecoveryPathWithoutLegacyDirectStart)"`
### Current proof anchors
1. `TestControlAdapter_StableIdentity`
2. `TestControlAdapter_RebuildRoleMapping`
3. `TestControl_PrimaryAssignment_StableServerID`
4. `TestControl_RebuildAssignment`
## Task B: Reader Port Separation
### Goal
Separate retained-history state reading as a pure execution muscle behind a
stable `sw-block` port.
### Source
1. `weed/storage/blockvol/v2bridge/reader.go`
### Destination
1. contract remains in `sw-block/bridge/blockvol/contract.go`
2. implementation stays thin in `weed/storage/blockvol/v2bridge/reader.go`
3. future code landing zone, if needed:
- `sw-block/bridge/blockvol/runtime`
- or equivalent execution package under `sw-block`
### Authority Rule
Reader logic is not semantic authority. It must only read backend facts and
project them into the engine-facing retained-history shape.
### Adapter Boundary
`weed/` may:
1. read `BlockVol.StatusSnapshot()`
2. map backend fields into the contract shape
`weed/` must not:
1. reinterpret durability meaning
2. patch semantic fallbacks into the reader
### Acceptance
1. `BlockVolReader` contract stays complete and stable in `sw-block`
2. `Reader` remains a thin adapter over real `BlockVol`
3. `StorageAdapter.GetRetainedHistory()` depends only on the contract, not on
weed internals
### Validation
1. `go test ./sw-block/bridge/blockvol`
2. `go test ./weed/storage/blockvol/v2bridge -run "TestReader_"`
### Current proof anchors
1. `TestStorageAdapter_RetainedHistoryFromReader`
2. `TestReader_RealBlockVol_StatusSnapshot`
3. `TestReader_RealBlockVol_HeadAdvancesWithWrites`
## Task C: Pinner Port Separation
### Goal
Separate WAL/snapshot/full-base hold mechanics as execution muscles behind a
stable `sw-block` pinning port.
### Source
1. `weed/storage/blockvol/v2bridge/pinner.go`
### Destination
1. contract remains in `sw-block/bridge/blockvol/contract.go`
2. implementation stays thin in `weed/storage/blockvol/v2bridge/pinner.go`
3. future migration target is a `sw-block`-owned execution-muscle package, with
weed-side `BlockVol` binding left thin
### Authority Rule
Hold/release mechanics are execution detail. Recovery policy decides *when* to
hold; pinner only decides *how* to pin in the backend.
### Adapter Boundary
`weed/` may:
1. wire retention floor into `BlockVol`
2. validate concrete hold positions against backend state
`weed/` must not:
1. decide recovery target
2. redefine which boundary is authoritative
### Acceptance
1. `BlockVolPinner` is the sole engine-facing pin contract
2. pinner implementation remains backend-thin and side-effect-local
3. pin lifecycle symmetry is covered in `sw-block` contract tests
### Validation
1. `go test ./sw-block/bridge/blockvol`
2. `go test ./weed/storage/blockvol/v2bridge -run "TestPinner_|TestBridge_"`
### Current proof anchors
1. `TestStorageAdapter_WALPinRejectsRecycled`
2. `TestStorageAdapter_SnapshotPinRejectsUntrusted`
3. `TestStorageAdapter_PinReleaseSymmetry`
4. `TestPinner_RealBlockVol_HoldWALRetention`
5. `TestPinner_RealBlockVol_HoldRejectsRecycled`
## Task D: Executor Muscle Separation
### Goal
Separate catch-up / rebuild execution mechanics from `weed/` runtime ownership
so that executor behavior is treated as a reusable muscle behind
`sw-block`-owned ports.
### Source
1. `weed/storage/blockvol/v2bridge/executor.go`
2. related tests in `weed/storage/blockvol/v2bridge/*transfer*`
3. related tests in `weed/storage/blockvol/v2bridge/*snapshot*`
4. related tests in `weed/storage/blockvol/v2bridge/*truncate*`
### Destination
1. contract shape in `sw-block/bridge/blockvol/contract.go`
2. engine-facing use through:
- `engine.CatchUpIO`
- `engine.RebuildIO`
3. implementation remains thin in `weed/` until backend-binding interfaces are
fully extracted
### Authority Rule
Executor code is allowed to:
1. transfer bytes
2. apply WAL entries
3. install snapshots/full base
4. truncate local WAL
Executor code is not allowed to:
1. classify recovery outcome
2. decide whether rebuild vs catch-up is needed
3. own publication or health meaning
### Adapter Boundary
`weed/` may:
1. call real `BlockVol` APIs
2. speak TCP rebuild/catch-up protocol
3. update local backend runtime state during execution
`weed/` must not:
1. redefine engine recovery phases
2. redefine target/achieved boundary meaning
### Acceptance
1. `BlockVolExecutor` aligns exactly with engine execution port expectations
2. engine/executor integration is possible without `sw-block` importing weed
3. executor logic is documented as reusable execution muscle, not semantic
authority
### Validation
1. `go test ./sw-block/bridge/blockvol`
2. `go test ./weed/storage/blockvol/v2bridge -run "TestExecutor_|TestBridge_"`
3. focused integrated runtime tests remain green:
- `go test ./weed/server -run "TestBlockService_ApplyAssignments_(PrimaryRole_UsesCoreStartRecoveryTaskForCatchUp|RebuildingRole_UsesCoreRecoveryPathWithoutLegacyDirectStart)"`
### Current proof anchors
1. `TestContract_BlockVolReaderInterface`
2. `TestExecutor_RealBlockVol_StreamWALEntries`
3. `TestExecutor_RealBlockVol_StreamPartialRange`
4. `TestExecutor_ErrorPaths`
## Parallel Execution Recommendation
These four tasks are safe to run in parallel if ownership stays clear:
1. Task A: canonical translation rules
2. Task B: reader port hardening
3. Task C: pinner port hardening
4. Task D: executor contract alignment
Recommended order for merge:
1. Task A
2. Task B
3. Task C
4. Task D
Reason:
1. Task A removes semantic drift first
2. Tasks B/C/D then migrate pure muscles behind that stable rule layer
## Delivery Note
Final outcome:
1. Task A required code change and is now delivered
2. Tasks B/C/D were reviewed and confirmed already at the acceptance bar
3. the next migration frontier is backend-binding extraction, not more contract
cleanup