code-index://docs/reason-codes is at 3,979 of its 4,000-token cap, so the next reason code this project mints cannot be documented #184
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#184
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 by dogfooding during the 2026-09-06 triage session that closed 22 issues, while verifying #155 — whose fix mints a new reason code and lands the resource within 21 tokens of its ceiling.
Measured
21 tokens of headroom. A reason code plus its one-line semantics does not fit in 21 tokens. So the next code this project declares will either go undocumented, or force whoever declares it to trim unrelated prose in the same change.
Why this is a correctness problem, not housekeeping
Reason codes are wire contract here — #80 says so explicitly ("Reason values are wire contract. Renames require compatibility normalization."), and the whole disclosure discipline rests on an agent being able to look one up and learn what it means. A catalogue that cannot grow is a contract that cannot grow.
The immediate pressure is real and already queued:
index_reconcilingto the closed coverage family (crates/indexer/src/coverage.rs:190, catalogued atcrates/mcp-server/src/docs/reason-codes.md:61,97,103) — that is the change that consumed the margin.PackageSet::refused()/RefusedPackagereaching no coverage code at all. Closing it means minting codes.generation_failure_reasonsis seeded fromFAILURE_REASONS) or a producer forUNCLASSIFIED".So this is not a distant ceiling; it is in the path of at least three open issues.
The failure mode to avoid, stated because this repo has the scar
The tempting response is to raise the cap. That is the move this project has repeatedly refused elsewhere and should refuse here:
73ef473trimmed prose rather than raise a ceiling ("The first draft was 26 tokens over and prose was cut, not the ceiling"), and #98's option 3 — "just raise it" — is explicitly rejected in that issue's own text.Note also that the resource cap is not the only ceiling under pressure: #160 measures the startup payload at 16,530 of 16,555 (25 tokens), #98/#133 put
overview_payload_budget_e2eat 25 tokens of 4,300, and #137 adds ~106 uncapped tokens per linked project. Four ceilings, all within ~25 tokens, is a pattern rather than four coincidences — and raising any one of them individually is how the pattern gets hidden.What must NOT be done
Resp::stage's schema doc listing three of the five values the source stamps — stale for two releases. The same drift, one layer out.Shape of a real fix
Two honest options, both of which need someone to choose:
#107's URI grader.startup_payload_budget_e2erecords its two-sided bound.Option 1 is more in keeping with how this tree has solved the same pressure elsewhere. Either way the decision should be taken before the next code is minted, not during.
Verification note
There should be a gate. Today the cap is enforced but nothing warns as it is approached, so this was found by a human-readable measurement during unrelated work rather than by CI. A floor-and-ceiling pair — as
startup_payload_budget_e2euses (MAX 16_555/MIN 10_000) — would make both "it grew past" and "it silently collapsed" visible.🤖 Filed by the triage lane, 2026-09-06, found while verifying #155.
CONFIRMED — and it was worse than filed, in a way that proves your own point about stale prose. Fixed on
lane/provenance(worktree/tmp/cosi-lane-provenance, based onfc329a8).Measured, and the finding you missed
reason-codesrefusal-codesYou measured
reason-codesat 3,979 and it was the one you filed.refusal-codeswas tighter. And the tree's own comment about it, written at the #80 S21 split, says:Stale by 1,356 tokens. That is exactly the drift you cite #72 for, one layer out: the growth half had 10 tokens, not 1,366, and the note designating it as the growth half was the reason nobody looked.
What shipped — option 1, split by family
Six catalogue topics instead of two, plus one new standalone page:
reason-codes(hub: how to read it, the five vocabularies, Coverage)refusal-codes(package/install, signatures, publisher trust)runtime-codes(runtime, operator confirmation, conformance)extraction-codes(what an extractor may say, fact validation)activation-offers(+ the Activation refusal family)code-inventories(owed, retired, declared-unwritten)answer-provenance(#181/#182 — new)The cap was not raised. No code was dropped or merged. Verified: every
##section of the two old files survives the split — the only heading that disappears is## The other half of this catalogue, replaced by a map of all seven.reason_code_registryis green (12 tests), includingevery_declared_code_is_in_the_catalogueand both inventory cross-checks.That
answer-provenancecould be minted at all is the demonstration you asked for: the next code this project declares now fits.The gate you asked for
Your verification note: "Today the cap is enforced but nothing warns as it is approached … A floor-and-ceiling pair would make both 'it grew past' and 'it silently collapsed' visible."
every_doc_topic_keeps_room_to_growrequires 1,400 tokens of headroom on every topic — sized against the largest section the split moved (Coverage, ~1,004 tokens), so a topic can absorb another family-sized block before delivery has to be reconsidered — plus a 100-token floor sized against the shortest real topic this server publishes (cursors, 161) rather than against the catalogue files, which would have been a floor no small topic could satisfy. It prints the widest topic and its headroom on every run.The old
every_doc_topic_fits_the_resource_budget_untruncatedstays: it catches the state where a document is already being served truncated, which is the one this cannot see.Mutations, run:
reason-codes.md→ RED: "at 3178 of 4000 tokens, leaving 822 of the 1400 tokens of headroom this catalogue is required to keep". Note the cap itself was not breached — the old gate would still have been green there, which is the whole point.code-inventories.mdwith a one-line stub → RED on the floor.The drift you predicted, closed structurally
reason_code_registryheld a hand-copied list of three catalogue files. A split into six would have left it grading two thirds of the catalogue while every gate reported green — the #72 shape again. It now derives the population twice over:doc_markdown_files()reads whatDOC_TOPICSpublishes, out ofserver.rs;ONE CATALOGUEsentence every catalogue page carries andanswer-provenancedoes not. The classification is a fact a reader can see, not metadata beside it.every_catalogue_file_carries_codes_of_its_ownthen asserts both directions: a page claiming membership must carry ≥5 codes, and the set of pages not claiming it must equal the declared standalone list exactly. A seventh topic is a decision, not an omission, and a stale declaration fails rather than reads as a comment.Mutations, run: stub
runtime-codes.md→ RED per file (the union of six still cleared the global floor of 60, which is why the check is per file); add"runtime-codes"to the standalone list → RED, because the page declares itself; hardcodecatalogue_files()back to two entries → RED across six registry tests.One thing your issue prompts that I did not do
You note
index_coveragepoints at catalogues containing none of its 17 reason codes. That is a real gap and the split does not close it — the codes still have no home. It needs its own decision about which family they belong to, so it is left for that rather than folded in here.Already fixed on
master— this issue is stale, and it also measured the wrong file as the tightest.Verified against the tree rather than the comment history. The split shipped on
lane/provenanceand is on master.The shape chosen: split by family (option 1), cap unchanged
Measured, current:
reason-codesanswer-provenancerefusal-codesruntime-codesextraction-codesactivation-offerscode-inventoriesThe cap was not raised, and no code was dropped or merged — which is the outcome this issue asked for. Trimming unrelated prose to buy headroom was the failure mode it named, and that is not what happened.
The correction to this issue's own measurement
This was filed about
reason-codesat 3,979. At that revisionrefusal-codeswas at 3,990 — tighter, and unmentioned. The issue identified the right defect through the wrong instance, which does not change the conclusion but is worth recording: a ceiling problem found by looking at one file will generally not be found at its worst point.The gate, and its mutation
every_doc_topic_keeps_room_to_grow(crates/mcp-server/src/server.rs:21435) requires 1,400 tokens of headroom plus a 100-token floor — so the failure fires while a new code still fits, rather than after it no longer does.Mutation (run): appended 60 catalogue rows to
reason-codes.md→The old cap-only gate stayed green at 3,992 — which is precisely the gap this issue was filed about. A cap that only fires once the catalogue is already full cannot protect the next code; a headroom floor can.
One thing to watch
The catalogue has already consumed 341 of its new headroom (
reason-codes2,008 → 2,349 since the split). That is normal growth and well inside the floor, but it means the 1,651 figure above is a snapshot, not a resting state. The gate is what makes that safe to ignore day to day.Closing.