Context
Surfaced during the PR #10269 three-cycle cross-family review on 2026-04-24. Each review cycle N+1 cost more context than cycle N because get_conversation returns the ENTIRE thread every call — my cycle-3 fetch pulled my cycle-1 review (~2K tokens), Gemini's cycle-1 response, my cycle-2 review, Gemini's cycle-2 response, my cycle-3 review, and her final comment. For an Architectural Pillar PR, that's ~15K tokens just to fetch "what's new since last time I looked."
The trajectory is worse for A2A: every agent responding to a review thread re-fetches the full history. At epic scale (sub-issues of #9999), this burns cumulative context proportional to review depth × participant count.
The Problem
Three interlocking gaps:
- Write-path information loss.
manage_issue_comment returns {"message": "Successfully created comment on PR #N"} — no comment ID. The agent that just posted can't reference its own comment's canonical URL.
- Read-path has no selective fetch.
get_conversation(pr_number: N) always returns every comment. No since_comment_id, no last_n, no comment_id for single-comment lookup.
- A2A has no hand-off shape. When Alice posts a review and wants Bob to read just her new comment, there's no conventional payload — Bob has to re-parse the whole thread to find what's new.
All three are coupled: fixing (1) enables (3), and (2) makes (3) efficient.
The Architectural Reality
ai/mcp/server/github-workflow/ — the wrapper that implements manage_issue_comment and get_conversation via gh CLI. GitHub's underlying REST API (/repos/{owner}/{repo}/issues/comments) DOES return comment IDs on create and supports per-ID fetch.
.agent/skills/pr-review/references/pr-review-guide.md — establishes reviewer conventions. Would need a new §9 "A2A Hand-off Protocol" section.
.agent/skills/pull-request/references/pull-request-workflow.md — same for author-side comment propagation.
- Memory Core mailbox (A2A substrate from #10145 → #10266) — the transport for comment-ID propagation between sessions. No changes needed to the mailbox itself; just a convention on payload shape.
Tool surface discipline: Current count is 84 tools across 4 MCP servers; hard cap ~100 for many agents (50 recommended). This ticket adds ZERO new tools — enhances existing tool parameters instead. Matches precedent: start_database/stop_database → manage_database.
The Fix
Phase 1 — manage_issue_comment returns comment ID on create/update
Current response shape:
{"message": "Successfully created comment on PR #N"}New response shape:
{
"message": "Successfully created comment on PR #N",
"commentId": "4309098042",
"url": "https://github.com/neomjs/neo/pull/N#issuecomment-4309098042",
"createdAt": "2026-04-23T23:53:17Z"
}GitHub REST already returns these fields; the wrapper just passes them through. Backward compatible — existing consumers that only read message continue to work.
Phase 2 — get_conversation gains three optional parameters
get_conversation({
pr_number: N, // existing, required
comment_id?: "4309098042", // NEW: fetch ONLY this comment body
since_comment_id?: "4309098042", // NEW: fetch everything AFTER this comment
last_n?: 3 // NEW: fetch last N comments
})Default behavior (all three new params omitted): unchanged — full conversation as today. Backward compatible.
Selector precedence: comment_id > since_comment_id > last_n > full. Explicit single > time-bounded > count-bounded > everything.
One minimalist-tool-surface discussion — decided against splitting into get_comment / list_comments: the new params live on the existing tool. The 84/100 tool-cap pressure (matches the manage_database condensation precedent) rules out tool-surface expansion.
Phase 3 — A2A comment-ID propagation convention
When a reviewer posts a review comment, capture the commentId from Phase 1's response. Then send a mailbox message to the PR author (or next reviewer) with the ID in the body:
send_message({
to: '@neo-gemini-pro',
subject: 're: PR #N review cycle 3',
body: 'Approved. Review at PR #N comment 4309098042. Your next iteration: [...]',
relatedTickets: ['#N']
})The recipient extracts comment_id: '4309098042' from the body and calls get_conversation({pr_number: N, comment_id: '4309098042'}) — scales linearly with new-comment count, not cumulative.
Convention documentation: new section .agent/skills/pr-review §9 A2A Hand-off Protocol + symmetric section in pull-request §8.
Acceptance Criteria
Out of Scope
- New tools (
get_comment, list_comments): explicitly rejected due to the 84/100 tool-surface cap and the manage_database condensation precedent. All three phases work through existing tool surface.
- Comment body size reduction (e.g., automatic summarization): orthogonal concern; this ticket is about selective FETCH, not compression.
- Historical backfill of comment IDs for pre-merge PRs: N/A — new behavior is forward-looking.
Avoided Traps
- Rich list-comments surface (
get_comment returning [{commentId, author, createdAt, firstLine}, ...]) was considered as a cheap scan primitive. Rejected: adds a tool, violates tool-cap discipline. Users can call get_conversation({last_n: N}) and parse — marginally more expensive but stays within existing surface.
- Server-side dedup / caching of conversation fetches: caching state across MCP-subprocess restarts is complex; not needed if selective fetch becomes the default reviewer pattern.
Related
- Origin: PR #10269 three-cycle review sequence (2026-04-24)
- A2A substrate: #10145, #10166, #10249, #10250, #10255, #10258, #10259, #10262, #10266 (the 8-PR chain that stabilized mailbox-as-A2A-bridge — this ticket extends that bridge to PR review coordination)
- Tool-surface condensation precedent:
manage_database (replacing start_database + stop_database)
- Parent epic: #9999
Origin Session ID: b02bd06c-a2cb-4aff-8af1-c4f2643c91be
Retrieval Hint: "comment id return selective fetch since_comment_id A2A payload" / "PR review cycle context bloat manage_issue_comment get_conversation"
Context
Surfaced during the PR #10269 three-cycle cross-family review on 2026-04-24. Each review cycle N+1 cost more context than cycle N because
get_conversationreturns the ENTIRE thread every call — my cycle-3 fetch pulled my cycle-1 review (~2K tokens), Gemini's cycle-1 response, my cycle-2 review, Gemini's cycle-2 response, my cycle-3 review, and her final comment. For an Architectural Pillar PR, that's ~15K tokens just to fetch "what's new since last time I looked."The trajectory is worse for A2A: every agent responding to a review thread re-fetches the full history. At epic scale (sub-issues of #9999), this burns cumulative context proportional to review depth × participant count.
The Problem
Three interlocking gaps:
manage_issue_commentreturns{"message": "Successfully created comment on PR #N"}— no comment ID. The agent that just posted can't reference its own comment's canonical URL.get_conversation(pr_number: N)always returns every comment. Nosince_comment_id, nolast_n, nocomment_idfor single-comment lookup.All three are coupled: fixing (1) enables (3), and (2) makes (3) efficient.
The Architectural Reality
ai/mcp/server/github-workflow/— the wrapper that implementsmanage_issue_commentandget_conversationviaghCLI. GitHub's underlying REST API (/repos/{owner}/{repo}/issues/comments) DOES return comment IDs on create and supports per-ID fetch..agent/skills/pr-review/references/pr-review-guide.md— establishes reviewer conventions. Would need a new §9 "A2A Hand-off Protocol" section..agent/skills/pull-request/references/pull-request-workflow.md— same for author-side comment propagation.Tool surface discipline: Current count is 84 tools across 4 MCP servers; hard cap ~100 for many agents (50 recommended). This ticket adds ZERO new tools — enhances existing tool parameters instead. Matches precedent:
start_database/stop_database→manage_database.The Fix
Phase 1 —
manage_issue_commentreturns comment ID oncreate/updateCurrent response shape:
{"message": "Successfully created comment on PR #N"}New response shape:
{ "message": "Successfully created comment on PR #N", "commentId": "4309098042", "url": "https://github.com/neomjs/neo/pull/N#issuecomment-4309098042", "createdAt": "2026-04-23T23:53:17Z" }GitHub REST already returns these fields; the wrapper just passes them through. Backward compatible — existing consumers that only read
messagecontinue to work.Phase 2 —
get_conversationgains three optional parametersget_conversation({ pr_number: N, // existing, required comment_id?: "4309098042", // NEW: fetch ONLY this comment body since_comment_id?: "4309098042", // NEW: fetch everything AFTER this comment last_n?: 3 // NEW: fetch last N comments })Default behavior (all three new params omitted): unchanged — full conversation as today. Backward compatible.
Selector precedence:
comment_id>since_comment_id>last_n> full. Explicit single > time-bounded > count-bounded > everything.One minimalist-tool-surface discussion — decided against splitting into
get_comment/list_comments: the new params live on the existing tool. The 84/100 tool-cap pressure (matches themanage_databasecondensation precedent) rules out tool-surface expansion.Phase 3 — A2A comment-ID propagation convention
When a reviewer posts a review comment, capture the
commentIdfrom Phase 1's response. Then send a mailbox message to the PR author (or next reviewer) with the ID in the body:send_message({ to: '@neo-gemini-pro', subject: 're: PR #N review cycle 3', body: 'Approved. Review at PR #N comment 4309098042. Your next iteration: [...]', relatedTickets: ['#N'] })The recipient extracts
comment_id: '4309098042'from the body and callsget_conversation({pr_number: N, comment_id: '4309098042'})— scales linearly with new-comment count, not cumulative.Convention documentation: new section
.agent/skills/pr-review §9 A2A Hand-off Protocol+ symmetric section inpull-request §8.Acceptance Criteria
manage_issue_commentaction:createresponse includescommentId,url,createdAtfields alongside existingmessage.manage_issue_commentaction:updateresponse includes the same fields.get_conversationacceptscomment_id,since_comment_id,last_noptional parameters with the documented precedence..agent/skills/pr-review/references/pr-review-guide.mdgains a §9 A2A Hand-off Protocol section describing the convention and a worked example..agent/skills/pull-request/references/pull-request-workflow.mdgains a symmetric section for author-side propagation.Out of Scope
get_comment,list_comments): explicitly rejected due to the 84/100 tool-surface cap and themanage_databasecondensation precedent. All three phases work through existing tool surface.Avoided Traps
get_commentreturning[{commentId, author, createdAt, firstLine}, ...]) was considered as a cheap scan primitive. Rejected: adds a tool, violates tool-cap discipline. Users can callget_conversation({last_n: N})and parse — marginally more expensive but stays within existing surface.Related
manage_database(replacingstart_database+stop_database)Origin Session ID:
b02bd06c-a2cb-4aff-8af1-c4f2643c91beRetrieval Hint:
"comment id return selective fetch since_comment_id A2A payload"/"PR review cycle context bloat manage_issue_comment get_conversation"