Skip to content

ci: run central PR maintenance every hour - #738

Closed
seonghobae wants to merge 7 commits into
developfrom
chore/hourly-pr-maintenance
Closed

ci: run central PR maintenance every hour#738
seonghobae wants to merge 7 commits into
developfrom
chore/hourly-pr-maintenance

Conversation

@seonghobae

Copy link
Copy Markdown
Collaborator

What

Add a thin hourly caller that invokes the source-pinned central review-fix scheduler and then the central review-and-merge scheduler for BandScope's develop queue.

Why

Open PRs can become review-ready or check-ready after their last repository event. The central required scheduler already owns review and merge policy, but BandScope needs an explicit one-hour heartbeat for review feedback fixes and a deterministic follow-up merge pass.

Behavior

  • Run at minute 17 of every hour and through manual dispatch.
  • Inspect up to 50 open PRs for actionable review feedback.
  • Retry a given head after one hour and dispatch at most three autofix runs per cycle.
  • Re-request missing current-head reviews, update at most three behind branches, enable auto-merge, and merge only through normal protected-branch rules.
  • Keep central logic in ContextualWisdomLab/.github; BandScope contains only the reusable-workflow caller and contract tests.

Verification

  • Red phase: contract test failed because the hourly workflow did not exist.
  • Green phase: 3 passed for the focused workflow contract tests.
  • Central reusable workflows are pinned to full commit SHA 5983b41ace75040c1d81818171ca7d0f3653254e.
  • Caller permissions are the exact union required by the two reusable workflows; no admin or security-event write permission is granted.

Security Notes

  • Trust boundary: GitHub Actions reusable workflows, inherited organization/repository secrets, PR review state, branch updates, and normal merges.
  • Mitigations: immutable central workflow pins, bounded dispatch/update budgets, one-hour retry guard, no local merge shell commands, no review dismissal, no thread resolution, and no branch-protection bypass.
  • Scheduled execution becomes active only after this PR is reviewed and merged into the default branch.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@seonghobae, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 39 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a6de0ef7-b6a7-42c1-ba5d-140576c9853c

📥 Commits

Reviewing files that changed from the base of the PR and between acdbea6 and 166e5a1.

📒 Files selected for processing (3)
  • .github/workflows/hourly-pr-maintenance.yml
  • docs/workflow/pr-review-merge-scheduler.md
  • services/analysis-engine/tests/test_hourly_pr_maintenance_workflow.py

Comment @coderabbitai help to get the list of available commands.

@seonghobae
seonghobae enabled auto-merge (squash) August 3, 2026 03:14

Copy link
Copy Markdown
Collaborator Author

Maintainer review found that the reusable workflow was SHA-pinned but the review-fix job still checked out its Python implementation from mutable main. The caller now passes the same immutable 40-character revision as canonical_ref, and the contract/documentation explicitly prevent regression to canonical_ref: main.

Independent verification: 3 focused tests passed, Python line coverage 100%, docstrings 5/5, and the caller retains the exact permission union with no admin/ruleset bypass path. @coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Candidate workflow, test, and documentation files =='
fd -t f . | rg -i '(^|/)(\.github/workflows/.*|.*(workflow|scheduler|review.?fix|merge|contract|ci).*\.(ya?ml|py|md))$' | sort

printf '%s\n' '== References to canonical_ref and central workflow pins =='
rg -n -C 4 --glob '*.{yml,yaml,py,md}' \
  '(canonical_ref|ContextualWisdomLab/\.github/\.github/workflows|5983b41ace75040c1d81818171ca7d0f3653254e)' \
  . || true

Length of output: 7389


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Hourly maintenance workflow candidates, including hidden paths =='
find .github -type f \( -name '*.yml' -o -name '*.yaml' \) -print 2>/dev/null | sort
find . -path '*/.github/workflows/*' -type f \( -name '*.yml' -o -name '*.yaml' \) -print 2>/dev/null | sort

printf '%s\n' '== Python test structure =='
ast-grep outline services/analysis-engine/tests/test_hourly_pr_maintenance_workflow.py --items all

printf '%s\n' '== Changed files in this PR =='
git diff --name-status "$(git merge-base HEAD origin/develop)" HEAD 2>/dev/null || git diff --name-status HEAD~1 HEAD

printf '%s\n' '== Full contract test =='
cat -n services/analysis-engine/tests/test_hourly_pr_maintenance_workflow.py

