Repository navigation
Description
Leg of epic #1149 (quota-plane Stage 2). Filed at Drew's direction, 2026-10-29: "there was supposed to be a unification in the 3 quota read methods." There wasn't — three independent quota readers exist today, they resolve credentials three different ways, and they disagree. This issue is the unification leg of #1149; it cross-links the legs it absorbs or depends on rather than replacing them.
The three readers
- OpenChamber web server
/api/quota/*— resolves credentials through the running OpenCode server'sGET /api/credentialprojection (openchamberserver/index.js:1647; projectionserver/lib/opencode/auth.js:91, 203-230, active rows only). openchamber quotaCLI — server-first, with a direct credential-store fallback (openCodeLocalCredentialSource, readingopencode.dbread-only). Built 2026-10-27 under fix(quota-plane): opencode-serve boot verification + quota CLI per-provider resilience (no wholesale transport failure) #1251, which deliberately switches to the store ONLY on transport failure and stamps each rowcredentialSource: server|local.- PM-stack aggregator gatherer (
pm-stack/aggregator/scripts/gather-quota.ts:10-19, 116-149) — readsopencode.dbdirectly, by design, because the server-API path is known to diverge (fix(quota-plane): opencode-serve boot verification + quota CLI per-provider resilience (no wholesale transport failure) #1251), replicates the server's projection itself, and additionally ingests bespoke per-provider file exporters (Meta:pm-stack/meta-exporter/meta-quota-export.mjs). Writesquota-current.jsonon a ~15-minute systemd tick.
Divergence evidence (2026-10-29, same evening, same pools)
- Antigravity: the hub (reader 3) reads the pool fine — state ok, Gemini weekly 4%, Claude weekly 57% @ 2026-10-30T00:15Z. Reader 1 returns
{"ok":false,"configured":false,"error":"Not configured"}. Root cause, pinned in fix(quota): /api/quota/antigravity reports 'Not configured' while the aggregator hub reads the pool fine — dispatcher gate treats a primary pool as unavailable openchamber#858: the server credential projection drops the refresh token that openchamber's antigravity resolver requires (providers/antigravity/auth.js:69-94), while the sibling google provider accepts the same entry with an access token alone — google answeredok:trueon the same server in the same pull. Compounding: the resolver swallows credential-store errors (providers/antigravity/index.js:36-38), so a failed read is indistinguishable from "no login exists." - Meta: the route is verified healthy (opencode#818 closed/completed), but reader 3's private exporter has failed every tick since its last ok tick at 2026-10-29T16:15Z with
subscription-quota: field windowReset not a finite number— one null reset from an inactive window fail-closes the whole export (diagnosed on feat(quota-plane): Meta adapter Phase 1 — laptop-side quota exporter (subscription-quota API, 15-min file export) #1301). The hub's file-export entry reads "unparseable" and its openchamber meta entry carries null percentages on both windows: a primary pool unreadable for 8+ consecutive steward runs. - OpenDesign: absent from the hub entirely until its provider deployed to the laptop instance (Deploy + verify: Open Design quota provider live on the laptop instance (running build predates #497/#520; credential import still owed) openchamber#536; deploy landed 2026-10-29, credential import still owed).
Meanwhile #2135 unified only the consumers — the steward went snapshot-first onto quota-current.json — but the dispatcher still live-probes reader 1, so consumers still disagree about the same pool at the same moment.
Why it matters
The fleet measurement gate forbids placement on a pool without a fresh read ≤60 min old. Every reader disagreement therefore closes a primary pool: Antigravity is the Gemini Flash pool's ONLY source and carries the Claude seats' clean read; Meta is a primary pool. The cost is burn-by-expiry — Antigravity's weekly (4% used on the Gemini tiers) resets Sat Oct 31 8:11 AM CDT largely unspent while OpenCode Go's monthly sits at ~96%. Three readers also means three places for the same bug family to recur (cf. the exporter's sibling defects #2460/#2461/#2470).
Proposed target state
One canonical read module: the direct credential-store read (the semantics reader 3 already implements and reader 2 falls back to) plus the shared provider fetchers, consumed by:
- the OpenChamber server endpoint (no more server-projection-only resolution),
- the CLI (no server-first/store-fallback split — one path, one provenance),
- the gatherer, which keeps its 15-minute tick and file-export ingestion but imports the same read module instead of carrying its own projection logic.
Exception providers fold into the same path where their integration plans allow (#1167/#1301 for Meta, #1169 for Google/Antigravity — this issue absorbs #1169's read-path half; the login/token-capture half stays with #1169). Per-provider error states stay distinct end-to-end: not-configured vs store-read-failure vs provider-error are different facts and must never collapse into one another.
Acceptance criteria
- All three surfaces (server endpoint, CLI, gatherer/hub) return identical windows for the same pool in the same tick, demonstrated on Antigravity, Meta, and one ordinary pool (e.g. ClinePass or OpenCode Go).
- No surface can report
not-configuredfor a credential the direct store read resolves. - Dispatcher, steward, babysitter, and the /quota UI consume one source with identical semantics (the Pool quota steward: consume the compiled hub numbers — probe only stale pools, follow-ups daily #2135 snapshot-first rule extends to the dispatcher's gate).
- A credential-store read failure surfaces as its own error state on every surface, distinct from
not-configured(the fix(id-world): manifest plan leaves omitted grants/ceiling/schedules/profile alone (#817) #858 resolver swallow is gone or subsumed). - The Meta exporter path either folds into the shared module or its parser contract is enforced by the same validation the shared path uses — a single bad field can no longer poison a whole pool's export.
Related
- Epic: epic(quota-plane): Stage 2 — 15-minute quota gathering in the PM stack, token adapters, automated pool decisions #1149 (this issue is its read-path unification leg)
- fix(quota-plane): opencode-serve boot verification + quota CLI per-provider resilience (no wholesale transport failure) #1251 — quota-plane resilience; origin of the known server-vs-store divergence and the CLI fallback
- plan(quota-plane): exception integration — Google/Antigravity (login, token capture, panel API) #1169 — Google/Antigravity exception integration (read-path half absorbed here by reference; token capture stays there)
- plan(quota-plane): exception integration — Meta (login, token capture, console API) #1167 + feat(quota-plane): Meta adapter Phase 1 — laptop-side quota exporter (subscription-quota API, 15-min file export) #1301 — Meta exception integration + exporter (fix expedited 2026-10-29 at priority 90; its parser fix is a down payment on the last acceptance criterion, not a substitute for this issue)
- feat(quota-plane): split gatherer rows per pool — OpenCode Go per-workspace + Antigravity pool grouping for the /quota overlay #1331 — gatherer per-pool row split (the gatherer's row shape this unification must preserve)
- fix(quota): /api/quota/antigravity reports 'Not configured' while the aggregator hub reads the pool fine — dispatcher gate treats a primary pool as unavailable openchamber#858 — the endpoint symptom (Antigravity "Not configured")
- Deploy + verify: Open Design quota provider live on the laptop instance (running build predates #497/#520; credential import still owed) openchamber#536 — OpenDesign deploy/import state
Activity
developing-today commentedon Oct 30, 2026
CODE-1270
dezren39 commentedon Oct 30, 2026
agent-note:v1
Agent: quota-unification-filer
State: filed
Found via: Drew, 2026-10-29 — "there was supposed to be a unification in the 3 quota read methods"
Filed at Drew's explicit direction (2026-10-29 ~20:19 CDT). This is the read-path unification leg of epic #1149: the OpenChamber /api/quota endpoint, the
openchamber quotaCLI, and the pm-stack aggregator gatherer each resolve credentials differently and disagree about live pools — Antigravity blind via the server projection (developing-today/openchamber#858), Meta poisoned in its private exporter (#1301), OpenDesign absent until deployed (developing-today/openchamber#536).Enqueued as a triage task on repo-health-code-pilot. Triage should confirm the shared-module shape (direct credential-store read as canonical, per pm-stack/aggregator/scripts/gather-quota.ts), rule on how #1169's read-path half folds in, and route the phased fix packets. Nothing self-assigned.
dezren39 commentedon Nov 1, 2026
Scope extension + fresh evidence — 2026-11-01 (Drew: "unify 1 quota path for all")
Drew re-issued the unification order tonight after the Command Code meter dispute. #2490 already covers the three readers; tonight's failures show the unification must also cover the consumer side, or the readers can agree and the surfaces still disagree:
pm-stack/aggregator/src/quota-extract.tsregex-parses dated prose out of the stewardship quota view and renders it as current pool state. On 2026-11-01 it presented a week-old Command Code read as current (defect filed separately as Quota reads: Command Code reports plan windows, not the top-up balance (extractor renders stale read) #3410). Under the unified design, the aggregator consumes the canonical record (quota-current.json/ its successor) only; prose extraction is retired as a data path — the view stays a human log.quota-current.json, while the fleet feed's pool mapping shows 84%/87%. One canonical record, one mapping — consumers never re-derive percentages.packages/web/server/lib/quota/providers/command-code.jsbuilds its monthly figure from/alpha/billing/creditsas a balance window (usedPercent: null); only 5h/weekly come fromwindowLimitsas real plan windows. The canonical module needs a plan monthly window for Command Code (console-format: monthly limit % of the $10 included credits).Acceptance addition: with the unified path live, one timestamped read per pool exists at any moment, and the dashboard, feed, steward view, and quota-check all show the same figures for the same pool at the same time (spot-check Command Code + both Go workspaces).
dezren39 commentedon Nov 1, 2026
Drew prioritized this in main chat 2026-11-01 (~02:01 CST) after tonight's Command Code / Go mapping disputes. Queue task 3721 moved from priority 90 (the last band — lower claims first) to priority 10, verified head of repo-health-code-pilot. The 2026-11-01 scope-extension comment above (consumer-side unification, plan-not-balance invariant, #3410) is part of the job.
35 remaining items
developing-today commentedon Nov 3, 2026
agent-note:v1
state: reviewed (coverage loop-back)
Coverage pass 2026-11-03, loop-back review: this issue was re-reviewed (drift / overlap / already-handled / stale / blockers / ordering) so every open issue in the four repos is reviewed and in the system. Verdict: still live; in the system as task 7327 (triage, queued, priority 50) in repo-health-code-pilot. Labels audited and synced. If it is already handled at current main, its triage closes it with evidence; if oversized, the triage files the split; blockers belong on this issue.
Found via: coverage loop-back 2026-11-03
developing-today commentedon Nov 3, 2026
agent-note:v1
state: reviewed (coverage loop-back)
Coverage pass 2026-11-03, loop-back review: this issue was re-reviewed (drift / overlap / already-handled / stale / blockers / ordering) so every open issue in the four repos is reviewed and in the system. Verdict: still live; in the system as task 7327 (triage, queued, priority 50) in repo-health-code-pilot. Labels audited and synced. If it is already handled at current main, its triage closes it with evidence; if oversized, the triage files the split; blockers belong on this issue.
Found via: coverage loop-back 2026-11-03
dezren39 commentedon Nov 3, 2026
Direction update (Drew ruling, 2026-11-03 11:48 CST — ask the OpenCode server, not a proxy/direct read): the aggregator gatherer leg of this unification is now server-first. PR #5062 (merged, e628bee) wires the gatherer with the CLI combined-source shape — openCodeCredentialSource (GET /api/credential on the standing fork server) primary, openCodeLocalCredentialSource only as transport-failure fallback (#1251 preserved, #1268 retention untouched). OpenDesign cannot follow yet: filed precisely as #5060.
dezren39 commentedon Nov 3, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 3, 2026
🤖 Agent note · triage findings (queue task 7327, 2026-11-03)
Verdict: server-first path landed where supported; OpenDesign remains an explicit exception
Fresh state: #2490 is OPEN, with no hard-stop labels. Its original direct-store-canonical framing was superseded by Drew's 2026-11-03 ruling to ask the OpenCode server first. I verified current source/PR state, but did not run a live quota tick or same-tick pool comparison in this triage.
mainat6aeb038a0cd64b5057912edac71d4c2744a8b5d6;pm-stack/aggregator/scripts/gather-quota.ts:673-719, 729-740wiresopenCodeCredentialSourcefirst andopenCodeLocalCredentialSourceonly after transport failure. If both fail, the tick fails loudly and preserves last-known rows. PR feat(quota-gatherer): quota ask terminates at the OpenCode server (server-first credential source) #5062 (mergee628bee) landed the server-first change; earlier aggregator(gatherer): use the shared openCodeLocalCredentialSource instead of the duplicated credential-store read (#2490 phase 3) #3416 is also merged.mainat45b030edf2c5c4a7bcceb10f637d98b7f5884dbc;packages/web/bin/lib/commands-quota.js:404-410uses the server source with local-store fallback. PR feat(aggregator): /program hub + per-project pages for all projects (#1120, #1121) #1142 (merge99bd9fa) fixedusesLocalStoreforwarding; impl(aggregator/collector): Project pool resolves a minority of board/roadmap refs (172 fixture fallbacks) - raise coverage and publish the ratio #1141 is closed.6c5faca) and follow-up id: F12.6 audit log and OpenTelemetry export #1063 are closed. Currentserver/lib/opencode/auth.js:94-140reads from the running OpenCode source;server/lib/quota/providers/antigravity/index.js:52-70gates the local-store fallback to a known-local OpenCode.#2490 stays open until the OpenDesign exception is resolved or explicitly accepted and the remaining parity acceptance is verified. The code paths are merged, but no runtime/same-tick verification was performed here.
dezren39 commentedon Nov 3, 2026
agent-note:v1
state: done (queue task 7327)