Skip to content

fix(release): Cargo.lock was 15 days stale — the binary-release workflow could not build - #2518

Closed
noahgift wants to merge 1 commit into
mainfrom
fix/stale-lockfile
Closed

fix(release): Cargo.lock was 15 days stale — the binary-release workflow could not build#2518
noahgift wants to merge 1 commit into
mainfrom
fix/stale-lockfile

Conversation

@noahgift

Copy link
Copy Markdown
Contributor

On a clean checkout of main, cargo metadata alone — no build, no test — rewrites the lockfile:

1 file changed, 87 insertions(+), 1436 deletions(-)

Reproduced identically in three independent worktrees, so it's the tree, not one machine.

Cargo.lock was last committed 2026-08-01 (0.63.0). Manifests changed 08-10 and 08-11 without it.

Why nothing caught it

Every CI job runs cargo without --locked. cargo then updates the lock in place and carries on green, so a stale lock is invisible on every PR.

The only jobs that pass --locked are the ones that never run on a PR:

.github/workflows/binary-release.yml:116  cross build ... --locked
.github/workflows/binary-release.yml:118  cargo build ... --locked

That is the release path. Running its exact command on main:

$ cargo build --release --bin pv -p aprender-contracts-cli --locked
error: cannot update the lock file ... because --locked was passed to prevent this

So the check that mattered only ran at the moment it was most expensive to fail — the same shape as the rest of this class: the guard did not scan the surface where the decision is made.

Fix

Regenerated Cargo.lock from the current manifests. cargo metadata --locked and the binary-release resolve path both exit 0 afterwards.

The 1,436 removed entries are dominated by arrow/parquet, consistent with the aprender-graph default-features work (#2467) landing without a lock update.

Guarded

check_lockfile_current.sh runs cargo metadata --locked — resolution is the whole question here, codegen is not, so it needs no build, no network, and takes about a second.

Its case table has a control row that is the actual point: row 2 adds a dependency to a probe manifest and asserts --locked refuses, so the guard cannot pass by never rejecting anything.

Mutation: restoring main's stale Cargo.lock turns the guard RED; regenerating turns it green. Verified both directions.

Wired into guard-runner-labels (in gate.needs). bashrs lint: 0 errors.

Found while investigating why agents' worktrees all showed a dirty Cargo.lock — it wasn't them.

…kflow could not build

On a clean checkout of main, `cargo metadata` ALONE -- no build, no test --
rewrites the lockfile:

    1 file changed, 87 insertions(+), 1436 deletions(-)

Reproduced identically in three independent worktrees, so it is the tree and not
one machine. Cargo.lock was last committed 2026-08-01 (0.63.0); manifests
changed 2026-08-10 and 2026-08-11 without it.

WHY NOTHING CAUGHT IT

Every CI job runs cargo WITHOUT --locked. cargo then updates the lock in place
and carries on green, so a stale lock is invisible on every PR. The only jobs
that pass --locked are the ones that never run on a PR:

    .github/workflows/binary-release.yml:116  cross build ... --locked
    .github/workflows/binary-release.yml:118  cargo build ... --locked

That is the RELEASE path. Running its exact command on main:

    $ cargo build --release --bin pv -p aprender-contracts-cli --locked
    error: cannot update the lock file ... because --locked was passed to
           prevent this

So the check that mattered only ran at the moment it was most expensive to fail
-- the same shape as the rest of this class: the guard did not scan the surface
where the decision is made.

FIX

Regenerated Cargo.lock from the current manifests. `cargo metadata --locked` and
the binary-release resolve path both exit 0 afterwards.

The 1436 removed entries are dominated by arrow/parquet, consistent with the
aprender-graph default-features work (#2467) landing without a lock update.

GUARDED

scripts/check_lockfile_current.sh runs `cargo metadata --locked`: resolution is
the whole question, codegen is not, so it needs no build and no network and
takes about a second.

Its case table has a control row that is the actual point -- row 2 adds a
dependency to a probe manifest and asserts --locked REFUSES, so the guard cannot
pass by never rejecting anything.

Mutation: restoring main's stale Cargo.lock turns the guard RED; regenerating it
turns it green. Verified both directions.

Wired into guard-runner-labels, which is in gate.needs. bashrs lint: 0 errors.
@noahgift

Copy link
Copy Markdown
Contributor Author

Superseded by #2527, which consolidates this with the other guard PRs. All four inserted into the same guard-runner-labels block in ci.yml, so merging them separately meant one conflict per merge — and each rebase is another push competing with the merge queue. Resolved once in #2527; the commits are carried over unchanged.

@noahgift noahgift closed this Aug 16, 2026
auto-merge was automatically disabled August 16, 2026 21:08

Pull request was closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant