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:

#RouteCost
ALower concurrencyDirectly reduces the draw; costs throughput — and you have twice asked for concurrency to stay at 5
BMove 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
CPer-seat identities so the quota is not sharedRemoves the coupling entirely; changes attribution, permissions and the claim-comment discipline that exists because identity is shared
DRate-aware backoff in the seats — check /rate_limit before write bursts, staggerCheap, no infra change; does not add capacity, only stops seats from wasting turns discovering exhaustion
EAccept and document — teach seats to recognise the signatureZero 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)

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