Skip to content

aggregator(snapshot-records): recordsFromDeepseekBalance takes the ¥ line's first date-shaped string unchecked — an impossible date (2026-02-30) shadows the section's valid Last-checked date, the record fails isSnapshotRecord and is silently dropped as 'already present' #3379

Closed

Description

@dezren39

Problem

recordsFromDeepseekBalance (pm-stack/aggregator/src/snapshot-records.ts:173-190, the DeepSeek PAYG CNY balance derivation from #1052) takes its observation date from the ¥ line with a bare date-shaped regex and never checks it is a real calendar date:

const date = /\d{4}-\d{2}-\d{2}/.exec(line)?.[0] ?? lastCheckedDate(section) ?? freshestDate(section);  // :182

Both fallbacks it shadows are #2264-hardened: freshestDate (same file, :45) filters candidates through parseIsoDate precisely so "an impossible date like 2026-02-30 or 2026-13-01 in prose must not win", and recordsFromPools (:206) uses only those validated fallbacks. The DeepSeek path is the one derivation in the file that bypasses the discipline — and because the regex matches an impossible date, the ?? chain never falls through to the section's valid Last checked: date.

Verified (laptop probe, real files at main e6577a9, snapshot-records.ts sha256 dc4d2b62…)

Probe: ~/git/fleet/probe-2026-11-01-laneA-deepseekdate/ (imports the real recordsFromDeepseekBalance / freshestDate / lastCheckedDate and the real isSnapshotRecord gate):

  • Control — ¥ line (2026-10-25 read): record ts=2026-10-25T12:00:00Z, isSnapshotRecord=true.
  • ¥ line (2026-02-30 read), section Last checked: 2026-10-30: record ts=2026-02-30T12:00:00Z, isSnapshotRecord=false.
  • ¥ line (2026-13-01 read): record ts=2026-13-01T12:00:00Z, isSnapshotRecord=false.
  • Control — no date on the ¥ line: falls back correctly to ts=2026-10-30T12:00:00Z (Last checked), gate passes.

Why it matters

The poisoned record is not stored — it is silently lost: SnapshotStore.appendLocked drops gate-failing records with records.filter(isSnapshotRecord) (snapshots.ts:610, no warning), and the backfill's summary counts everything not appended as "already present" (scripts/backfill-usage-snapshots.ts:434), so a mistyped/impossible date in the quota-view prose (e.g. 2026-02-30 for a Feb 28 read, or a month/day transposition) makes the DeepSeek reserve's balance observation vanish while the run reports it as a dedupe. The correct read date was sitting in the same section's Last checked: bullet the whole time. This is exactly the failure #2264 fixed for freshestDate; this one call site was missed.

Fix sketch

Validate the on-line candidate the same way the rest of the file does — e.g. take the first real date on the line (parseIsoDate(d) !== null, mirroring freshestDate), and only then fall back to lastCheckedDate(section) ?? freshestDate(section). An impossible on-line date should behave like no on-line date, not like a successful match.

Acceptance criteria

  • A ¥ line carrying an impossible date (2026-02-30, 2026-13-01, 2026-04-31) with a valid Last checked: date in the section derives a record stamped at the Last-checked (or freshest valid) date, and the record passes isSnapshotRecord.
  • A ¥ line carrying an impossible date and no other valid date in the section yields no record (fail-soft, as today for dateless lines).
  • Existing behavior is unchanged for a real on-line date and for the no-date fallback (existing DeepSeek tests in test/snapshot-writers.test.ts still pass).
  • New tests cover both impossible-date cases above.

Distinct from: #2568 (recordsFromProviderUsage percent range-check, different function), #2493 (github-billing impossible dates, different pipeline), #3365/#3364 (rollup/census gates).

Activity

  1. developing-today commented on Nov 1, 2026

    @developing-today
    Contributor
  2. added
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/lowNice to have; do when convenient
    app/aggregatorPackage/app: aggregator (pm-stack in this repo)
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    effort/sSmall: expected under 2 hours of work
    on Nov 1, 2026
  3. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  4. added
    app/pm-stackpm-stack (Pad/Grist) in developing-today/code
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 1, 2026
  5. 19 remaining items

  6. added
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 2, 2026
  7. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    Parked: OpenChamber scheduled lane parked task 5994 for 20 minutes — CI pending on the owning session PR #4418.

  8. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 2, 2026
  9. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  10. added a commit that references this issue on Nov 2, 2026
  11. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

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

Metadata

Metadata

Assignees

Labels

app/aggregatorPackage/app: aggregator (pm-stack in this repo)app/pm-stackpm-stack (Pad/Grist) in developing-today/codeeffort/sSmall: expected under 2 hours of workkind/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/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions