Parent #16136 identified three independent defects in the list_pull_requests board surface. Its
intake correctly found that the timestamp-delta and completeness contracts are not code-ready:
GitHub does not expose historical aggregate reviewDecision / head coordinates at a timestamp, and
a bounded current page cannot truthfully claim exhaustive unlisted membership.
That does not block the first independently useful leaf. The current board response still returns
only:
number, title, url, createdAt, author.login, state
The PR-state freshness gate names state, mergedAt, and reviewRequests; current-head review
work also depends on reviewDecision, headRefOid, and mergeStateStatus. All five facts are
already source-owned GraphQL fields used by the existing merge-readiness projection, but the board
query omits them.
This ticket deliberately splits only that field-parity leaf from #16136. Live duplicate searches
for list_pull_requests mergedAt reviewDecision reviewRequests headRefOid mergeStateStatus and
PR state freshness fields board tool, plus the open PR search, found only #16136 and no competing
implementation.
The Problem
An agent can refresh the whole open-PR board in one call, but cannot tell from that result whether
an open PR still needs review, whether the reviewed head changed, or whether GitHub currently
considers the head clean. Obeying the freshness gate therefore expands back into one
gh pr view <N> / per-PR tool call for every row.
The omission has a second fail-open edge: if reviewer-request data is absent or truncated, projecting
[] would mean “fetched and empty” even though the source was incomplete. The list surface needs the
same null-versus-empty distinction already used by merge-readiness.
Context
Parent #16136 identified three independent defects in the
list_pull_requestsboard surface. Its intake correctly found that the timestamp-delta and completeness contracts are not code-ready: GitHub does not expose historical aggregatereviewDecision/ head coordinates at a timestamp, and a bounded current page cannot truthfully claim exhaustiveunlistedmembership.That does not block the first independently useful leaf. The current board response still returns only:
The PR-state freshness gate names
state,mergedAt, andreviewRequests; current-head review work also depends onreviewDecision,headRefOid, andmergeStateStatus. All five facts are already source-owned GraphQL fields used by the existing merge-readiness projection, but the board query omits them.This ticket deliberately splits only that field-parity leaf from #16136. Live duplicate searches for
list_pull_requests mergedAt reviewDecision reviewRequests headRefOid mergeStateStatusandPR state freshness fields board tool, plus the open PR search, found only #16136 and no competing implementation.The Problem
An agent can refresh the whole open-PR board in one call, but cannot tell from that result whether an open PR still needs review, whether the reviewed head changed, or whether GitHub currently considers the head clean. Obeying the freshness gate therefore expands back into one
gh pr view <N>/ per-PR tool call for every row.The omission has a second fail-open edge: if reviewer-request data is absent or truncated, projecting
[]would mean “fetched and empty” even though the source was incomplete. The list surface needs the same null-versus-empty distinction already used by merge-readiness.The Architectural Reality
ai/services/github-workflow/queries/pullRequestQueries.mjsownsFETCH_PULL_REQUESTS.ai/services/github-workflow/PullRequestService.mjs#listPullRequestsowns the returned board projection.normalizeRequestedReviewer()already provides the canonical user/team reviewer identity shape.ai/mcp/server/github-workflow/openapi.yamlowns the tool and response schema.test/playwright/unit/ai/services/github-workflow/PullRequestService.spec.mjsis the existing service contract suite.learn/agentos/GitHubWorkflow.mdis the existing operator-facing tool catalog..mjsfile, MCP operation, parameter, or server state is required.The Fix
FETCH_PULL_REQUESTSwithmergedAt,reviewDecision,headRefOid,mergeStateStatus, and a boundedreviewRequestsconnection carryingpageInfo.null, never an omitted key.reviewRequestsas:[]when the connection is present, complete, and empty;nullwhen unavailable, truncated, or structurally unknown.Contract Ledger
mergedAt,reviewDecision,headRefOid,mergeStateStatusnullreviewRequestspageInfonull, never[]listPullRequestslimit/stateinputslist_pull_requestsoperationDecision Record impact
none. This is an additive response projection on an existing read operation and uses fields already consumed by the source-owned merge-readiness path.
Acceptance Criteria
mergedAt,reviewDecision,headRefOid, andmergeStateStatus; unavailable scalar values arenull, not omitted.[].null.limit,state, ordering, count, and structured GraphQL-error behavior remain unchanged.Out of Scope
since,arrived,moved, ordepartedprojections.believedOpen, caller-supplied prior coordinates, or exhaustiveunlistedmembership.limitcontract.Avoided Traps
updatedAt.Related
GET_MERGE_READINESS.Origin Session ID: 019fac4d-7844-7422-9486-7f73ccf308f5
Retrieval Hint: "list_pull_requests field parity mergedAt reviewDecision reviewRequests headRefOid mergeStateStatus"
Authored by Emmy (GPT-5.6 Sol Ultra, Codex).