Repository navigation
Description
Summary
iso() in the aggregator's OpenCode session mapper converts a server-supplied millisecond timestamp with no range/finite gate, so one session whose time.updated (or time.created) is beyond the valid Date range makes mapServerSessions throw — and every caller fails soft at the whole-server level, so that one bad session silently drops all sessions from that OpenCode server from the attention feed and the durable registry.
Evidence (main 5a34fa70)
pm-stack/aggregator/src/sources/opencode.ts:86-87:const iso = (ms: number | undefined): string | null => typeof ms === "number" && ms > 0 ? new Date(ms).toISOString() : null;
typeof+> 0admit1e16,Number.MAX_VALUE, andInfinity-adjacent magnitudes. JSDateis only valid to ±8.64e15 ms;new Date(1e16).toISOString()throwsRangeError: Invalid Date. (JSON cannot carryInfinity, but it happily carries1e16.)- The throw sites are unguarded: entry construction in
mapOne(opencode.ts:174createdAt: iso(s.time?.created),:179lastActivityAt: iso(s.time?.updated)) and the long-running-call stamp at:255.mapOne/mapServerSessionshave no per-session try/catch — one throw aborts the whole map. - The bad session is reliably included before it throws: the attention filter at
opencode.ts:146isnow - s.time.updated <= ATTENTION_WINDOW_MS, and for a huge futureupdatedthat difference is negative, so the session passes the filter and sorts first (:148). - Callers fail soft only at server granularity, which is what turns one bad row into a total loss:
pm-stack/aggregator/src/sources/live.ts:878(attention()) and:983(registry()): a throw fromlaptopMapped()is caught and the laptop part is dropped entirely (laptopSeen = false).pm-stack/aggregator/scripts/collect-fleet-feed.ts:456: the sandboxmapServerSessionscall sits in a try that leavesattention = []for the whole sandbox server on throw.
Reproduction (this run)
Sandbox Bun probe driving the real mapServerSessions against a stub v2 server (probe in /tmp/probe-laneB-ociso/probe.ts):
- Control — one normal session:
entries: 1,lastActivityAtstamped correctly. - Experiment — the same good session plus one session with
time.updated = 1e16:mapServerSessionsthrewRangeError: Invalid Date; zero entries returned, the good session included.
Why it matters
The timestamps come from a remote OpenCode server's JSON — data this process does not control (a skewed clock, a corrupt store, a different server version). Today a single out-of-range stamp blacks out an entire server's sessions from attention + registry with no error naming the cause: the aggregator just reports the laptop/sandbox source as unreachable/fixtures. Per-session data faults should degrade per-session.
Acceptance criteria
-
iso()(or its callers) returnsnullfor any value that is not a finite, in-Date-range timestamp — no throw for1e16,Number.MAX_VALUE, or negative/huge magnitudes. - One session with an out-of-range
time.created/time.updated/messagetime.createddoes not prevent the remaining sessions from the same server being mapped (regression test with a mixed good/bad session list against the real mapper, inpm-stack/aggregator/test/opencode.test.ts). - Triage pins whether far-future-but-valid stamps (e.g. +1 year) also count as "fresh" in the
:146attention filter, or whether that stays as-is — record the decision on this issue. - Existing aggregator tests pass.
Dedup
Checked open + closed issues for mapServerSessions, "opencode iso", "toISOString throws": no existing issue covers this mapper. #2196 is quota-extract's monthDayTime throw (different file/mechanism); #1540/#2253/#2264 are store/quota/snapshot date gates, distinct modules.
Activity
developing-today commentedon Oct 29, 2026
CODE-1144
dezren39 commentedon Oct 29, 2026
🤖 Agent note · filed
11 remaining items
dezren39 commentedon Oct 31, 2026
agent-note:v1
state: parked
task: 4327 (lane E)
pr: #3093 @ 8de9397
note: Implemented per pinned decisions: shared validMs predicate (finite, 0 < ms <= 8.64e15) inside iso() and the freshness inclusion; no per-session try/catch; far-future-valid stays fresh. bun test test/opencode.test.ts on laptop: 4 pass, 0 fail (new mixed good/bad regression). Parked for CI + Codex review; resume: CI green + Codex clean -> merge -> close this issue.
dezren39 commentedon Oct 31, 2026
Lane D picked up task 4327 — resuming PR 3093. Fresh check: head 8de9397 matches the checkpoint, Codex review COMPLETED on that head with no findings, diff verified (validMs gates both iso() and the freshness inclusion; regression tests for 1e16 updated/created). Aggregator PRs get no Actions CI, so verification is the laptop aggregator suite before merge.
Merge pull request #3093 from developing-today/queue/4327-2286-iso-range
dezren39 commentedon Oct 31, 2026
Done — PR 3093 merged (2ac4f4c). Codex clean on 8de9397; laptop verification: opencode.test.ts 4/4 pass; full aggregator suite 691 pass with 7 manifest/page failures proven identical on clean main (pre-existing, unrelated). Task 4327 completed fixed_merged.