Repository navigation
docs(AGENTS.md): read GitHub through REST, and stop mandating GraphQL - #3287
Merged
Merged
Conversation
Adds the fleet-shared `rest-not-graphql` block plus its manifest entry, and
fixes core's own guidance, which currently mandates the thing the block forbids.
Maintainer directive, 2026-09-04: "everyone should use rest".
The occasion: an agent polling `gh pr view` every 5 s exhausted GitHub's
SECONDARY rate limit for the whole session. The limit is per USER, so every
concurrent agent lost GitHub access, not just the one polling. Two agents
diagnosed it independently, and both were initially misled the same way —
`gh api /rate_limit` reads a pristine 5000/5000 remaining, 0 used while every
GraphQL call is refused with "API rate limit already exceeded". The primary
quota is not the signal; that PAIRING is the signature, so the block states it.
Core's line 102 told you to "Poll the MeshWeaver Build and Test check SUITE by
name via GraphQL", and blamed the alternative on "REST rate-limit 403s". Both
halves were wrong: the poll is exactly the call that exhausts the limit, and
`gh run watch` / `gh pr checks --watch` are GraphQL, not REST. It now names the
REST form:
gh api "repos/Systemorph/MeshWeaver/actions/runs?head_sha=<sha>" filtered on .name
Verified against this org before writing the rule: actions/runs?head_sha
returns the named workflow's status/conclusion, commits/<sha>/check-runs
returned 41 runs, commits/<sha>/check-suites gives per-suite state, and
pulls/<n> gives state/merged/mergeable_state.
The block does NOT forbid GraphQL outright — that would be false guidance. The
merge queue's `dequeuePullRequest` and queue entries have no REST equivalent
and are named as the reserved exception, which is why the merge-queue paragraph
below is unchanged.
Two caveats in the text are measured, not assumed: pulls/<n> answers
mergeable: null / "unknown" until GitHub recomputes after a push; and a check
suite an installed App never posts runs to stays queued forever — Azure Boards
does exactly this on core, which is why the existing "never wait for all
suites" warning is kept and now names it.
Adopted TEXT-FIRST. The six satellites carry the block already (Plugins#1317,
Education#268, Reinsurance#161, SocialMedia#137, Manufacturing#51, Memex#179),
byte-identical under the gate's own normalisation — sha256 0dd144539cdd47f1,
length 1519. This PR adds the manifest entry LAST, because the gate fails RED
for a repo that is listed and has no markers, so a half-landed rollout must not
be able to red the fleet.
🚨 Held as a DRAFT until those six merge: until then this PR's own
`AGENTS.md shared rule blocks` check is correctly red.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The new REST polling guidance introduces SHA placeholders without defining how to obtain them in a REST-only flow, which undermines the goal of avoiding GraphQL usage.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR updates the fleet-wide agent guidance to prefer GitHub REST API usage over GraphQL to avoid triggering GitHub’s secondary rate limits, and registers the new guidance as a shared-rule block for enforcement across repositories.
Changes:
- Replaces core PR-operations guidance to poll CI status via REST rather than GraphQL-based CLI commands.
- Adds a new fleet-shared
rest-not-graphqlshared-rule block toAGENTS.md. - Registers the
rest-not-graphqlblock in.github/shared-rules.jsonso the shared-rule gate can enforce adoption.
File summaries
| File | Description |
|---|---|
| AGENTS.md | Updates CI polling guidance to REST and adds the rest-not-graphql shared-rule block. |
| .github/shared-rules.json | Adds the rest-not-graphql block definition and required repo list to the shared-rule manifest. |
Review details
Suppressed comments (1)
AGENTS.md:129
- Inside the shared
rest-not-graphqlblock, the{sha}placeholder is never defined. Adding a one-liner for how to read it via REST helps keep the whole watcher loop GraphQL-free.
🚨 **Read GitHub through REST, not GraphQL.** GraphQL exhausts first, and the limit that bites is the **SECONDARY** one — `gh api /rate_limit` keeps reporting `5000/5000 remaining, 0 used` while every GraphQL call is refused with *"API rate limit already exceeded"*. The primary quota is therefore NOT the signal; that pairing IS the secondary limit. `gh pr view --json …`, `gh pr checks` and `gh run watch` all issue GraphQL, so a watcher built on them takes the whole session's GitHub access down with it, for every concurrent agent. REST does everything a PR watcher needs: `gh api "repos/{o}/{r}/actions/runs?head_sha={sha}"` filtered on `.name` for one workflow's `status`/`conclusion`; `.../commits/{sha}/check-runs` and `.../commits/{sha}/check-suites` for the checks; `.../pulls/{n}` for `state`, `merged` and `mergeable_state`. Reserve GraphQL for what REST cannot express — merge-queue entries and `dequeuePullRequest` — and never put one in a loop. 🚨 **Fast retries EXTEND a secondary limit**: on a refusal STOP for at least 5 minutes, do not retry, and do not switch to a different GraphQL query hoping it is cheaper. Poll no faster than 60 s and run ONE watcher, not several. Two REST caveats, both measured: `pulls/{n}` answers `mergeable: null` / `mergeable_state: "unknown"` until GitHub recomputes after a push — re-read, never read that as a verdict; and a check SUITE an installed App never posts runs to stays `queued` forever, so wait on the ONE workflow you care about by name, never on all suites.<!-- shared-rule:end rest-not-graphql -->
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| 🚨 **PR capability is CREDENTIAL × REPO — measure it for the repo you are in, never remember it** (`gh api repos/Systemorph/<repo> --jq '.permissions'`; `gh auth status`). The same repo answers differently to two sessions on the same day. **Never reach for `--admin`** — a refusal is information about the gate, not an obstacle to route around; on `FORBIDDEN`, re-authenticate with `! gh auth login`. | ||
|
|
||
| 🚨 **Poll the `MeshWeaver Build and Test` check SUITE by name via GraphQL and merge only on `COMPLETED/SUCCESS`.** Never wait for *all* check suites (an installed App that posts no runs leaves its suite `queued` forever), and never poll with `gh run watch` / `gh pr checks --watch` (REST rate-limit 403s masquerade as CI-red). `Consolidate test results` is the required check and the only one to require. | ||
| 🚨 **Poll the `MeshWeaver Build and Test` workflow by name over REST and merge only on `completed`/`success`** — `gh api "repos/Systemorph/MeshWeaver/actions/runs?head_sha=<sha>"`, filtered on `.name`. Never wait for *all* check suites (an installed App that posts no runs leaves its suite `queued` forever — `Azure Boards` does exactly this here), and never poll with `gh run watch` / `gh pr checks --watch`: both issue GraphQL, and exhausting the SECONDARY limit takes GitHub access away from every concurrent agent while `/rate_limit` still reads `5000/5000`. `Consolidate test results` is the required check and the only one to require. |
Contributor
Contributor
Contributor
Contributor
Contributor
Contributor
Contributor
rbuergi
marked this pull request as ready for review
September 4, 2026 08:12
This was referenced Sep 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the fleet-shared
rest-not-graphqlblock + its manifest entry, and fixes core's contradictory guidanceMaintainer directive, 2026-09-04: "everyone should use rest".
The occasion. An agent polling
gh pr viewevery 5 s exhausted GitHub's secondary rate limit for the whole session. The limit is per USER, so every concurrent agent lost GitHub access — not just the one polling. Two agents diagnosed it independently and both were misled the same way first:The primary quota is not the signal. That pairing is the signature, so the block says so explicitly — anyone who checks the quota otherwise concludes they are not rate-limited and goes looking somewhere else.
Core was mandating the exact call that causes it
Line 102 said: "Poll the
MeshWeaver Build and Testcheck SUITE by name via GraphQL", and blamed the alternative on "REST rate-limit 403s". Both halves were wrong — that poll is the call that exhausts the limit, andgh run watch/gh pr checks --watchare GraphQL, not REST. It now names the REST form:Verified against this org before writing the rule
actions/runs?head_sha=<sha>filtered on.namestatus/conclusioncommits/<sha>/check-runscommits/<sha>/check-suitesstatus/conclusionpulls/<n>state,merged,mergeable_stateThe block does not forbid GraphQL outright — that would be false guidance. The merge queue's
dequeuePullRequestand queue entries have no REST equivalent, so they are named as the reserved exception, and the merge-queue paragraph below is deliberately unchanged.Two caveats in the text are measured rather than assumed:
pulls/<n>answersmergeable: null/"unknown"until GitHub recomputes after a push; and a check suite an installed App never posts runs to staysqueuedforever —Azure Boardsdoes exactly this here, which is why the existing "never wait for all suites" warning is kept and now names it.Rollout: text first, manifest last
The six satellites already carry the block — Plugins#1317, Education#268, Reinsurance#161, SocialMedia#137, Manufacturing#51, Memex#179 — verified byte-identical under the gate's own normalisation (soft-wrap collapsed): sha256
0dd144539cdd47f1…, length 1519.This PR adds the
.github/shared-rules.jsonentry last, because the gate fails RED for a repo that is listed and has no markers. A half-landed rollout must not be able to red the fleet.🚨 Deliberately a DRAFT. Until those six merge, this PR's own
AGENTS.md shared rule blockscheck is correctly red — the manifest lists seven repos and only one has the markers onmain. Marking it ready before then would be asking the queue to merge a known-red change. Draft is also the documented opt-out fromauto-arm.yml.Incidentally:
gh pr createis itself GraphQL and was refused while creating these — all seven PRs were opened over REST (POST /repos/{o}/{r}/pulls), which is the rule demonstrating itself.🤖 Generated with Claude Code