Skip to content

fix(ci): add publish verification to prevent false positive Rust releases#256

Merged
konard merged 4 commits intomainfrom
issue-255-a04aa1055933
Apr 13, 2026
Merged

fix(ci): add publish verification to prevent false positive Rust releases#256
konard merged 4 commits intomainfrom
issue-255-a04aa1055933

Conversation

@konard
Copy link
Copy Markdown
Contributor

@konard konard commented Apr 13, 2026

Summary

  • Root cause analysis of false positive success on Rust package publishing
  • New publish-to-crates.mjs script with retry logic and post-publish verification against the crates.io API
  • Updated rust.yml workflow (both auto-release and manual-release) to use the new script
  • Case study documentation with timeline reconstruction and CI log excerpts

Root Causes Found

v0.8.0 — False Positive (GitHub release created, crate never published)

At commit b1d0d1d, the workflow had no cargo publish step in the auto-release job. The flow went:
cargo build --releaseCreate GitHub Release (skipping cargo publish entirely).

The Create GitHub Release step was gated on should_release == 'true' (not on published == 'true'), so it ran regardless of whether the crate was published.

Verified: link-assistant-agent returns 404 on crates.io — it was never published.

v0.9.0 — Correct Failure (cargo publish failed due to dirty Cargo.lock)

The cargo publish step was added in a subsequent PR, but it failed because cargo build --release (run in the workflow after the commit step) modified Cargo.lock, leaving it dirty.

error: 1 files in the working directory contain changes that were not yet committed into git:
Cargo.lock

Fix

New scripts/publish-to-crates.mjs (modeled after publish-to-npm.mjs):

  1. Pre-check: Queries crates.io API to see if version is already published
  2. Publish: Runs cargo publish --verbose --allow-dirty with retry logic (3 attempts)
  3. Post-verify: Queries crates.io API to confirm the crate version actually appeared
  4. Output: Sets published=true only after successful verification

The --allow-dirty flag prevents the Cargo.lock issue, while the post-publish verification ensures the crate actually made it to crates.io.

Test Plan

  • Verified crates.io API queries work correctly via experiments/test-crates-io-verification.mjs
  • Confirmed link-assistant-agent is NOT on crates.io (404)
  • Confirmed agent crate is owned by different user (liangshuai)
  • Validated workflow YAML syntax
  • Validated publish script Node.js syntax
  • Full end-to-end test requires a real cargo publish with valid token (will be tested on next release)

Documentation

  • docs/case-studies/issue-255/README.md — Full case study with timeline, root causes, and evidence
  • docs/case-studies/issue-255/ci-log-excerpts.md — Relevant CI log excerpts from 3 runs

Fixes #255

🤖 Generated with Claude Code

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

Issue: #255
@konard konard self-assigned this Apr 13, 2026
…ases

Replace raw `cargo publish` in rust.yml with a new `publish-to-crates.mjs`
script that verifies the crate actually appeared on crates.io after publishing.

Root causes found:
- v0.8.0: workflow had no `cargo publish` step at all — GitHub release was
  created directly after `cargo build`, with no actual crate publishing
- v0.9.0: `cargo publish` failed because `Cargo.lock` had uncommitted changes
  after `cargo build --release` modified it post-commit

Fixes:
- New `publish-to-crates.mjs` script with retry logic and post-publish
  verification against the crates.io API (matching `publish-to-npm.mjs` pattern)
- Uses `--allow-dirty` flag to avoid Cargo.lock false failures
- GitHub release creation remains gated on `published == 'true'` output
- Includes case study documentation with timeline and CI log excerpts

Fixes #255

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@konard konard changed the title [WIP] False positive success on Rust package publishing fix(ci): add publish verification to prevent false positive Rust releases Apr 13, 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@konard konard marked this pull request as ready for review April 13, 2026 02:55
@konard
Copy link
Copy Markdown
Contributor Author

konard commented Apr 13, 2026

🤖 Solution Draft Log

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

💰 Cost: $7.125467

📊 Context and tokens usage:

Claude Opus 4.6:

  • Context window: 147.4K / 1M (15%) input tokens, 29.2K / 128K (23%) output tokens

Total: (138.4K + 10.8M cached) input tokens, 29.2K output tokens, $6.981619 cost

Claude Haiku 4.5:

Total: (48.3K + 521.3K cached) input tokens, 6.3K / 64K (10%) output tokens, $0.143848 cost

🤖 Models used:

  • Tool: Anthropic Claude Code
  • Requested: opus
  • Main model: Claude Opus 4.6 (claude-opus-4-6)
  • Additional models:
    • Claude Haiku 4.5 (claude-haiku-4-5-20251001)

📎 Log file uploaded as Gist (3110KB)


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

@konard
Copy link
Copy Markdown
Contributor Author

konard commented Apr 13, 2026

✅ Ready to merge

This pull request is now ready to be merged:

  • All CI checks have passed
  • No merge conflicts
  • No pending changes

Monitored by hive-mind with --auto-restart-until-mergeable flag

@konard konard merged commit 33d1d8c into main Apr 13, 2026
16 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.

False positive success on Rust package publishing

1 participant