Skip to content

aggregator(charges): amountFromBody's verb evidence treats future and negated charges as paid — 'will be charged $X', 'to be paid $X' and 'not charged $X' all return $X, bypassing #3120's due veto (PR #3193 residual) #3224

Closed

Description

@dezren39

Problem

amountFromBody in pm-stack/aggregator/scripts/produce-charge-candidates.ts:169-186 treats future and negated charge wording as paid evidence. The verb-evidence tier added today in PR #3193 (commit d6dfa4c1, the Codex-P2 follow-up to #3120) is:

/\b(?:charged|paid)[:\s]*\$([\d,]+\.\d{2})/i   // line 175

It matches the verb wherever it appears, with no check on what precedes it, and it runs before #3120's due-language veto (lines 178-182). So a body that says the money has not moved — or has not moved yet — yields an amount, and gmailCandidates (line 235: amount ??= amountFromBody(text)) turns it into a charge candidate for the message's date.

Evidence (verified this run, 2026-10-31)

Laptop probe ~/git/fleet/probe-2026-10-31-laneA-chargeverb/ (on the laptop): the real produce-charge-candidates.ts from origin/main, sha256 999f2dd904924bc718aa278f209441656e85da05db75aa33c6a95e6d8b0eefe3 — identical on the sandbox and laptop clones — imported under bun test. Control passes; all five target cases return an amount today and should return undefined:

Body Today Expected
Receipt\nYou were charged $20.00 for OpenAI\nBalance due $0.00 (control, PR #3193's own test) "20.00" "20.00"
Your subscription renews Nov 5\nYou will be charged $20.00 on Nov 5 "20.00" undefined
Reminder: your card will be charged $42.50 tomorrow "42.50" undefined
Invoice\nAmount to be paid $20.00 by Nov 15\nAmount due $20.00 "20.00" undefined
The attempt failed. You were not charged $20.00 "20.00" undefined
Good news: your card was never charged $20.00 for this order "20.00" undefined

Result: 1 pass / 5 fail (probe.txt in the probe dir).

Why it matters

This is exactly the class #3120 closed today — money that is merely due, scheduled, or explicitly not charged becoming a charge candidate — re-entering through the fix's own new tier:

  • A renewal/reminder mail ("will be charged … tomorrow") becomes a candidate dated the reminder's day, then the real charge arrives later and the pipeline carries both (or dedupes against the wrong date).
  • An invoice body's "to be paid $X" defeats the due veto that is the whole point of lines 178-182: the veto only runs when the paid tiers found nothing.
  • A failure/declined body that reassures "you were not charged $X" produces the candidate fix(aggregator): charges producer turns declined purchase alerts and outstanding invoices into charge candidates (PR #2149) #3120's subject gate was built to stop, whenever the subject itself doesn't carry a gated word (the Gmail body read at line 235 is reached for receipt/invoice subjects whose subject carried no amount).

Acceptance criteria

Related: #3120 (closed by PR #3193 — this is a residual in that fix, not a reopen: the subject gate and due veto themselves work as designed), #3121 (the sibling body-fallback issue), #3161 (the charges evidence contract design).

Activity

  1. 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 31, 2026
  2. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  3. added
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 31, 2026
  4. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    Intake review

    Related: PR #3193 (the verb-evidence tier this is a residual of) and #3120 (the due-language veto it bypasses).

    Notes: Verified by the filer's laptop probe against the real produce-charge-candidates.ts (origin/main, sha256 recorded in the body): 1 control pass / 5 target fails — future ("will be charged"), scheduled ("to be paid") and negated ("not charged", "never charged") wording all return amounts today. The body already carries acceptance criteria, so no body change was made.

    Risks: Money-path sensitivity: a fabricated "paid" candidate misstates charges in the aggregator. The negation/future guard must not over-veto genuine receipts (the PR #3193 control case must keep passing).

    Suggested approach: Add a pre-tier guard in amountFromBody — reject verb matches preceded by future/negation markers (will be, to be, not, never) within a small window — and promote the body's six-row probe table to a pinning test.

    — fleet monitor intake, 2026-10-31 fleet-monitor run (17:12 CDT)

  5. added
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 1, 2026
  6. 5 remaining items

  7. added
    app/pm-stackpm-stack (Pad/Grist) in developing-today/code
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 1, 2026
  8. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — picked up
    Agent: repo-worker-code (OpenChamber scheduled lane)
    Task: repo-health-code-pilot task 5677 (small_fix)
    At: 2026-11-02T10:53:33Z
    State: picked-up
    Found via: atomic queue claim; no saved progress.
    Next: Fresh metadata confirms #3224 OPEN with no open matching PR. I will reproduce the false-positive cases on current main, implement the narrow verb-tier guard, run targeted tests, and open a PR or park before the run budget expires.
    Links: #3224 · task 5677

  9. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — handed-off
    Agent: repo-worker-code (OpenChamber scheduled lane)
    Task: repo-health-code-pilot task 5677 (small_fix)
    At: 2026-11-02T11:00:36Z
    State: handed-off
    Outcome: PR #4333 opened at fd87ced to fix #3224. Targeted parser tests pass; CI is pending.
    Links: #3224 · #4333 · task 5677

  10. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — done
    Agent: repo-worker-code (OpenChamber scheduled lane)
    Task: repo-health-code-pilot task 5677 (small_fix)
    At: 2026-11-02T11:00:47Z
    State: done
    Outcome: PR #4333 OPEN, issue #3224 OPEN pending merge. CI checks were pending at completion. Task labels cleared; no sandbox backlog or sweep-log changes made.
    Links: #3224 · #4333 · task 5677

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)app/pm-stackpm-stack (Pad/Grist) in developing-today/codeeffort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)meta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/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