From e283e7580dc8ca23e8f753942348f8d949b13dd4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 22:22:18 +0900 Subject: [PATCH 1/3] test(scheduler): require hourly review-repair cadence --- ..._review_fix_scheduler_workflow_contract.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/test_pr_review_fix_scheduler_workflow_contract.py diff --git a/tests/test_pr_review_fix_scheduler_workflow_contract.py b/tests/test_pr_review_fix_scheduler_workflow_contract.py new file mode 100644 index 000000000..fe04b37e8 --- /dev/null +++ b/tests/test_pr_review_fix_scheduler_workflow_contract.py @@ -0,0 +1,31 @@ +"""Workflow-level contract for the bounded PR review repair scheduler.""" + +from pathlib import Path + + +WORKFLOW = Path(".github/workflows/pr-review-fix-scheduler.yml") + + +def workflow_text() -> str: + """Return the canonical workflow source used by the scheduler.""" + + return WORKFLOW.read_text(encoding="utf-8") + + +def test_review_fix_scheduler_runs_once_per_hour() -> None: + """Every open-PR queue receives a fixed hourly repair opportunity.""" + + text = workflow_text() + assert 'cron: "23 * * * *"' in text + assert 'cron: "23 */2 * * *"' not in text + + +def test_same_head_autofix_retry_default_is_one_hour() -> None: + """A failed or incomplete repair can be retried on the next hourly sweep.""" + + text = workflow_text() + retry_block = text.split("retry_hours:", maxsplit=1)[1].split( + "autofix_workflow:", maxsplit=1 + )[0] + assert 'default: "1"' in retry_block + assert "inputs.retry_hours || '1'" in text From 09ca68520988fd4a3d7ead7cfd7a3b57bd308f62 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 22:22:47 +0900 Subject: [PATCH 2/3] fix(scheduler): run bounded review repairs hourly --- .github/workflows/pr-review-fix-scheduler.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-review-fix-scheduler.yml b/.github/workflows/pr-review-fix-scheduler.yml index cc7875bc8..c1ac1572b 100644 --- a/.github/workflows/pr-review-fix-scheduler.yml +++ b/.github/workflows/pr-review-fix-scheduler.yml @@ -26,7 +26,7 @@ on: retry_hours: description: Minimum hours before redispatching autofix for the same head required: false - default: "24" + default: "1" type: string autofix_workflow: description: Autofix workflow file to dispatch @@ -51,7 +51,10 @@ on: repository_dispatch: types: [pr-review-fix-scheduler] schedule: - - cron: "23 */2 * * *" + # One bounded repair dispatch per hourly sweep. The head-scoped marker and + # single-flight concurrency contract prevent duplicate work while allowing + # a failed or incomplete repair to be retried on the next hourly cycle. + - cron: "23 * * * *" concurrency: group: central-pr-review-fix-scheduler-${{ github.event.client_payload.target_repository || inputs.target_repository || vars.PR_REVIEW_FIX_TARGET_REPOSITORY || github.repository }} @@ -80,7 +83,7 @@ jobs: DRY_RUN: ${{ github.event.client_payload.dry_run == true || github.event.client_payload.dry_run == 'true' || inputs.dry_run == true }} MAX_PRS: ${{ github.event.client_payload.max_prs || inputs.max_prs || '50' }} MAX_DISPATCHES: ${{ github.event.client_payload.max_dispatches || inputs.max_dispatches || '1' }} - RETRY_HOURS: ${{ github.event.client_payload.retry_hours || inputs.retry_hours || '24' }} + RETRY_HOURS: ${{ github.event.client_payload.retry_hours || inputs.retry_hours || '1' }} AUTOFIX_WORKFLOW: pr-review-autofix.yml AUTOFIX_REPOSITORY: ContextualWisdomLab/.github CANONICAL_REF: main From 16a9916af8e5e11182c837a1c1b950300fead99b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 22:23:47 +0900 Subject: [PATCH 3/3] docs(changelog): record hourly repair cadence --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf30091dd..129f6d881 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Semantic Versioning where the repository publishes a release. ### Fixed +- Changed the bounded review-feedback repair scheduler from every two hours to every hour and made its exact-head redispatch default one hour, while retaining one-dispatch limits, head-scoped markers, and single-flight concurrency. - Bounded the Strix quality self-test's deterministic timeout fixtures to 3-second process and 5-second fake-sleep budgets so exact-head policy evidence completes inside the existing job limit without changing production Strix scanner timeouts, providers, credentials, or review semantics. - Allowed commas and ASCII parentheses in the bounded Strix changed-file path policy so legal tracked Packrat fixtures can receive exact-head security analysis, while rejecting raw `..` components before normalization and keeping controls, backslashes, whitespace ambiguity, and shell punctuation fail-closed. - Bound each review-agent invocation key to the wrapper's complete canonical payload, including the base branch and requesting actor; altered fields with a valid-format key now fail before durable-leader election or forwarding, and wrapper write permission is job-scoped.