Skip to content

Read a Per-Repository Review Policy Before Asking Any Bot for a Review - #3881

Merged
ptr727 merged 11 commits into
developfrom
feature/pr-review-policy
Nov 5, 2026
Merged

ptr727 merged 11 commits into
developfrom
feature/pr-review-policy

Conversation

@ptr727

@ptr727 ptr727 commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

Summary

This is the first step of the revised review cutover on #3877. Which bots review a repository's pull requests, on which bases, when, and how often is now a setting in that repository's own .github/pr-review.json. A repository carrying none reads the hub's spec/pr-review.default.json. That default reproduces the gate's current behavior exactly, so this pull request changes nothing until a repository opts in. Each repository can then be cut over, tested, or rolled back on its own, and the reviewer cost is tuned per repository.

  • Schema and reader. The schema is spec/pr-review.schema.json, and scripts/pr_review_policy.py reads and validates it. A test holds the two equal. The policy is read from the pull request's base branch, so a pull request cannot change the rules its own review runs under.
  • Copilot, governed in full.
    • trigger is auto, explicit, or off.
    • bases lists the branches it reviews.
    • when can hold the request until the head's checks pass. That makes the push, wait for a green build, then review question a per-repository setting the metrics can compare.
    • rounds and maxRounds cap the rounds. A spent cap hands a new head to an attested local pass.
    • gate decides whether the merge waits on Copilot. An explicit Copilot must gate, and the reader and schema refuse one that does not, since wait requests Copilot only for a round the merge waits on.
    • Where Copilot is off, ungated, or past its cap, no Copilot round is coming. So its refusals, partial rounds, pending requests, and cut history no longer stop an attested local pass from covering the head.
  • CodeRabbit and Qodo, kept simple by decision. Where a policy says explicit, each is asked by comment once per new head: @coderabbitai review, or full review, and /review. The ask can optionally wait for green checks. The merge never waits on either, and the reader refuses gate: true for them. Their findings reach the digest as they always did.
  • Trigger-agnostic text. The skill and rule text no longer depend on whether a repository's reviews arrive automatically or on request. wait requests what the policy owes, and the text names the hub default as a default. GOVERNANCE.md "PR Review Etiquette", drive-pr, pr-review-conduct, .github/copilot-instructions.md, docs/pr-reviewer-reference.md, and scripts/README.md are updated, and the generated skill trees regenerated.
  • New statuses. status=CHECKS_BEFORE_REVIEW exits 30 while checks run, 40 when they fail, and 44 when one is stuck or the head is conflicted. It routes to redrive.
  • Size ceiling. The CodeRabbit and Qodo reading and asking live in a new scripts/pr_review_side.py, and the policy reads off a payload in a new scripts/pr_review_payload.py, so pr_review.py stays under its size ceiling. mutated moves to scripts/gh_graphql.py so both modules share it.

Not in this pull request:

  • repo-config/configure.sh applying each repository's policy to the bot-side settings. That covers the Copilot ruleset rule and the CodeRabbit and Qodo files, through a local checkout.
  • The account-level settings repositories.
  • The metrics. Those are in the sibling feature/review-metrics pull request.

Verification

  • The full suite passes: 3,481 tests, 11 skipped, run with uv run --no-project --with-requirements tests/requirements.txt python -m unittest discover -s tests -p 'test_*.py'. The gate tests that predate the policy pass unchanged under the default, which shows the change is behavior-neutral there.
  • tests/test_pr_review_policy.py, new, covers parsing and refusals, schema parity, base matching, caps, and the Copilot cover decision with the default proven equal to the old one. It also covers head arrival, check holds, and the side asks. Wait-level cases cover a red build exiting 40 without a request, green checks reaching the request, and --request skipping the hold.
  • Each fix in ad9feaa, e4622ee, and 67612c8 has a test that fails with that fix reverted, checked one fix at a time.
  • ruff format, ruff check, mypy, pyright on the changed scripts, the prose gate against develop, and the eol gate all pass.
  • The local strict passes over 9946909, e4622ee, and 67612c8 are recorded, and 67612c8 is attested. The first two were answered in this push's two edit rounds. The findings still open are below.

