Fix #451: fork-deletion safety #462

Merged
crueber merged 2 commits from fix/issue-451 into main 2026-09-13 14:56:14 +00:00
Owner

Deleting a fork parent with live children converts the prefix to a storage-only meta repository instead of wiping it (fixes #451).

Shape (issue's recommended option): wal/ pack set preserved verbatim, meta/forks.json + parent fork.json kept (chain resolution + GC walk work untouched), meta/tombstone.json records the conversion; manifest/refs/checkpoints/collab state swept. Parent id never changes, so children's fork.json pointers stay correct with zero child writes. Check lives in Registry.Delete (single layer; API+CLI inherit).

Planner's call, forced by evidence: re-create ABSORBS (no refuse). A tombstone probe on the create path adds round trips to the push fast path and TestPushFastPathZeroCollabRoundTrips failed on it (+2 HEADs); Open=NotFound + Create=412 cannot coexist on one key, so refusal is unimplementable probeless. Absorb is zero-trip and consistent on all create paths; stale tombstone is informational (Delete re-derives liveness from the index); pre-delete packs are unowned until the next childless wipe (noted in docs).

Tests: TestDelete451*/TestCreate451* (table, multi-level chain, absorb, tombstone GC, fail-closed) -race; TestForkNetworkGCMetaParent (+corrupt) in maintain; TestE2E_ForkDeleteKeepsChildrenWorking (real git: clone+push+reads post-delete, absorb re-create). Coverage wal 95.1% / maintain 95.5% (gate holds); vet/build clean; budget test green unmodified. Docs: 03 §7 + Decisions, 05 §5.1.2 + Decisions. No new deps. Covers audit #449 parent-deletion/GC item.

Deleting a fork parent with live children converts the prefix to a storage-only meta repository instead of wiping it (fixes #451). Shape (issue's recommended option): wal/ pack set preserved verbatim, meta/forks.json + parent fork.json kept (chain resolution + GC walk work untouched), meta/tombstone.json records the conversion; manifest/refs/checkpoints/collab state swept. Parent id never changes, so children's fork.json pointers stay correct with zero child writes. Check lives in Registry.Delete (single layer; API+CLI inherit). Planner's call, forced by evidence: re-create ABSORBS (no refuse). A tombstone probe on the create path adds round trips to the push fast path and TestPushFastPathZeroCollabRoundTrips failed on it (+2 HEADs); Open=NotFound + Create=412 cannot coexist on one key, so refusal is unimplementable probeless. Absorb is zero-trip and consistent on all create paths; stale tombstone is informational (Delete re-derives liveness from the index); pre-delete packs are unowned until the next childless wipe (noted in docs). Tests: TestDelete451*/TestCreate451* (table, multi-level chain, absorb, tombstone GC, fail-closed) -race; TestForkNetworkGCMetaParent (+corrupt) in maintain; TestE2E_ForkDeleteKeepsChildrenWorking (real git: clone+push+reads post-delete, absorb re-create). Coverage wal 95.1% / maintain 95.5% (gate holds); vet/build clean; budget test green unmodified. Docs: 03 §7 + Decisions, 05 §5.1.2 + Decisions. No new deps. Covers audit #449 parent-deletion/GC item.
Sign in to join this conversation.
No description provided.