ucn 4.1.3 → 4.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/core/search.js CHANGED
@@ -11,7 +11,7 @@ const path = require('path');
11
11
  const { escapeRegExp, codeUnitCompare, inlineTestRanges, lineInRanges, classDispatchNames } = require('./shared');
12
12
  const { isTestFile } = require('./discovery');
13
13
  const { detectLanguage, getParser, getLanguageModule, langTraits } = require('../languages');
14
- const { getCachedCalls } = require('./callers');
14
+ const { getCachedCalls, _nameBindingReaches } = require('./callers');
15
15
  const { extractImports } = require('./imports');
16
16
 
17
17
  /**
@@ -181,6 +181,7 @@ function usages(index, name, options = {}) {
181
181
  const definitions = options.exclude || options.in
182
182
  ? allDefinitions.filter(d => index.matchesFilters(d.relativePath, options))
183
183
  : allDefinitions;
184
+ const targetFiles = new Set(allDefinitions.map(d => d.file).filter(Boolean));
184
185
 
185
186
  for (const def of definitions) {
186
187
  usagesList.push({
@@ -230,6 +231,19 @@ function usages(index, name, options = {}) {
230
231
  _importedHasDef = true;
231
232
  break;
232
233
  }
234
+ // A module namespace may expose the target through a
235
+ // re-export chain (`import httpx; httpx.URL(...)`,
236
+ // where httpx/__init__.py re-exports URL). Direct-file
237
+ // symbol checks silently dropped these compiler-true
238
+ // usages. Reuse the caller engine's conservative
239
+ // name-ownership chase: yes confirms; unknown stays
240
+ // visible in this raw-usage inventory; only a proven
241
+ // no is filtering evidence.
242
+ if (targetFiles.size > 0 &&
243
+ _nameBindingReaches(index, imp, name, targetFiles) !== 'no') {
244
+ _importedHasDef = true;
245
+ break;
246
+ }
233
247
  }
234
248
  return _importedHasDef;
235
249
  };
@@ -833,40 +847,108 @@ function structuralSearch(index, options = {}) {
833
847
  function example(index, name, options = {}) {
834
848
  index._beginOp();
835
849
  try {
836
- // MEDIUM-8: respect --include-tests. By default, test/fixture/mock files
837
- // are excluded as low-signal examples. When the user passes
838
- // includeTests:true, return matches from those files too.
839
- const exclude = options.includeTests
840
- ? []
841
- : ['test', 'spec', '__tests__', '__mocks__', 'fixture', 'mock'];
842
- const usageResults = usages(index, name, {
843
- codeOnly: true,
844
- className: options.className,
845
- // Scope examples to files matching --file (the flag was accepted but
846
- // silently ignored before).
850
+ // Resolve the exact target first. `--file`/stable handles identify the
851
+ // DEFINITION; they must never restrict candidate call sites to that same
852
+ // file (the old implementation did exactly that, selecting recursive or
853
+ // sibling calls while hiding every external example).
854
+ const { def } = index.resolveSymbol(name, {
847
855
  file: options.file,
848
- exclude,
849
- context: 5
856
+ className: options.className,
857
+ line: options.line,
850
858
  });
859
+ if (!def) return null;
860
+
861
+ // Candidate identity comes from the contracted caller engine, not raw
862
+ // same-name usages. This prevents an example for Java A.equals from being
863
+ // selected out of B.equals and lets module re-exports/receiver evidence
864
+ // participate exactly as they do in about/context/impact.
865
+ const rawCallers = index.findCallers(name, {
866
+ targetDefinitions: [def],
867
+ collectAccount: true,
868
+ });
869
+ const candidates = [
870
+ ...rawCallers.filter(c => c.tier !== 'unverified')
871
+ .map(c => ({ ...c, evidenceTier: 'confirmed' })),
872
+ ...rawCallers.filter(c => c.tier === 'unverified')
873
+ .map(c => ({ ...c, evidenceTier: 'unverified' })),
874
+ ...(rawCallers.unverifiedEntries || [])
875
+ .map(c => ({ ...c, evidenceTier: 'unverified' })),
876
+ ].filter(c => !c.functionReference && c.calledAs !== 'bound');
877
+
878
+ // Dedupe by site, preferring confirmed evidence when a parser shape
879
+ // reaches the same line through more than one resolution path.
880
+ candidates.sort((a, b) =>
881
+ (a.evidenceTier === b.evidenceTier ? 0 : (a.evidenceTier === 'confirmed' ? -1 : 1)) ||
882
+ codeUnitCompare(a.relativePath || a.file || '', b.relativePath || b.file || '') ||
883
+ (a.line || 0) - (b.line || 0));
884
+ const seenSites = new Set();
885
+ const allCalls = [];
886
+ for (const candidate of candidates) {
887
+ const rel = candidate.relativePath || path.relative(index.root, candidate.file);
888
+ const siteKey = `${rel}:${candidate.line}`;
889
+ if (seenSites.has(siteKey)) continue;
890
+ seenSites.add(siteKey);
891
+ const filePath = path.isAbsolute(candidate.file)
892
+ ? candidate.file : path.join(index.root, rel);
893
+ let lines = [];
894
+ try { lines = index._readFile(filePath).split('\n'); } catch { /* fail-loud metadata stays on the project */ }
895
+ const at = candidate.line - 1;
896
+ allCalls.push({
897
+ ...candidate,
898
+ file: filePath,
899
+ relativePath: rel,
900
+ usageType: 'call',
901
+ content: candidate.content || lines[at] || '',
902
+ before: lines.slice(Math.max(0, at - 5), at),
903
+ after: lines.slice(at + 1, at + 6),
904
+ });
905
+ }
851
906
 
