Repository navigation
Bring the Rust binary to Python 0.15.1 parity - #2
Merged
Merged
Conversation
Stdio MCP now answers newline-delimited JSON and still accepts Content-Length. CLI flags and directory scopes reach the engine, test detection covers the annotation and macro frameworks, and chisel migrate copies recorded results out of a legacy chisel.db. Benchmarks compare this build with Python 0.15.1. Co-authored-by: Aron Amos <IronAdamant@users.noreply.github.com>
Edge building and test-gaps no longer scan every unit for every import or edge. Snapshot loads skip an unchanged file and share one buffer for unescaped strings. Warm analyse and update skip unchanged files. Python method detection now sees defs after triple-quoted strings, so the large tree matches Python's 829 test units. Co-authored-by: Aron Amos <IronAdamant@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the gaps from the 2026-11-03 parity review of Python
v0.15.1(70d433b) against Rust 0.16.1 (4122fa8). The crate stays std-only. A Pythonimport chisellibrary is out of scope for this binary.A follow-up on the same branch makes the large-tree commands faster than Python and matches Python's test-unit set.
Benchmarks
Five runs, median ms (min–max), on Linux 6.12.94+, 4 vCPUs, Intel Xeon, 15.6 GiB RAM, Rust 1.97.0, Python 3.12.3. Small repo: two Python files. Large repo: the
djangopackage plus 80 of its test modules (about 1000 code files). History is split into commits of at most 100 paths, because a shallow-clone boundary commit lists every file and the pairing dominates co-change time. Full RSS table:scripts/benchmark_results.md. Reproduce withscripts/benchmark_parity.py.--help)Rust is faster on every command in both trees. On the large tree, cold analyse is 8.0 s against Python's 13.7 s, warm analyse is 63 ms against 8.6 s, and test-gaps is 73 ms against 163 ms. The small sample has 1 test unit on both sides. The large snapshots both have 829 test units, and the
(file, name)pairs match.Why the large tree was slow
test-gapsandtriagescanned every edge for every code unit. Covered ids are a set.git log -L, and edge building. Matching mtime, size, andHEADreturns the stored summary.The 822 vs 829 test units
Python's extra seven were real tests. Rust missed eight methods in
tests/migrations/test_multidb.pybecause a triple-quoted SQL string containing parentheses was not tracked across lines, so laterdeflines were skipped. Rust also emitted one placeholder unit fortests/bash_completion/management/commands/test_command.py, a Django management command whose filename looks like a test and which defines no test functions. Python emits no unit for that file. Blank lines no longer drop the enclosing class, so methods areClass.method, matching Python. After that, the large-tree test-unit names are identical (829).Parity checklist
CLI
--project-dir --storage-dir --json --limit: kept. Rust still accepts them before the subcommand.analyze: kept, including the Rust-only auto-queue above 300 files.updateoutput shape: fixed.code_units_foundis the units parsed this run (0 on a no-op).orphaned_results_cleanedandactive_file_locksare present.impact --functions: fixed. Names limit the direct edges.suggest-testsfile: fixed for Java, C#, and Swift method names. Ruby file-level units are kept (see below).suggest-tests --directory: fixed. Returns a{file: [tests]}map.suggest-tests --fallback: fixed. The flag is accepted. Python’s engine also stem-ranks when the flag is off and nothing matched, and Rust does the same. Withworking_treeand a file missing from the snapshot,--fallbackskips that stem list.suggest-testsstale_dbwhen the file is not in the snapshot: fixed.churn --unit: fixed. One row, with insertions andlast_changedfromgit log -Ldiff lines.churnwithout--unit: fixed. The file-level row only.ownership,history,who-reviews,diff-impact: kept. Already matched.coupling --min-count: fixed.coupling --working-tree: fixed. Untracked files get on-disk import partners and the working-tree note.risk-mapscores: fixed the causes called out (self-edges,require()as a code unit, missing heuristic edges, test files ranked as code). Remaining numeric gaps come from edge sets that are still not identical to Python’s.risk-mapdirectory: fixed.--no-exclude-testson risk-map, test-gaps, and triage: fixed.--coverage-mode: kept.--proximity/--no-proximity: fixed. Proximity stays on by default.--proximityis now accepted._meta.cycles: fixed. Tarjan SCC on directed imports, top three.locked_by,_meta.active_locks,_meta.lock_claimswhen a lock is held.stale-testsshape: fixed. A list when edges exist. Theno_edgesobject is unchanged.test-gapsbasic (calc.py:modcovered by a Java heuristic): fixed via weight-0.2 heuristic edges when a test file has no other edges. Stem match is case-insensitive, as in SQLiteLIKE.test-gapsfile /--directory: fixed.record-result --duration: fixed.duration_msis stored and read by the duration-variance map.statsshape: fixed. Addscommit_files,blame_cache,branch_co_changes,churn_stats,file_hashes, andshadow_graph.co_change_query_minis an integer.passed/failedstay (Rust-only).triagedirectory,--top-n,--no-exclude-tests: fixed.runpytest collection-error junk id: fixed. A status has to end the line. Underscore banners are dropped.runpytest id::to:: kept-as-Rust-improvement. Recorded ids match test-unit ids. Python stored the raw::form, which missed those units.runJest: fixed. Adds--jsonand--outputFile, stores a project-relative id.runnpx / go / cargo flags: fixed.npxis treated as Jest (as in Python).go testgets-json.cargo testgets--message-format=json. Go and cargo output is still not parsed, matching Python.runlive output: fixed. Stdout and stderr are streamed as they arrive.start-jobpositional kind: fixed.job-status/cancel-job, HTTP routes, lock acquire/release/refresh/check: kept.eval/new Functionwarning: fixed onsuggest_testsfor JS/TS files.serverInfo.versionis the crate version.list-locks --agent-id: fixed.optimize_storage: kept-as-Rust-improvement. There is no SQLite WAL to vacuum. The command still drops expired locks and rewrites the snapshot.--help: fixed.Storage and config
chisel.dbas the live store: not applicable. The snapshot stays.chisel/store.chisel migrate [chisel.db]copiestest_results(including duration and timestamp). It reads the main database and a sibling-walwhen one is present. Other commands do not openchisel.db.CHISEL_PROJECT_DIR,CHISEL_STORAGE_DIR, shards,CHISEL_INCLUDE_IGNORED: kept.CHISEL_BOOTSTRAP/register_dep_extractor: fixed as an executable, which is the constraint-compatible replacement.CHISEL_DEP_EXTRACTOR, ordep_extractorin.chisel/extensions.toml(same allow-flag as the unit extractor), reads{"path","language","content"}and returns dependencies. IfCHISEL_BOOTSTRAPis a path to an executable it is used the same way. A dotted Python import is not loaded. A warning is recorded instead.register_extractor: kept as the existingCHISEL_EXTRACTORexecutable.import chisel): not applicable. This tree is a binary.Extraction
#[test]: kept.@Testmethods of any name: fixed.[Fact]/[Theory]/[Test]/[TestMethod]: fixed.@Test: fixed.TEST,TEST_F,TEST_P,TEST_CASE,SCENARIO,BOOST_AUTO_TEST_CASEbecome test units, and those files are test files in risk-map.require()as a code unit: fixed. Edges no longer point at the test file itself.const x = require(...)is not a function. Tests with no other edges get heuristic edges of weight 0.2.requirestill contributes static import rows when the path resolves.include_results, extractor gate): kept.