printf '%s\n' '== Relevant scheduler documentation =='
sed -n '1,110p' docs/workflow/pr-review-merge-scheduler.md

Length of output: 11636


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Hourly caller structure =='
ast-grep outline .github/workflows/hourly-pr-maintenance.yml --items all || true

printf '%s\n' '== Hourly caller =='
cat -n .github/workflows/hourly-pr-maintenance.yml

printf '%s\n' '== PR diff against develop =='
base="$(git merge-base HEAD origin/develop 2>/dev/null || true)"
if [ -n "$base" ]; then
  git diff --check "$base" HEAD
  git diff --unified=80 "$base" HEAD -- \
    .github/workflows/hourly-pr-maintenance.yml \
    services/analysis-engine/tests/test_hourly_pr_maintenance_workflow.py \
    docs/workflow/pr-review-merge-scheduler.md
else
  git diff --check HEAD~1 HEAD
  git diff --unified=80 HEAD~1 HEAD -- \
    .github/workflows/hourly-pr-maintenance.yml \
    services/analysis-engine/tests/test_hourly_pr_maintenance_workflow.py \
    docs/workflow/pr-review-merge-scheduler.md
fi

printf '%s\n' '== Reusable-workflow caller conventions =='
rg -n -C 3 --glob '.github/workflows/*.{yml,yaml}' \
  '^(permissions:|workflow_dispatch:|[[:space:]]*uses: .*\.github/workflows/|[[:space:]]*secrets: inherit)' \
  .github/workflows

Length of output: 20201


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ContextualWisdomLab/.github"
ref="5983b41ace75040c1d81818171ca7d0f3653254e"

for path in \
  ".github/workflows/pr-review-fix-scheduler.yml" \
  ".github/workflows/pr-review-merge-scheduler.yml"
do
  printf '\n== %s at %s ==\n' "$path" "$ref"
  gh api \
    -H "Accept: application/vnd.github.raw+json" \
    "/repos/${repo}/contents/${path}?ref=${ref}"
done

Length of output: 58521


@seonghobae I found one blocking issue.

hourly-pr-maintenance.yml Line 30 passes the pinned revision as canonical_ref. However, the pinned central pr-review-fix-scheduler.yml does not consume this input. Its dispatch-review-fixes job sets CANONICAL_REF: main, and its checkout uses that environment variable. Therefore, the Python scheduler still checks out mutable main.

Update the central reusable workflow so that CANONICAL_REF uses inputs.canonical_ref. Then pin this caller to the central commit that contains that change. The local contract test should also pin that new revision.


✏️ Learnings added
Learnt from: seonghobae
URL: https://github.com/ContextualWisdomLab/bandscope/pull/738

Timestamp: 2026-08-03T03:59:50.432Z
Learning: At central revision `5983b41ace75040c1d81818171ca7d0f3653254e`, `ContextualWisdomLab/.github/.github/workflows/pr-review-fix-scheduler.yml` declares a `workflow_call` input named `canonical_ref`, but `dispatch-review-fixes` sets `CANONICAL_REF: main` instead of consuming `inputs.canonical_ref`. A BandScope caller that passes `canonical_ref` cannot make the scheduler checkout immutable at this revision.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae
seonghobae marked this pull request as draft August 3, 2026 04:09
auto-merge was automatically disabled August 3, 2026 04:09

Pull request was converted to draft

@seonghobae
seonghobae marked this pull request as ready for review August 3, 2026 05:09
@seonghobae
seonghobae enabled auto-merge (squash) August 3, 2026 05:10
cancel-in-progress: false

permissions:
actions: write
permissions:
actions: write
checks: read
contents: write

Copy link
Copy Markdown
Collaborator Author

Closing as superseded by ContextualWisdomLab/.github#704. The organization-level reusable review-fix scheduler now owns the hourly cadence and one-hour same-head retry while binding privileged code to job.workflow_repository and job.workflow_sha. Keeping this repository-local caller would duplicate scheduling and permanently pin BandScope to the older central implementation, whose internal checkout still follows mutable main. The central merge scheduler already revisits merge readiness independently, so no BandScope-local scheduler is needed.

@seonghobae seonghobae closed this Aug 3, 2026
auto-merge was automatically disabled August 3, 2026 05:29

Pull request was closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants