LearnNewsExamplesServices
Frontmatter
id16165
titleExpose PR-state freshness fields in list_pull_requests
stateClosed
labels
enhancementdeveloper-experienceaimodel-experience
assigneesneo-gpt-emmy
createdAtJul 30, 2026, 1:13 PM
updatedAtJul 30, 2026, 2:09 PM
githubUrlhttps://github.com/neomjs/neo/issues/16165
authorneo-gpt-emmy
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 30, 2026, 2:09 PM

Expose PR-state freshness fields in list_pull_requests

Closed Backlog/active-chunk-11 enhancementdeveloper-experienceaimodel-experience
neo-gpt-emmy
neo-gpt-emmy commented on Jul 30, 2026, 1:13 PM

Context

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.

The Architectural Reality

  • ai/services/github-workflow/queries/pullRequestQueries.mjs owns FETCH_PULL_REQUESTS.
  • ai/services/github-workflow/PullRequestService.mjs#listPullRequests owns the returned board projection.
  • normalizeRequestedReviewer() already provides the canonical user/team reviewer identity shape.
  • ai/mcp/server/github-workflow/openapi.yaml owns the tool and response schema.
  • test/playwright/unit/ai/services/github-workflow/PullRequestService.spec.mjs is the existing service contract suite.
  • learn/agentos/GitHubWorkflow.md is the existing operator-facing tool catalog.
  • No new .mjs file, MCP operation, parameter, or server state is required.

The Fix

  1. Extend FETCH_PULL_REQUESTS with mergedAt, reviewDecision, headRefOid, mergeStateStatus, and a bounded reviewRequests connection carrying pageInfo.
  2. Project every field on every list row. Scalar absence becomes null, never an omitted key.
  3. Project reviewRequests as:
    • [] when the connection is present, complete, and empty;
    • normalized reviewer identities when present and complete;
    • null when unavailable, truncated, or structurally unknown.
  4. Extend the OpenAPI response schema and the existing GitHub Workflow catalog entry.
  5. Pin populated, null, empty, and truncated behavior in the existing service unit suite.

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
Board scalar fields GitHub PR GraphQL node Always emit mergedAt, reviewDecision, headRefOid, mergeStateStatus Source absence → null OpenAPI + tool catalog Populated/null unit cells
reviewRequests GitHub reviewer-request connection + pageInfo Complete source → normalized array Missing/truncated/unknown source → null, never [] OpenAPI + tool catalog Empty/populated/truncated unit cells
Existing list semantics listPullRequests limit / state inputs Preserve ordering, filtering, count, and error shape Existing structured GraphQL error Existing operation description Captured variables + regression assertion
MCP catalog Existing list_pull_requests operation Same operation count; additive response fields only N/A Existing operation/schema Tool-limit/catalog regression remains green

Decision 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

  • Every returned PR row contains mergedAt, reviewDecision, headRefOid, and mergeStateStatus; unavailable scalar values are null, not omitted.
  • A complete reviewer-request connection returns normalized reviewer identities, including the existing user/team distinction.
  • A complete empty reviewer-request connection returns [].
  • A missing, truncated, or structurally unknown reviewer-request connection returns null.
  • Existing limit, state, ordering, count, and structured GraphQL-error behavior remain unchanged.
  • The OpenAPI schema documents the additive fields and the null-versus-empty reviewer contract.
  • The GitHub Workflow catalog states that the board rows carry current review/head/merge fields.
  • Focused service units pin populated, absent, empty, and truncated cells.
  • No MCP operation, request parameter, watermark, or server-side state is added.

Out of Scope

  • since, arrived, moved, or departed projections.
  • believedOpen, caller-supplied prior coordinates, or exhaustive unlisted membership.
  • Pagination or changing the current limit contract.
  • Rewriting either freshness-gate skill; #16136 retains that alignment work.
  • Adding a second board/overview tool.

Avoided Traps

  • Do not present a bounded page as an exhaustive board.
  • Do not infer historical head or review-decision state from updatedAt.
  • Do not map unavailable or truncated reviewer data to an empty array.
  • Do not reuse the heavier merge-readiness query with commit checks for a list projection that needs only PR-row fields.
  • Do not add a new MCP operation for additive fields.

Related

  • Narrow child of #16136.
  • Projection precedent: #16126.
  • Existing merge-readiness field owner: 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).

tobiu referenced in commit 768e5a6 - "feat(github-workflow): expose PR board freshness fields (#16165) (#16170) on Jul 30, 2026, 2:09 PM
tobiu closed this issue on Jul 30, 2026, 2:09 PM