Repository navigation
feat(guard): guard Rust, and stop conflating packages in a workspace - #787
Merged
Merged
Conversation
Five languages in one index now. Rust follows Go's shape: `pub fn` and
`struct`/`enum`/`trait` at column zero, methods inside `impl` blocks excluded
because `new`, `fmt` and `from` sit on half the types in any crate. `use`
clauses become the specifiers the resolver already speaks — `crate::db::client`
as `db/client`, `super::` and `self::` as the relative forms Python and
TypeScript already produce. `mod x;` is not an import: it declares a child in
the same directory.
The noise gate rejected the first version at 23.6 % on ripgrep, which is what
it exists for.
The cause was not Rust. ripgrep is a Cargo workspace, and `crates/cli` and
`crates/globset` both define `escape` — two published libraries with their own
namespaces, which no author would call duplication. The index had no idea
packages existed, so every monorepo had been getting this wrong in every
language since the beginning.
`files.package_root` now records the nearest ancestor holding a `Cargo.toml`,
`package.json`, `go.mod`, `pyproject.toml` or `setup.py`, and duplicates are
only reported within one package. Observed rather than configured, like every
other fact this index keeps. Schema goes to 2, and SessionStart now treats an
unusable schema as stale — otherwise an upgraded guard would sit silent forever
behind an index it cannot read, since the file exists and the missing-index
path never runs.
`config` and `options` join the stopwords. Not corpus fitting: `config` was the
loudest false positive in axios months of JavaScript ago and again in ripgrep,
where nearly every Rust module keeps its own private `Config`.
ripgrep 23.6 % -> 7.3 % serde 4.8 % -> 2.9 %
No regression elsewhere: requests 0.0 %, gin 2.0 %, flask 4.8 %, axios 5.6 %.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This was referenced Jul 29, 2026
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.
Five languages in one index. Rust follows Go's shape — but the interesting part is what the noise gate rejected on the way.
The gate did its job
The first version measured 23.6 % on ripgrep, over the 10 % budget, and
measure_noise.pyexited non-zero.The cause was not Rust. ripgrep is a Cargo workspace:
crates/cliandcrates/globsetboth defineescape. Those are two published libraries with their own namespaces, and no author would call that duplication.The index had no idea packages existed — so every monorepo had been getting this wrong, in every language, since the beginning. Node workspaces, Go modules and Python source trees split exactly the same way.
files.package_rootnow records the nearest ancestor holding aCargo.toml,package.json,go.mod,pyproject.tomlorsetup.py, and duplicates are reported only within one package. Observed rather than configured, like every other fact this index keeps.No regression elsewhere: requests 0.0 %, gin 2.0 %, flask 4.8 %, axios 5.6 %.
A schema bump that had to fix itself
Schema goes to 2. That exposed a second problem: an index written by an older schema is unusable, and nothing would ever replace it — the file exists, so the missing-index path never runs, and the guard would sit silent forever behind an index it cannot read. SessionStart now treats an unusable schema as stale.
Rust specifics
pub fn,struct,enum,trait,union,typeat column zero.implblocks are excluded:new,fmtandfromsit on half the types in any crate — the same rule as Go and for the same measured reason.use crate::db::clientbecomesdb/client;super::andself::become the relative forms Python and TypeScript already emit.use crate::api::{routes, schemas}keeps its prefix, because the braces name children of one directory.mod x;is not an import — it declares a child module in the same directory.suffix_to_dirhad to learn a second shape: Go carries the full module path and the repository holds its tail, while Rust drops the head (crateissrc/), so the repository holds the tail of the specifier. Ambiguous matches are discarded rather than guessed.configandoptionsjoin the stopwordsNot corpus fitting.
configwas the loudest false positive in axios, in JavaScript, before Rust existed here — and it came back as the dominant one in ripgrep, where nearly every module keeps a privateConfig.Verification
148 guard tests (14 new), all nine gates, six repositories across five languages within the noise budget,
ruffandmypyclean, markdownlint clean.🤖 Generated with Claude Code