Repository navigation
Description
Problem
mapJulesItems in pm-stack/aggregator/src/sources/jules.ts maps the keeper-written jules-review-state.json into attention-feed entries with no validation of the items container or its elements — the file is parsed with a bare as JulesReviewState cast at the only call site, and every field is dereferenced as if the declared TypeScript shape were guaranteed.
Evidence (verified this run, main 7d1b081c)
src/sources/jules.ts:43—Object.entries(state.items ?? {})accepts any non-nullishitems(object, array, or string).src/sources/jules.ts:47—title: item.titlethrows on anullitem;:54—(item.state ?? "").toUpperCase()throws on a non-stringstate(e.g. a number).scripts/collect-fleet-feed.ts:506-512— the sole caller wraps the whole block in onecatchthat logscollector: jules-review state unreadable; no Jules sessions this run, so one malformed element discards every Jules session and the keeper totals for that run, under a message that claims the file was unreadable when it parsed fine.src/sources/jules.ts:85—julesSummarycountsObject.keys(state.items ?? {}), so a stringitemsis counted per character.
Probe (Bun, importing the real src/sources/jules.ts, main 7d1b081c):
| Input | Result |
|---|---|
items: { ses1: null, ses2: {state:"COMPLETED", …} } |
throws TypeError: null is not an object (evaluating 'item.title') — the valid ses2 entry is lost with it |
items: { ses1: { state: 42, … } } |
throws TypeError: (item.state ?? "").toUpperCase is not a function |
top-level null state |
throws TypeError: null is not an object (evaluating 'state.items') |
items: "nope" (string) |
fabricates 4 phantom sessions with sessionIds "0".."3", all Jules UNKNOWN; julesSummary.tracked reports 4 |
items: [ {state:"FAILED", …} ] (array) |
fabricates a session with sessionId "0" |
Why it matters
The collector is the only path by which supervised Jules sessions reach the dashboard's needs-you feed and the identity registry (recordFromSessionEntry per entry, same block). A single bad element — a null placeholder or a mistyped field in a state file written by a different program (the keeper, outside this repo) — silently empties the whole Jules surface for that collection run, and the log line misdiagnoses it as an unreadable file, sending any investigation to the wrong place. The string/array shapes are worse in the other direction: they invent sessions that do not exist.
Acceptance criteria
mapJulesItemsnever throws on a malformed state: a non-object top level, a non-plain-objectitems, and non-object elements are skipped (per element where possible), so valid sibling entries still map.- Non-string scalar fields on an otherwise usable item (e.g. numeric
state) do not kill the entry or the batch; the entry degrades the way a missing field already does (Jules UNKNOWN). julesSummary'strackedcount agrees with the set of itemsmapJulesItemswould consider (no per-character counting of a stringitems).- The collector's Jules block no longer reports a parseable-but-malformed state as "unreadable" — the log distinguishes unreadable/unparseable from malformed-but-recovered, or the mapper's per-element skips are counted/logged.
- Tests in the aggregator suite (slice2 jules mapping describes) cover: null element among valid ones, numeric
state, stringitems, arrayitems, top-levelnull.
Dedup
#1587 is julesSummary's freshest-note HHMM selection — a different function and defect. The feed-gate family (#2450/#2451/#2445/#2446/#2439) covers isFleetFeed section checks in live.ts, not this collector-side mapper; searches for mapJulesItems and Jules collector validation returned no covering issue, open or closed.
Activity
dezren39 commentedon Oct 30, 2026
🤖 Agent note · filed
16 remaining items
dezren39 commentedon Nov 2, 2026
agent-note:v1 — state=parked
testis pending and none are failing.bun test test/slice2.test.tspasses (32 tests). Full suite's 2 failures and typecheck diagnostics were reproduced on clean main; no changed-file type diagnostics.dezren39 commentedon Nov 2, 2026
Agent note — task 5362 (lane F resume)
8c7ebc99e, diff re-read and matches the task 3763 pin exactly (sharedvalidJulesEntrieshelper, per-element skip, string-only field degradation, collector catch narrowed to read+parse with the malformed-skipped log).bun test test/slice2.test.tsPASS (32 tests); full-suite failures + typecheck errors reproduced on clean main (pre-existing, unrelated).testcheck still QUEUED (~30 min) and no Codex review exists on this head yet — re-review requested on PR fix(aggregator): validate Jules review items (#2531) #4208. Parked 20m per the CI rule; resume merges once checks resolve and Codex findings (if any) are dispositioned.dezren39 commentedon Nov 2, 2026
agent-note:v1 — parked (CI pending) — Lane D
dezren39 commentedon Nov 2, 2026
agent-note:v1 — state: picked-up (small_fix task 5362, lane F shift)
Merge pull request #4208 from developing-today/queue/5362-2531-jules-…
dezren39 commentedon Nov 2, 2026
agent-note:v1 — state: done (small_fix task 5362, lane F shift)