Repository navigation
Description
pm-stack(aggregator): entryFromTurso computes windowSeconds with raw Date.parse — impossible/non-ISO billing-period stamps roll instead of yielding null
Evidence
entryFromTurso (pm-stack/aggregator/src/quota-gather-map.ts, at origin/main 785247aad):
:627-630— the Turso subscription doc'scurrent_billing_period_start/current_billing_period_end(and their aliases) are read as raw unknown values.:631-635—windowSecondsis computed directly from them:
const startMs = typeof periodStart === "string" ? Date.parse(periodStart) : Number.NaN;
const endMs = typeof periodEnd === "string" ? Date.parse(periodEnd) : Number.NaN;
const windowSeconds =
Number.isFinite(startMs) && Number.isFinite(endMs) && endMs > startMs ? Math.round((endMs - startMs) / 1000) : null;Date.parse is the only gate. It rolls impossible calendar dates to a different instant and accepts non-ISO strings (in a timezone-dependent way), so a malformed billing period silently produces a plausible-looking but wrong window length on every Turso window the entry publishes (:643).
Verified this run with a laptop bun probe importing entryFromTurso at 785247aad (usage doc {organization:{usage:{databases:3}}}, Starter subscription):
| period start | period end | windowSeconds | expected |
|---|---|---|---|
2026-02-01T00:00:00Z |
2026-03-03T00:00:00Z (control) |
2592000 (30 d) | 30 d ✅ |
2026-02-30T00:00:00Z (impossible) |
2026-03-30T00:00:00Z |
2419200 (28 d) | null — Feb 30 does not exist; Date.parse rolled it to Mar 2 |
2026-02-01T00:00:00Z |
2026-02-30T00:00:00Z (impossible) |
2505600 (29 d) | null — rolled to Mar 2 |
February 1, 2026 |
March 3, 2026 (non-ISO) |
2592000 (30 d) | null — non-ISO stamps are accepted, and parsed in local time (the same probe's resetsAt came out 2026-03-03T06:00:00.000Z, i.e. UTC-6) |
not-a-date |
also-not-a-date (control) |
null | null ✅ |
Why it matters
windowSeconds is the billing-window length attached to every Turso quota window; downstream pacing/burn math treats it as measured fact. A period stamp that is impossible (Feb 30) or non-ISO currently yields a window that is days off (28 d or 29 d instead of no window) with no signal anything was wrong — the exact failure class the aggregator has been closing site by site with its real-calendar ISO gate (isIsoDate, pm-stack/aggregator/src/validate.ts:116).
Related but distinct: #4968 covers normalizeResetAt (the resetsAt derived from the same periodEnd, quota-gather-map.ts:44-57). Fixing #4968 does not touch this computation — windowSeconds parses periodStart/periodEnd itself and never goes through normalizeResetAt — so this stays live after #4968 lands.
Acceptance criteria
entryFromTursoyieldswindowSeconds: nullwhen either billing-period stamp is present but not a real ISO calendar date/time: impossible dates (2026-02-30,2026-04-31) and non-ISO strings (February 1, 2026,03/01/2026) included.- Valid ISO start/end stamps (including offsets) still produce the exact window length; the valid control above stays 2592000.
- Absent/non-string period stamps keep yielding
windowSeconds: null(unchanged). - Tests cover the impossible-start, impossible-end, and non-ISO cases plus the valid control, through
entryFromTurso;bun testinpm-stack/aggregatorpasses. - Out of scope:
normalizeResetAtitself (pm-stack(aggregator): normalizeResetAt accepts impossible and non-ISO reset dates — its string branch is Date.parse-only, rolling 2026-02-30 to Mar 2 instead of returning null #4968), and any change to which subscription fields are read.
Activity
dezren39 commentedon Nov 3, 2026
🤖 Agent note · state: filed
dezren39 commentedon Nov 3, 2026
🤖 Agent note · picked up
entryFromTursowindowSeconds period stamps withisIsoDate(pm-stack/aggregator/src/quota-gather-map.ts) per issue pm-stack(aggregator): entryFromTurso computes windowSeconds with raw Date.parse — impossible/non-ISO billing-period stamps roll instead of yielding null #5091, with tests through entryFromTurso.fix(aggregator): gate entryFromTurso period stamps with isIsoDate (#5097
dezren39 commentedon Nov 3, 2026
🤖 Agent note · done — fixed and merged
entryFromTursobilling-period stamps withisIsoDatebeforeDate.parse(pm-stack/aggregator/src/quota-gather-map.ts) and added the pm-stack(aggregator): entryFromTurso computes windowSeconds with raw Date.parse — impossible/non-ISO billing-period stamps roll instead of yielding null #5091 test block throughentryFromTurso(impossible start/end, non-ISO → null window; valid ISO control = 2,592,000 s).bun test test/quota-gather-map.test.ts49/49 pass. Full aggregator suite: only the timing-sensitive snapshot-retention lockfile tests failed under laptop load (~17 avg) — that file passes 23/23 in isolation in the same worktree; unrelated to this change.tsc --noEmit: zero diagnostics in changed files (the one remaining error is the pre-existing overview.test.ts fixture error, issue pm-stack(aggregator): typecheck red on main — test/overview.test.ts HealthView fixture missing the new required conflicts field (from #1282 / PR #5032) #5043).Merge origin/main into queue/6900-2579-implement-2579-aggregator-phas