Repository navigation
Description
aggregator: a future-dated gatherer read is 'fresh' forever until its date passes — quota-current freshness has no upper bound, so one skewed measuredAt pins a pool's windows for weeks
Summary
entryState in pm-stack/aggregator/src/quota-current.ts:56-61 decides whether
a gatherer entry may replace a pool's windows:
const t = Date.parse(entry.measuredAt);
return Number.isFinite(t) && nowMs - t <= QUOTA_CURRENT_FRESH_MS ? "ok" : "stale";The check bounds only the past. A measuredAt in the future gives a negative
age, which is always <= QUOTA_CURRENT_FRESH_MS (20 min) — so a read stamped
an hour, a day, or a month ahead is classified "ok", replaces the pool's
windows in overlayQuotaCurrent, recomputes the pool state and the routing
choices (computeChoices), and keeps doing so on every render until 20
minutes after its future date arrives. The newest-entry sort in the overlay
(Date.parse(b.measuredAt) - Date.parse(a.measuredAt), quota-current.ts:139-141)
also makes a future-dated entry win over every genuinely fresh entry for the
same service.
Evidence (verified on main 3b55904, Bun 1.4.2, real quota-current.ts sha256 c528e1e3 on the laptop)
Probe drove the real overlayQuotaCurrent with a fixed now
(2026-10-27T07:00:00Z), one pool (weekly window at 68%), and one ok entry
carrying a 42% window:
| measuredAt | result |
|---|---|
| 5m ago (control) | state healthy, windows replaced (42), freshness ok |
| 19m ago (control) | healthy, windows replaced, freshness ok |
| 21m ago (control) | state stale, windows kept (68) |
| 1h in the future | healthy, windows replaced (42), freshness ok |
| 30d in the future | healthy, windows replaced (42), freshness ok |
parseQuotaCurrent (quota-current.ts:41-52) validates only that
measuredAt is a string, so nothing upstream of entryState catches this
either. The existing tests (test/quota-current.test.ts) construct entries
only with past offsets (iso(msAgo)), so the future case is uncovered.
Why it matters
The module's own contract (header, quota-current.ts:7-19) is the dashboard's
data-honesty rule for the quota plane: a read past the freshness bound
"surfaces as the pool's state (error/stale, with the reason) — never as
zeros, and the pool's older windows are never silently presented as
current". A future stamp defeats that rule in the other direction: one
clock-skewed or mis-stamped gatherer write (the gatherer runs on a 15-minute
tick on another host) silently presents its numbers as the freshest truth
for as long as the skew lasts — a month in the verified case — and the
choices computed from those windows steer real session routing.
Acceptance criteria
- An entry whose
measuredAtis more than a small clock-skew tolerance in
the future (tolerance pinned in triage; it should be minutes, not the
unbounded current behaviour) is NOT classified fresh-ok: it surfaces as
stale (or error) with the pool's older windows not replaced. - The fresh-ok precedence sort cannot let a future-dated entry outrank a
genuinely fresh entry for the same service. - Regression tests in test/quota-current.test.ts for measuredAt at
+1h and a far-future date, alongside the existing past-offset controls. - No change to the freshness bound or semantics for past-dated reads.
Notes
- Deliberately not self-solved by the creator lane: the skew tolerance is a
small policy choice for triage (the gatherer and aggregator run on
different hosts, so zero tolerance could flap on real skew). - Sibling validator, different defect: aggregator: SnapshotStore accepts records it can never read back — non-finite estimate pairs and non-ISO timestamps pass validation, append reports success, and dedupe never sees them #1540 (snapshot store records) —
same app, unrelated module and mechanism.
Activity
developing-today commentedon Oct 28, 2026
CODE-595
dezren39 commentedon Oct 28, 2026
🤖 Agent note · filed
46 remaining items
dezren39 commentedon Oct 28, 2026
🤖 Agent note · parked
queue/1811-1541-quota-future-skew@ d76bd3c):QUOTA_CURRENT_FUTURE_SKEW_MS = 60_000in quota-current.ts entryState + 3 regression tests (+1h/+30d stale, within-tolerance fresh, same-service outranking). Laptop: quota-current tests 13/13 pass, biome clean; full aggregator suite 318 pass with only the pre-existing aggregator: actions.test.ts fails on main — applied snooze never lands in the Snoozed strip ('Snoozed by you (1)' missing) #1682 failure. PR CI checks are stuck pending in the runner queue (0 failures) past the 5-minute poll window.dezren39 commentedon Oct 28, 2026
🤖 Agent note · picked up
queue/1811-1541-quota-future-skew@ d76bd3caggregator: future-dated quota-current entries beyond 60s skew classi…
dezren39 commentedon Oct 28, 2026
🤖 Agent note · done
QUOTA_CURRENT_FUTURE_SKEW_MS = 60_000inentryState(pm-stack/aggregator/src/quota-current.ts): ok entries dated >60s in the future classify stale, do not replace windows, and cannot outrank genuinely fresh entries; +1h/+30d/+30s-control/same-service regression tests included.