fix(explore): a damped declaration file is a candidate, not a walk start (CG-28) - #2
Conversation
Verified on a real repo — and it says to drop the first commitThe fixture proved the fix works. It could not say what the change costs on a codebase nobody built it for, so I ran it against vitejs/vite (shallow clone: 1,719 files, 13,793 nodes, 32,822 edges). Method: the two commits touch
1. The CG-28 fix costs nothing here
2. The counter-case survives on a real repoQuery: the HMRPayload type and its update variants
3. a9655a2 has a real cost, and it isn't paying for anythingThe entire real-repo delta comes from the other commit, on one query — how does the dev server send an hmr payload to the browser:
A playground test-setup file displacing the HMR server implementation is a worse answer. The mechanism is the same one this PR is about, pointed the other way: dropping interface-owned method seeds re-normalizes the restart vector, so mass moves away from interface-heavy implementation files — And it isn't load-bearing: Delete a9655a2 and nothing I can measure gets worse; keep it and one real query gets a worse top hit. I'd rather this PR be the one line that's actually justified, so I'm proposing to reduce it to that. 4. My own defect, for the recordThe pushed commit carries a leftover I'll hold the rewrite until there's a view on it — say the word and this becomes a single commit with the marker gone, or I'll leave the branch as-is and drop a9655a2 separately if you'd rather keep the history. |
CG-28: on a prose flow query, a declaration-only file outranks the implementation it declares. The damage enters through the RWR restart vector, not through connectivity. `contains` is not a RANK_EDGE, so a declared member is near-isolated and carries almost no walk mass of its own — but the restart vector is uniform over seeds, so since colbymchenry#1638 a platform `.d.ts` contributes one seed per member, and those member names (`body`, `stream`, `metadata`) are exactly what a prose flow query matches. Every such seed divides the restart mass the implementation files are competing for. That is what halves an implementation file's graph mass while the shim's holds steady. Filter the damped files out of the seed set only. They stay candidates, stay reachable, and keep their `score` contribution; this changes where the walk starts and nothing else. The predicate is `isDampedDeclaration` rather than a bare ambient test because it already exempts a file whose declared type the query named — so the counter-case holds: on a query about the declared type the shim still ranks first, at mass 1.0. Fixture (ambient-decls-ts), flow query: storage/metadata.ts 0.137461 -> 0.504025 rank 2 -> 1 storage/stream.ts 0.058601 -> 0.214871 rank 4 -> 2 platform-shims.d.ts 0.184398 -> 0.009459 rank 1 -> 3, still named __tests__/explore-declaration-only.test.ts: 12 passed, 0 failed. Full suite against this base: 31 failed -> 30 failed, and the CG-28 gate is the only difference in the failing set. Verified on vitejs/vite (1,719 files, 13,793 nodes, 32,822 edges), one index shared across arms so ranking is the only variable: zero changed rows against the unpatched base on four prose flow queries, and the type counter-case keeps types/hmrPayload.d.ts at rank 1 (mass 0.185539). The change is inert where it is not needed.
88f9540 to
53da6dc
Compare
|
Merged into Verified on the merged branch myself rather than quoting your numbers: The part I most appreciate is the part you removed. Diagnosing that the damage enters through the restart vector rather than connectivity is what made this one line instead of a penalty retune, and then dropping the interface-owned-method-seed commit because the vite run showed it demoting |
Closes the CG-28 ranking failure in one line.
__tests__/explore-declaration-only.test.tsgoes to 12 passed / 0 failed, and the full suite against this base goes 31 failed → 30 failed with the CG-28 gate as the only difference in the failing set.The mechanism
On a prose flow query, a declaration-only file outranks the implementation it declares. The damage enters through the restart vector, not through connectivity.
containsis not inRANK_EDGES, so a declared member is nearly isolated in the walk graph and carries almost no mass of its own. Its whole effect is that it occupies a seed — and the restart vector is uniform over seeds, so every member divides the restart mass the implementation files are competing for. Since colbymchenry#1638 a platform.d.tscontributes one seed per member, with names (body,stream,metadata) that are exactly what a prose flow query matches. That is the 0.307 → 0.137 halving of an implementation file's mass while the shim's holds steady.So: filter the damped files out of the seed set only. They stay candidates, stay reachable, keep their
scorecontribution. This changes where the walk starts and nothing else.The predicate is
isDampedDeclarationrather than a bare ambient test, and that is what makes the counter-case work: it already exempts a file whose declared type the query named. On a query genuinely about the declared type the shim keeps its seeds and still ranks 1, at mass 1.0.Result on the fixture
Flow query,
ambient-decls-ts:src/storage/metadata.tssrc/storage/stream.tstypes/platform-shims.d.tsVerified on a real repo
The fixture cannot say what the change costs on a codebase nobody built it for, so I ran it against vitejs/vite — 1,719 files, 13,793 nodes, 32,822 edges. The commit touches
src/mcp/tools.tsonly, so one index serves every arm and ranking is the sole variable; two runs of the same build give 0 changed rows..d.tsfiles are either named by the query (exempt) or already below implementation.packages/vite/types/hmrPayload.d.tsstays rank 1 at mass 0.185539, identical patched and unpatched.The change is inert where it isn't needed, and that's the property I most wanted evidence for.
What I removed from this PR
This opened with two commits. The first one — dropping interface-owned method seeds — turned out to be both unnecessary and harmful, and the vite run is what showed it:
packages/vite/src/node/server/hmr.tsplayground/vitestSetup.tsA playground test-setup file displacing the HMR server implementation is a worse answer, and the cause is this same mechanism pointed the other way: dropping interface-owned method seeds re-normalizes the restart vector and moves mass off interface-heavy implementation files (
hmr.tsdeclaresHmrContextand friends). Meanwhile the CG-28 gate passes 12/12 without it. Deleting it costs nothing I can measure; keeping it costs one real query — so it's gone, and this PR is the single line the evidence actually supports.Correction to my first version of this PR
I wrote that "rank is ordered by
graphScore, notscore". The second half is right, the first is not, and the data in my own table showed it:src/lib/bucket.tsat rank 5 carried more graph mass thanplatform-shims.d.tsat rank 3.The comparator tiers first —
pinned,named,central,entry— and orders bygraphScorewithin a tier. Entry files fill the top ranks by descending mass, non-entry the rest by descending mass.What survives, and is the load-bearing part:
scoredoes not order the list. The shim lost onscore(26.25 against 27) and still took rank 1, so theRELEVANCE_KIND_WEIGHTand named-FIRST-tier mitigations — which movescoreand the seed tier — cannot reach this failure.graphScoreis what has to move, and this is the change that moves it.