Skip to content

ci: guard the release and the path a new user takes first - #18

Merged
TMHSDigital merged 1 commit into
mainfrom
ci/release-and-smoke
Sep 22, 2026
Merged

TMHSDigital merged 1 commit into
mainfrom
ci/release-and-smoke

Conversation

@TMHSDigital

Copy link
Copy Markdown
Owner

Three additions, each aimed at a failure that has actually happened in this
repository.

Release workflow, on tag push

The first thing it does is refuse when the tag and __version__ disagree.
That is not hypothetical: v0.1.0 was built by hand and went out as
plumbline-0.1.0.dev0 against a tag reading v0.1.0.

It then re-runs the gate at the tag, builds the wheel and sdist, asserts the
filenames carry the released version, installs the wheel into a clean
environment to confirm neither torch nor transformers leaked into the core
install and that py.typed is present, and attaches both artifacts.

It deliberately will not create a release and will not generate notes from
commit messages. The notes here are written by hand, so the workflow refuses if
no release exists for the tag. A future release becomes: write the notes, push
the tag.

Verified locally that the version check behaves:

v0.1.0 -> PASS (package 0.1.0)
v0.2.0 -> would FAIL the release (package says 0.1.0)

Quickstart job, which walks the README instead of trusting it

The unit suite has now twice passed while the first thing a new user does
was broken: an adapter raising a bare TypeError on a missing setting, and a
local arm failing every case with the reason visible only inside the artifact
JSON. Both were found by hand, both were in the path a newcomer takes first.

The job runs the documented command and asserts the report carries ECE, its
floor, and the inconclusive wording that must not regress to reading as a pass.
Then it checks the clone is still clean afterwards, and that a missing required
setting produces a named refusal with no traceback.

All assertions dry-run locally:

OK: ECE
OK: INCONCLUSIVE
OK: "INCONCLUSIVE" is not a pass
OK: calibrated-model floor
clone clean after quickstart: yes
OK: version matches __version__

Wheel job

The built distribution is a different artifact from the source tree. The entry
point, the optional-extra boundary and py.typed only exist once packaged,
which is exactly where Gate 6 found bugs.

Weekly schedule

Nothing here pins transitive dependencies beyond uv.lock's resolution, so a
release elsewhere can break the build with no commit of ours involved. Weekly
finds that while it is still small, and is rare enough that nobody learns to
ignore the mail. workflow_dispatch added to both workflows.

Not added

CI caching — already enabled via setup-uv's enable-cache: true. Noted
in PLAN.md rather than re-added.

PyPI publishing — declined, recorded in PLAN.md with the condition that
would reopen it.

Also: PLAN.md no longer claims the repository is private.

Three additions, each aimed at a failure that has actually happened here.

A release workflow, on tag push. v0.1.0 was built by hand and went out as
plumbline-0.1.0.dev0 against a tag reading v0.1.0, so the first thing this
does is refuse when the tag and __version__ disagree. It then re-runs the gate
at the tag, builds the wheel and sdist, asserts the filenames carry the
released version, installs the wheel into a clean environment to confirm
neither torch nor transformers leaked into the core install and that py.typed
is present, and attaches both artifacts. It will not create a release and will
not generate notes from commit messages: the notes are written, so the
workflow refuses if no release exists for the tag.

A quickstart job that walks the README rather than trusting it. The unit suite
has twice passed while the first thing a new user does was broken: an adapter
raising a bare TypeError on a missing setting, and a local arm failing every
case with the reason visible only inside the artifact JSON. Both were found by
hand. The job runs the documented command, asserts the report carries ECE, its
floor, and the inconclusive wording that must not regress to reading as a
pass, checks the clone is still clean afterwards, and confirms a missing
required setting produces a named refusal with no traceback.

A wheel job, because the built distribution is a different artifact from the
source tree. The entry point, the optional-extra boundary and py.typed only
exist once packaged, which is where Gate 6 found bugs.

Also a weekly schedule and workflow_dispatch on CI. Nothing here pins
transitive dependencies beyond uv.lock's resolution, so a release elsewhere can
break the build with no commit of ours involved. Weekly finds that while it is
small and is rare enough that nobody learns to ignore it.

CI caching was already enabled via setup-uv, so nothing was added for it.

PLAN.md no longer says the repository is private.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@TMHSDigital
TMHSDigital merged commit da7b736 into main Sep 22, 2026
11 checks passed
@TMHSDigital
TMHSDigital deleted the ci/release-and-smoke branch September 22, 2026 02:42
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