Skip to content

ci: release without anyone running a release - #16

Merged
github-actions[bot] merged 1 commit into
mainfrom
ci/self-releasing
Aug 16, 2026
Merged

ci: release without anyone running a release#16
github-actions[bot] merged 1 commit into
mainfrom
ci/self-releasing

Conversation

@catomean

Copy link
Copy Markdown
Collaborator

Two things still required a human. Both are now gone.

Cutting a release

It meant npm version && git push --tags from a laptop. Now: merge a version bump to main and the package ships. The workflow asks the registry whether package.json's version already exists, and publishes it if not.

That check rather than a tag trigger, for two reasons:

  • a tag pushed by GITHUB_TOKEN does not start another workflow — so "push a tag, let publish.yml notice" silently never runs. This fleet has hit that trap before.
  • asking npm what's published is idempotent: re-running the workflow, or pushing a tag by hand, can't double-publish or fail confusingly.

The tag is now created after a successful publish, so a tag never claims a release that didn't happen.

The token expiring

NPM_TOKEN expires 2026-11-14. Without a check, the thing that discovers that is a release failing in three months — and npm reports it as 403/ENEEDAUTH, which reads like a permissions problem rather than an expiry.

token-health.yml probes npm whoami weekly and, on failure, opens one issue (not one per week) with the fix written in it — including the trusted-publishing route that deletes the token entirely so it can't expire again.

Verified before shipping

  • both files parse as YAML
  • the registry check was run against the real registry: ai-forms@0.1.1 → "already published, skip"; ai-forms@9.9.9 → "would publish"

🤖 Generated with Claude Code

Two things still required a human, and both are now gone.

**Cutting a release.** It meant `npm version && git push --tags` from a laptop.
Now: merge a version bump to main and the package ships. The workflow asks the
registry whether package.json's version already exists and publishes it if not.

That check, rather than a tag trigger, for two reasons. A tag pushed by
GITHUB_TOKEN does not start another workflow — so "push a tag, let publish.yml
notice" silently never runs, which is a trap this fleet has hit before. And
asking npm what is published is idempotent: re-running the workflow, or pushing
a tag by hand, cannot double-publish or fail confusingly. The tag is now created
AFTER a successful publish, so a tag never claims a release that did not happen.

**The token expiring.** NPM_TOKEN expires 2026-11-14. Without a check, the thing
that discovers that is a release failing in three months — and npm reports it as
403/ENEEDAUTH, which reads like a permissions problem, not an expiry. So
token-health.yml probes `npm whoami` weekly and, when it fails, opens a single
issue with the fix written in it, including the trusted-publishing route that
removes the token entirely.

Verified before shipping: both files parse as YAML, and the registry check was
run against the real registry — ai-forms@0.1.1 correctly reports "already
published, skip", ai-forms@9.9.9 correctly reports "would publish".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions
github-actions Bot merged commit 7273cee into main Aug 16, 2026
1 check passed
@github-actions
github-actions Bot deleted the ci/self-releasing branch August 16, 2026 15:46
github-actions Bot pushed a commit that referenced this pull request Aug 16, 2026
The self-releasing workflow I merged an hour ago would not have released
anything, and the proof is in this repo: #16 merged to main and no publish run
started. threadkit's identical change did fire — because I merged that one by
hand with a user token.

auto-merge merges with GITHUB_TOKEN, and a push made with that token starts no
workflow. So `on: push: branches: [main]` silently does not fire for exactly the
merges that matter here. This is the no-cascade rule already documented in
CLAUDE.md, and I walked into it while writing the thing meant to remove manual
steps.

Two fixes, because one of them is a promise and the other is a mechanism:

- auto-merge.yml carries REARM_WORKFLOWS, whose comment says "keep this in sync
  when a push-triggered workflow is added". I added one and did not. Now listed.
- More importantly: publish.yml gains an hourly schedule. The question it asks —
  "is package.json's version on the registry?" — is idempotent, so asking it on a
  timer costs one `npm view` when there is nothing to do and repairs a missed
  release when there is. A hand-maintained list of workflows to re-arm is
  something to keep correct forever; a reconciler is correct by construction.

This matches how deploys already work in the fleet: compare desired against
actual and act on the difference, rather than trusting an event to arrive.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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