rolling-PR update mutates PR-object metadata on the just-merged triggering PR (not just release-prep/rolling) #274

Closed
opened 2026-07-01 22:54:50 +02:00 by bosun · 0 comments
Owner

Bug

The release-toolkit workflow (decide + actrelease) mutates PR-object metadata on the just-merged PR that triggered the run, in addition to updating the correct release-prep/rolling rolling PR. Result: two PRs in the repo end up with identical chore(release): vX.Y.Z title + assembled changelog body — the correct rolling PR, and the ex-feature PR that innocently triggered the workflow by merging.

Empirical

Reproduced in frankenbit/tmux-tell on v0.29.0 rolling cycle (2026-07-01 22:43):

  • #711 was a feature PR (title: "healthscan: adapter-resolver injection for codex chambers, closes #708"). Merged as bcf025710 on main at 22:43.
  • Post-merge, release workflow fired on push (event: push, status: success). It generated v0.29.0 rolling assembly.
  • After the workflow ran:
    • #703 (rolling PR, head=release-prep/rolling, correctly-titled): title="chore(release): v0.29.0", body=assembled changelog — ✓ correct
    • #711 (already-closed, merged): title="chore(release): v0.29.0", body=assembled changelog, changed_files=21 / +553 — WRONG mutation
  • head.ref, head.sha, merge_commit_sha on #711 remain correct (i/708-healthscan-adapter-resolver / b9cb414e / bcf025710) — only display-metadata (title + body + changed_files) is mutated.
  • Content-verified clean: the substrate fix landed correctly on bcf025710; only PR-object display is confused.

Impact

  • Discovery confusion: PR search / list shows two "chore(release): v0.29.0" PRs (one closed, one open) which reads as duplication or half-broken state.
  • Merge history: git log is fine, only Forgejo PR metadata is affected.
  • Nothing user-facing on the release itself (release page + tag + deploy chain all correct).
  • Hygiene bug, not correctness bug.

Hypothesis

The rolling-PR update step in reusable-release.yml likely does a PATCH by PR index/ref that mis-scopes when the triggering commit is on a feature-merged PR. Either the update-loop iterates over more PRs than intended, or the ID resolution picks up the wrong PR when the rolling PR and triggering PR are both matched by a chore(release): prefix.

Fix direction

  • Rolling-PR update should scope strictly to PRs with head.ref == release-prep/rolling, not by title-prefix or by "recently updated / merged" heuristic.
  • If update-in-place is done via GraphQL/list search, the query filter needs the head-ref constraint.

Refs

  • tmux-tell repro at v0.29.0 rolling cycle: frankenbit/tmux-tell#711 (feature PR with wrong metadata) + frankenbit/tmux-tell#703 (correct rolling PR)
  • Discovered during Surveyor post-merge verify (id 11c1); flagged upstream by QM (release-toolkit stewardship, tmux-tell task #658).
## Bug The release-toolkit workflow (`decide + act` → `release`) mutates PR-object metadata on the **just-merged PR that triggered the run**, in addition to updating the correct `release-prep/rolling` rolling PR. Result: two PRs in the repo end up with identical `chore(release): vX.Y.Z` title + assembled changelog body — the correct rolling PR, and the ex-feature PR that innocently triggered the workflow by merging. ## Empirical Reproduced in frankenbit/tmux-tell on v0.29.0 rolling cycle (2026-07-01 22:43): - **#711** was a feature PR (title: "healthscan: adapter-resolver injection for codex chambers, closes #708"). Merged as `bcf025710` on main at 22:43. - Post-merge, `release` workflow fired on push (event: push, status: success). It generated v0.29.0 rolling assembly. - **After the workflow ran**: - #703 (rolling PR, head=`release-prep/rolling`, correctly-titled): title="chore(release): v0.29.0", body=assembled changelog — ✓ correct - **#711 (already-closed, merged): title="chore(release): v0.29.0", body=assembled changelog, changed_files=21 / +553** — WRONG mutation - head.ref, head.sha, merge_commit_sha on #711 remain **correct** (`i/708-healthscan-adapter-resolver` / `b9cb414e` / `bcf025710`) — only display-metadata (title + body + changed_files) is mutated. - Content-verified clean: the substrate fix landed correctly on `bcf025710`; only PR-object display is confused. ## Impact - Discovery confusion: PR search / list shows two "chore(release): v0.29.0" PRs (one closed, one open) which reads as duplication or half-broken state. - Merge history: git log is fine, only Forgejo PR metadata is affected. - Nothing user-facing on the release itself (release page + tag + deploy chain all correct). - Hygiene bug, not correctness bug. ## Hypothesis The rolling-PR update step in `reusable-release.yml` likely does a PATCH by PR index/ref that mis-scopes when the triggering commit is on a feature-merged PR. Either the update-loop iterates over more PRs than intended, or the ID resolution picks up the wrong PR when the rolling PR and triggering PR are both matched by a `chore(release):` prefix. ## Fix direction - Rolling-PR update should scope strictly to PRs with `head.ref == release-prep/rolling`, not by title-prefix or by "recently updated / merged" heuristic. - If update-in-place is done via GraphQL/list search, the query filter needs the head-ref constraint. ## Refs - tmux-tell repro at v0.29.0 rolling cycle: https://git.frankenbit.de/frankenbit/tmux-tell/pulls/711 (feature PR with wrong metadata) + https://git.frankenbit.de/frankenbit/tmux-tell/pulls/703 (correct rolling PR) - Discovered during Surveyor post-merge verify (id 11c1); flagged upstream by QM (release-toolkit stewardship, tmux-tell task #658).
bosun closed this issue 2026-07-02 10:00:10 +02:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/release-toolkit#274
No description provided.