Repository navigation
SigMap 8.84.0
Minor. verify says what it checked, and no longer reads as proof when it checked nothing (#989, #1007, #998); the installed-library index reads a package through its barrels instead of reporting it empty (#990); and the generated map stops depending on where the repository is checked out (#993), with five published statements that ran ahead of their measurement corrected and pinned by a test (#992). All of it landed as PR #1035 (tracking issue #1034). Two behaviours change for anyone who gates CI on verify: a usage error now exits 2 (it was 1), and a run that found no issue but could not vouch for its answer, because the index is missing or stale, exits 3 (it was 0). The npm package gains one file (224 → 225): src/verify/coverage.js. Retrieval is not touched (src/retrieval and src/eval are unchanged), but the published token-reduction average moves 95.7% → 95.4% because the map now keeps more sections at the same budget (see Changed).
Added
verifynames what it checked and what it did not (#989 items 1, 3 and 4; #1007) —verifyis a name-level linter and its output read as proof. Every run now prints what it checked (checked 3 claims — 1 file path · 1 backticked call · 1 npm script) and what it did not (not checked: calls in fenced or raw code · member calls (obj.method()) · library APIs (named imports from, and members of, installed libraries)), in the terminal, in--json(summary.claims,summary.coverage,summary.repoSymbolsIndexed;summary.checksis unchanged), in the HTML report (an amber banner and a scope line) and in theverify_suggestionMCP tool. An answer that names nothing checkable prints "nothing to check" and never a green tick. A skipped symbol check is named in both the clean and the failing path (#1007: with no index the symbol set is empty, the fake-symbol pass does not run, and the report used to say "no hallucinations detected" anyway). The README, the CLI reference, the verify guide and the tool description state the scope, drop "every fabrication" and "no competitor", and point attsc/pyrightfor whatverifycannot see.- A distinct exit code when the index cannot vouch for the answer (#989) —
0no issue found against a current index ·1at least one issue ·2usage error (no argument, a missing path, a directory, an unreadable file) ·3no issue found but the index is missing or stale, or its symbol check did not run. A finding is1whatever the index says. Staleness uses the same rule asjudgeandask(a source file newer than the context file), and installed libraries alone no longer make a run with no repository index look checked. - The installed-library index reads a package through its barrels,
typesVersions, theexportsmap and@types(#990 items 1 and 2) — the index read only a package's entry declaration file, so a package that keeps its names behindexport * from './…'read as empty while the output said it grounded against it.resolveEntrynow finds the entry the way TypeScript does (types/typings, thetypescondition ofexports,typesVersionsagainst a fixed assumed compiler so the answer is the same on every machine,index.d.ts,main, thennode_modules/@types/<dep>including@types/scope__name), andreadDtsClosurefollowsexport *andexport * as nsthrough relative specifiers (./x,./x.js,./x.ts), through another installed package and through a subpath of the package itself, with cycle safety and read limits. What it could not enumerate (a missing file, a limit hit, anexport =namespace) marks the librarypartial, and the footer says a name absent from a partial library is not proof. Theverify_suggestionfooter now lists each library with its name count and says "no readable types — library imports not checked" instead of "Grounded against " for one it read nothing from. A cache entry records every file it was read from and is valid only while all of them are unchanged (cold build of 45 libraries about 144 ms, warm about 4 ms). scripts/measure-lib-index.mjsandbenchmarks/lib-index-sample.json(#990) — a pinned sample of 46 popular packages (and 13@typespackages) and the script that counts the names the index reads from each. On the sample, 18 of 46 packages read as 0 names before and none do now: zod 1 → 302, rxjs 0 → 228, date-fns 0 → 459, valibot 736, ramda 316, vue 361. 14 of the 46 arepartial, mostlyexport =packages (lodash, express, debug, koa, ws).scripts/check-path-independence.mjs(#993) — copies a repository to checkout paths of different length, generates the map in each and exits 1 if two disagree (the wall-clock line is the only line allowed to differ). It copies withpreserveTimestamps, because the drop order ranks by file age.writeAll(fd, text)(#998) — a synchronous write that retries a full pipe and ignores a reader that closed early, the pattern the benchmark gates already used, now the one way the CLI core prints a one-shot result.
Changed
verifyexit codes (#989, #998) — see the top of this entry. The two existing tests that pinned exit1for a usage error now pin2, and the one that expected a clean verdict with no repository index now expects the qualified one.- The token budget prices a section by the path it renders, and the generated map is a fixed point on its first run (#993) —
applyTokenBudgetpriced each section by its absolute path while the heading renders the repository-relative one, so the same commit lost sections the deeper it was cloned. On a realginclone, the same commit gave 72, 65, 61 and 55 sections at checkout paths of 79, 135, 195 and 255 characters; it now gives 83 at all four, andcobra,clickandexpressare identical at all four depths. It also classified files by the absolute path, so a checkout under a directory namedtest,testsormocksturned every file into a test or a mock, and the module grouping readprocess.cwd()instead of the project root. Separately, the first run was not a fixed point: the second run indexed the file the first one wrote (.github/copilot-instructions.md) and the third indexed the second (3, 4, 4 sections with changing bytes; now 3, 3, 3 with identical bytes). An adapter's output that is entirely generated is no longer indexed, and for a human-owned file such asCLAUDE.mdorAGENTS.mdonly the lines above the managed section are. The wall-clock stays one trailingUpdated:line (the #683 layout) and a test now pins that. - Five published statements that ran ahead of their measurement are corrected, and a test pins them (#992) — "no per-repo tuning" and "blind selection" (the retrieval benchmark pins
srcDirsfor all 21 repositories inbenchmarks/config-overrides.json; the generalization page now says so and puts the zero-config third-party figure, 55.3% over 208 tasks in 35 repositories, beside the 80.4%); "Hidden files … 0 with SigMap" (the 0 was a literal; the saved run's owndroppedCountis 4,555 files the token budget leaves out of the written map, still reachable throughsigmap ask, against 5,335 without SigMap); the Zenodo record (its results file hasfinal_tokens= 0 in all 405 rows, so every link to it now says so); "a 43.7% reduction across 105 real coding tasks" (a prompt-weight model, now called modeled); and "5.9× lift" (80.4% over a random-file baseline of 13.6%, now stated as such beside the 2.35× against a content-search baseline).test/integration/published-claims.test.jsfails if any of the phrases returns without its qualifier. - The retrieval gate's
hardfloor moves from 70.0% to 68.0% — a loosening of the gate (#1034, PR #1035) — thehardsplit scores this repository's own source, so it moves with the indexed file set (the gate's own note says so). The v8.83.0 tip read 63 of 90 (70.0%) with no headroom; this release adds one indexed module and edits six more, and reads 62 of 90 (68.9%). The floor is a constant (--min, default0.70), not derived from the stored baseline, so re-saving the baseline does not clear it; it is now0.68, which is 62 of 90 and still 0 tasks of headroom. No ranking code changed and nothing was edited to chase a benchmark query.minedreads 40 of 60 (66.7%),easy18 of 20. - Published metrics. Hit@5 (80.4%), the task-success proxy (60.0%, 63 of 105), prompt reduction (43.7%), test-discovery F1 (98.0%), the third-party gate (115 of 208), the grounding corpus and the hallucination guard reproduce v8.83.0. Five figures move, and each was attributed rather than assumed: a control run of the
v8.83.0tag in the same layout reproduces the saved reports leaf for leaf (the one exception isgin's raw token count, 222,314 → 223,122: the old code counts as source the generated file a previous run left in the shared clone, 47 KB or about 11.8k tokens, and that file differs from run to run), and two hybrid trees, each with one of the two budget changes reverted, split the cause. Token reduction 95.7% → 95.4% (average over 21 repositories; final tokens 258,439 → 280,959, signatures 1,622 → 1,786, files left out of the map 4,745 → 4,555) and the grounded symbols 16,259 → 17,823 (dark 52,218 → 50,595, hallucination-risk share 76.3% → 73.9%) come from pricing sections by their relative path: the hybrid that kept relative pricing reads 95.42% / 281,034 / 17,833, the hybrid that kept absolute pricing 95.66% / 258,399 / 16,257. The benchmark clones sit under a long absolute path, so the old budget charged every section for a prefix its heading never shows, and the published 95.7% depended on where the clones live. The raw-token total and file count (13,674,158 → 13,662,499; 6,594 → 6,593 files) come from no longer counting a generated file as source (the without-SigMap hidden-files figure moves with them, 5,339 → 5,335, and was not isolated further). Two repositories swap MRR (vue-core0.9 → 0.8,svelte0.589 → 0.689; the mean is unchanged), and the honest comparison reads SigMap 92.0% (unchanged) against a grep baseline of 39.2% (49 of 125; it read 40.0%, 50 of 125) — the grep side scans the working tree, documentation included, so the lift reads 2.35× (2.30×). Three runs of the new code on shared clones in three different states give identical reports (0 differing leaves in six reports); the old code could not do that. The quality page's own snapshot boxes carriedsigmap-v8.80-mainand 2026-10-18 since v8.80.0; they now read the current ID and date, and its grounded-symbol table, average (42% → 46% over the 19 repositories whose raw estimate held) and daily savings (GPT-4o$335+→$334+, Haiku$134+→$133+; the monthly$10,000+,$12,000+and$4,000+stand) read the report.
Fixed
verify --json | jqreceived a document cut at 65,536 bytes, and so didreview-prand every other one-shot printer (#998) — stdout is asynchronous when it is a pipe:process.stdout.write(x)returns after the first 64 KB andprocess.exit()then discards what is still queued. All 86 one-shot print sites in the CLI core go throughwriteAllnow (the two that exit from the write callback keep their form) and a test fails if a bare one returns.verify --jsonthrough a pipe: 65,536 → 1,083,545 bytes, equal to the file-redirected size;review-pr --markdown: 65,536 → 121,043.verify <directory>threw a rawEISDIRstack trace (#998) — a missing argument, a missing path, a directory or an unreadable file now print the usage line and exit2, so1keeps meaning "issues found".node:built-in imports were reported as missing packages, and a bare file name (util.js) is no longer reported when the repository has a file of that name (#989).http2anddiagnostics_channeljoin the built-in list, and anode:name that is not a built-in is left alone rather than called fabricated.
Notes
- A limit of the path-independence fix, found by CI on the first push and not fixed here. The checkout path no longer changes the map, but the checkout moment still can on a filesystem with a coarse clock: Linux stamps files from a clock of about 4 ms, so 92 files written in a loop land on 26 distinct modification times, and the budget's comparator sorts by age before signal quality and path.
map-path-independencepassed on macOS and failed on Linux for that reason; the test andcheck-path-independence.mjsnow hold timestamps fixed so they measure the path alone. No real repository showed the residual (four fresh Linux copies ofgingave identical maps; one repository, one run, so it says nothing about how common it is). Breaking recency ties by importance is #993 item 5, left open: it changes which files the budget keeps and needs a per-task measurement of its own. - The "under 10% of runtime exports" half of #990's bar is not met. 14 of the 46 sampled packages are
partial(mostlyexport =namespaces), and the comparison against what the package exports at run time (scripts/measure-lib-index.mjs --runtime) executes each package, so it is off by default and was not run. - Not done, on purpose: callees in fenced and raw code and the held-out set (#989 items 2 and 5); flagging a named import absent from a fully indexed library, and member names of
export =namespaces (#990 items 3 and 4); breaking recency ties (#993 item 5);package.json's description still says "installed libraries". - Outside this repository, and the maintainer's to publish: a corrected Zenodo version (record 19898842 has
final_tokens= 0 in 405 of 405 rows, counted 2026-10-27) and the About texts ofsigmap-benchmark-suiteandsigmap-live. - The retrieval gate has no headroom, again.
hardis exactly 62 of 90 against a floor of 62; any change to the indexed file set can move it by a task either way. A local read from a working tree with uncommitted changes can differ from CI's by one task (a hook-regeneratedAGENTS.mdmoved it 62 → 61 here); measure in a clean worktree.