Skip to content

Review gate: "reviewed, nothing found" only on a Copilot review of the current head - #6371

Merged
rbuergi merged 5 commits into
mainfrom
fix/4730-review-evidence-current-head
Oct 9, 2026
Merged

rbuergi merged 5 commits into
mainfrom
fix/4730-review-evidence-current-head

Conversation

@rbuergi

@rbuergi rbuergi commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Refs #4730

The decision being implemented

#4730: "reviewed, nothing found" = ONLY a completed Copilot review object on the CURRENT head with zero findings. No timeout-based acceptance. review-waived label stays the escape. (maintainer decision)

Recorded as policy review-evidence-current-head in Doc/Architecture/PolicyNotProse.

What changes in Automatic review answered (check-review-answered.py evaluate)

  • No reviewer thread on the pull request ⇒ condition 1 holds only for a Copilot review (account 175728472, type Bot, non-PENDING, not a refusal) whose commit_id is the current head (copilot_review_on). These are not that evidence any more:
    • a clean Copilot review of an earlier head,
    • the internal reviewer's clean review,
    • the Reviewer unavailable degradation check run, which released condition 1 with nobody having reviewed the pull request.
  • With findings, nothing changes. The threads show a review happened, and condition 2 decides (review-once-per-pull-request).
  • The new red is named on all three surfaces: the headline RED — NO REVIEW OF THIS HEAD, the step summary, and To go green. The remedy is a maintainer re-requesting the Copilot review, or review-waived. It is a structured field (Verdict.stale_clean), and --wait-for-review does not wait for it, because no wait delivers a review the ruleset (review_on_push: false) will not request.
  • The generated-only App pull request stays not owed. That rule rests on provenance and does not claim a review happened. A settle pull request that is rewritten after a clean earlier-head review also stays not owed. A person's pull request in the same state is red, and a negative control pins that.

Consequence for reviewers to weigh

The rulesets review once per pull request, so a clean pull request that is pushed again after its review reads no review of this head until a maintainer re-requests Copilot or applies the waiver. The push can be a fix or a merge of main. Pull requests with findings are unaffected.

Verification

  • python3 .github/scripts/check-review-answered.py --self-test: all cases green. There are 10 new EVIDENCE cases (positive and negative pairs), plus 2 generated-only cases. The degradation-release cases are now negative controls.
  • Negative control: with the old acceptance monkeypatched back in (any landed review of any head counts), 3 cases fail: the earlier-head case, the waiver-credit case, and the person's-lock-PR control.

Docs

  • ReviewFindingsAnswered.md has a new section, Reviewed, nothing found — the only evidence that counts. The degradation section is marked retired for the merge gate, and the rule, the table and the summary are updated.

🤖 Generated with Claude Code

