Skip to content

Commit 500b2a7

Browse files
fix(impl-merge): let a re-dispatch finish the bookkeeping of an already-merged PR
The merge step has long treated "already merged" as success and continued to promotion, labels, issue close and the Postgres sync — the whole point of dispatching the workflow again after a run that crashed post-merge. It never got there: the completeness check before it fetched the PR branch, and `gh pr merge --delete-branch` had removed that branch at the merge, so the re-run died on `couldn't find remote ref`. Seen on #11295 (2026-09-05): the GCP auth step failed 5 s after the squash, the images stayed in staging while the metadata on main already pointed at production, and the re-dispatch could not repair it. The check now reads the files from origin/main when the PR is merged, which is where the squash commit put them, and no longer tries to close a merged PR when they are absent. The babysit skill gets the gotcha and the status-cycle rule (compare landed pairs against production images). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LfPAdJKa4JWzvsEUQZUuhs
1 parent 601d305 commit 500b2a7

3 files changed

Lines changed: 54 additions & 8 deletions

File tree

.claude/skills/babysit-pipeline/SKILL.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,19 @@ nothing failed.
259259
put the spec on `rescue_specs.txt`: the driver's dispatch
260260
auto-closes every open PR of the pair, so a regeneration fired while
261261
a repair is mid-flight throws that work away.
262+
- **A `Merge: PR #N` run that fails AFTER "Merge PR to main" leaves a
263+
silent hole: the squash is on main (metadata pointing at production
264+
URLs, the driver counts the pair as done) but the images are still in
265+
staging, the `impl:<lib>:done` label, issue close and Postgres sync
266+
never ran.** Seen on #11295 (2026-09-05, GCP auth step failed 5 s
267+
after the squash). Read the failed run's step list — a failure at or
268+
after `Authenticate to GCP` with `Merge PR to main` green is this
269+
case — then `gh workflow run impl-merge.yml -f pr_number=N`: the
270+
workflow treats an already-merged PR as success and runs the
271+
post-merge steps. Never promote the images by hand. Every status
272+
cycle should compare the pairs landed on main against
273+
`gs://anyplot-images/plots/<spec>/<lang>/<lib>/plot-light.png`; a
274+
merge failure in the run list is the trigger to look.
262275
- **`Merge: PR #N` failing five times with "Head branch is out of
263276
date" while `mergeable` stays `UNKNOWN` is a stuck PR object, not a
264277
branch problem.** Seen on #10850 (2026-09-01): `update-branch` had

.github/workflows/impl-merge.yml

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -166,17 +166,38 @@ jobs:
166166
EXT: ${{ steps.extract.outputs.ext }}
167167
BRANCH: ${{ steps.check.outputs.branch }}
168168
PR_NUM: ${{ steps.check.outputs.pr_number }}
169+
REPOSITORY: ${{ github.repository }}
169170
run: |
170-
# Fetch the PR branch to check its contents
171-
git fetch origin "$BRANCH"
172-
173171
IMPL_FILE="plots/${SPEC_ID}/implementations/${LANGUAGE}/${LIBRARY}${EXT}"
174172
META_FILE="plots/${SPEC_ID}/metadata/${LANGUAGE}/${LIBRARY}.yaml"
175173
176-
# Check if implementation file exists on the PR branch
177-
if ! git show "origin/${BRANCH}:${IMPL_FILE}" &>/dev/null; then
178-
echo "::error::Implementation file missing on branch: ${IMPL_FILE}"
174+
# A re-dispatch for a PR that is already merged has no branch to
175+
# fetch: `gh pr merge --delete-branch` removed it. That is exactly
176+
# the run this dispatch exists for — the first one merged and then
177+
# crashed before the post-merge bookkeeping (PR #11295: the GCP auth
178+
# step failed 5 s after the squash, so the images stayed in staging
179+
# while the metadata on main already pointed at production). Read
180+
# the files from main in that case, which is where the squash
181+
# commit put them, so the run reaches promotion, labels and sync.
182+
STATE=$(gh pr view "$PR_NUM" --repo "$REPOSITORY" --json state -q .state 2>/dev/null || echo "")
183+
if [ "$STATE" = "MERGED" ]; then
184+
echo "::notice::PR #${PR_NUM} is already merged — validating against origin/main"
185+
git fetch origin main
186+
REF="origin/main"
187+
else
188+
# Fetch the PR branch to check its contents
189+
git fetch origin "$BRANCH"
190+
REF="origin/${BRANCH}"
191+
fi
192+
193+
# Check if implementation file exists on the PR branch (or on main)
194+
if ! git show "${REF}:${IMPL_FILE}" &>/dev/null; then
195+
echo "::error::Implementation file missing on ${REF}: ${IMPL_FILE}"
179196
echo "::error::This indicates an incomplete generation - metadata exists but implementation is missing"
197+
if [ "$STATE" = "MERGED" ]; then
198+
echo "::error::PR is already merged — nothing to close; the implementation needs a regeneration"
199+
exit 1
200+
fi
180201
echo "::error::Closing PR to prevent partial merge"
181202
182203
gh pr close "$PR_NUM" --comment "**Merge blocked:** Implementation file \`${IMPL_FILE}\` is missing from this PR branch. Only metadata was found. This indicates an incomplete code generation. Please regenerate using \`generate:${LIBRARY}\` label."
@@ -185,8 +206,8 @@ jobs:
185206
fi
186207
187208
# Check if metadata file exists
188-
if ! git show "origin/${BRANCH}:${META_FILE}" &>/dev/null; then
189-
echo "::warning::Metadata file missing on branch: ${META_FILE}"
209+
if ! git show "${REF}:${META_FILE}" &>/dev/null; then
210+
echo "::warning::Metadata file missing on ${REF}: ${META_FILE}"
190211
echo "::warning::This is unusual but not blocking - metadata will be created on next review"
191212
fi
192213
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
### Fixed
2+
3+
- **A re-dispatched `impl-merge` run can finish the bookkeeping of a PR that is already merged**
4+
the merge step has long treated "already merged" as success and continued to promotion,
5+
labels, issue close and the Postgres sync, which is the whole point of dispatching the
6+
workflow again after a run that crashed post-merge. It never got there: the completeness
7+
check before it fetched the PR branch, and `gh pr merge --delete-branch` had removed that
8+
branch at the merge, so the re-run died on `couldn't find remote ref`. Seen on #11295
9+
(2026-09-05): the GCP auth step failed 5 s after the squash, the images stayed in staging
10+
while the metadata on main already pointed at production, and the re-dispatch could not
11+
repair it. The check now reads the files from `origin/main` when the PR is merged — where
12+
the squash commit put them — and no longer tries to close a merged PR when they are absent.

0 commit comments

Comments
 (0)