evidence_gaps warns on every reply that the answer may be short, and gives no way to find out which file — index_coverage(path) needs the path you are trying to learn #241
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#241
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 the #184/#205 lane, and independently confirmed by me across an entire working session — which is itself the evidence for the claim.
The fact
Every reply from this server on this repository carries:
The three-state discipline here is correct and I am not disputing it.
partial_sourcesnames the partial files this reply's own body names;partial_sources_in_indexis aCOUNT(DISTINCT path)over the whole index. So when the partial file is not among your results, you get1and[], and the design's own doc calls it exactly right:The defect
The remedy the disclosure names requires the answer it is withholding.
index_coverage(path)reports what a producer said about one path you already know. The reader's question here is which path, and no surface answers it.The options available to a caller are: call
index_coverageon every file in the repository, or ignore the warning. Both are the wrong answer for a disclosure that appears on every single reply.Why this is worse than a missing feature
A warning that cannot be acted on is trained away. I read
partial_sources_in_index: 1several dozen times in one session — while closing issues about disclosure honesty — and never once investigated it, because there was no next step. That is the failure mode: the disclosure is correct, permanent, and therefore invisible. It has become the wallpaper thatcompose_evidence_semantics's own doc comment warns against:The clause is not constant — it fires on a real condition — but from the reader's side it is indistinguishable from constant, because the condition never changes and nothing can be done about it.
What must NOT be done
partial_sourcesis empty. That would collapse "one file in this index is partial and it is not in your results" into "nothing to report" — losing a true fact, and re-creating #216 exactly.partial_sources' reply-scoped semantics. The named-row behaviour is right — a partial file among your results deserves to be named inline. This issue is only about the anonymous remainder.Shape of a fix
The cheapest honest thing is a surface that enumerates them on demand, so the per-reply clause can point at a call that works:
code-index://index/partial-sources), orindex_health/project_overview, which already carry index-wide facts and are called once rather than per-query, orindex_coveragemode that takes no path and returns the partial set.Then the
semanticsstring's last sentence changes fromindex_coverage(path)— which the reader cannot use — to whichever of these exists. That one-line change is most of the value: it converts an unactionable warning into a pointer.Bounded, obviously: the enumeration needs a cap and a
*_truncatedsibling like every other list here, and #205 is the fresh precedent for how (cap + always-present total, so "nothing cut" is a measurement).What a fix must prove
partial_sourcesas it does today.partial_sources_unmeasuredalready models this; the new surface must match it rather than invent a second vocabulary.Related
#216 (where
partial_sourcescame from — this is its unfinished half), #205 (the bounding pattern any list surface should follow), #197 (the payload budget that rules out inlining), #148 (which planned the naming).Filed 2026-09-09 against
master5ac45d9, observed live oncode-index-mcp 0.26.1 (94d7de6).Fixed on
masterate97972c(merged98d3e3f). The anonymous denominator now has a call that names it:resolution_gapscarriesevidence_gaps.partial_source_census—sources(capped per project),total(exact,COUNT(DISTINCT path)),cap,truncated,unmeasured,semantics.Both of this issue's suggested surfaces were wrong, and the measurements say why
A resource would have repeated the defect. MCP resources are not callable by the model in the clients this server targets — a user @-mentions them. Pointing an agent-facing disclosure at a resource hands the agent another next step it cannot take. Zero startup cost, zero reachability.
"A field on
index_health/project_overview" is half-impossible. There is noindex_healthtool — it is a daemon RPC thatproject_overviewcomposes. Andproject_overviewhas 3 tokens of content headroom, so it cannot carry a list at all.And a new tool was ruled out by measurement, not preference: the startup payload sits at 16,503 of 16,515 — 12 tokens of an owed reserve. Median tool entry is 612 tokens. Even making
index_coverage'spathoptional is ~+1 token of JSON schema, which breaches a reserve that "may not get worse".resolution_gapstakes no required argument, is index-wide, is called deliberately rather than per query, and itsunresolvedcounts are FLOORS because of partial sources — so the census belongs beside them. It is rendered from thePartialSourceProbethe grader already takes for every reply, so the census rows andpartial_sources_in_indexcannot disagree, and it costs zero extra queries.Cost
tools/list+initialize)resolution_gapsThe +131 is attributed and re-recorded under the mechanism #235 shipped hours earlier —
plugin-wpf11786→11917 — and isolated by reverting one clause: with the census forced toNonethe tier measures 11786 exactly, so the whole move is the census and #243's hint rewrite costs zero there. It lands on one question; the other eighteen are byte-identical. 37 tokens were trimmed back before recording (the composed clause now points at the census rather than repeating its sentence).Mutations
15 run, 15 RED, 0 survivors. The ones that decide it:
partial_source_census: Noneunconditionally → RED: "the call the clause names must ANSWER:resolution_gapscarried nopartial_source_census.sourcesat all, so following the pointer lands the reader exactly whereindex_coverage(path)did." Note the lane's own honesty here: under M7 the composed clause still reads perfectly; only following it finds nothing. That is this issue in one line.sources: (total > 0).then(...)is the #216 shape and reds.sources: [], total: 0: "there is no list to be empty when nobody was asked."totalfrom the page rather than the population → RED twice, unit and e2e at the 501-file cap.The three-state discipline this issue insisted on is intact and graded in all three states.
Two gates caught the lane mid-work
evidence_semantics_registryG1 caught a first draft citing`evidence_gaps.partial_source_census`— which passed G3 only because the prefix stopped the token matching a field name: a citation answering to nothing, wearing a longer name. Anddisclosure_contract_e2e's clean-index rule neededresolution_gapscarved out as a measurement (assertingsources: [],total: 0, semantics) with acarved == 1guard so the exemption cannot be for nobody.An undisclosed limit found while working, worth its own issue
search_texton the exact phrase"search_text on its name confirms whether"returnstotal: 0while that string is inserver.rs— a Rust\-continued literal splits it across source lines, and the trigram index sees the raw bytes. Nothing in the reply discloses that a phrase can be defeated by a line continuation. Same class as the 3-character floor, which #52 does disclose. Filing separately.Verification:
fmt0 ·clippy -D warnings0 · rustdoc 0 ·cargo test --workspace331 · both e2e legs 0 ·corpus_ratchetbaseline unmoved ·precision_gate7/7 phantoms=0.Closing.
answer_provenancewas byte-identical: nothing says which generation answered #245