LearnNewsExamplesServices
Frontmatter
id16191
titleFalsify believed-open PR membership in list_pull_requests
stateClosed
labels
enhancementaitestingarchitecturemodel-experience
assigneesneo-gpt-emmy
createdAtJul 30, 2026, 10:29 PM
updatedAtJul 30, 2026, 11:06 PM
githubUrlhttps://github.com/neomjs/neo/issues/16191
authorneo-gpt-emmy
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 30, 2026, 11:06 PM

Falsify believed-open PR membership in list_pull_requests

Closed Backlog/active-chunk-11 enhancementaitestingarchitecturemodel-experience
neo-gpt-emmy
neo-gpt-emmy commented on Jul 30, 2026, 10:29 PM

Context

Parent #16136 was created after a stale board claim said four pull requests remained merge-eligible when three had already merged. Its first code-ready leaf, #16165 / PR #16170, now gives every list_pull_requests row the current merge, review-request, head, and merge-state fields.

The remaining parent prescription is still too broad. Live source and Euclid's intake comment on #16136 prove that a timestamp cannot reconstruct historical aggregate reviewDecision or headRefOid, and a bounded open page cannot truthfully derive exhaustive unlisted membership. Neither updatedAt nor an empty delta may substitute for unavailable history.

This leaf keeps only the mechanism that directly falsifies the motivating claim: submit the exact PR numbers currently believed open and read their current membership in one source-owned operation.

Fresh duplicate sweep on 2026-07-30:

  • live latest-20 open issues and GitHub title/body search found #16136 only;
  • open-PR search found no competing branch;
  • repository issue/discussion archive and Knowledge Base search confirmed #16136 is the broad parent, while #16165 explicitly leaves this leaf out of scope;
  • current A2A last-30 claim sweep found no competing implementation claim;
  • npm run --silent ai:structure-map -- --files --loc confirms the existing owners remain ai/mcp/server/github-workflow and ai/services/github-workflow; no new .mjs file or subsystem is needed.

The Problem

The widened board can tell an agent what is open now, but it still cannot mechanically refute the list the agent is about to repeat. A caller who believes [16129, 16133, 16134, 16135] are open must compare that memory against current rows by hand. That manual subtraction is the step that failed in #16136's incident.

Coupling the belief check to state or limit would reproduce the defect: a believed PR outside the returned open page is neither proven terminal nor proven missing. Adding unlisted would overclaim board completeness unless the whole open connection were exhausted. Adding since / moved would overclaim historical coordinates GitHub does not expose at a timestamp.

The Architectural Reality

  • list_pull_requests is already the owning MCP operation; no new tool is warranted.
  • FETCH_PULL_REQUESTS and PullRequestService.listPullRequests() own the current snapshot.
  • GitHub's repository GraphQL object can resolve multiple validated pullRequest(number: N) fields under aliases in one request. The exact submitted numbers therefore need neither server state nor a per-PR network loop.
  • GraphqlService.query() already supports aliased partial-data semantics, but a missing/inaccessible pull request normally resolves to null; the projection must preserve that as explicit uncertainty rather than silently dropping the number.
  • The current default call shape delivered by #16170 must remain unchanged when no belief is supplied.

