Pair each ref with the version kind it publishes; stamp the version into the library #63

Merged
mph merged 1 commit from ci/publish-gate-and-buildinfo into main 2026-08-14 17:49:46 +00:00
Owner

Two changes, both consequences of cutting 0.5.0.

1. The publish collision that made the 0.5.0 tag run fail

Tag v0.5.0 and main named the same commit, and that commit carried publishVersion = "0.5.0". Both refs match this workflow's trigger, so two runs raced to publish the same version:

  • Run 393 (push to main) — published first, succeeded.
  • Run 394 (push of tag v0.5.0) — HttpTransporterException: HTTP Status: 409. The registry refuses to overwrite a release.

The release itself was fine — all five artifacts are live at 0.5.0 — but the failure would repeat on every release, because main holds the release version for the span of one commit between the release commit and the bump back to a snapshot.

The publish step now runs only when the ref and the version kind match:

ref version publishes
branch -SNAPSHOT yes
branch release no
tag release yes
tag -SNAPSHOT no

2. The version is available at runtime

BuildInfo compiles publishVersion into works.iterative.claude.core.BuildInfo.version, so an application using the SDK can report which version it runs.

The value comes from the literal in build.mill, not from git state. Deriving it from git was considered and rejected:

  • Mill 1.1.x does ship mill.util.VcsVersion built in, and it works here.
  • But format() yields 0.5.0-1-f1cfde one commit past a tag — a new coordinate per commit. Consumers would lose the ability to pin 0.6.0-SNAPSHOT and pick up the newest build.
  • Its version task is a Task.Input and dirtyHash is part of the state, so any uncommitted edit would change the constant and recompile every module that depends on core.
  • Every actions/checkout@v4 here is a shallow clone with no tags. Verified: a --depth 1 clone of this repo has 0 tags and git describe --tags fails, so the version would silently fall back to 0.0.0.

A literal has none of those properties.

Verification

  • ./mill __.test — SUCCESS, including the two new BuildInfoTest cases
  • ./mill __.fix --check — SUCCESS
  • Gate logic exercised across all four ref/version combinations; results match the table above
  • Generated constant: val version: String = "0.6.0-SNAPSHOT"
  • claude-code-query-core_3 POM gains no dependency — the plugin is build-time only
  • uispike.laminar.fullLinkJS gzip 217852 B, under the 256000 B gate (BuildInfo is JVM-only)
Two changes, both consequences of cutting 0.5.0. ## 1. The publish collision that made the 0.5.0 tag run fail Tag `v0.5.0` and `main` named the same commit, and that commit carried `publishVersion = "0.5.0"`. Both refs match this workflow's trigger, so two runs raced to publish the same version: - Run 393 (push to `main`) — published first, succeeded. - Run 394 (push of tag `v0.5.0`) — `HttpTransporterException: HTTP Status: 409`. The registry refuses to overwrite a release. The release itself was fine — all five artifacts are live at 0.5.0 — but the failure would repeat on every release, because `main` holds the release version for the span of one commit between the release commit and the bump back to a snapshot. The publish step now runs only when the ref and the version kind match: | ref | version | publishes | |---|---|---| | branch | `-SNAPSHOT` | yes | | branch | release | no | | tag | release | yes | | tag | `-SNAPSHOT` | no | ## 2. The version is available at runtime `BuildInfo` compiles `publishVersion` into `works.iterative.claude.core.BuildInfo.version`, so an application using the SDK can report which version it runs. The value comes from the literal in `build.mill`, not from git state. Deriving it from git was considered and rejected: - Mill 1.1.x does ship `mill.util.VcsVersion` built in, and it works here. - But `format()` yields `0.5.0-1-f1cfde` one commit past a tag — a new coordinate per commit. Consumers would lose the ability to pin `0.6.0-SNAPSHOT` and pick up the newest build. - Its version task is a `Task.Input` and `dirtyHash` is part of the state, so any uncommitted edit would change the constant and recompile every module that depends on `core`. - Every `actions/checkout@v4` here is a shallow clone with no tags. Verified: a `--depth 1` clone of this repo has 0 tags and `git describe --tags` fails, so the version would silently fall back to `0.0.0`. A literal has none of those properties. ## Verification - `./mill __.test` — SUCCESS, including the two new `BuildInfoTest` cases - `./mill __.fix --check` — SUCCESS - Gate logic exercised across all four ref/version combinations; results match the table above - Generated constant: `val version: String = "0.6.0-SNAPSHOT"` - `claude-code-query-core_3` POM gains no dependency — the plugin is build-time only - `uispike.laminar.fullLinkJS` gzip 217852 B, under the 256000 B gate (BuildInfo is JVM-only)
ci,build: pair each ref with the version kind it publishes; stamp the version into the library
All checks were successful
CI / Check Linting (pull_request) Successful in 55s
CI / Run Tests (pull_request) Successful in 1m10s
CI / Run Integration Tests (pull_request) Successful in 1m45s
CI / Check Bundle Size (pull_request) Successful in 48s
CI / Check Formatting (pull_request) Successful in 58s
CI / Compile (pull_request) Successful in 1m18s
6b9551cc0b
The registry refuses to overwrite a release, so the 0.5.0 tag run failed with a
409: main and the tag named the same commit at the same release version, and the
main push had already claimed it. The publish step now runs only for a tag at a
release version, or a branch at a snapshot.

BuildInfo compiles publishVersion into works.iterative.claude.core.BuildInfo, so
an application using the SDK can report which version it runs. The value comes
from the literal in build.mill rather than from git state, which keeps the
constant stable across commits and dirty working trees.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
mph merged commit 7d1ba5d399 into main 2026-08-14 17:49:46 +00:00
mph deleted branch ci/publish-gate-and-buildinfo 2026-08-14 17:49:46 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
iterative-works/claude-code-query!63
No description provided.