Repository navigation
ci(publish): make publishing idempotent so a second run is green, not E403 - #33
Merged
Merged
Conversation
… E403
One merge starts Publish twice — the PAT-made push and the auto-merge
sweep's workflow_dispatch re-arm, seconds apart. Both ask the registry
before either publishes, both build, and the loser gets E403 "cannot
publish over previously published versions" (bip-kit 0.2.6, 0.2.7 on
2026-09-11). A red run that means nothing is wrong teaches everyone to
ignore the workflow.
- concurrency group "publish", never cancelled: the second run waits,
then sees the version on the registry and skips
- registry check writes a green step summary ("already published —
nothing to do") and gates install/verify/publish
- npm publish failure is re-checked against the registry: if the
version is there, that is the goal state, not an error
OIDC trusted publishing, verify-before-publish, tag checks and the
re-arm list are unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WqKqMnHQHSmkGFfc5t7Rxn
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The Publish workflow can run twice for one merge — once from the push (the auto-merge sweep merges with a PAT, whose pushes do trigger workflows) and once from the sweep's
workflow_dispatchre-arm (rearm_workflows: "ci.yml publish.yml"). Two runs asking the registry the same question at the same moment both hear "not published", both build, and the secondnpm publishgetsE403 cannot publish over previously published versions. A red run that means "nothing is wrong" trains everyone to ignore the workflow; the next thing ignored will be a real failure.The re-arm stays: it exists so a merge whose push trigger was suppressed still publishes. Idempotency is what makes both paths safe.
Measurement (
gh run list --workflow publish.yml --limit 10)Pattern not present in the last 10 runs (all hourly
scheduleticks against 31099dc, all success — no version bump has merged since the sweep switched to a PAT). The workflow has the same registry check and the same push + workflow_dispatch triggers as bip-kit, so the next version bump would hit the identical race.Fix — publishing is idempotent, at three layers
concurrency: { group: publish, cancel-in-progress: false }— the second run waits for the first instead of racing it, then finds the version on the registry and skips. Never cancel: a cancelled publish is a half-shipped release.npm view <name>@<version> version): if the exact version is already published, write a green step summary ("already published — nothing to do") and skip install/verify/publish.npm publishfails but the version is now on the registry, that is the goal state — green with a "published by a concurrent run" summary. A real publish failure still exits 1.Everything else is unchanged: OIDC trusted publishing, verify-before-publish, tag checks, triggers.
Mutation proof — the guard's shell snippet run locally against the real registry
(a) current version → "already published", exit 0. (b) fake bump
9.9.9-proof→ "not on the registry; releasing it". Nothing was published.Verification
pnpm run verifygreen locally (log:/tmp/verify-threadkit.log, exit 0). Prettier passes on the workflow file.🤖 Generated with Claude Code
https://claude.ai/code/session_01WqKqMnHQHSmkGFfc5t7Rxn