Skip to content

SigMap 8.80.0

Choose a tag to compare

@github-actions github-actions released this 18 Oct 20:19
· 119 commits to main since this release
dca7387

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 --batch and python.prefetch() (#970, PR #1003) — the default Python extractor used to start python3 python_ast.py <file> for every .py file: 2,933 process starts on Django, 182.2 s against 3.7 s for the regex tier. --batch reads 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, the sigmap sync llms.txt walk and freshen call it, and it is incremental: a file already answered and unchanged is not sent again, so sync, 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.9 in 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's python3 and prints that row beside the gated one. It is never gated and never saved: the gate still generates with python3 shadowed, 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 fake python3 that 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, for sigmap sync and for freshen; a failed, a part-way and a hung batch; python3 absent; 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 the freshen line fails its case. xrepo-gate.test.js gains a case that --python-ast leaves 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 archive of 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 commit run-benchmark.mjs already 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 runs host-readers.test.js with SIGMAP_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 custom CODEX_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.toml and OpenCode's documented mcp local-server schema to opencode.json or ~/.config/opencode/opencode.json. They had been written to .claude/settings.json, config.yaml and a schema OpenCode does not read, so the host CLIs reported that SigMap was not configured. Installs use npx -y sigmap --mcp for 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's mcp list when that CLI is installed and fail when it does not report SigMap, and print a manual check when it is absent. query_context is marked for Claude Code's upfront loading, and --setup, doctor and the documentation follow.
  • Bundle checks across line endings (PR #1002, @mikemikimike) — build-bundle.mjs and bundle-repro.test.js normalise line endings, so a Windows core.autocrlf checkout 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, with python3 genuinely 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; no python3 on 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-ast rows are not part of it. The guide's results table, interval, headroom and both --why tables 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, so benchmark:test-discovery and validate:grounding-coverage keep skipping them on a machine that has run fetch:xrepo. Unflagging two of them fails xrepo-corpus.test.js. Vapor is not flagged: it is one of the canonical clones.
  • KNOWN_LIMITATIONS.md says 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 python3 the generated meta line gains toolchain=python@3.x, so a committed context file regenerates with that one line changed, and a host with no usable python3 is unchanged. A host where python3 exists 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: run sigmap --setup or sigmap 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 spawnSync below 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 inside spawnSync is CPython parsing the files, not process starts — builtins.compile is 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 release spawnSync held 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 warning lines — and VitePress's src/node/build/generateSitemap.ts (x127) is not indexed, because a zero-config run indexes nothing under src/node/build/, which looks like the build/ 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.json differs 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×, hard 71.1% (64 of 90, one task of headroom), mined 66.7% (40 of 60) and jvm 41.0% (25 of 61) are unchanged, and the xrepo corpus is the figure above. One published self-scored reading moves, and untouched merged develop reads 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", answer gen-context.js) goes from rank 4 to rank 9 when #1003 lands, and t011 ("python dataclass BaseModel field extraction", answer python.js) from rank 1 to 3 as that file gains signatures. With the generated recent-changes block off, easy reads 90.0% before and after #1003 (t006 is a miss at rank 38 to 39 either way), so the 95.0% leaned on that block; hard and mined flip 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 merged develop reads 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 xrepo job 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).