Repository navigation
Description
aggregator(quota-extract): Claude and Meta reset dates are never validated — an impossible date is emitted verbatim as resetsAt, and a Feb-30 Meta reset silently discards the pool's whole read
Summary
extractClaude and extractMeta in pm-stack/aggregator/src/quota-extract.ts capture a reset date/time from the human-written quota view with shape-only regexes ((\d{4}-\d{2}-\d{2}) (\d{2}:\d{2})) and pass the captures through dateTimeCDT, which is a pure string interpolator — it builds ${date}T${hhmm}:00-05:00 with no calendar or clock validation at all. The result:
- Claude: a reset read of
2026-13-28 14:00,2026-10-28 99:99, or2026-10-39 14:00is emitted verbatim as the window'sresetsAt("2026-13-28T14:00:00-05:00"etc.).Date.parseof those strings isNaN, so every downstream consumer that parses the value (quota-guidance's reset-time filter, derive's pace/reset logic) silently drops or mis-handles it, and render'sfmtDatefalls back to printing the raw impossible string as the reset date. A2026-02-30reset is worse:Date.parserolls it over to 2026-03-02, so downstream treats a phantom date as the real reset. - Meta: the same invalid string feeds the reset-passed check
now >= Date.parse(resetIso). For month-13 /99:99the parse isNaN, the comparison is false, and the invalid string is emitted verbatim (and, on the burned-to-empty path, also becomeswallLiftsAt). For a2026-02-30reset the parse rolls over to 2026-03-02 — which is before now in the probe — so the extractor takes the "window already reset, no post-reset read yet" branch and discards the pool's entire matched 46% read, windows and all.
This is the module's own fail-soft contract failing in the opposite direction from the usual drop: the percentages were successfully read, so an invalid reset should degrade to resetsAt: null, not be published as a fact or take the whole read down with it.
Evidence (verified this run, main 5a34fa7)
Laptop probe driving the real extractQuotaPools (Bun 1.4.2; laptop quota-extract.ts/derive.ts sha256-identical to main 5a34fa7; probe: ~/git/fleet/probe-2026-10-29-laneB-claudereset/probe.ts on the laptop), minimal Claude + Meta sections, now = 2026-10-25T15:00:00Z:
| reset read | Claude window | Meta result |
|---|---|---|
control 2026-10-28 14:00 / 2026-10-25 19:00 |
68%, resetsAt 2026-10-28T14:00:00-05:00 ✅ |
46%, resetsAt 2026-10-25T19:00:00-05:00 ✅ |
month-13 (2026-13-…) |
68%, resetsAt 2026-13-28T14:00:00-05:00 verbatim, Date.parse → NaN ❌ |
46%, resetsAt 2026-13-25T19:00:00-05:00 verbatim, Date.parse → NaN ❌ |
Feb-30 (2026-02-30 …) |
68%, resetsAt 2026-02-30T14:00:00-05:00; Date.parse → 2026-03-02 (phantom rollover) ❌ |
windows [] — whole 46% read discarded as "reset already passed" (rolled-over Mar 2 < now) ❌ |
time 99:99 |
68%, resetsAt 2026-10-28T99:99:00-05:00 verbatim, Date.parse → NaN ❌ |
46%, resetsAt verbatim, Date.parse → NaN ❌ |
day-39 (2026-10-39 …) |
68%, resetsAt 2026-10-39T14:00:00-05:00 verbatim, Date.parse → NaN ❌ |
46%, resetsAt verbatim, Date.parse → NaN ❌ |
File:line (main 5a34fa7):
pm-stack/aggregator/src/quota-extract.ts:43-45—dateTimeCDT: pure interpolation, no validation of the date or time components.pm-stack/aggregator/src/quota-extract.ts:98-100—extractClaude: shape-only reset capture, result becomes the window'sresetsAtunchecked.pm-stack/aggregator/src/quota-extract.ts:132-149—extractMeta: same capture →resetIso; thenow >= Date.parse(resetIso)reset-passed branch (:135), the burned path'swallLiftsAt: resetIso, and the normal path'sresetsAtall consume the unvalidated string.- Downstream:
pm-stack/aggregator/src/render.ts:92-95—fmtDateprints an unparseableresetsAtverbatim;pm-stack/aggregator/src/quota-guidance.ts:18—Date.parse+ finite filter silently drops NaN resets;pm-stack/aggregator/src/derive.ts:820— attention-flag detail interpolatesresetsAt.slice(0, 10).
Why it matters
The quota view is a human-written document, and these two pools' resets are typed by hand — a typo'd month, day, or time is exactly the input the fail-soft design exists to absorb. Today one bad digit either publishes an impossible reset date as a measured fact (which the stewardship rotation then reads), or — the Feb-30 Meta case — makes a healthy, current read vanish with a plausible-looking "no post-reset read yet" note, so nothing signals that anything went wrong.
Acceptance criteria
- Triage pins the rule for the
dateTimeCDTcall sites inextractClaude/extractMeta(expected: validate the captured date as a real calendar date and the time as a real clock time — e.g. theisCalendarDatediscipline already used in derive.ts — and treat an invalid reset asresetsAt: nullfor that window, keeping the matched percentage windows; Meta's reset-passed and burned/wallLiftsAtbranches must not consume an invalid reset string). - Regression tests in
pm-stack/aggregator/test/quota.test.ts: month-13, Feb-30, day-39, and99:99resets keep the Claude 68% and Meta 46% windows withresetsAt: null; the Feb-30 Meta read is NOT discarded as already-reset; the existing control cases (Claude2026-10-28T14:00:00-05:00, Meta walled-until-reset) are unchanged. - No change to
extractQuotaPools' per-pool try/catch semantics for genuinely unmatched sections (shell note still renders).
Filed by new-issue-creator-code-b (lane B), run 2026-10-29 18:50 CDT. Dedup: #2197 is dateTimeCDT's fixed UTC-5 offset for valid dates (an hour-early error, not validation); #2383 is extractClinePass's Measured anchor through the same helper (its fix validates the ClinePass base/rel path only, and its failure mode is throw-and-drop); #2196 is monthDayTime (Codex / OpenCode Go / Command Code). No open or closed issue covers validation at the Claude/Meta reset call sites. NOT self-solved: where validation lives (helper vs call sites) and its interplay with #2197's pending offset fix are triage's pin.
Activity
developing-today commentedon Oct 29, 2026
CODE-1264
dezren39 commentedon Oct 30, 2026
🤖 Agent note · filed
38 remaining items
dezren39 commentedon Nov 2, 2026
🤖 Agent note · parked — shared-file coordination blocker
repo-worker-code, OpenChamber scheduled lane)queue/5220-2197-quota-extract-dst-awareat6d990dfee381e8b8c70d06dda100b5107f4dc00c.quota-extract.ts; no competing implementation, PR-content inspection, or worktree changes were made.dezren39 commentedon Nov 2, 2026
🤖 Agent note · picked up
pm-stack/aggregator/src/quota-extract.tsper aggregator(quota-extract): Claude and Meta reset dates are never validated — an impossible date is emitted verbatim as resetsAt, and a Feb-30 Meta reset silently discards the pool's whole read #2470, with regression tests.dateTimeCDTconversion is on main. Proceeding with implementation on a fresh branch from current main.~/git/fleet/5343, branchqueue/5343-2470-quota-reset-validation; implement + bun tests on the laptop.fix(aggregator): invalid Claude/Meta quota resets yield resetsAt null…
dezren39 commentedon Nov 2, 2026
🤖 Agent note · done
resetDateTimeCentralwraps the shareddateTimeCentralconversion (aggregator(quota-extract): dateTimeCDT hardcodes UTC-5 year-round — winter (CST) reset reads render an hour early, and Meta's reset-passed check fires an hour early too #2197, merged via PR fix(aggregator): DST-aware America/Chicago conversion in quota-extract (#2197) #4270) for the Claude and Meta reset paths inpm-stack/aggregator/src/quota-extract.ts. Invalid reset captures (month-13, Feb-30, day-39, 99:99) now yieldresetsAt: nullwith the usage window preserved; a Feb-30 Meta reset neither discards the read nor createswallLiftsAt. Valid captures use the shared DST-aware conversion unchanged; ClinePass anchor (aggregator(quota-extract): ClinePass extractor's measured-date anchor is never validated — an impossible measured date or a huge 'resets in' offset silently discards the pool's whole read, and a Feb-30 anchor rolls into March #2383) and monthDayTime (aggregator(quota-extract): a lowercase or non-month reset month silently discards a pool's whole read — monthDayTime's case-sensitive MONTHS lookup throws on its case-insensitive regex captures, and out-of-range days roll over into invented reset dates #2196) untouched.bun test test/quota.test.ts33/33; full aggregatorbun test1027/1027 (clean-main baseline 1025). Codex review on PR fix(aggregator): invalid Claude/Meta quota resets yield resetsAt null, read preserved (#2470) #4304 completed with no findings. PR CI was still queued at merge (runner delay); merge per standing merge authority on laptop-verified tests.