Repository navigation
Open
Labels
app/pm-stackpm-stack (Pad/Grist) in developing-today/codepm-stack (Pad/Grist) in developing-today/codeeffort/mMedium: expected under 1 day of workMedium: expected under 1 day of workkind/featureNew feature or capability requestNew feature or capability requestpriority/normalOrdinary priority (the default)Ordinary priority (the default)source/creatorFiled by the new-issue-creator jobFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this itemQueue packet kind: verify, reproduce, and route this item
Description
Part of epic #1184; implementation follow-up of design issue #1259 (spend rollups). Design note: doc/spend-rollups-design-1259.md.
Scope
Attach real PAYG dollar charges to pools/services in the spend rollups, extending the existing charges pipeline — pm-stack/aggregator/src/charges-collect.ts / charges-match.ts / charges-catalog.ts (#1057, Plaid + Gmail charge candidates matched to services) — instead of building a second money path.
Rules (per the design note)
- Only matched, real charges enter the dollars column. Unmatched charges stay visible in the existing unmatched-charge surfacing; they are never force-attributed to a project/epic.
- A charge attributes to a project/epic only through the pool/service it matched AND attributed session activity for that pool in the charge period; otherwise it lands at stack level as "unattributed dollars" — shown, not hidden.
- Dollars are never converted to or from tokens or share-of-window, in either direction, anywhere in this slice.
- OpenCode's per-session
costfield is a list-price estimate: it is excluded from the dollars column entirely (drill-down labelling is the rendering slice's job).
Acceptance criteria
- Tests: matched charge with in-period attributed activity → project/epic dollars; matched charge without → stack-level unattributed dollars; unmatched charge → absent from rollups, still surfaced as unmatched.
- Reconciliation: rollup dollars for a period equal the charges pipeline's matched totals for that period.
- No code path in the PR reads a per-session
costvalue into a dollars total (guarded by a test on the rollup writer inputs).
Checks
bun testandbunx tsc --noEmitinpm-stack/aggregatorpass (CI on the PR).
Metadata
Metadata
Assignees
Labels
app/pm-stackpm-stack (Pad/Grist) in developing-today/codepm-stack (Pad/Grist) in developing-today/codeeffort/mMedium: expected under 1 day of workMedium: expected under 1 day of workkind/featureNew feature or capability requestNew feature or capability requestpriority/normalOrdinary priority (the default)Ordinary priority (the default)source/creatorFiled by the new-issue-creator jobFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this itemQueue packet kind: verify, reproduce, and route this item
Activity
dezren39 commentedon Nov 3, 2026
agent-note:v1
state: triaged (coverage pass)
Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as triage at priority 40 (priority/normal). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
Found via: coverage pass 2026-11-03
dezren39 commentedon Nov 3, 2026
🤖 Agent note · done
gh pr list --search 4826returns only the merged design-note docs PR docs(pm-stack): spend rollups design note (#1259) #4828 and PR docs(pm-stack): correct slice issue numbers in spend-rollups design note (#1259) #4855.dda1def9710f2fc0adb45076aa4edc31f8be6eb5(laptop primary, read-only check): the charges pipeline the slice must extend is present (pm-stack/aggregator/src/charges-collect.ts,charges-match.ts,charges-catalog.ts), and a grep forunattributed dollars/unattributedDollarsacross aggregatorsrc/andtest/returns nothing — the slice's signature behaviour (matched-but-unattributed charges landing as stack-level unattributed dollars) does not exist yet.doc/spend-rollups-design-1259.md.small_fix, repo-health-code-pilot, deduperepo-health:v1:fix:developing-today/code:issue:4826) carrying the issue's acceptance and checks (bun test+bunx tsc --noEmitinpm-stack/aggregator, via CI on the PR). Issue impl(pm-stack): PAYG dollar attribution via the charges pipeline (#1259 slice 5) #4826 labels set toqueue/queuedfor task 8767.dezren39 commentedon Nov 3, 2026
🤖 Agent note · picked up
costreads into dollar totals; acceptance + reconciliation + guard tests per the issue bodydezren39 commentedon Nov 3, 2026
🤖 Agent note · done (PR opened)
src/spend-dollars.tspure core (matchedChargesFrom+attributePaygDollars): matched charges attribute to a project/epic only with attributed activity for that service in the charge's month; otherwise stack-level unattributed dollars with a reason (no-attributed-activity/ambiguous-activity, never split, never guessed); unmatched charges absent from rollups by construction; integer-cents reconciliation (rollup total = pipeline matched total per month). Acceptance + reconciliation + no-per-session-cost guard tests intest/spend-dollars-4826.test.ts(11/11). Full aggregator suite on the laptop worktree: 1431 pass / 0 fail;tscshows only the pre-existingoverview.test.tserror also present on clean main. Slices 1 (impl(pm-stack): spend attribution projection — session to issue/epic resolution, unattributed shown (#1259 slice 1) #4822) and 2 (impl(pm-stack): spend rollup store — weekly/monthly per project/epic, versioned restatement (#1259 slice 2) #4823) are still open — this core is what they will feed/persist; no store or rendering built here.