Handle stacked PR retarget and merge-queue trigger gaps#618
Handle stacked PR retarget and merge-queue trigger gaps#618seonghobae wants to merge 15 commits into
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Extends the central PR Review Merge Scheduler workflow’s pull_request_target trigger coverage to react to merge-readiness transitions that may occur without a head push (e.g., retargeting, merge-queue transitions, and auto-merge state flips), and adds a contract test to prevent trigger regressions.
Changes:
- Expand
pull_request_targetactivity types inpr-review-merge-scheduler.ymlto includeedited,enqueued,dequeued, andauto_merge_disabled(while keeping existing gates unchanged). - Add a workflow contract test to lock the expected trigger types for the merge scheduler.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| tests/test_required_workflow_queue_contract.py | Adds a contract test to ensure the merge scheduler workflow keeps the intended pull_request_target.types coverage. |
| .github/workflows/pr-review-merge-scheduler.yml | Widens pull_request_target event types so the scheduler runs on retarget/queue/auto-merge state transitions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…cked-pr-automerge
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
tests/test_required_workflow_queue_contract.py:51
- The new workflow contract test extracts
pull_request_target.typesvia brittle string splits and assumes an inlinetypes: [...]list plus a laterpull_request_review:key. This couples the contract to YAML formatting and trigger ordering rather than just the trigger set, so a harmless reformat (e.g. multi-line list) would fail the test.
def test_merge_scheduler_pull_request_target_includes_retarget_and_queue_events() -> None:
workflow = workflow_text("pr-review-merge-scheduler.yml")
trigger_block = workflow.split("pull_request_target:", 1)[1].split(
"pull_request_review:",
1,
)[0]
types_line = next(
line.strip() for line in trigger_block.splitlines() if line.strip().startswith("types:")
)
listed = types_line.split("[", 1)[1].split("]", 1)[0]
trigger_types = {item.strip() for item in listed.split(",") if item.strip()}
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
tests/test_required_workflow_queue_contract.py:51
- This contract test currently assumes the
pull_request_target.typeslist is expressed as a single inline[a, b, c]YAML sequence. That makes the test fail on semantically equivalent formatting changes (e.g., block-listtypes:\n - opened) or quoted items, even though the trigger set is unchanged. Consider parsing both inline and block-list forms so the contract locks the trigger semantics rather than the exact YAML layout.
types_line = next(
line.strip() for line in trigger_block.splitlines() if line.strip().startswith("types:")
)
listed = types_line.split("[", 1)[1].split("]", 1)[0]
trigger_types = {item.strip() for item in listed.split(",") if item.strip()}
Rename the pull_request_target contract test to match its actual scope (retarget + auto-merge transitions, not queue events). Accept sentence punctuation after natural-English citations like "line 42 in path." while still rejecting continued suffix paths. Add regression assertions for trailing punctuation acceptance and suffix rejection in adversarial evidence validation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
tests/test_required_workflow_queue_contract.py:53
- The contract test extracts
pull_request_target.typesby splitting on commas, which will fail if the workflow YAML later switches to quoted items (e.g.,"opened") or other harmless formatting tweaks. Since this test is meant to lock the set of trigger types (not their YAML formatting), normalize tokens more robustly (e.g., viare.findall) so future formatting-only edits don’t cause spurious failures.
assert m is not None, "pull_request_target.types list not found in scheduler workflow"
trigger_types = {t.strip() for t in m.group(1).split(",") if t.strip()}
…cked-pr-automerge
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
tests/test_required_workflow_queue_contract.py:52
- The contract test parses the inline
types: [...]list by splitting on commas, but it doesn’t normalize optional YAML quoting (e.g.types: ["opened", ...]). Quoting doesn’t change the workflow semantics, but would make this test fail unnecessarily. Consider stripping surrounding single/double quotes when buildingtrigger_typesto keep the contract focused on the trigger set rather than formatting.
trigger_types = {t.strip() for t in m.group(1).split(",") if t.strip()}
|
Merge-loop status: human-action blocker — model pool fully exhausted (not PR-caused) Adversarial review of this PR is complete and positive: the dedupe root cause was verified against the live Actions API (run-name expansion breaks main's dedup -> re-dispatch -> concurrency cancellation; observed live killing sweep runs 30115195827/30115019581/30115248345/30115472631 at 21:21-21:37Z Jul 24). The fix is correct and minimal; follow-up commits (3183d15, 7701ff0, e0b9309, 8c2fa1a, 09cea2a, f65b975) closed all residuals. All 35 required check names are green on head cfa6f55; the only missing merge evidence is an OpenCode APPROVED review. That review cannot be produced by any provider in the pool. Latest run 30134761310 (head cfa6f55, Jul 25 00:16-00:22Z, outcome=exhausted, MODEL_OUTPUT_UNAVAILABLE) shows all three provider families hard-down:
Pool hit the 30-attempt ceiling cycling these deterministic failures. Org-wide: 0 successes in the last 60 repository_dispatch reviews. Re-dispatching cannot help until one of these is fixed by a human:
Governance was kept intact throughout: no required-check weakening or bypass; scheduler dispatch limits respected. |
Create an empty commit so required checks re-evaluate on a fresh head, clearing stale failed opencode-review context from unauthorized repository_dispatch rerun attempts. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Merge-loop status: concrete human-action blocker (provider credits/quota exhausted)Adversarial review verdict: No PR-caused defects in this diff. The scheduler dedup reorder was empirically validated (Actions API returns rendered Failure classification: transient infra — org-wide model-provider exhaustion. Three consecutive scheduler-dispatched review runs failed with
Per-provider signatures (all 10 pool candidates failed):
Corroboration: no real-model review succeeded org-wide since ~23:05 UTC (disksage#16, seedream_evasepic#124, wardnet#47/#48 all failed the same way). The deterministic-evidence fallback correctly refuses to approve without a real-model review — governance intact. Human action required: top up OpenRouter credits and/or restore GitHub Models budget (org billing), or wait for quota reset. Once providers recover: trigger a scheduler sweep with Do not press "Re-run" on failed |
Merge-loop status: blocked on provider billing (human action required)Adversarial review of this PR's diff found no defects; all required checks pass except Evidence (head
|
| Run | Time (UTC) | Signature |
|---|---|---|
| 30136608845 | 00:34 | repository_dispatch authorization rejected actor=seonghobae sender=github-actions[bot] (human-triggered scheduler dispatch; self-heals via cron dispatches — later runs passed validation) |
| 30137949893 | 01:10 | same actor rejection |
| 30138330069 | 01:21 | validation OK; MODEL_OUTPUT_UNAVAILABLE after pool exhaustion |
| 30138465894 | 01:25 | validation OK; MODEL_OUTPUT_UNAVAILABLE |
| 30138968747 | 01:40 | validation OK; all 10 candidates fatal in ~5s each |
Per-provider failure classes (run 30138968747)
- github-models/ (deepseek-v3-0324, gpt-4.1, gpt-5, gpt-5-chat, o3, deepseek-r1*):
class=authentication-or-permission. Direct probe ofmodels.github.ai/inferencereturns HTTP 403"Unable to proceed with model usage. This account has locked billing." - openrouter/ (deepseek-v3.2, qwen3-coder):
class=credit-exhausted(HTTP 402) — org OpenRouter credit was burned by run 30120972549 (see Kill hung runs early when a pinned pool model is delisted #621 commit message); the Kill hung runs early when a pinned pool model is delisted #621 spend guards now correctly stop retry spend. - openai/gpt-5.6-luna:
class=quota-or-budget.
Required human action
- Unlock GitHub billing for the account backing
STRIX_GITHUB_MODELS_TOKEN(Models API rejects with "locked billing"). - Top up OpenRouter credits, and/or the direct OpenAI budget.
Once any one provider is funded, the cron scheduler (every 15 min) auto-redispatches the same-head review and this PR merges without further intervention. No approvals exist for any head, so nothing stale can merge.
|
Merge-loop status (automated adversarial review pass) Adversarial review of head c4a9023: no PR-caused defects found.
Only blocker:
Scheduler cron keeps redispatching every 15 min; PR merges automatically once any provider recovers and the review approves. No timing/gate changes made per fixed governance rules. |
seonghobae
left a comment
There was a problem hiding this comment.
Automation note: all review threads are now resolved (0 unresolved). Triggering scheduler re-scan for current head c4a9023.
Merge-loop status: human-action blocker (model-provider outage)Adversarial review of this PR's content found no defects. Scheduler dedupe reorder ( The only blocker is infrastructure, not this PR: every
Evidence runs for #618c4a9023: 30142031164, 30141689649, 30141364368, 30140921858. Same signature reproduced at 2026-07-25T04:46Z (run 30144526218, kaefa#70) and as far back as 2026-07-23T01:19Z (run 29964744722) — even the successful dispatch runs since Jul 22 only passed by reusing prior same-head approvals. No PR has automation-merged since #559 (Jul 14); all later merges were manual. Human actions needed (any one unblocks the pool):
Once any provider recovers, no further action is needed on this PR: all 11 review threads are resolved, Strix evidence is complete, and the scheduler will re-dispatch the same-head review and merge on a real-model APPROVED verdict. Governance untouched — no checks weakened or bypassed. |
Merge-loop status (pass @ 2026-07-25 05:5xZ): human-action blocker persists ? org-wide model-provider billing exhaustionAdversarial review of head
Check state: all required checks green at head except
Classification: infrastructure, not PR-caused. Exhaustion has persisted org-wide since ~20:40Z Jul 24 across all sibling repos. Governance correctly refuses deterministic approval ("only an existing real-model APPROVED review bound to this exact head may satisfy the required review"). No code change here can or should fix this. Human action required: restore model-provider capacity ? clear the GitHub Models billing lock on the org/installation, and/or fund OpenRouter (402) / OpenAI quota. The queue sweep re-dispatches reviews automatically (#549 retried 03:48/04:07/05:03/05:28Z), so PR #618 will re-review and merge without further intervention once any provider recovers. |
|
Merge-loop status: blocked on org-wide review-provider outage (human action required) Adversarial review of this PR found no PR-caused defects; the only failing required check is
Per-provider failure classes from the model-pool logs (provider content suppressed, classes logged):
These classes are not time-window rate limits; reruns will keep failing until at least one credential/budget is restored. Per governance, no deterministic fallback may approve after provider exhaustion — only a real-model APPROVED review bound to this exact head. Once any provider is restored, re-run the failed |
Merge-loop status (pass @ 2026-07-25 08:2xZ): human-action blocker persists ? org-wide model-provider quota exhaustionAdversarial re-review of head Only failing required check:
Scheduler state (not a defect): run 30149522878 decisions ? #618 Human action required: restore model-provider quota/billing (GitHub Models inference quota, OpenAI direct credit, and/or OpenRouter credit). No workflow timing changes were made per the fixed rule (opencode-review timing untouchable; failures = infra, re-run only). Governance intact: no required-check weakening or bypass. |
Merge-loop status: blocked by infrastructure (human action required) ? PR content is soundAdversarial review of this PR's diff found no defects. The scheduler The failing
Failed run evidence (all #618c4a9023, all
Required human actions (any one restores reviews):
Durable fix: migrate the review model pool off Once any provider is funded, the scheduler auto-redispatches the review for this head; no PR changes are needed. |
Merge-loop status: human-action blocker (provider billing), not PR-causedAdversarial review result: PR #618 diff re-reviewed (trigger-type widening, Blocker (with signatures): every OpenCode model-pool attempt fails at the provider account level. Central run 30153577309 attempts 1-6 all ended
Last genuine model review org-wide: ~2026-07-21T04:17Z; since then 129/200 central review runs failed with this signature and all run-level "successes" had the model job skipped (fast-approval scope) - misleading for gauging provider health. Human actions (any one unblocks):
Also recommended: replace retired Once any provider is restored: |
Merge-loop pass @ 2026-07-25T14:1xZ: blocker persists ? provider billing (human action), not PR-causedFresh evidence (post-dates prior comment): run 30153577309 attempt 7 completed failure at 14:03:11Z with the identical signature ?
Outage scope: 0/134 Adversarial re-review of head Only human actions unblock (any one, per #624): top up OpenRouter credits, restore OpenAI quota, or set a fine-grained PAT (Models: read) as org secret |
|
Merge-loop status (agent): blocked on org-wide model-provider outage — not PR-caused. Head
Identical failures hit unrelated repos at the same time (disksage#16 run 30162265183, wardnet#48 run 30162237155, fast-mlsirm#194 run 30162208656), confirming infra, not this diff. Adversarial review of the PR diff itself found no defects; evidence-gate strictness is unchanged. Human action needed: restore provider access — top up OpenRouter credits, restore the OpenAI API budget, and check the GitHub Models token/entitlement (auth failures started ~15:17 UTC). No timing/gate changes were made per policy. Auto-merge (squash) is already armed; once providers recover, rerun run 30153577309 (or let the scheduler re-dispatch) and the PR merges with no further changes. |
|
Merge-loop status (adversarial review + blocker report) Adversarial review of the diff itself: PASS ? no findings.
Merge blocker: infrastructure, not PR-caused ? human action required.
Required human action: unlock GitHub billing for the org/account (and/or top up OpenRouter credits or restore the OpenAI budget). Once any provider recovers, rerun run 30153577309 ? all other required checks are already green on head No timing/threshold edits were made to the review workflow per repo policy (infra failures ? rerun only). |
|
Merge-loop final pass: blocker is deterministic, not transient ? rerunning is pointless until #624 is mitigated. New evidence since the last pass:
Adversarial review outcome (this pass): PR #618 diff remains defect-free. One adjacent base-branch defect was found and filed as #626 ? Human action required (any one of #624's mitigations): top up OpenRouter credits, restore OpenAI quota, or (until Jul 30 only) set a fine-grained Models-read PAT as org secret |
Merge-loop status: blocked on model-pool billing (human action required)Adversarial review of this PR: no defects found.
Why
Human action (any one unblocks the pool):
After that, the merge scheduler auto-reruns the review; auto-merge (squash) is already enabled, so #618 merges without further intervention. Governance untouched: no checks weakened or bypassed. |
Merge-loop status: blocked on provider billing (human action required)PR #618 is code-complete. Adversarial review of the diff found no defects; every required check passes on head
Evidence
Human actions to unblock
Then: No gate weakening or bypass was applied; fail-closed is working as designed. |
Merge-loop pass (2026-07-25T20:2xZ): blocker re-verified — still provider billing, human action requiredAdversarial re-review of head Fresh billing probes (post-mitigation #614/#619/#622/#621, all already on
Failure is deterministic and org-wide (every queue-sweep dispatch 19:52–20:12Z failed identically), therefore not PR-caused and not transient. Per governance rules no required-check weakening or bypass is permitted, and rerunning before #624 (provider billing/credits) is resolved is guaranteed to fail. Once billing is restored, rerun the failed |
Summary
pull_request_targettrigger coverage foredited,ready_for_review,auto_merge_enabled, andauto_merge_disabledin the central merge scheduler workflowenqueued/dequeuedactivity typesRoot cause
Stacked PR chains can change merge-readiness without a head push (base retarget and auto-merge state flips). The scheduler workflow did not trigger on those transitions, so automerge reevaluation could stall until a later sweep.
Why this is safe
Validation
python -m pytest tests/test_required_workflow_queue_contract.py tests/test_adversarial_evidence.py -v