Skip to content

[Decision] The shared GitHub identity's GraphQL quota is being burned to 2× — MCP writes go through GraphQL, so seats are silently write-blocked while reads keep working #11742

Description

@os-steve

Filed by the domain:devx PM seat (session session_015ahemw8RcTgqtxrj15PEZx) for maintainer decision. Measured, not inferred.

What was measured

GET /rate_limit on the shared identity, read directly with the environment token at 2026-08-24 14:33:22Z:

graphql   10006/5000   remaining      0   reset 14:40:10Z     <<< EXHAUSTED, 2× over quota
core         35/15000  remaining  14965                        <<< REST essentially untouched
search        0/30     remaining     30

⚠️ used exceeds limit by more than 2×. That is not a seat unlucky at the tail of its budget; it is the whole fleet's hourly GraphQL allowance spent and then spent again.

Why it is invisible until it bites

The MCP GitHub server's writes go through GraphQL; its reads go through REST.

The tell is the error text itself — issue_write fails with failed to get issue ID, because it resolves the issue's GraphQL node ID before it can write. Meanwhile every issue_read, list_issues and pull_request_read kept working normally throughout.

⇒ A seat in this state reads a perfectly healthy repo and cannot change it, and nothing in the read path says so. This session hit it for roughly 9 minutes and it produced a real half-state: issue #11673 carried a comment saying "Closing completed" while its state stayed open, because the comment (REST) landed and the state change (GraphQL) did not.

Why it is a fleet problem, not a seat problem

All AI seats share one GitHub identity (user ID 317605050). The quota is per-identity, so every seat draws on one 5000/hour GraphQL budget, and one seat's burst starves the others. With concurrency at 5 this is structural rather than incidental.

⭐ Same family as #11363 (shared verify-lock contention, measured superlinear in seat concurrency): a cost that only becomes visible once concurrency is raised, and whose symptom is misread as a local failure by the seat that meets it.

What needs deciding

⛔ Every mitigation is a tradeoff that belongs to you, not to a lane PM:

# Route Cost
A Lower concurrency Directly reduces the draw; costs throughput — and you have twice asked for concurrency to stay at 5
B Move MCP writes to REST where the API supports it (the core bucket is at 35/15000 — effectively free) Needs an MCP-server change, outside this repo; largest headroom by far
C Per-seat identities so the quota is not shared Removes the coupling entirely; changes attribution, permissions and the claim-comment discipline that exists because identity is shared
D Rate-aware backoff in the seats — check /rate_limit before write bursts, stagger Cheap, no infra change; does not add capacity, only stops seats from wasting turns discovering exhaustion
E Accept and document — teach seats to recognise the signature Zero cost; the failure keeps happening, but stops being misdiagnosed

What this seat has already done (no decision needed)

Adopted D locally as a discipline, and corrected a rule that was almost right:

This lane's instrument rule said "a rate-limit probe must use a WRITE call, because read-green ≠ write-green." That was right about the symptom and wrong about the cause. The precise version: MCP writes are GraphQL and reads are REST — they are separate quota buckets and must be probed separately. A single /rate_limit read tells you which one is exhausted and exactly when it resets, which is strictly better than retrying blind.

⭐ Worth propagating to other lanes: any seat that concludes "GitHub is down" or "my write failed, I'll retry" on this signature is misreading it.

What I recommend

B if it is reachable, D immediately regardless. B is where the headroom is — the REST bucket is 15000 and effectively unused, so the same work costs nothing there. D is free and stops seats burning turns on blind retries. ⛔ I do not recommend A: you have set concurrency at 5 deliberately, twice, and this is a quota-shape problem rather than a workload-size one.

⛔ Nothing is being changed on this card until you choose.

Refs: #11363 (the sibling concurrency cost, measured) · #11673 (the half-state this produced)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions