From 64bf199b468ecf271819c7739e9ce109822268d0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 19:06:16 +0900 Subject: [PATCH 1/3] test(scheduler): isolate remaining CI-only recovery calls --- CHANGELOG.md | 5 +++++ tests/test_pr_review_merge_scheduler.py | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a1552edf4..efac045047 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ - Raised `hourly-review-repair.yml`'s discovery ceiling from 50 to 200 while rotating deterministic 50-PR deep-inspection windows by hourly run number. The scheduler hydrates only the selected window and stops immediately after its single dispatch, preserving access to newer PRs without quadrupling expensive review/check/comment work. See `docs/doctoring/hourly-review-repair-single-file-consolidation.md`'s 2026-09-03 follow-up. ## [Unreleased] +- Complete the scheduler test isolation introduced by #1896 for the two + remaining fixtures that invoke `inspect_pr(..., dry_run=False)` or + `main(...)`. Both now stub the environment-gated startup-failure recovery + owner, so `GITHUB_ACTIONS=true` exercises the production guard without + issuing real GitHub calls or rejecting synthetic fixture SHAs. - **Fix current-main contract drift that blocked the unscoped `agent-review-runtime-quality-ci.yml` "Verify scheduler and contextual-orchestrator review-repair contracts" step (which discovers and diff --git a/tests/test_pr_review_merge_scheduler.py b/tests/test_pr_review_merge_scheduler.py index b821fe1ee3..1e5848aac3 100644 --- a/tests/test_pr_review_merge_scheduler.py +++ b/tests/test_pr_review_merge_scheduler.py @@ -252,6 +252,11 @@ def fake_run(args): }, ) monkeypatch.setattr(sched, "run", fake_run) + monkeypatch.setattr( + sched, + "recover_current_head_startup_failures", + lambda repo, pr, *, dry_run: [], + ) decision = inspect(candidate, dry_run=False) @@ -9010,6 +9015,11 @@ def test_main_reconciles_the_durable_admission_gate_when_a_state_path_is_given( lambda repo, workflow, pr, dry_run: dispatched.append(pr["number"]), ) monkeypatch.setattr(sched, "cancel_stale_pr_runs", lambda repo, pr, dry_run: []) + monkeypatch.setattr( + sched, + "recover_current_head_startup_failures", + lambda repo, pr, *, dry_run: [], + ) state_path = tmp_path / "admission.json" assert ( From 0996fdfa605b64397cc760445512df2c163e5c3a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 19:37:21 +0900 Subject: [PATCH 2/3] =?UTF-8?q?fix(ci):=20=EC=8A=A4=EC=BC=80=EC=A4=84?= =?UTF-8?q?=EB=9F=AC=20=EB=B3=80=EA=B2=BD=EC=9D=98=20=ED=92=88=EC=A7=88=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=EB=88=84=EB=9D=BD=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Codex --- .../agent-review-runtime-quality-ci.yml | 12 +++++- CHANGELOG.md | 5 +++ ...nt_review_runtime_quality_consolidation.py | 41 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/.github/workflows/agent-review-runtime-quality-ci.yml b/.github/workflows/agent-review-runtime-quality-ci.yml index fd54b694a1..fec8abd7f0 100644 --- a/.github/workflows/agent-review-runtime-quality-ci.yml +++ b/.github/workflows/agent-review-runtime-quality-ci.yml @@ -32,6 +32,9 @@ on: - "tests/test_strix_quality_timeout_fixture_budget.py" - "tests/test_agent_review_runtime_quality_consolidation.py" - ".github/workflows/pr-review-merge-scheduler.yml" + - "scripts/ci/pr_review_merge_scheduler.py" + - "scripts/ci/pr_review_merge_scheduler_core.py" + - "tests/test_pr_review_merge_scheduler.py" - "scripts/ci/current_head_run_coalescer.py" - ".github/workflows/pr-review-fix-scheduler.yml" - "scripts/ci/pr_review_fix_scheduler.py" @@ -203,12 +206,19 @@ jobs: noema_suite=true opencode_suite=true ;; - .github/workflows/pr-review-merge-scheduler.yml|\ + .github/workflows/pr-review-merge-scheduler.yml) + queue_suite=true + review_repair_suite=true + ;; scripts/ci/current_head_run_coalescer.py) queue_suite=true ;; .github/workflows/pr-review-fix-scheduler.yml|\ scripts/ci/pr_review_fix_scheduler.py|\ + scripts/ci/pr_review_merge_scheduler.py|\ + scripts/ci/pr_review_merge_scheduler_core.py|\ + tests/test_pr_review_merge_scheduler.py|\ + tests/test_agent_review_runtime_quality_consolidation.py|\ .github/workflows/pr-review-autofix.yml|\ .github/workflows/hourly-review-repair.yml|\ scripts/ci/pr_review_conflict_scope.py|\ diff --git a/CHANGELOG.md b/CHANGELOG.md index efac045047..7eec3c4a58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ - Raised `hourly-review-repair.yml`'s discovery ceiling from 50 to 200 while rotating deterministic 50-PR deep-inspection windows by hourly run number. The scheduler hydrates only the selected window and stops immediately after its single dispatch, preserving access to newer PRs without quadrupling expensive review/check/comment work. See `docs/doctoring/hourly-review-repair-single-file-consolidation.md`'s 2026-09-03 follow-up. ## [Unreleased] +- Include merge-scheduler entrypoint, core, and regression-test changes in + the existing runtime-quality workflow's trigger and suite selector. Scheduler + workflow edits retain queue checks and also select the full review-repair + suite, including edits to the selector's own regression tests. Changelog-only + edits still do not start this runner; no job is added. - Complete the scheduler test isolation introduced by #1896 for the two remaining fixtures that invoke `inspect_pr(..., dry_run=False)` or `main(...)`. Both now stub the environment-gated startup-failure recovery diff --git a/tests/test_agent_review_runtime_quality_consolidation.py b/tests/test_agent_review_runtime_quality_consolidation.py index dfa6342c0d..d80bd45319 100644 --- a/tests/test_agent_review_runtime_quality_consolidation.py +++ b/tests/test_agent_review_runtime_quality_consolidation.py @@ -3,8 +3,11 @@ from __future__ import annotations import re +import subprocess from pathlib import Path +import pytest + REPOSITORY_ROOT = Path(__file__).resolve().parents[1] WORKFLOW_PATH = ( @@ -143,6 +146,44 @@ def test_review_repair_suite_is_selected_and_conditionally_executed() -> None: assert workflow.count("runs-on:") == 1 +@pytest.mark.parametrize( + ("changed_path", "should_run"), + ( + ("scripts/ci/pr_review_merge_scheduler.py", True), + ("scripts/ci/pr_review_merge_scheduler_core.py", True), + ("tests/test_pr_review_merge_scheduler.py", True), + ("tests/test_agent_review_runtime_quality_consolidation.py", True), + (".github/workflows/pr-review-merge-scheduler.yml", True), + ("CHANGELOG.md", False), + ), +) +def test_merge_scheduler_changes_start_and_select_contracts( + changed_path: str, should_run: bool +) -> None: + """Bind scheduler changes to both runner admission and the real selector.""" + workflow = _workflow_text() + trigger = workflow.split("on:\n", 1)[1].split("\nconcurrency:\n", 1)[0] + assert (f' - "{changed_path}"' in trigger) is should_run + + selector = workflow.split(' case "$changed_path" in\n', 1)[1].split( + " esac", 1 + )[0] + result = subprocess.run( + [ + "bash", "--noprofile", "--norc", "-e", "-o", "pipefail", "-c", + 'IFS= read -r changed_path\nreview_repair_suite=false\n' + 'case "$changed_path" in\n' + selector + + 'esac\nprintf "%s" "$review_repair_suite"\n', + ], + input=changed_path + "\n", + text=True, + capture_output=True, + check=True, + ) + assert result.stdout == str(should_run).lower() + assert result.stderr == "" + + def test_commercial_readiness_suite_is_selected_and_conditionally_executed() -> None: """Preserve the retired caller's coverage contract in the shared job.""" From f7f11af21a085725524be015460d03ed873700bb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 19:42:33 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix(ci):=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=A0=84=EC=B2=B4=20=EA=B2=80=EC=82=AC=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Codex --- .../agent-review-runtime-quality-ci.yml | 1 - CHANGELOG.md | 4 +-- ...nt_review_runtime_quality_consolidation.py | 28 +++++++++++-------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/.github/workflows/agent-review-runtime-quality-ci.yml b/.github/workflows/agent-review-runtime-quality-ci.yml index fec8abd7f0..3680da8778 100644 --- a/.github/workflows/agent-review-runtime-quality-ci.yml +++ b/.github/workflows/agent-review-runtime-quality-ci.yml @@ -218,7 +218,6 @@ jobs: scripts/ci/pr_review_merge_scheduler.py|\ scripts/ci/pr_review_merge_scheduler_core.py|\ tests/test_pr_review_merge_scheduler.py|\ - tests/test_agent_review_runtime_quality_consolidation.py|\ .github/workflows/pr-review-autofix.yml|\ .github/workflows/hourly-review-repair.yml|\ scripts/ci/pr_review_conflict_scope.py|\ diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eec3c4a58..06b3dba425 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,8 @@ - Include merge-scheduler entrypoint, core, and regression-test changes in the existing runtime-quality workflow's trigger and suite selector. Scheduler workflow edits retain queue checks and also select the full review-repair - suite, including edits to the selector's own regression tests. Changelog-only - edits still do not start this runner; no job is added. + suite. Selector-only test edits use the existing unconditional contract step; + changelog-only edits still do not start this runner. No job is added. - Complete the scheduler test isolation introduced by #1896 for the two remaining fixtures that invoke `inspect_pr(..., dry_run=False)` or `main(...)`. Both now stub the environment-gated startup-failure recovery diff --git a/tests/test_agent_review_runtime_quality_consolidation.py b/tests/test_agent_review_runtime_quality_consolidation.py index d80bd45319..b0c90eb707 100644 --- a/tests/test_agent_review_runtime_quality_consolidation.py +++ b/tests/test_agent_review_runtime_quality_consolidation.py @@ -73,6 +73,9 @@ def test_consolidated_workflow_materializes_one_runner_job() -> None: assert "workflow_dispatch:" not in workflow assert "gh api" not in workflow assert re.search(r"(?m)^[ \t]*sleep[ \t]+", workflow) is None + self_test_step = workflow.split("- name: Verify consolidated workflow contract", 1)[1] + assert "if:" not in self_test_step + assert "python -m pytest -q tests/test_agent_review_runtime_quality_consolidation.py" in self_test_step def test_changelog_only_edits_do_not_boot_the_consolidated_runner() -> None: @@ -147,23 +150,24 @@ def test_review_repair_suite_is_selected_and_conditionally_executed() -> None: @pytest.mark.parametrize( - ("changed_path", "should_run"), + ("changed_path", "starts_runner", "review_repair", "queue"), ( - ("scripts/ci/pr_review_merge_scheduler.py", True), - ("scripts/ci/pr_review_merge_scheduler_core.py", True), - ("tests/test_pr_review_merge_scheduler.py", True), - ("tests/test_agent_review_runtime_quality_consolidation.py", True), - (".github/workflows/pr-review-merge-scheduler.yml", True), - ("CHANGELOG.md", False), + ("scripts/ci/pr_review_merge_scheduler.py", True, True, False), + ("scripts/ci/pr_review_merge_scheduler_core.py", True, True, False), + ("tests/test_pr_review_merge_scheduler.py", True, True, False), + ("tests/test_agent_review_runtime_quality_consolidation.py", True, False, False), + (".github/workflows/pr-review-merge-scheduler.yml", True, True, True), + ("scripts/ci/current_head_run_coalescer.py", True, False, True), + ("CHANGELOG.md", False, False, False), ), ) def test_merge_scheduler_changes_start_and_select_contracts( - changed_path: str, should_run: bool + changed_path: str, starts_runner: bool, review_repair: bool, queue: bool ) -> None: """Bind scheduler changes to both runner admission and the real selector.""" workflow = _workflow_text() trigger = workflow.split("on:\n", 1)[1].split("\nconcurrency:\n", 1)[0] - assert (f' - "{changed_path}"' in trigger) is should_run + assert (f' - "{changed_path}"' in trigger) is starts_runner selector = workflow.split(' case "$changed_path" in\n', 1)[1].split( " esac", 1 @@ -171,16 +175,16 @@ def test_merge_scheduler_changes_start_and_select_contracts( result = subprocess.run( [ "bash", "--noprofile", "--norc", "-e", "-o", "pipefail", "-c", - 'IFS= read -r changed_path\nreview_repair_suite=false\n' + 'IFS= read -r changed_path\nreview_repair_suite=false\nqueue_suite=false\n' 'case "$changed_path" in\n' + selector - + 'esac\nprintf "%s" "$review_repair_suite"\n', + + 'esac\nprintf "%s,%s" "$review_repair_suite" "$queue_suite"\n', ], input=changed_path + "\n", text=True, capture_output=True, check=True, ) - assert result.stdout == str(should_run).lower() + assert result.stdout == f"{str(review_repair).lower()},{str(queue).lower()}" assert result.stderr == ""