Repository navigation
Description
aggregator(snapshot-records): shape-only dates win freshestDate — a 2026-13-01 'Last checked' silently drops a pool's whole snapshot history, 2026-02-30 is stored as a phantom March date
Summary
pm-stack/aggregator/src/snapshot-records.ts carries its own copy of the shape-only date logic already filed for saas-extract (#2206) — but this copy feeds the usage snapshot store, not the cards, and a fix to saas-extract will not touch it. DATE_RE (snapshot-records.ts:30, /\d{4}-\d{2}-\d{2}/g) has no calendar check; freshestDate (:42-45) string-sorts and takes the max; lastCheckedDate (:54-70) and recordsFromPools (:165, lastCheckedDate(section) ?? freshestDate(section)) stamp every snapshot record for a quota pool with that winner via dayTs (:35-37).
Evidence (verified this run, main 5a34fa7)
Sandbox Bun probe driving the real recordsFromPools / freshestDate / lastCheckedDate plus the real SnapshotStore / isSnapshotRecord (probe: /tmp/probe-laneA-snapdate/probe.ts, probe2.ts):
- Control
**Last checked:** 2026-10-26→ record ts2026-10-26T12:00:00Z, valid,SnapshotStore.appendreturns 1. - Same bullet plus a typo
2026-13-01→lastCheckedDatereturns2026-13-01; record ts2026-13-01T12:00:00Z;isSnapshotRecordis false (Date.parse is NaN) andSnapshotStore.appendreturns 0 of 1 with no error or log — the pool's whole history point silently vanishes. **Last checked:** 2026-01-15; typo 2026-02-30→ the impossible date wins string-max; record ts2026-02-30T12:00:00ZpassesisSnapshotRecordbecauseDate.parserolls it over to 2026-03-02 — a phantom March observation is stored (in theusage-2026-02.jsonlfile, sincesnapshotFileForslices the string month), and pace/sort logic downstream ages it from a date that never existed.2026-04-31behaves the same (rolls to May 1).- Leap control
2024-02-29works correctly and must keep working.
File:line (main 5a34fa7):
pm-stack/aggregator/src/snapshot-records.ts:30—DATE_REshape only.pm-stack/aggregator/src/snapshot-records.ts:42-45—freshestDatestring-sort max.pm-stack/aggregator/src/snapshot-records.ts:54-70—lastCheckedDatebuilt onfreshestDate.pm-stack/aggregator/src/snapshot-records.ts:159-165—recordsFromPoolsstamps all pool records from that date.pm-stack/aggregator/src/snapshots.ts:29,117— store validationDate.parseNaN-rejects month-13 records (silent drop inappend's filter) but rollover-accepts Feb-30/Apr-31 records.
Why it matters
Snapshot records are the hub's long-term usage history (§4 design): they feed pace projections and trend charts, and writers are explicitly safe-to-rerun because records keep their observation date. One typo'd date in the hand-edited quota-view section either (a) erases a pool's history point for that run with no signal anywhere — append just reports a smaller count — or (b) permanently writes a phantom-dated point into the append-only store, where dedupe keys on the phantom ts so a later corrected read appends a second point instead of replacing it. The store's own validation cannot catch case (b): the string is ISO-shaped and Date.parse rolls it over.
Acceptance criteria
- Triage pins the non-calendar-date rule for this module (expected: impossible dates are ignored by
freshestDate/lastCheckedDatein snapshot-records.ts — a real date in the same text still wins — mirroring whatever rule aggregator(saas-extract): shape-only dates win freshestDate — a 2026-13-01 'Last checked' masks a real read (measuredAt goes stale/null), 2026-02-30 becomes a renewal date #2206's triage pins for saas-extract, so the two copies cannot drift; sharing one implementation is also acceptable if triage prefers it). - Regression tests in the aggregator test suite (snapshot-writers test home): a Last checked bullet with
2026-10-26+2026-13-01yields records at2026-10-26;2026-02-30/2026-04-31never become a record ts;2024-02-29still counts. - No behavior change for real dates:
recordsFromPoolsoutput identical on the existing fixture (including the Last-checked-beats-2027-renewal case).
Filed by new-issue-creator-code-a (lane A), run 2026-10-29 06:05 CDT. Dedup: #2206 is the same shape-only pattern in saas-extract.ts (different file, different consumer — the cards vs the snapshot store; filed separately by the same convention as #2194/#2199); #1540 is SnapshotStore validation of non-finite pairs / non-ISO timestamps (store-side, distinct); #2253/#2242 are quota-current/health stamp paths, distinct.
Activity
developing-today commentedon Oct 29, 2026
CODE-1127
dezren39 commentedon Oct 29, 2026
🤖 Agent note · filed
dezren39 commentedon Oct 31, 2026
🤖 Agent note · triaged — rule pinned, fix routed (queue task 4316)
74afc26e:pm-stack/aggregator/src/snapshot-records.ts:30DATE_RE = /\d{4}-\d{2}-\d{2}/g;:42-45freshestDatestring-sorts matches and returns the max — still shape-only, no calendar check.lastCheckedDate(:54-70) andrecordsFromPoolsboth consume it. The probe evidence filed with this issue (month-13 → append silently drops the pool's records; 2026-02-30 → stored as a phantom 2026-03-02 observation) stands unrebutted at current main.freshestDateignores non-calendar dates — month outside 01–12, day 00, or day beyond the month's length under the Gregorian leap rule. The freshest real calendar date wins; if no real date exists, returnnull(the module's existing fail-soft discipline). Never clamp, neverDate.parse-rollover.isCalendarDate(yyyy-mm-dd)helper insnapshot-records.tsfilteringDATE_REmatches before the max pick. aggregator(saas-extract): shape-only dates win freshestDate — a 2026-13-01 'Last checked' masks a real read (measuredAt goes stale/null), 2026-02-30 becomes a renewal date #2206 (saas-extract's own copy, still open) adopts the same helper in its fix rather than growing a third copy — this fix does not touchsaas-extract.ts(scope exclusion stands).recordsFromPoolsfixture output unchanged.dezren39 commentedon Oct 31, 2026
Closing as fixed by PR #3035 (merged 5411129, queue task 4006 slice 1): freshestDate in snapshot-records.ts and saas-extract.ts now only lets real calendar dates compete (validate.ts isIsoDate), so an impossible date like 2026-13-01 or 2026-02-30 in prose can no longer win freshness or be stored as a phantom March date. Probe coverage landed with the slice; laptop verification recorded on PR #3035.
fix(aggregator): non-calendar renews date resolves to null (#2206) (#…