From a2437db19364ebcc0035e1e5cb8cc81d01a690f4 Mon Sep 17 00:00:00 2001
From: Vaiz <4908982+Vaiz@users.noreply.github.com>
Date: Thu, 3 Sep 2026 08:29:45 +0100
Subject: [PATCH 1/6] fix(cargo-anvil): stop anvil-msrv-test from executing
benchmarks
`anvil-msrv-test` ran `cargo test --all-targets`. That flag expands to
`--lib --bins --tests --benches --examples`, so the recipe built AND
EXECUTED every bench target as part of the minimum-version check.
A bench declared `harness = false` delegates its run to a separate driver
binary -- criterion's, or a profiler runner such as `gungraun-runner`
driving Valgrind. `anvil-msrv-test-setup` installs only `cargo-delta` and
the MSRV toolchain, so that driver is never present and the group fails on
a prerequisite it does not declare:
--> Error in ae_basic_operations_cg: Failed to run benchmarks:
No such file or directory (os error 2).
Is gungraun-runner installed and gungraun-runner in your $PATH?
error: recipe `anvil-msrv-test` failed with exit code 1
That failure carries no minimum-version signal. An MSRV check exists to
prove the affected packages still compile and their tests still pass under
the declared minimum compiler; running benchmark harnesses is not part of
that, and it breaks the check for any adopter with a `harness = false`
bench. Observed on microsoft/oxidizer#718 (linux and linux-arm legs).
Use `--tests` instead. Chosen over the literally-equivalent
`--lib --bins --tests` because `--lib` errors with "no library targets
found" on a bin-only affected package under impact scoping -- the same
reason `anvil-miri` already selects `--tests`, documented in `miri.just`.
`--tests` selects exactly the targets carrying `test = true`: lib unit
tests, bin unit tests and integration tests.
A compile-only `--all-targets --no-run` pass was considered and rejected.
Benches and examples are dev-only targets that no consumer compiles, so
they do not constrain the crate's real MSRV, and the repository already
covers "do they still build" without running them: `anvil-bench` is
`cargo bench --no-run` and `anvil-examples` is `cargo build --examples`.
Adding the pass would double MSRV build time on the PR critical path for
a signal already owned elsewhere. This change makes `msrv-test` consistent
with that existing repository-wide policy.
No doctest coverage is lost: `--all-targets` suppresses doctests as well,
and `anvil-doc-test` owns them.
`msrv-test.just` was the only template with `cargo test --all-targets`.
`clippy.just` and `udeps.just` also pass `--all-targets`, but to `cargo
clippy` and `cargo udeps`, which compile without executing; both are left
as they are. `anvil-llvm-cov` and the other nextest paths are untouched.
The `impact.rs` contract test pinned the old argv; it now pins the new one
and additionally asserts that neither `--all-targets` nor `--benches` ever
reaches the MSRV invocations, so a regression fails loudly rather than
silently re-enabling bench execution.
Design doc, README and the mirrored lib.rs table updated to match; the
three emitted-tree snapshots re-recorded and reviewed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
crates/cargo-anvil/README.md | 2 +-
crates/cargo-anvil/docs/design/checks.md | 28 +++++++++++++++----
crates/cargo-anvil/src/lib.rs | 2 +-
.../justfiles/anvil/checks/msrv-test.just | 25 +++++++++++++++--
crates/cargo-anvil/tests/impact.rs | 11 ++++++--
.../snapshots/snapshots__ado_backend.snap | 25 +++++++++++++++--
.../snapshots/snapshots__github_backend.snap | 25 +++++++++++++++--
.../snapshots/snapshots__local_only.snap | 25 +++++++++++++++--
8 files changed, 125 insertions(+), 18 deletions(-)
diff --git a/crates/cargo-anvil/README.md b/crates/cargo-anvil/README.md
index d3eb1fb2..5e4f4b20 100644
--- a/crates/cargo-anvil/README.md
+++ b/crates/cargo-anvil/README.md
@@ -298,7 +298,7 @@ both locally and in cloud workflows. `pr-fast` is one job, while the
pr-slow | pr-test | llvm-cov | dual feature-config; gated by cargo-coverage-gate |
| doc-test | runs both feature configs |
| examples | compile-only |
- pr-msrv | msrv-test | dual feature-config, all-target tests under the declared MSRV |
+ pr-msrv | msrv-test | dual feature-config; lib/bin/integration tests under the declared MSRV (benches and examples are not run) |
pr-runtime-analysis | miri | libtest, not nextest |
| careful | self-cleans on a toolchain bump |
| loom | opt-in targets only |
diff --git a/crates/cargo-anvil/docs/design/checks.md b/crates/cargo-anvil/docs/design/checks.md
index 7ccb2499..aebbc965 100644
--- a/crates/cargo-anvil/docs/design/checks.md
+++ b/crates/cargo-anvil/docs/design/checks.md
@@ -211,20 +211,36 @@ matrix overhead.
#### `pr-msrv` (minimum-version tests)
-When the root manifest declares an MSRV, Anvil runs `cargo test --all-targets`
-for affected packages under that compiler. Cargo's all-target set covers
-library and binary unit tests, integration tests, examples, and benches as test
-targets. Anvil runs exactly two feature configurations: `--all-features` and
+When the root manifest declares an MSRV, Anvil runs `cargo test --tests`
+for affected packages under that compiler. `--tests` selects every target that
+carries `test = true` -- library and binary unit tests, and integration tests.
+Anvil runs exactly two feature configurations: `--all-features` and
the default features. It does not add a `--no-default-features` pass; such a
pass can exercise feature-negative code, but it is outside the current policy.
-This is the all-target test execution at the minimum supported compiler;
+This is the test execution at the minimum supported compiler;
`pr-test` runs the same affected suite through coverage instrumentation on the
catalog nightly. Other checks that use the selected stable compiler do not execute
-this all-target suite, so an MSRV fallback does not make `pr-msrv` a duplicate.
+this suite, so an MSRV fallback does not make `pr-msrv` a duplicate.
A selecting toolchain file does not suppress the MSRV run, even when it selects the
same compiler, because the MSRV group is the authoritative minimum-version test
result.
+The check deliberately does **not** use `--all-targets`. That flag expands to
+`--lib --bins --tests --benches --examples`, which makes `cargo test` build *and
+execute* every bench harness. A bench declared `harness = false` delegates its
+run to a separate driver binary -- criterion's, or a profiler runner such as
+`gungraun-runner` driving Valgrind -- and `anvil-msrv-test-setup` installs only
+the MSRV toolchain, so that driver is absent and the group fails on a
+prerequisite it never declares. That failure says nothing about the minimum
+supported version. It also matches the repository-wide policy that benches and
+examples are compiled but never run: `bench` uses `cargo bench --no-run` and
+`examples` uses `cargo build --examples`, and both keep that compile coverage on
+the selected stable compiler. `--tests` is preferred over the equivalent
+`--lib --bins --tests` because `--lib` errors with "no library targets found" on
+a bin-only affected package under impact scoping, the same reason `miri` uses it.
+No doctest coverage is lost, since `--all-targets` suppresses doctests too and
+`doc-test` owns them.
+
The group uses the same OS/architecture matrix and per-OS impact sets as `pr-test`
so cfg-gated targets and dependencies are exercised under the MSRV. It runs in
parallel with the other PR groups. When no root MSRV exists,
diff --git a/crates/cargo-anvil/src/lib.rs b/crates/cargo-anvil/src/lib.rs
index 31fd7881..1d665f5e 100644
--- a/crates/cargo-anvil/src/lib.rs
+++ b/crates/cargo-anvil/src/lib.rs
@@ -299,7 +299,7 @@
//! pr-slow | pr-test | llvm-cov | dual feature-config; gated by cargo-coverage-gate |
//! | doc-test | runs both feature configs |
//! | examples | compile-only |
-//! pr-msrv | msrv-test | dual feature-config, all-target tests under the declared MSRV |
+//! pr-msrv | msrv-test | dual feature-config; lib/bin/integration tests under the declared MSRV (benches and examples are not run) |
//! pr-runtime-analysis | miri | libtest, not nextest |
//! | careful | self-cleans on a toolchain bump |
//! | loom | opt-in targets only |
diff --git a/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just b/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just
index f95b38cf..915cc742 100644
--- a/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just
+++ b/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just
@@ -23,9 +23,30 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact
exit 0
}
$pkg = @(if ($include) { -split $include } else { '--workspace' })
- & cargo "+$toolchain" test @pkg --all-targets --all-features --locked
+ # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected
+ # packages still COMPILE and their tests still PASS under the declared
+ # minimum compiler. `--all-targets` expands to
+ # `--lib --bins --tests --benches --examples`, so `cargo test` would also
+ # build and EXECUTE every bench harness. A bench declared `harness = false`
+ # delegates its run to a separate driver binary (criterion's, or a profiler
+ # runner such as `gungraun-runner`, itself usually driving Valgrind). The
+ # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that
+ # driver is absent and the check fails on a prerequisite this group never
+ # declares -- a failure unrelated to the minimum-version signal. Benches and
+ # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`)
+ # and `anvil-examples` (`cargo build --examples`); this recipe keeps that
+ # same repository-wide policy.
+ #
+ # `--tests` selects exactly the targets that carry `test = true`: lib unit
+ # tests, bin unit tests, and integration tests. It is used in preference to
+ # `--lib --bins --tests` because `--lib` errors with "no library targets
+ # found" on a bin-only affected package under impact scoping, whereas
+ # `--tests` already covers lib unit tests and tolerates libless packages.
+ # No doctest coverage is lost: `--all-targets` suppresses doctests as well,
+ # and `anvil-doc-test` owns them.
+ & cargo "+$toolchain" test @pkg --tests --all-features --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- & cargo "+$toolchain" test @pkg --all-targets --locked
+ & cargo "+$toolchain" test @pkg --tests --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
# Install the declared MSRV toolchain only when this check is required.
diff --git a/crates/cargo-anvil/tests/impact.rs b/crates/cargo-anvil/tests/impact.rs
index bb7649b0..9afcae29 100644
--- a/crates/cargo-anvil/tests/impact.rs
+++ b/crates/cargo-anvil/tests/impact.rs
@@ -1036,11 +1036,18 @@ fn msrv_test_uses_affected_packages_for_both_feature_modes_and_skips_without_msr
assert!(output.status.success(), "anvil-msrv-test failed:\n{combined}");
let argv = fs::read_to_string(&log).unwrap();
for expected in [
- format!("+1.97 test {affected} --all-targets --all-features --locked"),
- format!("+1.97 test {affected} --all-targets --locked"),
+ format!("+1.97 test {affected} --tests --all-features --locked"),
+ format!("+1.97 test {affected} --tests --locked"),
] {
assert!(argv.contains(&expected), "missing MSRV invocation '{expected}' in:\n{argv}");
}
+ // The MSRV check must not build or execute bench targets: `--all-targets`
+ // expands to include `--benches`, and a `harness = false` bench then runs
+ // through a driver binary the msrv setup chain never installs.
+ assert!(
+ !argv.contains("--all-targets") && !argv.contains("--benches"),
+ "MSRV invocations must not select bench targets; captured argv:\n{argv}"
+ );
let manifest = fs::read_to_string(root.join("Cargo.toml")).unwrap();
fs::write(
diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap
index bbcffad6..1d74fd1b 100644
--- a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap
+++ b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap
@@ -2790,9 +2790,30 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact
exit 0
}
$pkg = @(if ($include) { -split $include } else { '--workspace' })
- & cargo "+$toolchain" test @pkg --all-targets --all-features --locked
+ # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected
+ # packages still COMPILE and their tests still PASS under the declared
+ # minimum compiler. `--all-targets` expands to
+ # `--lib --bins --tests --benches --examples`, so `cargo test` would also
+ # build and EXECUTE every bench harness. A bench declared `harness = false`
+ # delegates its run to a separate driver binary (criterion's, or a profiler
+ # runner such as `gungraun-runner`, itself usually driving Valgrind). The
+ # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that
+ # driver is absent and the check fails on a prerequisite this group never
+ # declares -- a failure unrelated to the minimum-version signal. Benches and
+ # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`)
+ # and `anvil-examples` (`cargo build --examples`); this recipe keeps that
+ # same repository-wide policy.
+ #
+ # `--tests` selects exactly the targets that carry `test = true`: lib unit
+ # tests, bin unit tests, and integration tests. It is used in preference to
+ # `--lib --bins --tests` because `--lib` errors with "no library targets
+ # found" on a bin-only affected package under impact scoping, whereas
+ # `--tests` already covers lib unit tests and tolerates libless packages.
+ # No doctest coverage is lost: `--all-targets` suppresses doctests as well,
+ # and `anvil-doc-test` owns them.
+ & cargo "+$toolchain" test @pkg --tests --all-features --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- & cargo "+$toolchain" test @pkg --all-targets --locked
+ & cargo "+$toolchain" test @pkg --tests --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
# Install the declared MSRV toolchain only when this check is required.
diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
index 3a91bee1..b2f359f4 100644
--- a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
+++ b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
@@ -2927,9 +2927,30 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact
exit 0
}
$pkg = @(if ($include) { -split $include } else { '--workspace' })
- & cargo "+$toolchain" test @pkg --all-targets --all-features --locked
+ # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected
+ # packages still COMPILE and their tests still PASS under the declared
+ # minimum compiler. `--all-targets` expands to
+ # `--lib --bins --tests --benches --examples`, so `cargo test` would also
+ # build and EXECUTE every bench harness. A bench declared `harness = false`
+ # delegates its run to a separate driver binary (criterion's, or a profiler
+ # runner such as `gungraun-runner`, itself usually driving Valgrind). The
+ # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that
+ # driver is absent and the check fails on a prerequisite this group never
+ # declares -- a failure unrelated to the minimum-version signal. Benches and
+ # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`)
+ # and `anvil-examples` (`cargo build --examples`); this recipe keeps that
+ # same repository-wide policy.
+ #
+ # `--tests` selects exactly the targets that carry `test = true`: lib unit
+ # tests, bin unit tests, and integration tests. It is used in preference to
+ # `--lib --bins --tests` because `--lib` errors with "no library targets
+ # found" on a bin-only affected package under impact scoping, whereas
+ # `--tests` already covers lib unit tests and tolerates libless packages.
+ # No doctest coverage is lost: `--all-targets` suppresses doctests as well,
+ # and `anvil-doc-test` owns them.
+ & cargo "+$toolchain" test @pkg --tests --all-features --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- & cargo "+$toolchain" test @pkg --all-targets --locked
+ & cargo "+$toolchain" test @pkg --tests --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
# Install the declared MSRV toolchain only when this check is required.
diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap b/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap
index 9855809a..fb61a923 100644
--- a/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap
+++ b/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap
@@ -1660,9 +1660,30 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact
exit 0
}
$pkg = @(if ($include) { -split $include } else { '--workspace' })
- & cargo "+$toolchain" test @pkg --all-targets --all-features --locked
+ # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected
+ # packages still COMPILE and their tests still PASS under the declared
+ # minimum compiler. `--all-targets` expands to
+ # `--lib --bins --tests --benches --examples`, so `cargo test` would also
+ # build and EXECUTE every bench harness. A bench declared `harness = false`
+ # delegates its run to a separate driver binary (criterion's, or a profiler
+ # runner such as `gungraun-runner`, itself usually driving Valgrind). The
+ # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that
+ # driver is absent and the check fails on a prerequisite this group never
+ # declares -- a failure unrelated to the minimum-version signal. Benches and
+ # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`)
+ # and `anvil-examples` (`cargo build --examples`); this recipe keeps that
+ # same repository-wide policy.
+ #
+ # `--tests` selects exactly the targets that carry `test = true`: lib unit
+ # tests, bin unit tests, and integration tests. It is used in preference to
+ # `--lib --bins --tests` because `--lib` errors with "no library targets
+ # found" on a bin-only affected package under impact scoping, whereas
+ # `--tests` already covers lib unit tests and tolerates libless packages.
+ # No doctest coverage is lost: `--all-targets` suppresses doctests as well,
+ # and `anvil-doc-test` owns them.
+ & cargo "+$toolchain" test @pkg --tests --all-features --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- & cargo "+$toolchain" test @pkg --all-targets --locked
+ & cargo "+$toolchain" test @pkg --tests --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
# Install the declared MSRV toolchain only when this check is required.
From 7897ecf20d0c15aa507e88911d877384a0a5c6d2 Mon Sep 17 00:00:00 2001
From: Vaiz <4908982+Vaiz@users.noreply.github.com>
Date: Thu, 3 Sep 2026 08:30:51 +0100
Subject: [PATCH 2/6] docs(cargo-anvil): name the mechanism in the action
tag-pin comments
The generated workflows carried this comment at every tag-pinned action:
uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved
The claim is true for these specific pins -- GitHub's immutable-releases
feature does lock the tag to a commit, and the REST API reports
`"immutable": true` for each of them. But the sentence asserts a property
of the TAG, and read on its own it looks like a general claim that Git
tags are stable, which is false and is exactly the belief SHA-pinning
exists to defend against.
Read that way it is also self-undermining: if tags could not be moved,
the SHA pins on `actions/checkout` and `actions/download-artifact` in the
same file would be pointless. On microsoft/oxidizer#718 this produced four
separate automated-reviewer findings that a human had to rebut one at a
time.
Reword to name the mechanism the pin depends on instead:
# pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
Same length class, one line, and it no longer generalises: it says why
THIS pin is safe rather than what tags are. Applied to all five sites --
`cargo-bins/cargo-binstall` in setup-action.yml, `codecov/codecov-action`
in both pr- and scheduled-impl-workflow.yml, and both
`marocchino/sticky-pull-request-comment` uses in pr-impl-workflow.yml.
`docs/design/github.md` reproduces both the comment and a sample step, so
both copies are updated to keep the doc and the templates from drifting,
plus a sentence recording why the comment names a mechanism rather than
asserting tag stability. The "Action pinning" section already explained
that immutability is per-release and must be re-confirmed on a version
bump; added one sentence stating that `actions/checkout` and
`actions/download-artifact` stay SHA-pinned because immutable releases are
opt-in per publisher and theirs have not enabled it -- not because those
actions are less trusted.
Behaviour is unchanged: comments only, same action versions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
crates/cargo-anvil/docs/design/github.md | 12 +++++++++---
.../templates/github/pr-impl-workflow.yml | 6 +++---
.../templates/github/scheduled-impl-workflow.yml | 2 +-
crates/cargo-anvil/templates/github/setup-action.yml | 2 +-
.../tests/snapshots/snapshots__github_backend.snap | 10 +++++-----
5 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/crates/cargo-anvil/docs/design/github.md b/crates/cargo-anvil/docs/design/github.md
index 83f16ec9..c1ebd151 100644
--- a/crates/cargo-anvil/docs/design/github.md
+++ b/crates/cargo-anvil/docs/design/github.md
@@ -990,11 +990,17 @@ the repository is deleted and recreated, and publishing generates a release
attestation covering the tag, commit SHA and assets. The tag is a stable identifier
under those rules, and unlike a SHA it stays readable in the diff when the pin is
bumped. Generated files carry a
-`# immutable release, the tag cannot be moved` comment at each such pin, so the reason
-a tag appears where a SHA is otherwise expected is visible at the use site.
+`# pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)`
+comment at each such pin, so the reason a tag appears where a SHA is otherwise
+expected is visible at the use site. The comment names the mechanism the pin relies
+on rather than asserting that tags are stable in general -- they are not, and a
+reader who takes it that way will draw the wrong conclusion about the other pins.
Every other action is pinned by commit SHA with the version in a trailing comment, for
example `actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1`.
+`actions/checkout` and `actions/download-artifact` are in this group not because they
+are less trusted but because immutable releases are opt-in per publisher and theirs
+have not enabled it, so a SHA is the only pin that fixes the code being run.
Immutability is a property of one published release, not a standing guarantee about
the publisher. When bumping a tag-pinned action, confirm the new release still reports
@@ -1031,7 +1037,7 @@ The upload step:
```yaml
- name: Upload coverage to Codecov
if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != ''
- uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved
+ uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info
flags: ${{ matrix.os }}
diff --git a/crates/cargo-anvil/templates/github/pr-impl-workflow.yml b/crates/cargo-anvil/templates/github/pr-impl-workflow.yml
index d7738e37..3827022c 100644
--- a/crates/cargo-anvil/templates/github/pr-impl-workflow.yml
+++ b/crates/cargo-anvil/templates/github/pr-impl-workflow.yml
@@ -154,13 +154,13 @@ jobs:
# write tokens).
- name: Upsert anvil-semver advisory
if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') != ''
- uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved
+ uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
header: anvil-semver
path: target/anvil/comments/semver.md
- name: Clear anvil-semver advisory
if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') == ''
- uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved
+ uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
header: anvil-semver
delete: true
@@ -216,7 +216,7 @@ jobs:
# fails. The separate hashFiles predicates require both feature
# configurations; one multi-pattern call would accept a partial pair.
if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != ''
- uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved
+ uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info
flags: ${{ matrix.os }}
diff --git a/crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml b/crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml
index fae9fd00..e2917666 100644
--- a/crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml
+++ b/crates/cargo-anvil/templates/github/scheduled-impl-workflow.yml
@@ -73,7 +73,7 @@ jobs:
# the Codecov UI can distinguish PR-tier uploads from scheduled
# uploads while still tracking each platform separately.
if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != ''
- uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved
+ uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info
flags: scheduled,${{ matrix.os }}
diff --git a/crates/cargo-anvil/templates/github/setup-action.yml b/crates/cargo-anvil/templates/github/setup-action.yml
index 0c5c0077..1441dbc4 100644
--- a/crates/cargo-anvil/templates/github/setup-action.yml
+++ b/crates/cargo-anvil/templates/github/setup-action.yml
@@ -109,7 +109,7 @@ runs:
# cargo-binstall keeps the cold bootstrap path fast.
- name: Install cargo-binstall
- uses: cargo-bins/cargo-binstall@v1.21.0 # immutable release, the tag cannot be moved
+ uses: cargo-bins/cargo-binstall@v1.21.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
- name: Install just
shell: bash
diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
index b2f359f4..7e566f1f 100644
--- a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
+++ b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
@@ -597,7 +597,7 @@ runs:
# cargo-binstall keeps the cold bootstrap path fast.
- name: Install cargo-binstall
- uses: cargo-bins/cargo-binstall@v1.21.0 # immutable release, the tag cannot be moved
+ uses: cargo-bins/cargo-binstall@v1.21.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
- name: Install just
shell: bash
@@ -997,13 +997,13 @@ jobs:
# write tokens).
- name: Upsert anvil-semver advisory
if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') != ''
- uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved
+ uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
header: anvil-semver
path: target/anvil/comments/semver.md
- name: Clear anvil-semver advisory
if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') == ''
- uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved
+ uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
header: anvil-semver
delete: true
@@ -1059,7 +1059,7 @@ jobs:
# fails. The separate hashFiles predicates require both feature
# configurations; one multi-pattern call would accept a partial pair.
if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != ''
- uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved
+ uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info
flags: ${{ matrix.os }}
@@ -1292,7 +1292,7 @@ jobs:
# the Codecov UI can distinguish PR-tier uploads from scheduled
# uploads while still tracking each platform separately.
if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != ''
- uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved
+ uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info
flags: scheduled,${{ matrix.os }}
From 8e68a0a020bb27b38ebb64ce56f242cb3636fe68 Mon Sep 17 00:00:00 2001
From: Vaiz <4908982+Vaiz@users.noreply.github.com>
Date: Thu, 3 Sep 2026 08:47:54 +0100
Subject: [PATCH 3/6] chore(anvil): regenerate repository anvil state
ox-tools consumes its own cargo-anvil templates, so the two preceding
template changes leave the checked-in generated files stale and
`regenerate-check` fails with:
Repository anvil state is out of date.
Run 'cargo run -p cargo-anvil -- anvil' and commit the diff.
Regenerated with `cargo run -p cargo-anvil -- anvil`. The diff is exactly
the emitted counterpart of the two template edits, nothing else:
- justfiles/anvil/checks/msrv-test.just
`cargo test --all-targets` -> `--tests`, plus the rationale comment.
This repository's own MSRV check therefore stops building and running
bench targets too.
- .github/actions/anvil-setup/action.yml
cargo-binstall pin comment.
- .github/workflows/anvil-pr-impl.yml
codecov and both sticky-pull-request-comment pin comments.
- .github/workflows/anvil-scheduled-impl.yml
codecov pin comment.
`.anvil.lock` records the new catalog checksum and the four file
checksums. No other emitted file changed (84 unchanged).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.anvil.lock | 8 +++----
.github/actions/anvil-setup/action.yml | 2 +-
.github/workflows/anvil-pr-impl.yml | 6 +++---
.github/workflows/anvil-scheduled-impl.yml | 2 +-
justfiles/anvil/checks/msrv-test.just | 25 ++++++++++++++++++++--
5 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/.anvil.lock b/.anvil.lock
index c1bee4b7..f450afd2 100644
--- a/.anvil.lock
+++ b/.anvil.lock
@@ -21,7 +21,7 @@ checksum = "sha256:d564a0ce424cda58c8f5b2476cf0c8b36e759afbdf8227608bd1f3fc74913
[[file]]
path = ".github/actions/anvil-setup/action.yml"
-checksum = "sha256:e1029f7ff95a5966184b4c04ccbed04ee8ba93bfc93bc9ac307d3dcef31374fb"
+checksum = "sha256:a8e3cb37301ef39783721603b5145ab73dc79b7b4897c06b43b03db1f224a8a8"
[[file]]
path = ".github/actions/anvil-setup/just-problem-matcher.json"
@@ -33,7 +33,7 @@ checksum = "sha256:7c43a36153ec346427892dca414fe971da616f99827fb5241167b1cf58a97
[[file]]
path = ".github/workflows/anvil-pr-impl.yml"
-checksum = "sha256:70c77226f9efe7252047d9ea4be93a1ac328708e72f4665214cb0c13e06b5c80"
+checksum = "sha256:6368d048bf4921279b4f67306b22125cd48778e9d299508af1cb34f67f1de1a5"
[[file]]
path = ".github/workflows/anvil-pr.yml"
@@ -41,7 +41,7 @@ checksum = "sha256:0c2530d9a38e6a74e0a7fd4f999b4a1790f97de30b58b68c6c2344600da19
[[file]]
path = ".github/workflows/anvil-scheduled-impl.yml"
-checksum = "sha256:ee1261dc018f6bdf3252890b57f0bc9510810c69505a64d3aef6d26315b824a3"
+checksum = "sha256:5550d9e336bff247a92cbea1698b38dde7b0f97ae811928f23e023fd773e3652"
[[file]]
path = ".github/workflows/anvil-scheduled.yml"
@@ -141,7 +141,7 @@ checksum = "sha256:9e9d0cbfef1e1e1586c2af4e9c387719c2f017ea1203d326baacc3ae25df8
[[file]]
path = "justfiles/anvil/checks/msrv-test.just"
-checksum = "sha256:9c25b140dcaa4b38db7701fd627dd9a2d5ad5f9bb83d4490c146058bf4328cc8"
+checksum = "sha256:d6301aa12b97a6176dd75a7921666f43f02fee6e88b9b2930b5d03d462908ec2"
[[file]]
path = "justfiles/anvil/checks/mutants-diff.just"
diff --git a/.github/actions/anvil-setup/action.yml b/.github/actions/anvil-setup/action.yml
index 0c5c0077..1441dbc4 100644
--- a/.github/actions/anvil-setup/action.yml
+++ b/.github/actions/anvil-setup/action.yml
@@ -109,7 +109,7 @@ runs:
# cargo-binstall keeps the cold bootstrap path fast.
- name: Install cargo-binstall
- uses: cargo-bins/cargo-binstall@v1.21.0 # immutable release, the tag cannot be moved
+ uses: cargo-bins/cargo-binstall@v1.21.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
- name: Install just
shell: bash
diff --git a/.github/workflows/anvil-pr-impl.yml b/.github/workflows/anvil-pr-impl.yml
index d7738e37..3827022c 100644
--- a/.github/workflows/anvil-pr-impl.yml
+++ b/.github/workflows/anvil-pr-impl.yml
@@ -154,13 +154,13 @@ jobs:
# write tokens).
- name: Upsert anvil-semver advisory
if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') != ''
- uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved
+ uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
header: anvil-semver
path: target/anvil/comments/semver.md
- name: Clear anvil-semver advisory
if: always() && github.event_name == 'pull_request' && matrix.os == 'linux' && github.event.pull_request.head.repo.full_name == github.repository && hashFiles('target/anvil/comments/semver.md') == ''
- uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved
+ uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
header: anvil-semver
delete: true
@@ -216,7 +216,7 @@ jobs:
# fails. The separate hashFiles predicates require both feature
# configurations; one multi-pattern call would accept a partial pair.
if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != ''
- uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved
+ uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info
flags: ${{ matrix.os }}
diff --git a/.github/workflows/anvil-scheduled-impl.yml b/.github/workflows/anvil-scheduled-impl.yml
index fae9fd00..e2917666 100644
--- a/.github/workflows/anvil-scheduled-impl.yml
+++ b/.github/workflows/anvil-scheduled-impl.yml
@@ -73,7 +73,7 @@ jobs:
# the Codecov UI can distinguish PR-tier uploads from scheduled
# uploads while still tracking each platform separately.
if: always() && matrix.os != 'windows-arm' && hashFiles('target/coverage/lcov-all-features.info') != '' && hashFiles('target/coverage/lcov-no-default.info') != ''
- uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved
+ uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
files: target/coverage/lcov-all-features.info,target/coverage/lcov-no-default.info
flags: scheduled,${{ matrix.os }}
diff --git a/justfiles/anvil/checks/msrv-test.just b/justfiles/anvil/checks/msrv-test.just
index f95b38cf..915cc742 100644
--- a/justfiles/anvil/checks/msrv-test.just
+++ b/justfiles/anvil/checks/msrv-test.just
@@ -23,9 +23,30 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact
exit 0
}
$pkg = @(if ($include) { -split $include } else { '--workspace' })
- & cargo "+$toolchain" test @pkg --all-targets --all-features --locked
+ # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected
+ # packages still COMPILE and their tests still PASS under the declared
+ # minimum compiler. `--all-targets` expands to
+ # `--lib --bins --tests --benches --examples`, so `cargo test` would also
+ # build and EXECUTE every bench harness. A bench declared `harness = false`
+ # delegates its run to a separate driver binary (criterion's, or a profiler
+ # runner such as `gungraun-runner`, itself usually driving Valgrind). The
+ # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that
+ # driver is absent and the check fails on a prerequisite this group never
+ # declares -- a failure unrelated to the minimum-version signal. Benches and
+ # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`)
+ # and `anvil-examples` (`cargo build --examples`); this recipe keeps that
+ # same repository-wide policy.
+ #
+ # `--tests` selects exactly the targets that carry `test = true`: lib unit
+ # tests, bin unit tests, and integration tests. It is used in preference to
+ # `--lib --bins --tests` because `--lib` errors with "no library targets
+ # found" on a bin-only affected package under impact scoping, whereas
+ # `--tests` already covers lib unit tests and tolerates libless packages.
+ # No doctest coverage is lost: `--all-targets` suppresses doctests as well,
+ # and `anvil-doc-test` owns them.
+ & cargo "+$toolchain" test @pkg --tests --all-features --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- & cargo "+$toolchain" test @pkg --all-targets --locked
+ & cargo "+$toolchain" test @pkg --tests --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
# Install the declared MSRV toolchain only when this check is required.
From 38e0ebab60a67f48c192d9987aba00ad52285b0a Mon Sep 17 00:00:00 2001
From: Vaiz <4908982+Vaiz@users.noreply.github.com>
Date: Thu, 3 Sep 2026 09:04:27 +0100
Subject: [PATCH 4/6] fix(cargo-anvil): trim in-recipe prose and finish the
pin-comment sweep
Three follow-ups from review.
1. The rationale comment in `msrv-test.just` was 22 lines. That text is
emitted verbatim into every adopter's `justfiles/`, where nobody is
looking for a design essay. Cut to 5 lines, each carrying a fact a
reader of the generated recipe needs; the full reasoning already lives
in `docs/design/checks.md`, which is where it belongs.
2. Dropped two paragraphs added to `docs/design/github.md` in the previous
commit. Both restated what the surrounding text already said.
3. The pin-comment reword had only covered the anvil templates. The
repository's own hand-maintained CI carried the same overstated wording
on actions the templates never emit, so `# immutable release, the tag
cannot be moved` still shipped from here. Updated all six:
- .github/workflows/main.yml (sticky-pull-request-comment x2, codecov)
- .github/workflows/codeql.yml (codeql-action init and analyze)
- .github/actions/setup/action.yml (taiki-e/install-action)
Every tag-pinned action in the repository now carries the new comment;
SHA-pinned actions keep their `# vX.Y.Z` version comment.
Also finished the `--all-targets` documentation sweep the first commit
missed. These still described the MSRV check as running all targets, which
would have reintroduced the bench-execution pitfall for anyone following
the docs:
- docs/design/ado.md, the `pr_msrv` stage
- docs/design/local.md, `anvil-msrv-test` (it explicitly listed
"examples, and benches as test targets")
- docs/design/local.md and docs/design/README.md, the no-tooling
fallback snippet, which told a cargo-only user to run
`cargo test --workspace --all-targets` -- the exact command that
executes bench harnesses. Now `--tests`, which also restores the
claim that the snippet matches the recipe bodies.
Templates, generated output and `.anvil.lock` regenerated; snapshots
re-recorded. No `cargo test --all-targets` remains anywhere in the repo.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.anvil.lock | 4 +--
.github/actions/setup/action.yml | 2 +-
.github/workflows/codeql.yml | 4 +--
.github/workflows/main.yml | 6 ++---
crates/cargo-anvil/docs/design/README.md | 2 +-
crates/cargo-anvil/docs/design/ado.md | 2 +-
crates/cargo-anvil/docs/design/github.md | 7 +----
crates/cargo-anvil/docs/design/local.md | 9 ++++---
.../justfiles/anvil/checks/msrv-test.just | 26 ++++---------------
.../snapshots/snapshots__ado_backend.snap | 26 ++++---------------
.../snapshots/snapshots__github_backend.snap | 26 ++++---------------
.../snapshots/snapshots__local_only.snap | 26 ++++---------------
justfiles/anvil/checks/msrv-test.just | 26 ++++---------------
13 files changed, 41 insertions(+), 125 deletions(-)
diff --git a/.anvil.lock b/.anvil.lock
index f450afd2..d6fa3360 100644
--- a/.anvil.lock
+++ b/.anvil.lock
@@ -1,7 +1,7 @@
version = 1
tool = "anvil"
tool_version = "0.6.0"
-catalog_checksum = "sha256:b1b94e5783dbe34fbf8f9c69a5e14cec3ece374e58876358ef4cd151f3f94e68"
+catalog_checksum = "sha256:177e1baf0a827f5bcee78730506e6dc8da92be11a6d836c045a0b4020fb2ed9f"
[[file]]
path = ".anvil/container/Dockerfile.dockerignore"
@@ -141,7 +141,7 @@ checksum = "sha256:9e9d0cbfef1e1e1586c2af4e9c387719c2f017ea1203d326baacc3ae25df8
[[file]]
path = "justfiles/anvil/checks/msrv-test.just"
-checksum = "sha256:d6301aa12b97a6176dd75a7921666f43f02fee6e88b9b2930b5d03d462908ec2"
+checksum = "sha256:3f8690b4b8ec60b1b1aa3f35b32797f7b81eb64b347080ba9ee8b21e1b55ecce"
[[file]]
path = "justfiles/anvil/checks/mutants-diff.just"
diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml
index b80e103d..7e4532ab 100644
--- a/.github/actions/setup/action.yml
+++ b/.github/actions/setup/action.yml
@@ -107,7 +107,7 @@ runs:
- name: Install Cargo Tools
if: inputs.cargo-tools != ''
- uses: taiki-e/install-action@v2.81.8 # immutable release, the tag cannot be moved
+ uses: taiki-e/install-action@v2.81.8 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
tool: ${{ steps.expand.outputs.cargo_tools }}
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index ae85e8aa..51d29ffa 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -69,7 +69,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@v4.37.7 # immutable release, the tag cannot be moved
+ uses: github/codeql-action/init@v4.37.7 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
@@ -98,6 +98,6 @@ jobs:
exit 1
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v4.37.7 # immutable release, the tag cannot be moved
+ uses: github/codeql-action/analyze@v4.37.7 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index d61280d1..3fb03f4c 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -154,14 +154,14 @@ jobs:
- name: Post Semver Failure Comment
if: steps.semver.outcome == 'failure' && github.event.pull_request.head.repo.full_name == github.repository
- uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved
+ uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
header: semver-check
path: semver-comment.txt
- name: Remove Semver Comment on Success
if: steps.semver.outcome == 'success' && github.event.pull_request.head.repo.full_name == github.repository
- uses: marocchino/sticky-pull-request-comment@v3.0.5 # immutable release, the tag cannot be moved
+ uses: marocchino/sticky-pull-request-comment@v3.0.5 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
header: semver-check
delete: true
@@ -262,7 +262,7 @@ jobs:
- name: Generate Coverage (no-default-features)
run: cargo +${{ env.RUST_NIGHTLY }} llvm-cov --no-default-features --workspace --lcov --output-path lcov-no-def.info
- name: Upload Coverage to Codecov
- uses: codecov/codecov-action@v7.0.0 # immutable release, the tag cannot be moved
+ uses: codecov/codecov-action@v7.0.0 # pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: lcov-all.info,lcov-no-def.info
diff --git a/crates/cargo-anvil/docs/design/README.md b/crates/cargo-anvil/docs/design/README.md
index 601deede..6b144daf 100644
--- a/crates/cargo-anvil/docs/design/README.md
+++ b/crates/cargo-anvil/docs/design/README.md
@@ -206,7 +206,7 @@ update the recipes or cloud-workflow building blocks.
A user with only `cargo` (no `just`, no `cargo-anvil`) can still run the basics:
```sh
-cargo test --workspace --all-targets --all-features --locked
+cargo test --workspace --tests --all-features --locked
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
cargo fmt --check
```
diff --git a/crates/cargo-anvil/docs/design/ado.md b/crates/cargo-anvil/docs/design/ado.md
index 135df73a..a8d6db50 100644
--- a/crates/cargo-anvil/docs/design/ado.md
+++ b/crates/cargo-anvil/docs/design/ado.md
@@ -373,7 +373,7 @@ x86_64 jobs and per-OS affected-package impact sets as `pr_test`, and invokes
`anvil-pr-msrv`. The stage consumes the per-OS impact artifact like the other PR
groups; when the root manifest declares no MSRV, the recipe exits successfully
after reporting that it skipped the test. Otherwise it runs affected-package
-`cargo test --all-targets` in all-features and default-features configurations.
+`cargo test --tests` in all-features and default-features configurations.
Ordinary stable checks honor a caller-provided `RUSTUP_TOOLCHAIN`. The dedicated
MSRV setup ensures the declared root MSRV is available through rustup.
diff --git a/crates/cargo-anvil/docs/design/github.md b/crates/cargo-anvil/docs/design/github.md
index c1ebd151..f97255ae 100644
--- a/crates/cargo-anvil/docs/design/github.md
+++ b/crates/cargo-anvil/docs/design/github.md
@@ -992,15 +992,10 @@ under those rules, and unlike a SHA it stays readable in the diff when the pin i
bumped. Generated files carry a
`# pinned by tag: this release is an immutable release (GitHub locks the tag to a commit)`
comment at each such pin, so the reason a tag appears where a SHA is otherwise
-expected is visible at the use site. The comment names the mechanism the pin relies
-on rather than asserting that tags are stable in general -- they are not, and a
-reader who takes it that way will draw the wrong conclusion about the other pins.
+expected is visible at the use site.
Every other action is pinned by commit SHA with the version in a trailing comment, for
example `actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1`.
-`actions/checkout` and `actions/download-artifact` are in this group not because they
-are less trusted but because immutable releases are opt-in per publisher and theirs
-have not enabled it, so a SHA is the only pin that fixes the code being run.
Immutability is a property of one published release, not a standing guarantee about
the publisher. When bumping a tag-pinned action, confirm the new release still reports
diff --git a/crates/cargo-anvil/docs/design/local.md b/crates/cargo-anvil/docs/design/local.md
index f2aecb66..7cec05ca 100644
--- a/crates/cargo-anvil/docs/design/local.md
+++ b/crates/cargo-anvil/docs/design/local.md
@@ -439,9 +439,10 @@ compiler. Anvil does not provision a separate tooling compiler; checks that
require nightly continue to use their catalog-pinned nightly.
When the root manifest declares an MSRV, `anvil-msrv-test` runs affected-package
-`cargo test --all-targets` in all-features and default-features configurations
-under that compiler. This includes library and binary unit tests, integration
-tests, examples, and benches as test targets. It does not add a
+`cargo test --tests` in all-features and default-features configurations
+under that compiler. This covers library and binary unit tests and integration
+tests; benches and examples are deliberately excluded, because `cargo test`
+would execute bench harnesses. It does not add a
`--no-default-features` pass. A root toolchain file does not suppress this
minimum-version run. Without a root MSRV the recipe is a no-op.
@@ -690,7 +691,7 @@ exactly the same arguments cloud workflows uses, because cloud workflows invokes
A user with only `cargo` (no `just`, no `cargo-anvil`) can still run the basics:
```sh
-cargo test --workspace --all-targets --all-features --locked
+cargo test --workspace --tests --all-features --locked
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
cargo fmt --check
```
diff --git a/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just b/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just
index 915cc742..915ac428 100644
--- a/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just
+++ b/crates/cargo-anvil/templates/justfiles/anvil/checks/msrv-test.just
@@ -23,27 +23,11 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact
exit 0
}
$pkg = @(if ($include) { -split $include } else { '--workspace' })
- # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected
- # packages still COMPILE and their tests still PASS under the declared
- # minimum compiler. `--all-targets` expands to
- # `--lib --bins --tests --benches --examples`, so `cargo test` would also
- # build and EXECUTE every bench harness. A bench declared `harness = false`
- # delegates its run to a separate driver binary (criterion's, or a profiler
- # runner such as `gungraun-runner`, itself usually driving Valgrind). The
- # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that
- # driver is absent and the check fails on a prerequisite this group never
- # declares -- a failure unrelated to the minimum-version signal. Benches and
- # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`)
- # and `anvil-examples` (`cargo build --examples`); this recipe keeps that
- # same repository-wide policy.
- #
- # `--tests` selects exactly the targets that carry `test = true`: lib unit
- # tests, bin unit tests, and integration tests. It is used in preference to
- # `--lib --bins --tests` because `--lib` errors with "no library targets
- # found" on a bin-only affected package under impact scoping, whereas
- # `--tests` already covers lib unit tests and tolerates libless packages.
- # No doctest coverage is lost: `--all-targets` suppresses doctests as well,
- # and `anvil-doc-test` owns them.
+ # `--tests` = lib/bin unit tests + integration tests. NOT `--all-targets`,
+ # which adds `--benches`: `cargo test` EXECUTES bench harnesses, and a
+ # `harness = false` bench needs a driver binary this group never installs.
+ # Benches/examples stay compile-only (`anvil-bench`, `anvil-examples`).
+ # `--tests` over `--lib --bins --tests`: `--lib` fails on bin-only packages.
& cargo "+$toolchain" test @pkg --tests --all-features --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& cargo "+$toolchain" test @pkg --tests --locked
diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap
index 1d74fd1b..c6ba50a5 100644
--- a/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap
+++ b/crates/cargo-anvil/tests/snapshots/snapshots__ado_backend.snap
@@ -2790,27 +2790,11 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact
exit 0
}
$pkg = @(if ($include) { -split $include } else { '--workspace' })
- # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected
- # packages still COMPILE and their tests still PASS under the declared
- # minimum compiler. `--all-targets` expands to
- # `--lib --bins --tests --benches --examples`, so `cargo test` would also
- # build and EXECUTE every bench harness. A bench declared `harness = false`
- # delegates its run to a separate driver binary (criterion's, or a profiler
- # runner such as `gungraun-runner`, itself usually driving Valgrind). The
- # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that
- # driver is absent and the check fails on a prerequisite this group never
- # declares -- a failure unrelated to the minimum-version signal. Benches and
- # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`)
- # and `anvil-examples` (`cargo build --examples`); this recipe keeps that
- # same repository-wide policy.
- #
- # `--tests` selects exactly the targets that carry `test = true`: lib unit
- # tests, bin unit tests, and integration tests. It is used in preference to
- # `--lib --bins --tests` because `--lib` errors with "no library targets
- # found" on a bin-only affected package under impact scoping, whereas
- # `--tests` already covers lib unit tests and tolerates libless packages.
- # No doctest coverage is lost: `--all-targets` suppresses doctests as well,
- # and `anvil-doc-test` owns them.
+ # `--tests` = lib/bin unit tests + integration tests. NOT `--all-targets`,
+ # which adds `--benches`: `cargo test` EXECUTES bench harnesses, and a
+ # `harness = false` bench needs a driver binary this group never installs.
+ # Benches/examples stay compile-only (`anvil-bench`, `anvil-examples`).
+ # `--tests` over `--lib --bins --tests`: `--lib` fails on bin-only packages.
& cargo "+$toolchain" test @pkg --tests --all-features --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& cargo "+$toolchain" test @pkg --tests --locked
diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
index 7e566f1f..ade9fb80 100644
--- a/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
+++ b/crates/cargo-anvil/tests/snapshots/snapshots__github_backend.snap
@@ -2927,27 +2927,11 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact
exit 0
}
$pkg = @(if ($include) { -split $include } else { '--workspace' })
- # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected
- # packages still COMPILE and their tests still PASS under the declared
- # minimum compiler. `--all-targets` expands to
- # `--lib --bins --tests --benches --examples`, so `cargo test` would also
- # build and EXECUTE every bench harness. A bench declared `harness = false`
- # delegates its run to a separate driver binary (criterion's, or a profiler
- # runner such as `gungraun-runner`, itself usually driving Valgrind). The
- # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that
- # driver is absent and the check fails on a prerequisite this group never
- # declares -- a failure unrelated to the minimum-version signal. Benches and
- # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`)
- # and `anvil-examples` (`cargo build --examples`); this recipe keeps that
- # same repository-wide policy.
- #
- # `--tests` selects exactly the targets that carry `test = true`: lib unit
- # tests, bin unit tests, and integration tests. It is used in preference to
- # `--lib --bins --tests` because `--lib` errors with "no library targets
- # found" on a bin-only affected package under impact scoping, whereas
- # `--tests` already covers lib unit tests and tolerates libless packages.
- # No doctest coverage is lost: `--all-targets` suppresses doctests as well,
- # and `anvil-doc-test` owns them.
+ # `--tests` = lib/bin unit tests + integration tests. NOT `--all-targets`,
+ # which adds `--benches`: `cargo test` EXECUTES bench harnesses, and a
+ # `harness = false` bench needs a driver binary this group never installs.
+ # Benches/examples stay compile-only (`anvil-bench`, `anvil-examples`).
+ # `--tests` over `--lib --bins --tests`: `--lib` fails on bin-only packages.
& cargo "+$toolchain" test @pkg --tests --all-features --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& cargo "+$toolchain" test @pkg --tests --locked
diff --git a/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap b/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap
index fb61a923..df2d8cc6 100644
--- a/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap
+++ b/crates/cargo-anvil/tests/snapshots/snapshots__local_only.snap
@@ -1660,27 +1660,11 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact
exit 0
}
$pkg = @(if ($include) { -split $include } else { '--workspace' })
- # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected
- # packages still COMPILE and their tests still PASS under the declared
- # minimum compiler. `--all-targets` expands to
- # `--lib --bins --tests --benches --examples`, so `cargo test` would also
- # build and EXECUTE every bench harness. A bench declared `harness = false`
- # delegates its run to a separate driver binary (criterion's, or a profiler
- # runner such as `gungraun-runner`, itself usually driving Valgrind). The
- # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that
- # driver is absent and the check fails on a prerequisite this group never
- # declares -- a failure unrelated to the minimum-version signal. Benches and
- # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`)
- # and `anvil-examples` (`cargo build --examples`); this recipe keeps that
- # same repository-wide policy.
- #
- # `--tests` selects exactly the targets that carry `test = true`: lib unit
- # tests, bin unit tests, and integration tests. It is used in preference to
- # `--lib --bins --tests` because `--lib` errors with "no library targets
- # found" on a bin-only affected package under impact scoping, whereas
- # `--tests` already covers lib unit tests and tolerates libless packages.
- # No doctest coverage is lost: `--all-targets` suppresses doctests as well,
- # and `anvil-doc-test` owns them.
+ # `--tests` = lib/bin unit tests + integration tests. NOT `--all-targets`,
+ # which adds `--benches`: `cargo test` EXECUTES bench harnesses, and a
+ # `harness = false` bench needs a driver binary this group never installs.
+ # Benches/examples stay compile-only (`anvil-bench`, `anvil-examples`).
+ # `--tests` over `--lib --bins --tests`: `--lib` fails on bin-only packages.
& cargo "+$toolchain" test @pkg --tests --all-features --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& cargo "+$toolchain" test @pkg --tests --locked
diff --git a/justfiles/anvil/checks/msrv-test.just b/justfiles/anvil/checks/msrv-test.just
index 915cc742..915ac428 100644
--- a/justfiles/anvil/checks/msrv-test.just
+++ b/justfiles/anvil/checks/msrv-test.just
@@ -23,27 +23,11 @@ anvil-msrv-test: anvil-msrv-test-validate-prereqs anvil-impact
exit 0
}
$pkg = @(if ($include) { -split $include } else { '--workspace' })
- # `--tests`, NOT `--all-targets`. An MSRV check exists to prove the affected
- # packages still COMPILE and their tests still PASS under the declared
- # minimum compiler. `--all-targets` expands to
- # `--lib --bins --tests --benches --examples`, so `cargo test` would also
- # build and EXECUTE every bench harness. A bench declared `harness = false`
- # delegates its run to a separate driver binary (criterion's, or a profiler
- # runner such as `gungraun-runner`, itself usually driving Valgrind). The
- # `anvil-msrv-test-setup` chain installs only the MSRV toolchain, so that
- # driver is absent and the check fails on a prerequisite this group never
- # declares -- a failure unrelated to the minimum-version signal. Benches and
- # examples are compiled, never run, by `anvil-bench` (`cargo bench --no-run`)
- # and `anvil-examples` (`cargo build --examples`); this recipe keeps that
- # same repository-wide policy.
- #
- # `--tests` selects exactly the targets that carry `test = true`: lib unit
- # tests, bin unit tests, and integration tests. It is used in preference to
- # `--lib --bins --tests` because `--lib` errors with "no library targets
- # found" on a bin-only affected package under impact scoping, whereas
- # `--tests` already covers lib unit tests and tolerates libless packages.
- # No doctest coverage is lost: `--all-targets` suppresses doctests as well,
- # and `anvil-doc-test` owns them.
+ # `--tests` = lib/bin unit tests + integration tests. NOT `--all-targets`,
+ # which adds `--benches`: `cargo test` EXECUTES bench harnesses, and a
+ # `harness = false` bench needs a driver binary this group never installs.
+ # Benches/examples stay compile-only (`anvil-bench`, `anvil-examples`).
+ # `--tests` over `--lib --bins --tests`: `--lib` fails on bin-only packages.
& cargo "+$toolchain" test @pkg --tests --all-features --locked
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& cargo "+$toolchain" test @pkg --tests --locked
From 3b98234b3830d4fce81e00c3d97a70ab355868a6 Mon Sep 17 00:00:00 2001
From: Vaiz <4908982+Vaiz@users.noreply.github.com>
Date: Thu, 3 Sep 2026 09:26:29 +0100
Subject: [PATCH 5/6] chore(cargo-anvil): refresh the README doc2readme
fingerprint
`_anvil-readme` was failing on every leg with "The documentation in your
source code has changed" for cargo-anvil. The README body was already in
sync with the rustdoc in `src/lib.rs` -- the stale part was the
`[__cargo_doc2readme_dependencies_info]` fingerprint, which encodes a
hash of the doc comments doc2readme generated the link table from. The
rustdoc edits in the earlier commits changed that hash without changing
any rendered text, so a by-eye comparison of the two sides looked clean
while `cargo doc2readme --check` still rejected it.
Regenerated with `just package=cargo-anvil readme`; the only resulting
change is the fingerprint line. `cargo run -p cargo-anvil -- anvil`
reports all 88 generated items unchanged, so no other artifact drifted.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
crates/cargo-anvil/README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/crates/cargo-anvil/README.md b/crates/cargo-anvil/README.md
index 5e4f4b20..cafec43c 100644
--- a/crates/cargo-anvil/README.md
+++ b/crates/cargo-anvil/README.md
@@ -491,7 +491,7 @@ And `docs/verification.md` for the continuous-validation strategy.
This crate was developed as part of The Oxidizer Project. Browse this crate's source code.
- [__cargo_doc2readme_dependencies_info]: ggGmYW0CYXZlMC43LjNhdIQbFhzZ8rzWNNYbuRaDSGWynFgbH4PMdoT7GNcbVwNPtPjAhvFhYvRhcoQbLvVGTNtetQUbnp9vX0Ew7_gbkZEyxfXZXyMbltL72AXa-o1hZIGDa2NhcmdvLWFudmlsZTAuNi4wa2NhcmdvX2Fudmls
+ [__cargo_doc2readme_dependencies_info]: ggGmYW0CYXZlMC43LjNhdIQbFhzZ8rzWNNYbuRaDSGWynFgbH4PMdoT7GNcbVwNPtPjAhvFhYvRhcoQbVqn03OrTnSYblGjeKgXeGVgb6z3iwQiK18Abc5kLxsXto9xhZIGDa2NhcmdvLWFudmlsZTAuNi4wa2NhcmdvX2Fudmls
[__link0]: https://crates.io/crates/cargo-delta
[__link1]: https://docs.rs/cargo-anvil/0.6.0/cargo_anvil/?search=artifacts::container
[__link10]: https://docs.rs/cargo-anvil/0.6.0/cargo_anvil/?search=artifacts
From 946afed0535256298e0489a527053861ca7c6dce Mon Sep 17 00:00:00 2001
From: Vaiz <4908982+Vaiz@users.noreply.github.com>
Date: Thu, 3 Sep 2026 11:30:19 +0100
Subject: [PATCH 6/6] chore(anvil): recompute the .anvil.lock catalog checksum
after rebase
Rebasing onto main conflicted on `catalog_checksum` alone -- both sides
rewrote that one line and git cannot merge a hash. main has since added
a catalog item (the plan is now 92 items, up from 91), so neither side's
value was correct on the new base.
Resolved by regenerating rather than picking a side: `cargo run -p
cargo-anvil -- anvil` recomputes the checksum from the merged catalog.
It reports the other 89 generated items unchanged, so the emitted
workflows, actions and justfiles this branch touches survived the rebase
intact and only the lock needed updating.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.anvil.lock | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.anvil.lock b/.anvil.lock
index d6fa3360..f37bc73e 100644
--- a/.anvil.lock
+++ b/.anvil.lock
@@ -1,7 +1,7 @@
version = 1
tool = "anvil"
tool_version = "0.6.0"
-catalog_checksum = "sha256:177e1baf0a827f5bcee78730506e6dc8da92be11a6d836c045a0b4020fb2ed9f"
+catalog_checksum = "sha256:3415a24c3e1b7216ecfd37ecfda02b4e6039851b70f07e45a676597254874191"
[[file]]
path = ".anvil/container/Dockerfile.dockerignore"