fix(prompt-hook): close the segment-vocab integrity gaps (#1141, #1142, #1144, #1145, #1146) (#1150)
Five hardening fixes to the #1136 MEDIUM (graph-derived) tier: - #1141: updateNode() now writes the segment vocabulary like insertNode() does — framework post-extract renames (NestJS route prefixing) left the new name permanently unsearchable (the old rows orphaned, the backfill gated on an EMPTY vocab, so even a full re-index re-created the drift). - #1142: new CodeGraph.healSegmentVocabIfEmpty() — the hook opens the graph without sync, so a database migrated from pre-vocab schema kept the MEDIUM tier dormant until some unrelated sync ran. The hook heals on first use (one SELECT when populated; lock-aware, defers to a running sync) and records noop-vocab-empty when it can't. - #1144: a name whose only nodes are file/import kind is skipped instead of falling back to surfacing an import statement as a matched symbol; import specifiers no longer enter the vocab at all (shared isSegmentableKind gate across insertNode/updateNode/rebuild page query) since they can never be surfaced and only inflate rarity statistics. - #1145: plural variant folding is keyed on English plural spelling — bare-s plurals no longer mint a bogus -es sibling (services→servic), unambiguous sibilant-es plurals no longer mint a bogus -s sibling (classes→classe), trailing -ss singulars no longer strip (class→clas); genuinely ambiguous endings (caches/databases) still emit both keys. - #1146: getSegmentCoOccurrence folds variants to their original word inside the SQL (CASE mapping + COUNT(DISTINCT word)) so a plural pair of ONE word can't tie with a genuine two-word match and crowd it past the pre-fold ORDER BY/LIMIT; the JS re-check stays as the honesty layer. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
be55b93d02
commit
35611b92bb
@@ -73,9 +73,31 @@ describe('segmentLookupVariants — light plural folding', () => {
|
||||
it('folds trailing s/es so plurals hit singular segments', () => {
|
||||
expect(segmentLookupVariants('services')).toContain('service');
|
||||
expect(segmentLookupVariants('machines')).toContain('machine');
|
||||
expect(segmentLookupVariants('classes')).toContain('class');
|
||||
});
|
||||
|
||||
it('bare-s plurals no longer mint a bogus -es sibling (#1145)', () => {
|
||||
expect(segmentLookupVariants('services')).toEqual(['services', 'service']);
|
||||
expect(segmentLookupVariants('machines')).toEqual(['machines', 'machine']);
|
||||
});
|
||||
|
||||
it('unambiguous sibilant-es plurals no longer mint a bogus -s sibling (#1145)', () => {
|
||||
expect(segmentLookupVariants('classes')).toEqual(['classes', 'class']);
|
||||
expect(segmentLookupVariants('hashes')).toEqual(['hashes', 'hash']);
|
||||
});
|
||||
|
||||
it('a trailing -ss is a singular, not a plural — no strip (#1145)', () => {
|
||||
expect(segmentLookupVariants('class')).toEqual(['class']);
|
||||
expect(segmentLookupVariants('process')).toEqual(['process']);
|
||||
});
|
||||
|
||||
it('ambiguous endings emit BOTH candidate keys — a wrong exclusive guess would lose the real match', () => {
|
||||
expect(segmentLookupVariants('caches')).toEqual(['caches', 'cach', 'cache']); // cache + s
|
||||
expect(segmentLookupVariants('databases')).toEqual(['databases', 'databas', 'database']); // database + s
|
||||
});
|
||||
|
||||
it('never strips a word below the minimum', () => {
|
||||
expect(segmentLookupVariants('bus')).toEqual(['bus']);
|
||||
expect(segmentLookupVariants('boxes')).toEqual(['boxes']); // -es strip would go sub-minimum
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user