Skip to content

aggregator: a garbage or future-dated generatedAt is 'live' forever — the orchestration diagnosis and fleet-feed gate never check that the timestamp parses #1564

Closed

Description

@dezren39

Summary

The aggregator's freshness gates accept a generatedAt that is not a date at all — and a date arbitrarily far in the future — and report the data as live/fresh indefinitely:

  • orchestrationSectionProblem (pm-stack/aggregator/src/feed.ts:120-135, the check itself at :124) checks only typeof s.generatedAt === "string". It never checks that the string parses as a date.
  • diagnoseOrchestrationSection (feed.ts:165-176, age at :170) computes ageMs = Math.max(0, now - Date.parse(s.generatedAt)). For an unparseable string Date.parse is NaN, Math.max(0, NaN) is NaN, and NaN > ORCHESTRATION_STALE_MS is false — so the section diagnoses as live, with ageMs: NaN. For a future stamp the age clamps to 0, so the section stays live until 90 minutes after its future date.
  • isFleetFeed (feed.ts:193-204) has the same shape: generatedAt is string-only. A feed stamped "not-a-date" passes the gate and is served by loadFeed.
  • feedAgeText (feed.ts:225-227) renders the garbage case literally as NaNd old in the provenance strings (sources/live.ts:715,757,892,…), and the future case as fresh.
  • buildHealth (health.ts:229,249-250) derives feedAgeMs the same clamped way, so a garbage/future feed is never stale and never sets degraded.

Verified (this run, on main db6f7d0)

Probe ON THE LAPTOP (Bun, driving the real feed.ts, sha256 identical both sides; probe + log in the goal's hidden_files/probe-2026-10-27-laneB-feeddate/):

  • Control, section stamped 10 min ago → state=live (correct); 2 h ago → state=stale (correct).
  • Section stamped "not-a-date" → state=live, ageMs=NaN, feedAgeText="NaNd old".
  • Section stamped +30 days in the future → state=live, ageMs=0, feedAgeText="fresh" — and it stays live until 90 min after that future date.
  • isFleetFeed accepts both the garbage and the +30d feed (true); the valid control also true.

Why it matters

The diagnosis is the aggregator's honesty backbone (#1139/#1140): it decides whether Today / Needs-you render the orchestration section as current or show the "section is stale — its last published state" banners (render.ts:2215,2428), what provenance claims (live (fleet feed · …)), and whether /health reports the stack degraded. A publisher bug or clock skew that emits a malformed or future generatedAt therefore defeats every one of those surfaces at once — stale tiers, goals, and measurements present as live readings indefinitely, with no banner and no health signal. That is precisely the failure class the diagnosis was built to surface ("a publisher whose section is being rejected has a bug to fix"), except this input is never rejected.

Distinct from #1541 (quota-current's measuredAt freshness in a different module, different gate, different fix surface).

Acceptance criteria

  • A section whose generatedAt does not parse as a date diagnoses as invalid (failing check named generatedAt), not live; orchestrationSectionProblem is still the single source of truth for the gate.
  • A section/feed stamped implausibly in the future (beyond a small pinned clock-skew tolerance) is not reported live/fresh — it diagnoses stale or invalid per a documented rule, and the tolerance is pinned in a test.
  • isFleetFeed rejects a feed whose generatedAt does not parse; loadFeed therefore returns null for it instead of serving it as current.
  • feedAgeText / ageMsText can never render NaNd old for an input that reaches them (defence in depth at the validator is enough if the render paths are unreachable with NaN — say which in the fix).
  • Regression tests in pm-stack/aggregator/test/orchestration.test.ts (and health tests if buildHealth's feed age changes): garbage date, future date, and the existing fresh/stale controls.
  • Existing orchestration/health test suites still pass.

Activity

  1. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    app/aggregatorPackage/app: aggregator (pm-stack in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 28, 2026
  3. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (lane B, new-issue-creator-code-b)
    • Session / ID: cron job new-issue-creator-code-b, run 2026-10-27 20:50 CDT
    • Found via: filed this run
    • Task: Triage the generatedAt freshness gates in pm-stack/aggregator/src/feed.ts (orchestration diagnosis + fleet-feed gate) and health.ts — a garbage or future-dated timestamp currently reports live/fresh forever.
    • Expectation: effort/s — done looks like: unparseable generatedAt diagnoses invalid, future stamps are not live beyond a pinned skew tolerance, regression tests in orchestration.test.ts, existing suites green.
    • Links: verified with a Bun probe on the laptop driving the real feed.ts (sha256 13d18193 identical both sides); probe + log in the goal bookkeeping (probe-2026-10-27-laneB-feeddate/).
  4. added
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 28, 2026
  5. 48 remaining items

  6. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 28, 2026
  7. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  8. added a commit that references this issue on Oct 28, 2026
  9. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/aggregatorPackage/app: aggregator (pm-stack in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobstatus:donetask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions