LearnNewsExamplesServices
Frontmatter
id13587
titleBlock strict merge-ready on outstanding review requests
stateClosed
labels
bugaiarchitecturemodel-experience
assigneesneo-opus-ada
createdAtJun 20, 2026, 5:27 AM
updatedAtJun 20, 2026, 7:02 AM
githubUrlhttps://github.com/neomjs/neo/issues/13587
authorneo-gpt
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 20, 2026, 7:02 AM

Block strict merge-ready on outstanding review requests

Closed v13.1.0/archive-v13-1-0-chunk-4 bugaiarchitecturemodel-experience
neo-gpt
neo-gpt commented on Jun 20, 2026, 5:27 AM

Context

During the #13584 merge-gate discussion on 2026-06-20, the live PR state exposed a merge-readiness false positive:

  • gh pr view 13584 returned reviewDecision=APPROVED, mergeStateStatus=CLEAN, and all checks green.
  • The same live response still contained reviewRequests: [neo-opus-grace].
  • A second peer (neo-opus-ada) had sent an A2A approval, but had not posted a formal GitHub review state.

Tobi's operator judgment was the stricter and substrate-correct rule: if an author assigns two reviewers, the merge is blocked until both requested reviewers approve, request changes, explicitly step out, or are unrequested. A flattened GitHub reviewDecision=APPROVED is not enough when an explicit reviewer request remains active.

Live latest-open sweep: checked the latest 20 open issues at 2026-06-20T03:25Z; no equivalent reviewer-request merge-gate ticket found. Closest adjacent tickets were unrelated Agent OS stability lanes (#13586, #13575, #13498, #13496, #13480). A2A in-flight sweep: checked latest 30 all-status messages at 2026-06-20T03:25Z; no overlapping [lane-claim] / [lane-intent] for this reviewer-contract gap found. Knowledge Base sweep surfaced adjacent cross-family review mandate and manage_pr_reviewers invitation-layer substrate, but no rule tying outstanding reviewRequests to merge-readiness.

Release classification: post-release / Agent OS process hardening. This is merge-gate correctness, but the immediate #13584 case is handled by targeted A2A to Grace; the general rule can land boardless unless the operator explicitly promotes it.

The Problem

Neo's PR lifecycle has multiple review signals:

  • reviewDecision tells whether GitHub has enough formal review state to consider the PR approved.
  • reviewRequests tells who the author/operator explicitly asked to review.
  • A2A review messages provide useful peer signal, but they do not clear GitHub's requested-reviewer contract unless paired with a formal PR review or an explicit step-out / unrequest action.

Today an agent can honestly report "approved + clean" from reviewDecision=APPROVED while a requested reviewer is still outstanding. That is exactly the class of stale merge-ready signal the review process is supposed to prevent: the human merge gate sees a green surface, but the author-declared reviewer contract is not fully disposed.

The Architectural Reality

Relevant substrate already exists:

  • .agents/skills/pr-review/references/pr-review-guide.md requires live PR-state freshness before relaying review or merge-eligibility claims, and warns to relay the review body's verdict rather than flattened enums.
  • .agents/skills/post-review-pickup/references/post-review-pickup-workflow.md requires live PR state before lane-state declarations that name PR status.
  • ai/services/github-workflow/PullRequestService.mjs and ai/mcp/server/github-workflow/openapi.yaml expose manage_pr_reviewers as the invitation layer for GitHub reviewer requests.
  • reviewDecision remains necessary for formal approval, but it is not sufficient when reviewRequests is non-empty.

The missing rule is the merge-readiness contract:

A PR with outstanding requested reviewers is not strict-merge-ready, even if reviewDecision=APPROVED, unless each outstanding request is explicitly disposed by approval, request-changes, comment-step-out, or author/operator unrequest.

The Fix

Add a narrow merge-readiness guard wherever agents report or lint "eligible for human merge":

  1. Fetch reviewRequests alongside reviewDecision, mergeStateStatus, checks, and head SHA in PR-state freshness checks.
  2. Treat non-empty reviewRequests as a merge-gate blocker unless the body explicitly documents a disposal path:
    • requested reviewer posted formal APPROVED;
    • requested reviewer posted formal CHANGES_REQUESTED;
    • requested reviewer posted a visible "stepping out / no review needed from me" comment;
    • author/operator removed the review request via manage_pr_reviewers(action: 'remove').
  3. Update review / PR / post-review-pickup guidance so agents do not claim strict merge-ready from reviewDecision=APPROVED alone.
  4. If a mechanical lint exists for review or PR-body merge-ready language, extend it to catch the false-positive pattern when reviewRequests is non-empty.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
PR merge-readiness claim GitHub PR reviewDecision, reviewRequests, checks, and head SHA Require reviewDecision=APPROVED, green checks, and empty/disposed reviewRequests before claiming strict merge-ready If requests remain, state "approved/clean, but strict gate waits on requested reviewer(s)" pr-review / pull-request / post-review-pickup guidance #13584 live state: reviewDecision=APPROVED plus reviewRequests=[neo-opus-grace]
Reviewer invitation lifecycle manage_pr_reviewers and GitHub requested-reviewers API Outstanding requested reviewers are explicit author/operator contract, not advisory noise Author/operator may remove stale requests explicitly GitHub Workflow MCP docs / PR workflow docs manage_pr_reviewers is already documented as invitation layer
A2A review signal Memory Core A2A messages A2A approval can inform author response, but does not clear a GitHub requested-reviewer slot by itself Ask the peer to post formal review or step-out, or remove request A2A handoff guidance #13584 Ada A2A approval did not remove Grace's outstanding GitHub request

Decision Record impact

none. This clarifies merge-readiness process semantics using existing GitHub review primitives; it does not change human-only merge authority.

Acceptance Criteria

  • PR-state freshness checks that report merge eligibility include reviewRequests.
  • Any merge-ready / eligible-for-human-merge language distinguishes reviewDecision=APPROVED from strict readiness when reviewRequests is non-empty.
  • Guidance documents name the reviewer-contract rule: all explicitly requested reviewers must disposition or be unrequested.
  • If a relevant lint/validator exists, it catches "approved + mergeable" claims that omit non-empty reviewRequests.
  • Tests or fixture coverage include a PR-like state with reviewDecision=APPROVED, green checks, and one outstanding requested reviewer.

Out of Scope

  • Changing GitHub branch protection.
  • Requiring more than one reviewer when only one reviewer was requested.
  • Treating all A2A review signals as invalid; A2A remains useful context, but formal requested-reviewer slots need explicit disposition.
  • Any agent execution of gh pr merge; human-only merge authority remains unchanged.

Avoided Traps

  • Do not collapse "cross-family approval exists" into "every requested reviewer has dispositioned".
  • Do not rely on GitHub's flattened reviewDecision as the only merge-gate signal.
  • Do not silently ignore stale reviewer requests; either remove them explicitly or report them as the remaining strict gate.

Related

Related: #13584 Related: #10214 Related: #11273

Origin Session ID

Origin Session ID: current @neo-gpt Codex Desktop session, 2026-06-20.

Handoff Retrieval Hints

  • query_raw_memories: 13584 reviewDecision APPROVED reviewRequests neo-opus-grace strict merge gate
  • query_raw_memories: requested reviewers block merge readiness flattened reviewDecision approved
  • Exact PR-state anchor: #13584 at 6f755137595cca6770836428e5f86c3c7b2222fd returned reviewDecision=APPROVED and reviewRequests=[neo-opus-grace].