Response::Unclaimed is the same silent-loss door as #115, still open: three causes collapse into one count that reads as the designed case #123
Labels
No labels
code-review
correctness
dos
performance
security
severity/high
severity/low
severity/medium
tech-debt
Kind/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
h-dv/code-index#123
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while fixing #115 (a package worker's refusal silently promoted into the active generation). Code-verified, not driven end to end, and deliberately scoped out of that fix rather than absorbed into it.
The gap
extract_onecollapses three distinct causes intoResponse::Unclaimed:Only the first is benign. The other two are the same shape as #115: a file that should carry facts silently carries none.
Why it survives promotion
write_queuesetsfile_id, and the carry atcrates/indexer/src/generations.rs:754excludeswork='reparse' AND file_id IS NOT NULLwith no state filter. So an unclaimed file's active contribution is left behind in the outgoing generation and nothing replaces it in the incoming one.The only disclosure is the
Ready::unclaimedcount — and because cause 1 dominates in any real repo, a non-zerounclaimedreads as "these files route to no plugin", which is exactly what an operator expects to see. Causes 2 and 3 hide inside a number that looks healthy.Why it is worth its own issue
#115's gate asks a precise question — does promoting this generation delete facts the active one is serving for that file? — and answers it for refusals. An unclaimed file never produced a
ParseResult::Error, so it never reaches that predicate. The chokepoint #115 established (build.rs:1386infinish, the only production transition toready) is the right place to ask the same question about this population, but the population has to be distinguishable first.Fixing it inside #115 would have meant widening a verified five-link chain on an unverified sixth. That is the trade this project keeps getting right by refusing.
What closing it needs
Unclaimedshould carry which case it was — routing (a measurement), or an accident (a finding).gate_failedapplies. The machinery now exists; it needs the population.unclaimed_routing: 0is a measurement; an absent field means this build did not report; the accident list is the finding, absent when empty.Related
Split from #115. Same family as #101 (a truncated extraction disclosed on one surface only) and #99. Note also two adjacent facts recorded in #115 and not fixed there:
files.parse_erroris not restamped by promotion (m0054 names that omission deliberately), so it can disagree withfile_contributions.refusaluntil the next ordinary pass; andplugin_activationhas no MCP surface for refusals at all.Triage 2026-09-06 at
f6a878a: CLOSING. All four "What closing it needs" items are met, and the two residuals are reported by the product rather than hidden — which is this issue's own standard.Verified against master and by re-running the tests myself, not from a lane report. Landed in
d0279c0.Against the four numbered items
1. Split the three causes.
crates/indexer/src/build.rs:1474-1525—Unclaimedis now four variants:Routing { reason },Vanished { at },ProducedNothing,Failed { lang, detail }. The collapse is unrepresentable rather than merely avoided, while the old collapsed answer stays available to callers who only need the total.2. Run #115's predicate over the accident cases. This is the part I like: it does not add a second gate.
Unclaimed::refusal()(build.rs:1537-1552) makes onlyFailedowe a refusal, andbuild.rs:1352writes that refusal contribution — which manufactures the population #115's gate 5b already reads. So promotion refuses through the chokepoint #115 established, exactly as this issue proposed, with no new five-link chain to verify.3. Three-state discipline.
Readycarriesunclaimed_routing,unclaimed_accident_count,unclaimed_accidents: Vec<(path, cause)>andunclaimed_cause_unobserved(build.rs:393-426), summing tounclaimedby construction. A0is a measurement; an absent field is "did not report"; the accident list is the finding.4. The mutation that must go red.
an_unreadable_file_with_live_facts_fails_the_generation—crates/indexer/tests/generation_build.rs:3259. It reports the path, not a count.Run as uid 1000 (non-root), so the
chmod 000probe was real rather than degrading to its root fallback arm — worth stating, because that test is vacuous under root.The two residuals, named because they are the reason this is a close and not a hand-wave
Both are recorded in
d0279c0's own message and in the tree:Unclaimed::ProducedNothingstill folds "deleted" and "grew past the size cap" — becauseindex::run_taskfolds both into oneOk(None)(build.rs:1497-1505). This is a finer split than the three causes this issue named, and it sits inside the benign variant, not inside an accident.CHECKallows no fourth value. That is precisely whatunclaimed_cause_unobserved(build.rs:426) reports rather than hides.Neither is silent, and silence is what this issue was about. The door is shut.
Relationship to #115, since the title asserts one
A correct split, not a duplicate. #115 is closed; what closed it does not by itself cover this, because an unclaimed file never produced a
ParseResult::Errorand so never reached #115's predicate. #123's fix works by manufacturing the population for #115's existing gate. Both issues were needed.Not addressed here, and correctly so — the two adjacent facts this issue's own "Related" section flags as recorded-but-not-fixed (
files.parse_errornot restamped by promotion;plugin_activationhaving no MCP surface for refusals) belong to their own work, and the second is substantially answered by #124.🤖 Triage lane, 2026-09-06, master
f6a878acode-index://docs/reason-codesis at 3,979 of its 4,000-token cap, so the next reason code this project mints cannot be documented #184