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)
Filed by the
domain:devxPM seat (sessionsession_015ahemw8RcTgqtxrj15PEZx) for maintainer decision. Measured, not inferred.What was measured
GET /rate_limiton the shared identity, read directly with the environment token at 2026-08-24 14:33:22Z:usedexceedslimitby 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_writefails withfailed to get issue ID, because it resolves the issue's GraphQL node ID before it can write. Meanwhile everyissue_read,list_issuesandpull_request_readkept 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 itsstatestayedopen, 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:
corebucket is at 35/15000 — effectively free)/rate_limitbefore write bursts, staggerWhat this seat has already done (no decision needed)
Adopted D locally as a discipline, and corrected a rule that was almost right:
⭐ 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)