From 846cee70c79ad8645d185f548e7ea3017733ea0f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 04:58:45 +0900 Subject: [PATCH 01/16] fix(scheduler): do not cancel same-SHA scan on review A pull_request_review shares the PR concurrency group with pull_request_target, so cancel-in-progress on that event retired scan-pr-queue even when the head SHA had not changed. --- .../workflows/pr-review-merge-scheduler.yml | 5 +++- .../test_required_workflow_queue_contract.py | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-review-merge-scheduler.yml b/.github/workflows/pr-review-merge-scheduler.yml index d98a72e605..1d521ed98e 100644 --- a/.github/workflows/pr-review-merge-scheduler.yml +++ b/.github/workflows/pr-review-merge-scheduler.yml @@ -88,7 +88,10 @@ concurrency: github.event_name == 'repository_dispatch' && github.event.client_payload.pr_number != '' && format('pr-{0}', github.event.client_payload.pr_number) || github.event_name == 'repository_dispatch' && format('repo-dispatch-{0}', github.repository) || github.ref }} - cancel-in-progress: ${{ github.event_name == 'pull_request_target' || github.event_name == 'pull_request_review' || github.event_name == 'repository_dispatch' }} + # pull_request_review shares this PR group. Cancelling on that event + # retires an in-flight scan-pr-queue even when the head SHA is unchanged. + # A new head still arrives as pull_request_target and cancels the old run. + cancel-in-progress: ${{ github.event_name == 'pull_request_target' || github.event_name == 'repository_dispatch' }} # Scorecard Token-Permissions (alert #9): declare a least-privilege default at # the workflow level. The scan-pr-queue job that actually needs write access diff --git a/tests/test_required_workflow_queue_contract.py b/tests/test_required_workflow_queue_contract.py index 87277d45f5..37505f513c 100644 --- a/tests/test_required_workflow_queue_contract.py +++ b/tests/test_required_workflow_queue_contract.py @@ -1491,6 +1491,30 @@ def test_merge_scheduler_has_no_workflow_run_trigger() -> None: assert "workflow_run:" not in workflow.split("workflow_call:", 1)[0] +def test_review_event_does_not_cancel_same_head_scan() -> None: + """Keep a same-SHA review from cancelling the in-flight required scan. + + ``pull_request_review`` uses the same PR concurrency group as + ``pull_request_target``. ``cancel-in-progress`` on the review event + therefore retires ``scan-pr-queue`` even when the head SHA did not + change. A new head still cancels through ``pull_request_target``. + """ + workflow = workflow_text("pr-review-merge-scheduler.yml") + concurrency = workflow.split("concurrency:", 1)[1].split("permissions:", 1)[0] + cancel_lines = [ + line.strip() + for line in concurrency.splitlines() + if line.strip().startswith("cancel-in-progress:") + ] + + assert len(cancel_lines) == 1 + cancel_line = cancel_lines[0] + assert "github.event_name == 'pull_request_target'" in cancel_line + assert "github.event_name == 'repository_dispatch'" in cancel_line + assert "github.event_name == 'pull_request_review'" not in cancel_line + assert "github.event.pull_request.head.sha" not in concurrency + + def test_review_events_can_dispatch_after_threads_are_resolved() -> None: """Let the scheduler dispatch OpenCode when a review event clears its last blocker.""" workflow = workflow_text("pr-review-merge-scheduler.yml") From 17be694aaff421f8b48aa24250aeedd8eb2d696c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 05:03:14 +0900 Subject: [PATCH 02/16] test(scheduler): require pending exact-head queue preservation --- .../test_required_workflow_queue_contract.py | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/tests/test_required_workflow_queue_contract.py b/tests/test_required_workflow_queue_contract.py index 37505f513c..6ec50305f3 100644 --- a/tests/test_required_workflow_queue_contract.py +++ b/tests/test_required_workflow_queue_contract.py @@ -1491,27 +1491,19 @@ def test_merge_scheduler_has_no_workflow_run_trigger() -> None: assert "workflow_run:" not in workflow.split("workflow_call:", 1)[0] -def test_review_event_does_not_cancel_same_head_scan() -> None: - """Keep a same-SHA review from cancelling the in-flight required scan. +def test_review_events_queue_without_replacing_required_scan() -> None: + """Preserve running and pending exact-head scans in the shared PR group. - ``pull_request_review`` uses the same PR concurrency group as - ``pull_request_target``. ``cancel-in-progress`` on the review event - therefore retires ``scan-pr-queue`` even when the head SHA did not - change. A new head still cancels through ``pull_request_target``. + GitHub's default ``queue: single`` replaces an existing pending run. + The native ``queue: max`` contract preserves pending runs and cannot be + combined with ``cancel-in-progress: true``. Stale events are rejected + by the scheduler's live pull-request validation instead. """ workflow = workflow_text("pr-review-merge-scheduler.yml") concurrency = workflow.split("concurrency:", 1)[1].split("permissions:", 1)[0] - cancel_lines = [ - line.strip() - for line in concurrency.splitlines() - if line.strip().startswith("cancel-in-progress:") - ] - assert len(cancel_lines) == 1 - cancel_line = cancel_lines[0] - assert "github.event_name == 'pull_request_target'" in cancel_line - assert "github.event_name == 'repository_dispatch'" in cancel_line - assert "github.event_name == 'pull_request_review'" not in cancel_line + assert "queue: max" in concurrency + assert "cancel-in-progress:" not in concurrency assert "github.event.pull_request.head.sha" not in concurrency From ce3a4d9f0b93584de85a076fb314840d262d3b68 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 05:03:36 +0900 Subject: [PATCH 03/16] fix(scheduler): preserve pending exact-head scans --- .github/workflows/pr-review-merge-scheduler.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr-review-merge-scheduler.yml b/.github/workflows/pr-review-merge-scheduler.yml index 1d521ed98e..8ad80e0109 100644 --- a/.github/workflows/pr-review-merge-scheduler.yml +++ b/.github/workflows/pr-review-merge-scheduler.yml @@ -88,10 +88,10 @@ concurrency: github.event_name == 'repository_dispatch' && github.event.client_payload.pr_number != '' && format('pr-{0}', github.event.client_payload.pr_number) || github.event_name == 'repository_dispatch' && format('repo-dispatch-{0}', github.repository) || github.ref }} - # pull_request_review shares this PR group. Cancelling on that event - # retires an in-flight scan-pr-queue even when the head SHA is unchanged. - # A new head still arrives as pull_request_target and cancels the old run. - cancel-in-progress: ${{ github.event_name == 'pull_request_target' || github.event_name == 'repository_dispatch' }} + # Preserve every pending PR event in GitHub's native FIFO queue. The + # scheduler re-reads the live pull request before any mutation, so stale + # events fail closed without retiring another exact-head scan. + queue: max # Scorecard Token-Permissions (alert #9): declare a least-privilege default at # the workflow level. The scan-pr-queue job that actually needs write access From be51220705e2967ebd87746be8d95c35ef42d6d6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 05:04:57 +0900 Subject: [PATCH 04/16] docs(gap): record scheduler pending preservation authority --- docs/product-technical-gap-baseline.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index c617e3ad73..e61e358062 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -7,6 +7,12 @@ 이 문서는 제품·기술·운영 Gap을 현재 문서와 현재 GitHub 상태에 묶어 두는 기준선이다. 새 작업은 먼저 이 문서의 Gap ID를 PR 설명과 테스트 증거에 연결하고, PR의 정확한 exact HEAD·Checks·리뷰를 다시 수집한 뒤 구현한다. 표의 상태는 작성 시점의 관측값이므로, 병합 판단에는 재사용하지 않는다. 이 인벤토리는 스냅샷이며 merge authorization이 아니다. +### 2026-09-20 scheduler concurrency authority delta + +| Gap ID | 상태 | exact-head evidence | causal owner / next gate | +|---|---|---|---| +| CONTROL-SCHEDULER-PENDING-PRESERVATION-01 | **Proposed / source repaired on `.github#2289`; protected-main integration pending** | GitHub's native concurrency contract replaces an existing pending run under the default `queue: single`. [RED `17be694aaff421f8b48aa24250aeedd8eb2d696c`](https://github.com/ContextualWisdomLab/.github/commit/17be694aaff421f8b48aa24250aeedd8eb2d696c) proves the workflow lacked pending preservation; [GREEN `ce3a4d9f0b93584de85a076fb314840d262d3b68`](https://github.com/ContextualWisdomLab/.github/commit/ce3a4d9f0b93584de85a076fb314840d262d3b68) uses `queue: max`, removes the incompatible cancellation key, and preserves PR-number live-state validation. Focused assertions 2/2, Python compile 1/1, YAML parse 1/1 passed against exact remote blobs. | Central `.github` owns scheduler concurrency. Stale events re-read the live pull request and fail closed; they do not retire another exact-head scan. Completion requires fresh exact-head hosted Checks, no unresolved actionable review, qualifying independent approval, and ordinary protected-main merge. | + ### 2026-09-13 current-head incident delta | Gap ID | 상태 | exact-head evidence | causal owner / next gate | From 6784c193a3aba019c12906802cf74d3c6ac29cc5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 05:26:19 +0900 Subject: [PATCH 05/16] test(scheduler): pin same-SHA and new-head scan preservation queue: max already keeps a pending run when cancellation is off, but the close-event contracts still required the cancellation key GitHub rejects beside that queue. State both cases in the contract instead. Co-authored-by: Cursor --- .../workflows/pr-review-merge-scheduler.yml | 10 +++-- tests/test_close_empty_pr_queue_pressure.py | 6 ++- .../test_required_workflow_queue_contract.py | 39 +++++++++++++------ 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/.github/workflows/pr-review-merge-scheduler.yml b/.github/workflows/pr-review-merge-scheduler.yml index 8ad80e0109..41d3b951c6 100644 --- a/.github/workflows/pr-review-merge-scheduler.yml +++ b/.github/workflows/pr-review-merge-scheduler.yml @@ -88,9 +88,13 @@ concurrency: github.event_name == 'repository_dispatch' && github.event.client_payload.pr_number != '' && format('pr-{0}', github.event.client_payload.pr_number) || github.event_name == 'repository_dispatch' && format('repo-dispatch-{0}', github.repository) || github.ref }} - # Preserve every pending PR event in GitHub's native FIFO queue. The - # scheduler re-reads the live pull request before any mutation, so stale - # events fail closed without retiring another exact-head scan. + # queue: single would replace a pending run even when in-progress + # cancellation is off. queue: max keeps that pending run, an in-progress + # same-SHA scan, and the successor for a new head (the group is the PR + # number, not the head SHA). In-progress cancellation cannot be enabled + # beside queue: max. The scheduler re-reads the live pull request before + # any mutation, so a stale event fails closed without retiring the + # exact-head scan. queue: max # Scorecard Token-Permissions (alert #9): declare a least-privilege default at diff --git a/tests/test_close_empty_pr_queue_pressure.py b/tests/test_close_empty_pr_queue_pressure.py index 6da88f63f1..f094acbd08 100644 --- a/tests/test_close_empty_pr_queue_pressure.py +++ b/tests/test_close_empty_pr_queue_pressure.py @@ -30,7 +30,11 @@ def test_closed_pull_request_does_not_allocate_a_noop_runner( assert "closed" in workflow assert "github.event.pull_request.number" in concurrency assert "github.event.pull_request.head.sha" not in concurrency - assert re.search(r"(?m)^[ \t]+cancel-in-progress:[ \t]+\S", concurrency) + if filename == "pr-review-merge-scheduler.yml": + assert "queue: max" in concurrency + assert "cancel-in-progress:" not in concurrency + else: + assert re.search(r"(?m)^[ \t]+cancel-in-progress:[ \t]+\S", concurrency) assert "cancel-closed-pr-runs:" not in workflow assert "github.event.action != 'closed'" in workflow assert evidence_job in workflow diff --git a/tests/test_required_workflow_queue_contract.py b/tests/test_required_workflow_queue_contract.py index 6ec50305f3..e129e69677 100644 --- a/tests/test_required_workflow_queue_contract.py +++ b/tests/test_required_workflow_queue_contract.py @@ -226,10 +226,11 @@ def test_merge_scheduler_uses_native_auto_merge_after_required_checks() -> None: assert "github.event_name == 'repository_dispatch' && github.run_id" not in ( concurrency_contract ) - # Anchored, not a substring: this workflow's value is an expression rather - # than a constant, so it cannot use the boolean helper, but a commented-out - # setting must not satisfy it either. - assert re.search(r"(?m)^[ \t]+cancel-in-progress:[ \t]+\$\{\{", concurrency_contract) + # ``queue: max`` keeps every pending run. ``cancel-in-progress: true`` is + # a workflow validation error beside it, and the default ``queue: single`` + # would replace a pending exact-head scan even when cancellation is false. + assert "queue: max" in concurrency_contract + assert "cancel-in-progress:" not in concurrency_contract assert "github.event_name == 'repository_dispatch'" in concurrency_contract @@ -1105,9 +1106,20 @@ def test_pull_request_close_events_cancel_superseded_runs_without_heavy_jobs() - assert "actions: write" in cleanup_job assert "actions/checkout" not in cleanup_job assert "cleanup skipped" not in cleanup_job + elif filename == "pr-review-merge-scheduler.yml": + # Close still skips the scan job. Pending and in-progress scans stay, + # including across a new head, because ``queue: max`` cannot combine + # with ``cancel-in-progress: true``. + assert "cancel-closed-pr-runs:" not in workflow + concurrency_contract = workflow.split("concurrency:", 1)[1].split( + "permissions:", 1 + )[0] + assert "github.event.pull_request.number" in concurrency_contract + assert "github.event.pull_request.head.sha" not in concurrency_contract + assert "queue: max" in concurrency_contract + assert "cancel-in-progress:" not in concurrency_contract elif filename in { "codeql-pr.yml", - "pr-review-merge-scheduler.yml", "python-security.yml", "sast-semgrep.yml", "security-scan.yml", @@ -1492,12 +1504,16 @@ def test_merge_scheduler_has_no_workflow_run_trigger() -> None: def test_review_events_queue_without_replacing_required_scan() -> None: - """Preserve running and pending exact-head scans in the shared PR group. - - GitHub's default ``queue: single`` replaces an existing pending run. - The native ``queue: max`` contract preserves pending runs and cannot be - combined with ``cancel-in-progress: true``. Stale events are rejected - by the scheduler's live pull-request validation instead. + """Keep the required scan for the same SHA and for a new head. + + GitHub's default ``queue: single`` replaces an existing pending run even + when ``cancel-in-progress`` is false. ``queue: max`` keeps that pending + run and every later run, including a new head, and cannot be combined + with ``cancel-in-progress: true``. Omitting cancellation therefore also + leaves an in-progress same-SHA scan running. The group stays on the PR + number, not the head SHA, so the new head waits in that same queue + instead of dropping the scan. Stale events fail closed when the + scheduler re-reads the live pull request. """ workflow = workflow_text("pr-review-merge-scheduler.yml") concurrency = workflow.split("concurrency:", 1)[1].split("permissions:", 1)[0] @@ -1505,6 +1521,7 @@ def test_review_events_queue_without_replacing_required_scan() -> None: assert "queue: max" in concurrency assert "cancel-in-progress:" not in concurrency assert "github.event.pull_request.head.sha" not in concurrency + assert "format('pr-{0}', github.event.pull_request.number)" in concurrency def test_review_events_can_dispatch_after_threads_are_resolved() -> None: From e2647c5b6d72259e99a36a4955faeb0a2967931c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:01:32 +0900 Subject: [PATCH 06/16] test(scheduler): require exact-head admission and stale-run retirement Corrected RED: preserve same-head pending scans with an exact-head workflow queue, while requiring an actions:write metadata cleanup to retire only predecessor-head runs after repository/PR/head revalidation. Focused result before production repair: 4 failed, 72 passed. --- tests/test_close_empty_pr_queue_pressure.py | 11 +++- .../test_required_workflow_queue_contract.py | 66 ++++++++++++++----- 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/tests/test_close_empty_pr_queue_pressure.py b/tests/test_close_empty_pr_queue_pressure.py index f094acbd08..d8ec8547f9 100644 --- a/tests/test_close_empty_pr_queue_pressure.py +++ b/tests/test_close_empty_pr_queue_pressure.py @@ -29,11 +29,20 @@ def test_closed_pull_request_does_not_allocate_a_noop_runner( assert "closed" in workflow assert "github.event.pull_request.number" in concurrency - assert "github.event.pull_request.head.sha" not in concurrency if filename == "pr-review-merge-scheduler.yml": + assert "github.event.pull_request.head.sha" in concurrency assert "queue: max" in concurrency assert "cancel-in-progress:" not in concurrency + cleanup_job = workflow.split( + " cancel-superseded-pr-runs:", 1 + )[1].split(" scan-pr-queue:", 1)[0] + assert "actions: write" in cleanup_job + assert "actions/checkout" not in cleanup_job + assert "github.event.action == 'closed'" in cleanup_job + assert "TARGET_PR_NUMBER" in cleanup_job + assert "TARGET_PR_HEAD_SHA" in cleanup_job else: + assert "github.event.pull_request.head.sha" not in concurrency assert re.search(r"(?m)^[ \t]+cancel-in-progress:[ \t]+\S", concurrency) assert "cancel-closed-pr-runs:" not in workflow assert "github.event.action != 'closed'" in workflow diff --git a/tests/test_required_workflow_queue_contract.py b/tests/test_required_workflow_queue_contract.py index e129e69677..1de319fe23 100644 --- a/tests/test_required_workflow_queue_contract.py +++ b/tests/test_required_workflow_queue_contract.py @@ -226,13 +226,25 @@ def test_merge_scheduler_uses_native_auto_merge_after_required_checks() -> None: assert "github.event_name == 'repository_dispatch' && github.run_id" not in ( concurrency_contract ) - # ``queue: max`` keeps every pending run. ``cancel-in-progress: true`` is - # a workflow validation error beside it, and the default ``queue: single`` - # would replace a pending exact-head scan even when cancellation is false. + # The workflow-level queue serializes only duplicate admissions for one + # exact head. The scan job has the PR-stable cancellation boundary that + # retires a predecessor head after the successor has been admitted. assert "queue: max" in concurrency_contract assert "cancel-in-progress:" not in concurrency_contract + assert "github.event.pull_request.head.sha" in concurrency_contract + assert "github.event.client_payload.pr_head_sha" in concurrency_contract assert "github.event_name == 'repository_dispatch'" in concurrency_contract + cleanup_job = workflow.split(" cancel-superseded-pr-runs:", 1)[1].split( + " scan-pr-queue:", 1 + )[0] + assert "actions: write" in cleanup_job + assert "actions/checkout" not in cleanup_job + assert "github.event.pull_request.number" in cleanup_job + assert "github.event.pull_request.head.sha" in cleanup_job + assert "pull_requests" in cleanup_job + assert "force-cancel" in cleanup_job + def test_merge_scheduler_provides_same_repository_dispatch_credential() -> None: """Guard the runner-token dispatch credential for central review workflows. @@ -1107,17 +1119,24 @@ def test_pull_request_close_events_cancel_superseded_runs_without_heavy_jobs() - assert "actions/checkout" not in cleanup_job assert "cleanup skipped" not in cleanup_job elif filename == "pr-review-merge-scheduler.yml": - # Close still skips the scan job. Pending and in-progress scans stay, - # including across a new head, because ``queue: max`` cannot combine - # with ``cancel-in-progress: true``. + # Close skips the scan job. Exact-head admission preserves same-head + # work, while the job-level PR group retires a predecessor head. assert "cancel-closed-pr-runs:" not in workflow concurrency_contract = workflow.split("concurrency:", 1)[1].split( "permissions:", 1 )[0] assert "github.event.pull_request.number" in concurrency_contract - assert "github.event.pull_request.head.sha" not in concurrency_contract + assert "github.event.pull_request.head.sha" in concurrency_contract assert "queue: max" in concurrency_contract assert "cancel-in-progress:" not in concurrency_contract + assert "cancel-superseded-pr-runs:" in workflow + cleanup_job = workflow.split( + " cancel-superseded-pr-runs:", 1 + )[1].split(" scan-pr-queue:", 1)[0] + assert "actions: write" in cleanup_job + assert "github.event.pull_request.number" in cleanup_job + assert "github.event.pull_request.head.sha" in cleanup_job + assert "actions/checkout" not in cleanup_job elif filename in { "codeql-pr.yml", "python-security.yml", @@ -1503,26 +1522,37 @@ def test_merge_scheduler_has_no_workflow_run_trigger() -> None: assert "workflow_run:" not in workflow.split("workflow_call:", 1)[0] -def test_review_events_queue_without_replacing_required_scan() -> None: - """Keep the required scan for the same SHA and for a new head. +def test_review_events_preserve_same_head_and_retire_predecessor_head() -> None: + """Serialize one head without making a new head wait behind stale work. - GitHub's default ``queue: single`` replaces an existing pending run even - when ``cancel-in-progress`` is false. ``queue: max`` keeps that pending - run and every later run, including a new head, and cannot be combined - with ``cancel-in-progress: true``. Omitting cancellation therefore also - leaves an in-progress same-SHA scan running. The group stays on the PR - number, not the head SHA, so the new head waits in that same queue - instead of dropping the scan. Stale events fail closed when the - scheduler re-reads the live pull request. + The workflow-level exact-head queue preserves all admissions for a head. + A different head enters another workflow group and its bounded metadata + cleanup retires only the predecessor scan after revalidating repository, + pull request, and head identity. """ workflow = workflow_text("pr-review-merge-scheduler.yml") concurrency = workflow.split("concurrency:", 1)[1].split("permissions:", 1)[0] assert "queue: max" in concurrency assert "cancel-in-progress:" not in concurrency - assert "github.event.pull_request.head.sha" not in concurrency + assert "github.event.pull_request.head.sha" in concurrency + assert "github.event.client_payload.pr_head_sha" in concurrency assert "format('pr-{0}', github.event.pull_request.number)" in concurrency + cleanup_job = workflow.split(" cancel-superseded-pr-runs:", 1)[1].split( + " scan-pr-queue:", 1 + )[0] + assert "github.event.action == 'synchronize'" in cleanup_job + assert "github.event.action == 'closed'" in cleanup_job + assert "actions: write" in cleanup_job + assert "actions/checkout" not in cleanup_job + assert "TARGET_REPOSITORY" in cleanup_job + assert "TARGET_PR_NUMBER" in cleanup_job + assert "TARGET_PR_HEAD_SHA" in cleanup_job + assert "live_target_matches" in cleanup_job + assert "pull_requests" in cleanup_job + assert "force-cancel" in cleanup_job + def test_review_events_can_dispatch_after_threads_are_resolved() -> None: """Let the scheduler dispatch OpenCode when a review event clears its last blocker.""" From 739a34c07d56f331767e6200d5172c648d0e27cf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:04:36 +0900 Subject: [PATCH 07/16] fix(scheduler): retire revalidated predecessor head runs --- .../workflows/pr-review-merge-scheduler.yml | 111 ++++++++++++++++-- 1 file changed, 103 insertions(+), 8 deletions(-) diff --git a/.github/workflows/pr-review-merge-scheduler.yml b/.github/workflows/pr-review-merge-scheduler.yml index 41d3b951c6..7e432861d8 100644 --- a/.github/workflows/pr-review-merge-scheduler.yml +++ b/.github/workflows/pr-review-merge-scheduler.yml @@ -87,14 +87,16 @@ concurrency: github.event_name == 'repository_dispatch' && github.event.client_payload.target_repository != '' && github.event.client_payload.pr_number != '' && format('target-{0}-pr-{1}', github.event.client_payload.target_repository, github.event.client_payload.pr_number) || github.event_name == 'repository_dispatch' && github.event.client_payload.pr_number != '' && format('pr-{0}', github.event.client_payload.pr_number) || github.event_name == 'repository_dispatch' && format('repo-dispatch-{0}', github.repository) || - github.ref }} - # queue: single would replace a pending run even when in-progress - # cancellation is off. queue: max keeps that pending run, an in-progress - # same-SHA scan, and the successor for a new head (the group is the PR - # number, not the head SHA). In-progress cancellation cannot be enabled - # beside queue: max. The scheduler re-reads the live pull request before - # any mutation, so a stale event fails closed without retiring the - # exact-head scan. + github.ref }}-${{ + github.event_name == 'pull_request_target' && github.event.action == 'closed' && format('head-{0}-closed', github.event.pull_request.head.sha) || + github.event_name == 'pull_request_target' && format('head-{0}', github.event.pull_request.head.sha) || + github.event_name == 'pull_request_review' && format('head-{0}', github.event.pull_request.head.sha) || + github.event_name == 'repository_dispatch' && github.event.client_payload.pr_head_sha != '' && format('head-{0}', github.event.client_payload.pr_head_sha) || + 'no-head' }} + # GitHub's native FIFO queue preserves duplicate admissions for one exact + # head. A successor head receives a distinct group, then the bounded cleanup + # job below retires only revalidated predecessor runs. Close uses a distinct + # suffix so it can retire an active scan for the same final head. queue: max # Scorecard Token-Permissions (alert #9): declare a least-privilege default at @@ -105,6 +107,99 @@ permissions: contents: read jobs: + cancel-superseded-pr-runs: + if: >- + github.event_name == 'pull_request_target' && + ( + github.event.action == 'synchronize' || + github.event.action == 'closed' + ) + runs-on: ubuntu-24.04 + permissions: + actions: write + contents: read + pull-requests: read + env: + GH_TOKEN: ${{ github.token }} + TARGET_REPOSITORY: ${{ github.repository }} + TARGET_PR_NUMBER: ${{ github.event.pull_request.number }} + TARGET_PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} + TARGET_ACTION: ${{ github.event.action }} + steps: + - name: Cancel revalidated predecessor scheduler runs + shell: bash + run: | + set -euo pipefail + + if ! [[ "$TARGET_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] || + ! [[ "$TARGET_PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || + ! [[ "$TARGET_PR_HEAD_SHA" =~ ^[0-9a-fA-F]{40}$ ]]; then + echo "::error::Superseded-run cleanup rejected malformed target identity." + exit 1 + fi + + live_pull="$(gh api "repos/${TARGET_REPOSITORY}/pulls/${TARGET_PR_NUMBER}")" + live_repository="$(jq -r '.base.repo.full_name // empty' <<<"$live_pull")" + live_number="$(jq -r '.number // 0' <<<"$live_pull")" + live_state="$(jq -r '.state // empty' <<<"$live_pull")" + live_head_sha="$(jq -r '.head.sha // empty' <<<"$live_pull")" + live_target_matches=false + if [ "$live_repository" = "$TARGET_REPOSITORY" ] && + [ "$live_number" = "$TARGET_PR_NUMBER" ] && + [ "$live_head_sha" = "$TARGET_PR_HEAD_SHA" ]; then + case "$TARGET_ACTION:$live_state" in + synchronize:open|closed:closed) live_target_matches=true ;; + esac + fi + if [ "$live_target_matches" != "true" ]; then + echo "Superseded-run cleanup skipped because the event no longer matches the live pull request." + exit 0 + fi + + workflow_runs="$( + gh api --paginate --slurp \ + "repos/${TARGET_REPOSITORY}/actions/workflows/pr-review-merge-scheduler.yml/runs?event=pull_request_target&per_page=100" + )" + mapfile -t superseded_run_ids < <( + jq -r \ + --argjson pr_number "$TARGET_PR_NUMBER" \ + --argjson current_run_id "$GITHUB_RUN_ID" \ + --arg target_head "$TARGET_PR_HEAD_SHA" \ + --arg target_action "$TARGET_ACTION" \ + ' + .[] | .workflow_runs[]? + | select(.id != $current_run_id) + | select( + .status == "requested" or + .status == "waiting" or + .status == "pending" or + .status == "queued" or + .status == "in_progress" + ) + | select(any(.pull_requests[]?; .number == $pr_number)) + | select($target_action == "closed" or .head_sha != $target_head) + | .id + ' <<<"$workflow_runs" + ) + + for run_id in "${superseded_run_ids[@]}"; do + if gh api -X POST \ + "repos/${TARGET_REPOSITORY}/actions/runs/${run_id}/force-cancel" \ + >/dev/null 2>&1; then + echo "Cancelled superseded scheduler run $run_id." + continue + fi + run_status="$( + gh api "repos/${TARGET_REPOSITORY}/actions/runs/${run_id}" \ + --jq '.status // empty' + )" + if [ "$run_status" = "completed" ]; then + continue + fi + echo "::error::Could not force-cancel nonterminal scheduler run $run_id." + exit 1 + done + scan-pr-queue: # repository_dispatch review runs do not reliably carry pull_requests metadata. # Without this guard, one completed central review can wake a repo-wide scan. From 648674c92f1016f5cf8420f75d9d8679ff2dc665 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:05:51 +0900 Subject: [PATCH 08/16] test(scheduler): bind cleanup to pull request head authority --- tests/test_required_workflow_queue_contract.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_required_workflow_queue_contract.py b/tests/test_required_workflow_queue_contract.py index 1de319fe23..8f138faae2 100644 --- a/tests/test_required_workflow_queue_contract.py +++ b/tests/test_required_workflow_queue_contract.py @@ -242,7 +242,9 @@ def test_merge_scheduler_uses_native_auto_merge_after_required_checks() -> None: assert "actions/checkout" not in cleanup_job assert "github.event.pull_request.number" in cleanup_job assert "github.event.pull_request.head.sha" in cleanup_job - assert "pull_requests" in cleanup_job + assert ".pull_requests[]?" in cleanup_job + assert ".head.sha" in cleanup_job + assert ".head_sha != $target_head" not in cleanup_job assert "force-cancel" in cleanup_job From 406c7178974c3b887694a229a59c66a02e0810dd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:06:11 +0900 Subject: [PATCH 09/16] fix(scheduler): compare associated pull request head --- .github/workflows/pr-review-merge-scheduler.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-review-merge-scheduler.yml b/.github/workflows/pr-review-merge-scheduler.yml index 7e432861d8..f239332764 100644 --- a/.github/workflows/pr-review-merge-scheduler.yml +++ b/.github/workflows/pr-review-merge-scheduler.yml @@ -176,8 +176,20 @@ jobs: .status == "queued" or .status == "in_progress" ) - | select(any(.pull_requests[]?; .number == $pr_number)) - | select($target_action == "closed" or .head_sha != $target_head) + | select( + any( + .pull_requests[]?; + (.head.sha // "") as $run_pr_head + | .number == $pr_number + | select( + $target_action == "closed" or + ( + ($run_pr_head | test("^[0-9a-fA-F]{40}$")) and + $run_pr_head != $target_head + ) + ) + ) + ) | .id ' <<<"$workflow_runs" ) From 10dc596407af27560974b7323aa9cd9e1b3f013d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:13:41 +0900 Subject: [PATCH 10/16] docs(gap): record stacked exact-head scheduler repair --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e61e358062..1d8f7716bd 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -11,7 +11,7 @@ | Gap ID | 상태 | exact-head evidence | causal owner / next gate | |---|---|---|---| -| CONTROL-SCHEDULER-PENDING-PRESERVATION-01 | **Proposed / source repaired on `.github#2289`; protected-main integration pending** | GitHub's native concurrency contract replaces an existing pending run under the default `queue: single`. [RED `17be694aaff421f8b48aa24250aeedd8eb2d696c`](https://github.com/ContextualWisdomLab/.github/commit/17be694aaff421f8b48aa24250aeedd8eb2d696c) proves the workflow lacked pending preservation; [GREEN `ce3a4d9f0b93584de85a076fb314840d262d3b68`](https://github.com/ContextualWisdomLab/.github/commit/ce3a4d9f0b93584de85a076fb314840d262d3b68) uses `queue: max`, removes the incompatible cancellation key, and preserves PR-number live-state validation. Focused assertions 2/2, Python compile 1/1, YAML parse 1/1 passed against exact remote blobs. | Central `.github` owns scheduler concurrency. Stale events re-read the live pull request and fail closed; they do not retire another exact-head scan. Completion requires fresh exact-head hosted Checks, no unresolved actionable review, qualifying independent approval, and ordinary protected-main merge. | +| CONTROL-SCHEDULER-PENDING-PRESERVATION-01 | **Proposed / source repaired on stacked `.github#2289`; protected-main integration pending** | GitHub's native concurrency contract replaces an existing pending run under default `queue: single`. [RED `17be694a`](https://github.com/ContextualWisdomLab/.github/commit/17be694aaff421f8b48aa24250aeedd8eb2d696c) established the missing pending-preservation contract; [GREEN `ce3a4d9f`](https://github.com/ContextualWisdomLab/.github/commit/ce3a4d9f0b93584de85a076fb314840d262d3b68) adopted `queue: max`. Concurrent RED `e2647c5b` then exposed tests without production exact-head cleanup; production repair [`739a34c0`](https://github.com/ContextualWisdomLab/.github/commit/739a34c07d56f331767e6200d5172c648d0e27cf), authority RED [`648674c9`](https://github.com/ContextualWisdomLab/.github/commit/648674c92f1016f5cf8420f75d9d8679ff2dc665), and GREEN [`406c7178`](https://github.com/ContextualWisdomLab/.github/commit/406c7178974c3b887694a229a59c66a02e0810dd) bind cleanup to associated PR `head.sha`, not `pull_request_target` run `.head_sha`. Ordinary two-parent stack [`873a35f4`](https://github.com/ContextualWisdomLab/.github/commit/873a35f45c9c3b25f72797b25b6bbe98051d0f3d) preserves #2289 and canonical #2283 histories. Exact remote verification: static contracts 14/14, jq synchronize/closed fixtures 2/2, Python compile 2/2, YAML parse 1/1, cleanup Bash syntax 1/1. | Central `.github` owns scheduler concurrency; #2289 is stacked on #2283 rather than acting as a divergent writer. Same-head events retain native FIFO admission, successor heads enter a distinct group, and metadata-only cleanup revalidates live repository/PR/head before retiring predecessor runs. Completion requires prerequisite #2283 integration, fresh exact-head hosted Checks, no actionable review, qualifying independent approval, and ordinary protected-main merge. | ### 2026-09-13 current-head incident delta From 8067fb65daa6b01265f3c0e011ffd83b7f439273 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:20:34 +0900 Subject: [PATCH 11/16] fix(scheduler): verify superseded-run cancellation --- .../workflows/pr-review-merge-scheduler.yml | 61 +++++--- ...920-scheduler-cancellation-verification.md | 3 + .../test_required_workflow_queue_contract.py | 148 +++++++++++++++++- 3 files changed, 193 insertions(+), 19 deletions(-) create mode 100644 CHANGELOG.d/20260920-scheduler-cancellation-verification.md diff --git a/.github/workflows/pr-review-merge-scheduler.yml b/.github/workflows/pr-review-merge-scheduler.yml index f239332764..d2fbc1018a 100644 --- a/.github/workflows/pr-review-merge-scheduler.yml +++ b/.github/workflows/pr-review-merge-scheduler.yml @@ -138,20 +138,22 @@ jobs: exit 1 fi - live_pull="$(gh api "repos/${TARGET_REPOSITORY}/pulls/${TARGET_PR_NUMBER}")" - live_repository="$(jq -r '.base.repo.full_name // empty' <<<"$live_pull")" - live_number="$(jq -r '.number // 0' <<<"$live_pull")" - live_state="$(jq -r '.state // empty' <<<"$live_pull")" - live_head_sha="$(jq -r '.head.sha // empty' <<<"$live_pull")" - live_target_matches=false - if [ "$live_repository" = "$TARGET_REPOSITORY" ] && - [ "$live_number" = "$TARGET_PR_NUMBER" ] && - [ "$live_head_sha" = "$TARGET_PR_HEAD_SHA" ]; then - case "$TARGET_ACTION:$live_state" in - synchronize:open|closed:closed) live_target_matches=true ;; - esac - fi - if [ "$live_target_matches" != "true" ]; then + live_target_matches() { + local live_pull live_repository live_number live_state live_head_sha + live_pull="$(gh api "repos/${TARGET_REPOSITORY}/pulls/${TARGET_PR_NUMBER}")" + live_repository="$(jq -r '.base.repo.full_name // empty' <<<"$live_pull")" + live_number="$(jq -r '.number // 0' <<<"$live_pull")" + live_state="$(jq -r '.state // empty' <<<"$live_pull")" + live_head_sha="$(jq -r '.head.sha // empty' <<<"$live_pull")" + [ "$live_repository" = "$TARGET_REPOSITORY" ] && + [ "$live_number" = "$TARGET_PR_NUMBER" ] && + [ "$live_head_sha" = "$TARGET_PR_HEAD_SHA" ] && { + [ "$TARGET_ACTION:$live_state" = "synchronize:open" ] || + [ "$TARGET_ACTION:$live_state" = "closed:closed" ] + } + } + + if ! live_target_matches; then echo "Superseded-run cleanup skipped because the event no longer matches the live pull request." exit 0 fi @@ -195,16 +197,39 @@ jobs: ) for run_id in "${superseded_run_ids[@]}"; do + if ! live_target_matches; then + echo "Superseded-run cleanup stopped because the target changed before cancellation." + exit 0 + fi if gh api -X POST \ "repos/${TARGET_REPOSITORY}/actions/runs/${run_id}/force-cancel" \ >/dev/null 2>&1; then - echo "Cancelled superseded scheduler run $run_id." + cancellation_verified=false + for attempt in 1 2 3 4 5 6; do + IFS=$'\t' read -r run_status run_conclusion < <( + gh api "repos/${TARGET_REPOSITORY}/actions/runs/${run_id}" \ + --jq '[.status // "", .conclusion // ""] | @tsv' + ) + if [ "$run_status" = "completed" ] && + [ "$run_conclusion" = "cancelled" ]; then + cancellation_verified=true + break + fi + if [ "$attempt" -lt 6 ]; then + sleep 1 + fi + done + if [ "$cancellation_verified" != "true" ]; then + echo "::error::Scheduler run $run_id did not reach completed/cancelled after accepted force-cancel." + exit 1 + fi + echo "Verified cancelled scheduler run $run_id." continue fi - run_status="$( + IFS=$'\t' read -r run_status run_conclusion < <( gh api "repos/${TARGET_REPOSITORY}/actions/runs/${run_id}" \ - --jq '.status // empty' - )" + --jq '[.status // "", .conclusion // ""] | @tsv' + ) if [ "$run_status" = "completed" ]; then continue fi diff --git a/CHANGELOG.d/20260920-scheduler-cancellation-verification.md b/CHANGELOG.d/20260920-scheduler-cancellation-verification.md new file mode 100644 index 0000000000..c6efbdc28f --- /dev/null +++ b/CHANGELOG.d/20260920-scheduler-cancellation-verification.md @@ -0,0 +1,3 @@ +### Scheduler cleanup proves cancellation before completion + +The required-review merge scheduler now revalidates the live pull request immediately before each superseded-run mutation and treats an accepted force-cancel request as incomplete until GitHub reports the run as `completed/cancelled`. Bounded executable regressions cover a concurrent head advance, a cancellation that never terminates, and a successful asynchronous cancellation. diff --git a/tests/test_required_workflow_queue_contract.py b/tests/test_required_workflow_queue_contract.py index edc106437e..97ca73fa52 100644 --- a/tests/test_required_workflow_queue_contract.py +++ b/tests/test_required_workflow_queue_contract.py @@ -1553,6 +1553,153 @@ def test_review_events_preserve_same_head_and_retire_predecessor_head() -> None: assert "force-cancel" in cleanup_job +def _run_merge_scheduler_cleanup( + tmp_path: Path, + pull_states: list[dict[str, object]], + run_states: list[dict[str, object]], +) -> tuple[subprocess.CompletedProcess[str], str]: + """Execute the production scheduler cleanup against a stateful fake ``gh``.""" + if shutil.which("jq") is None: + pytest.skip("jq is required to execute the production cleanup") + step = workflow_step( + workflow_text("pr-review-merge-scheduler.yml"), + "Cancel revalidated predecessor scheduler runs", + ) + run_block = step.split(" run: |\n", 1)[1].split( + "\n scan-pr-queue:", 1 + )[0] + script = textwrap.dedent(run_block) + fake_bin = tmp_path / "bin" + fake_bin.mkdir() + calls = tmp_path / "calls" + pulls = tmp_path / "pulls" + runs = tmp_path / "runs" + pulls.write_text( + "\n".join(json.dumps(state) for state in pull_states) + "\n", + encoding="utf-8", + ) + runs.write_text( + "\n".join(json.dumps(state) for state in run_states) + "\n", + encoding="utf-8", + ) + fake_gh = fake_bin / "gh" + fake_gh.write_text( + """#!/usr/bin/env bash +set -euo pipefail +printf '%s\n' "$*" >>"$FAKE_CALLS" +next_line() { + local source="$1" + local count_file="${source}.count" + local count=0 + [[ ! -f "$count_file" ]] || count="$(cat "$count_file")" + count=$((count + 1)) + printf '%s' "$count" >"$count_file" + sed -n "${count}p" "$source" +} +if [[ "$*" == *"/pulls/7"* ]]; then + next_line "$FAKE_PULLS" + exit 0 +fi +if [[ "$*" == *"actions/workflows/pr-review-merge-scheduler.yml/runs"* ]]; then + printf '%s\n' '[{"workflow_runs":[{"id":100,"status":"queued","pull_requests":[{"number":7,"head":{"sha":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}}]}]}]' + exit 0 +fi +if [[ "$*" == *"actions/runs/100/force-cancel"* ]]; then + exit 0 +fi +if [[ "$*" == *"actions/runs/100"* ]]; then + state="$(next_line "$FAKE_RUNS")" + if [[ "$*" == *"--jq"* ]]; then + jq -r '[.status // "", .conclusion // ""] | @tsv' <<<"$state" + else + printf '%s\n' "$state" + fi + exit 0 +fi +exit 1 +""", + encoding="utf-8", + ) + fake_gh.chmod(0o755) + result = subprocess.run( # noqa: S603, S607 + ["bash", "-c", script], + env={ + **os.environ, + "PATH": f"{fake_bin}{os.pathsep}{os.environ['PATH']}", + "FAKE_CALLS": str(calls), + "FAKE_PULLS": str(pulls), + "FAKE_RUNS": str(runs), + "GH_TOKEN": "synthetic-actions-token", + "GITHUB_RUN_ID": "999", + "TARGET_REPOSITORY": "owner/repo", + "TARGET_PR_NUMBER": "7", + "TARGET_PR_HEAD_SHA": "a" * 40, + "TARGET_ACTION": "synchronize", + }, + capture_output=True, + text=True, + check=False, + ) + return result, calls.read_text(encoding="utf-8") + + +def _live_scheduler_pull(*, head_sha: str = "a" * 40) -> dict[str, object]: + """Build one live pull-request response for scheduler cleanup evidence.""" + return { + "base": {"repo": {"full_name": "owner/repo"}}, + "number": 7, + "state": "open", + "head": {"sha": head_sha}, + } + + +def test_scheduler_cleanup_revalidates_target_after_run_selection(tmp_path: Path) -> None: + """A concurrent head advance after selection must prevent cancellation.""" + result, calls = _run_merge_scheduler_cleanup( + tmp_path, + [ + _live_scheduler_pull(), + _live_scheduler_pull(head_sha="c" * 40), + ], + [{"status": "completed", "conclusion": "cancelled"}], + ) + + assert result.returncode == 0, result.stderr + assert calls.count("/pulls/7") == 2 + assert "/actions/runs/100/force-cancel" not in calls + + +def test_scheduler_cleanup_fails_when_accepted_cancel_never_finishes( + tmp_path: Path, +) -> None: + """A successful POST is not proof that the run reached terminal cancellation.""" + result, calls = _run_merge_scheduler_cleanup( + tmp_path, + [_live_scheduler_pull()] * 8, + [{"status": "in_progress", "conclusion": None}] * 6, + ) + + assert result.returncode == 1 + assert calls.count("actions/runs/100 --jq") == 6 + assert "did not reach completed/cancelled" in result.stdout + + +def test_scheduler_cleanup_verifies_accepted_cancelled_state(tmp_path: Path) -> None: + """Finish only after GitHub reports the accepted cancellation as terminal.""" + result, calls = _run_merge_scheduler_cleanup( + tmp_path, + [_live_scheduler_pull()] * 8, + [ + {"status": "in_progress", "conclusion": None}, + {"status": "completed", "conclusion": "cancelled"}, + ], + ) + + assert result.returncode == 0, result.stderr + assert calls.count("actions/runs/100 --jq") == 2 + assert "Verified cancelled scheduler run 100." in result.stdout + + def test_review_events_can_dispatch_after_threads_are_resolved() -> None: """Let the scheduler dispatch OpenCode when a review event clears its last blocker.""" workflow = workflow_text("pr-review-merge-scheduler.yml") @@ -2200,4 +2347,3 @@ def test_scorecard_medium_plus_governance_has_owner_and_runbook() -> None: assert "latest head commit" in runbook assert "cancel superseded runs" in runbook assert "Every central workflow failure must print the actionable reason" in runbook - From c39f57d4890be5bab12e8845014eeefe1e99f7ae Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:21:06 +0900 Subject: [PATCH 12/16] docs(gap): bind scheduler cancellation proof --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 1d8f7716bd..fcb05d6bcb 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -11,7 +11,7 @@ | Gap ID | 상태 | exact-head evidence | causal owner / next gate | |---|---|---|---| -| CONTROL-SCHEDULER-PENDING-PRESERVATION-01 | **Proposed / source repaired on stacked `.github#2289`; protected-main integration pending** | GitHub's native concurrency contract replaces an existing pending run under default `queue: single`. [RED `17be694a`](https://github.com/ContextualWisdomLab/.github/commit/17be694aaff421f8b48aa24250aeedd8eb2d696c) established the missing pending-preservation contract; [GREEN `ce3a4d9f`](https://github.com/ContextualWisdomLab/.github/commit/ce3a4d9f0b93584de85a076fb314840d262d3b68) adopted `queue: max`. Concurrent RED `e2647c5b` then exposed tests without production exact-head cleanup; production repair [`739a34c0`](https://github.com/ContextualWisdomLab/.github/commit/739a34c07d56f331767e6200d5172c648d0e27cf), authority RED [`648674c9`](https://github.com/ContextualWisdomLab/.github/commit/648674c92f1016f5cf8420f75d9d8679ff2dc665), and GREEN [`406c7178`](https://github.com/ContextualWisdomLab/.github/commit/406c7178974c3b887694a229a59c66a02e0810dd) bind cleanup to associated PR `head.sha`, not `pull_request_target` run `.head_sha`. Ordinary two-parent stack [`873a35f4`](https://github.com/ContextualWisdomLab/.github/commit/873a35f45c9c3b25f72797b25b6bbe98051d0f3d) preserves #2289 and canonical #2283 histories. Exact remote verification: static contracts 14/14, jq synchronize/closed fixtures 2/2, Python compile 2/2, YAML parse 1/1, cleanup Bash syntax 1/1. | Central `.github` owns scheduler concurrency; #2289 is stacked on #2283 rather than acting as a divergent writer. Same-head events retain native FIFO admission, successor heads enter a distinct group, and metadata-only cleanup revalidates live repository/PR/head before retiring predecessor runs. Completion requires prerequisite #2283 integration, fresh exact-head hosted Checks, no actionable review, qualifying independent approval, and ordinary protected-main merge. | +| CONTROL-SCHEDULER-PENDING-PRESERVATION-01 | **Proposed / source repaired on stacked `.github#2289`; protected-main integration pending** | GitHub's native concurrency contract replaces an existing pending run under default `queue: single`. [RED `17be694a`](https://github.com/ContextualWisdomLab/.github/commit/17be694aaff421f8b48aa24250aeedd8eb2d696c) established the missing pending-preservation contract; [GREEN `ce3a4d9f`](https://github.com/ContextualWisdomLab/.github/commit/ce3a4d9f0b93584de85a076fb314840d262d3b68) adopted `queue: max`. Concurrent RED `e2647c5b` then exposed tests without production exact-head cleanup; production repair [`739a34c0`](https://github.com/ContextualWisdomLab/.github/commit/739a34c07d56f331767e6200d5172c648d0e27cf), authority RED [`648674c9`](https://github.com/ContextualWisdomLab/.github/commit/648674c92f1016f5cf8420f75d9d8679ff2dc665), and GREEN [`406c7178`](https://github.com/ContextualWisdomLab/.github/commit/406c7178974c3b887694a229a59c66a02e0810dd) bind cleanup to associated PR `head.sha`, not `pull_request_target` run `.head_sha`. Ordinary two-parent stack [`873a35f4`](https://github.com/ContextualWisdomLab/.github/commit/873a35f45c9c3b25f72797b25b6bbe98051d0f3d) preserves #2289 and canonical #2283 histories. Exact remote verification: static contracts 14/14, jq synchronize/closed fixtures 2/2, Python compile 2/2, YAML parse 1/1, cleanup Bash syntax 1/1. Cancellation-verification RED at `406c7178` failed all three executable regressions (post-selection live-head revalidation, accepted-but-nonterminal cancellation, and asynchronous terminal proof); GREEN [`8067fb65`](https://github.com/ContextualWisdomLab/.github/commit/8067fb65daa6b01265f3c0e011ffd83b7f439273), tree `004a1713`, passes those regressions 3/3 and the affected scheduler contracts 6/6 under both default and `GITHUB_ACTIONS=true` environments. Hosted exact-head Checks remain pending. | Central `.github` owns scheduler concurrency; #2289 is stacked on #2283 rather than acting as a divergent writer. Same-head events retain native FIFO admission, successor heads enter a distinct group, and metadata-only cleanup revalidates live repository/PR/head before retiring predecessor runs. Completion requires prerequisite #2283 integration, fresh exact-head hosted Checks, no actionable review, qualifying independent approval, and ordinary protected-main merge. | ### 2026-09-13 current-head incident delta From 2a81604d1be7b015d3675fa847466edb8f5101f7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:24:35 +0900 Subject: [PATCH 13/16] test(scheduler): reject stale targeted-dispatch head --- tests/test_opencode_workflow_shell_syntax.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_opencode_workflow_shell_syntax.py b/tests/test_opencode_workflow_shell_syntax.py index b0a672b1a2..487fb5f31a 100644 --- a/tests/test_opencode_workflow_shell_syntax.py +++ b/tests/test_opencode_workflow_shell_syntax.py @@ -208,6 +208,7 @@ def test_merge_scheduler_targeted_dispatch_validates_live_exact_pr(tmp_path): "DEFAULT_BRANCH": "main", "TARGET_REPOSITORY_INPUT": "ContextualWisdomLab/naruon", "TARGET_PR_NUMBER": "1179", + "TARGET_HEAD_SHA_INPUT": "4afd4af7ad343660356791873d940aa2846f40c2", "TARGET_BASE_BRANCH_INPUT": "develop", "ALLOWED_TARGET_REPOSITORIES": ( "ContextualWisdomLab/.github, ContextualWisdomLab/naruon" @@ -248,6 +249,23 @@ def test_merge_scheduler_targeted_dispatch_validates_live_exact_pr(tmp_path): assert "absent from the configured exact allowlist" in rejected.stdout assert not output.exists() + stale_head_env = { + **env, + "TARGET_HEAD_SHA_INPUT": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + } + stale_head = subprocess.run( + [bash], + input=script, + text=True, + capture_output=True, + check=False, + env=stale_head_env, + ) + + assert stale_head.returncode == 1 + assert "head does not match the live PR" in stale_head.stdout + assert not output.exists() + output.unlink(missing_ok=True) cross_repo_pull = { **pull, From 4767b64be35455fc7b36d2a656f014929343f456 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:25:20 +0900 Subject: [PATCH 14/16] fix(scheduler): bind targeted dispatch to live head --- .github/workflows/pr-review-merge-scheduler.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-review-merge-scheduler.yml b/.github/workflows/pr-review-merge-scheduler.yml index d2fbc1018a..6e8e01a469 100644 --- a/.github/workflows/pr-review-merge-scheduler.yml +++ b/.github/workflows/pr-review-merge-scheduler.yml @@ -351,6 +351,7 @@ jobs: GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || steps.scheduler_app_token.outputs.token || github.token }} TARGET_REPOSITORY_INPUT: ${{ github.event.client_payload.target_repository || '' }} TARGET_PR_NUMBER: ${{ github.event.client_payload.pr_number || '' }} + TARGET_HEAD_SHA_INPUT: ${{ github.event.client_payload.pr_head_sha || '' }} TARGET_BASE_BRANCH_INPUT: ${{ github.event.client_payload.base_branch || '' }} ALLOWED_TARGET_REPOSITORIES: ${{ vars.OPENCODE_REPOSITORY_DISPATCH_TARGETS }} run: | @@ -370,8 +371,9 @@ jobs: exit 1 fi if ! [[ "$TARGET_REPOSITORY_INPUT" =~ ^ContextualWisdomLab/[A-Za-z0-9_.-]+$ ]] || - ! [[ "$TARGET_PR_NUMBER" =~ ^[1-9][0-9]*$ ]]; then - printf '::error::Targeted scheduler dispatch rejected an invalid repository or pull request number. target=%s pr=%s\n' "${TARGET_REPOSITORY_INPUT:-}" "${TARGET_PR_NUMBER:-}" + ! [[ "$TARGET_PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || + ! [[ "$TARGET_HEAD_SHA_INPUT" =~ ^[0-9a-fA-F]{40}$ ]]; then + printf '::error::Targeted scheduler dispatch rejected invalid repository, pull request, or head identity. target=%s pr=%s head=%s\n' "${TARGET_REPOSITORY_INPUT:-}" "${TARGET_PR_NUMBER:-}" "${TARGET_HEAD_SHA_INPUT:-}" exit 1 fi @@ -413,6 +415,10 @@ jobs: printf '::error::Targeted scheduler dispatch base branch does not match the live PR. supplied=%s live=%s\n' "$TARGET_BASE_BRANCH_INPUT" "$live_base_branch" exit 1 fi + if [ "${TARGET_HEAD_SHA_INPUT,,}" != "${live_head_sha,,}" ]; then + printf '::error::Targeted scheduler dispatch head does not match the live PR. supplied=%s live=%s\n' "$TARGET_HEAD_SHA_INPUT" "$live_head_sha" + exit 1 + fi { printf 'repository=%s\n' "$TARGET_REPOSITORY_INPUT" From 95fa1d676f2e5fa1428b99aaa30120fbfa7ad9af Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:26:20 +0900 Subject: [PATCH 15/16] docs(gap): bind targeted-dispatch head proof --- docs/product-technical-gap-baseline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index fcb05d6bcb..2b071cba41 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -11,7 +11,7 @@ | Gap ID | 상태 | exact-head evidence | causal owner / next gate | |---|---|---|---| -| CONTROL-SCHEDULER-PENDING-PRESERVATION-01 | **Proposed / source repaired on stacked `.github#2289`; protected-main integration pending** | GitHub's native concurrency contract replaces an existing pending run under default `queue: single`. [RED `17be694a`](https://github.com/ContextualWisdomLab/.github/commit/17be694aaff421f8b48aa24250aeedd8eb2d696c) established the missing pending-preservation contract; [GREEN `ce3a4d9f`](https://github.com/ContextualWisdomLab/.github/commit/ce3a4d9f0b93584de85a076fb314840d262d3b68) adopted `queue: max`. Concurrent RED `e2647c5b` then exposed tests without production exact-head cleanup; production repair [`739a34c0`](https://github.com/ContextualWisdomLab/.github/commit/739a34c07d56f331767e6200d5172c648d0e27cf), authority RED [`648674c9`](https://github.com/ContextualWisdomLab/.github/commit/648674c92f1016f5cf8420f75d9d8679ff2dc665), and GREEN [`406c7178`](https://github.com/ContextualWisdomLab/.github/commit/406c7178974c3b887694a229a59c66a02e0810dd) bind cleanup to associated PR `head.sha`, not `pull_request_target` run `.head_sha`. Ordinary two-parent stack [`873a35f4`](https://github.com/ContextualWisdomLab/.github/commit/873a35f45c9c3b25f72797b25b6bbe98051d0f3d) preserves #2289 and canonical #2283 histories. Exact remote verification: static contracts 14/14, jq synchronize/closed fixtures 2/2, Python compile 2/2, YAML parse 1/1, cleanup Bash syntax 1/1. Cancellation-verification RED at `406c7178` failed all three executable regressions (post-selection live-head revalidation, accepted-but-nonterminal cancellation, and asynchronous terminal proof); GREEN [`8067fb65`](https://github.com/ContextualWisdomLab/.github/commit/8067fb65daa6b01265f3c0e011ffd83b7f439273), tree `004a1713`, passes those regressions 3/3 and the affected scheduler contracts 6/6 under both default and `GITHUB_ACTIONS=true` environments. Hosted exact-head Checks remain pending. | Central `.github` owns scheduler concurrency; #2289 is stacked on #2283 rather than acting as a divergent writer. Same-head events retain native FIFO admission, successor heads enter a distinct group, and metadata-only cleanup revalidates live repository/PR/head before retiring predecessor runs. Completion requires prerequisite #2283 integration, fresh exact-head hosted Checks, no actionable review, qualifying independent approval, and ordinary protected-main merge. | +| CONTROL-SCHEDULER-PENDING-PRESERVATION-01 | **Proposed / source repaired on stacked `.github#2289`; protected-main integration pending** | GitHub's native concurrency contract replaces an existing pending run under default `queue: single`. [RED `17be694a`](https://github.com/ContextualWisdomLab/.github/commit/17be694aaff421f8b48aa24250aeedd8eb2d696c) established the missing pending-preservation contract; [GREEN `ce3a4d9f`](https://github.com/ContextualWisdomLab/.github/commit/ce3a4d9f0b93584de85a076fb314840d262d3b68) adopted `queue: max`. Concurrent RED `e2647c5b` then exposed tests without production exact-head cleanup; production repair [`739a34c0`](https://github.com/ContextualWisdomLab/.github/commit/739a34c07d56f331767e6200d5172c648d0e27cf), authority RED [`648674c9`](https://github.com/ContextualWisdomLab/.github/commit/648674c92f1016f5cf8420f75d9d8679ff2dc665), and GREEN [`406c7178`](https://github.com/ContextualWisdomLab/.github/commit/406c7178974c3b887694a229a59c66a02e0810dd) bind cleanup to associated PR `head.sha`, not `pull_request_target` run `.head_sha`. Ordinary two-parent stack [`873a35f4`](https://github.com/ContextualWisdomLab/.github/commit/873a35f45c9c3b25f72797b25b6bbe98051d0f3d) preserves #2289 and canonical #2283 histories. Exact remote verification: static contracts 14/14, jq synchronize/closed fixtures 2/2, Python compile 2/2, YAML parse 1/1, cleanup Bash syntax 1/1. Cancellation-verification RED at `406c7178` failed all three executable regressions (post-selection live-head revalidation, accepted-but-nonterminal cancellation, and asynchronous terminal proof); GREEN [`8067fb65`](https://github.com/ContextualWisdomLab/.github/commit/8067fb65daa6b01265f3c0e011ffd83b7f439273), tree `004a1713`, passes those regressions 3/3 and the affected scheduler contracts 6/6 under both default and `GITHUB_ACTIONS=true` environments. Targeted cross-repository dispatch still accepted a caller-supplied `pr_head_sha` for concurrency without comparing it to the live pull request; executable RED [`2a81604d`](https://github.com/ContextualWisdomLab/.github/commit/2a81604d1be7b015d3675fa847466edb8f5101f7) rejects a stale value, and GREEN [`4767b64b`](https://github.com/ContextualWisdomLab/.github/commit/4767b64be35455fc7b36d2a656f014929343f456) requires a 40-hex identity and exact case-insensitive live-head match before scheduling. Hosted exact-head Checks remain pending. | Central `.github` owns scheduler concurrency; #2289 is stacked on #2283 rather than acting as a divergent writer. Same-head events retain native FIFO admission, successor heads enter a distinct group, and metadata-only cleanup revalidates live repository/PR/head before retiring predecessor runs. Completion requires prerequisite #2283 integration, fresh exact-head hosted Checks, no actionable review, qualifying independent approval, and ordinary protected-main merge. | ### 2026-09-13 current-head incident delta From 021ffb2bb6914f810f192cc69980ecc1245c79d0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 20 Sep 2026 06:36:59 +0900 Subject: [PATCH 16/16] test(scheduler): align layered concurrency oracles --- ...urrent_head_coalescer_self_cancellation.py | 24 ++++++++++++------ tests/test_opencode_agent_contract.py | Bin 146935 -> 120059 bytes 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/test_current_head_coalescer_self_cancellation.py b/tests/test_current_head_coalescer_self_cancellation.py index e49193d4df..59662174c0 100644 --- a/tests/test_current_head_coalescer_self_cancellation.py +++ b/tests/test_current_head_coalescer_self_cancellation.py @@ -10,7 +10,7 @@ def test_current_head_coalescer_shares_pr_scoped_scheduler_admission() -> None: - """The integrated step reuses PR-scoped scheduler admission and its runner.""" + """Exact-head admission and metadata cleanup share the scheduler boundary.""" workflow_text = WORKFLOW_PATH.read_text(encoding="utf-8") coalescer = workflow_text.split("\n scan-pr-queue:\n", 1)[1] concurrency_block = workflow_text.split("\nconcurrency:\n", 1)[1].split( @@ -24,11 +24,19 @@ def test_current_head_coalescer_shares_pr_scoped_scheduler_admission() -> None: assert "Retire redundant queued exact-head runs" in coalescer assert "github.repository == 'ContextualWisdomLab/.github'" in coalescer - assert "github.event.pull_request.head.sha" not in concurrency_block + assert "github.event.pull_request.head.sha" in concurrency_block assert "github.event.pull_request.number" in concurrency_block - assert any( - line.startswith("cancel-in-progress:") - and "github.event_name == 'pull_request_target'" in line - for line in active_lines - ) - assert "queue: max" not in workflow_text + assert "github.event.client_payload.pr_head_sha" in concurrency_block + assert "queue: max" in active_lines + assert not any(line.startswith("cancel-in-progress:") for line in active_lines) + + cleanup = workflow_text.split( + "\n cancel-superseded-pr-runs:\n", 1 + )[1].split("\n scan-pr-queue:\n", 1)[0] + assert "actions: write" in cleanup + assert "actions/checkout" not in cleanup + assert "TARGET_REPOSITORY:" in cleanup + assert "TARGET_PR_NUMBER:" in cleanup + assert "TARGET_PR_HEAD_SHA:" in cleanup + assert "live_target_matches" in cleanup + assert 'actions/runs/${run_id}/force-cancel' in cleanup diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index 5a41cb7cdc140ea69e7bb02d7560e2c47313e8eb..4351b42a62224ada0af21cb1b8e56247bc5df1e6 100644 GIT binary patch literal 120059 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 literal 146935 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 Fe*r0A)aU>J