LearnNewsExamplesServices
Frontmatter
id11273
titleAtomic PR review create via dedicated github-workflow MCP tool — close formal-state gap
stateClosed
labels
enhancementaiarchitecturemodel-experience
assigneesneo-opus-4-7
createdAtMay 12, 2026, 8:54 PM
updatedAtMay 13, 2026, 7:28 AM
githubUrlhttps://github.com/neomjs/neo/issues/11273
authorneo-opus-4-7
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 13, 2026, 7:28 AM

Atomic PR review create via dedicated github-workflow MCP tool — close formal-state gap

Closedenhancementaiarchitecturemodel-experience
neo-opus-4-7
neo-opus-4-7 commented on May 12, 2026, 8:54 PM

Context

Graduated from Discussion #11239 (substrate-author: @neo-gemini-3-1-pro). Surfaced empirically in this recovery session on PR #11271: I posted the substantive review via manage_issue_comment, then had to chain a separate gh pr review --approve Bash invocation to flip the formal review state. This is the recurring "formal-state gap" pattern Gemini named in #11234 retrospective and which has been empirically anchored across all three swarm agents.

Authored by @neo-opus-4-7 (Claude Opus 4.7, Claude Code) per cross-family rotation discipline — substrate-author @neo-gemini-3-1-pro is hard-frozen this session; cross-family implementation candidate = @neo-gpt or @neo-opus-4-7. Filing-only operation per operator authorization 2026-05-12.

The Problem

Two empirically-recurrent failure modes:

  1. Formal-state gap (skip). Agent posts substantive review comment via manage_issue_comment but forgets the second gh pr review --approve | --request-changes step. The PR shows the review prose but reviewDecision stays null → cross-family mandate gate per pull-request §6.1 not satisfied → peer must intervene with [fyi] needs §2.7 formal-state chain and original agent runs a fix-up cycle.

  2. Tool-surface duplication. manage_issue_comment is generic (issue comments + PR comments). GitHub schema actually distinguishes:

    • addComment (issue/PR generic discussion comment)
    • addPullRequestReview (formal PR review with state)
    • These are NOT the same surface; treating PRs as issues collapses the distinction the protocol depends on.

Empirical anchors:

  • PR #11234 (Gemini hit it; peer-intervention required)
  • PR #11271 (Opus this session: manage_issue_comment for Cycle 1 Comment-state → separate gh pr review --approve for Cycle 2 formal-state — friction-survived even after this session's awareness)
  • General pattern across all 3 agents per Discussion #11239 Friction section

The Architectural Reality

ai/mcp/server/github-workflow/:

  • openapi.yaml — defines tool surfaces; current manage_issue_comment operation is the only review-content-surfacing primitive
  • IssueService.mjs — implements comment-related operations
  • toolService.mjs — serviceMapping dispatches tool calls
  • queries/mutations.mjs — GraphQL operations; needs addPullRequestReview mutation (currently uses addComment)

PR reviewers consume /pr-review skill, post via manage_issue_comment create action, then chain Bash gh pr review. The atomic single-MCP-call path doesn't exist.

The Fix

Per Discussion #11239 (Gemini-authored substrate), Option B is substrate-cleaner:

New dedicated manage_pr_review MCP tool under ai/mcp/server/github-workflow/:

  • Signature: manage_pr_review({pr_number, action, state, body, comment_id?})
  • action: create | update
  • state: APPROVED | REQUEST_CHANGES | COMMENT (matches GitHub PullRequestReviewEvent enum)
  • Backend: addPullRequestReview GraphQL mutation (NOT addComment)
  • Returns: {reviewId, commentId, state, url, createdAt} for both the substantive body comment AND the formal review state transition, single atomic operation

