Skip to content

A failed tag lookup must refuse, not skip the guard - #28

Merged
thpoll83 merged 3 commits into
mainfrom
claude/win-compose-window-styling-ngrk9y
Oct 9, 2026
Merged

thpoll83 merged 3 commits into
mainfrom
claude/win-compose-window-styling-ngrk9y

Conversation

@thpoll83

@thpoll83 thpoll83 commented Oct 7, 2026 •

Copy link
Copy Markdown
Owner

Follow-up to #27, which merged. New PR because that branch is done; restarted from main at c3a001e.

The script

tag_commit() — added in #27 to stop an existing tag defeating the commit pin — returned None both for a confirmed 404 and for any failure. The caller skips its check when there is no tag, so a 5xx, a 403 or a timeout read as "no tag" and let a publish through at whatever commit the tag really points at. That is the exact case #27 existed to prevent, and the same shape as a bug already fixed once in this file in release_exists(), where only a 404 counts as an answer.

Three outcomes now: a sha, "" for a confirmed 404, None for "cannot tell". The annotated-tag dereference and any unrecognised ref shape also return None rather than guessing, and the caller refuses when it cannot check. The sha comparison is exact (at != target) rather than startswith on ten characters — both sides are full 40-char shas.

tag lookup before after
5xx guard skipped, publish proceeds refuses
403 guard skipped, publish proceeds refuses
404 (confirmed absent) proceeds proceeds
tag at the wrong commit refuses refuses, naming both shas

Byte-identical to qmk_firmware#356 and PolyKybdHost#318, where 16 mutation-swept tests now cover this file.

The docs

Both of these landed after #27's documentation was written, so the files lagged the code again — the failure mode this whole change exists to fix.

  • CLAUDE.md gains the existing-tag rule: target_commitish is "Unused if the Git tag already exists", so publishing never moves a tag and the pin's report becomes a claim. PK-0.9.20 sat exactly there — tag on 6cb987cb1a declaring 0.9.19, pin resolving 113093cfa2 — so the script would have printed the right commit and published the wrong one. ⚠️ With the note that this check must fire even when the version gate passes, which is the part that is easy to get wrong.
  • RELEASE.md gains its own section for it, because the recovery it already described was the worse of the two. A dispatch attaches correct assets to the tag where it is, leaving git checkout <tag> on a tree declaring the previous version. Moving the tag and publishing normally fixes the cause, and is what actually resolved 0.9.20 — commands included, with the caveat to check no release exists on the tag before force-pushing.

PK-0.9.20

Released at 14:00 UTC with the tag moved to 113093cfa2. Assert the built version matches the tag: success — its first pass on a real publish — assets named 0.9.20, status.txt agreeing, releases/latest correct. The guard added in #27 is what caught the mislabelled tag target before the publish, so it paid for itself the same day.

Review

Per CLAUDE.md, a green board here means it compiles, and there is nothing to compile in this diff. CodeRabbit can be asked with @coderabbitai review.

🤖 Generated with Claude Code

https://claude.ai/code/session_015jui4uFYS3SXuhXSRgew9i

Summary by Sourcery

Refuse releases when an existing tag cannot be verified or points to a different commit, while documenting safe recovery procedures.

Bug Fixes:

  • Make tag validation refuse publication when the existing tag lookup fails instead of treating an API error as an absent tag.
  • Require an exact full-commit match for existing tags before publishing.

Enhancements:

  • Distinguish confirmed missing tags, resolved tag commits, and indeterminate tag lookups, including annotated tags and unsupported ref shapes.
  • Document existing-tag behavior, misplaced-tag recovery, and the PK-0.9.20 release incident.

Documentation:

  • Add guidance for correcting misplaced release tags and clarify the limitations of workflow dispatch recovery.

RetriggerConfidence Score: 5/5

The PR appears safe to merge; the previous documentation finding is fixed.

Summary

The PR makes tag_commit() distinguish a missing tag from a failed lookup. Publishing refuses when the tag cannot be checked and compares full commit SHAs.

  • Adds recovery instructions for misplaced tags.
  • The latest edit fixes the previous documentation finding: users now copy the commit from the refusal, not an unreachable target: line.
  • No new issues or repository-rule violations were found.

Reviews (3) · Last reviewed commit: "Point the tag-move recovery at the refus..." · Reviewed by Greptile

