Bug: accounts.stats investmentTotal ignores investments table (Itaú OF shows R$0 invested)
Context (pt-BR)
Post Featurebase 6aea1bfcc28a57fa423bb6fd (MCP pluma_accounts_stats, gravidade alta, 1 voto). Relator UUID 3573845b-21b5-47d7-8d23-dae23393231c (mesmo de PLU-844). Cliente MCP relatou "investimentos do Itaú não importados" porque investmentTotal = 0 e só há conta corrente + cartão Itaú em accounts.
Não é falha de sync Pluggy neste caso. Posições já estão em investments. O buraco é agregação financeira (accounts.stats.investmentTotal / netWorth e MCP) que ignora a tabela investments. SWE não começa sem decisão do Lucca (A/B/C abaixo) — matriz: cálculo financeiro.
Problem
Open Finance Itaú (connector 601) syncs investment positions into investments linked to the checking/credit connected_account. It does not create accounts rows with type=investment (0 such rows for connector 601 in prod).
accounts.stats (apps/web/api/trpc/_services/accounts.ts) computes:
investmentTotal = Σ balance WHERE accounts.type ∈ {investment, INVESTMENT}
netWorth = investmentTotal + cashTotal − creditTotal
So for every user whose wealth lives only in investments (the Itaú / OF pattern), MCP pluma_accounts_stats and any UI bound to accounts.stats report R$ 0 invested and an understated net worth — even when Contas UI (AssetCategoriesSection → fetchInvestmentsWithAccounts) already sums investments.balance correctly.
The Featurebase filing is an MCP false-negative on import; the product bug is stats ≠ Contas / Investimentos.
Evidence (read-only, anonymized)
Reporter
- UUID
3573845b-21b5-47d7-8d23-dae23393231c - Itaú
connected_accountactive, connector601, last_sync 2026-11-03, nosync_error accountson that item: checking + credit only (notype=investment)investmentson that CA: 3 rows, allFIXED_INCOME/ACTIVE/ not hidden, with positivebalance/amount/value(sum > R$ 50k; aligns with ">~90 mil" claim without exposing exact amounts)- MCP
pluma_accounts_stats→investmentTotal = 0(by design of the buggy aggregator)
System impact (COUNT only)
| Metric | Count |
| -- | -- |
| Active Itaú items (connector 601) | ~344 |
| …with ≥1 investment position | 185 |
| …with positive position value | 131 |
| …with zero positions | 159 |
| accounts with type=investment (all connectors) | 1 (1 user) |
| Users with visible investments rows | 909 |
| Users with positions but no investment account | 908 |
Bank profile 601 / 201 Itaú: known_issues=[], needs_correction=false.
Secondary cohort: ~159 Itaú items with no positions may be consent / Pluggy empty / product INV gap (see historical PLU-107). Out of scope for this issue until Lucca asks for a Pluggy read on a sample itemId.
Expected behavior
accounts.stats.investmentTotal(and thereforenetWorth/ MCPpluma_accounts_stats) must include the sum of visible non-manualinvestmentspositions (same population Contas already shows), not onlyaccounts.type=investment.- Contas / Investimentos Beta and stats must agree for the same user scope.
- Creating a synthetic
accounts.type=investmentrow is not required for the minimum fix (option A).
Acceptance criteria (Gherkin)
Feature: accounts.stats includes investments table positions
Scenario: Itaú-style user with positions and no investment account
Given a user has BRL cash C and credit debt D
And N ACTIVE non-manual investments with positive balance totaling I
And zero accounts with type=investment
When accounts.stats runs
Then investmentTotal equals I
And netWorth equals C + I - D (with credit sign rules from PLU-844)
Scenario: Contas and stats agree
Given the same user as above
When Contas AssetCategoriesSection investment header and accounts.stats run
Then both investment totals equal I within rounding
Scenario: Manual investments are not double-counted
Given a manual investment already counted via manualPortfolio
When accounts.stats aggregates investments
Then is_manual=true rows are excluded (same as fetchInvestmentsWithAccounts)
Scenario: Hidden / inactive positions excluded
Given investments with is_hidden=true or status≠ACTIVE
When accounts.stats runs
Then those rows do not enter investmentTotal
Scenario: MCP mirrors the fix
Given the same authenticated user
When pluma_accounts_stats is called
Then investmentTotal is no longer zero solely because accounts.type≠investment
Out of scope
- Pluggy upstream ticket / reconnect for the ~159 Itaú items with zero positions (separate investigation).
- Creating
accounts.type=investmentmirror rows from sync (option B only). - Dashboard
totalBalancecredit sign bug (PLU-844) — coordinate so both aggregators end consistent. - Investment returns / Dia-Mês columns (PLU-801), cost basis (PLU-784).
Risks
- Raising
investmentTotal/netWorthfor ~908 users changes headline wealth (correct, but CX/comms). - Double-count if some connectors still write both
accounts.type=investmentandinvestmentsfor the same money — today only 1 investment account exists; still need a join rule (prefer positions; or subtract overlapping account ids). - Must stay aligned with PLU-844 credit liability rules when both land.
Likely files
apps/web/api/trpc/_services/accounts.ts(stats— add investments sum)- Possibly
apps/web/api/trpc/_services/dashboard.tsif summary must include positions too apps/web/src/lib/accounts/accounts-data.ts(fetchInvestmentsWithAccounts— reference filters)- Unit tests under
apps/web/__tests__/accounts/api/ - MCP docs if field semantics change
Effort
S for option A (query + tests). Option B = M (sync + possible migration) → Lucca.
Priority
High (P1) — core net-worth / MCP figure understates invested wealth for ~908 users (~131 Itaú with positive value alone). Not P0: data present, app up, Contas path already shows positions for this reporter. Not a Pluggy outage.
Decision needed (Lucca) — bloqueante
A — Recommended. Extend accounts.stats (and dashboard wealth total if it still ignores positions) to add SUM(investments.balance) for status=ACTIVE, is_manual=false, not hidden, same household/user scope as Contas. Document MCP. Coordinate with PLU-844 so netWorth formula becomes cash + investmentsPositions[+investmentAccounts if non-overlapping] − abs(credit). No migration / no sync change.
B. Do A plus have Pluggy sync create/update accounts.type=investment aggregate rows per connected_account so list/stats stay account-centric. Touches lib/pluggy / sync — Lucca required. Effort M.
C. Treat MCP filing as invalid: keep investmentTotal = accounts only; update MCP tool copy to point at Investimentos / Contas investments section; no aggregator change. Leaves netWorth systematically low for OF banks.
Recommendation: A. Sync already works for the reporter; fix the aggregator Contas already bypassed. Park zero-position Itaú cohort as a follow-up Pluggy sample if Lucca wants.
Status
Todo — blocked on Lucca A/B/C. Do not assign SWE until decided. Related: PLU-844 (same reporter, same financial-aggregation matrix).
No comments yet
Be the first to share your thoughts.