852
- const calls = usageResults.filter(u => u.usageType === 'call' && !u.isDefinition);
907
+ const callSiteInScope = call => {
908
+ if (!options.callSiteFile) return true;
909
+ const resolved = index.resolveFilePathForQuery(options.callSiteFile);
910
+ if (typeof resolved === 'string') return call.file === resolved;
911
+ return call.relativePath.includes(options.callSiteFile);
912
+ };
913
+ const confirmedAllCalls = allCalls.filter(call =>
914
+ call.evidenceTier === 'confirmed' && callSiteInScope(call));
915
+ const unverifiedAllCalls = allCalls.filter(call =>
916
+ call.evidenceTier === 'unverified' && callSiteInScope(call));
917
+ const includeByTestPolicy = call => {
918
+ if (options.includeTests) return true;
919
+ const fe = index.files.get(call.file);
920
+ return !isTestFile(call.relativePath, fe?.language);
921
+ };
922
+ // A command called `example` must never silently promote a same-name or
923
+ // possible-dispatch candidate into a target example. Select only from the
924
+ // confirmed evidence band; report the unverified pool as an abstention.
925
+ const calls = confirmedAllCalls.filter(includeByTestPolicy);
926
+ const visibleUnverified = unverifiedAllCalls.filter(includeByTestPolicy);
853
927
  if (calls.length === 0) {
854
- // No matches in non-test files. Look at how many WERE excluded so we
855
- // can tell the user there's something they could see with
856
- // --include-tests, instead of saying "no examples found" silently.
857
- if (!options.includeTests) {
858
- const allUsages = usages(index, name, {
859
- codeOnly: true,
860
- className: options.className,
861
- file: options.file,
862
- exclude: [],
863
- context: 0,
864
- });
865
- const excludedCalls = allUsages.filter(u =>
866
- u.usageType === 'call' && !u.isDefinition).length;
867
- if (excludedCalls > 0) {
868
- return { best: null, totalCalls: 0, excludedTestCalls: excludedCalls };
869
- }
928
+ // Tell the user when compiler-shaped candidates exist only in tests.
929
+ if (!options.includeTests && confirmedAllCalls.length > 0) {
930
+ return {
931
+ best: null,
932
+ totalCalls: 0,
933
+ confirmedCalls: 0,
934
+ unverifiedCalls: visibleUnverified.length,
935
+ excludedTestCalls: confirmedAllCalls.length,
936
+ };
937
+ }
938
+ if (visibleUnverified.length > 0) {
939
+ return {
940
+ advisory: 'scored-selection',
941
+ best: null,
942
+ totalCalls: 0,
943
+ confirmedCalls: 0,
944
+ unverifiedCalls: visibleUnverified.length,
945
+ unverifiedCandidates: visibleUnverified.slice(0, 10).map(c => ({
946
+ file: c.relativePath,
947
+ line: c.line,
948
+ content: c.content,
949
+ reason: c.reason || c.resolution || 'identity-unverified',
950
+ })),
951
+ };
870
952
  }
871
953
  return null;
872
954
  }
@@ -916,7 +998,13 @@ function example(index, name, options = {}) {
916
998
  // Advisory command (v4 two-tier surface): scored example selection, not
917
999
  // a verified "best" claim.
918
1000
  if (!options.diverse) {
919
- return { advisory: 'scored-selection', best, totalCalls: calls.length };
1001
+ return {
1002
+ advisory: 'scored-selection',
1003
+ best,
1004
+ totalCalls: calls.length,
1005
+ confirmedCalls: calls.filter(c => c.evidenceTier === 'confirmed').length,
1006
+ unverifiedCalls: visibleUnverified.length,
1007
+ };
920
1008
  }
921
1009
 
922
1010
  // --diverse: cluster call sites by AST argument-shape and return one
@@ -977,6 +1065,8 @@ function example(index, name, options = {}) {
977
1065
  advisory: 'scored-selection',
978
1066
  best,
979
1067
  totalCalls: calls.length,
1068
+ confirmedCalls: calls.filter(c => c.evidenceTier === 'confirmed').length,
1069
+ unverifiedCalls: visibleUnverified.length,
980
1070
  clusters,
981
1071
  totalClusters: clusterList.length,
982
1072
  };
@@ -1027,14 +1117,17 @@ function tests(index, nameOrFile, options = {}) {
1027
1117
  // Resolve --file scoping: find the source file that defines this symbol
1028
1118
  // and only include test files that import from it (directly or via re-exports).
1029
1119
  let sourceFileFilter = null;
1120
+ let targetDefs = [];
1030
1121
  if (options.file && !isFilePath) {
1031
- const defs = index.find(nameOrFile, { exact: true, file: options.file, className: options.className });
1032
- if (defs.length > 0) {
1033
- sourceFileFilter = _buildSourceFileImporters(index, defs);
1122
+ targetDefs = index.find(nameOrFile, { exact: true, file: options.file, className: options.className });
1123
+ if (targetDefs.length > 0) {
1124
+ sourceFileFilter = _buildSourceFileImporters(index, targetDefs);
1034
1125
  }
1035
1126
  // If no defs found, sourceFileFilter stays null → no file scoping applied.
1036
1127
  // The execute handler validates before calling, so this path means
1037
1128
  // the file matched but no exact symbol — fall through gracefully.
1129
+ } else if (!isFilePath) {
1130
+ targetDefs = index.find(nameOrFile, { exact: true, className: options.className });
1038
1131
  }
1039
1132
 
1040
1133
  // Find all test files
@@ -1133,7 +1226,9 @@ function tests(index, nameOrFile, options = {}) {
1133
1226
  let localShadow = false;
1134
1227
  if (!isFilePath) {
1135
1228
  const localDefs = (entry.symbols || []).filter(s => s.name === searchTerm);
1229
+ const targetDefinedHere = !!options.file && targetDefs.some(d => d.file === testPath);
1136
1230
  if (localDefs.length > 0 &&
1231
+ !targetDefinedHere &&
1137
1232
  !(entry.importBindings || []).some(b => b.name === searchTerm)) {
1138
1233
  localShadow = testRanges
1139
1234
  ? localDefs.every(s => lineInRanges(s.startLine, testRanges))
@@ -1179,7 +1274,8 @@ function tests(index, nameOrFile, options = {}) {
1179
1274
  matchType = 'call';
1180
1275
  } else {
1181
1276
  // 'reference' — check if inside string literal
1182
- matchType = strPattern.test(lineContent) ? 'string-ref' : 'reference';
1277
+ matchType = strPattern.test(lineContent) ? 'string-ref' :
1278
+ (usage.inAttribute ? 'unverified-reference' : 'reference');
1183
1279
  }
1184
1280
 
1185
1281
  // className scoping for calls: check receiver
@@ -1188,11 +1284,22 @@ function tests(index, nameOrFile, options = {}) {
1188
1284
  }
1189
1285
 
1190
1286
  // className scoping for references: require class-associated receiver
1191
- if (className && (matchType === 'reference' || matchType === 'string-ref')) {
1287
+ if (className && (matchType === 'reference' || matchType === 'string-ref' ||
1288
+ matchType === 'unverified-reference')) {
1192
1289
  // Bare references (no receiver) like `fn = save` have no class
1193
1290
  // association — skip them. Only keep member-access references
1194
1291
  // where the receiver matches the target class.
1195
- if (!usage.receiver) continue;
1292
+ if (!usage.receiver && matchType !== 'unverified-reference') continue;
1293
+ if (!usage.receiver && matchType === 'unverified-reference') {
1294
+ matches.push({
1295
+ line: usage.line,
1296
+ content: lineContent.trim(),
1297
+ matchType,
1298
+ evidenceTier: 'unverified',
1299
+ reason: 'macro-generated-reference',
1300
+ });
1301
+ continue;
1302
+ }
1196
1303
  if (!dispatchNames.has(usage.receiver) &&
1197
1304
  !(instanceTypeMap && dispatchNames.has(instanceTypeMap.get(usage.receiver)))) {
1198
1305
  continue;
@@ -1275,6 +1382,90 @@ function tests(index, nameOrFile, options = {}) {
1275
1382
  }
1276
1383
  }
1277
1384
 
1385
+ // Compiler-shaped caller supplement (trust command arm): the literal
1386
+ // usage scan above is excellent for imports/type/string references, but
1387
+ // receiver aliases and re-exported module calls are owned by the caller
1388
+ // engine. Merge its CONFIRMED exact-target test sites so `tests` cannot
1389
+ // miss calls that `about`/`impact` already know about. For a globally
1390
+ // unique callable name, also retain account-unverified sites under the
1391
+ // explicit `unverified-call` label: independent compiler/LSP evaluation
1392
+ // shows these contain real interface/trait dispatch that a test-discovery
1393
+ // command must not silently drop. Repeated names never receive that broad
1394
+ // supplement because it would leak sibling classes/files.
1395
+ if (!isFilePath && targetDefs.length > 0) {
1396
+ const testInfo = new Map(testFiles.map(t => [t.path, t]));
1397
+ const callerSites = [];
1398
+ const globallyUniqueTarget = index.find(searchTerm, { exact: true }).length === 1;
1399
+ for (const def of targetDefs) {
1400
+ const raw = index.findCallers(searchTerm, {
1401
+ targetDefinitions: [def],
1402
+ collectAccount: true,
1403
+ });
1404
+ callerSites.push(
1405
+ ...raw.map(c => ({ ...c, _testEvidenceTier: 'confirmed' })),
1406
+ ...(globallyUniqueTarget ? (raw.unverifiedEntries || []).map(c => ({
1407
+ ...c,
1408
+ _testEvidenceTier: 'unverified',
1409
+ })) : []),
1410
+ );
1411
+ }
1412
+
1413
+ for (const site of callerSites) {
1414
+ const info = testInfo.get(site.file);
1415
+ if (!info) continue;
1416
+ if (info.testRanges && !lineInRanges(site.line, info.testRanges)) continue;
1417
+ // For a repeated name, the source-import scope is an additional
1418
+ // identity guard. For a globally unique name, exact-target caller
1419
+ // evidence is stronger than filesystem layout: workspace-level
1420
+ // Rust tests, Go black-box packages, and generated test trees may
1421
+ // exercise a crate/package without importing the defining file.
1422
+ // Unverified sites remain visibly tiered; they are not promoted.
1423
+ if (sourceFileFilter && !globallyUniqueTarget && !sourceFileFilter.has(site.file)) continue;
1424
+ // A bare callback/reference/call can bind a standalone function
1425
+ // with the same name, but it cannot identify a class method
1426
+ // target. Use the parser's call-kind bit rather than requiring a
1427
+ // textual receiver: fluent chains such as `.addStaticBlock(...)`
1428
+ // have a call receiver but no simple receiver identifier. Rust
1429
+ // proc-macro attribute references are handled by the AST usage
1430
+ // branch above as explicitly unverified references.
1431
+ if (className && !site.isMethod) continue;
1432
+ if (excludeArr.length > 0 &&
1433
+ !index.matchesFilters(info.entry.relativePath, { exclude: excludeArr })) continue;
1434
+ const localSameName = (info.entry.symbols || []).some(s => s.name === searchTerm);
1435
+ const importsTargetName = (info.entry.importBindings || []).some(b => b.name === searchTerm);
1436
+ const explicitlyScopedToLocal = !!options.file && targetDefs.some(d => d.file === site.file);
1437
+ if (localSameName && !importsTargetName && !explicitlyScopedToLocal && !site.receiver) continue;
1438
+
1439
+ let fileResult = results.find(r => r.file === info.entry.relativePath);
1440
+ if (!fileResult) {
1441
+ fileResult = { file: info.entry.relativePath, matches: [] };
1442
+ results.push(fileResult);
1443
+ }
1444
+ if (fileResult.matches.some(m => m.line === site.line &&
1445
+ ['call', 'unverified-call'].includes(m.matchType))) continue;
1446
+ fileResult.matches = fileResult.matches.filter(m =>
1447
+ !(m.line === site.line && m.matchType === 'test-case'));
1448
+ fileResult.matches.push({
1449
+ line: site.line,
1450
+ content: (site.content || index.getLineContent(site.file, site.line) || '').trim(),
1451
+ matchType: site._testEvidenceTier === 'confirmed' ? 'call' : 'unverified-call',
1452
+ evidenceTier: site._testEvidenceTier,
1453
+ ...(site.resolution && { resolution: site.resolution }),
1454
+ ...(site.reason && { reason: site.reason }),
1455
+ });
1456
+ }
1457
+
1458
+ for (const fileResult of results) {
1459
+ fileResult.matches.sort((a, b) => (a.line || 0) - (b.line || 0) ||
1460
+ codeUnitCompare(a.matchType || '', b.matchType || ''));
1461
+ if (options.callsOnly) {
1462
+ fileResult.matches = fileResult.matches.filter(m =>
1463
+ ['call', 'test-case', 'unverified-call'].includes(m.matchType));
1464
+ }
1465
+ }
1466
+ results.sort((a, b) => codeUnitCompare(a.file || '', b.file || ''));
1467
+ }
1468
+
1278
1469
  return results;
1279
1470
  } finally { index._endOp(); }
1280
1471
  }
@@ -1304,6 +1495,25 @@ function _buildSourceFileImporters(index, defs) {
1304
1495
  }
1305
1496
  }
1306
1497
 
1498
+ // Go imports own packages, not individual files. The resolver represents
1499
+ // a package import with one deterministic file (for example active_help.go),
1500
+ // so starting the reverse walk from only command.go loses real importers
1501
+ // of other declarations in that same package. Expand only languages whose
1502
+ // declared package scope is the directory; JS/TS/Python files in one
1503
+ // directory remain distinct modules, and Java imports remain class-exact.
1504
+ for (const srcPath of [...sourceAbsPaths]) {
1505
+ const srcEntry = index.files.get(srcPath);
1506
+ if (langTraits(srcEntry?.language)?.packageScope !== 'directory') continue;
1507
+ const srcDir = path.dirname(srcPath);
1508
+ for (const [candidatePath, candidateEntry] of index.files) {
1509
+ if (candidateEntry.language === srcEntry.language &&
1510
+ path.dirname(candidatePath) === srcDir &&
1511
+ !isTestFile(candidateEntry.relativePath, candidateEntry.language)) {
1512
+ sourceAbsPaths.add(candidatePath);
1513
+ }
1514
+ }
1515
+ }
1516
+
1307
1517
  // BFS through the export graph: walk from source files outward through
1308
1518
  // re-export chains. At each hop, verify the intermediate file actually
1309
1519
  // exports the target symbol (prevents overmatching barrels that import
@@ -1352,10 +1562,21 @@ function _buildSourceFileImporters(index, defs) {
1352
1562
  candidateDirs.add(path.join(srcDir, td));
1353
1563
  }
1354
1564
  // Java convention: src/main/java/com/pkg → src/test/java/com/pkg
1565
+ let javaTestPackageDir = null;
1355
1566
  if (srcDir.includes(path.sep + 'main' + path.sep)) {
1356
- candidateDirs.add(srcDir.replace(path.sep + 'main' + path.sep, path.sep + 'test' + path.sep));
1567
+ javaTestPackageDir = srcDir.replace(path.sep + 'main' + path.sep, path.sep + 'test' + path.sep);
1568
+ candidateDirs.add(javaTestPackageDir);
1357
1569
  }
1358
1570
 
1571
+ // Cargo integration tests may be nested (`tests/testsuite/foo.rs`).
1572
+ // Derive the crate root from its conventional src/ segment; a
1573
+ // workspace can contain many independent crate-local test trees.
1574
+ const rustSrcMarker = path.sep + 'src' + path.sep;
1575
+ const rustSrcAt = srcEntry.language === 'rust' ? srcPath.lastIndexOf(rustSrcMarker) : -1;
1576
+ const rustIntegrationRoot = rustSrcAt >= 0
1577
+ ? path.join(srcPath.slice(0, rustSrcAt), 'tests')
1578
+ : null;
1579
+
1359
1580
  for (const [absPath, fe] of index.files) {
1360
1581
  if (importers.has(absPath)) continue; // already included
1361
1582
  if (!isTestFile(fe.relativePath, fe.language) &&
@@ -1380,21 +1601,22 @@ function _buildSourceFileImporters(index, defs) {
1380
1601
  continue;
1381
1602
  }
1382
1603
 
1383
- // Java: same-package tests need no import statement either — a
1384
- // test file in the same directory sees the source's package
1385
- // members directly (fix #244: tests --file silently dropped
1386
- // MathIntegrationTest.java while affected-tests found it).
1387
- if (srcEntry.language === 'java' && testDir === srcDir) {
1604
+ // Java: same-package tests need no import statement either. The
1605
+ // source and test packages can be physical mirrors under
1606
+ // src/main and src/test, and ANY test class in that package may
1607
+ // exercise the target (not only TargetNameTest.java).
1608
+ if (srcEntry.language === 'java' &&
1609
+ (testDir === srcDir || testDir === javaTestPackageDir)) {
1388
1610
  importers.add(absPath);
1389
1611
  continue;
1390
1612
  }
1391
1613
 
1392
- // Rust: Cargo integration tests live in <crate-root>/tests/ and
1393
- // import via the crate's PACKAGE name, which the import resolver
1394
- // does not map to project files (fix #244).
1614
+ // Rust: Cargo integration tests live anywhere below
1615
+ // <crate-root>/tests/ and import via the crate's PACKAGE name,
1616
+ // which the import resolver does not map to project files.
1395
1617
  if (srcEntry.language === 'rust' &&
1396
- path.basename(testDir) === 'tests' &&
1397
- srcPath.startsWith(path.dirname(testDir) + path.sep)) {
1618
+ rustIntegrationRoot &&
1619
+ (absPath === rustIntegrationRoot || absPath.startsWith(rustIntegrationRoot + path.sep))) {
1398
1620
  importers.add(absPath);
1399
1621
  continue;
1400
1622
  }
package/core/tracing.js CHANGED
@@ -23,7 +23,7 @@ const path = require('path');
23
23
  const { escapeRegExp, codeUnitCompare, inlineTestRanges, lineInRanges, classDispatchNames } = require('./shared');
24
24
  const { isTestFile } = require('./discovery');
25
25
  const { getCachedCalls } = require('./callers');
26
- const { detectLanguage, getLanguageModule } = require('../languages');
26
+ const { getLanguageModule } = require('../languages');
27
27
 
28
28
  /**
29
29
  * Contract-mode caller expansion for the tree commands. Memoizes the full
@@ -1244,7 +1244,7 @@ function affectedTests(index, name, options = {}) {
1244
1244
  // functions (#[test] fns in Rust's #[cfg(test)] mods, Go Test*)
1245
1245
  // live in production-path FILES but are tests themselves — the
1246
1246
  // language's getEntryPointKind says so; they need no coverage.
1247
- for (const [fp, fe] of index.files) {
1247
+ for (const [, fe] of index.files) {
1248
1248
  if (isTestFile(fe.relativePath, fe.language)) continue;
1249
1249
  const langModule = getLanguageModule(fe.language);
1250
1250
  const kindOf = langModule?.getEntryPointKind;
@@ -0,0 +1,158 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Command trust matrix — executable inventory of what proves each command.
5
+ *
6
+ * This is intentionally not a table of accuracy percentages. It records the
7
+ * independent evidence or invariant that is capable of falsifying each
8
+ * command's documented claim. test/trust-matrix.test.js fails closed when a
9
+ * canonical command is added without an entry or when a referenced proof
10
+ * artifact disappears.
11
+ */
12
+
13
+ const PROOF_CATALOG = Object.freeze({
14
+ 'oracle-callers': {
15
+ kind: 'external-oracle',
16
+ artifact: 'eval/run-oracle-eval.js',
17
+ claim: 'Compiler/LSP references score confirmed/unverified caller edges and semantic recall.',
18
+ },
19
+ 'oracle-callees': {
20
+ kind: 'external-oracle',
21
+ artifact: 'eval/run-oracle-eval.js',
22
+ claim: 'The same compiler/LSP edges are re-read from caller scope to score callee answers.',
23
+ },
24
+ 'oracle-symbols': {
25
+ kind: 'external-oracle',
26
+ artifact: 'eval/run-oracle-eval.js',
27
+ claim: 'Compiler/LSP symbols gate definition discovery, pinning, and extraction.',
28
+ },
29
+ 'oracle-references': {
30
+ kind: 'external-oracle',
31
+ artifact: 'eval/run-oracle-eval.js',
32
+ claim: 'Compiler/LSP code references gate usages, direct tests, and confirmed examples.',
33
+ },
34
+ 'oracle-deadcode': {
35
+ kind: 'external-oracle',
36
+ artifact: 'eval/run-deadcode-eval.js',
37
+ claim: 'Every sampled dead-code claim is challenged with compiler/LSP references.',
38
+ },
39
+ conservation: {
40
+ kind: 'accounting-invariant',
41
+ artifact: 'test/conservation.test.js',
42
+ claim: 'Observed text occurrences partition without unexplained loss.',
43
+ },
44
+ 'cross-language-fixtures': {
45
+ kind: 'independent-fixture',
46
+ artifact: 'test/cross-language.test.js',
47
+ claim: 'Equivalent language fixtures assert the command contract across supported parsers.',
48
+ },
49
+ 'command-fixtures': {
50
+ kind: 'independent-fixture',
51
+ artifact: 'test/command-coverage.test.js',
52
+ claim: 'Behavioral fixtures assert output semantics and negative cases.',
53
+ },
54
+ 'graph-invariants': {
55
+ kind: 'algebraic-invariant',
56
+ artifact: 'test/command-coverage.test.js',
57
+ claim: 'Dependency duality, traversal depth, cycle, and export invariants are checked.',
58
+ },
59
+ 'surface-parity': {
60
+ kind: 'architecture-invariant',
61
+ artifact: 'test/parity-test.js',
62
+ claim: 'CLI, MCP, and interactive surfaces dispatch the same canonical handler.',
63
+ },
64
+ 'systematic-options': {
65
+ kind: 'combinatorial-invariant',
66
+ artifact: 'test/systematic-test.js',
67
+ claim: 'Supported command/flag combinations execute with stable envelopes.',
68
+ },
69
+ 'git-fixtures': {
70
+ kind: 'integration-fixture',
71
+ artifact: 'test/command-coverage.test.js',
72
+ claim: 'Temporary Git histories assert diff attribution and composed checks.',
73
+ },
74
+ 'framework-fixtures': {
75
+ kind: 'adversarial-fixture',
76
+ artifact: 'test/feature.test.js',
77
+ claim: 'Positive and confusable framework shapes test advisory detection.',
78
+ },
79
+ 'protocol-fixtures': {
80
+ kind: 'protocol-invariant',
81
+ artifact: 'test/regression-mcp.test.js',
82
+ claim: 'Stateful expansion and MCP envelopes are checked end-to-end.',
83
+ },
84
+ 'performance-budget': {
85
+ kind: 'performance-gate',
86
+ artifact: 'eval/run-performance-gate.js',
87
+ claim: 'Cold indexing, warm cache, semantic-query p95, and memory stay within budgets.',
88
+ },
89
+ });
90
+
91
+ function row(claim, proofs, performanceClass, decisionSafety, oracleReason = null) {
92
+ return Object.freeze({ claim, proofs: Object.freeze(proofs), performanceClass, decisionSafety, oracleReason });
93
+ }
94
+
95
+ const COMMAND_TRUST_MATRIX = Object.freeze({
96
+ about: row('tiered-semantic', ['oracle-callers', 'oracle-callees', 'conservation', 'surface-parity'], 'semantic-query', 'review-required'),
97
+ context: row('tiered-semantic', ['oracle-callers', 'oracle-callees', 'conservation', 'surface-parity'], 'semantic-query', 'review-required'),
98
+ impact: row('tiered-semantic', ['oracle-callers', 'conservation', 'surface-parity'], 'semantic-query', 'review-required'),
99
+ blast: row('tiered-derived', ['oracle-callers', 'conservation', 'command-fixtures', 'surface-parity'], 'graph-query', 'review-required'),
100
+ smart: row('tiered-derived', ['oracle-callees', 'oracle-symbols', 'command-fixtures', 'surface-parity'], 'semantic-query', 'review-required'),
101
+ trace: row('tiered-derived', ['oracle-callees', 'conservation', 'command-fixtures', 'surface-parity'], 'graph-query', 'review-required'),
102
+ reverseTrace: row('tiered-derived', ['oracle-callers', 'conservation', 'command-fixtures', 'surface-parity'], 'graph-query', 'review-required'),
103
+ example: row('confirmed-or-abstain-advisory', ['oracle-references', 'command-fixtures', 'surface-parity'], 'semantic-query', 'advisory-only'),
104
+ related: row('advisory-ranking', ['oracle-callers', 'oracle-callees', 'command-fixtures', 'surface-parity'], 'semantic-query', 'advisory-only'),
105
+ brief: row('ast-fact-summary', ['oracle-symbols', 'command-fixtures', 'surface-parity'], 'source-query', 'navigation'),
106
+
107
+ find: row('exact-indexed-definition', ['oracle-symbols', 'cross-language-fixtures', 'surface-parity'], 'symbol-query', 'navigation'),
108
+ usages: row('literal-code-reference-inventory', ['oracle-references', 'cross-language-fixtures', 'surface-parity'], 'project-scan', 'review-required'),
109
+ toc: row('indexed-symbol-accounting', ['cross-language-fixtures', 'command-fixtures', 'surface-parity'], 'project-scan', 'navigation', 'No compiler exposes a portable table-of-contents contract; symbol totals and filters use fixture/accounting invariants.'),
110
+ search: row('literal-or-structural-match', ['cross-language-fixtures', 'command-fixtures', 'systematic-options', 'surface-parity'], 'project-scan', 'navigation', 'Literal results are text-ground exact; structural filters are AST fixture-checked rather than semantic identity claims.'),
111
+ tests: row('tiered-direct-test-evidence', ['oracle-references', 'cross-language-fixtures', 'surface-parity'], 'semantic-query', 'review-required'),
112
+ affectedTests: row('tiered-transitive-test-evidence', ['oracle-callers', 'oracle-references', 'conservation', 'command-fixtures', 'surface-parity'], 'graph-query', 'review-required'),
113
+ deadcode: row('candidate-not-safe-delete', ['oracle-deadcode', 'cross-language-fixtures', 'command-fixtures', 'surface-parity'], 'project-scan', 'advisory-only'),
114
+ entrypoints: row('framework-advisory', ['framework-fixtures', 'cross-language-fixtures', 'surface-parity'], 'project-scan', 'advisory-only', 'Framework registration/reflection has no universal compiler oracle; positive and confusable framework fixtures define the static claim.'),
115
+ endpoints: row('framework-advisory', ['framework-fixtures', 'cross-language-fixtures', 'surface-parity'], 'project-scan', 'advisory-only', 'Route/client matching is framework-specific and explicitly advisory.'),
116
+
117
+ fn: row('exact-source-extraction', ['oracle-symbols', 'cross-language-fixtures', 'surface-parity'], 'source-query', 'navigation'),
118
+ class: row('exact-source-extraction', ['oracle-symbols', 'cross-language-fixtures', 'surface-parity'], 'source-query', 'navigation'),
119
+ lines: row('exact-file-slice', ['command-fixtures', 'systematic-options', 'surface-parity'], 'source-query', 'navigation', 'The file bytes and validated line bounds are the direct oracle.'),
120
+ expand: row('stateful-protocol', ['protocol-fixtures', 'surface-parity'], 'source-query', 'navigation', 'Expansion is a cache/protocol contract, not a semantic-analysis claim.'),
121
+
122
+ imports: row('static-import-inventory', ['graph-invariants', 'cross-language-fixtures', 'surface-parity'], 'graph-query', 'navigation', 'File import syntax/resolution is checked with language fixtures and graph duality; dynamic imports remain explicit blind spots.'),
123
+ exporters: row('reverse-static-import-inventory', ['graph-invariants', 'cross-language-fixtures', 'surface-parity'], 'graph-query', 'navigation', 'Reverse edges are proven by import/export graph duality.'),
124
+ fileExports: row('static-export-inventory', ['graph-invariants', 'cross-language-fixtures', 'surface-parity'], 'graph-query', 'navigation', 'Static visibility/export shapes use language fixtures; runtime mutation remains outside the claim.'),
125
+ graph: row('static-dependency-traversal', ['graph-invariants', 'cross-language-fixtures', 'surface-parity'], 'graph-query', 'navigation', 'Traversal is an algebraic derivative of the static import graph.'),
126
+ circularDeps: row('static-cycle-detection', ['graph-invariants', 'command-fixtures', 'surface-parity'], 'graph-query', 'navigation', 'Cycle output is checked against known graph fixtures and traversal invariants.'),
127
+
128
+ verify: row('tiered-signature-check', ['oracle-callers', 'cross-language-fixtures', 'command-fixtures', 'surface-parity'], 'semantic-query', 'review-required'),
129
+ plan: row('refactor-preview', ['oracle-callers', 'cross-language-fixtures', 'command-fixtures', 'surface-parity'], 'semantic-query', 'review-required'),
130
+ diffImpact: row('git-diff-derived-impact', ['oracle-callers', 'git-fixtures', 'command-fixtures', 'surface-parity'], 'git-query', 'review-required'),
131
+ check: row('composed-precommit-diagnostic', ['oracle-callers', 'oracle-references', 'git-fixtures', 'command-fixtures', 'surface-parity'], 'git-query', 'review-required'),
132
+
133
+ typedef: row('exact-indexed-type', ['oracle-symbols', 'cross-language-fixtures', 'surface-parity'], 'symbol-query', 'navigation'),
134
+ stacktrace: row('advisory-frame-resolution', ['command-fixtures', 'surface-parity'], 'source-query', 'advisory-only', 'Stack formats and source-map/runtime availability are environment-specific; unresolved frames remain visible.'),
135
+ api: row('static-public-surface', ['graph-invariants', 'cross-language-fixtures', 'command-fixtures', 'surface-parity'], 'project-scan', 'review-required', 'Static exports are the claim; reflection and external consumers are explicitly outside the universe.'),
136
+ stats: row('index-accounting', ['command-fixtures', 'systematic-options', 'surface-parity'], 'project-scan', 'navigation', 'Counts are checked against the built index and deterministic fixture totals.'),
137
+ doctor: row('diagnostic-not-accuracy', ['command-fixtures', 'systematic-options', 'surface-parity'], 'project-scan', 'advisory-only', 'Doctor reports index/evidence limitations and never presents itself as an accuracy oracle.'),
138
+ auditAsync: row('async-advisory', ['cross-language-fixtures', 'command-fixtures', 'surface-parity'], 'project-scan', 'advisory-only', 'Missing-await semantics depend on framework/type flow; findings are advisory and fixture-tested.'),
139
+ orient: row('diagnostic-composition', ['command-fixtures', 'systematic-options', 'surface-parity'], 'project-scan', 'navigation', 'Orient composes index counts, entrypoint hints, and doctor limitations.'),
140
+ });
141
+
142
+ function summarizeCommandTrust() {
143
+ const commands = Object.entries(COMMAND_TRUST_MATRIX);
144
+ const oracleBacked = commands.filter(([, spec]) =>
145
+ spec.proofs.some(id => PROOF_CATALOG[id]?.kind === 'external-oracle')).length;
146
+ const advisoryOnly = commands.filter(([, spec]) => spec.decisionSafety === 'advisory-only').length;
147
+ return {
148
+ commands: commands.length,
149
+ classified: commands.length,
150
+ oracleBacked,
151
+ invariantOrFixtureBacked: commands.length - oracleBacked,
152
+ advisoryOnly,
153
+ unclassified: 0,
154
+ contract: 'proof-classification-not-runtime-accuracy',
155
+ };
156
+ }
157
+
158
+ module.exports = { PROOF_CATALOG, COMMAND_TRUST_MATRIX, summarizeCommandTrust };
package/core/verify.js CHANGED
@@ -5,7 +5,6 @@
5
5
  * as the first argument instead of using `this`.
6
6
  */
7
7
 
8
- const path = require('path');
9
8
  const { detectLanguage, getParser, getLanguageModule, safeParse, langTraits } = require('../languages');
10
9
  const { escapeRegExp, codeUnitCompare } = require('./shared');
11
10
 
package/eslint.config.js CHANGED
@@ -6,7 +6,7 @@ module.exports = [
6
6
  js.configs.recommended,
7
7
  {
8
8
  languageOptions: {
9
- ecmaVersion: 2020,
9
+ ecmaVersion: 'latest',
10
10
  sourceType: 'commonjs',
11
11
  globals: {
12
12
  // Node.js globals
@@ -31,7 +31,7 @@ module.exports = [
31
31
  },
32
32
  rules: {
33
33
  'no-undef': 'error',
34
- 'no-unused-vars': ['warn', { args: 'none', caughtErrors: 'none' }],
34
+ 'no-unused-vars': ['warn', { args: 'none', caughtErrors: 'none', ignoreRestSiblings: true }],
35
35
  'no-redeclare': 'error',
36
36
  'eqeqeq': ['warn', 'smart'],
37
37
  'no-constant-condition': ['error', { checkLoops: false }],