MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / getSegmentMatches

Method getSegmentMatches

src/index.ts:1322–1398  ·  view source on GitHub ↗

* Graph-derived prompt matching for the front-load hook's MEDIUM tier: * which indexed symbols do these prose words name? "state machine des * commandes" → `OrderStateMachine`, in any human language whose technical * nouns are Latin script — no keyword list involved. * * Precision com

(words: string[], limit: number = 6)

Source from the content-addressed store, hash-verified

1320 * returned symbol is guaranteed to exist right now.
1321 */
1322 getSegmentMatches(words: string[], limit: number = 6): SegmentMatch[] {
1323 if (words.length === 0) return [];
1324 // Variant → original word (plural folding), for coverage accounting.
1325 const variantToWord = new Map<string, string>();
1326 for (const word of words) {
1327 for (const variant of segmentLookupVariants(word)) {
1328 if (!variantToWord.has(variant)) variantToWord.set(variant, word);
1329 }
1330 }
1331 const variants = [...variantToWord.keys()];
1332
1333 // Tier A: co-occurrence. The SQL folds variants back to their original
1334 // word (#1146), so minWords=2 means two distinct PROMPT WORDS — a name
1335 // matching both `service` and `services` can't tie with (or crowd past
1336 // the LIMIT) a genuine two-word match. The JS re-check below recomputes
1337 // the fold from live segments as the honesty layer.
1338 const variantPairs = [...variantToWord.entries()].map(([segment, word]) => ({ segment, word }));
1339 const candidates: Array<{ name: string; matchedWords: Set<string> }> = [];
1340 for (const hit of this.queries.getSegmentCoOccurrence(variantPairs, 2, 24)) {
1341 const matched = this.wordsMatchingName(hit.name, variantToWord);
1342 if (matched.size >= 2) candidates.push({ name: hit.name, matchedWords: matched });
1343 }
1344
1345 // Tier B: single rare word. Only when co-occurrence found nothing — a
1346 // co-occurring name is categorically stronger evidence — and under
1347 // stricter rules, because one word is thin: the word must be ≥5 chars
1348 // (measured FPs: "this", "typo"); the segment must appear in AT LEAST TWO
1349 // names (a concept the codebase is about clusters across names —
1350 // CheckoutService/CheckoutController — while a prose coincidence is a
1351 // singleton: measured FP "deploy to PRODUCTION" → the one name
1352 // matchesNonProductionDir); and the candidate name must have ≥2 segments
1353 // (a bare common verb matching a bare function name — "write" → `write` —
1354 // is prose coincidence, not the user naming a symbol).
1355 if (candidates.length === 0) {
1356 const singleWordVariants = variants.filter((v) => variantToWord.get(v)!.length >= 5);
1357 const counts = this.queries.getSegmentNameCounts(singleWordVariants);
1358 const rare = [...counts.entries()]
1359 .filter(([, n]) => n >= 2 && n <= CodeGraph.SEGMENT_RARITY_CEILING)
1360 .sort((a, b) => a[1] - b[1])
1361 .slice(0, 2);
1362 for (const [variant] of rare) {
1363 const word = variantToWord.get(variant)!;
1364 for (const name of this.queries.getNamesForSegment(variant, 12)) {
1365 if (splitIdentifierSegments(name).length < 2) continue;
1366 candidates.push({ name, matchedWords: new Set([word]) });
1367 }
1368 }
1369 }
1370
1371 // Verify against nodes (the honesty gate) and pick a representative
1372 // definition per name. A name whose only nodes are file/import kind has
1373 // no real definition to point at — surfacing the import statement instead
1374 // reads as a matched symbol but isn't one (#1144) — so it's skipped, the
1375 // same way an orphaned vocab row is. (Import names no longer enter the
1376 // vocab at write time, but rows written before that exclusion persist
1377 // until the next full index.)
1378 const out: SegmentMatch[] = [];
1379 const seen = new Set<string>();

Callers 2

mainFunction · 0.80

Calls 10

wordsMatchingNameMethod · 0.95
segmentLookupVariantsFunction · 0.90
splitIdentifierSegmentsFunction · 0.90
hasMethod · 0.80
getSegmentNameCountsMethod · 0.80
getNamesForSegmentMethod · 0.80
getMethod · 0.65
getNodesByNameMethod · 0.65
setMethod · 0.45

Tested by

no test coverage detected