Fix #459: chain cache staleness #470

Merged
crueber merged 1 commit from fix/issue-459 into main 2026-09-13 16:55:32 +00:00
Owner

Child of #449 (audit F6). wal forkChain was a handle-lifetime cache, but the adopted-provenance backfill CAS-moves Root under a live handle and the chain is built from Parent+Root — a stale cache skipped the Root short-circuit past a dead middle.

Fix (not the documented-window fallback): the handle caches its own Parent+Root+Version with the chain and revalidates on every use with one exact-key GET of its own fork.json (failure path only — forkChain runs after an own-prefix NotFound — so law-6 hot-path budgets are untouched); the Root backfill now bumps Version like every other fork.json CAS (already-correct docs untouched, no churn). forkMu stays a leaf lock (snapshot outside, GET+compare outside, store under lock). ForkDoc comment updated; decision appended to docs/features/03_pull_requests.md.

Tests: TestForkChainRootBackfillInvalidates (fails on old code with stale [f/c], passes on fix); go test ./internal/wal/... + ./internal/pulls/... -race green; cover wal 95.1%, pulls 96.1% (≥95 gate holds); gofmt/vet clean. No new deps.

Child of #449 (audit F6). wal forkChain was a handle-lifetime cache, but the adopted-provenance backfill CAS-moves Root under a live handle and the chain is built from Parent+Root — a stale cache skipped the Root short-circuit past a dead middle. Fix (not the documented-window fallback): the handle caches its own Parent+Root+Version with the chain and revalidates on every use with one exact-key GET of its own fork.json (failure path only — forkChain runs after an own-prefix NotFound — so law-6 hot-path budgets are untouched); the Root backfill now bumps Version like every other fork.json CAS (already-correct docs untouched, no churn). forkMu stays a leaf lock (snapshot outside, GET+compare outside, store under lock). ForkDoc comment updated; decision appended to docs/features/03_pull_requests.md. Tests: TestForkChainRootBackfillInvalidates (fails on old code with stale [f/c], passes on fix); go test ./internal/wal/... + ./internal/pulls/... -race green; cover wal 95.1%, pulls 96.1% (≥95 gate holds); gofmt/vet clean. No new deps.
wal forkChain was a handle-lifetime cache, but the adopted-provenance
backfill CAS-moves Root under a live handle and the chain is built from
Parent+Root. The handle now caches its own Parent+Root+Version and
revalidates on every use with one exact-key GET (failure path only);
the Root backfill bumps Version like every other fork.json CAS.
Regression: TestForkChainRootBackfillInvalidates. Decision appended to
docs/features/03_pull_requests.md.
Sign in to join this conversation.
No description provided.