CR-DIST-06: stop distribution manifests drifting from the shipped version - #247
Merged
Merged
Conversation
…sion
Three manifests carried hand-maintained version strings that nothing updated.
They reached 0.80.0 while PyPI served 0.83.0 — three releases stale.
Not a paywall leak: the Claude Code / Codex plugins invoke `graq` from the
user's own environment and pin no version, so a stale manifest never installs
old code. It is a listing that advertises a version we no longer ship, which
reads as an abandoned project.
server.json was subtler. The registry workflow already rewrote it INSIDE the CI
checkout before publishing, so the published registry entry was always correct
— but the rewrite was never committed, so the file in git stayed stale forever.
Correct artifact, wrong repo. The two now agree.
The two plugin manifests were touched by nothing at all, and users read those
straight from the GitHub repo. Those were the genuinely broken ones.
- scripts/ci/sync_manifest_versions.py — sets the version across all three.
--check reports drift and exits 1. Strict PEP440 (a malformed version must
never reach a public listing). A missing key raises rather than silently
no-opping; an absent file is reported, not failed. Output format matches how
the files are stored, so a sync is a one-line diff, not a reformat.
- publish-mcp-registry.yml — calls the script instead of the inline
server.json-only heredoc, and commits the result back to master AFTER the
publish+verify steps. Committing a version we then failed to publish would
advertise a release that does not exist.
- Drift guard test asserting every manifest == graqle.__version__ — this is
what would have caught the 0.80.0 drift three releases ago.
Sentinel BLOCKED pass 1 on two workflow defects, both correct, both fixed:
1. `git checkout master` fails on the default shallow single-branch checkout
— no local master ref exists, so the step dies with "pathspec 'master' did
not match any file(s)" AFTER a successful publish, leaving manifests stale.
Reproduced locally with `git clone --depth 1 --branch v0.83.0
--single-branch` before fixing. Fixed with fetch-depth: 0.
2. `git pull --ff-only` hard-fails if anything lands on master mid-job. Now a
3-attempt fetch/reset/sync/push loop; the sync is idempotent so replaying
on newer master is safe.
After 3 failed attempts this warns rather than failing the job: the package is
already published and the registry entry already correct, so failing a green
release over a cosmetic listing would train people to ignore red. The drift
guard then catches it on the next PR instead of letting it rot for three
releases. Sentinel reviewed that deviation explicitly and approved it.
Mutation-tested: reverting server.json to 0.80.0 makes the drift guard fail;
restoring makes it pass. 7 new tests; packaging + licensing 329 passed 0 failed.
Sentinel pass 2: APPROVE, 0 blockers, 91%.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
🛡️ GraQle PR Guardian💥 Blast Radius: 8 modules affected
Total blast radius: 8 🏛️ Governance Verdict
|
| Metric | Value |
|---|---|
| Blast Radius | 8 |
| Files Analyzed | 8 |
| Blocked | 0 |
| SHACL Violations | 0 |
| Verdict | WARN |
🔬 Powered by GraQle PR Guardian v0.1.0 · Scan completed 2026-08-02T20:13:51.251148+00:00
Found while checking what a Claude Code directory reviewer actually fetches: .claude-plugin/marketplace.json still advertised 0.80.0. Root cause of the miss: the marketplace version is NESTED under plugins[0]. A top-level grep for '"version"' finds only metadata.version and walks straight past it, which is how I concluded these files "carry no version" in the first pass. - Both marketplace manifests added as sync targets (plugins.0.version). - metadata.version deliberately NOT synced: it is the marketplace SCHEMA version (1.0.0), not the SDK release. Syncing it would corrupt the manifest. Verified it still reads 1.0.0 after a sync. - ensure_ascii=False when writing: the marketplace description contains a real em-dash, and default json.dumps rewrote it as — — turning a one-line version bump into a mojibake diff on a file reviewers read. - Workflow now `git add -A` instead of an explicit file list. The script owns which files are targets; an explicit list silently drops targets added later, which is precisely the failure this commit is fixing. Safe because the retry loop resets to origin/master first, so nothing else can be dirty. 9 tests (was 7). Diff is 2 version lines, no reformatting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
harishquantamix
approved these changes
Aug 2, 2026
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.
CR-DIST-06 — stop distribution manifests drifting from the shipped version
Public port of private #328 (
d2cbf28c), merged 2026-08-02. All six files arebyte-identical to
private/master.The problem, on this repo right now
server.jsonplugins/claude-code/.../plugin.jsonplugins/codex/.../plugin.jsonThree releases stale. Not a paywall leak — the plugins invoke
graqfrom the user'sown environment and pin no version, so a stale manifest never installs old code. It is a
listing advertising a version we no longer ship, on the copy people actually browse.
The subtlety
server.jsonwas only half broken: the registry workflow already rewrote it insidethe CI checkout before publishing, so the published registry entry was always
correct — the rewrite was simply never committed. The two plugin manifests were
touched by nothing at all, and those are read straight from GitHub.
Correct artifact, wrong repo. They now agree — which also stops the next person
investigating a registry bug that never existed.
What ships
scripts/ci/sync_manifest_versions.py— syncs all three.--checkexits 1 ondrift; strict PEP 440 (malformed version → exit 2); a missing key raises rather than
silently no-opping. Output matches the stored format, so a sync is a one-line diff.
publish-mcp-registry.yml— calls the script instead of the inlineserver.json-only heredoc, and commits back after publish+verify.== graqle.__version__— what would havecaught this three releases ago.
Sentinel BLOCKED pass 1 — both blockers correct, both fixed
B1 —
git checkout masterfails on the default shallow checkout; the step would havedied with
pathspec 'master' did not match any file(s)after a successful publish,leaving manifests stale — manufacturing the very defect it fixes. Reproduced locally with
git clone --depth 1 --branch v0.83.0 --single-branchbefore fixing. →fetch-depth: 0.B2 —
git pull --ff-onlyhard-fails if anything lands on master mid-job. → 3-attemptfetch/reset/sync/push loop; the sync is idempotent so replaying is safe.
After 3 failed attempts it warns rather than failing — the package is already
published and the registry entry already correct, and failing a green release over a
cosmetic string trains people to ignore red. The drift guard catches it next PR. Sentinel
reviewed that deviation explicitly and approved it.
Evidence
server.jsonto 0.80.0 makes the guard fail.private/master.Rule #0
git remote -vrun before push. Public cherry-pick authorised only because private#328 is merged (
2026-08-02T16:41:10, base advanced tob2a08e77).🤖 Generated with Claude Code