You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Carved out of #697 at sign-off (2026-08-08), where an adversarial review demonstrated it against that
slice's patch rather than argued it. Recorded rather than fixed there because the fix is a fleet-wide
contract change, not one loop's, and because the window it needs is opened by #653 / #682.
The property
Every consumer resolves a committed root through metadata::resolve_chunk_map, which answers Ok(None) when the key holds no live committed generation — the root is gone
(crates/core/src/metadata.rs:2657-2659) or the generation it landed on is not Committed
(:2662-2664). Every maintenance loop skips that answer: gc.rs:404, restore.rs:646, and
reconstruction after #697.
Skipping is the right answer for a key whose object really is gone. It is the wrong answer for a key
this pass's own scan saw Committed moments earlier: that is not "no object here", it is "the
object retired or was rewritten under the read" — a hole in the reading, indistinguishable at the
call site from the first case.
Why it matters — a loop that DRAINS on absence, not just one that builds a set
GC and restore build sets and refuse to certify over an incomplete reading, so a skipped object costs
them coverage. Reconstruction converts absence into a delete:
the scan returns a committed root at inode:1 holding queued chunk 0xA100;
by the time resolve_chunk_map re-reads that root it carries a Pending generation, so crates/core/src/metadata.rs:2662-2664 answers Ok(None);
the walk skips the object, so no site is recorded for 0xA100;
the assessment reads "no committed map references this chunk" → Assessment::Drain;
the drain gate is on "the reading has a hole" only — and a skip does not mark one — so the delete
lands, and the pass answers Reconciled::Changed with zerounresolvable-chunk-map and zero refused-segmented rows.
The repair obligation is the last record saying live data is under-replicated. Deleting it for want of
a reading, and certifying over an object the pass never read, are the two halves of the C-1 invariant
(docs/principles.md:109) that #650 / #651 / #697 exist to restore — reached by the one path all three
were told to treat as benign.
The obvious fix — treat Ok(None) on a key the scan saw Committed as "retired under the read" and
mark the reading incomplete — contradicts the rule pinned across the whole #681 line: "Ok(None) from
the resolver is skipped, exactly as both merged peers skip it — not counted, not named". Changing
it in one loop makes reconstruction disagree with gc.rs:404 and restore.rs:646 about what the same
answer means, which is how this class got introduced in the first place.
Reachability
Bounded today by two facts, neither of which survives this milestone:
nothing in this build produces a segmented root at all (crates/core/src/metadata.rs:1460-1463 — "the segmented shape has no producer in this build (core: staged segment publication committer (635.6) #653 lands the staged publication committer)");
nothing rewrites a committed inode root back to Pending under a live key.
#653 (staged segment publication) and #682 (repoint_chunk — writes into a segmented record)
are exactly the slices that open the window: a root being republished is a root whose generation
changes between one pass's scan and its resolve.
What this issue is asking for
Decide once, fleet-wide:
Whether Ok(None) for a key the caller's own scan returned as Committed is distinguishable at
the seam (the resolver knows both facts; the caller has only one of them), and if so whether it
should be a distinct answer rather than an Option.
What each loop owes on it: a loop that only builds a set may keep skipping and lose coverage; a loop
that discards an obligation on absence (reconstruction's queue drain; desired_state's
drain-status) must not, because absence there is a destructive conclusion.
Whether the answer is a concurrent path in the rubric's sense — if it is, it lands with seeded
Tier-0 DST coverage, and the cost belongs with the slice that adopts it.
Depends on nothing. #653 and #682 make it reachable, and should not land without an answer.
Carved out of #697 at sign-off (2026-08-08), where an adversarial review demonstrated it against that
slice's patch rather than argued it. Recorded rather than fixed there because the fix is a fleet-wide
contract change, not one loop's, and because the window it needs is opened by #653 / #682.
The property
Every consumer resolves a committed root through
metadata::resolve_chunk_map, which answersOk(None)when the key holds no live committed generation — the root is gone(
crates/core/src/metadata.rs:2657-2659) or the generation it landed on is notCommitted(
:2662-2664). Every maintenance loop skips that answer:gc.rs:404,restore.rs:646, andreconstruction after #697.
Skipping is the right answer for a key whose object really is gone. It is the wrong answer for a key
this pass's own scan saw
Committedmoments earlier: that is not "no object here", it is "theobject retired or was rewritten under the read" — a hole in the reading, indistinguishable at the
call site from the first case.
Why it matters — a loop that DRAINS on absence, not just one that builds a set
GC and restore build sets and refuse to certify over an incomplete reading, so a skipped object costs
them coverage. Reconstruction converts absence into a delete:
inode:1holding queued chunk0xA100;resolve_chunk_mapre-reads that root it carries aPendinggeneration, socrates/core/src/metadata.rs:2662-2664answersOk(None);0xA100;Assessment::Drain;lands, and the pass answers
Reconciled::Changedwith zerounresolvable-chunk-mapand zerorefused-segmentedrows.The repair obligation is the last record saying live data is under-replicated. Deleting it for want of
a reading, and certifying over an object the pass never read, are the two halves of the C-1 invariant
(
docs/principles.md:109) that #650 / #651 / #697 exist to restore — reached by the one path all threewere told to treat as benign.
Why it was not fixed in #697
The obvious fix — treat
Ok(None)on a key the scan sawCommittedas "retired under the read" andmark the reading incomplete — contradicts the rule pinned across the whole #681 line: "
Ok(None)fromthe resolver is skipped, exactly as both merged peers skip it — not counted, not named". Changing
it in one loop makes reconstruction disagree with
gc.rs:404andrestore.rs:646about what the sameanswer means, which is how this class got introduced in the first place.
Reachability
Bounded today by two facts, neither of which survives this milestone:
crates/core/src/metadata.rs:1460-1463—"the segmented shape has no producer in this build (core: staged segment publication committer (635.6) #653 lands the staged publication committer)");
Pendingunder a live key.#653 (staged segment publication) and #682 (
repoint_chunk— writes into a segmented record)are exactly the slices that open the window: a root being republished is a root whose generation
changes between one pass's scan and its resolve.
What this issue is asking for
Decide once, fleet-wide:
Ok(None)for a key the caller's own scan returned asCommittedis distinguishable atthe seam (the resolver knows both facts; the caller has only one of them), and if so whether it
should be a distinct answer rather than an
Option.that discards an obligation on absence (reconstruction's queue drain;
desired_state'sdrain-status) must not, because absence there is a destructive conclusion.
Tier-0 DST coverage, and the cost belongs with the slice that adopts it.
Depends on nothing. #653 and #682 make it reachable, and should not land without an answer.