Open findings from the local strict pass (edit budget spent)

The fourteen findings listed for 9946909 are answered. Thirteen are fixed in ad9feaa and e4622ee, and the boolean version refusal is kept, since True == 1 would otherwise parse as version 1. Of the seven from the pass over e4622ee, six are fixed in 67612c8. The rest are open, all introduced:

  1. scripts/pr_review_side.py around line 279: an explicit after-checks CodeRabbit or Qodo is never asked when CI outlasts Copilot's round. The ask reads the checks once after the Copilot poll and gets PENDING. wait then exits 0, and the merge gate's own wait requests nothing.
  2. scripts/pr_review_side.py around line 75: a DIRTY or unreadable rollup exits 44 through checks_status. The wait usage text and the README exit table give 44 only for a stuck check. The held path documents a DIRTY head as 45.
  3. Design: side_asks in scripts/pr_review_side.py repeats the trusted-and-shown filter that trusted_comments in scripts/pr_review_rounds.py owns. This belongs with Share the Attestation Marker and Reviewer Logins Between the Gate and the Metrics Report #3880, below.
  4. Design: PAYLOAD_KEY = POLICY_KEY in scripts/pr_review_policy.py gives one constant a second name. The test asserting the two agree, and the docstring sentences explaining them, go with it.
  5. Design: request_side_reviews in scripts/pr_review_side.py repeats the post-and-confirm that comment_on_pr in scripts/pr_review.py does.

Dropped findings

  • ruff check reporting E402 on mutated = shared.mutated: disproved, since ruff check scripts/pr_review.py with the pinned config passes.

Deferred

Refs #3877, #3758.

🤖 Generated with Claude Code

ptr727 and others added 4 commits November 4, 2026 17:52
Each pull request bot costs money or agent time per round, so which bots review which pull
requests, when, and how often is now a per-repository choice. A repository states it in
`.github/pr-review.json`, read from the pull request's base branch so a pull request cannot
change its own policy. A repository carrying none reads `spec/pr-review.default.json`, which
keeps the gate's behavior as it was, so nothing changes until a repository opts in.

`wait` requests whatever the policy owes that has not started on its own. Copilot keeps its
review-request mutation, and CodeRabbit and Qodo are now asked by comment. So the skills and
the rule text no longer depend on whether a repository's reviews arrive automatically or on
request, and a repository can be cut over, tested, or rolled back alone. A request can wait
for the head's checks to pass first, which is the setting the push-then-build measurement
compares. A spent Copilot cap hands a new head to an attested local pass.

The CodeRabbit and Qodo reading and asking live in a new pr_review_side.py, so the gate stays
under its size ceiling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The local strict pass on the review-policy change found that a stale request or answer could
read as one on a head pushed later, since a commit's own timestamp is not its push. A head now
arrives with its earliest check, and green is judged with the gate's own check shapes, so a
head with no check posted yet is pending inside the grace rather than green.

An automatic reviewer the policy gates on is no longer asked while it has begun or may still
begin, which would have bought a second round. The policy read now retries through `reread`,
so a transient failure no longer ends a run that never used to read it. A Copilot entry with
`gate` off hands every head to the local pass. The schema and the reader are held equal by a
test, and copilot now refuses `command` in both.

The held-head notes and the docstrings no longer state that only a non-default base is held,
and the skill text names the hub default as a default. The repo-config README still describes
the ruleset as configure.sh applies it today, which the follow-up that makes configure.sh read
the policy changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a Fresh Read

The second local strict pass found that the side reviewers were judged on a stale or absent
read. They were never asked once Copilot already covered the head, and they were judged after
a wait for green checks on the read taken before it. Each is now judged on a fresh read, read
again after that wait, and the liveness read carries the base so the policy rides it too.

A head now arrives when GitHub created its first check suite, which happens at the push. A
head with no suite yet reads as just arrived, so a request made before the checks start still
counts for that head, and no check yet never reads as green.

