mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #238] [groom] cursor-review's severity badge is authored from two tables in post-review.py and re-parsed by a hardcoded vocabulary regex in build-ledger.py #245
Labels
No labels
cursor-review-catalog-drift
groom
groom
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/github-workflows#245
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/github-workflows/pull/238
Author: @cloud-code-bot[bot]
Created: 8/27/2026
Status: 🔄 Open
Base:
main← Head:groom/github-workflows-whole-repo-github-cursor-review-33073755508-0📝 Commits (4)
5e0f0f2groom: cursor-review's severity badge is authored from two tables in post-review.py and re-parsed by a hardcoded vocabulary regex in build-ledger.py493a0e7test(cursor-review): pin the badge contract on the table that gates rendering9a2fb6btest(cursor-review): pin the ingress vocabulary and the default severity tooc3e8c62Merge branch 'main' into groom/github-workflows-whole-repo-github-cursor-review-33073755508-0📊 Changes
2 files changed (+120 additions, -0 deletions)
View changed files
📝
.github/cursor-review/build-ledger.py(+31 -0)📝
.github/cursor-review/tests/test_build_ledger.py(+89 -0)📄 Description
ELI-5
When the review bot leaves an inline comment, it starts the comment with a little severity badge like
🔴 **Critical** —. A second script, the one that builds the "what did earlier rounds already say" ledger, has to peel that badge back off before it quotes the finding to the next round's models. The badge is written in one file (post-review.py) and peeled off in another (build-ledger.py), and the peeler re-types the list of severity names and the badge's exact shape by hand. Nothing checks that the two spellings still agree, so if someone added a severity or reworded a label, the writer would keep working while the peeler quietly stopped peeling — no error, just slightly worse quoting. This PR adds a test that renders a real badge with the real writer and feeds it to the real peeler, for every severity, so the two can no longer drift apart unnoticed. No production behavior changes.What changed
.github/cursor-review/tests/test_build_ledger.py— newTestSeverityBadgeContractclass with three tests. The first asserts the three severity tables carry the same keys (SEVERITY_EMOJI/SEVERITY_LABEL/SEVERITY_ORDER) and are non-empty, so neither a partial table nor an emptied one slips through. The second loops over every key ofpost_review.SEVERITY_EMOJI— the tablenormalize_severitygates the renderable vocabulary on, not the sort-order list — renders a finding throughpost_review.normalize_comments(the actual renderer that builds the badge), and assertsbuild_ledger._strip_badgereturns that exact severity and the untouched prose. The badge string is never re-typed in the test, so a change to the label, the**…**shape or the dash CHARACTER fails here; spacing around the dash is deliberately NOT pinned, because_BADGE_RE's\s*runs absorb it. The third test holds the deliberately tolerant^\S*\s*prefix: a badge with no emoji, or with an emoji the writer does not use today, still parses..github/cursor-review/build-ledger.py— comment only, above_BADGE_RE: records that the vocabulary is re-typed on purpose (so the ledger keeps reading bodies written by an olderpost-review.pystill live on a pinned caller ref) and that the duplication is pinned by that test instead of shared via an import. It also states what the tolerance actually is —^\S*swallows any non-whitespace run, not just an emoji, so a forged badge strips too, which is safe only because the sole caller reads thread roots of Bot-authored consolidated reviews — and that renaming a severity label means ADDING the new spelling to the alternation while KEEPING the old one, since rounds already posted by a caller on an older ref still carry it.No runtime code was touched, so the ledger, the poster and their outputs are byte-for-byte what they were.
Why
post-review.pybuilds the badge fromSEVERITY_EMOJI/SEVERITY_LABEL, and its ownstrip_severity_badgereverses it by rebuilding the same string from those tables — its docstring says that is precisely so the two cannot drift.build-ledger.py's_BADGE_REdoes the opposite: it hardcodes(Critical|High|Medium|Low|Nit)and the badge's punctuation as a literal alternation, with nothing tying it back to the tables. If a severity were added, a label renamed, or the dash/spacing changed, the ledger could silently stop stripping and would carry badge-prefixed bodies into the prior-review context, which may degrade the repeat/dedup matching the ledger exists for; it would not raise. There is no evidence of this having happened.Sharing the formatter outright would cost something real, so this PR does not do it: the tolerant
^\S*\s*prefix accepts any emoji or none on purpose, which is what lets the ledger keep parsing comments written by an olderpost-review.pythat a consumer is still pinned to. A test is the smaller instrument that closes the drift gap without giving that up, and it matches the pattern already used in this suite for the body-only prose marker, which is likewise duplicated on purpose and pinned across the two files by a test.Verifier rationale
Problem (verified end to end)
post-review.py owns the badge:
SEVERITY_EMOJI(line 42) andSEVERITY_LABEL(line 49) are formatted intof"{SEVERITY_EMOJI[severity]} **{SEVERITY_LABEL[severity]}** — "at line 999, andstrip_severity_badge(line 805) reverses it by RECONSTRUCTING the same string. Its docstring states the rule explicitly:Reconstructed from the same two tables that built it rather than re-matched with a regex, so the two can never drift.build-ledger.py does the thing that docstring rejects.
_BADGE_RE(line 107) is^\S*\s*\*\*(Critical|High|Medium|Low|Nit)\*\*\s*—\s*— the severity vocabulary re-typed as a literal alternation — and_strip_badge(line 298) is documented only asSplit post-review.py's severity badge off an inline comment body.Why the usual objections do not apply
.github/cursor-review/and are always checked out at the same ref. build-ledger.py ALREADY loads a sibling module by path —_load_gate_unresolved()at line 87, whose docstring saysReused, not re-implemented: the ledger takes CONSOLIDATED_MARKER... from that one module. The precedent for sharing is in this very file, which also refutes the finder'sif build-ledger.py must stay import-freecaveat.^\S*\s*deliberately accepts any emoji or none, so the ledger keeps parsing bodies written by an OLDER post-review.py still live on a pinned caller ref. Sharing the strict FORMATTER would break that. The finder concedes this and it is correct.Risk (conditional)
Adding a severity, renaming a label, or changing the dash/spacing would leave post-review.py working while build-ledger.py silently stopped stripping — badge-prefixed bodies would then be carried into the prior-review context, degrading the repeat/dedup matching the ledger exists for. It would not error.
Fix (blind-implementable, minimal form first)
Preferred: move
SEVERITY_EMOJI,SEVERITY_LABEL, abadge_for(severity)and the tolerantstrip_badge(body)into.github/cursor-review/severity.py; import it from post-review.py directly and from build-ledger.py via the sameimportlib.util.spec_from_file_locationidiom_load_gate_unresolvedalready uses; build_BADGE_RE's alternation fromSEVERITY_LABEL.values()rather than a literal, keeping the^\S*\s*prefix as is.Minimum acceptable: keep both files as they are and add a test asserting that
_BADGE_REmatchesbadge_for(s)for EVERY key inSEVERITY_EMOJI. Both suites exist (tests/test_post_review.py, 1688 lines;tests/test_build_ledger.py, 1414 lines).Not security
The badge strip is a prefix removal on text the workflow itself wrote; the ledger's actual trust controls (the Bot-author requirement on prior reviews, the fence defanging, the body-only sentinel literals) are separate code and are untouched by this change.
Provenance
Verified:
python3 -m unittest discover -s .github/cursor-review/tests -p 'test_*.py'— 364 tests, OK. Green again on the MERGED result againstmain(373 tests), alongside the agents-md (46) and groom (365) suites,shellcheck -xandbash .github/bump-callers/tests/test_bump_callers.sh(437 passed). Every pin was checked by mutation, not argument: droppingnitfromreview-output-mcp.py's ingress tuple fails 1 test; renaming themediumkey consistently across all three post-review.py tables fails 3 (it failed 1 before round 2, and none of them the dangling-DEFAULT_SEVERITYrelationship); requiring whitespace after the emoji run (^\S*\s+) fails exactly the spaceless and empty prefixes; the em dash changed to a hyphen fails 5; and a spacing-only change stays green, which is why the "spacing" claim is absent from both the comment and the docstring.Deviations: The verifier's preferred fix (extract a shared
severity.py) was deliberately not taken; this is its "minimum acceptable" form, for the old-ref-tolerance reason the verifier itself records. All eleven review findings across two rounds (five Low, six Nit) were accepted and applied — round 2 added the ingress vocabulary to the key-set equality, pinnedDEFAULT_SEVERITY's renderability (the one relationship whose breach raisesKeyErrorrather than degrading), covered the spaceless badge shape, and corrected three over-claims in the_BADGE_REcomment: the caller's gate is Bot-author-plus-forgeable-marker rather than "bodies this workflow wrote", the keep-the-old rename rule now covers the em dash as well as labels, and a new label's lowercase must equal its severity key. No runtime code changed.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.