Expand description
GitHub PR check-badge resolution for the worktrees tree (#1337).
The engine half of the PR badge, mirroring the crate::worktrees registry /
crate::daemon::services::worktrees adapter split: this module is pure
resolution — build a query, run gh, reduce the reply, cache the result — and
knows nothing about the daemon, the socket, or the tray. The adapter owns the
poll loop and the change-notify.
§Why this lives in the daemon
Badges were resolved extension-side (ADR-0050), which made cost scale with the number of open VS Code windows and — the actual bug — meant nothing ever re-asked GitHub after a badge was first computed. Resolving once in the daemon and fanning the answer out over the existing subscribe stream makes cost invariant to window count and lets an unfocused window show live CI state.
§No credential enters the daemon
Resolution shells out to gh api graphql, so the GitHub token stays inside
gh where the user already put it — exactly as ADR-0050 wanted, and following
ADR-0003’s “shell out to gh/git for GitHub operations”. This is why moving
resolution daemon-side does not widen the worktrees service’s no-credential
posture (ADR-0040): the daemon never sees a token.
§Why one query for everything
repository(owner:,name:) and ref(qualifiedName:) take no first:/last:
argument, so neither is a GraphQL connection and neither contributes to the
query’s cost. Aliasing them is free: one query covering every (repo, branch)
pair the tree knows about costs 1 point against the 5,000/hour budget,
independent of how many repos, worktrees, or windows are open. Measured against
rust-works/omni-dev: cost 1 up to ~50 branches, 2 at 100, 4 at 200.
Two shapes are deliberately avoided:
gh pr list --json statusCheckRollup, which the extension used, is an alias for acommits(last:1)connection — it adds one request per PR and costs 2.checkSuites { checkRuns { totalCount } }is a third-level connection and costs 11.
§The explicit negative (#1370)
Resolution is tri-state per target, not binary. “No open PR heads this branch”
is a successful answer (PrResolution::NoPr), distinct from “never
resolved” (absent from the cache). Absence used to carry both meanings, which
left a client unable to tell “checked, none” from “old daemon that never
checked” — so every window’s degraded gh pr list fallback re-fired per
window × repo × 60s forever, burning the very GraphQL budget this module
exists to protect. A failed poll still reports nothing: negatives are only
ever minted from a successfully parsed reply.
Structs§
- Merge
Info - What the merge-queue op needs to know about a branch’s open PR.
- PrBadge
- The PR badge shown on a worktree row: which PR heads this branch and how its CI is doing.
- PrStatus
Cache - The poller-written, snapshot-read resolution cache.
- PrTarget
- One (repo, branch) pair to resolve a badge for. Derived from the tree — a repo contributes a target per worktree that has a branch.
- Query
Rate Limit - The
rateLimitblock folded into every PR-poll reply (#1389, fix 8).
Enums§
- Enqueue
Outcome - The outcome of a single
enqueuePullRequestmutation. - PrCheck
State - The rolled-up CI verdict for a pull request.
- PrResolution
- The outcome for one successfully checked target (#1370).
Functions§
- enqueue_
pull_ request - Enqueues one PR into its repo’s merge queue via the
enqueuePullRequestmutation. Blocking — run on a blocking thread. - resolve_
gh_ binary - Resolves
gh, preferring [GH_BIN_ENV], then the first existing well-known absolute path, then bareghonPATH. - resolve_
merge_ targets - Resolves merge-queue eligibility facts for every target in one
gh api graphqlcall. Blocking — run on a blocking thread. - resolve_
with - Resolves every target in one
gh api graphqlcall, using theghatbin. - resolve_
with_ budget resolve_withthat also returns the poll’s folded-in graphql budget reading (#1389, fix 8).