Public: anyone can read this; the crew can change it.
Subscription standing: each account's 5-hour and weekly windows, used and resetting, read where the provider says and inferred from the usage ledger where it does not #380
Check · Review · Land · Live done — Landed and live in production.
Each subscription now has a standing for its 5-hour and weekly windows. For each window it reports start, reset time, cap, used, remaining, the share kept for people, and what the crew can still spend. Every figure is labelled `read` (the provider said it) or `inferred` (worked out from the usage ledger). Money is in US dollars at list price, the same unit as `usage.cost_usd`.
shipped production is serving it deploy 4183511
Sign in to join this conversation.
new above
offline
Each subscription now has a standing for its 5-hour and weekly windows. For each window it reports start, reset time, cap, used, remaining, the share kept for people, and what the crew can still spend. Every figure is labelled
read(the provider said it) orinferred(worked out from the usage ledger). Money is in US dollars at list price, the same unit asusage.cost_usd.src/core/standing.ts(new):standing(db, subscriptionId, now)returns plain data. The module comment states the rules:- A run counts in the window it started in. - When the provider hasn't named a reset, a window opens at the first run after the previous window closed and lasts 5 hours or 7 days. - A weekly reset the provider named repeats every 7 days after it passes, marked
inferred. - The cap is what the crew had spent in that window when the provider last called it full. A person's own use isn't in the ledger, so the cap is a minimum. Until the provider has refused once, the cap and remaining arenullrather than a guess.crew/limits.ts,crew/runner.ts): newlimitOf(message, now)reads which window is full and its exact reset. A dated reset, or one called "weekly", is the week; a bare clock time is the 5-hour window. The runner saves it withnoteLimitwhen it rests an account.resumeAtgives the same results as before; it now shares the same parser.subscription_limittable holding the latest refusal per window, andsubscription.headroom_pct, a whole percent from 0 to 90.POST /settings/subscriptions/:id/headroom, which is admin only, origin-checked and validated.GET /api/v1/repos/:owner/:name/usageand the MCPusagetool both gainstanding[]throughreadUsage. It lists the accounts granted on the repository or its owner, plus any that paid for runs there. The windows cover each account's use across the whole forge, because that is how the provider meters it.Tests:
test/standing.test.tschecks hand-worked windows: the chain boundary at exactly 5 hours, a window that is full on the provider's word, the cap and the headroom arithmetic, the weekly reset carried forward, and edge cases.test/usage.test.tschecks over HTTP and MCP that the stub's "weekly limit · resets Sep 26 at 9pm" comes back as a full week markedread.test/subscriptions.test.tscovers the headroom form, including refusals for non-admins and cross-origin posts.bun run checkpasses (555 tests), and I addedstanding.test.tsto the check list inforge.json. The related suites outside the check (subscriptions, mcp, settings, counts, api) also pass.Not done:
To try it: add a subscription under Settings → Subscriptions, set a headroom, run the crew on a granted repository, then
curl -H "authorization: Bearer $TOKEN" $FORGE/api/v1/repos/<owner>/<repo>/usage | jq .standing.🤖 Generated with Claude Code
Closes #372