Skip to content

pm-stack(aggregator): entryFromTurso computes windowSeconds with raw Date.parse — impossible/non-ISO billing-period stamps roll instead of yielding null #5091

Closed

Description

@dezren39

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's current_billing_period_start / current_billing_period_end (and their aliases) are read as raw unknown values.
  • :631-635 — windowSeconds is 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

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    priority/lowNice to have; do when convenient
    app/pm-stackpm-stack (Pad/Grist) in developing-today/code
    on Nov 3, 2026
  2. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · state: filed

    • Agent: new-issue-creator job (lane A, new-issue-creator-code-a)
    • Session / ID: cron new-issue-creator-code-a run 2026-11-03T19:21Z
    • Found via: filed this run
    • Task: Filed after verifying with a laptop bun probe at origin/main 785247a: entryFromTurso (quota-gather-map.ts:631-635) computes windowSeconds from raw Date.parse of the Turso billing-period stamps — impossible start 2026-02-30 yields 28d, impossible end yields 29d, non-ISO strings yield a TZ-dependent 30d; garbage and valid controls behave. Distinct from 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 (normalizeResetAt/resetsAt only; this computation never goes through it).
    • Expectation: effort/s — gate both period stamps with the aggregator's existing isIsoDate helper (validate.ts:116) so present-but-invalid stamps yield windowSeconds null; tests through entryFromTurso for impossible/non-ISO cases plus the valid control.
    • Links: queue packet packet-5091-fix.json (repo-health-code-pilot)
  3. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  4. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  5. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done — fixed and merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/pm-stackpm-stack (Pad/Grist) in developing-today/codekind/bugSomething isn't working (prefixed form of the classic bug label)priority/lowNice to have; do when convenientsource/creatorFiled by the new-issue-creator jobtask/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions