Skip to content

Publishes to npm from a version tag push - #206

Merged
johnnyt merged 1 commit into
mainfrom
pts-xt71-release-workflow-on-tag
Oct 4, 2026
Merged

johnnyt merged 1 commit into
mainfrom
pts-xt71-release-workflow-on-tag

Conversation

@johnnyt

@johnnyt johnnyt commented Oct 4, 2026

Copy link
Copy Markdown
Member

What

The npm publish moves from a person's hand to a GitHub Actions workflow.
.github/workflows/release.yml publishes @riddler/predicator when a
v*.*.* tag is pushed, and only when every check before the publish passes
at the tagged commit:

  • the tagged commit is an ancestor of the default branch's head, the branch
    named by the push event (github.event.repository.default_branch), never a
    literal name;
  • the tag without its v equals .version in package.json at that commit;
  • npm does not already show that version (a version already published is
    reported, never published again; this also answers a re-run of a run that
    did publish);
  • the full quality gate is green: the toolchain, cache, dependency and gate
    steps are copied byte for byte from ci.yml, and the gate command is read
    from gate.full in .claude/wurk.json as CI reads it.

The publish runs under npm trusted publishing: the job's permissions are
contents: read and id-token: write, no token exists in the file, the
repository's secrets or anywhere else, and npm adds provenance itself. Before
the publish, node and npm are checked against trusted publishing's floor and
npm is upgraded only when it is below it. npm publish runs under
mise exec --, so the existing prepack publish guard runs unchanged. The
run ends by printing the published version's address. Nothing else triggers
the workflow: no branch push, no pull request, no manual dispatch.

CLAUDE.md's bold npm publish row, two clauses of its relay paragraph
and the publish sentence of its Release preps paragraph, and the publish
sentences of .claude/wurk/release.md, now say the same thing: an agent or a
session never runs npm publish; the release workflow publishes on the tag
push the release-prep row already allows; a failed workflow is re-run from its
Actions page, never worked round by a local publish. The rewording is the
maintainer's own words, ruled by the operator, 2026-10-04.

ADR-0006 records the decision at proposed: the three conditions, the
registry, the trust model by name, what a failed publish does, the
documentation decision and that a published version stands. It also says a
re-run of a failed publish repeats the checks and the gate, and that a
prerelease tag is not a case it decides. It stays proposed
until a version has been published through the workflow.

No file under src/ changes, and no version or tag moves.

Checks

  • Full gate (mise exec -- pnpm run gate) green locally on this tree.
  • actionlint was not run: it is not installed on the machine this was
    written on. Instead the file was parsed as YAML, every run: script passed
    bash -n, and the four check steps were exercised under bash in a scratch
    clone at the v0.6.0 tag with the step's environment set by hand: the
    ancestry and version checks passed, the registry check stopped with
    "already on npm", a mismatched tag name stopped the version check, an extra
    commit off the default branch stopped the ancestry check, and an empty
    default-branch name stopped the fetch. No step from the toolchain on, and
    no publish, has run.
  • The copied block was compared with ci.yml and is identical.

Direction check of the record

Every claim in ADR-0006 was checked against main and this branch:
package.json's repository.url, files, publishConfig and prepack
script; scripts/publish-guard.mjs as the guard prepack runs;
.github/workflows/ci.yml's toolchain-to-gate steps; gate.full in
.claude/wurk.json; and each workflow step the record names, cited by its
step name because the workflow exists only on this branch. The record cites no
commit. git diff origin/main -- docs/adr/ removes no line: the record is a
new file and the index gains one row.

Provenance

  • Engineering choices (the workflow runs the gate itself, the default branch
    read from the event, the version read from package.json at the tag, the
    toolchain copied from ci.yml, npm trusted publishing, one record, no manual
    dispatch): decided by the conductor under a standing consent, 2026-10-03.
  • The failed-publish handling and the documentation decision: decided by the
    conductor under a standing consent, 2026-10-04.
  • The npm upgrade is guarded rather than unconditional: the node mise.toml
    pins already bundles an npm above the floor, so an unconditional upgrade
    would only add an unpinned major to every release; the floor is still
    enforced. Decided by the conductor under a standing consent, 2026-10-04.
  • The registry check before the toolchain is the implementation of "a version
    the registry already shows is reported, not re-published".
  • concurrency is set at the workflow's top level over its single job, keyed
    by the tag ref, with cancel-in-progress: false.
  • Beyond the named row and sentences, more text moved because the change made
    it false or ambiguous: in CLAUDE.md's relay paragraph, "publishing" in
    the list of what stays forbidden now reads "running npm publish", and its
    last clause names the workflow as what publishes; and the closing publish
    sentence of .claude/wurk/release.md. The ADR
    index in docs/adr/README.md gains the new record's row, as every new
    record here has.
  • No changelog fragment: changelog.d/README.md excludes documentation, ADRs
    and CI changes.

A release workflow publishes @riddler/predicator to npm when a v*.*.*
tag is pushed, and only when the tagged commit is on the default
branch the push event names, the tag equals package.json's version
there, npm does not already show that version, and the full gate,
copied from ci.yml and read from gate.full, is green there. It
publishes under npm trusted publishing: id-token write, no token
anywhere, provenance automatic, npm checked against the floor and
upgraded only when below it, and the prepack guard left to run.

The authority table's npm publish row, its relay paragraph, the
Release preps paragraph and the release recipe now say an agent or a
session never runs npm publish: the workflow publishes on the tag
push, and a failed run is re-run from its Actions page, never worked
round by a local publish. ADR-0006 records the decision at proposed.

No source file, version or tag moves. actionlint was not run. Run: the
full pnpm gate green on this exact staged tree.

Refs: pts-xt71
@johnnyt
johnnyt merged commit fc0d86c into main Oct 4, 2026
1 check passed
@johnnyt
johnnyt deleted the pts-xt71-release-workflow-on-tag branch October 4, 2026 23:52
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