Skip to content

release: close remaining tag and artifact coherence gaps - #559

Merged
dgenio merged 13 commits into
mainfrom
agent/release-coherence-hardening
Aug 30, 2026
Merged

release: close remaining tag and artifact coherence gaps#559
dgenio merged 13 commits into
mainfrom
agent/release-coherence-hardening

Conversation

@dgenio

@dgenio dgenio commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Summary

Hardens the remaining release-coherence boundaries tracked by #519 without changing package/runtime behavior.

What changed

  • publication checkout now fetches tags and proves that the release tag resolves to the exact checked-out commit before any test/build/publish work continues;
  • release validation exposes the verified commit as workflow output for auditability;
  • adds stdlib-only scripts/verify_dist.py to inspect the exact wheel and sdist built for publication before they are uploaded;
  • verifies artifact cardinality and filenames;
  • verifies wheel METADATA and sdist PKG-INFO Name/Version against the intended release;
  • verifies the wheel contains chainweaver/py.typed;
  • adds unit tests for happy path, metadata drift, missing py.typed, and unexpected dist artifacts;
  • strengthens structural workflow tests so tag-commit and built-metadata checks cannot silently disappear.

Why

The repository already has strong source-level coherence checks in scripts/release.py and post-publish verification, and v0.14.1 successfully published to PyPI. The remaining high-value gaps in #519 were proving the built artifacts themselves match the intended version and making the publish job explicitly prove it is operating on the commit named by the release tag.

This does not claim #519 is closed until CI passes and the issue's full acceptance criteria are re-audited.

Validation

Expected on this PR:

  • workflow YAML structural tests;
  • new distribution-verifier unit tests;
  • normal CI matrix/static checks.

Closes #519 only after the acceptance-criteria audit confirms no remaining gap.

dgenio and others added 6 commits August 22, 2026 06:04
`_verify_sdist` selected PKG-INFO with `member.name.endswith("/PKG-INFO")`.
setuptools ships the `.egg-info` directory inside the sdist, so a real archive
has two:

    chainweaver-0.14.1/PKG-INFO
    chainweaver-0.14.1/chainweaver.egg-info/PKG-INFO

The selector collected both and raised "expected one PKG-INFO, found 2".
Reproduced by exporting this branch, running `python -m build`, and running the
script against the result — it exits 1. The step sits after `python -m build`
and before `Upload dist artifacts`, so on the next `v*` tag the build job would
have died and publish never run: a release outage introduced by the change
meant to protect releases.

Now matches only the archive's top-level PKG-INFO via PurePosixPath parts.

The tests did not catch this because the fixture wrote a single PKG-INFO — a
shape `python -m build` never produces. The fixture now adds the nested
egg-info member, so all five existing cases exercise the real thing, plus one
new case asserting the nested file is ignored rather than counted.

Verified by mutation: with the realistic fixture and the old selector, three
tests fail (including two that previously passed against the unrealistic
shape); with the fix, six pass. End to end, `verify_dist.py 0.14.1` against a
genuine wheel + sdist prints "verified ChainWeaver 0.14.1 wheel + sdist
metadata" and exits 0.

Also moves `Sequence` to `collections.abc` (ruff UP035, pre-existing on this
branch and would have failed lint).

Co-Authored-By: Claude <noreply@anthropic.com>

dgenio commented Aug 30, 2026

Copy link
Copy Markdown
Owner Author

Found a release-breaking bug in this branch and fixed it on the branch — d48da5a.

The bug

scripts/verify_dist.py rejected every real sdist. _verify_sdist selected metadata with member.name.endswith("/PKG-INFO"), and setuptools ships the .egg-info directory inside the sdist, so a genuine archive has two:

chainweaver-0.14.1/PKG-INFO
chainweaver-0.14.1/chainweaver.egg-info/PKG-INFO

Reproduced rather than reasoned about — exported this branch, ran python -m build, ran the script:

$ python3 scripts/verify_dist.py 0.14.1
distribution verification error: chainweaver-0.14.1.tar.gz: expected one PKG-INFO, found 2
$ echo $?
1

Why it mattered. In publish.yml the step sits after python -m build and before Upload dist artifacts. On the next v* tag the build job would have died and publish never run — a release outage introduced by the change whose purpose is protecting releases.

The fix, and the reason the tests missed it

Selection now matches only the archive's top-level PKG-INFO, via PurePosixPath(...).parts.

The more interesting half: the five existing tests passed because _build_fixture wrote a single PKG-INFO — a shape python -m build never produces. The suite was asserting against an artifact that does not exist. The fixture now adds the nested egg-info member, so all five existing cases exercise the real shape, plus one new case pinning that the nested file is ignored rather than counted.

Verified by mutation: with the realistic fixture and the old selector, 3 tests fail — including two that previously passed against the unrealistic shape. With the fix, 6 pass. End to end against a genuine wheel + sdist:

$ python3 scripts/verify_dist.py 0.14.1
verified ChainWeaver 0.14.1 wheel + sdist metadata
$ echo $?
0

ruff check, ruff format --check, mypy clean. Also moved Sequence to collections.abc — pre-existing on this branch and would have failed lint.

One structural gap I did not close

No CI job builds a distribution, so verify_dist.py still meets a real artifact for the first time during an actual release. That is exactly why this bug survived review and a green suite. distribution-check.yml is not the home for it — it triggers on workflow_run after Publish, so it validates what already shipped.

The fix would be a small job in ci.yml that runs python -m build and then verify_dist.py against the result on every PR. I have deliberately not added it: it is a scope decision on your draft, and I have already changed the branch once. Say the word and I will.

Two minors from the review, also unaddressed: test "${tag_commit}" = "${head_commit}" fails with no diagnostic showing which SHAs disagreed, and the github-release job still binds by tag_name: v${version} rather than the verified SHA — a residual gap against this PR's own goal.

The PR is still a draft and its previous CI run (2026-08-22) predates three commits of main, so it needs a fresh run before merge.


Generated by Claude Code

scripts/verify_dist.py gates the release in publish.yml, between `python -m
build` and the artifact upload. Nothing in CI built a distribution, so the
script met a real one for the first time *during a release*.

That is not hypothetical: it is exactly how it shipped rejecting every real
sdist. setuptools puts a second PKG-INFO inside `<pkg>.egg-info/`, the selector
matched both, and the unit tests passed because their fixture wrote only one —
a shape `python -m build` never produces. A verifier whose first real run is
the thing it guards is not a gate.

The new job builds wheel + sdist and runs the verifier against the result, so
the release path is exercised on ordinary PRs instead of at tag time.

Version is read as a literal from chainweaver/__init__.py, since pyproject sets
`dynamic = ["version"]`. Deliberately not imported — the job installs only
`build`, so a missing runtime dependency would turn a version lookup into a
spurious release-gate failure. Deliberately not derived from the built
filename either, which would make verify_dist's own filename check vacuous.

Verified by running the job's exact sequence locally against a pristine export:
`python -m build`, then the sed version read (0.14.1), then
`python scripts/verify_dist.py 0.14.1` -> "verified ChainWeaver 0.14.1 wheel +
sdist metadata", exit 0. With the pre-fix selector the same sequence exits 1,
so the job would have caught the bug it now guards against.

Co-Authored-By: Claude <noreply@anthropic.com>
@dgenio
dgenio marked this pull request as ready for review August 30, 2026 11:34
@dgenio
dgenio merged commit 08be8da into main Aug 30, 2026
23 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.

Restore release, tag, package, and documentation version coherence

2 participants