feat(usage): unify subscription quota readings across federated instances - #6114
Merged
Conversation
…nces A subscription is one account across every federated install, but each machine could only read the quota panel of its own local CLI — so every subscription card was a partial view captioned "Local sessions only — does not include other devices or claude.ai." The federation already carries this user's other devices. Each instance's last quota reading now rides the `usage` sync category alongside its usage digest, and the cards are unified before they render: account-wide meters take the freshest reading per limit key (summing them would multiply one allowance), while per-machine activity counts sum. A card this machine could not read — a logged-out CLI, a scrape in flight — is filled from a peer that read the same account. Instances marked as paying API rates are excluded, since they meter a different account, and a single-machine install is unchanged, caption included. The Usage page card now says how many instances it combined and names them, replacing the CLI's local-only wording. Claude-Session: https://claude.ai/code/session_016Co1zj9L1cEMNmudHWZGaN
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.
Summary
Subscription usage cards said "Local sessions only — does not include other devices or claude.ai." But a subscription is one account across every federated instance, and PortOS already federates usage data — the other devices are right there. Each install could only read its own local CLI's quota panel, so every card was a partial view of a shared allowance.
Each instance's last quota reading now rides the
usagesync category alongside its usage digest, and the cards are unified before they render.Two merge rules, because the halves of a card mean different things:
limits(the meters) are account-wide — every machine reads the same server-side allowance, just at a different moment. The freshest reading per limit key wins; summing them would multiply one allowance by the number of machines that looked at it.activity(requests/sessions) is per-machine — exactly what the provider's caption is about — so those sum.metrics[]stays local: its values are prose ("3 renders · 24h"), not addends.Also:
Mechanics: the readings live in an in-memory SWR cache (a reading costs a 10-20s CLI/TUI spawn) which can't be federated — it dies with the process, and the category's checksum keys on file fingerprints.
services/providerQuotaShare.jspersists them todata/provider-quotas.json, added toUSAGE_CHECKSUM_PATHSand folded into the entry'scapturedAtso a quota refresh with no new AI runs still advances the slot a peer pulls. The write is skipped when a card's claim is unchanged, so a page poll doesn't hand peers a new slot that says nothing new.Nothing here reads a provider — the AI Provider Usage Policy holds; this only records and forwards what a user-triggered reading already produced. Peer payloads are rebuilt to the wire shape on arrival, same recursion-depth reason as the usage digest.
ADR amended:
docs/decisions/2026-09-01-federated-usage-metrics.md.Test plan
server/lib/fleetQuotas.test.js(new, 11 cases) — sanitization drops unmergeable input and strips unknown fields; freshest-meter-wins vs summed-activity; local reading holds a tie; peer-only window appended; an unreadable local card filled from a peer; no card invented for a disabled family; note wording and name-list collapse.server/services/peerUsage.test.js(+5 cases) — readings publish under this instance and advance the LWW stamp; an unchanged claim is not re-recorded; a narrowed read merges rather than retiring skipped families; peer payloads rebuilt to the wire shape; API-billed instances excluded.client/src/pages/UsagePage.test.jsx(+2 cases) — the fleet pill names contributors; absent on a single-machine install.38617 passed | 14 skipped, client10208 passed | 2 skipped. Lint clean.agy(Gemini 3.8 Flash, low effort): NO FINDINGS.https://claude.ai/code/session_016Co1zj9L1cEMNmudHWZGaN