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

Method getSegmentMatches

src/index.ts:1321–1397  ·  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

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