The Fix

  1. Add optional believedOpen: number[] to list_pull_requests, bounded to 100 unique positive integers. Over-cap input is rejected before GitHub I/O; the service never truncates or silently partitions the coordinate.

  2. When absent, execute the existing query and return the existing response byte-for-byte in behavior.

  3. When present, build one GraphQL request containing:

    • the existing bounded board connection; and
    • one alias per validated believed number, returning number, state, and mergedAt.
  4. Add an opt-in response projection:

       {
        checkedAt: '2026-07-30T…Z',
        belief: {
            stillOpen: [16133],
            falsified: [
                {number: 16129, state: 'MERGED', mergedAt: '…'}
            ],
            unverifiable: [
                {number: 999999, reason: 'not-found-or-inaccessible'}
            ]
        }
    }
  5. Keep this projection independent of state and limit: submitted numbers are resolved directly, not inferred from board-page absence.

  6. Document the opt-in capability in x-neo-tool-summary and the operation description within the existing tool-description budgets.

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
believedOpen input caller's explicit current belief up to 100 unique positive PR numbers invalid shape rejects before GitHub I/O OpenAPI summary + description validation matrix
Belief source read GitHub repository PR resolver one batched GraphQL request resolves every submitted number directly null/inaccessible alias becomes explicit unverifiable result operation description captured-query + missing-row fixture
stillOpen current GitHub PR state contains submitted numbers whose exact row is OPEN never inferred from bounded board membership response schema open/terminal mixed fixture
falsified current GitHub PR state / mergedAt only observed terminal rows carry state + merge timestamp unavailable observation never masquerades as refutation response schema merged/closed fixture
unverifiable null or inaccessible direct alias unresolved numbers carry explicit reason without changing the caller belief no submitted number is dropped or falsely refuted response schema missing/inaccessible fixture
checkedAt service clock after the combined read emitted only with the opt-in belief projection absent on the unchanged default shape response schema ISO timestamp assertion
Default list response #16165 / PR #16170 unchanged when believedOpen is absent existing structured GraphQL error existing docs exact regression assertion
Tool-description budget OpenAPI summary tiers caller can discover believedOpen without a new operation no catalog growth x-neo-tool-summary + description tool-limit/catalog tests

Acceptance Criteria

  • list_pull_requests accepts optional believedOpen with at most 100 unique positive integers and rejects invalid input before GitHub I/O.
  • With believedOpen absent, the captured query, variables, and returned response remain unchanged from PR #16170.
  • With believedOpen present, one GraphQL call resolves the board and every submitted number; no per-PR network loop or server state is introduced.
  • Every submitted currently-open number appears exactly once in belief.stillOpen.
  • Every submitted terminal number appears exactly once in belief.falsified with current state and mergedAt (null when closed-unmerged).
  • A missing or inaccessible number appears exactly once in belief.unverifiable with reason not-found-or-inaccessible; it is never silently dropped or reported as falsified.
  • Every submitted number appears exactly once across stillOpen, falsified, and unverifiable.
  • belief classification is independent of the board state and limit; page absence is never used as terminal evidence.
  • The opt-in response includes an ISO checkedAt; the default response does not gain it.
  • x-neo-tool-summary names believedOpen within 120 characters and the full description remains within 1,024 characters.
  • The MCP operation count does not grow; OpenAPI/tool registration tests remain green.
  • No since, arrived, moved, departed, or unlisted claim enters this leaf.

Out of Scope

  • Timestamp-based history or reconstructing earlier head/review coordinates; current head staleness is already observable through the existing headRefOid field.
  • Exhaustive current-open pagination or unlisted membership.
  • Changing the board's state, limit, ordering, or default response.
  • Server-side/per-identity watermarks.
  • Rewriting the freshness skills; parent #16136 retains that final alignment after the instrument shape converges.
  • A new board/overview MCP operation.

Avoided Traps

  • Infer falsification from board absence: a bounded page cannot prove terminal state.
  • Treat inaccessible as falsified: lack of an observation cannot refute a caller belief.
  • Add unlisted: exhaustive complement requires exhausting the current-open connection.
  • Call each PR separately: recreates the N-call cost that made the freshness gate easy to skip.
  • Use updatedAt for moved: unrelated comments and metadata advance it.
  • Add server memory: makes identical calls non-idempotent and hides the caller coordinate.
  • Change the default shape: forces all consumers to pay for an opt-in falsifier.

Decision Record impact

None. This is an additive, stateless projection on the existing GitHub Workflow read operation, aligned with #16126's derive-from-caller-coordinate precedent and the no-new-tool constraint in #16136.

Related

Narrow leaf of #16136 · field-parity predecessor #16165 / PR #16170 · source-owned projection precedent #16029 / PR #16126.

Origin Session ID: b1ebc46a-5a83-496c-aa8b-385af785e9cb

Retrieval Hint: list_pull_requests believedOpen batched aliases exact membership falsified no unlisted no since

Authored by Emmy (GPT-5.6 Sol Ultra, Codex)

tobiu referenced in commit d21f273 - "feat(github): classify believed-open pull requests (#16191) (#16192)" on Jul 30, 2026, 11:06 PM
tobiu closed this issue on Jul 30, 2026, 11:06 PM