fix(manifest): bump own pins 0.8.0 → 0.8.2 + CI pin-staleness gate - #68
Conversation
) Both .claude-plugin manifests (marketplace.json pin AND plugin.json) lagged the v0.8.2 tag — the release flow bumps Cargo.toml/server.json but never touched these. Gate: scripts/check_marketplace_pins.py (PIN_BEHIND_RELEASE + SELF_PIN_MISMATCH, two-sided per ZTS#52) + weekly-cron workflow, pattern from Cortex #179. Externally verified: the gate caught plugin.json 0.8.0 AFTER the marketplace bump — a second stale file the audit had not listed — then exit 0 with both fixed. Closes #67 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The gate cannot detect the defect it was written for
Replay the incident from #67 against this code:
The PR body says the gate "proved itself during authoring: after bumping the marketplace pin, it flagged Corollary: Third version file, uncovered
No testsThe diff adds No Completion LedgerPer §13.2 the ledger is mandatory and its absence is REFUSED at Move 0, before other analysis. The body is a good summary but it is not a ledger: no row-per-path, no path→test mapping. Also unmet from #67
What would close this
Item 3 is the one I would not compromise on: without it there is no evidence the gate catches the incident, and the current code demonstrably does not. |
The reviewed version only compared marketplace.json vs plugin.json: both stale together (the actual #67 state: manifests 0.8.0, tag v0.8.2) passed green. Now byte-identical with the canonical copy (cdeust/Cortex): PIN_BEHIND_TAG compares local pins against this repo's own latest semver git tag (offline, originates detection — the incident replay is the load-bearing test), SERVER_JSON_SPLIT guards the third leg that sat unguarded, fail-open network arms, release counts in messages. Dead code eliminated by USE: check_github_pin now exercised via the shared tests. 15 unit tests run in CI via plain unittest (no new deps); weekly cron diffs this copy against canonical so the two can never diverge into a no-op again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review addressed in full (commit pushed) + Completion Ledger (§13.2)The core hole is closed: detection now ORIGINATES.
Merge order note: Cortex #182 should merge first (it hosts the canonical file the drift check reads). |
Confirmed fixed
Three items remain, none of them the logic. 1. Build artifacts committed — blocking (§9, §14)Both are in the diff, and 2. Merge order: Cortex#182 must land first
3. Release procedure still undocumented (criterion 3)cdeust/Cortex#182 added a LedgerStill no Completion Ledger (§13.2). With the arms now genuinely covered this is mostly transcription, but it is the artifact the reviewer reconciles against. |
…ease procedure Review round 2 on #68 — three non-logic items. - Remove scripts/__pycache__/*.pyc and scripts/tests/__pycache__/*.pyc from the index. Build artifacts (§9); they entered because this Rust repo now carries a Python gate and nothing ignored bytecode. - .gitignore: __pycache__/ + *.py[cod], so it cannot recur on the next Python touch (§14.1 — fix the defect that was seen, here, not later). - CONTRIBUTING.md "Releasing": a release is not shipped until its pins move. Names the four version-carrying files (marketplace.json, plugin.json, server.json, Cargo.toml) and ends the checklist at `python3 scripts/check_marketplace_pins.py` exiting 0 — closing #67 criterion 3, the procedure that prevents the gap the gate detects. Verified: 15/15 unit tests green via the CI invocation (`python3 -m unittest scripts/tests/test_check_marketplace_pins.py`); gate exits 0; all four version files at 0.8.2 matching tag v0.8.2. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016gFqzbbNDwPtFzaoGDti7R
Closes #67 — releasing does not ship. Installs subscribe through
.claude-plugin/marketplace.json, and this repo's manifests sat at 0.8.0 whileserver.jsonand the latest tag were at v0.8.2 — a three-way split that delivered v0.8.1 and v0.8.2 to zero installs, with no error anywhere.The incident, and why the first cut of this PR did not catch it
A gate that only compares
marketplace.jsonagainstplugin.jsonreports green on the incident: both files were stale at 0.8.0, so they agreed with each other. Nothing read the tag. The gate now reads the latest local git tag (PIN_BEHIND_TAG, offline, git only), so it can originate the detection rather than confirm a human's.Failure classes
PIN_BEHIND_TAGPIN_BEHIND_RELEASESELF_PIN_MISMATCHplugin.jsonSERVER_JSON_SPLITserver.json≠ the primary marketplace pin — the third leg of the splitTwo-sided by design per cdeust/zetetic-team-subagents#52:
installed < pinandpin < releaseare different defects with different owners; a one-sided check reports false compliance.One artifact, not two copies
scripts/check_marketplace_pins.pyis a byte-identical copy of the canonical file in cdeust/Cortex. A cron-onlycanonical-driftjob diffs against it weekly, so the two repos cannot diverge into a version where one is a no-op. Cron-only is deliberate: PR runs must not depend on the sibling repo's merge state.Prevention, not just detection
CONTRIBUTING.mdgains a Releasing section: the checklist ends atpython3 scripts/check_marketplace_pins.pyexiting 0, and names all four version-carrying files (marketplace.json,plugin.json,server.json,Cargo.toml). The gate catches a stale pin after the fact; the procedure is what stops it being created (#67 criterion 3).Completion Ledger (§13.2)
Paths introduced → asserting test
parse_semverv-prefix and baretest_v_prefix_and_bareparse_semvernon-semver →Nonetest_non_semver_nonetest_numeric_not_lexicographic(2.9.0 < 2.10.0)PIN_BEHIND_TAGfires on the real incidenttest_incident_replay_both_manifests_stale_tag_ahead— fails on the pre-fix code (§13 G2)PIN_BEHIND_TAGsilent when currenttest_current_pin_green(negative assertion, §13 G4)test_untagged_repo_no_crash_no_flagtest_frozen_pin_skips_tag_check_keeps_coherencePIN_BEHIND_RELEASEfires, with release counttest_stale_flagged_with_counttest_stale_flagged_count_degradedtest_current_and_ahead_passtest_network_failure_degrades_to_noticeKeyErrortest_no_releases_repo_is_notice_not_keyerrortest_unparseable_tag_reportedSERVER_JSON_SPLITthird leg flaggedtest_three_way_split_third_leg_flaggedserver.json→ passtest_aligned_passes_and_absent_passes§13.1 checklist
python3 scripts/check_marketplace_pins.py→All marketplace pins current.exit 0server.json, manifestless local dir — each mapped abovegit taginvocation; bounded by manifest sizeurlopenused as a context manager withAPI_TIMEOUT_S; no leaked handlessubprocess.runwith an argument listGITHUB_TOKENread from env, never loggedNOTICE: … network degradedis explicit, and the summary line reports that notices occurredtest_incident_replay_both_manifests_stale_tag_aheadtmp_path; no fixed paths, no sleepstest_current_pin_green,test_current_and_ahead_pass,test_aligned_passes_and_absent_passespython3 -m unittest scripts/tests/test_check_marketplace_pins.py→ Ran 15 tests … OK;cargo fmt --checkandcargo clippy -D warningscleanscripts/CONTRIBUTING.mdReleasing section addedcanonical-driftSKIPPED by design on PR (cron-only).pycfiles removed and__pycache__/+*.py[cod]added to.gitignore— seen during review, fixed here, not deferredVerification quoted
🤖 Generated with Claude Code
https://claude.ai/code/session_016gFqzbbNDwPtFzaoGDti7R