Skip to content

Dev - #8

Merged
T342guy merged 8 commits into
mainfrom
Dev
Aug 22, 2026
Merged

Dev#8
T342guy merged 8 commits into
mainfrom
Dev

Conversation

@T342guy

@T342guy T342guy commented Aug 22, 2026

Copy link
Copy Markdown
Owner

No description provided.

T342guy and others added 8 commits August 21, 2026 23:47
The image was a separate workflow, so it built whatever Cargo.toml said at
its own ref while only the release run ever bumped it. An image published
from main therefore carried the version from before the bump, and the release
archives and the image disagreed about what they were.

There is one pipeline now, in the order the work actually depends on: work
out and commit the version, build and package the binaries from that tag,
publish the release, then build the image from the same commit and push it
tagged with that version — plus latest, but only from main, so a manual run
from a branch cannot move it.

The image job runs after publish rather than beside it, so a published image
always corresponds to a release that exists. On branch builds publish is
skipped rather than run, so the job depends on `always()` and a check that
nothing failed; there it builds the image without pushing, which still
validates the Dockerfile.

The version stamping both build jobs need is now scripts/stamp-version.sh
rather than two copies of the same shell inside the YAML — it is idempotent,
verifies Cargo.lock came along, and can be run by hand. Verified locally:
stamping twice is a no-op, --locked still builds afterwards, and the binary
reports the stamped version.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCG3RQAiVnGLAMCxxwAFvf
CI and release were two workflows racing on every push. They are one run
now, so a green tick on a commit means the same run that would have
released it was happy with it. ci.yml is gone; release.yml grew `checks`
and `bench` jobs, and `publish` waits on both.

The bump and the tag moved out of `prepare` and into `publish`, which is
the more important half of the change: they now happen after the checks
and every build have passed, so a failing run no longer leaves a dangling
tag and a burned version number behind.

Benchmarks are compared against the previous release rather than just
printed. bench-report.sh reduces a criterion run to one median and one
absolute deviation per case and attaches it to the release as
benchmarks.json; the next release downloads it and bench-compare.sh rates
the result. A case only counts as moved when it clears both a flat 5%
floor and the two runs' own measured spread, and the overall figure is the
geometric mean of the ratios. The verdict opens both the release notes and
the job summary.

Pre-releases: dispatch with `prerelease` ticked to cut 0.1.3-pre1-<date>.
They are numbered from the last *production* tag, so cutting them never
advances what the next production release will be called — pre1 through
pre9 of 0.1.3 still leave 0.1.3 as the next real release, which simply
drops the preN part. They are also inert by construction: marked as a
pre-release on GitHub, the tag pushed without moving the branch so main
never carries a preN version, and the image tagged `prerelease` rather
than `latest`.

Both scripts are tested rather than trusted. test-next-version.sh pins the
"pre-releases must not advance production" case directly;
test-bench-tools.sh caught a real units bug where the overall figure was a
fraction while the per-case deltas were percentages, so halving every
benchmark reported "-0.5%" instead of "-50%". lint-workflows.sh extracts
the bash embedded in the workflow and runs it past bash -n and shellcheck,
since nothing else was checking the most fragile code in the repo.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCG3RQAiVnGLAMCxxwAFvf
Production releases are manual-only now. Cutting one is the single
decision that needs a human to say patch, minor or major, so it happens
from the Actions tab on main with the bump chosen there. Asking for a
production release off any other branch is refused rather than quietly
downgraded — it would tag code main has never seen.

Everything else publishes automatically, on its own channel:

  main, pushed        0.1.4-pre1-2026.aug.22
  main, dispatched    0.1.4-2026.aug.22
  dev, pushed         0.1.4-dev1-2026.aug.22
  a pull request      0.1.4-claude.1-2026.aug.22
  anything else       built and checked, nothing published

"A pull request branch" means one with an open pull request, and the
channel is named after whoever opened it — on a push the event carries no
PR, so the workflow asks for it. A branch with no PR has no author to name
a channel after and does not mint releases. Fork pull requests are built
and checked but never tagged: untrusted code does not get a release.

The base still comes from the last production tag, so none of these
channels advance production numbering — pre, dev and every contributor can
be running against 0.1.4 at once and the next production release is still
0.1.4, which simply drops the channel part. Counters are per channel and
restart when production ships.

pre and dev join straight onto their counter; a username takes a dot.
That asymmetry is load-bearing rather than sloppy: neither fixed channel
can end in a digit, but a username can, and `user1` with counter 1 would
read `user11` with no way to parse it back. Logins are sanitised into
valid semver identifiers on the way in, so dependabot[bot] becomes the
dependabot-bot channel.

latest still means the last production release and nothing else. The two
standing channels get their own moving tags, prerelease and dev;
contributor channels get only their exact version, so a pull request can
never move a tag someone is following.

The branch rules live in release-plan.sh rather than in YAML so they can
be tested — 57 cases now cover the channel formats, the per-channel
counters, the refusals and the login sanitising. Runs on main and dev no
longer cancel each other, so a publish is never interrupted half way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCG3RQAiVnGLAMCxxwAFvf
The notice read "channel: production" on a branch build that publishes
nothing at all, because an empty channel means both "production" and
"not publishing" and the fallback could not tell them apart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCG3RQAiVnGLAMCxxwAFvf
Three cases exercised the "nothing tagged yet" fallback, where the base
comes from the manifest rather than a tag — and asserted a literal 0.1.1,
which was only right while Cargo.toml said 0.1.0. Merging dev brought in
84fa313, the release commit that stamps Cargo.toml to 0.1.3, so the
fallback started returning 0.1.4 and the suite failed on the version
number rather than on any behaviour.

The test was reading the project's live version and treating it as a
constant, so it was going to break on the first release that stamped the
manifest. It was a question of when.

Those cases now write their own manifest and read it with --manifest, so
nothing in the suite depends on what Packrat is versioned at today. Added
with them: the post-release shapes the fallback actually has to cope with
(a version already carrying a date, a preN, or a contributor channel, all
of which must be stripped back to a bare number before bumping), and a
case whose fixture is deliberately 9.9.9 so that any future drift back
onto the repo's own Cargo.toml fails loudly instead of silently.

Verified by running both suites against manifests reading 0.1.0,
0.1.3-2026.aug.21, 2.5.9-pre4-2027.jan.1 and 41.0.0 — 63 and 21 cases
pass unchanged in all four.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCG3RQAiVnGLAMCxxwAFvf
Stop the version tests asserting a version number
@T342guy
T342guy merged commit 8fd5487 into main Aug 22, 2026
11 checks passed
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.

2 participants