Date: 2026-04-05
Scope: Adversarial architecture review after /review (Codex + Claude Code). T1–T4 shipped; T5–T6 deferred per issue brief.
Inputs: experiments/results/review-010.md, experiments/ideas/issue-010.md, agents/peer-review-agent.md Challenge Mode.
No blocking issues.
- Fit: Monolith Next.js + Neon Postgres + session auth matches Phase 3 scope and expected user volume. Unified scope + SQL-backed aggregates (replacing row-capped client math) removes a real scalability ceiling for heavy accounts.
- AI path: Facts JSON (Layer A) → structured Gemini output with citation validation preserves a defensible boundary: amounts stay server-authoritative; model copy is constrained. Documented limitation: Google GenAI SDK does not cancel in-flight requests on timeout — timeout rejects to the caller but work may continue (cost/latency tail). Acceptable for MVP if monitored; not a ship blocker given 9s cap and rule-based fallback.
- Complexity: Phase 3 added several API surfaces (transactions, scope, insights, coaching expansion). The split into
useDashboardState,TxnFilterBar,TxnRow, and lib modules is appropriate; no unnecessary microservices.
Non-blocking observations
- Read-path cost:
GET /api/transactionsand merchant insight routes can execute heavyGROUP BY/ filtered scans for an authenticated user. Unlikestatement/parse, there is no explicit rate limit on these reads. Cross-tenant abuse is mitigated by auth; self-DoS or cost amplification via rapid UI actions remains a product hardening item for a later slice (not blocking QA).
No blocking issues.
- Auth: Code review confirmed
getSessionUser()before data access on new routes and ownership checks onstatement_id/statement_ids. - Races: Dashboard load uses
AbortControllerto prevent stale scope overwrites — addresses the highest-risk client race called out in review-010. - Partial AI failure: Coaching narrative failure paths return structured
ok: falseoutcomes; rule-basedmessageon advisories remains. PostHog server events use fire-and-forget.catch(() => {})on hot paths per anti-patterns. - Persistence:
persist-statementfail-closed pattern preserved from prior cycles. - Observability: Sentry wired in dashboard/transactions/backfill catch blocks per second review pass.
Non-blocking observations
- Merchant normalization: Heuristic
merchant_keywill mis-bucket noisy descriptors; issue brief already flags parser variance — aligns with deferred deeper normalization (T5–T6 territory). - Backfill route: Cursor-based batching + batched
unnestUPDATE reduces timeout risk; still a privileged maintenance path — ensure it stays cron/admin-only in operations (verify deployment posture in/qa-test).
No blocking issues.
- Problem statement: Unified date/source scope, transaction-native truth, merchant rollups, and facts-grounded coaching match
issue-010.mddesired outcome for T1–T4. - Deferred scope: T5–T6 explicitly deferred — no spec drift in shipped code.
- Telemetry: New events are server-side single-emission for the review scope (
transactions_*,scope_changed,merchant_rollup_clicked,coaching_facts_expanded,coaching_narrative_*). North Star proxy (e.g. second-month upload) remains a/metric-planconcern, not a peer-review gate failure. - Safety: Generative path instructs no invented amounts, no ₹ in narrative, no securities advice — consistent with
docs/COACHING-TONE.mddirection.
Non-blocking observations
- Perceived vs actual: Plan/issue called out explicit PRD decision for global rollup; implementation follows blended “actual” + profile perceived baseline — consistent with documented plan; revisit if product wants per-account perceived later.
No blocking issues across the three lenses. Remaining items are hardening and follow-ups (read-path rate limits, merchant quality, metric-plan alignment), appropriate for /qa-test and /metric-plan, not for re-opening execute-plan.
| Assumption | Risk | Mitigation in repo |
|---|---|---|
| Heuristic merchant keys are “good enough” for coaching | Mis-ranked merchants, high “Other” | Known; exploration/issue callouts; T5–T6 deferred |
| Authenticated users won’t hammer expensive list endpoints | DB load / cost | Auth bounds cross-user abuse; per-user throttle not yet required for MVP gate |
| Gemini returns schema-valid JSON often enough | Bad JSON / hallucination | Zod + citation validation + timeout + fallback to rules |
Counterarguments are contained; none justify blocking QA.
Approval is conditional on no new evidence of auth bypass or cross-tenant data leak; code review + this pass did not find one. If QA finds a route regression, reopen.
- Reliability (3am): Gemini timeout without true abort — monitor p95 spend and consider queue/async coaching later if costs spike. Non-blocking.
- Adversarial user: Session-only abuse of transactions API could stress own data; rate limit is product backlog. Non-blocking.
- Future maintainer:
TIMEOUT_MS+ SDK abort note ingemini-coaching-narrative.ts— good; keep when upgrading@google/genai.
No mandatory agent-file edits required from this review. Suggested for /learning if reinforced:
- File:
agents/backend-architect-agent.md
Section: Mandatory Pre-Approval Checklist
Add: "For finance dashboards with user-scoped heavy read APIs (aggregations, GROUP BY, unbounded filters), document either pagination/cursor guarantees, per-user rate limits, or explicit 'trusted client' assumption in the plan."
- Root VIJ-37 should receive
/linear-sync statusafter this artifact andproject-state.mdupdate (peer-review PASS → still Review stage label until QA completes per linear-sync mapping).