Repository navigation
Description
meta-exporter: subscription-quota timestamps are never range-checked — an ms-scale resets_at exports a year-58790 reset as a successful reading, and an out-of-Date-range value throws a bare RangeError misclassified as fetch-failed
Evidence (verified this run, main 5a34fa70)
pm-stack/meta-exporter/meta-quota-export.mjs, parseSubscriptionQuota (lines 61–97):
- The numeric validation loop (line 76) checks only
Number.isFinite(v) || v < 0forwindow_resets_at/weekly_resets_at. There is no upper bound and no plausibility window. iso(line 87) isnew Date(epochSecs * 1000).toISOString()— unbounded.as_ofis not in the validated field set at all;consoleAsOf(line 90) calls the sameiso()whenevernum(q.as_of)is finite.
Probe (node, importing the real module from main):
| input | result |
|---|---|
window_resets_at = 1793090405000 (millisecond-scale, finite, ≥ 0 — passes validation) |
exported window resetAt: "+058790-10-10T04:03:20.000Z" inside a status: "ok" success document |
window_resets_at = 1e300 (finite, ≥ 0 — passes validation) |
bare RangeError: Invalid time value escapes parseSubscriptionQuota — err.status/err.exitCode are undefined, it is not an ExportError |
as_of = 1e300 |
same bare RangeError from the consoleAsOf path |
The escaped RangeError lands in main()'s catch-all, which wraps any non-ExportError as fetch-failed (exit 7). Per the file's own contract, shape drift is unparseable (exit 6): the header documents the failure taxonomy and the parser is documented "Throws on any shape drift — fail-closed, never partial zeros."
Why it matters
This exporter's whole design is fail-closed: "a failed tick can never be mistaken for a reading." Both failure modes break that contract:
- A units drift at the Meta console API (seconds → milliseconds is the classic one) silently exports a garbage
resetAtas a successful reading; the quota gatherer (feat(quota-plane): quota-gatherer service in the PM stack — 15-minute tick, quota-current contract #1151) ingests these windows for reset/burn display, so the corruption propagates downstream as fact. - The RangeError path writes a failure document with the wrong status (
fetch-failedinstead ofunparseable), sending whoever investigates hunting a network/page problem when the payload shape drifted.
Acceptance criteria
parseSubscriptionQuotarejects epoch fields (window_resets_at,weekly_resets_at, andas_ofwhen present) that do not produce a valid, plausible date — e.g. outside a sane window around now, or of millisecond magnitude — by throwingExportError("unparseable", 6, …).- No bare
RangeErrorescapes anyparse*function: every shape drift surfaces asunparseable/ exit 6. - New tests in
meta-quota-export.test.mjs: ms-scalewindow_resets_atrejected; huge finitewindow_resets_atrejected witherr.status === "unparseable"; hugeas_ofrejected (or explicitly pinned tonull); the captured-payload test and all existing tests still pass (node --test pm-stack/meta-exporter/).
Dedup
#2175 is the CDP-plumbing timeout (transport, open); #2350 is the entry-point symlink check (open); #1566 (closed) added the window_duration_secs validation only. No open or closed issue covers the epoch/resets_at/as_of range validation. Sibling filed this run: the parsePaygBalance truncation issue (different function, different mechanism).
Activity
developing-today commentedon Oct 29, 2026
CODE-1257
dezren39 commentedon Oct 29, 2026
🤖 Agent note · filed
8 remaining items
dezren39 commentedon Nov 1, 2026
🤖 Agent note · picked up
as_ofin meta-exporter, with regression tests.~/git/fleet/, implement and run the targeted Node test file.Merge pull request #3446 from developing-today/queue/5340-2460-meta-e…
dezren39 commentedon Nov 1, 2026
🤖 Agent note · done
ac56cb9d4ec2e1368a01c55ada64cd63dbfdf9b0; meta-exporter: subscription-quota timestamps are never range-checked — an ms-scale resets_at exports a year-58790 reset as a successful reading, and an out-of-Date-range value throws a bare RangeError misclassified as fetch-failed #2460 closed by the merge.node --test pm-stack/meta-exporter/meta-quota-export.test.mjs— 18/18 pass. No CI checks were pending; GitHub reported only CodeRabbit neutral/skipped.