From 08a16caa4fdb0d0d86c44bb8cd7aed611beaab7b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 13:16:59 +0900 Subject: [PATCH 1/2] test(scheduler): reproduce central target-inventory waste --- tests/test_pr_review_merge_scheduler.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/test_pr_review_merge_scheduler.py b/tests/test_pr_review_merge_scheduler.py index 0e2aba2330..7e10cf555c 100644 --- a/tests/test_pr_review_merge_scheduler.py +++ b/tests/test_pr_review_merge_scheduler.py @@ -10866,3 +10866,24 @@ def test_withheld_mutation_guidance_uses_recorded_reason_after_environment_chang assert "workflow GITHUB_TOKEN" in "\n".join( sched.head_mutation_credential_upgrade_summary([decision]) ) + + +def test_central_dispatch_skips_non_authoritative_target_actions_inventory( + monkeypatch, +): + """Central review dispatch must not spend App quota on target old-head runs.""" + monkeypatch.setenv( + "SCHEDULER_REQUIRED_WORKFLOW_REPOSITORY", + "ContextualWisdomLab/.github", + ) + monkeypatch.setattr( + sched, + "cancel_stale_pr_runs", + lambda *args, **kwargs: pytest.fail( + "central dispatch must not enumerate target Actions runs" + ), + ) + + decision = inspect(make_pr(baseRefName="feature-base"), trigger_reviews=False) + + assert decision.action == "skip" From a42ab0035b953241ad81f01414efad555287540c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 13:17:30 +0900 Subject: [PATCH 2/2] fix(scheduler): skip central target Actions inventory --- CHANGELOG.md | 5 +++ ...ral-review-target-inventory-suppression.md | 35 +++++++++++++++++++ docs/product-technical-gap-baseline.md | 15 ++++++++ scripts/ci/pr_review_merge_scheduler_core.py | 6 +++- 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 docs/doctoring/central-review-target-inventory-suppression.md diff --git a/CHANGELOG.md b/CHANGELOG.md index df6ee0c9b9..c47c4bda6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -162,6 +162,11 @@ ## Proposed +- Skip target-repository old-head Actions inventory when review execution is + centralized. Same-repository stale-run cleanup remains enabled; central + review lifecycle is handled in the configured dispatch repository, avoiding + an unauthoritative API read that can exhaust the cross-repository App quota. + - Run Python Security and Agent Review Runtime Quality CI for stacked pull requests by removing their pull-request base-branch filters. Extend the permanent stacked-workflow contract so all four owner review workflows diff --git a/docs/doctoring/central-review-target-inventory-suppression.md b/docs/doctoring/central-review-target-inventory-suppression.md new file mode 100644 index 0000000000..ecee9edc1a --- /dev/null +++ b/docs/doctoring/central-review-target-inventory-suppression.md @@ -0,0 +1,35 @@ +# Central review target-inventory suppression + +Decision date: **2026-09-07** + +## Problem + +When the trusted reviewer is hosted centrally, target-repository old-head +workflow runs are not the authority for the central current-head verdict. +Enumerating those target runs before dispatch consumes the cross-repository +Actions credential and can exhaust its App quota before useful review work +starts. + +## Decision + +Compare the configured review dispatch repository with the target repository. +If they differ, do not enumerate or cancel target old-head runs from this +decision path. The central reviewer owns its own run lifecycle in the dispatch +repository. If they are the same repository, retain existing stale-run cleanup. + +## Failure scenes + +- Central review of a target repository: no target Actions inventory read occurs. +- Same-repository review: stale old-head runs are still cancelled. +- Repository name casing differs: case-insensitive identity prevents accidental + cross-repository classification. + +## Evidence and follow-up + +RED commit: `08a16caa4fdb0d0d86c44bb8cd7aed611beaab7b`. +Fresh exact-head hosted checks and independent review remain required. + +## Reference + +GitHub. (2026). *REST API endpoints for workflow runs*. +https://docs.github.com/en/rest/actions/workflow-runs diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 1cae019f9a..ded5f53046 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -3401,3 +3401,18 @@ same name in another file can carry the opposite safety property.** workflows at exact head `e2204eeb1ec2789ff791036140ba1672995d25f5`; RED commit `890bac2f69ff1a51f774ddf5d6c5d819afed4ac9`; fresh exact-head hosted checks remain required. + + +### Central review target-inventory suppression + +- **Status:** Proposed +- **Owner:** `ContextualWisdomLab/.github` +- **Problem:** Before dispatching a central current-head review, the scheduler + enumerated target-repository old-head Actions runs that are not central + admission authority, spending the cross-repository App quota. +- **Action:** Skip only that target enumeration when the configured review + dispatch repository differs from the target; preserve same-repository + stale-run cleanup. +- **Evidence:** RED commit + `08a16caa4fdb0d0d86c44bb8cd7aed611beaab7b`; fresh exact-head hosted checks + remain required before integration. diff --git a/scripts/ci/pr_review_merge_scheduler_core.py b/scripts/ci/pr_review_merge_scheduler_core.py index 9adcac3e37..5034ebd29e 100644 --- a/scripts/ci/pr_review_merge_scheduler_core.py +++ b/scripts/ci/pr_review_merge_scheduler_core.py @@ -4270,7 +4270,11 @@ def inspect_pr( pass run(["gh", "pr", "close", str(number), "--repo", repo]) return Decision(number, "close_empty", "base 대비 실제 변경 0건") - cancel_stale_pr_runs(repo, pr, dry_run=dry_run) + # A central reviewer owns run lifecycle in its dispatch repository. + # Target old-head runs are not admission authority, and enumerating them + # spends the cross-repository installation quota before current-head review. + if repository_dispatch_target(repo).casefold() == repo.casefold(): + cancel_stale_pr_runs(repo, pr, dry_run=dry_run) if base_ref != base_branch: # Stacked/cascade PR (base is another feature branch). Org required # workflows are only injected for default-branch-target PRs, so these