Lite-parity audit: per-address spendableBalance was set equal to the gross balance, ignoring the backend's
per-note 'spendable' flag (spending key present AND note at/below the anchor height), and has_spending_key
was effectively always true (mapAddress never set spendabilityKnown). So the Send auto-picker could select
an address that can't fund the send, and an imported view-only (zxviews) address looked spendable.
- Parser: carry the backend per-note 'spendable' flag when present (Sapling notes; transparent utxos keep
the confirmed/unspent rule). It can only narrow spendability, never widen it.
- Mapper: derive per-address spending-key evidence from positive signals only — a spendable note proves a
key (spendable), a confirmed long-mature (>=100 blocks) still-non-spendable note proves view-only
(!spendable); fresh/immature/no notes stay unknown so nothing is mislabelled.
- Controller: info.balance stays the gross sum; info.spendableBalance now counts only backend-spendable
outputs; a tolerated partial refresh keeps the last-known spendable balance and view-only verdict.
Display/selection only — gating can only get stricter for view-only/unanchored funds; no send/sweep/encrypt
call changes. Test: testLitePerAddressSpendableAndViewOnly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>