Skip to content

pm-stack(aggregator): isSaasService accepts impossible/non-ISO measuredAt — derived snapshot records fail isSnapshotRecord #5281

Open

Description

@dezren39

Problem

isSaasService in pm-stack/aggregator/src/feed.ts:697 (the element gate behind sanitizeSaasServices, applied at the loadFeed boundary) accepts any string as a SaaS service's measuredAt:

(typeof v.measuredAt === "string" || v.measuredAt === null) &&

That is weaker than every sibling measuredAt gate in the same file:

  • isQuotaFreshness — feed.ts:548: isIsoDate(v.measuredAt)
  • isPaygLine — feed.ts:969: (v.measuredAt === null || isIsoDate(v.measuredAt))

isIsoDate (validate.ts:116) requires a real ISO calendar date. The SaaS gate does not, so impossible and non-ISO stamps survive sanitization verbatim.

Verified (laptop bun probe at origin/main 12fcad9, probe in ~/git/fleet/probe-2026-11-03-laneA4-scan, removed after the run)

A minimal otherwise-valid service was passed through sanitizeSaasServices, then recordsFromSaasServices + isSnapshotRecord:

measuredAt kept by sanitizeSaasServices derived record ts isSnapshotRecord
2026-02-30 yes (dropped=0) 2026-02-30T12:00:00Z false
2026-04-31 yes (dropped=0) 2026-04-31T12:00:00Z false
March 2, 2026 yes (dropped=0) March 2, 2026 false
not-a-date yes (dropped=0) not-a-dateT12:00:00Z false
2026-03-01 (control) yes 2026-03-01T12:00:00Z true

Why it matters

Distinct from: #5188 (same sanitizer — PAYG/metric range gates, now fixed; it left measuredAt type-only), #5018 (the saas-extract export-overlay documents, a different input path), and #5102 (freshness() consumer).

Acceptance criteria

  • isSaasService requires measuredAt to be null or isIsoDate(...), matching isPaygLine in the same file; a service with an impossible or non-ISO measuredAt is dropped by sanitizeSaasServices and counted in dropped.
  • Regression tests cover at least 2026-02-30, 2026-04-31, and a non-ISO string (March 2, 2026) being dropped, with a valid ISO date and a null stamp kept as controls.
  • Aggregator test suite and typecheck stay green.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    priority/lowNice to have; do when convenient
    app/pm-stackpm-stack (Pad/Grist) in developing-today/code
    on Nov 4, 2026
  2. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (new-issue-creator-code-a)
    • Session / ID: cron new-issue-creator-code-a run 2026-11-03 22:05 CST
    • Found via: filed this run
    • Task: Gate isSaasService's measuredAt with isIsoDate (null stays allowed), matching isPaygLine/isQuotaFreshness in feed.ts; regression tests for impossible/non-ISO stamps.
    • Expectation: effort s — done when a service with an impossible/non-ISO measuredAt drops in sanitizeSaasServices (counted), valid/null stamps keep passing, and the aggregator suite + typecheck stay green.
    • Links: evidence + probe results in the issue body; queue packet enqueued this run (repo-health-code-pilot).
  3. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 4, 2026
  4. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

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

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  7. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

    • Agent: fleet monitor
    • Session / ID: repo-fleet-monitor run 2026-11-03 22:12 CST (safety-net reconciliation)
    • Found via: monitor reconciliation
    • Task: Label sync only: this issue carried queue/queued + queue/claimed at once while its live fix task (task 9179) is parked. Labels reset to the truth: queue/parked + status/parked, work/assigned kept. No task state changed.
    • Expectation: task 9179's holder resumes from its park as scheduled.
  8. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    app/pm-stackpm-stack (Pad/Grist) in developing-today/codekind/bugSomething isn't working (prefixed form of the classic bug label)priority/lowNice to have; do when convenientqueue/parkedQueue task is parked (waiting on CI, time, or an event)source/creatorFiled by the new-issue-creator jobstatus/parkedDeliberately paused with a recorded resume conditiontask/small-fixQueue packet kind: bounded fix with reproduction and targeted testswork/assignedQueue worker lifecycle state

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions