You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With current code on the platform-wallet PR stack (verified on fix/3625-thepastaclaw-hardening), it is not possible to load identities that don't belong to any wallet — even though the persistor schema allows writing them.
Out-of-wallet ("orphan" / observed-only) identities can be stored to the SQLite persister with wallet_id = NULL (V002 schema permits this by design — CODE-002), but they are silently dropped on startup: no consumer-side reader exists to bring them back into the in-memory IdentityManager.
IdentityManager instances are constructed inside ClientWalletStartState, scoped to a single wallet — there is no client-level IdentityManager that owns orphans across wallets.
4. Persister load() does not load identities at all
// V002: wallet_id is nullable on identities; this load path still// wants only the rows belonging to the wallet the caller asked// for, so the WHERE clause matches by wallet_id (orphan identities// — wallet_id NULL — are out of scope for this per-wallet loader).letmut stmt = conn.prepare("SELECT identity_id, entry_blob, tombstoned FROM identities WHERE wallet_id = ?1",)?;
No sibling load_orphans() / load_out_of_wallet() reader exists.
Root cause
Two-level loader gap. The current load contract is:
persister.load() → reconstructs ClientStartState (platform addresses only today; wallets deferred).
There is no third path that loads identities where wallet_id IS NULL. Even though V002 schema permits orphan rows and the in-memory IdentityManager has an out_of_wallet_identities bucket, the bucket is always empty post-load.
What would be needed
Add a top-level orphan slot to ClientStartState — e.g. pub out_of_wallet_identities: BTreeMap<Identifier, ManagedIdentity> — OR introduce a client-level IdentityManager separate from the per-wallet ones.
Add a persister reader for orphans: SELECT ... FROM identities WHERE wallet_id IS NULL — either as a new method on the schema module or by extending load().
Update manager::load::load_from_persistor to destructure and consume the new slot, populating the runtime IdentityManager with orphans.
Decide ownership model: should the client-level orphan collection be a single global IdentityManager, or should each per-wallet manager hold a view into the global orphans?
CODE-002 — original triage finding that motivated V002 cascade-through-identities.
PROJ-001 (this PR) — FFI register_identity now requires wallet_id at the boundary; once this issue is fixed, a sibling FFI entry point for orphan registration may also be wanted.
Statement
With current code on the platform-wallet PR stack (verified on
fix/3625-thepastaclaw-hardening), it is not possible to load identities that don't belong to any wallet — even though the persistor schema allows writing them.Out-of-wallet ("orphan" / observed-only) identities can be stored to the SQLite persister with
wallet_id = NULL(V002 schema permits this by design — CODE-002), but they are silently dropped on startup: no consumer-side reader exists to bring them back into the in-memoryIdentityManager.Evidence
1.
ClientStartStatehas no orphan-identities slotpackages/rs-platform-wallet/src/changeset/client_start_state.rs:26-40No top-level
BTreeMap<Identifier, ManagedIdentity>or equivalent orphan collection.2.
load.rsdestructure ignores everything elsepackages/rs-platform-wallet/src/manager/load.rs:38-483.
IdentityManagerhas an orphan bucket — but only per-walletpackages/rs-platform-wallet/src/wallet/identity/state/manager/mod.rs:69-98IdentityManagerinstances are constructed insideClientWalletStartState, scoped to a single wallet — there is no client-levelIdentityManagerthat owns orphans across wallets.4. Persister
load()does not load identities at allpackages/rs-platform-wallet-storage/src/sqlite/persister.rs:28, 1001-10285. Per-wallet schema reader explicitly excludes orphans
packages/rs-platform-wallet-storage/src/sqlite/schema/identities.rs:104-142No sibling
load_orphans()/load_out_of_wallet()reader exists.Root cause
Two-level loader gap. The current load contract is:
persister.load()→ reconstructsClientStartState(platform addresses only today; wallets deferred).register_wallet()→ callsschema::identities::load_state(conn, wallet_id)filteringWHERE wallet_id = ?1.There is no third path that loads identities where
wallet_id IS NULL. Even though V002 schema permits orphan rows and the in-memoryIdentityManagerhas anout_of_wallet_identitiesbucket, the bucket is always empty post-load.What would be needed
ClientStartState— e.g.pub out_of_wallet_identities: BTreeMap<Identifier, ManagedIdentity>— OR introduce a client-levelIdentityManagerseparate from the per-wallet ones.SELECT ... FROM identities WHERE wallet_id IS NULL— either as a new method on the schema module or by extendingload().manager::load::load_from_persistorto destructure and consume the new slot, populating the runtimeIdentityManagerwith orphans.IdentityManager, or should each per-wallet manager hold a view into the global orphans?Scope notes
schema/identities.rs.Related
register_identitynow requires wallet_id at the boundary; once this issue is fixed, a sibling FFI entry point for orphan registration may also be wanted.