- api.probe: assert a regular user is 403 on /api/admin/*, /api/status,
/api/about-admin (read + write) — B1/B11 authorization
- confirmed (static): settings PUT whitelists USER_SETTING_KEYS (no
mass-assignment), notifications route splits requireAdmin/requireUser
- docs: mark B10/B11/B12 probed
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- scripts/prod-smoke.js + prod-smoke.sh: build, boot `node server.js` serving
dist/ against a scratch DB, and drive the real artifact with Playwright
(login + lazy routes) to confirm the vendor-chunk split loads in production
- npm run smoke:prod; passes green
- docs: B15 harness command + status
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- routes/summary buildBankTracking: fetch unpaid candidates and filter by
resolveDueDate in JS so annual / off-month quarterly bills don't inflate the
SimpleFIN "unpaid this month" metric (completes the occurrence-gating family)
- add tests/summaryBankTracking.test.js (isolated route test)
- docs: archive QA-B5-02; Active Findings Log now empty (0 open)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- analyticsService: only add a bill's expected_amount in months it actually
occurs (resolveDueDate), so annual / off-month quarterly bills no longer
inflate the expected-vs-actual line every month (QA-B5-03, same root as B5-01)
- add a Tracker<->Analytics reconciliation guard to e2e/api.probe.spec.js
- docs: archive QA-B5-03; cycle log
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- routes/summary: filter the expense list by resolveDueDate so annual and
off-month quarterly bills no longer inflate the monthly total / "monthly
result" — the Summary now agrees with the Tracker for the same month (QA-B5-01)
- add a Tracker<->Summary reconciliation guard in e2e/api.probe.spec.js
- docs: archive QA-B5-01; track QA-B5-02 (SimpleFIN unpaid_this_month residual)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- utils/money: toCents rounds off the shortest decimal string instead of
Math.round(n*100), so 1.005 -> 101 (not 100). Output is identical for all
integer / <=2-decimal / "$1,234.56" inputs, so no downstream change (QA-B7-01)
- add tests/money.test.js (9 tests; the money core previously had none)
- docs: archive QA-B7-01 to HISTORY v0.41.0; QA cycle 1 now 0 open findings
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- CategoriesPage: category rows are now a plain container with a dedicated
chevron toggle button, instead of role=button rows nesting action buttons
- PlanStatusBanner: split the collapsible header into a name/progress toggle,
sibling action buttons, and a chevron toggle (actions no longer nested in the
trigger button)
- add e2e/categories.spec.js expand regression; all 8 authed pages now pass axe
- docs: archive QA-B14-02 to HISTORY v0.41.0; QA plan status/cycle-log
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>