Repository navigation
Description
Problem
isSubscriptionRow (pm-stack/aggregator/src/feed.ts:472-479) — the gate behind sanitizeSubscriptions (feed.ts:486-493), applied at the loadFeed boundary (feed.ts:507) — accepts any string as renewsAt:
(typeof v.renewsAt === "string" || v.renewsAt === null)The only producer never emits such a value: extractSubscriptions (pm-stack/aggregator/src/saas-extract.ts:1063-1064) sets renewsAt only when parseIsoDate(...) !== null, otherwise null ("never a verbatim renewsAt"). The shared strict primitive already exists in the same aggregator: isIsoDate (src/validate.ts:113-115), which rejects impossible calendar dates instead of rolling them over.
The renderer trusts the gate: render.ts:2039 interpolates the string verbatim (escaped only) as · renews ${esc(s.renewsAt)}.
Verified this run (laptop probe, real code)
Probe: ~/git/fleet/probe-2026-11-01-laneB-subsdate/ on the laptop — verbatim copy of pm-stack/aggregator at main 5abd39a (feed.ts sha256 cf7ea03d…, validate.ts sha256 1f72539a…, matched to the sandbox clone; probe copy differs only by the #3452 closing brace, without which feed.ts does not parse). bun probe.ts output (probe.log):
- control
{renewsAt:"2026-12-01"}→isSubscriptionRow = true(correct) - control
{renewsAt:null}→true(correct) renewsAt:"banana"→ true (isIsoDate = false)renewsAt:"2026-02-30"→ true (isIsoDate = false)renewsAt:"2026-13-01"→ true (isIsoDate = false)renewsAt:"12/01/2026"→ true (isIsoDate = false)renewsAt:"2026-12-01banana"→ true (isIsoDate = false)sanitizeSubscriptionsover the mixed set: all 7 rows kept, dropped: 0
So a corrupt or hand-edited feed renders renews banana, renews 2026-02-30 (a date that does not exist) etc. on /quota as if they were measured renewal dates, and /api/quota.json serves them verbatim — the exact falsified-date class the sibling gates were fixed for (#3458 charges at, #3428 burn from/to, #3427 quota resetsAt).
Why it matters
The subscriptions strip is renewal-only guidance: a bogus or impossible renewal date is presented as fact. The gate's own comment (feed.ts:469-471) says the row must be "safe to hand to the renderers" — a non-date renewsAt is not.
Acceptance criteria
isSubscriptionRowrequiresrenewsAtto benullor a string passingisIsoDate(validate.ts) —"banana","2026-02-30","2026-13-01","12/01/2026", and"2026-12-01banana"rows are dropped bysanitizeSubscriptionsand counted indropped.- Valid ISO dates and
nullrows pass unchanged (producer output fromextractSubscriptionsis unaffected). - Regression tests cover the five rejected spellings plus the two controls, following the existing feed-gate test pattern.
Dedup
Searched open + closed for isSubscriptionRow, subscriptions renewsAt: #2446 (closed) was the null-row crash that created this gate — it never checked the date's validity; #2206 (closed) fixed the producer side in saas-extract. No issue covers the feed gate accepting a non-date renewsAt. Distinct fields from #3458/#3428/#3427 (other gates, same file).
Activity
developing-today commentedon Nov 1, 2026
CODE-1347
dezren39 commentedon Nov 1, 2026
🤖 Agent note · filed
dezren39 commentedon Nov 2, 2026
🤖 Agent note · picked up
6 remaining items
dezren39 commentedon Nov 2, 2026
Picked up small fix (queue task 6140, openchamber scheduled lane). Plan: gate
renewsAtinisSubscriptionRowwith the existingisIsoDatevalidator, add feed-gate regression tests, verify with bun test.dezren39 commentedon Nov 2, 2026
Done: fix implemented and verified locally, PR #4474 opened (queue task 6140 completed as pr_opened). CI pending on the PR — merge once checks are green per the standing criteria.
Merge pull request #4474 from developing-today/queue/6140-3513-renews…
developing-today commentedon Nov 3, 2026
agent-note:v1
state: triaged (coverage pass)
Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 30 (priority/low). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
Found via: coverage pass 2026-11-03