Skip to content

tech-debt batch 4: rename currentCharges + hot-path query dedupe (#153/#154)#167

Merged
delabrcd merged 1 commit into
mainfrom
tech-debt/batch-4-numeric
Jun 22, 2026
Merged

tech-debt batch 4: rename currentCharges + hot-path query dedupe (#153/#154)#167
delabrcd merged 1 commit into
mainfrom
tech-debt/batch-4-numeric

Conversation

@delabrcd

Copy link
Copy Markdown
Owner

Tech-debt batch 4 — numeric-path cleanup (epic #161). Behavior-preserving; produced money values are byte-identical.

Closes #153, closes #154.

#153 — rename misleading totalDueAmount-named fields → currentCharges

The in-memory derived fields that carry currentCharges were named totalDueAmount (the field standards §1 forbids for analysis). Renamed across series.ts (BillInput), queries.ts feed + shapeBill/latestBill, csv.ts (BillCsvRow, same CSV header), notifications.ts shapes, and in-lockstep readers (useDashboardData, BillsPanel, statSpec, SettingsView) + tests. The real Prisma Bill.totalDueAmount column and the NG-API field are untouched.

  • The ?? b.totalDueAmount fallback (for a bill whose PDF isn't parsed yet) is kept exactly (no value change). Whether to keep falling back to the forbidden API field is a separate semantic decision — flagged on Rename totalDueAmount-named fields that actually carry currentCharges #153, not changed here.
  • The persisted Notification.payload JSON key is deliberately kept as totalDueAmount (renaming it wouldn't be byte-identical for existing prod rows — syncNotifications upserts skipDuplicates and NotificationsBell reads the key). Append-only discipline (standards §6).

#154 — hot-path query efficiency (behavior-preserving)

  • New lightweight getAccountMeta(accountId) (account + billCount + first/latest statement + schedule) — /api/settings uses it instead of the full getOverview (was running Kalman/projection/anomaly/series for ~5 scalars). Settings JSON unchanged.
  • getMonthlySeries now accepts optional prefetched {account, bills}; getOverview fetches them once and feeds both itself and the series (was running the same account+bills queries twice per /api/overview). Series is order-independent of bill order (Map aggregation) → byte-identical.

Verification (local)

  • Docker test stage: 67 files / 973 tests (existing series/csv/notifications tests pass unchanged = value-preservation proof). Production build green. No new dependency.
  • ⚠ Touches displayed money numbers → lead will confirm GET /api/verify green on staging's real data before release.

…ath queries (#154)

#153 — rename the in-memory fields literally named `totalDueAmount` that actually
carry `currentCharges` (standards §1: currentCharges is canonical, never the API
totalDueAmount). Pure rename, value-preserving:
  - series.ts BillInput.totalDueAmount -> currentCharges (+ its read into billTotal)
  - queries.ts series feed (line ~159) now produces `currentCharges:` and shapeBill's
    derived field is `currentCharges`; lifetimeSpend + latestBill readers follow
  - csv.ts BillCsvRow.totalDueAmount -> currentCharges (emitted under the
    `currentCharges` CSV header, unchanged)
  - notifications.ts NotificationsOverview.latestBill / NotificationBill /
    NotificationBillInput -> currentCharges
  - wire/in-app readers updated in lockstep (useDashboardData, BillsPanel,
    statSpec, SettingsView) so displayed values are byte-identical

The `?? b.totalDueAmount` fallback (for a bill whose PDF isn't parsed yet) is kept
EXACTLY as-is so produced numbers + /api/verify stay identical; whether to keep
falling back to the forbidden API field is flagged as a separate decision.

The PERSISTED Notification.payload JSON key stays `totalDueAmount` (a new distinct
NotificationBillPayload type) — renaming it would not be byte-identical on existing
prod rows (skipDuplicates never rewrites them; the bell reads the persisted key).

#154 — remove redundant hot-path queries, behavior-preserving:
  - new getAccountMeta(accountId): the ~5 scalars /api/settings actually uses
    (account/billCount/firstStatement/latestBill/schedule) via cheap queries, no
    series/Kalman/projection/anomaly/budget pipeline; /api/settings now calls it
  - getMonthlySeries accepts optional pre-fetched {account, bills}; getOverview
    gathers account+bills once and feeds both itself and the series (was running
    account.findUnique + bill.findMany twice per /api/overview hit). Series is
    order-independent of the bills, so reuse yields a byte-identical result.

Docker test stage: 973 tests pass. Production builder (eslint + tsc + next build):
green. /api/verify must still be confirmed green on staging's real account.
@delabrcd delabrcd merged commit 6a4a497 into main Jun 22, 2026
6 checks passed
@delabrcd delabrcd deleted the tech-debt/batch-4-numeric branch June 22, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hot-path query efficiency: /api/settings + getOverview double-fetch Rename totalDueAmount-named fields that actually carry currentCharges

1 participant