SPEC 015 Composition Report - rafaelfqueiroz/allmywallet GitHub Wiki
SPEC-015 — Composition Report
| Status | Draft |
| PRD source | F5.4 (FR-5.21–5.24) |
| Depends on | SPEC-009, SPEC-011 |
| Milestone | M5 |
Description
The report that answers what am I actually holding, and is it balanced?
It is the simplest of the four and the most used: a share-of-total view plus a sortable table of every holding with its value, quantity, average price, current price and unrealized gain. Because SPEC-011 supplies the grouping dimension, this single report covers what other trackers split into several — by asset class, by wallet, by ticker, by sector, by institution.
It also carries the one place the product comes closest to opinion: a concentration flag when a single asset exceeds a configurable share. That flag is informational and must stay that way — AllMyWallet gives no investment advice.
Business rules
| ID | Rule |
|---|---|
| BR-015-01 | Composition is presented by the selected grouping (SPEC-011): asset class, wallet, individual asset, sector, or institution. |
| BR-015-02 | Two presentations: a share-of-total visualization, and a sortable table with value, quantity, average price, current price and unrealized gain per row. |
| BR-015-03 | Sector data applies to stocks and FIIs where available; holdings with no sector appear in "Not classified" (SPEC-011, BR-011-10), never dropped. |
| BR-015-04 | Composition drift over time — how allocation across the selected grouping shifted during the period. |
| BR-015-05 | Concentration flags when a single asset exceeds a user-configurable share of the scope (default 20%). |
| BR-015-06 | Concentration flags are informational only and explicitly not advice. No wording may suggest an action to take. |
| BR-015-07 | Shares are computed on current market value, not on cost basis. |
| BR-015-08 | Unrealized gain per row = current value − (quantity × average cost) (SPEC-009, BR-009-04). |
| BR-015-09 | Estimated values (accrued fixed income) are marked distinctly (SPEC-009, BR-009-11). |
| BR-015-10 | Shares sum to 100% for the scope, and the value total equals the endpoint of the Portfolio Value report for the same scope and date (SPEC-013, BR-013-12). |
| BR-015-11 | At wallet scope, quantities and values reflect allocated quantities, not full positions (SPEC-010). |
| BR-015-12 | Grouping by wallet at portfolio scope includes Unassigned (SPEC-011, BR-011-09). |
| BR-015-13 | Current value uses the latest delayed quote with its timestamp displayed (SPEC-008, BR-008-04). |
Acceptance Criteria
- Composition renders for all five grouping dimensions.
- Shares sum to 100% for every grouping.
- The value total equals the Portfolio Value report endpoint for the same scope and date.
- The table sorts by every column, ascending and descending.
- Value, quantity, average price, current price and unrealized gain are correct per row.
- Unrealized gain reconciles to value minus quantity × average cost.
- Holdings without sector data appear in "Not classified" and totals still reconcile.
- Drift over time shows allocation shifts across the period for the selected grouping.
- A holding exceeding the configured threshold is flagged; changing the threshold in user settings changes which holdings flag.
- Flag wording is informational and suggests no action — verified by review, not just by test.
- Accrued fixed income is visually distinguished from observed prices.
- At wallet scope, a partially-allocated asset shows the allocated quantity, not the full position.
- Grouping by wallet at portfolio scope includes Unassigned and sums to the portfolio.
- The quote timestamp and delay tier are displayed.
- An empty scope renders an empty state.
Out of Scope
- Target allocation and drift against a target — moved to SPEC-017 at M7, which answers PRD Q6. Rebalancing suggestions remain out of scope everywhere: SPEC-017 supplies arithmetic against targets the user set and never a recommendation. BR-015-06 stands unchanged.
- Risk metrics: correlation, diversification scores, beta.
- Fundamental data beyond sector: P/E, dividend yield history, market cap.
- Geographic or currency exposure breakdown, including look-through for BDRs.
- Look-through into FII or ETF underlying holdings.
- Any buy, sell or rebalance recommendation.
- Sourcing sector classification data (PRD Q5 — open question whether free coverage suffices).
- Historical composition reconstruction before the earliest imported transaction.
Decision Logs
| # | Decision | Alternatives considered | Rationale |
|---|---|---|---|
| DL-015-01 | One report driven by SPEC-011's grouping, not several composition reports. | Separate reports for asset class, sector, wallet | The underlying computation is identical and only the grouping key changes. Separate reports would drift apart and multiply the surface where totals can stop reconciling. |
| DL-015-02 | Shares computed on market value, not cost. | Share of invested capital | Composition answers "what is my money exposed to now". A position that tripled represents three times the exposure it did at purchase, and a cost-based share would understate exactly the concentration the user needs to see. |
| DL-015-03 | Concentration flag is informational, with a user-configurable threshold. | No flag; a fixed threshold; actionable rebalancing advice | A flag is genuinely useful — concentration builds silently as winners run. Advice would make the product an unlicensed advisor (PRD risk R7). A user-set threshold makes it a tool the user configures rather than a judgement the product imposes. Superseded in part by SPEC-017 (M7), which permits user-set targets: the advice risk is mitigated by requiring every threshold to originate with the user, rather than by omitting the feature. The concentration flag itself remains informational and unchanged. |
| DL-015-04 | "Not classified" for missing sector rather than exclusion. | Drop holdings with no sector from the sector view | Fixed income has no sector, and it can be a large share of a Brazilian portfolio. Dropping it would make the sector view disagree with every other view of the same scope, with no visible explanation. |
| DL-015-05 | Wallet scope shows allocated quantities, not full positions. | Show the full position when any part is allocated | Showing the full position would make wallet composition wrong for every split holding and would double-count across wallets — a 60/40 split would appear as 100% in both. |
| DL-015-06 | Cross-report equality with Portfolio Value asserted. | Independent computation per report | Consistent with SPEC-013 DL-013-06 and SPEC-014 DL-014-07. Two reports disagreeing about the portfolio total is the most trust-destroying defect available, and an automated assertion catches it in CI. |