Skip to content

Publishes to Hex from CI on a tag push - #686

Merged
johnnyt merged 1 commit into
mainfrom
sb-inp3-release-workflow-on-tag
Oct 5, 2026
Merged

johnnyt merged 1 commit into
mainfrom
sb-inp3-release-workflow-on-tag

Conversation

@johnnyt

@johnnyt johnnyt commented Oct 5, 2026

Copy link
Copy Markdown
Member

What

Today the publish is the one release step a person runs by hand; the version bump, the changelog promotion and the tag are already the automation's. This adds .github/workflows/release.yml, which publishes statifier_blocks to Hex when a version tag is pushed, and only when the tagged commit passes every check below. The move to tag-push publishing was ruled by the operator, 2026-10-04.

  • Trigger: a push of a tag matching v*.*.*, and nothing else (no branch push, no pull request, no workflow_dispatch). permissions: contents: read; one job; concurrency keyed by the tag ref with cancel-in-progress: false.
  • Before any toolchain: full-history checkout; the default branch is fetched under the name the push event gives (github.event.repository.default_branch, passed through env:); the run stops unless the tagged commit is an ancestor of that branch's head (git merge-base --is-ancestor), unless the tag without its v equals @version in mix.exs at the tagged commit, and when Hex already shows that version or does not answer.
  • Gate: the toolchain, cache, dependency and gate steps of ci.yml's gate job, copied byte for byte (Node and actions/setup-node@v4 included), so the gate is gate.full read from .claude/wurk.json (today mix quality) exactly as CI runs it. A red gate publishes nothing. The headless job is not copied: it proves an optional-dependency tree, is not part of the gate, and ci.yml runs it on every push to the default branch.
  • Publish: mix hex.publish --yes, docs with the package, with HEX_API_KEY from ${{ secrets.HEX_API_KEY }} in that one step's env: and nowhere else; then the hex.pm and HexDocs addresses of the version are printed.

CLAUDE.md's release-prep row (its "always for the publish" clause), its relay paragraph's last clause and its Release preps paragraph's publish sentence, and the closing publish sentence of .claude/wurk/release.md, now say in the operator's words: an agent or a session never runs mix hex.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 relay sentence that publishing or cutting a release stays forbidden however consent arrives is unchanged: it is still true.

ADR-0019 records the decision at proposed. It stays proposed until the workflow has published a version.

Provenance

  • Running the gate inside the workflow (not reading CI's result), the default branch from the event payload, the version from mix.exs at the tag, the toolchain copied from ci.yml rather than shared, and no manual dispatch: decided by the conductor under a standing consent, 2026-10-03.
  • Docs publishing with the package, no automatic retry, one hand re-run of a publish step that failed on a registry or network error, and a version Hex already shows reported rather than published again (the fourth pre-toolchain check): decided by the conductor under a standing consent, 2026-10-04.
  • Correction to the brief's wording: the acceptance says a published version is "replaceable on hex.pm within one hour, then only revertable". mix help hex.publish ("Reverting a package") says a new version of an existing package can be reverted or updated within one hour, and after that a version can only be retired (mix help hex.retire). The record states the latter.
  • docs/adr/.cite-baseline.json is regenerated by mix adr.cites --update: the new index row in docs/adr/README.md moves the README lines ADR-0005 cites by number, the same shape as earlier index-row additions on main. No record text is removed.
  • No changelog fragment: changelog.d/README.md excludes documentation, ADRs, and CI or agent tooling changes.

Checks

  • Full mix quality green on the committed tree: 3,954 of 3,954 tests, 95.3% coverage, dialyzer clean, ADR cites green.
  • actionlint was not run (it is not installed on the machine that wrote this). Instead: the file parses as YAML; every run: script passes bash -n; the copied block is byte-identical to the gate job's steps in ci.yml, from the comment above "Read the toolchain out of mise.toml" to the end of "Full quality gate"; and the four check steps' scripts were run under bash in a scratch clone at v0.42.0 with the step env set by hand: fetch, ancestry and version passed, the Hex check stopped with "already on Hex"; a mismatched tag name stopped the version check; an extra commit off main stopped the ancestry check. No step from the toolchain on, and no publish, has executed.
  • No file under lib/ changes; no version bump; no tag.

Direction check of the record

Every claim in ADR-0019 was checked against main at 9874ead and against the workflow in this request: the trigger, permissions, concurrency, the order of the checks, the copied block and the publish step match release.yml by step name; ci.yml's "Full quality gate" step and the gate job's steps match the cited range; the release-prep row, relay paragraph and Release preps paragraph match CLAUDE.md as this request leaves them; the Hex replace and revert window matches mix help hex.publish, and retirement matches mix help hex.retire. Cites into this repository are by anchor with the SHA they were read at; the workflow, which is only on this branch, is cited by step name alone. git diff origin/main -- docs/adr/ removes no line of any record; the only removed lines are the regenerated entries of .cite-baseline.json.

Out of this request: changelog.d/README.md's "At release" section still says the publish is the operator's; it is corrected separately.

A new workflow, .github/workflows/release.yml, publishes this package
to Hex when a v*.*.* tag is pushed, and only when the tagged commit is
on the default branch (named by the push event, never written in the
file), the tag names @Version in mix.exs at that commit, Hex does not
already show that version, and the full gate (gate.full from
.claude/wurk.json) is green there. The toolchain-to-gate steps are
copied byte for byte from ci.yml's gate job, Node included; the
headless job is not copied. The publish step alone sees the
HEX_API_KEY secret; the docs publish with the package.

CLAUDE.md's release-prep row, relay paragraph and Release preps
paragraph, and the closing section of .claude/wurk/release.md, now say
an agent or a session never runs mix hex.publish: the release workflow
publishes on the tag push, and a failed workflow is re-run from its
Actions page, never worked round by a local publish. ADR-0019 records
the decision at proposed; the index row moved cited README lines, so
the ADR cites baseline is regenerated.

Gate: full mix quality green on this staged tree (3,954 of 3,954
tests, 95.3% coverage, dialyzer clean, ADR cites green).

Refs: sb-inp3
@johnnyt
johnnyt merged commit d504636 into main Oct 5, 2026
2 checks passed
@johnnyt
johnnyt deleted the sb-inp3-release-workflow-on-tag branch October 5, 2026 00:10
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