`tag_commit()` returned None both for a confirmed 404 and for any
failure, and the caller SKIPS its check when there is no tag -- so a 5xx,
a 403 or a timeout read as "no tag" and let a publish through at whatever
commit the tag really points at, which is the thing the guard exists to
prevent.

That is the same shape as the failed-lookup bug already fixed once in
this script, in release_exists(), where only a 404 counts as an answer. I
reproduced it in the helper written to fix the related bug, one function
away from the comment warning about it.

Three outcomes now, matching published_latest_version(): a sha, "" for a
confirmed 404, None for "cannot tell". The annotated-tag dereference and
any ref shape the code does not understand also return None rather than
guessing. The caller refuses when it cannot check, naming that an existing
tag is never moved by publishing, so there is nothing safe to assume.

The sha comparison is exact now (`at != target`) instead of a
`startswith` on the first ten characters; both sides are full 40-char
shas, one from `git log --format=%H` and one from the API.

Tested through main() with the lookup stubbed to each outcome: 5xx
refuses, 403 refuses, a 404 correctly skips the guard and proceeds, and a
tag genuinely at the wrong commit refuses naming both shas. Plus the
regression run -- the newest four prepared tags through main() in each of
the three repos, all exiting 0 with the right Latest verdict.

Found by Greptile on PolyKybdHost#318 and qmk_firmware#356.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015jui4uFYS3SXuhXSRgew9i

@revixappdev revixappdev Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • [FIX] Tag lookup guard: tag_commit() now distinguishes a confirmed 404 ("") from an indeterminate lookup (None); release publishing refuses when it cannot determine whether a tag exists, and compares full commit SHAs when checking an existing tag.
  • This PR isn't getting a full Revix review right now — reviews are free for open-source projects but limited to a few a day, and this organization has already used today's. Reviews resume on Oct 08 at 00:00 UTC.

Free open-source reviews are in cooldown — Revix reviews open-source pull requests for free every day, and the summary above is still on us. Want every PR reviewed? https://www.revix.ai

@sourcery-ai

sourcery-ai Bot commented Oct 7, 2026

Copy link
Copy Markdown

Sorry @thpoll83, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 6 days and 2 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 10773f9c-41d1-4fb0-a2b2-cd043d60ba31

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread scripts/publish_release.py
Both came out of PK-0.9.20 after #27's docs were written, so the files
lagged the code again -- the failure mode this whole change exists to fix.

`target_commitish` is documented as "Unused if the Git tag already
exists", so publishing never moves a tag: the build comes from wherever
the tag points while the script reports the commit it wanted. Reached by
an ordinary sequence -- publish early, delete the release, merge the bump,
try again -- and PK-0.9.20 sat exactly there, tag on 6cb987c declaring
0.9.19 with the pin resolving 113093c. ⚠️ The note says the check must
fire even when the version gate passes, which is the part that is easy to
get wrong: there the pin found a correct commit and the mismatch gate sees
nothing wrong.

RELEASE.md gains its own section for it, because the recovery it already
described was the WORSE of the two. A dispatch attaches correct assets to
the tag where it is, leaving `git checkout <tag>` on a tree declaring the
previous version -- the kind of thing that sends a bisect wrong. Moving
the tag and publishing normally fixes the cause, and is what actually
resolved 0.9.20; the commands are there, with the caveat to check no
release exists on the tag before force-pushing.

Also corrects the window in ④ from "the window in between" to ~4 hours,
now that it has an end.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015jui4uFYS3SXuhXSRgew9i
Comment thread RELEASE.md Outdated
The instruction said `--dry-run` prints the commit to use on its
`target:` line. It does not, in the one case the section is about: the
tag check dies before the summary is printed, so a dry-run on a
misplaced tag shows the refusal and nothing else.

Reproduced with the lookups stubbed -- no `target:` line in the output,
and the refusal naming both commits -- which is also exactly what the
maintainer's own paste of the PK-0.9.20 refusal showed earlier. I wrote
the sentence with that evidence already on screen.

Describes the ordering rather than citing line numbers, which is the
stale-prose hazard this change exists to reduce.

Found by Greptile on #28.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015jui4uFYS3SXuhXSRgew9i
@thpoll83
thpoll83 merged commit f5c7f10 into main Oct 9, 2026
5 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.

2 participants