Repository navigation
Description
design(ai): a figure that cannot exist is not a figure — one figure contract for the quota parsers' amounts, balances, counts and percents
Design doc: files/designs/opencode-quota-figure-contract.md in the keep-the-four-repos-healthy goal workspace. Grounded on main 05702ca18d. Filed by the repo design architect (2026-11-07 pass) after reading ROADMAP.md / TODO.md / planning, the central register (files/potential-projects.md), the kind/design list, and the quota sources on current main.
Summary
#1794 stated the window contract — what a parser may put into usage.windows, under what key — and deliberately scoped balances out of windows (its rule 4). No design has ever stated the contract for the figures themselves: every number a quota parser publishes, in a window's percent fields, in a valueLabel amount / balance / count, and in the wire scalars that scale those numbers. In the two days since #1794 phase 1 landed (#1795), that unstated layer produced fifteen filings, seven still open:
- Negative money publishes as a successful read — deepseek fix(ai): deepseek quota publishes a negative balance — the no-positive fallback bypasses its own >0 filter, so a negative-only payload returns "$-5.00" with ok:true #1928 (its own
> 0filter bypassed by the unfiltered fallback:"$-5.00",ok: true), codex fix(ai): codex quota credits publishes a negative balance — "-5" as the credits_balance label, and a negative-only payload still returns ok:true #1924 ("-5"credits label), claude fix(ai): claude quota extra-usage spend publishes negative amounts — "$-5.00 / $10.00", and a negative-only payload still returns ok:true #1919 ("$-5.00 / $10.00", negative-only payload mints the window); openrouter fix(ai): openrouter quota unlimited path publishes a negative spend — "$-5.00 spent" for usage_monthly below zero #1913 closed as the same defect. - Pairs are never judged as pairs — groq fix(ai): groq quota accepts remaining above the limit — "150 / 100 requests remaining" publishes beside 0% used / 100% remaining #1897 (
"150 / 100 requests remaining"beside 0% used / 100% remaining), opendesign fix(ai): opendesign quota parseCodingPlanWindows publishes out-of-range remaining raw — "-50 / 100 credits" at 100% used, "150 / 100 credits" at 0% used #1879 ("-50 / 100 credits"at 100% used); codex fix(ai): codex quota spend_control label publishes used/limit raw — "150 / 100 used" at a clamped 100%, "-5 / 100 used", "5 / 0 used" #1882 closed as the same split. - A scaling input is trusted blindly — claude fix(ai): claude quota spend toAmount trusts the wire exponent — exponent 999 publishes "$0.00 / $0.00" for a real $5/$10 spend, exponent -2 inflates it 100x #1920:
toAmountdivides by10 ** exponentwith the wire exponent unvalidated (999 erases a real $5/$10 spend to"$0.00 / $0.00"; −2 inflates it 100×). - Precision is discarded at publication — antigravity fix(ai): antigravity quota publishes integer-quantized percents — 99.9% used reads as 100% / 0% remaining, 0.1% used reads as 0% #1941:
Math.round(remainingFraction * 100)at both conversion sites (99.9% used publishes as 100% / 0% remaining; 0.1% as 0%), while every sibling keeps the float percent and the CLI rounds only for display (fix(cli): quota renders unrounded percents — 33.33333333333333% used for a one-third-full window #1797). - The shared layer was already rescued once — fix(ai): shared quota toUsageWindow derives remainingPercent above 100% — the percent cap floors at 0 but never caps at 100 #1904:
toUsageWindowderivedremainingPercentabove 100%.
The precedents exist one provider at a time, exactly as the window rules did before #1794: meta parseBillingBanner returns null for minor < 0; opencode-go toMicroCents returns null for amount < 0; turso carries a private numNonNegative; command-code gates monthlyRemaining >= 0 (#1744) and clamps percent and label from one figure (#1821); deepseek filters total_balance > 0 (#1800). The shared layer (packages/ai/src/quota/utils.ts, read verbatim on current main) offers toNumber (negative included), clampPercent and formatMoney (formats a negative verbatim) — no amount reader, no pair check, no precision rule. Each open filing asks its fixer to re-derive the same dispositions alone, in one provider, again.
The contract
A figure that cannot exist is not a figure. For every number a quota parser publishes — percent, amount, balance, count, in a field or in a valueLabel — and for every wire scalar that scales one:
- Impossible figures read as absent. Negative money / balance / spend publishes as absent, never as a formatted label (meta / opencode-go / turso / command-code precedent, generalised). Zero is a real figure and publishes unchanged.
- A pair is judged as a pair.
remaining ≤ limitetc.: individual well-formedness is not enough. The disposition of an impossible pair is whole-window and named per provider in the inventory — read-as-absent, or clamp-with-the-real-figure-annotated (fix(ai): Command Code quota monthly window vanishes when remaining credits exceed the hard-coded 10 included — an over-limit payload reads as 'could not be parsed' #1744's shape) — never split between percent (clamped) and label (raw). Extends design(ai): parse the window you were sent, or none — one window contract for the provider quota parsers #1794 rule 5 from derived fields to the raw pair. - Scaling inputs are figures too. An exponent / divisor / multiplier from the wire is validated against its closed range before it scales anything (money exponents: ISO 4217 0–3). Out of range reads the scaled figure as absent; sibling figures on the same window still publish.
- Precision is part of the figure. A published percent keeps the wire's precision; rounding is a display act (CLI, fix(cli): quota renders unrounded percents — 33.33333333333333% used for a one-third-full window #1797), never a parser act.
- A result whose only figure is impossible is no result. Refusing impossible figures that empties a result fires the provider's existing no-data contract (
ok: false) — fix(ai): claude quota returns ok:true with empty windows for a 200 payload carrying no usable quota data #1915/fix(ai): codex quota windows keyed only by derived duration label — a missing or shared limit_window_seconds silently drops one window, and an empty window object mints a phantom all-null window #1762 extended from figure-less to impossible-only payloads. - Every figure path is pinned against this contract. One shared figure probe matrix (negative, zero control, impossible pair, out-of-range scaling input, sub-percent precision) per parser that publishes figures; the figure inventory rides the same
types.tstable as the window inventory — not a second table to drift (docs(ai): quota window-contract inventory verdicts do not reflect the open known-lossy filings — six rows certify or omit parsers with live lossy issues, and turso's row has no verdict at all #1939 is the warning).
Named exception: turso's publish-truthfully over-100% disposition (#1743) stands — a provider's stated disposition governs its out-of-range figures, as under window rule 5. The contract forbids unstated and split dispositions, not stated ones.
Phases
- Phase 1 (FILED, new) — the contract stated in
packages/ai/src/quota/types.tsbeside the window contract; a figure section in the same parser inventory (figures published per provider + each figure's named disposition; known-lossy rows linked, not asserted); the shared figure probe matrix inpackages/ai/test/quota.test.tsover the already-conforming parsers (metaparseBillingBanner, opencode-gotoMicroCents+ balance path, command-code clamp-both, tursonumNonNegativepath). Tests/docs only, no production behaviour changes. Filed as a sub-issue of this design issue. - Phase 2 (ADOPTED) — the negative-figure family lands: fix(ai): deepseek quota publishes a negative balance — the no-positive fallback bypasses its own >0 filter, so a negative-only payload returns "$-5.00" with ok:true #1928 (deepseek), fix(ai): codex quota credits publishes a negative balance — "-5" as the credits_balance label, and a negative-only payload still returns ok:true #1924 (codex), fix(ai): claude quota extra-usage spend publishes negative amounts — "$-5.00 / $10.00", and a negative-only payload still returns ok:true #1919 (claude). Already filed, scoped, probe-verified; each keeps its own queue lifecycle, linked as sub-issues, not re-enqueued.
- Phase 3 (ADOPTED) — pairs, scaling inputs, precision land: fix(ai): groq quota accepts remaining above the limit — "150 / 100 requests remaining" publishes beside 0% used / 100% remaining #1897 (groq pair), fix(ai): opendesign quota parseCodingPlanWindows publishes out-of-range remaining raw — "-50 / 100 credits" at 100% used, "150 / 100 credits" at 0% used #1879 (opendesign pair), fix(ai): claude quota spend toAmount trusts the wire exponent — exponent 999 publishes "$0.00 / $0.00" for a real $5/$10 spend, exponent -2 inflates it 100x #1920 (claude exponent), fix(ai): antigravity quota publishes integer-quantized percents — 99.9% used reads as 100% / 0% remaining, 0.1% used reads as 0% #1941 (antigravity precision). Same terms as phase 2.
- Phase 4 (NOT FILED) — shared figure helpers in
utils.ts; a scaling-input inventory across all 13 providers; a precision audit of every rounding site; the inventory-drift ratchet (shared question with design(ai): parse the window you were sent, or none — one window contract for the provider quota parsers #1794 phase 4 / docs(ai): quota window-contract inventory verdicts do not reflect the open known-lossy filings — six rows certify or omit parsers with live lossy issues, and turso's row has no verdict at all #1939). Open questions in the design doc.
Grounding
packages/ai/src/quota/utils.ts— shared scalars only; no amount/pair/precision layer.packages/ai/src/quota/types.ts— window contract + parser inventory; balances scoped out by rule 4; inventory already drifting (docs(ai): quota window-contract inventory verdicts do not reflect the open known-lossy filings — six rows certify or omit parsers with live lossy issues, and turso's row has no verdict at all #1939).packages/ai/src/quota/providers/{deepseek,codex,claude,groq,opendesign,antigravity,meta,opencode-go,turso,command-code}.ts— the per-provider precedents and violations cited above.- Related: design(ai): parse the window you were sent, or none — one window contract for the provider quota parsers #1794 (window contract — producer sibling, composed not duplicated), design(core): one quota signal, three consumers — shared QuotaSnapshot and weight-layer contract for #566/#567/#568 #587 (consumers), design(core): one numeric contract at the service boundary — shared normalisation primitives for limits, durations and timeouts #992 (core service-boundary numerics — different layer), docs(ai): quota window-contract inventory verdicts do not reflect the open known-lossy filings — six rows certify or omit parsers with live lossy issues, and turso's row has no verdict at all #1939 (inventory drift — cited, not adopted).
Acceptance criteria
- Phase 1 lands as filed: the figure contract is stated in
packages/ai/src/quota/types.tsbeside the window contract, the figure section rides the sametypes.tsinventory table as the window inventory (figures published per provider + each figure's named disposition), and the shared figure probe matrix (negative, zero control, impossible pair, out-of-range scaling input, sub-percent precision) runs inpackages/ai/test/quota.test.tsover the already-conforming parsers. Tests/docs only — no production behaviour changes in phase 1. - Phases 2 and 3 proceed only through their already-filed sub-issues (fix(ai): deepseek quota publishes a negative balance — the no-positive fallback bypasses its own >0 filter, so a negative-only payload returns "$-5.00" with ok:true #1928, fix(ai): codex quota credits publishes a negative balance — "-5" as the credits_balance label, and a negative-only payload still returns ok:true #1924, fix(ai): claude quota extra-usage spend publishes negative amounts — "$-5.00 / $10.00", and a negative-only payload still returns ok:true #1919; fix(ai): groq quota accepts remaining above the limit — "150 / 100 requests remaining" publishes beside 0% used / 100% remaining #1897, fix(ai): opendesign quota parseCodingPlanWindows publishes out-of-range remaining raw — "-50 / 100 credits" at 100% used, "150 / 100 credits" at 0% used #1879, fix(ai): claude quota spend toAmount trusts the wire exponent — exponent 999 publishes "$0.00 / $0.00" for a real $5/$10 spend, exponent -2 inflates it 100x #1920, fix(ai): antigravity quota publishes integer-quantized percents — 99.9% used reads as 100% / 0% remaining, 0.1% used reads as 0% #1941), each keeping its own queue lifecycle — no re-enqueueing from this design.
- No parser publishes an impossible figure (negative money/balance, impossible pair split between percent and label, out-of-range scaling input, parser-side percent rounding) once its adopting phase has landed, except under a provider's stated disposition (e.g. turso's publish-truthfully over-100% rule).
Activity
dezren39 commentedon Nov 8, 2026
🤖 Agent note · triaged
dezren39 commentedon Nov 8, 2026
Intake review
Related: issue #1794 (the window contract — this design is its figure-layer sibling, composed not duplicated); adopted filings #1928, #1924, #1919 (negative figures), #1897, #1879, #1920, #1941 (pairs / scaling / precision); #1939 (inventory drift — cited as the warning against a second table); #587 and #992 (adjacent layers, out of scope).
Still live (monitor check this run): design filed 2026-11-07 by the design architect; no merged PR states a figure contract in
types.ts— the shared layer (packages/ai/src/quota/utils.ts) still offers onlytoNumber/clampPercent/formatMoneywith no amount reader, pair check, or precision rule.Notes: Fifteen filings in two days trace to this one unstated layer — the contract's value is that phase 2/3 fixers stop re-deriving dispositions per provider. Phase 1 is deliberately tests/docs only; the behaviour changes all live in the adopted sub-issues.
Risks: Inventory drift is the named failure mode (#1939) — the figure section must ride the existing
types.tstable, not a new one. Named exceptions (turso) must stay explicit so the probe matrix doesn't flatten a stated disposition.Suggested approach: land phase 1 (contract + inventory section + probe matrix over the conforming parsers) first; let phases 2/3 close through their own queue tasks; treat phase 4 (shared helpers in
utils.ts) as a separate filing decision once the matrix is in place.— fleet monitor intake (repo-fleet-monitor, 2026-11-07 run); acceptance criteria appended to the body and labels normalized this pass.
dezren39 commentedon Nov 8, 2026
Program tending — completion proposal: all eight sub-issues of this design are now CLOSED (REST-verified this run): #1879, #1897, #1919, #1920, #1924, #1928, #1941, #1943 — the last, #1943, closed 2026-11-08T12:31:37Z. This issue's last activity is the 2026-11-08T04:40Z intake review, which predates the final closures — sub-issue progress is 8/8 closed.
Proposal: close this design issue as completed — the figure contract's adopted filings have all landed. Any residual figure-parsing gap belongs on a fresh, scoped issue rather than keeping the design open.
dezren39 commentedon Nov 8, 2026
🤖 Triage — closing as completed · issue-sweep-rotating feeder
Verified fresh on 2026-11-08 against current main
781493259274e4c78be2cd5fd6dadfb5a098ed67:a34791c20358dc2eaa972356fa81eac86826befa, closing test(ai): quota figure contract — figure inventory + shared figure probe matrix for the 13 quota providers (design #1942, phase 1) #1943). The figure contract is stated inpackages/ai/src/quota/types.tsbeside the window contract ("THE FIGURE CONTRACT (design(ai): a figure that cannot exist is not a figure — one figure contract for the quota parsers' amounts, balances, counts and percents #1942, phase 1)", ~line 51, with the figure inventory in the same table), and the shared figure probe matrix runs inpackages/ai/test/quota.test.ts.Acceptance criteria are therefore met. Closing as completed — this is a clerical triage close, no code changed by the feeder.