OPER-173
Stacked-PR parent-merge detection — trigger rescue immediately on parent squash-merge
Band
SMALL
Suggested
Justin Cooke
Body
--- feature_id: FEAT-studio-dispatcher band: SMALL target_repo: operant-health/operant-studio --- ## Context Reconciliation of OPER-146 (2026.09.09) surfaced a recurring class of stall in the stacked-PR workflow. When a parent PR in a stacked series is squash-merged into main, GitHub does not automatically rebase the child PRs onto main; their `base` ref still points at the deleted parent branch (or at a stale SHA on a branch that lingered), and their diff-against-main balloons to include the parent's already-shipped commits. The existing `stacked-pr-rescue.yml` workflow exists to handle exactly this, but during the OPER-146 drain it did not fire for hours after the parent (#437) merged. Every child in the stack (#438, #439, #463) had to be manually rebased onto main + `base` repointed + `[BLOCKED]` prefix removed + draft flipped to ready. That is a 4-step manual sequence per PR, run three times in one afternoon, on a single stack. Concretely observed: - PR #437 merged 21:14Z - PR #438 sat with `base=agent/oper-146-pr2` (deleted) and mergeable_state=dirty until 00:10Z manual intervention - stacked-pr-rescue.yml recent-runs history shows no invocation between 13:18Z and midnight This is Class **Stacked-PR-Parent-Merge-Detection-Lag**. Distinct from Premature-DONE (OPER-448 territory, which reconciles Ledger status against writeSets coverage); this class blocks *shipping* the actual code, not just the record. Related evidence: reconciliation comment on OPER-146 (Ledger cuid cmttws4zg0084jo04jevjmcxx). ## Acceptance Criteria Gate specification: 1. **Trigger surface.** `stacked-pr-rescue.yml` MUST subscribe to `pull_request` closed+merged events, not only to schedule/workflow_dispatch. On every merge, it MUST scan all open PRs whose `base` matches either (a) the merged PR's head ref or (b) any branch whose head SHA equals the merged PR's head SHA at merge time. 2. **Detection semantics.** For each identified child PR, the workflow MUST: - Repoint `base` to the merged parent's target (usually `main`) - Fetch the parent's post-merge commit SHA on main - Rebase the child branch onto that SHA (drop parent's now-shipped commits) - Force-push the rebased child branch - Post a sticky comment on the child summarizing the parent-merge + rebase action taken 3. **Un-blocking.** If the child PR title starts with `[BLOCKED]` AND its only remaining blocker was the parent PR, the workflow MUST also: - Retitle to drop `[BLOCKED]` - Flip draft to ready (`markPullRequestReadyForReview`) Otherwise leave title/draft as-is; the fleet's other guards decide. 4. **Failure handling.** If rebase produces conflicts, the workflow MUST NOT force-push; instead post a sticky comment on the child requesting manual attention and label with `stacked-rescue-conflict`. 5. **Idempotency.** Multiple invocations on the same parent-merge event MUST NOT stack extra force-pushes or duplicate comments. 6. **Observability.** Every workflow run MUST log: (a) which parent PR triggered it, (b) which children matched, (c) which children were rebased successfully, (d) which children hit conflicts. Log format compatible with fleet's existing dispatch observability parser. 7. **Test.** Add an integration test in `.github/workflows-tests/` that simulates parent-merge with two stacked children, verifies both children are rebased + un-blocked, and verifies a conflict on the second child produces the manual-attention path without force-pushing. ## Non-goals - Does NOT try to detect stacks whose parents were merged via non-squash strategies (rebase-merge is rare in this monorepo) - Does NOT handle diamond-shaped dependencies (two PRs both stacking on one parent both stacked-on) beyond flat linear chains ## Effort Single Ledger ticket family. Parallelizable with OPER-157 (auto-update-branch on ms=behind) but independent of it. Unblocking prerequisites: none — `stacked-pr-rescue.yml` already exists as scaffold.
Attachments
Loading attachments…
Comments
Loading comments…