Files
sure/test/controllers
buzzromainandClaude Opus 5 0d0003b032 fix(onchain-wallets): show linked wallets on the accounts page, and drop the tracking row on unlink (#3136)
Two gaps in #3081 after it merged, both raised there by @jjmata's review of
#2191 — credit to that PR for identifying them.

**Linked wallets were invisible on /accounts.** The feature creates real Sure
accounts and they count towards net worth, but the accounts page never showed
them: `Account.manual` excludes anything carrying a provider link, and unlike
the twenty other providers there was no on-chain section to claim them. A
family whose only connection was a wallet saw the empty state on the one page
meant to list their accounts. The controller now loads the items, the view
renders them, and the empty-state condition counts them.

The card is rendered by name rather than as a collection, because the model's
default partial slot is already the provider settings row; renaming it would be
the tidier convention but costs eight locale files of churn for a follow-up fix.

**A generic unlink left the tracking row behind.** The dedicated disconnect
flow is careful, but `AccountsController#unlink` destroys the AccountProvider
directly, and an OnchainWalletAccount holds that link rather than being held by
it. Orphaned, it stops syncing — the syncer only reads linked rows — while its
partial unique index still holds the (item, chain, address, asset) slot, so
linking that same asset again would collide with a row nothing displays. It is
destroyed with its link now, following the CoinStats precedent in the same
model, with a guard against the recursion that precedent lacks. The regression
test is the one asked for explicitly: the Sure account and its holdings survive
as manual while the tracking row and the provider link go.

**The card only renders accounts the viewer may see.** Found in review of this
branch. An item is surfaced as soon as ONE of its accounts is accessible, so
rendering them all showed a member given access to one wallet account the names
and balances of the others. Reproduced before fixing, with two real addresses
under one item and a member shared into only one: the unshared account's name
appeared on /accounts. Non-admins now get the accessible subset and the address
count derives from it; admins keep the whole item, which is the rule
visible_provider_items already applies.

That pattern is not specific to this card — six existing providers pass
`item.accounts` unfiltered to the same partial, which filters nothing. In the
same reproduction the unshared name appeared twice, once from a CoinStats card
over the same accounts. Raised separately for the maintainers; only this card
is changed here.

Both figures are computed on the item off the preloaded associations and
prepared per card by the controller, the way `_coinstats_sync_stats_map`
already is: a first attempt did it in the template with a `linked` scope, which
opened a fresh relation and cost a query per row. Measured on /accounts with 1
then 5 wallet items: 52->79 queries became 50->69, so 6.75 per extra item
became 4.75.

Verified beyond the suite: a real Bitcoin address linked, then both flows
driven over real HTTP — `GET /accounts` renders the card, and
`DELETE /accounts/:id/unlink` leaves the account behind reporting `manual:
true`. Integration parity was checked rather than assumed: on-chain now appears
everywhere CoinStats does, the nightly family sync picks it up through its own
reflection over `*_items` associations, and it is already exposed to the mobile
client via /api/v1/accounts and to /api/v1/provider_connections.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 23:39:51 +02:00
..