rust:mordant: rebuild the lint libraries when the pinned entries change - #38418
rust:mordant: rebuild the lint libraries when the pinned entries change#38418robobun wants to merge 1 commit into
Conversation
cargo-dylint builds each [workspace.metadata.dylint] entry out of cargo's git checkout of the pinned rev into target/dylint/libraries/<toolchain>/, one target dir shared by every rev. Cargo skips freshness checks on files under $CARGO_HOME/git and the rev is not part of the fingerprint, so after a rev bump the library built from the previous rev is reused and the bump gets triaged against the old lints. Record the entries the directory was built from in it and discard it when they differ.
|
Warning Review limit reached
Next review available in: 35 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
Comment |
|
Status: reproduced and fixed, self-review in progress.
|
There was a problem hiding this comment.
LGTM — self-contained dev-tooling fix with a hermetic test.
What was reviewed:
- The invalidation key (JSON of
[workspace.metadata.dylint]) and that only<target>/dylint/libraries/is removed, leaving the workspace check cache and driver intact. - Write-before-build ordering of
built-from.json— sound, avoids a rebuild loop while a bump is being triaged with non-zero lint exits. cargo metadatahandling:maxBufferraised, non-zero status exits before anyrmSync; the test's 2 MBpackagesfield exercises the buffer cap.- Test hermeticity: stand-in
cargo/bunon PATH,skipIf(isWindows)for the sh stubs, concurrent stdout/stderr/exited drain, and thedylint --versionprobe handled by the stub.
Extended reasoning...
Overview
This PR touches two files: scripts/rust-mordant.ts (a developer/CI wrapper around cargo dylint) and a new test at test/internal/rust-mordant-pin-bump.test.ts. The script gains a ~30-line stanza that reads cargo metadata --no-deps, compares the [workspace.metadata.dylint] table against a marker file in <target>/dylint/libraries/built-from.json, and removes that directory when they differ so cargo-dylint rebuilds the lint pack from the newly pinned rev instead of reusing a stale build. Nothing under src/ changes; no shipped runtime behavior is affected.
Security risks
None. The script is local dev tooling invoked via bun run rust:mordant. The only destructive operation is rmSync on <target_directory>/dylint/libraries, where target_directory comes from cargo metadata for this workspace — a build-artifact directory. Worst-case failure mode is an unnecessary ~1-minute lint-library rebuild. No user input, no network, no auth/crypto/permissions.
Level of scrutiny
Low. This is a build-script quality-of-life fix with a clearly stated root cause (cargo's fingerprint check skips sources under $CARGO_HOME/git, so a rev bump doesn't invalidate the shared libraries/ target dir). The blast radius is confined to a regenerable cache directory. CI already starts from an empty target dir, so this only changes behavior on developer machines that have run the script before. No CODEOWNERS cover the changed paths.
Other factors
The test is well-constructed per the repo's review guidance: it uses tempDir/bunEnv/bunExe from harness, drains stdout/stderr/exited concurrently, uses Buffer.alloc(n, fill) rather than .repeat(), asserts full result objects with toEqual, covers all four branches (no record, same pin, changed pin, cargo metadata failure), verifies the check cache is not discarded, and is properly gated with skipIf(isWindows) since the stubs are sh scripts. The stub cargo correctly short-circuits the dylint --version probe so it isn't counted as a run. Test placement in test/internal/ matches existing precedent for build-script tests (build-rust-toolchain-probe.test.ts, build-download-retry.test.ts, etc.). The PR description includes a real reproduction and a manual verification against the current pin. No outstanding reviewer comments.
|
Nothing to change from the review above; it covers the points the change rests on (the key is the metadata table, only |
|
Updated 2:05 AM PT - Aug 14th, 2026
❌ @robobun, your commit 1e5d44f has some failures in 🧪 To try this PR locally: bunx bun-pr 38418That installs a local version of the PR into your bun-38418 --bun |
|
Updated 5:05 AM PT - Aug 14th, 2026
❌ @robobun, your commit 1e5d44f has some failures in 🧪 To try this PR locally: bunx bun-pr 38418That installs a local version of the PR into your bun-38418 --bun |
Problem
revunder[workspace.metadata.dylint]in Cargo.toml is bumped,bun run rust:mordanton a machine that has run it before keeps linting with the library built from the previous rev. Seen going fc46d7f -> 4e08693: cargo-dylint printedFinished release ... in 0.14swith noCompiling mordantline,target/dylint/libraries/<toolchain>/release/libmordant.sowas byte for byte the old build, and the run still reportedstored projectionat src/bundler/ParseTask.rs:88, a finding the new rev no longer produces. The bump procedure in .github/workflows/CLAUDE.md (change the rev, run the script, triage what it reports) therefore triages against the old lints. CI is unaffected, every run there starts from an empty target dir.cargo build --release --target-dir <target>/dylint/libraries/<toolchain>inside cargo's checkout of the rev,~/.cargo/git/checkouts/mordant-*/<rev>/(cargo-dylint 6.0.3,build_libraryindylint/src/library_packages/mod.rs). The target dir is the same for every rev, and so is the fingerprint directory (mordant-cd12729808ff36defor both revs): the package is hashed by its path relative to its own workspace root, which is the checkout itself.$CARGO_HOME/gitand$CARGO_HOME/registry, which it assumes never change (find_stale_file, cargosrc/compiler/fingerprint/mod.rs). The new checkout's files are never looked at, so the old build stays fresh untiltarget/dylint/librariesis deleted by hand. cargo-dylint has no option to force the build; its only knob is--no-build.Fix
scripts/rust-mordant.tsaskscargo metadata --no-depsfor the target directory and the[workspace.metadata.dylint]table (the two things cargo-dylint itself reads), keeps the table's JSON in<target>/dylint/libraries/built-from.json, and removes that directory before running cargo-dylint when the file is missing or differs. When it matches nothing happens and cargo reuses the build as before.libraries/is discarded. The check of the workspace itself (<target>/dylint/target/) needs no help, dylint's driver hashes the metadata and the library bytes into rustc's dependency tracking, which is also why the stale library was visibly re-linting the workspace in the first place.cargo metadata --no-depsis about 400 KB here and spawnSync stops capturing at 1 MB by default, so the cap is raised.test/internal/rust-mordant-pin-bump.test.tsruns the script against stand-incargoandbunexecutables and checks that a directory with no record is discarded, that the same pin keeps it, that a changed pin discards it and leaves the check cache alone, and that a failingcargo metadatastops the run. The script's change is outsidesrc/, so the fail-before run isgit stash push -- scripts/ && bun bd test test/internal/rust-mordant-pin-bump.test.ts: the directory is kept and no record is written. Passes with the change.target/dylint/librariesholding the fc46d7f build and Cargo.toml at the current pin (18a5734), the script printed its rebuilding line, cargo printedCompiling mordant v0.1.0 (.../18a5734), the workspace pass finished clean (exit 0, as Bump mordant to 18a5734 #38384 says it should), and a second run reused the build (Finished ... in 0.08s, no rebuilding line).Background
[workspace.metadata.dylint]in Cargo.toml tells cargo-dylint which git rev of it to build and load..fingerprint/in a target dir that cargo compares against to decide whether to recompile. For a package built from a local path it includes the list of source files whose mtimes are compared against it; the$CARGO_HOMEexemption above removes the checkout's files from that comparison.<target>/dylint/libraries/<toolchain>/with the library builds (what this change manages),<target>/dylint/target/<toolchain>/with the check of this workspace, and~/.dylint_drivers/<toolchain>/with the driver. The last two are already keyed by what invalidates them.Reproduction at the previous two pins
Cargo.toml at fc46d7f, empty
target/dylint:Cargo.toml moved to 4e08693:
The 4e08693 checkout was created after the build above (its files are newer than the fingerprint), and the fingerprint's dep-info lists the sources as
src/lib.rs,src/stored_projection.rs, ... relative to whichever checkout is being built, so without the$CARGO_HOMEexemption cargo would have rebuilt.rm -rf target/dylint/librariesfollowed by the same command compiles mordant from the 4e08693 checkout.