Skip to content

fix(fr-gate): attribute items via commits/pulls, not commit subjects - #90

Merged
LukasWodka merged 2 commits into
developfrom
fix/fr-gate-skip-issue-refs
Jul 27, 2026
Merged

fix(fr-gate): attribute items via commits/pulls, not commit subjects#90
LukasWodka merged 2 commits into
developfrom
fix/fr-gate-skip-issue-refs

Conversation

@LukasWodka

@LukasWodka LukasWodka commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

The bug (multi-symptom, one root)

fr-gate derived its "contained items" and its attribution vouch by scraping (#N) from commit subjects. Under this org's <subject> (#issue) (#PR) convention that's unreliable three ways:

  1. Grabs issue numberspullRequest(number:N) returns NOT_FOUND → treated as an API failure → 5 retries → "Status unreadable" → fail CLOSED. (backend#1228: 16 issue-refs, e.g. #1005.)
  2. Grabs bare #N mentions of unrelated old PRs (the #234 / #472 style).
  3. Misses a commit's real PR when the (#PR) isn't in the subject at all (rebase-merges; squash subjects that kept only the issue ref). A naive skip-NOT_FOUND patch then failed OPENUNATTRIB counts an (#issue) subject as "attributed", so the real PR is never discovered or gated (Bugbot High on the first cut of this PR).

The fix

Build both the item list (PRS) and the attribution (UNATTRIB) from GitHub's authoritative commit→PR attributionrepos/{repo}/commits/{sha}/pulls returns the actual merged PR(s) that introduced each commit — instead of scraping subjects:

  • Pass 1 — merge commits that are themselves PR merges vouch for their M^1..M^2 range and contribute their PR (sync merges contribute nothing; their pushes fall to pass 2).
  • Pass 2 — each non-merge commit not already vouched → resolve its introducing merged PR via the API. No merged PR ⇒ a direct push ⇒ UNATTRIB (fail closed). Persistent API error ⇒ fail closed.
  • Issues/mentions are never treated as PRs; every commit's real PR is discovered and gated; the empty-PRS → gate-the-promotion-PR fallback stays, so the gate can never pass on nothing.
  • --depth=200 base fetch bounds the commit set (and the call count).

Validation

Ran the exact logic against #1228's real failing range (staging 0e4af47d .. develop 8ddbbef2, 41 non-merge commits):

PRs discovered 39 real merged PRs
Issue-ref leaks (of the 16) 0
False-unattributable 0 (UNATTRIB empty)
#234 / #472 mention-noise dropped
#1191 (genuine containing PR) kept

actionlint clean. This is the commits/pulls-primary approach backend#1265 called for.


Note

High Risk
Changes the required promotion gate’s item discovery and direct-push detection; incorrect attribution could block valid releases or miss unreviewed commits.

Overview
Replaces subject-line (#N) scraping in the FR gate “Discover items” step with GitHub’s commits/{sha}/pulls API as the source of truth for which merged PRs are in the promotion and whether every commit is attributable.

Pass 1 resolves merge commits via the API and only treats them as PR merges when merge_commit_sha matches the commit (so sync merges don’t vouch for unrelated base-branch pushes). Pass 2 walks non-merge commits not already covered by that vouching; each gets an API lookup for merged PRs, with retries and fail-closed on persistent API errors. The gated PR list (prs) is built from deduped attributed PR numbers instead of parsed subjects.

This addresses false failures from issue refs in subjects, noise from mentioned PR numbers, and fail-open gaps when the real PR isn’t in the subject (rebase/squash cases).

Reviewed by Cursor Bugbot for commit b54b422. Bugbot is set up for automated code reviews on this repo. Configure here.

@LukasWodka

Copy link
Copy Markdown
Contributor Author

bugbot run

Comment thread .github/workflows/fr-gate.yml Outdated
Replaces the commit-subject '(#N)' scrape (both the item list and the
attribution vouch) with GitHub's authoritative commit->PR attribution
(repos/{repo}/commits/{sha}/pulls). The scrape was unreliable three ways under
this org's '<subject> (#issue) (#PR)' convention:

  1. it grabbed ISSUE numbers -> pullRequest() NOT_FOUND -> gate failed CLOSED
     (backend#1228: 16 issue-refs, e.g. #1005);
  2. it grabbed bare '#N' MENTIONS of unrelated PRs (#234/#472 style); and
  3. it MISSED a commit's real PR when the (#PR) wasn't in the subject
     (rebase-merges / issue-only squash subjects) -> a naive NOT_FOUND-skip then
     failed OPEN, since UNATTRIB counts an (#issue) subject as attributed and the
     real PR is never gated (Bugbot High on the first cut of this PR).

commits/{sha}/pulls returns the actual MERGED PR(s) that introduced each commit
-- the single source of truth for both PRS and UNATTRIB. One call per commit not
already vouched by a PR-merge (M^1..M^2); retry; fail CLOSED on a persistent API
error. The --depth=200 base fetch bounds the commit set and the call count.

Validated against backend#1228's exact failing range (staging 0e4af47d ..
develop 8ddbbef2, 41 non-merge commits): yields 39 real merged PRs, ZERO
issue-ref leaks, ZERO false-unattributable, drops the #234/#472 mention-noise,
and correctly keeps #1191 (a genuine containing PR). actionlint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@LukasWodka
LukasWodka force-pushed the fix/fr-gate-skip-issue-refs branch from 048ed81 to edc65f9 Compare July 27, 2026 10:47
@LukasWodka LukasWodka changed the title fix(fr-gate): skip issue/mention refs instead of failing closed fix(fr-gate): attribute items via commits/pulls, not commit subjects Jul 27, 2026
@LukasWodka

Copy link
Copy Markdown
Contributor Author

bugbot run

Comment thread .github/workflows/fr-gate.yml
commits/{sha}/pulls lists EVERY PR whose branch contains a commit, so a sync
merge ("Merge develop into feature") was listed for the feature PR. The old
non-empty check let that sync merge enter MERGES and mark a direct-push-to-base
it happened to pull in as "covered", skipping Pass 2 and reopening the Bugbot
#73 fail-open hole. Require merge_commit_sha==sha so only true PR merges vouch;
any other merge drops its payload to Pass 2 for individual attribution.

Verified on real history: backend sync merge ba80b3a yields no merge_commit_sha
match (drops to Pass 2), while every 'Merge pull request #N' matches #N.

Addresses Bugbot 'Sync merges reopen attribution hole'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@LukasWodka

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit b54b422. Configure here.

@LukasWodka
LukasWodka merged commit eb32750 into develop Jul 27, 2026
2 checks passed
@LukasWodka
LukasWodka deleted the fix/fr-gate-skip-issue-refs branch July 27, 2026 15:48
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.

1 participant