Repository navigation
Description
Summary
summarizeDns (pm-stack/aggregator/src/dns.ts:99-102) derives "today" and the 45-day spend-horizon cutoff from Date#toISOString() — the UTC calendar day:
const cutoff = new Date(now.getTime() + soonDays * 86_400_000).toISOString().slice(0, 10);
const today = now.toISOString().slice(0, 10);The dashboard's house convention is America/Chicago: derive.ts:457-475 already provides chicagoYmd(now) ("2026-10-25" in America/Chicago for an instant) and addDaysYmd(ymd, n) for exactly this kind of date-only comparison — the helpers the #1629 fix introduced for freshness(). dns.ts uses neither.
Verified behaviour (probe run on the laptop, main d39e611)
Probe test in the real aggregator tree (bun test, detached worktree; dns.ts sha256 10933bba identical in both clones), with a register holding domains renewing 2026-10-27 and 2026-10-28:
- CTRL —
now = 2026-10-27T15:00:00Z(10:00 CDT; UTC and Chicago agree on the date):nextRenewal= the 2026-10-27 domain,renewingSoon= both domains. ✅ - BUG —
now = 2026-10-28T01:30:00Z(2026-10-27 20:30 CDT — still Oct 27 for the viewer):nextRenewalreturns the 2026-10-28 domain andrenewingSoondrops the 2026-10-27 domain entirely. The domain renewing today (Chicago) vanishes from both the "Next renewal" card and the "Renewing in 45 days" spend card (render.ts:2533-2545) every evening from 19:00 CDT until midnight — and symmetrically, tomorrow's renewal is presented as today's for those five hours.
The existing dns tests (test/slice3.test.ts, 19 pass on the same tree) exercise summarizeDns only at 2026-12-28T00:00:00Z — midnight UTC, where UTC and Chicago dates differ too (Dec 27 18:00 CST) but the fixture's renewal dates are far enough away that the one-day shift changes nothing.
Why it matters
The /dns page is the fleet's renewal-spend surface: "Next renewal" and "Renewing in 45 days · $total" are how upcoming domain spend is spotted. For five hours every evening the page skips the domain that renews that day and understates the 45-day total by that domain's price — a wrong answer on a money page, in the timezone the rest of the aggregator already standardised on.
Acceptance criteria
-
summarizeDnscomputestodayvia the Chicago calendar (reusechicagoYmdfrom derive.ts) and the cutoff viaaddDaysYmd(today, soonDays)or an equivalent Chicago-anchored computation — notoISOString().slice(0, 10)day derivation left in dns.ts. - Regression test: at
2026-10-28T01:30:00Z(Oct 27 evening CDT) a domain renewing 2026-10-27 isnextRenewaland appears inrenewingSoon; a domain renewing 2026-10-28 also appears inrenewingSoon. - The existing slice3 dns tests keep passing, including the midnight-UTC summary case.
- A DST-boundary case is pinned (e.g. an instant during the CDT→CST transition week) so the cutoff arithmetic cannot drift by an hour into the wrong day.
Scope notes
- Distinct from aggregator: freshness() ages date-only stamps by the UTC day, not Chicago — a read dated today reports '1d ago' (and stale) from 19:00 Chicago onward #1629 (derive.ts
freshness()aging date-only stamps by the UTC day — fixed with the same helpers, different function and symptom) and from aggregator: roadmap Horizon dates are never validated — month 13 invents a Q5 lane and an 'undefined 2026' month, month 00 a Q0 lane, and ymdLabel throws on them #1628 (Horizon dates never validated). This is the one remainingtoISOString().slice(0, 10)day derivation in the aggregator's date-only comparisons — triage should grep to confirm no sibling remains. - Fix direction is deliberately narrow: dns.ts only. Whether
parseDnsRegistershould also validate that a renewal date is a real calendar date is aggregator: roadmap Horizon dates are never validated — month 13 invents a Q5 lane and an 'undefined 2026' month, month 00 a Q0 lane, and ymdLabel throws on them #1628-family territory and is not part of this issue.
Activity
developing-today commentedon Oct 28, 2026
CODE-674
dezren39 commentedon Oct 28, 2026
🤖 Agent note · filed
13 remaining items
dezren39 commentedon Oct 31, 2026
agent-note:v1 | worker repo-worker-code (Lane D, task 4242) | parked — CI + Codex pending on PR #3060
3921e93ce:summarizeDnsnow derives today viachicagoYmd(now)and the 45-day cutoff viaaddDaysYmd(today, soonDays)(derive.ts house helpers) instead of the UTCtoISOString()day.bun test test/slice3.test.ts— 21 pass / 1 fail; the failure is the pre-existing manifest route-uniqueness test owned by PR fix(aggregator): restore the overview page's group and the /board route #2604 (aggregator: pages manifest broken on main — PageDef.group missing (3 typecheck errors, 7 test failures) #2580), verified identical on the clean tree (19 pass / same 1 fail). New tests pin the evening-CDT case (20:30 CDT: Chicago-day renewal is nextRenewal + in renewingSoon) and the spring DST boundary (cutoff 2026-04-21 by calendar count).fixed_merged.dezren39 commentedon Oct 31, 2026
🤖 Agent note · picked up
fix(aggregator): summarizeDns ages renewals by the Chicago day (#1684) (
dezren39 commentedon Oct 31, 2026
🤖 Agent note · done
bun test test/slice3.test.tsre-run fresh this shift = 21 pass / 1 fail, the single failure being the pre-existing manifest route-uniqueness failure owned by PR fix(aggregator): restore the overview page's group and the /board route #2604 (aggregator: pages manifest broken on main — PageDef.group missing (3 typecheck errors, 7 test failures) #2580), unrelated to dns.ts. Codex review on head 3921e93: completed, no findings. No PR-tier Actions CI exists for aggregator paths; the only runs on the head were the two jules push workflows, which also fail on main (unrelated).