Repository navigation
[finding] plugins/uberdev/skills/merge-pipeline/lib/release-anchor.sh — 2 findings #800
Description
@TheFJK — /uberdev:premerge flagged a blocker finding on PR #793.
Origin: b91a1efddcf3a7d76231e72c66146acb27f308a2
Agent: premerge.review.code_review
File: plugins/uberdev/skills/merge-pipeline/lib/release-anchor.sh:150
Severity: blocker (Phase premerge)
Disposition: DEFERRED (premerge-repair-budget-exhausted)
Tier: BLOCKER
Blocks: #793
Findings (2)
1. plugins/uberdev/skills/merge-pipeline/lib/release-anchor.sh:150 — blocker / BLOCKER / DEFERRED (premerge-repair-budget-exhausted) — The placeholder regex is applied to all removed lines rather than only those inside the section the commit opens, so any
Lenses: premerge.review.code_review
RELEASE_ANCHOR_PLACEHOLDER_RE is matched against the whole removed-line set, not scoped to the section the release commit opens. A release commit may therefore delete any italic bullet from any previously shipped release's notes and still return tolerated. The constant's own header states the intent is a release-note placeholder and that a release commit has no business deleting a shipped release's notes, so the implementation does not enforce the scope it claims. Impact is bounded only because nothing in the repo reads CHANGELOG.md back - bump-version.sh and goal-state.sh write it and no shipped code parses it.
2. plugins/uberdev/skills/merge-pipeline/lib/release-anchor.sh:227 — blocker / BLOCKER / DEFERRED (premerge-repair-budget-exhausted) — A removed blank line defeats the changelog_deletions check in both directions, on exactly the shape 5a produces
Lenses: premerge.review.code_review
The check tests every removed CHANGELOG line against the placeholder and unreleased regexes, and a blank removed line matches neither. When a release commit removes a pending-notes stub together with an adjacent blank line - what 5a produces whenever a prior release left its stub unreplaced, the case the new header comment explicitly wants to tolerate - git pairs them into one hunk, chg_removed becomes a newline followed by the stub, the empty first line fails the grep, and the probe returns changelog_deletions. TRUST_HEAD then stays on the trailer-less release commit and PATH_2 (b) fails trust_trail_trailer_missing, which is the unresolvable premerge trail this rewrite was made to fix. The mirror image is also live: when the removals are only blank lines, command substitution strips them to the empty string, the -n guard skips the check entirely, and the deletion is silently tolerated. Both reproduced on a throwaway repo.
To resolve: address the findings above in code and close this issue. Closing resolves exactly the findings listed in this body and the findings added by a later comment on it — one index records both, and closing resolves that recorded set and nothing else. A finding in this file that this issue never recorded is filed as a NEW issue rather than suppressed, so closing never mutes the file. Before closing, apply finding:true-positive if it was a real defect or finding:false-positive if it was not — that label is the eval ground truth (RFC 0018).
Activity
TheFJK commentedon Aug 24, 2026
Read with #801 — that issue is why this one has no failing test behind it.
This defect re-breaks the premerge trust trail on exactly the CHANGELOG shape Phase 5a produces: a release commit that removes a pending-notes stub together with an adjacent blank line.
TRUST_HEADthen stays on the trailer-less release commit and PATH_2 (b) failstrust_trail_trailer_missing— the unresolvable premerge trail therelease-anchor.shrewrite was made to fix.The natural question is why the suite did not catch it. #801 is the answer:
tests/trust-trail-base-identity.test.shbuilds every executed b.5 row with aPR_JSONthat has nolabelskey, so those rows resolve an empty label set and assert nothing about the label/trailer agreement. A default-allow mutation there leavesmerge.test.sh,trust-trail-base-identity.test.shandtrust-trail-evaluator.test.shall green.So the green suite around this area is not evidence. Fix #801 first, or fixing this one lands against a test bed that cannot tell you whether it worked.