Repository navigation
SigMap 8.80.0
Minor. The Python AST tier starts one process per thousand files instead of one per file, sigmap mcp install writes the config files Claude Code, Codex CLI and OpenCode actually read, and the third-party corpus reaches PHP, C#, Swift, Kotlin and Vue (#970, PR #1003; #994, PR #1002, from @mikemikimike; #984, second slice, PR #1001). #970 and #984 stay open: one of #970's acceptance criteria is not met as written (see Notes), and #984's target is at least 200 questions over at least 30 repositories, of which this is 128 over 25.
Added
python_ast.py --batchandpython.prefetch()(#970, PR #1003) — the default Python extractor used to startpython3 python_ast.py <file>for every.pyfile: 2,933 process starts on Django, 182.2 s against 3.7 s for the regex tier.--batchreads one JSON-encoded path per stdin line and answers a version line and then one{path, sigs}line per file, flushed per file so a crash keeps every earlier answer; a file that cannot be read or parsed answers[], as the single-file call does.prefetch()hands a run's files over in chunks of 1,000 (200 a process cost Django 3.9 s of interpreter start-up against 2.9 s at 1,000) and keeps the answers, each with the size and mtime taken before python read the file, so a file edited afterwards takes the per-file call as it always did.generate,--diff, thesigmap syncllms.txt walk andfreshencall it, and it is incremental: a file already answered and unchanged is not sent again, sosync, which walks the files twice, starts one process in total. A caller that does not prefetch is unchanged, never wrong, only slower.toolchain=python@3.9in the generated header (#970, PR #1003) — when the Python AST tier served any file, the meta line names the interpreter, major and minor, as it does for the opt-in TypeScript tier. The tier stays on by default, because it is the more accurate one, and is labelled instead of being made opt-in. A run in which it served no file carries no label.run-xrepo-gate.mjs --python-ast(#970, PR #1003) — scores the Python repositories a second time with the host'spython3and prints that row beside the gated one. It is never gated and never saved: the gate still generates withpython3shadowed, so its committed numbers do not depend on which Python is installed. On this corpus Django reads 4 of 5 and Flask 5 of 5 on both tiers, under Python 3.9.6 and under 3.14.6 (MRR 0.383 to 0.367 for Django, 0.690 to 0.700 for Flask).scripts/check-python-batch-equivalence.mjs(#970, PR #1003) — dev-only: compares the batch answer with the old per-file call for every file of one or more trees. It never ships and nothing loads it at run time.python-batch-ast.test.js, 15 cases (#970, PR #1003) — a fakepython3that logs each invocation, so the number of processes is counted and no real Python is needed: one process per chunk and none to read the answers back; one process for 30 files through the CLI, forsigmap syncand forfreshen; a failed, a part-way and a hung batch;python3absent; a file edited after the pre-pass; the label; and, against the real interpreter, batch against single-file for every kind of file. All 15 fail on v8.79.0's code, and removing thefreshenline fails its case.xrepo-gate.test.jsgains a case that--python-astleaves the gated rows and the saved baseline untouched.- Five pinned repositories and 25 questions, x104–x128 (#984, PR #1001) — Composer (PHP), Newtonsoft.Json (C#), Vapor (Swift), Exposed (Kotlin) and VitePress, the first repository whose answers include Vue single-file components. Each was labelled from a clean
git archiveof its pin by one annotator and answered independently by a second shown only the questions, and SigMap was first run on them after the labels were final. All 25 file sets matched exactly; since x084, 43 of 45 matched exactly, all 45 share a file and none are disjoint. Both annotators are language models, so the agreement bounds labelling noise and says nothing about blind spots they share. Vapor is pinned at the commitrun-benchmark.mjsalready uses, so one clone serves both gates; five questions first written against a newer commit were discarded and redone at that pin, and none of them is in the corpus. mcp-host-compat.yml(#994, PR #1002, @mikemikimike) — a weekly and manually dispatched workflow that installs the current Claude Code, Codex CLI and OpenCode CLIs and runshost-readers.test.jswithSIGMAP_REQUIRE_HOST_CLIS=1, so each host's own reader checks the config SigMap generated for it. The PR reports the three CLIs reading their generated configs in isolated temporary homes (Claude Code 2.1.146, Codex CLI 0.157.1, OpenCode 1.19.3), and adds installer cases for native config formats, migration with unrelated settings kept, a customCODEX_HOME, host verification failures, invalid JSON and repeat installs.
Fixed
- MCP host configuration (#994, PR #1002) — thanks @mikemikimike. Claude Code, Codex CLI and OpenCode now receive the config formats their CLIs read: Claude Code's project server goes to
.mcp.json, Codex CLI's to$CODEX_HOME/config.tomland OpenCode's documentedmcplocal-server schema toopencode.jsonor~/.config/opencode/opencode.json. They had been written to.claude/settings.json,config.yamland a schema OpenCode does not read, so the host CLIs reported that SigMap was not configured. Installs usenpx -y sigmap --mcpfor these hosts instead of a machine-specific path, migrate only older SigMap entries and keep unrelated settings and servers, verify the result with each host'smcp listwhen that CLI is installed and fail when it does not report SigMap, and print a manual check when it is absent.query_contextis marked for Claude Code's upfront loading, and--setup,doctorand the documentation follow. - Bundle checks across line endings (PR #1002, @mikemikimike) —
build-bundle.mjsandbundle-repro.test.jsnormalise line endings, so a Windowscore.autocrlfcheckout no longer reports a false stale bundle. - A Python repository's first run (#970, PR #1003) — Django's default path went from 182.2 s to 5.35 s (median of three, user plus system CPU 151.5 s to 5.22 s) on a scratch copy of the pinned tree, 1.70 times the
python3-absent run of the same tree and 1.43 times the old one, withpython3genuinely absent from PATH for that comparison and a load average of 4 to 5. A failed or hung batch leaves the files it did not answer to the regex tier, prints one line to stderr (python3 AST pass failed for N of M Python file(s) (exit 3); they use the regex tier) and never falls back to one process per file; nopython3on PATH is silent, as before.
Changed
- The xrepo baseline is re-recorded, with
run-xrepo-gate.mjs --save(#984, PR #1001) — 69 of 103 (67.0%, 95% interval 57.4–75.3%) to 81 of 128 (63.3%, 54.7–71.1%). The 20 earlier repositories reproduce their baseline task for task, so the fall is the new repositories: Composer 1 of 5, Newtonsoft.Json 2, Vapor 5, Exposed 2, VitePress 2. Unreachable tasks go from 6 to 8, and one task is 0.8 points where it was 1.0. The--python-astrows are not part of it. The guide's results table, interval, headroom and both--whytables follow the baseline, and a test pins each of them to it. - The four new clones nothing else expects are flagged
xrepoOnly(PR #1001) — Composer, Newtonsoft.Json, Exposed and VitePress, sobenchmark:test-discoveryandvalidate:grounding-coveragekeep skipping them on a machine that has runfetch:xrepo. Unflagging two of them failsxrepo-corpus.test.js. Vapor is not flagged: it is one of the canonical clones. KNOWN_LIMITATIONS.mdsays what the Python tier is deterministic over (#970, PR #1003) — per Python version. The interpreter decides which files parse (Django: 2,001 files on Python 3.9, 2,010 on 3.14), so a host with another Python, or none, extracts the same tree differently; the header label names which one served it. The benchmark guide's note that Flask moved from 5 of 5 to 4 of 5 with the host's Python is replaced by the two-tier reading above, because it does not reproduce on the current corpus.
Notes
- Upgrading. Python: nothing to configure. On a repository with Python files and a usable
python3the generated meta line gainstoolchain=python@3.x, so a committed context file regenerates with that one line changed, and a host with no usablepython3is unchanged. A host wherepython3exists but exits non-zero (a stub, for instance) now prints the one-line notice on each run where it used to fall back silently. MCP: runsigmap --setuporsigmap mcp install <host>again to move an older Claude Code or Codex entry to the file its CLI reads. Neither change adds a file to the package. - The #970 criterion that is not met. The issue asks for
spawnSyncbelow 10% of wall time in a CPU profile of the default path. It is 64.9% (3.47 s of 5.34 s). A synchronous batch cannot satisfy that: what remains insidespawnSyncis CPython parsing the files, not process starts —builtins.compileis 80% of the Python side's time (2.33 s of 2.9 s over Django's 2,933 files), and the extractor's own code is negligible. Before this releasespawnSyncheld about 80% of the 182 s run. The criterion is for the maintainer to restate (an absolute figure) or to meet with Python-side worker processes, which this release does not add. The persisted content-hash cache in the issue's proposal belongs to #971, which lists #970 as its blocker. - Byte-identical output. Batch against the old per-file call over flask (83 files), django (2,933), fastapi (1,121), httpx (60), click (63) and rich (213): 4,473 files, 0 differ, and 0 differ over the first 4,137 under Python 3.14.6. Django's full retrieval index is identical in all 2,086 entries. The label's six tokens can move which one file a budget-packed context file collapses to anchors (on Django, one file), and the retrieval index does not move.
- What the new repositories found. Newtonsoft.Json's
DefaultSerializationBinder.cs(x110) yields no signatures from the C# extractor — a zero-config run of the pin reports "no extractable signatures", and the class header's base list is interleaved with#pragma warninglines — and VitePress'ssrc/node/build/generateSitemap.ts(x127) is not indexed, because a zero-config run indexes nothing undersrc/node/build/, which looks like thebuild/directory skip behind Astro's x071. Composer reads 1 of 5, with four ranking misses at ranks 26 to 94. The tasks stay in the corpus as measured product gaps; the causes are not confirmed. - Published metrics. Every figure reproduces v8.79.0's reports leaf for leaf apart from version and date stamps, step timings and captured output tails, with the exceptions named here: the six reports the matrix rewrites (against the 43 canonical clones), test-discovery and the grounding reports have zero differing leaves, and
latest.jsondiffers only by its labels. Token reduction 95.7%, hit@5 80.4%, task success 61.9%, test-discovery F1 98.0% (28 repositories), the grounding corpus (43 repositories, 75.3%), the honest comparison 92.8% (116 of 125) against grep's 40.0% (50 of 125) = 2.32×,hard71.1% (64 of 90, one task of headroom),mined66.7% (40 of 60) andjvm41.0% (25 of 61) are unchanged, and the xrepo corpus is the figure above. One published self-scored reading moves, and untouched mergeddevelopreads the same, so it belongs to the merged code and not to this release's text.easy, the reference corpus the guide calls leaky, reads 90.0% (18 of 20) where it read 95.0%:t006("token budget enforcement dropping files", answergen-context.js) goes from rank 4 to rank 9 when #1003 lands, andt011("python dataclass BaseModel field extraction", answerpython.js) from rank 1 to 3 as that file gains signatures. With the generated recent-changes block off,easyreads 90.0% before and after #1003 (t006is a miss at rank 38 to 39 either way), so the 95.0% leaned on that block;hardandminedflip no task at any of the three merged changes. The honest scan reads documentation, so it also depends on text: SigMap's own generated files take 125 of the 625 top-5 places in grep's results on this release's tree, as at v8.79.0, where untouched mergeddevelopreads 126, so the release's own text moves that count back. Five unpublished MRR leaves of the honest report move in the third decimal against v8.79.0 — SigMap's overall 0.765 to 0.758, the easy split 0.786 to 0.778 and the large bucket 0.773 to 0.758, which the control reads identically and so belong to the merged code, and the grep side's overall 0.193 to 0.194 and large bucket 0.137 to 0.138, where the control reads 0.139 for the large bucket and also moves the small one (0.299 to 0.295). No hit count moves in any split or bucket. - Third-party CI time. The
xrepojob fetches the five new repositories (about 190 MB shallow) and scores 128 tasks in 1 minute 3 seconds to 1 minute 14 seconds on Linux. Locally the gate takes 40 seconds for all 25 repositories. - Not done. The paired exact-test verdict in the gate's output, the 200-question and 30-repository targets, and re-recording the signal-arm report and the sweep tables on the final corpus (they still describe 83 tasks, and the guide says so) are later steps of #984. A Python-side worker pool, if the maintainer wants the 10% criterion met as written, is open; so is the persisted cache (#971).