getPersistedMainQuota returns mainQuota — which carries an embedded accountIdentity — alongside the top-level mainQuotaCheckedAt, which carries no account binding of its own. QuotaManager.seedMainFromStorage consumes that pair and uses the timestamp to build QuotaEntry.checkedAt and refreshAfter, where it acts as the persisted-vs-current ordering fence (quota-manager.ts:565 and :584).
So a caller can validate the identity on one field and then trust a second field that a concurrent cross-account write may have already moved.
Consequence
A mixed state — quota belonging to account A, timestamp belonging to account B — lets the persisted A entry win the cache ordering fence against a newer in-memory A entry, and keeps stale A poll-owned fields resident until an observation later than B's timestamp arrives.
What it does not do, so the severity is not overstated: strict identity checking still prevents cross-account quota from being served through getMain, and each window's own checkedAt caps refreshAfter, so the mixed timestamp alone cannot suppress a refresh that is otherwise due.
Reachability
The ordinary request path reaches it, with no additional race needed once the mixed state exists:
harvestQuotaHeaders -> persistPushedQuota -> refreshSidebarQuota -> updateStorage -> seedMainFromStorage
Relationship to the publication defect
This is the second instance of one shape. The first was in persistPushedQuota, where the published feed entry validated mainQuota.accountIdentity and then adopted the unbound mainQuotaCheckedAt, so a feed entry for account A could carry account B's observation time. That one is fixed — publication now always uses the request's own entry.checkedAt — and it was reachable in practice: it surfaced as an intermittent CI failure that took several runs to catch, because removing ~300ms of network latency from the test suite made the interleaving reachable where it previously was not.
Fixing the publication site does not fix this one; they consume the same unbound pair independently.
Two directions
- Bind the timestamp to the account in persisted state, so an unbound read becomes impossible. Cleanest, but it is a schema change and needs a compatibility decision for existing state files.
- Stop trusting the top-level timestamp independently and derive the entry's observation time from the account-bound quota itself, keeping only account-bound timestamps in the fence.
The second is smaller and needs no migration; the first removes the shape rather than the instance. I have not implemented either — filing rather than bundling it into an open PR, since both touch persisted-state semantics and deserve their own review.
Found during a five-way independent review of the network-guard branch.
getPersistedMainQuotareturnsmainQuota— which carries an embeddedaccountIdentity— alongside the top-levelmainQuotaCheckedAt, which carries no account binding of its own.QuotaManager.seedMainFromStorageconsumes that pair and uses the timestamp to buildQuotaEntry.checkedAtandrefreshAfter, where it acts as the persisted-vs-current ordering fence (quota-manager.ts:565and:584).So a caller can validate the identity on one field and then trust a second field that a concurrent cross-account write may have already moved.
Consequence
A mixed state — quota belonging to account A, timestamp belonging to account B — lets the persisted A entry win the cache ordering fence against a newer in-memory A entry, and keeps stale A poll-owned fields resident until an observation later than B's timestamp arrives.
What it does not do, so the severity is not overstated: strict identity checking still prevents cross-account quota from being served through
getMain, and each window's owncheckedAtcapsrefreshAfter, so the mixed timestamp alone cannot suppress a refresh that is otherwise due.Reachability
The ordinary request path reaches it, with no additional race needed once the mixed state exists:
Relationship to the publication defect
This is the second instance of one shape. The first was in
persistPushedQuota, where the published feed entry validatedmainQuota.accountIdentityand then adopted the unboundmainQuotaCheckedAt, so a feed entry for account A could carry account B's observation time. That one is fixed — publication now always uses the request's ownentry.checkedAt— and it was reachable in practice: it surfaced as an intermittent CI failure that took several runs to catch, because removing ~300ms of network latency from the test suite made the interleaving reachable where it previously was not.Fixing the publication site does not fix this one; they consume the same unbound pair independently.
Two directions
The second is smaller and needs no migration; the first removes the shape rather than the instance. I have not implemented either — filing rather than bundling it into an open PR, since both touch persisted-state semantics and deserve their own review.
Found during a five-way independent review of the network-guard branch.