The displaced-run refusal sat only on the fresh fallback. The resumable branch
returned before it, so an interrupted recovery that had already fallen back to
generation 2 resumed at 2 — correctly, since finishing an interrupted seal must
not orphan its artifact — and stranded a published run naming generation 1
exactly as a fresh fallback would, one crash later. Review reproduced it with a
run at 1, an orphan at 1, and a `.recovery-<journal>-2.prefix`: the store opened
with `object_source(0, 1) == None`.
`preferred` is now computed before either path can return, and both call one
closure keyed on choosing anything other than the identity the frames already
carry. A resumable artifact at `preferred` displaces nothing and the guard is a
no-op on it, which is its own test — a guard keyed on "a resumable artifact
exists" would refuse every interrupted recovery on a root that has ever sealed,
and that test fails rather than letting the over-broad version pass.
Both refusing tests share one assertion helper, so the paths cannot drift in the
tests either. Each guard call is separately mutation-checked: disabling the
resumed one reproduces the reported open with the run's source unpinned.
Contract review 2026-07-30-B amended with the finding and the general form of
it — the check belongs on the outcome, that the frames are being renamed, not
on the branch that produced the rename.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XKzM69CHmBuDcA3qN1jFdh