Repository navigation
AB#3143 Release: install and boot the wheel before publishing it - #5
Merged
Merged
Conversation
The wheel is what PyPI serves and what `pip install` gives users, and nothing
ever installed it. AB#3142 made the publish wait for the exe verification, but
that gates the PyInstaller binary built from source - a different artifact,
resolved differently. A wheel-only fault (a missing packages entry, a bad hatch
build glob, an undeclared dependency) would still have reached PyPI, where a
version number can never be reused.
The build job now installs the freshly-built wheel into a clean virtualenv and
makes it answer a real MCP initialize handshake, running from /tmp so the import
resolves to the installed package and can never fall through to ./src. It also
asserts the version the server reports matches the tag being released, so a
forgotten version bump fails the build instead of burning a version.
publish-pypi already needs this job, so this gates the publish for free.
Whether the check was even viable on Linux was an open question worth settling
before adding it to the release path: modelchoice-mcp depends on xlwings
unconditionally and the server import chain pulls it in, and a gate that cannot
pass would have blocked every future release. There is no Docker or WSL on the
dev box, so it was verified on a real ubuntu runner via a throwaway
push-triggered workflow on a scratch branch, since deleted:
modelchoice-mcp 0.0.31 installed
xlwings OK 0.36.14
server OK MCPServer 0.0.31
serverInfo {"name":"modelchoice-mcp","version":"0.0.31"} PASS
The assertion logic was then exercised on all three paths against a real
handshake - matching tag passes, mismatched tag fails with a clear message,
unparseable response fails - because a gate that cannot fail is not a gate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The wheel is what PyPI serves and what
pip installgives users — and nothing ever installed it. AB#3142 made the publish wait for the exe verification, but that gates the PyInstaller binary built from source: a different artifact, resolved differently. A wheel-only fault — a missingpackagesentry, a bad hatch build glob, an undeclared dependency — would still have reached PyPI, where a version number can never be reused.Change
The
buildjob now installs the freshly-built wheel into a clean virtualenv and makes it answer a real MCPinitializehandshake. It runs from/tmpso the import resolves to the installed package and can never fall through to./src.publish-pypialready needsbuild, so this gates the publish for free.It also asserts the version the server reports matches the tag being released — a forgotten version bump now fails the build instead of permanently burning a PyPI version.
Was it even viable on Linux?
Worth settling before adding a gate to the release path:
modelchoice-mcpdepends onxlwingsunconditionally and the server import chain pulls it in, so a check that couldn't pass would have blocked every future release. No Docker or WSL on the dev box, so I verified it on a real ubuntu runner with a throwaway push-triggered workflow on a scratch branch (since deleted):Does the gate actually fail?
A gate that can't fail isn't a gate, so the assertion logic was exercised on all three paths against a real handshake:
v0.0.31, wheel reports0.0.31v0.0.99, wheel reports0.0.31wheel reports 0.0.31 but the tag is v0.0.99could not parse serverInfoVersion extraction parses the JSON rather than grepping for a literal, so a future formatting change in the SDK can't turn this into a spurious release blocker.
Note
release.ymlonly fires onv*tags, so merging doesn't exercise it. The ubuntu probe and the failure-path tests above are the pre-merge evidence; the next tag is the first real run.