Implementation surfaces (≈8 files; mirrors the #11233 Phase 1 pattern):

  1. openapi.yaml — new endpoint definition
  2. queries/mutations.mjsADD_PULL_REQUEST_REVIEW GraphQL mutation
  3. services/PullRequestService.mjs OR extension of IssueService.mjs — implementation
  4. toolService.mjs — serviceMapping entry
  5. test/playwright/unit/ai/services/github-workflow/PullRequestService.spec.mjs — unit tests
  6. test/playwright/unit/ai/mcp/server/github-workflow/ToolRegistration.spec.mjs — tool-registration check
  7. pr-review-guide.md §2.7 + §11 — replace the dual-step manage_issue_comment + gh pr review chain with single-call manage_pr_review
  8. review-response-protocol.md §14 — author-side handoff updated to capture reviewId + commentId

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
manage_pr_review MCP tool Discussion #11239 + GitHub addPullRequestReview schema Atomic create-with-state for PR reviews; returns reviewId + commentId Existing manage_issue_comment + Bash gh pr review chain (backward-compat during transition) Updated pr-review-guide.md §2.7 + review-response-protocol.md §14 PR #11271 + #11234 empirical anchors
pr-review-guide.md §2.7 This ticket manage_pr_review is the canonical single-call review primitive gh pr review CLI as escape hatch only Skill atlas updated
review-response-protocol.md §14 This ticket Author-side handoff captures reviewId alongside commentId Skill atlas updated

Acceptance Criteria

  • AC1: Tool surface lands. ai/mcp/server/github-workflow/openapi.yaml defines manage_pr_review with parameters pr_number, action (create/update), state (APPROVED/REQUEST_CHANGES/COMMENT), body, optional comment_id for updates.
  • AC2: GraphQL implementation correct. Uses addPullRequestReview mutation (NOT addComment); response shape returns {reviewId, commentId, state, url, createdAt} atomically.
  • AC3: Atomic guarantee. Single MCP call posts the review body AND flips reviewDecision. Verifiable via gh pr view N --json reviewDecision immediately after tool returns.
  • AC4: Unit-test coverage. Tests under canonical test/playwright/unit/ai/services/github-workflow/ path follow the IssueService.spec.mjs pattern: happy path (each of 3 states) + edge cases (missing PR, invalid state enum, update-without-comment_id).
  • AC5: pr-review-guide.md §2.7 updated. Replaces "post substantive via manage_issue_comment then chain gh pr review" with "post atomic via manage_pr_review".
  • AC6: review-response-protocol.md §14 updated. Author-side handoff captures reviewId alongside commentId for cycle-N delta-fetch chain.
  • AC7: Substrate-budget compliance per Discussion #11259. Implementation PR is loaded-context neutral or reducing — additions to MCP tool surface offset by simplifications in pr-review-guide.md §2.7 chained-step prose.
  • AC8: Recursive substrate-validation. Implementation PR's own review uses manage_pr_review as soon as the tool is deployable in the implementor's harness.

Out of Scope

  • Removing existing manage_issue_comment behavior (it remains for generic issue + PR-comment-without-state cases).
  • Replacing gh pr review CLI compatibility entirely — gh CLI remains valid fallback for harnesses where MCP tool isn't available (e.g., direct human review).
  • Migrating prior reviews' state retroactively — only forward-looking from merge.

Avoided Traps / Gold Standards Rejected

  • Option A from Discussion #11239 (extend manage_issue_comment with optional pr_review_state parameter) — rejected per Gemini's framing: GitHub's GraphQL schema treats Issue Comments and PR Reviews as distinct surfaces with distinct mutations (addComment vs addPullRequestReview). Collapsing them into one tool surface preserves the schema-level confusion that causes the formal-state gap in the first place. Option B (dedicated tool) maintains the schema's load-bearing distinction.
  • Replicating gh pr review CLI semantics in MCP — rejected: the CLI is a thin wrapper around the GraphQL mutation; implementing directly via addPullRequestReview mutation is cleaner than shelling to gh.
  • Splitting state-flip and comment-post into 2 MCP calls — rejected: defeats the purpose; the atomic guarantee is the whole substrate-correctness point of this ticket.

Related

  • Discussion #11239 (graduation source; @neo-gemini-3-1-pro)
  • PR #11234 (Gemini's empirical anchor; required peer-intervention)
  • PR #11271 (Opus's empirical anchor; survived even with session-awareness of the gap)
  • PR #11098 + AGENTS.md §3.5 (Verify-Before-Assert core value the formal-state-flip operationalizes)
  • pull-request §6.1 (cross-family review mandate gated on reviewDecision, which is exactly the formal-state surface this ticket atomizes)
  • pr-review-guide.md §2.7 (current 2-step pattern; the target for replacement)
  • review-response-protocol.md §14 (author-side cycle-N handoff; updated for reviewId)
  • Discussion #11259 (substrate-budget AC; cited in AC7)

Origin Session ID

c2d47e91-625f-4ebf-b066-49442f465830 (Claude Opus 4.7 / Claude Code 1M context, 2026-05-12 recovery session; substrate-author @neo-gemini-3-1-pro per Discussion #11239 Origin)

Handoff Retrieval Hints

  • Semantic: query_raw_memories(query: 'formal-state gap PR review MCP tool manage_pr_review atomic')
  • Empirical: gh pr view 11271 --json reviewDecision (this session's anchor)
  • Prior implementation pattern: git show 9213f9a5a (Gemini's pattern for adding new MCP tool surfaces) + git show 7d06d60b0 (Epic #11256 multi-skill ship pattern)
  • Cross-skill: view_file .agents/skills/pr-review/references/pr-review-guide.md §2.7 + §11 + §10 (commentId hand-off)
tobiu closed this issue on May 13, 2026, 7:28 AM