The policy read projects its content as JSON, so the retried read stops at the first good one
rather than reading every retry. A side request held by failed checks exits 40 like the Copilot
one, and an automatic Qodo round counts toward its cap. `mutated` moves to `gh_graphql.py`, so
the gate and the side module share one comment-path helper, and the policy reader moves into
`pr_review_policy.py`. The `--help` exit text names the two new statuses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The maintainer chose to simplify the comment-triggered reviewers after the third local strict
pass. Making the merge wait on CodeRabbit or Qodo, and filling a missed automatic start, kept
producing defects, because neither bot leaves a reliable record of which push it reviewed.

So Copilot keeps the whole policy, its gate included, and CodeRabbit and Qodo are asked by
comment once per new head when their policy says explicit, after green checks where it says
so. The reader refuses `gate: true` for them, an automatic one is never asked, and the merge
never waits on either. Their findings reach the digest as they always did. The asks now run
before Copilot's own wait for green checks, so an on-open ask is never delayed behind it, and
each reviewer is judged again after any wait.

A check stuck in a shape no wait clears is named and exits 44 rather than polling the timeout
out. The side-review gate, its poll, `status=SIDE_REVIEW_PENDING`, and the unused
`committedDate` field are gone, and a wait-level test covers an ask on a head Copilot already
covered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings November 5, 2026 02:47
@coderabbitai

coderabbitai Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@ptr727

ptr727 commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head ab0837b0c7b40fe5c3f273e958ff2da71b9b1196, the content this pull request carries at that commit against develop, and it recorded 7 findings.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Active correctness and documentation issues remain, including a critical path that can bypass the required green-check prerequisite and several moderate policy, deduplication, and request-ordering defects.

12 open issues
What changed in this PR

This pull request introduces repository-owned pull request review policies while preserving the existing hub default behavior. Policies control reviewer coverage, triggers, timing, round limits, and Copilot gating.

Changes:

  • Adds the policy schema, default configuration, parser, base-branch loading, and validation tests.
  • Integrates policy-aware Copilot, CodeRabbit, and Qodo requests, check holds, and new exit statuses.
  • Updates governance documentation, review guidance, generated skills, digests, and size checks.

This pull request requires changes.

File Description
tests/​test_pr_review.py Updates existing gate fixtures and expectations for policy-aware payloads.
tests/​test_pr_review_size.py Adds the side-review module to size checks.
tests/​test_pr_review_policy.py Tests policy parsing, coverage, side reviews, check holds, and wait behavior.
tests/​test_pr_merge.py Recognizes the new pre-review check status.
spec/​pr-review.schema.json Defines the repository review-policy schema.
spec/​pr-review.default.json Defines the behavior-preserving default policy.
scripts/​README.md Documents policy behavior, reviewer requests, and exit statuses.
scripts/​pr_review.py Loads policies and coordinates reviewer requests and check holds.
scripts/​pr_review_side.py Implements CodeRabbit and Qodo requests and pre-review check handling.
scripts/​pr_review_rounds.py Applies policy-driven Copilot coverage and local-pass decisions.
scripts/​pr_review_policy.py Reads, validates, caches, and defaults repository policies.
scripts/​pr_review_answers.py Routes the new check status through redrive handling.
scripts/​gh_graphql.py Provides shared mutation-response traversal.
GOVERNANCE.md Updates the provider-agnostic review-loop contract.
docs/​pr-reviewer-reference.md Documents policy-controlled reviewer triggers.
.github/​skills/​pr-review-conduct/​SKILL.md Updates the generated review-conduct guidance.
.github/​skills/​drive-pr/​SKILL.md Updates the generated pull-request driving guidance.
.github/​copilot-instructions.md Documents policy-controlled Copilot coverage.
.claude-plugin/​fleet-skills/​skills/​pr-review-conduct/​SKILL.md Carries the generated Claude review-conduct skill.
.claude-plugin/​fleet-skills/​skills/​drive-pr/​SKILL.md Carries the generated Claude pull-request driving skill.
.claude-plugin/​fleet-skills/​.source-digests/​pr-review-conduct Updates the generated review-conduct source digest.
.claude-plugin/​fleet-skills/​.source-digests/​drive-pr Updates the generated driving-skill source digest.
.agents/​skills/​pr-review-conduct/​SKILL.md Updates the authoritative review-conduct skill.
.agents/​skills/​drive-pr/​SKILL.md Updates the authoritative pull-request driving skill.

