Skip to content

Rust releases: skip versions crates.io already has, fail closed on every release git command (#211) - #216

Merged
konard merged 6 commits into
mainfrom
issue-211-694addd7e007
Oct 13, 2026
Merged

konard merged 6 commits into
mainfrom
issue-211-694addd7e007

Conversation

@konard

@konard konard commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Fixes #211.

What was still broken after #215

PR #215 (secrets: inherit) fixed the deploy key. In the first release run after it, 38359465127, the key arrives and the push lands, but nothing was published:

ssh-key: ***
git remote add origin git@github.com:link-foundation/start.git
New version: 0.24.0
[main b1e1cfb] rust-v0.24.0
✅ Version bump committed and pushed to main
start-command@0.24.0 is already published to crates.io
publish_result=already_published
GitHub release already exists: rust-v0.24.0 ([Rust] 0.24.0)

rust/Cargo.toml on main was 0.23.0. crates.io has had 0.24.0 since 2026-10-10T18:58Z, built from an older tree. The minor bump picked 0.24.0 again, and the self-healing publish step turned that into a green no-op. The fragments 204/208/210/211 were consumed into a ## [0.24.0] changelog entry that crates.io does not contain. Acceptance criteria 1 and 2 were therefore still unmet.

Changes

  • Skip versions crates.io already has. In scripts/release-git.mjs, nextUnpublishedVersion() keeps bumping until crates.io returns 404, and fails closed on any other status. For 0.23.0 with a minor bump and 0.24.0 taken, the result is 0.25.0.
  • Fail closed on every release command. command-stream's $ resolves on a non-zero exit. Fix #211: Rust release jobs get the deploy key (secrets: inherit); a rejected push fails the release #215 checked only git push. Now every git and version command in version-and-commit.mjs (fetch, rebase, add, commit, push, changeset version, instant bump) goes through checked().
  • Verify the version commit reached main before publishing. After the push, verifyCommitOnRemote() fetches main and requires the commit to be an ancestor of origin/main. Ancestry is used instead of comparing heads, because another merge may land right after the push.
  • Workflow guard. publish-to-crates.mjs emits published_before_run=true only when the version existed before it tried to publish. A retry that finds its own upload does not emit it. In both auto-release and manual-release, rust.yml fails the job when the run committed that version itself.
  • Changelog accuracy. While this PR was open, a manual minor release published start-command@0.25.0 (commit 69c82b4, crates.io 2026-10-13T07:11:48Z). Its tree includes PR fix: restore observed CPU quotas and recover penalty monitors #208 and PR fix: attribute Docker OOM exits after the last cgroup sample #210. The ## [0.24.0] entry is annotated as not on crates.io, and the 0.25.0 entry says it ships those changes. rust/changelog.d/211.md is a patch fragment for the automation fix.
  • Case study with CI evidence: docs/case-studies/issue-211/.

Not implemented: the "fragments remain on main" check

A PR merged during a release run can legitimately add a new fragment, so that check would fail spuriously. The ancestry check verifies the same thing directly: the commit that removed the fragments is on main.

How to reproduce

  • bun experiments/issue-211-rejected-push.mjs pushes to a bare remote whose pre-receive hook rejects the push. Output: { threw: false, code: 1, stderr: "remote: GH013: ..." }.
  • node experiments/issue-211-version-and-commit-e2e.mjs runs the real version-and-commit.mjs with a fake crates.io that already has 0.24.0:
    • Rejecting remote: exit 1, Error: git push origin main failed with exit code 1, no version_committed.
    • Accepting remote: New version: 0.25.0, Verified <sha> is on origin/main, and remote main gets rust-v0.25.0.

Tests

  • js/test/release-git.mjs (new): rejected push reproduction, checked() throwing, the ancestry check failing for a rejected push and passing after main moves on, version skipping (0.23.0 + minor with 0.24.0 taken → 0.25.0), and failing closed on HTTP 503.
  • js/test/publish-to-crates.mjs: published_before_run is set only for a version that already existed.
  • bun run check, actionlint and zizmor pass locally. zizmor reports the same findings as before.

Status of the acceptance criteria

Adding .gitkeep for PR creation (default mode).
This file will be removed when the task is complete.

Issue: #211
@konard konard self-assigned this Oct 13, 2026
konard and others added 3 commits October 13, 2026 07:07
…eached main

command-stream's $ resolves on a non-zero exit, so a failed fetch, rebase,
add or commit fell through like the rejected push did before #215. All of
them now go through checked() in scripts/release-git.mjs, and after the
push the version commit must be an ancestor of a freshly fetched
origin/main.

Run 38359465127 showed the defect left after #215: main had 0.23.0, the
minor bump picked 0.24.0, which crates.io already had from an older tree,
and the publish step turned into a green no-op. The Rust bump now skips
every version crates.io has, and rust.yml fails when the version the run
committed was already published before the publish step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The 0.24.0 entry on main was never published (crates.io had 0.24.0 from
2026-10-10); it is annotated, and a minor fragment makes the next release
0.25.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@konard konard changed the title [WIP] Rust releases are stuck at 0.24.0: Auto Release push is rejected by the main ruleset but the job ends green Rust releases: skip versions crates.io already has, fail closed on every release git command (#211) Oct 13, 2026
konard and others added 2 commits October 13, 2026 07:21
A manual minor release published start-command@0.25.0 (with PR #208 and
PR #210) while this PR was open, so the fragment no longer needs to force
a minor bump.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@konard
konard marked this pull request as ready for review October 13, 2026 07:32
@konard

konard commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

Working session summary

I've finished the fix for #211 and marked PR #216 ready for review. All 34 CI checks pass, and the full local JS suite passes (1247 tests, 0 failures).

What I found: PR #215 had already fixed the deploy key, and in the first release run after it (38359465127) the version commit did reach main. But the bump went from 0.23.0 to 0.24.0, a version crates.io already had from an older build on 2026-10-10. Publishing was skipped as "already published" and the job still ended green. So the CPU-penalty fixes (PR #208) and OOM-attribution fixes (PR #210) still weren't on crates.io.

What the PR changes:

  • Skips taken versions: the Rust bump keeps going until it reaches a version crates.io doesn't have. If crates.io answers with anything other than "found" or "not found", the release fails rather than guessing.
  • Every release command is checked: Fix #211: Rust release jobs get the deploy key (secrets: inherit); a rejected push fails the release #215 only checked git push. Now fetch, rebase, add, commit, push and the version-bump steps all fail the job if they fail.
  • Confirms the commit reached main: after pushing, the script fetches main and fails unless the version commit is part of it. This still works if someone else merges right after the push.
  • Workflow guard: rust.yml now fails if the run committed a version that was already on crates.io before publishing. A retry that finds its own earlier upload doesn't trigger it.
  • Tests: js/test/release-git.mjs uses a local remote that rejects every push, the way the main ruleset did, plus a fake crates.io. Two scripts in experiments/ reproduce the silent rejected push and run the real release script end to end. A write-up with the CI evidence is in docs/case-studies/issue-211/.

Partly done outside this PR: while I was working, someone ran a manual release that published start-command@0.25.0 to crates.io, and it includes PRs #208 and #210. That covers the issue's goal of getting those fixes onto crates.io. I added a note to the 0.24.0 changelog entry saying it never reached crates.io, and made this PR's changelog fragment a patch, so the next automatic release will be 0.25.1.

Still unconfirmed: a fully automatic release from start to finish. Only the first release run on main after this merges can show that.

Not done as suggested: the issue proposed failing a run if changelog fragments remain on main afterwards. A PR merged during the release could add a new fragment and make that fail for no real reason. The check that the version commit reached main covers the same failure, and the case study explains this.


This summary was automatically extracted from the AI working session output.

@konard

konard commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

🤖 Solution Draft Log

This log file contains the complete execution trace of the AI solution draft process.

💰 Cost: $2.811051

📊 Context and tokens usage:

  • 117.0K / 1M (12%) input tokens, 42.4K / 128K (33%) output tokens

Total: (142 new + 108.3K cache writes + 5.5M cache reads) input tokens, 42.4K output tokens, $2.811051 cost

🤖 Models used:

  • Tool: Anthropic Claude Code
  • Requested: opus (claude-opus-5-5)
  • Thinking level: high (~23999 tokens)
  • Model: Claude Opus 5.5 (claude-opus-5-5)

📎 Log file uploaded as Gist (2253KB)


Now working session is ended, feel free to review and add any feedback on the solution draft.

@konard

konard commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

⚠️ Auto-merge blocked: this pull request is ready, but it was not merged automatically

All merge requirements are satisfied — CI passed, there are no conflicts, and there are no pending changes.

Auto-merge (--auto-merge) was requested but is being held back:

What to do next:


Reported automatically by hive-mind with the --auto-merge flag.

@konard
konard merged commit 6ac9895 into main Oct 13, 2026
42 checks passed
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.

Rust releases are stuck at 0.24.0: Auto Release push is rejected by the main ruleset but the job ends green

1 participant