From 0ea6797e58d4692de51fe637da741c9ced2cfa0a Mon Sep 17 00:00:00 2001 From: Guenter Sandner Date: Fri, 11 Sep 2026 19:27:29 +0200 Subject: [PATCH] fix: wait for CI checks to register before polling for completion When a PR is first created, GitHub Actions may not have registered any checks yet, so statusCheckRollup is empty. The completion loop interpreted an empty rollup as 'all checks passed' and merged prematurely. Added Phase 1: poll until at least one CI check appears in statusCheckRollup (5-minute timeout) before entering the Phase 2 completion loop. --- AGENTS.md | 1 + memory-bank/activeContext.md | 2 +- memory-bank/custom-instructions.md | 20 ++++++++++++----- memory-bank/progress.md | 5 +++++ tools/bin/maintenance.sh | 35 ++++++++++++++++++++++++++++-- 5 files changed, 54 insertions(+), 9 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index fa63641f..2d54425c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,3 +3,4 @@ ## General - Always check the `memory-bank/` directory before starting a task. +- **Never commit, push, or create PRs without explicit user request** — see `memory-bank/custom-instructions.md` for the full rule. diff --git a/memory-bank/activeContext.md b/memory-bank/activeContext.md index 5a1926be..34a56f0c 100644 --- a/memory-bank/activeContext.md +++ b/memory-bank/activeContext.md @@ -8,7 +8,7 @@ All 339 tests pass (277 CJS + 62 ESM). ## Current Work -None. +PR #40 (fix: wait for CI checks to register before polling for completion) — CI checks running, waiting for merge. ## Pending Tasks diff --git a/memory-bank/custom-instructions.md b/memory-bank/custom-instructions.md index dd303987..45aea482 100644 --- a/memory-bank/custom-instructions.md +++ b/memory-bank/custom-instructions.md @@ -26,17 +26,25 @@ These instructions apply to all future sessions working in this project. ### Commit workflow (mandatory) +**Never** perform any of the following actions unless the user has explicitly asked for it: + +- `git commit` / `git commit --amend` +- `git push` +- `gh pr create` +- `gh pr merge` +- Any other command that alters the remote repository or its history + After implementing changes, follow this procedure: 1. **Present a summary** of all changes made (files modified, added, deleted) -2. **Stop and wait** for the user to explicitly request a commit — do NOT proceed to `git commit` on your own -3. Only when the user explicitly asks to commit or amend, execute `git add` and `git commit` with a commit message that always contains a `Co-authored-by` trailer, identifying the AI agent and model used: +2. **Stop and wait** for the user to explicitly request the next step (e.g. commit, push, create PR) +3. Only when the user explicitly asks, proceed — and for commits, always include a `Co-authored-by` trailer identifying the AI agent and model used: - ```text - Co-authored-by: () - ``` + ```text + Co-authored-by: () + ``` -This checkpoint exists because implementing changes and committing them are separate concerns. The user may want to review, adjust, or split changes before they become part of the repository history. +This checkpoint exists because implementing changes, committing them, and publishing them are separate concerns. The user may want to review, adjust, or split changes before they become part of the repository history, and may want to control when and how changes reach the remote. ## Coding diff --git a/memory-bank/progress.md b/memory-bank/progress.md index 7f2c7582..7601aa48 100644 --- a/memory-bank/progress.md +++ b/memory-bank/progress.md @@ -1,6 +1,11 @@ # Progress +### CI checks false-positive fix in maintenance.sh (2026-09-11) +- Fixed `step3_merge_pr()` in `maintenance.sh`: when a PR is freshly created, GitHub Actions hasn't registered any checks yet, so `statusCheckRollup` is empty. The completion loop interpreted an empty rollup as "all checks passed" and merged prematurely. +- Added Phase 1: poll until at least one CI check appears in `statusCheckRollup` (5-minute timeout), before entering the Phase 2 completion loop. +- This complements the earlier fix (PR #36) that handled false-negatives from skipped/neutral checks. + ### CI checks false-negative fix in maintenance.sh (2026-08-22) - Fixed `step3_merge_pr()` in `maintenance.sh`: `gh pr checks --watch` returns non-zero when any check is not "pass", including skipped/neutral checks (e.g., `create-release`, `musl` that only run on tag events) - Replaced the `gh pr checks --watch` exit-code check with: (1) run `gh pr checks --watch` ignoring exit code, then (2) query GitHub API for `statusCheckRollup` with `conclusion == "failure"` to detect actual failures diff --git a/tools/bin/maintenance.sh b/tools/bin/maintenance.sh index 9f6c8bb3..dccc3940 100755 --- a/tools/bin/maintenance.sh +++ b/tools/bin/maintenance.sh @@ -274,11 +274,42 @@ step3_merge_pr() { log "Waiting for CI checks on PR #$pr_number..." - # Poll the GitHub API until all checks reach a terminal state. + local poll_interval=30 + + # Phase 1: Wait for at least one CI check to appear in the rollup. + # When a PR is first created, GitHub Actions may not have registered + # any checks yet, so statusCheckRollup is empty. The completion loop + # below would incorrectly treat an empty rollup as "all passed". + local startup_max=300 # 5 minutes max to wait for checks to appear + local startup_elapsed=0 + + while [[ $startup_elapsed -lt $startup_max ]]; do + local check_count + check_count="$(gh pr view "$pr_number" --repo "$GH_REPO" \ + --json statusCheckRollup \ + --jq '.statusCheckRollup | length' \ + 2>/dev/null || echo 0)" + + if [[ "$check_count" -gt 0 ]]; then + log "CI checks registered (${check_count} check(s) found)" + break + fi + + log "No CI checks registered yet (${startup_elapsed}s elapsed)..." + sleep "$poll_interval" + startup_elapsed=$((startup_elapsed + poll_interval)) + done + + if [[ $startup_elapsed -ge $startup_max ]]; then + echo "ERROR: No CI checks appeared for PR #$pr_number after $((startup_max / 60)) minutes." >&2 + echo " This may indicate the CI workflow was not triggered." >&2 + exit "$EXIT_GENERAL_ERROR" + fi + + # Phase 2: Poll until all checks reach a terminal state (have a conclusion). # gh pr checks --watch returns immediately when checks haven't started # yet (e.g. GitHub Actions still queued), causing a false "all passed". local max_wait=1800 # 30 minutes - local poll_interval=30 local elapsed=0 while [[ $elapsed -lt $max_wait ]]; do