fix(release): gate the publish on CI instead of re-running it, and widen the wait#356
Merged
Merged
Conversation
…den the wait Two structural defects turned every release into a slow coin flip. v1.0.56 hit both. `npm-publish.yml` ran `pnpm validate:full` before publishing. That re-executed the entire gate suite SERIALLY in one job — the same suite `ci.yml` had already run for that exact commit, sharded across ~7 parallel jobs when it landed on main. The step took 48m57s of a 51-minute publish and proved nothing new. It is the pipeline ci.yml's own header describes escaping: "was a single ~40-min serial job". Replace it with the invariant that actually matters: poll `ci.yml`'s run for the tagged commit and refuse to publish unless it concluded success. That is strictly stronger than before, because `validate:full` never checked whether CI had passed at all — it just re-ran a subset by hand. Then do only the work specific to publishing: `build:clean` (prepack needs a dist, and a release must not inherit stale output) and `smoke:tarball` (packs and inspects the real artifact, the check that catches bundling regressions in what users install). `dockerhub-release.yml`'s `github-release` job waits for that publish on a fixed 120x15s = 30-minute budget. A ~50-minute publish cannot fit, so it timed out 2m38s early and failed the workflow. v1.0.55 had cleared the identical wait with 18 SECONDS to spare — the gate was passing by accident. The window also floats: the job starts only after the image builds, so faster builds make it expire earlier. State the budget once as ATTEMPTS + INTERVAL_SECONDS, raise it to 60 minutes, and have the timeout message report the budget it exhausted so "slow" is distinguishable from "hung". Also bound the publish job with timeout-minutes. It had none, so it inherited GitHub's 6-hour default; one earlier release run sat for 2h26m before failing. Guarded by test/architecture/release-pipeline-gate.test.ts, which fails on the pre-patch workflows for all three properties. Workflow files are not built, linted, or executed by `pnpm validate`, and the race only manifests on a tag push that no PR exercises — so nothing else could have caught either defect. Fixes the stale CLAUDE.md claim that no workflow creates the GitHub release: dockerhub-release.yml's github-release job does.
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.
Description
Two structural defects made every release a slow coin flip. v1.0.56 hit both.
1. The publish path re-ran CI's entire gate suite, serially.
npm-publish.ymlcalledpnpm validate:fullbefore publishing — the same suiteci.ymlhad already run for that exact commit, sharded across ~7 parallel jobs when it landed on main. Measured on v1.0.56: that one step took 48m57s of a 51-minute publish. It is precisely the pipelineci.yml's own header describes escaping — "was a single ~40-min serial job".Replaced with the invariant that actually matters: poll
ci.yml's run for the tagged commit and refuse to publish unless it concludedsuccess. This is strictly stronger than before, becausevalidate:fullnever checked whether CI had passed at all — it just re-ran a subset by hand. Then only publish-specific work remains:build:clean(prepack needs a dist, and a release must not inherit stale output) andsmoke:tarball(packs and inspects the real artifact — the check that catches bundling regressions in what users install).2. The workflow waiting on that publish could not outlast it.
dockerhub-release.yml'sgithub-releasejob polled on a hard-coded120 × 15s= 30-minute budget. A ~50-minute publish cannot fit, so it timed out 2m38s early and failed:v1.0.55 cleared the identical wait with 18 seconds to spare — the gate was passing by accident. The window also floats: the job starts only after the image builds, so faster builds make it expire earlier. Budget is now stated once as
ATTEMPTS+INTERVAL_SECONDS, raised to 60 minutes, and the timeout message reports the budget it exhausted so "slow" is distinguishable from "hung".3. Also: the publish job had no
timeout-minutes, inheriting GitHub's 6-hour default — one earlier release run sat 2h26m before failing. Now bounded at 90.Net effect: the publish drops from ~51 minutes to roughly the CI wait plus ~5 minutes of build-and-pack, and the Docker Hub race disappears.
Related Issue
N/A: release-pipeline CI configuration. No runtime behavior, security boundary, or public API changes — the defects live entirely in
.github/workflows/and were observed live on the v1.0.56 release.Type of Change
Checklist
pnpm validate) — ran via the pre-push hookactions: readto read workflow runsRED Test Proof
test/architecture/release-pipeline-gate.test.tsfails on the pre-patch workflows for all three properties. Captured by restoringHEAD's workflow files and re-running:All 3 pass on this branch.
Evidence and Residual Risk
gh: CI-success →exit 0; CI-failure → printsRefusing to publish a commit whose CI did not passandexit 1; exhausted budget → bounded loop, timeout message,exit 1. Both files parse as YAML and both blocks passbash -n. Budget arithmetic verified: publish waits 45 min for CI, Docker Hub waits 60 min for the publish.pnpm validategreen via pre-push); workflow logic exercised against a stubbed GitHub CLI rather than a live tag.ci.ymlmust actually produce a run for the tagged commit, otherwise the new gate waits its full 45 minutes and fails — if a tag is ever cut on a commit that never landed on main via a push, this blocks rather than silently publishing, which is the intended direction but is a behavior change; (b) the publish now depends on the GitHub Actions API being readable, a new failure mode that did not exist before; (c) the 60-minute Docker Hub budget is sized for a publish that no longer waits ~49 minutes — if the CI wait ever dominates, revisit both numbers together. Unrelated and still open from the v1.0.56 clean-room install:comis initaccepting an under-length gateway token into a systemd restart loop,comis doctor's PID-file false negative under systemd, andinit --quickrelocating the documented log path.🤖 Generated with Claude Code