Repository navigation
fix(release): verify-only re-run mode and SemVer-aware Latest (#47) - #51
Conversation
…ostics (#47) Checkpoint of the reviewed round-4 state (frozen-47-r4, identical bytes) recovered from the ss-wt-47 worktree after a PC crash. Not final: Sol r4 has one open HIGH (arm/flip same job under runner loss) and round 5 is pending. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lip if: test (#47) Round 5 of #47 review. Removes the claim that post-publish verification still runs if the runner dies: job outputs are only delivered at job finalization, so a lost runner after the flip skips `verify`. Documents the limitation and the read-only `verify_only` recovery in the workflow comments and RELEASE_CHECKLIST.md section 9. The durable fix (flip in its own job) is tracked in #50. No workflow logic changed (YAML parses equal). The arm/flip `if:` test now compares full `if:` lines for exact equality; mutation-verified (`&& false` on the arm, `|| true` on the flip both fail). Verified: py -3.13 -m pytest backend/tests/test_publish_verify.py -q -> 115 passed; actionlint clean; git diff --check clean. Reviews on frozen-47-r5 (12f7a596): Opus APPROVE-WITH-NOTES, Sol APPROVE-WITH-NOTES (both accept the #50 FOLLOWUP_DEBT classification). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (4)
Included review availability: This review used your included allowance. 7 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 8 reviews per hour. 📝 WalkthroughWalkthroughThe release workflow adds a read-only ChangesRelease publishing and verification
Priority: ➖ Normal Estimated code review effort: 4 (Complex) | ~45 minutes Change: Feature Sequence Diagram(s)sequenceDiagram
participant VerifyJob as verify job
participant TaggedCommit as tagged commit
participant Verifier as publish_verify.py
participant ReleasesAPI as GitHub Releases API
VerifyJob->>TaggedCommit: Read RELEASE_METADATA.md for the tag
VerifyJob->>Verifier: Run combined verification with expected metadata
Verifier->>ReleasesAPI: List releases and read release state
Verifier->>ReleasesAPI: Download release assets
Verifier-->>VerifyJob: Return latest, state, and hash results
Merge Risk: ⚪ Minimal · up to The release checks and read-only recovery path have no identified issue requiring a fix before merge. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 32.56% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 129 functions across 2 files. (2 skipped: 2 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
Closes #47.
What this changes
release-publish.ymlgains three things. Nothing here publishes a release; this PR only changes the workflow and its verifier.A. Verify-only mode (
workflow_dispatch,verify_only: true)A strictly read-only re-check of an already-public release, safe to run any number of times.
publishjob does not run at all (if: github.event_name == 'push' || inputs.verify_only != true);verifyruns withpermissions: contents: read.gh api --method GETandgh release download. It cannot create a draft, publish, edit release state, upload assets, create/move/delete tags, or delete a release. Structural tests enforce this on the verify job.verify_onlyruns have their own concurrency group, so a re-check never queues behind (or blocks) a publish.B. SemVer-aware Latest
The workflow no longer forces
--lateston every publish.publish_verify.py latestcompares the tag against every other non-draft, non-prerelease release using SemVer 2.0 precedence and passes an explicit--latest=true|falsetogh release edit. The verifier is told the same expectation. It does not assume a new release must be Latest: when it is not expected to be Latest, it checks that/releases/latestpoints at a release with higher precedence.Covered by tests:
v1.10.0 > v1.9.9,v2.0.0 > v1.99.99,v1.2.1 < v1.3.0(publishing v1.2.1 while v1.3.0 exists keeps v1.3.0 as Latest), prerelease identifiers, build metadata, and unparseable tags (fail closed before any draft exists).C. State and hash diagnostics, both always run
publish_verify.py verifyruns the state check (public, not prerelease, exactly the expected assets, Latest as expected; bounded retry for GitHub's read-after-write delay) and the re-download-and-re-hash check independently. It prints one combined report covering all four combinations (state pass/fail × hashes pass/fail) and fails at the end if either failed. Failure messages name the case: A (release missing/wrong), B (release correct, Latest not yet as expected), C (API unreadable). The verifier never republishes or retries a publish.Verification now runs in its own
verifyjob with its own time budget. The verifier enforces an end-to-end deadline that fits inside that job's timeout, so the report is always printed.Safety notes from review
set -ecapture their status withrc=0; cmd || rc=$?before any diagnostic prints.gh release viewis not banned globally. It stays in the read-only places that legitimately use it; tests forbid it only where mutation or refusal behaviour must be excluded.$GITHUB_ENV/$GITHUB_OUTPUT, and no${{ }}expressions are interpolated intorun:scripts.verifyjob usesreleases/tags/{tag}, which never returns drafts, so a leftover draft reads as "missing" (case A). It does not depend on draft listing. Only the refuse-if-exists check lists drafts, and it runs in thecontents: writepublish job. GitHub documents that draft listings go to tokens with push access. This relies on that documented behaviour; it was not live-tested, because doing so would require creating a draft.Known limitation (tracked separately)
The step that records "a publish was attempted" and the flip to public run in the same job. If the runner machine is lost after GitHub accepts the flip but before the job finishes, GitHub never receives the job's outputs and
verifyis skipped. Onmaintoday verification already runs inside that same job, so this is not a regression. The recovery is averify_onlydispatch, documented indocs/RELEASE_CHECKLIST.md§9. Follow-up issue: #50.Verification
py -3.13 -m pytest backend/tests/test_publish_verify.py -q: 115 passedactionlint .github/workflows/release-publish.yml: cleangit diff --check: cleanif:equality between the arm and flip steps was mutation-tested (&& false/|| trueboth fail the test).🤖 Generated with Claude Code
Summary by CodeRabbit