Skip to content

Commit ddd383d

Browse files
fix(spec-drift): retry the promotion PR on every run, not only on commit runs
The first live dispatch of the repaired watcher proved the persistence fix works — `spec-drift/auto-promotion` pushed clean, no GH006, content persisted for the first time since 2026-07-06 — and immediately exposed a gap in the same step: * [new branch] spec-drift/auto-promotion -> spec-drift/auto-promotion ::warning::promotion branch pushed, but opening the PR failed … GraphQL: GitHub Actions is not permitted to create or approve pull requests Pushing the branch and opening the PR are two different failure modes, but PR creation lived INSIDE the has-new-commits branch. So a run that persisted the branch and then failed to open the PR left the content sitting on a branch with no review surface — and the next quiet run (nothing new to capture) took the early `exit 0` and never retried. The promotion would stay unreviewed until someone happened to read the branch list: the same silent stall this whole mechanism exists to remove, one level up. Splits the two. Pushing stays conditional on new commits; ensuring the PR exists now runs on EVERY run for as long as `origin/<promo>` is ahead of the base, guarded by `merge-base --is-ancestor` so a merged promotion does not reopen. Chose retry-while-ahead over retrying only after a failed create because the "branch ahead, no open PR" state is the thing that actually needs correcting, whatever produced it — a failed create, a human closing the PR without merging, or a transient API error. Testing the state is robust; remembering the event is not. The underlying repo setting was also enabled (`can_approve_pull_request_reviews` on the Actions workflow permissions — the single toggle that gates BOTH creating and approving PRs). Safe here: main requires 9 status checks with `enforce_admins: true` and `required_pull_request_reviews: null`, so approvals are not a merge gate and the approve half of the toggle confers nothing. Verified: YAML parses, actionlint clean, harness re-pinned (`audit-harness verify` → OK, one hash line changed). The behaviour itself is verified by the next dispatch, which must open the PR for the already-pushed branch — the exact case the old code could not reach. Refs intent-solutions-io/intent-eval-platform#10, #11
1 parent a631a93 commit ddd383d

2 files changed

Lines changed: 32 additions & 9 deletions

File tree

.github/workflows/spec-drift-watch.yml

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -646,19 +646,42 @@ jobs:
646646
run: |
647647
set -uo pipefail
648648
if [[ -z "$(git log --oneline "origin/${GITHUB_REF_NAME}..HEAD" 2>/dev/null)" ]]; then
649-
echo "Nothing to promote — no commit-backs this run."
649+
echo "No new commit-backs this run."
650650
echo "promoted=false" >> "${GITHUB_OUTPUT}"
651-
exit 0
651+
else
652+
git branch --force "${PROMO_BRANCH}" HEAD
653+
if ! git push --force origin "${PROMO_BRANCH}"; then
654+
echo "::error::promotion branch push FAILED — this run's capture, lineage, currency row and liveness heartbeat did not persist."
655+
echo "promoted=false" >> "${GITHUB_OUTPUT}"
656+
echo "push_failed=true" >> "${GITHUB_OUTPUT}"
657+
exit 0
658+
fi
659+
echo "promoted=true" >> "${GITHUB_OUTPUT}"
652660
fi
653661
654-
git branch --force "${PROMO_BRANCH}" HEAD
655-
if ! git push --force origin "${PROMO_BRANCH}"; then
656-
echo "::error::promotion branch push FAILED — this run's capture, lineage, currency row and liveness heartbeat did not persist."
657-
echo "promoted=false" >> "${GITHUB_OUTPUT}"
658-
echo "push_failed=true" >> "${GITHUB_OUTPUT}"
662+
# Ensuring the PR exists is INDEPENDENT of whether this run produced
663+
# commits, and that separation is load-bearing.
664+
#
665+
# These are two different failure modes: the push can succeed while
666+
# `gh pr create` fails (it did — "GitHub Actions is not permitted to
667+
# create or approve pull requests", a repo setting). When PR creation
668+
# lived inside the has-new-commits branch, that left the content
669+
# persisted on a branch with no PR, and the NEXT quiet run — nothing new
670+
# to capture — took the early exit and never retried. The promotion would
671+
# sit unreviewed and unmerged until someone happened to look at the
672+
# branch list, which is the same silent-stall this whole mechanism exists
673+
# to remove.
674+
#
675+
# So: retry on every run for as long as the branch is ahead of the base.
676+
git fetch --no-tags origin "${PROMO_BRANCH}" 2>/dev/null || true
677+
if ! git rev-parse --verify --quiet FETCH_HEAD >/dev/null; then
678+
echo "No promotion branch on the remote — nothing to open a PR for."
679+
exit 0
680+
fi
681+
if git merge-base --is-ancestor FETCH_HEAD "origin/${GITHUB_REF_NAME}" 2>/dev/null; then
682+
echo "Promotion branch is not ahead of ${GITHUB_REF_NAME} — nothing to review."
659683
exit 0
660684
fi
661-
echo "promoted=true" >> "${GITHUB_OUTPUT}"
662685
663686
existing="$(gh pr list --head "${PROMO_BRANCH}" --base "${GITHUB_REF_NAME}" \
664687
--state open --json number --jq '.[0].number' 2>/dev/null || true)"

.harness-hash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ ee7eb3ebd24be4ae2132e021a8bbcd853f25474371e43a8ec40d3c473e5baaa6 .github/workfl
1818
db162cbe380e2d61bbcc820cdd5a89807ca1a7cf221b8f5e28ef3c0ce9ed1767 .github/workflows/schema-drift.yml
1919
a71c2bf4169af59d3708009fc95d7d097fdcb68f3d4a70337e8578f93c085279 .github/workflows/sign-dogfood-bundle.yml
2020
6a17759ce2e0def32e582753d198be5e173f8eca5611155bc8755dc2bc96fb5d .github/workflows/sign-evidence-bundle.yml
21-
0e1e942a0f5d8203e5ff0c7162e3d3452869a06665143b77503b43f98cd54e4d .github/workflows/spec-drift-watch.yml
21+
bc70d8ece0e05ef79a9c8b4709626612170c7d561c022e12a320d6707389240c .github/workflows/spec-drift-watch.yml
2222
ae775f92124df36c98fdaef3a5e3664bfc04fdbf57ead568639f1586576e9481 .github/workflows/statemachine-drift.yml
2323
fd1851c44df5a21ed73da430a1945b542e0fb4c13c3740f88cb2d4a41db65ec3 .github/workflows/typos.yml
2424
46ed22f848d0b061faabc96c4dee071a52a514a430ca722b043733af502ce48b .harness-hash-extra-patterns

0 commit comments

Comments
 (0)