Repository navigation
Description
Problem
In staged mode (#4641), the charge-candidates producer takes its period from the fetcher's charge-inputs-manifest.json — and never validates it:
pm-stack/aggregator/scripts/produce-charge-candidates.tsmain()(:371-378):start = manifest.start; end = manifest.end;straight fromJSON.parse, with no presence, format, calendar, or ordering check. The same file already imports and appliesisRealCalendarDateto every Plaid transaction date (:133) and every Gmail message day (:326) — the manifest period is the one date input exempt from it.- A manifest whose
start/endare missing (e.g. a fetcher schema drift or a hand-staged directory) makesstart/endundefined: the Gmail path dies ond.replaceAllinsidegmailCandidatesand is swallowed bymain's catch ("plaid candidates only"), the Plaid path ignores the period entirely in staged mode, and the producer writes a candidates file withperiod: {}(undefined fields vanish inJSON.stringify), logsundefined..undefined, and exits 0. - The daily collector consumes the file keyed by its period; a period-less batch is indistinguishable from a successful run at the exit-code/log level the fleet monitors, so the corruption surfaces only as missing/misattributed charges downstream. A malformed date string (e.g.
2026-13-40) or an inverted window (endbeforestart) passes the same way: nothing ever compares the staged payloads against a real window.
This is the manifest counterpart of the staged-mode contract at :66-69: staging that does not describe a real period is absent staging, and must fail visibly.
Evidence (verified this run, laptop probe at origin/main 17610f5)
Probe: ~/git/fleet/probe-2026-11-02-laneB-chargestaged/ — producer extracted verbatim from origin/main (script md5 70bff805), complete staging (both Gmail triage responses, one Plaid transaction, one Gmail receipt), manifest replaced with {"note":"no period fields"}:
- Output:
producer: wrote out-probe2.json — 1 candidates for undefined..undefined (plaid 1, gmail 0, gmail skipped 0), exit 0; stderrproducer: gmail read failed (undefined is not an object (evaluating 'd.replaceAll')); plaid candidates only. - The written file's period is literally
"period": {}. - Control with the good manifest (
{"start":"2026-11-01","end":"2026-11-02"}) in the same probe directory: 2 candidates, correct period, exit 0.
Related: #4660 (staged triage fallback in the same feature — different mechanism: the triage loop, not the manifest read), #4641 (the staged split), #3333 (live-mode --start/--end argument handling — different input path).
Acceptance criteria
- In staged mode, a manifest with a missing, malformed, non-calendar, or inverted (
end<start) period fails the run visibly: non-zero exit and no candidates file presented as a successful batch. - Validation reuses the file's existing
isRealCalendarDatestandard for both fields. - With a valid manifest, staged output is unchanged (control case above).
- Live mode (env unset) is unchanged.
- A regression test or scripted fixture covers the missing-fields manifest case.
Activity
dezren39 commentedon Nov 2, 2026
🤖 Agent note · filed
probe-2026-11-02-laneB-chargestaged@ origin/main 17610f5): a staged manifest without start/end makes the producer write a candidates file withperiod: {}, logundefined..undefined, drop Gmail via a swallowed TypeError, and exit 0 — the manifest period is the one date input never passed through the file's own isRealCalendarDate checks.creator-b-2026-11-02-1720/packets/packet-4663-triage.json(enqueued to repo-health-code-pilot); companion staged-mode defect aggregator(charges-producer): staged mode falls back to the live Gmail CLI when gmail-triage.json is short — the whole Gmail source is silently dropped and the run exits 0 #466015 remaining items
dezren39 commentedon Nov 3, 2026
Agent note — parked (CI pending)
repo-worker-code), lanecode-kqueue/6627-4663-staged-manifest-period(head5239c6c0d, re-verified fresh) — the prior lane was rate-limited out of PR creation. PR aggregator(charges-producer): validate the staged manifest period (#4663) #4670 is MERGEABLE, diff is exactly the producer + its test, Codex review completed with no findings. Prior-lane verification stands in task 6627 checkpoints: bun tests 29+31 pass, probe rerun correct.dezren39 commentedon Nov 3, 2026
🤖 Agent note · done
Triage verdict: CONFIRMED on current main (17610f5, verified fresh via
ghraw read ofpm-stack/aggregator/scripts/produce-charge-candidates.tsthis shift)::371-376— staged branch:const manifest = JSON.parse(...), thenstart = manifest.start; end = manifest.end;with no presence, format, calendar, or ordering check anywhere in the file for the manifest period (grep:manifestoccurs only at:369-376).isRealCalendarDateis imported at:58and applied to Plaid transaction dates (:133) and Gmail message days (:326) — the manifest period is the one date input exempt.undefinedbounds is swallowed bymain's catch ("plaid candidates only"), after which the producer writesperiod: {start, end}—undefinedfields drop inJSON.stringify, yielding the literalperiod: {}— and exits 0. This matches the creator's laptop probe on the same commit (field-less manifest →1 candidates for undefined..undefined, exit 0, fileperiod {}; good-manifest control → 2 candidates, correct period).Routing: fix enqueued as task 6627 (small_fix, dedupe_key
repo-health:v1:fix:developing-today/code:issue:4663): validate both manifest fields withisRealCalendarDateplusend >= startin the staged branch before any candidate work; any failure exits non-zero with no successful candidates file; regression fixture for the missing-fields case; live mode unchanged. Issue #4663 stays open for task 6627.dezren39 commentedon Nov 3, 2026
🤖 Agent note · picked up — PR #4670 conflicted with main, fixing forward
Merge pull request #4670 from developing-today/queue/6627-4663-staged…
dezren39 commentedon Nov 3, 2026
🤖 Agent note · done — PR #4670 merged, issue #4663 closed
bun test test/produce-charge-candidates.test.ts31/31 pass at the merged head. Full aggregator suite: 1206 pass, 2 fail + 1 error, all verified pre-existing on clean origin/main (brief-surfaces render failure; web-push package missing in alerts) — unrelated to this change.