Repository navigation
Description
meta-exporter: parseSubscriptionQuota's num() reinterprets empty, hex and scientific strings as real measurements — a drifted '' used value exports as a measured 0% window
Evidence (verified this run, main da42bfe7)
pm-stack/meta-exporter/meta-quota-export.mjs, parseSubscriptionQuota (line 69):
const num = (v) => (typeof v === "string" || typeof v === "number" ? Number(v) : NaN);The console API legitimately sends decimal strings (the captured-payload test at meta-quota-export.test.mjs:19-21 uses "100000000000" / "1023570000"), so accepting strings is intentional. But bare Number() accepts far more than decimal spellings, and the parser's own contract (header, lines 66-68) is "Throws on any shape drift — fail-closed, never partial zeros":
Probe (laptop, importing the real module — file md5 2f76d55332752bd1c43a86505f289007 on both clones; valid control payload, one field mutated per case; probe ~/git/fleet/probe-2026-10-30-laneB-metaempty/):
| input | result |
|---|---|
| control (numeric fields) | status-ok windows: 5h usedPct 10, weekly usedPct 20 |
window_weighted_used = "" |
OK — 5h usedPct exported as 0 (a fabricated measured-zero window) |
weekly_weighted_used = " " (whitespace) |
OK — weekly usedPct exported as 0 |
window_weighted_used = "0x10" |
OK — usedPct 16 (hex reinterpreted) |
window_weighted_used = "1e2" |
OK — usedPct 100 (scientific reinterpreted) |
window_resets_at = "" with used = 10 |
OK — resetAt 1970-01-01T00:00:00.000Z: "" is neither null nor undefined, so it bypasses resetField's absent-reset guard (lines 92-100), then Number("") === 0 passes the finite/≥0 check |
as_of = "" |
OK — consoleAsOf 1970-01-01T00:00:00.000Z instead of null |
controls: window_weighted_used = "abc" / null |
correctly throws unparseable (exit 6) |
The existing malformed-reset test (meta-quota-export.test.mjs:157-163) pins "soon", -5, true, {} as fail-closed — "" slips past exactly the guard that test exists to enforce. Only the limit/duration fields are incidentally saved, by their separate zero checks (window_limit = "" → "zero limit"; duration "" → ≤ 0): the used fields have no such backstop, so they are where the fake reading lands.
Why it matters
This exporter's whole design is that "a failed tick can never be mistaken for a reading" (file header). An empty-string used value — the classic shape-drift / missing-value spelling from an upstream API — is currently exported in a status: "ok" document as a measured 0% window, and the quota gatherer ingests it as fact: real usage disappears from the burn/reset display precisely when the console API starts drifting. Hex/scientific spellings are silently reinterpreted into different numbers instead of failing closed.
Acceptance criteria
parseSubscriptionQuotaaccepts only plain decimal spellings (the API's actual format, per the captured payload) for its numeric fields: empty, whitespace-only, hex (0x…), scientific (1e…), and otherwise non-decimal strings throwExportError("unparseable", 6, …), for the used/limit/duration fields and insideresetField/as_ofalike.window_resets_at = ""on a window with recorded usage fails closed like the absent-reset case;as_of = ""yieldsconsoleAsOf: nullorunparseable, never the 1970 epoch.- New tests in
meta-quota-export.test.mjscover:""and" "used values rejected;"0x10"/"1e2"used values rejected;""reset with usage rejected; the captured-payload (decimal-string) test and all existing tests still pass (node --test pm-stack/meta-exporter/).
Dedup
- 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 (open) is the timestamp range/plausibility gap (ms-scale and out-of-Date-range values) — a decimal-string or numeric input problem; it does not cover the used fields or the
Number("") === 0coercion, and its fix would not stop a fake 0% window. The""→ 1970 rows above are the same root cause (num()) surfacing in the timestamp fields; fixingnum()here also removes those two spellings from 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's surface. - meta-exporter: parseBillingBanner accepts fractional minor units — 1050.5 exports as $10.505 of free credits instead of failing closed on shape drift #2510 (open) is
parseBillingBanneraccepting fractional numbers — different function, different mechanism (no string coercion). - supabase-export: parseDbSize/parseRequestCount accept empty, hex, scientific and fractional strings as real measurements — Number("") reads a drifted db-size row as a measured 0-byte database #2743 is the same
Number()pattern in supabase-export (different app/file). meta-exporter: window_duration_secs is never validated — a missing/junk duration exports a 'window-NaNs' window as a successful reading #1566 (closed) added thewindow_duration_secsvalidation only.
Activity
dezren39 commentedon Oct 30, 2026
🤖 Agent note · filed
1 remaining item
dezren39 commentedon Oct 30, 2026
agent-note:v1 — picked up and implemented, queue task 4025 (repo-worker-code, openchamber-scheduled-lane, 2026-10-30).
Fix on branch queue/4025-2789-meta-decimal, PR #2864. Verdict: bug confirmed live on origin/main exactly as triaged. Awaiting CI.
Merge pull request #2864 from developing-today/queue/4025-2789-meta-d…
dezren39 commentedon Oct 30, 2026
agent-note:v1 — done, queue task 4025 (repo-worker-code, openchamber-scheduled-lane, 2026-10-30).
PR #2864 merged as d142e40 (merge state CLEAN; 16/16 node --test pass locally, no repo workflow covers this path). Issue auto-closed. In-flight labels removed.