Review effort: Lite

Comment thread scripts/pr_review_side.py Resolved
Comment thread scripts/pr_review.py Resolved
Comment thread scripts/pr_review.py Resolved
Comment thread scripts/pr_review_policy.py Resolved
Comment thread scripts/pr_review_side.py Resolved
Comment thread GOVERNANCE.md Resolved
Comment thread scripts/README.md Resolved
Comment thread scripts/README.md Resolved
Comment thread scripts/pr_review.py Resolved
@codecov

codecov Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.15670% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.69%. Comparing base (3a81362) to head (67612c8).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
scripts/pr_review_policy.py 91.61% 14 Missing ⚠️
scripts/pr_review_side.py 97.43% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3881      +/-   ##
===========================================
+ Coverage    83.31%   83.69%   +0.37%     
===========================================
  Files           29       32       +3     
  Lines         9956    10290     +334     
===========================================
+ Hits          8295     8612     +317     
- Misses        1661     1678      +17     
Flag Coverage Δ
python-3.13 83.69% <95.15%> (+0.37%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

ptr727 and others added 2 commits November 4, 2026 19:01
Copilot's first round on the review-policy pull request found these, each fixed here:

- `checks_hold` dropped a check node it could not read, so a rollup holding only one read as
  green. An unread node now holds the review as `UNREAD`.
- The Copilot auto-request asked whether the policy requests Copilot but not whether it covers
  the base. It now asks both, through `copilot_wanted`.
- A side reviewer waiting for green checks blocked the Copilot request. The side asks now run
  in two phases, on-open before Copilot's own wait and after-checks after its request. A
  reviewer already asked or answered is skipped before any wait.
- `{"version": true}` passed, since `True == 1`. A boolean version is refused.
- Before a head's first suite, an ask read as never made, so the next run asked again. The
  head's commit time now bounds it from below until a suite exists.
- The rule and skill text claimed `wait` requests every review the policy owes. It now says
  `wait` sends each request the policy asks for, and that an automatic bot starts on its own.
  The README's automatic-Copilot sentence and its exit-44 row are corrected, and the `--help`
  text moves the new 44 case under the 44 entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The local strict pass on the review-round fixes found two of them wrong.

The base check added to the Copilot auto-request skipped the round `wait` forces on a pull
request into develop that carries a partial round or a truncated history. The held-head logic
already excludes every base the policy does not cover, so the check is reverted. Staged test
payloads now carry the hub default policy, so every command-level case runs the path a live
run takes.

The commit-time fallback for a side ask read a field the live query never fetched. The query
fetches `committedDate` again, and an ask now counts for the head where it postdates the
head's commit, the one stamp that never moves once the head exists.

The GOVERNANCE, drive-pr, and pr_review_policy wording now says `wait` sends each request the
policy asks for, and that only a gated Copilot has a missed start filled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head e08f17564cdaf867375435d37897454b4a3499d9, the content this pull request carries at that commit against develop, and it recorded 5 findings.

ptr727 and others added 2 commits November 4, 2026 21:33
The reader and the schema now refuse a Copilot policy that is explicit with
gate false, since wait requests Copilot only for a round the merge waits on.
Where the policy has Copilot off or ungated, a partial round or a truncated
history no longer stops a local pass from covering the head, so wait no
longer polls its timeout for a round it never asked for. The comment, attest
and claims reads skip the policy fetch they never consult. Tests cover green
checks reaching an after-checks request and --request skipping the hold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Where Copilot is off, ungated, or past its round cap, no Copilot round is
coming, so its refusals, partial rounds, pending requests, and cut history
on the head no longer stop an attested local pass from covering it. A spent
cap with a partial round on record therefore no longer requests a paid round
past the cap. A capped side reviewer is not asked once the comments run past
the read window, since its rounds cannot then be counted. The hosted
reviewer check predicate is shared, and the no-op policy flags on reads that
never select a base are dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 9946909fcde799968ebfebebb873872229ef92f3, the content this pull request carries at that commit against develop, and it recorded 14 findings.

ptr727 and others added 3 commits November 4, 2026 22:10
Answers findings 1 to 8 of the local pass over 9946909.

- wait reads past a head refusal where copilot_settled holds, and drops
  it at the exit, so a settled head exits as status reads it.
- checks_hold reads an open workflow run as PENDING, as
  held_checks_open does, so a request never goes out between needs:
  stages.
- The after-checks side asks run after the Copilot poll, and a held
  Copilot request is judged again on a fresh read after the check wait.
- The exit-49, excluded-files, and explicit-trigger texts, the
  maxRounds description, and the skill, Copilot-instructions, README,
  and reference statements now say what copilot_settled waives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Answers findings 9 to 13 of the local pass over 9946909.

- pr_review_payload.py holds the policy's payload key and its two
  repeated reads, the default branch and a bot's entry. promotion,
  copilot_settled, side_reviewers, and copilot_policy share them, and
  pr_review_policy's PAYLOAD_KEY is that key.
- copilot_rounds becomes reviewed_heads(pr, login), which CodeRabbit's
  round count reuses.
- The whole-source write guards scan pr_review_side.py and
  pr_review_policy.py too, and the new module joins the reader set.
- pr_review_policy.py and pr_review_payload.py get size ceilings, and
  pr_review_rounds.py drops to 695 lines of its 700.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Answers six of the seven findings of the local pass over e4622ee.

- A side ask on a pull request no longer open is skipped, since a peer
  can merge or close it while wait polls.
- A capped bot whose review history runs past the read window counts
  as past its cap, so wait never requests a Copilot round over a cap
  it cannot count.
- A conflicted head with no check reads DIRTY and exits 44 naming the
  conflict, rather than PENDING until the timeout.
- An answer outside a review no longer keeps a settled Copilot's head
  from its local pass, so it exits 49 rather than 40.
- The after-checks side ask reads the checks once rather than polling,
  so no wait that says it stops goes on polling.
- wait's usage text names the side asks and the held Copilot request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ptr727

ptr727 commented Nov 5, 2026

Copy link
Copy Markdown
Owner Author

A recorded local strict-review pass covers head 67612c8d5e1cf787a293463ed3ef24642f4820b9, the content this pull request carries at that commit against develop, and it recorded 4 findings.

@ptr727
ptr727 merged commit 62f8b04 into develop Nov 5, 2026
13 checks passed
@ptr727
ptr727 deleted the feature/pr-review-policy branch November 5, 2026 14:57
ptr727 added a commit that referenced this pull request Nov 5, 2026
…mes in UTC (#3888)

## Why

#3881 left two defects in `scripts/pr_review_side.py`, and #3885 adds
two design items and a documentation gap. Each sits on the
review-cutover track (#3877), and the pilot needs the first one fixed
before any repository gives CodeRabbit or Qodo `when: after-checks`.

## What

- **An after-checks side reviewer is asked once CI settles (#3885 item
1).** `side.ask` read the head's checks once, after the Copilot poll. So
where a Copilot round already covered the head, or landed first, a check
still running gave `PENDING` and only a note. Nothing asked later, since
the merge gate's `run_wait` passes `may_request=False`. Now a wait that
polls for a Copilot round hands the ask the `await_green` partial, which
polls the checks on the wait's own clock and is bounded by `--timeout`.
Every other wait reads them once. That covers the checks-hold,
unrecorded-request, quota and refusal stops, exit 49, and a held head,
whose own poll already waits on the checks. A wait that polled re-reads
the payload before its digest and exit code, so a check that went green
during the side poll is not judged stuck from a stale read. A pull
request merged or closed while its checks settled is asked nothing.
- **Ask times compare as instants (#3887).** `side_asked_on_head`
compared a comment's UTC `createdAt` with the head's `committedDate` as
text, and a `GitTimestamp` keeps the committer's offset. Both now go
through `pr_review_checks.utc_instant`.
- **Exit 44 names its DIRTY and unreadable holds (#3885 item 2)**, in
the `wait` usage text and `scripts/README.md`. The exit-0 text now also
names the after-checks exception to "does not poll the checks".
- **`PAYLOAD_KEY` is gone (#3885 item 3).** Callers read
`pr_review_payload.POLICY_KEY`, and the test asserting the two agree is
dropped.
- **One post-and-confirm helper (#3885 item 4).** `side.post_comment`
posts a conversation comment and says whether its URL and exact body
confirm it. `comment_on_pr` and the side asks both call it.

`scripts/pr_review.py` sits at 2199 of its 2200-line ceiling after this
change. The next change that adds logic there has to move some first, as
#3880 plans.

Refs #3885, #3887, #3877. The closing keywords belong on the develop ->
main promotion PR.

## Verification

- The full suite, `uv run --no-project --with-requirements
tests/requirements.txt python -m unittest discover -s tests`, ran 3539
tests with 11 skipped, all passing, at 6bd9a5c. The `test_pr_review*`
suites pass at the head, 709 tests.
- The new `TestSideAskTiming` cases in `tests/test_pr_review_policy.py`
were each run against the pre-change scripts or with their fix reverted,
and each one failed. Those are the outlasting-CI ask, the poll hand-off
per wait path, the merged-during-poll ask, the fresh digest read, and
both UTC offsets.
- ruff format and check are clean. The pre-commit hook's mypy, prose and
EOL gates pass.

## Local-review findings, disposed

Three recorded `local-strict-review` passes at the `frontier` tier
covered the branch. The third, at 08cb68a, raised nothing.

- `introduced`, fixed in bc8e6ae: the digest and exit code came from a
payload read before the side poll, so a check that went green during it
could read as `NOT_PICKED_UP` and exit 44.
- `introduced`, fixed in bc8e6ae: a held head handed the ask a poll,
which could delay exit 46 by up to `--timeout`.
- `introduced`, fixed in bc8e6ae: a pull request merged while its
checks settled could still be asked.
- `introduced`, fixed in bc8e6ae: the usage text and the README `0` row
still said a covered head's exit 0 never polls the checks.
- `introduced`, fixed in 08cb68a: the usage text and README still said
any polling wait awaits the checks after the held-head change.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
ptr727 added a commit that referenced this pull request Nov 6, 2026
…t Policy (#3892)

## Summary

Promotes #3881, #3884, #3886, #3888, #3889, and #3891 to `main`.

Closes #3200.
Closes #3885.
Closes #3887.

- **Per-repository review policy (#3881).** `scripts/pr_review.py` reads
which bots review a repository, on which bases, when, and how often,
from the repository's own policy, with the hub default reproducing
today's behavior.
- **Review return on cost (#3886).** `scripts/backlog_metrics.py`
measures reviewer cost per useful finding. It is now a uv script, so the
metrics server's weekly timer must run it as `uv run --no-project
--script scripts/backlog_metrics.py` from this release on.
- **After-checks side reviewer (#3888).** An explicit after-checks
CodeRabbit or Qodo is asked once CI settles, and ask times compare in
UTC.
- **Commit in place for an operational repository (#3889).** The policy
file became `.github/agent-policy.json`, with its schema under `review`
and a `guard` section that lets `gh-write-guard` allow an in-place
commit on a listed branch.
- **Agent policy rendered from the registry (#3891).**
`repo-config/configure.sh` renders `.github/agent-policy.json` from
`registry/repos.json` and applies the bot settings it implies: the
Copilot ruleset rule, CodeRabbit's auto-review keys, and Qodo's
auto-feedback key. Once this is on `main`, `configure.sh check` reports
agent-policy drift on every repository until `apply --checkout` has been
run there.
- **Dependabot (#3884).** The actions-deps group bump.

Each feature pull request carried recorded local strict review passes,
with every finding fixed, declined with evidence, or filed (#3890).

🤖 Generated with [Claude Code](https://claude.com/claude-code)
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