rbuergi and others added 2 commits October 9, 2026 21:15
…e current head (#4730)

Policy review-evidence-current-head. With no reviewer thread on the pull
request, condition 1 of Automatic review answered now requires a completed
Copilot review object on the CURRENT head. A clean review of an earlier
head, the internal reviewer's clean review and the 'Reviewer unavailable'
degradation run no longer release it; review-waived stays the escape.
The new state is named (RED - NO REVIEW OF THIS HEAD) and is not waited for.

Refs #4730

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 9, 2026 19:15

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

Historical refusals can mask the new verdict, and existing policy documentation still contradicts the change.

2 open findings
What changed in this PR

Tightens review evidence so clean reviews count only for the current head.

Changes:

  • Adds current-head Copilot review validation.
  • Retires degradation-based merge-gate acceptance.
  • Documents and tests the revised policy.
File Description
.github/​scripts/​check-review-answered.py Implements and tests current-head review evidence.
ReviewFindingsAnswered.md Documents the revised gate behavior.
PolicyNotProse.md Registers the new policy.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 408 to 412
stale_reported = stale_clean
# Only when the state actually STANDS: a waived refusal is not an unreviewable pull
# request, it is a reviewed-enough one, and saying otherwise would re-create the
# confusion in the other direction.
refused += [first_line(r.get("body")) for k, r in kinds if k == "refused"]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. This is fixed in cb5ab4e: once a review has landed and the only problem is that it was not of this head (stale_clean), historical refusals are no longer collected into refused. The reader is therefore told RED — NO REVIEW OF THIS HEAD and not "unreviewable". A new self-test case pins the mixed history, a refusal followed by a clean review of an earlier head. It asserts the NO-REVIEW-OF-THIS-HEAD headline and the re-request remedy, and that none of the UNREVIEWABLE strings appear.

| `review-then-suites` | RETIRED — superseded by `suites-parallel-with-review`. Was: every pull request in the fleet moved REVIEW FIRST, then the suites, then the arm: the stage gate (`node-repo-stage-gate.yml`, default `review-before-suites: true`, with its `stage-advance.yml` listener) holds the expensive suites until the head's automatic review landed and every finding is answered; the suites then test a fresh merge with the current main (`suites-test-fresh-merge`); and auto-merge is armed only when the review is answered AND every required status check of the base is green on the head (`check-review-answered.py` arm gate condition 4, ported by MeshWeaver.Plugins `PrArming`). Replaces `suites-parallel-with-review` (suites beside the review), which it reverted the same day; `review-before-suites: false` remains a per-caller opt-out that never changes the merge or the arm. Manual: [Staged Pull Request Pipeline](../StagedPullRequestPipeline). | retired | 2026-10-05 → 2026-10-07 | maintainer |
| `suites-parallel-with-review` | The expensive suites run BESIDE the automatic review: the stage gate (`node-repo-stage-gate.yml`, default `review-before-suites: false`) lets them start as soon as stage 0 is green, on a fresh merge with the current main (`suites-test-fresh-merge`). Merging and arming are untouched — auto-merge is armed only when the review is answered AND every required status check of the base is green on the head (`check-review-answered.py` arm gate condition 4, ported by MeshWeaver.Plugins `PrArming`). Back in force after `review-then-suites` (review first, then the suites) was retired — the reviewer takes one review at a time, so holding the suites behind it left runners idle. `review-before-suites: true` (with the `stage-advance.yml` listener) remains a per-caller opt-in. Manual: [Staged Pull Request Pipeline](../StagedPullRequestPipeline). | in force | 2026-10-07 | maintainer |
| `suites-test-fresh-merge` | Every suite job of a pull request tests the head merged onto the base branch's CURRENT tip, resolved when the suites start and reported in the run — never GitHub's `refs/pull/N/merge` as it stood at the push, and never a stale merge on a re-run. The merge is computed in the job (no push, no branch update, no new head or review); a head that conflicts with the current tip is red. Manual: [Fresh Merge Under Test](../FreshMergeUnderTest). | in force | 2026-10-05 | maintainer |
| `review-evidence-current-head` | "Reviewed, nothing found" is ONLY a completed Copilot review object on the CURRENT head with zero findings. `Automatic review answered` (`check-review-answered.py` `evaluate`, via `copilot_review_on`) accepts no timeout, no `Reviewer unavailable` degradation run, no internal-reviewer review and no clean review of an earlier head as that evidence; a pull request WITH findings is still judged by its answered threads (`review-once-per-pull-request`). The `review-waived` label applied by a maintainer stays the escape. A generated-only App pull request stays *not owed* (provenance, not a claim of review). Manual: [Review Findings Answered](../ReviewFindingsAnswered) → *Reviewed, nothing found*. | in force | 2026-10-09 | maintainer |

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. This is fixed in cb5ab4e and e65557e. The review-once-per-pull-request register row now names its narrowing: with no reviewer thread, Automatic review answered accepts only a Copilot review of the current head. The manual's One review per pull request section at lines 178 and 183 now says the same and links to Reviewed, nothing found. The stage gate and the arm gate keep the any-head acceptance, as before.

rbuergi and others added 3 commits October 9, 2026 21:41
…egister narrows review-once (#6371 review)

Refs #4730

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…iew)

Refs #4730

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Test Results

    24 files      24 suites   49m 58s ⏱️
11 275 tests 11 082 ✅ 193 💤 0 ❌
11 288 runs  11 095 ✅ 193 💤 0 ❌

Results for commit e65557e.

@rbuergi
rbuergi merged commit 479c9b7 into main Oct 9, 2026
@rbuergi
rbuergi deleted the fix/4730-review-evidence-current-head branch October 10, 2026 13:10
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