Repository navigation
Description
Summary
entryFromResult in the quota gatherer (pm-stack/aggregator/src/quota-gather-map.ts:173-177) converts a provider result's fetchedAt epoch-ms value with new Date(result.fetchedAt).toISOString() after checking only typeof === "number" and Number.isFinite. A finite value outside the JS Date range (max ±8.64e15 ms) makes new Date(...) an Invalid Date, and .toISOString() on it throws RangeError: Invalid Date. Because the gatherer maps every result for a provider in one .map() call, that one bad result discards the provider's whole tick.
The same file already knows this guard: normalizeResetAt (quota-gather-map.ts:44-49) checks Number.isNaN(d.getTime()) ? null : d.toISOString() for window resetAt values — fetchedAt is the one conversion in the file left unguarded.
Evidence (verified this run on main 5a34fa70)
pm-stack/aggregator/src/quota-gather-map.ts:173-177—measuredAtistypeof result.fetchedAt === "number" && Number.isFinite(result.fetchedAt) ? new Date(result.fetchedAt).toISOString() : tickIso. ThetickIsofallback exists for missing/non-finite values, but a finite out-of-range value takes the throwing branch instead of the fallback.pm-stack/aggregator/scripts/gather-quota.ts:199—const entries = results.map((r) => entryFromResult(r, tickIso))runs insiderunProvider's try/catch (~:196-215): a throw returns{ state: "error", entries: [] }for that provider, so every credential/window that provider returned correctly in the same tick is dropped with it.- Probe (Bun, real
quota-gather-map.tsimported from main,/tmp/probe-laneB-fetchat/probe.ts):- control
fetchedAt: 1793075143879→ OK,measuredAt=2026-10-27T04:25:43.879Z fetchedAt: 1e16→ THREW RangeError Invalid DatefetchedAt: 9e15(just over the Date maximum) → THREW RangeErrorfetchedAt: -1e16→ THREW RangeError- batch map of [good result,
fetchedAt: 1e16result] → THREW — whole map lost - in-file control:
normalizeResetAt(1e16)→null(guarded, no throw)
- control
- Secondary, same gate:
fetchedAt: 0yieldsmeasuredAt=1970-01-01…instead of the tick fallback, so a zero stamp renders a fresh read as ~56 years old / instantly stale. (normalizeResetAtrequiresv > 0;entryFromResulthas no such check.)
Why it matters
fetchedAt is produced by the OpenChamber quota module, outside this repo — the mapper is exactly the boundary that is supposed to absorb a provider's bad stamp (its header, quota-gather-map.ts:1-15, promises a provider whose usage is not well-shaped "yields no windows (never zeros)", i.e. degrade per-entry, never fail the tick). Today one out-of-range stamp — e.g. a provider computing in microseconds or nanoseconds (1e16 is a plausible µs-scale value for 2026), or a corrupted upstream timestamp — turns a successful fetch into a provider-wide error entry every 15-minute tick until the provider is fixed, with the gatherer's error text (RangeError: Invalid Date) naming neither the provider field nor the value.
This is the same defect class as #2286 (iso() in the OpenCode session mapper), in a different module with a different data source and blast radius: there one bad session dropped a server's session feed; here one bad stamp drops a provider's quota tick.
Acceptance criteria
-
entryFromResultnever throws for any numericfetchedAt: a finite value that does not produce a valid Date (out of range, or<= 0) falls back totickIso, exactly as a missing/non-finite value already does. - One result with a bad
fetchedAtno longer discards the other results in the same provider batch — the bad entry is still produced (with the tick stamp), not dropped. - Regression tests in
pm-stack/aggregator/test/quota-gather-map.test.tspin:1e16,-1e16, and0→measuredAt === tickIsowith windows intact; the existing ms control (1793075143879→2026-10-27T04:25:43.879Z) is unchanged. - No change to
normalizeResetAt, the file-export path (entryFromFileExport, whosemeasuredAtparse is already NaN-gated), or the quota-current contract shape.
Dedup
Searched open + closed issues for quota-gather-map, entryFromResult, fetchedAt, and RangeError Invalid Date aggregator: #2286 is the OpenCode session mapper (sources/opencode.ts), distinct file/source; #1624 is gatherer snapshot dedupe by credentialId, distinct; no filing covers the entryFromResult fetchedAt conversion. The 2026-10-29T10:58Z backlog check that cleared quota-gather-map covered entryFromFileExport's NaN-gated measuredAt only.
Activity
developing-today commentedon Oct 29, 2026
CODE-1179
dezren39 commentedon Oct 29, 2026
🤖 Agent note · state: filed
6 remaining items
dezren39 commentedon Nov 1, 2026
🤖 Agent note · done
dezren39 commentedon Nov 2, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 2, 2026
🤖 Agent note · done