Cross-cutting Étape 2 coverage proving the per-security detail feature does not
regress aggregations, returns, date-move, or deletion.
Rust (lib.rs, +3 real-SQLite tests):
- regression_detailed_account_totals_equal_simple_account_totals: a detailed
account whose holdings sum to V yields byte-identical date/category/vehicle
SUM() totals to a simple account worth V (frozen golden numbers 1300/300/...).
Proven where SUM() GROUP BY actually runs, unlike the TS mock harness.
- migration_v14_to_v16_on_populated_db_preserves_integrity_and_totals: realistic
multi-type DB (simple + convertible priced w/ 2-snapshot history + non-
convertible priced) — totals byte-identical before/after v16, values
preserved, qty/price NULLed only on converted lines, one shared security,
non-convertible line fully intact.
- regression_snapshot_delete_cascades_to_holdings: two-hop CASCADE
(snapshot -> line -> holdings); security survives (RESTRICT).
TS (balance-flow.test.ts, +6 integration tests):
- detailed snapshot save end-to-end (aggregated line + securities + holdings in
one BEGIN/COMMIT); aggregated line value = rounded-cent SUM(holdings).
- rollback on injected holding INSERT failure (no partial line/holdings).
- snapshot date-move with a detailed account: line + holdings move together;
collision rolls both back (#200).
- golden-value invariant: detailed line stores the same value a simple account
would, feeding getSnapshotTotalsByDate identically.
- deleteSnapshot emits exactly one parent DELETE (FK cascades the rest).
No production code changed — pure test PR. Builds on the v16 tests (#211) and
the detailed-save/securities unit tests (#212) without duplicating them.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Priced balance categories now carry an explicit `asset_type`
('stock' | 'crypto') so PriceFetchControl can route to the right
provider without symbol heuristics. ETH = Ethan Allen NYSE AND
Ethereum crypto are no longer ambiguous.
Migration v10 adds a nullable column and backfills the two seeded
priced categories (key='stock','crypto'). Legacy custom priced rows
stay NULL until the user edits the category — SnapshotLineRow hides
the price-fetch button when asset_type is NULL on a priced row, so
manual entry remains available.
Service-side validation rejects priced creation without asset_type
('asset_type_required') and rejects values outside ('stock','crypto')
('asset_type_invalid'). Simple kind coerces asset_type to NULL.
The CategoryVariant of AccountForm shows the selector only when
kind=priced, requires it on submit, and resets it on kind switch.
i18n keys added under balance.category.assetType.* (FR + EN).
Tests:
- 4 new Rust migration tests in lib.rs (column add, seed backfill,
legacy row stays NULL, CHECK rejects 'gold')
- 6 new vitest cases on createBalanceCategory + listBalanceAccounts
asserts c.asset_type AS category_asset_type in the join
- balance-flow integration test updated to pass asset_type='stock'
No new test for SnapshotLineRow render guard — project lacks
@testing-library/react + jsdom; the guard is one boolean expression
covered by manual QA per autopilot decisions in PR #167.
Fixes#169
End-to-end happy path through the full Bilan stack: account → priced
category → priced snapshot → linked transfer → return. Drives every
service against the existing in-memory FakeDb harness used by
category-migration tests so SQL shape (table names + parameters) can be
asserted alongside service outputs.
Currency lock: USD / EUR / GBP / JPY / AUD all rejected up-front by the
service with a typed `currency_unsupported` code, no DB hit. The CAD
default is verified to land in the INSERT params explicitly.
Priced-kind safety: a snapshot save with one out-of-tolerance line must
NOT clear pre-existing lines (the DELETE is gated behind the validation
loop). A drift just within ε is accepted unchanged.
computeAccountReturn wiring: malformed dates are rejected client-side
without invoking the Rust command; missing active profile yields a typed
`transfer_active_profile_unknown`; partial-period payloads are forwarded
unchanged (null fields preserved).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>