quota: provider-agnostic window model with provenance, merge rule, and linear pace (#725 Part 1)#740
Open
avs-io wants to merge 1 commit into
Open
quota: provider-agnostic window model with provenance, merge rule, and linear pace (#725 Part 1)#740avs-io wants to merge 1 commit into
avs-io wants to merge 1 commit into
Conversation
…d linear pace (getagentseal#725 Part 1)
avs-io
marked this pull request as ready for review
July 18, 2026 03:13
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.
Part 1 of #725, matching the model shape proposed in the epic thread (design comment posted there yesterday).
What changed
src/quota.ts— pure, side-effect-free, no UI, no network. Depends on nothing, per the epic's Part 1 scoping:QuotaWindow(kind, label, usedFraction, resetsAt, windowSeconds) with a per-windowsource: 'live' | 'derived'— provenance is load-bearing: a derived window is an estimate and surfaces must be able to render it as one, same discipline ascostIsEstimated.mergeQuotaWindows(live, derived): live wins per window kind (quotaWindowKeykeeps named and custom kinds distinct); derived fills the gaps; provenance survives on each window.computePace(window, now): whole-window linear pace — expected fraction, delta (deficit/reserve), projected-at-reset, and an exhaustion ETA only when the projection overflows and the window is longer than 6h. Guards: nothing until 3% of the window has elapsed, nothing on reset skew (past, or beyond one window length), nothing on an exhausted window, inputs clamped. Same semantics as the menubar'sQuotaPacein menubar: linear pace on Codex quota windows — deficit/reserve, projection, run-out ETA #728 so surfaces can never disagree about pace.buildPlanQuota(...): assembles the merged, pace-annotated view. A provider with no readings yields an empty windows list — absent data is absent, never zeros.On the open question from the design comment (where live snapshots enter on the CLI side): this lands option (a) — the model takes optional
livewindows as an input and works offline-first from derived data alone; no new network surface, per the epic's non-goals.How tested
npx tsc --noEmitclean; newtests/quota.test.ts: 16 tests, table-driven over the merge rule (live/derived collisions, custom-kind separation, empty sources) and every pace guard and branch (on-pace, deficit ETA landing strictly before reset, reserve, short-window ETA suppression, early-window/skew/exhausted silence, the 6h boundary against the exported constant), injected clock throughout.app/electron/cli.test.tson a fresh clone — the known app/electron/cli.test.ts fails on a fresh clone: dev-resolution tests require a built dist/cli.js #681 issue, and they pass oncenpm run buildproducesdist/cli.js.