Task
Gate the profile-creation control on the registry being readable. When ProfileSession fails to load its registry it substitutes an in-memory store; once profile creation becomes reachable, a mint performed in that state spends real XCH and writes its journal nowhere durable.
Context
ProfileSession::unreadable swaps the store for a MemoryRegistryStore — crates/dig-app-core/src/account/profile_session.rs:354-359, via ..Self::unprofiled() at :343.
This is inert today and becomes live with this epic. ProfileCreation cannot currently be Possible on the shipped seam (the binary returns MintSeams::NoChainTransport at crates/dig-app/src/bin/dig-app.rs:576), so no mint can be started at all. The moment the create control lands (epic #2398, the wiring + create-control stage), a session whose registry failed to load will accept a mint and journal it to memory only.
The failure, concretely
- Registry read fails for a non-
NotFound reason (IO error, or a corrupt file → ProfileError::Corrupt, profile_session.rs:186-197).
- Session boots
unreadable, backed by MemoryRegistryStore.
- User creates a profile. Real XCH is spent; a DID singleton and dig-store are minted on chain.
- The journal and the resulting profile record exist only in memory.
- On restart the paid-for DID is gone from the app's view, and
next_free_ix recomputes from an empty registry — so the next mint re-mints at an already-occupied index.
Money spent, a permanent on-chain identity created, and no durable record that it happened. That is inside epic #2398's money carve-out on two counts at once: it lies about money, and it lies about whether the mint took effect.
Scope — minimal, one arm and one guard
Gate the create control on session.unreadable_reason().is_none() and render CreationBlocked (or the equivalent honest refusal) when it is Some. Do not rework the registry store, do not make unreadable recoverable, and do not change dig-account — an unreadable registry correctly fails loudly already (ProfilesReading::of_session reports Unknown(Unreadable) rather than Known(vec![]), profiles.rs:154-159). The only defect is that creation would be offered on top of it.
This MUST land in the same PR as the create control, not after it — shipping the control first opens the window this closes.
Evidence required
A test proving the create control is refused when the session is unreadable, and still offered when the registry is merely absent (NotFound → ProfileRegistry::empty() at profile_session.rs:191) — the absent case is the ordinary first-run state and must NOT be blocked. Both directions, or the guard is vacuous.
Related: epic #2398; #2919 (the chain-read absence fix in the same family).
Moved from DIG-Network/dig_ecosystem#2923 so this repo's own PR can close it (CLAUDE.md §1.3). GitHub refuses
a private-to-public issue transfer, so the body was copied and comment history stayed on the
original.
Orchestrator ticket: https://github.com/DIG-Network/dig_ecosystem/issues/2398
Task
Gate the profile-creation control on the registry being readable. When
ProfileSessionfails to load its registry it substitutes an in-memory store; once profile creation becomes reachable, a mint performed in that state spends real XCH and writes its journal nowhere durable.Context
ProfileSession::unreadableswaps the store for aMemoryRegistryStore—crates/dig-app-core/src/account/profile_session.rs:354-359, via..Self::unprofiled()at:343.This is inert today and becomes live with this epic.
ProfileCreationcannot currently bePossibleon the shipped seam (the binary returnsMintSeams::NoChainTransportatcrates/dig-app/src/bin/dig-app.rs:576), so no mint can be started at all. The moment the create control lands (epic #2398, the wiring + create-control stage), a session whose registry failed to load will accept a mint and journal it to memory only.The failure, concretely
NotFoundreason (IO error, or a corrupt file →ProfileError::Corrupt,profile_session.rs:186-197).unreadable, backed byMemoryRegistryStore.next_free_ixrecomputes from an empty registry — so the next mint re-mints at an already-occupied index.Money spent, a permanent on-chain identity created, and no durable record that it happened. That is inside epic #2398's money carve-out on two counts at once: it lies about money, and it lies about whether the mint took effect.
Scope — minimal, one arm and one guard
Gate the create control on
session.unreadable_reason().is_none()and renderCreationBlocked(or the equivalent honest refusal) when it isSome. Do not rework the registry store, do not makeunreadablerecoverable, and do not change dig-account — an unreadable registry correctly fails loudly already (ProfilesReading::of_sessionreportsUnknown(Unreadable)rather thanKnown(vec![]),profiles.rs:154-159). The only defect is that creation would be offered on top of it.This MUST land in the same PR as the create control, not after it — shipping the control first opens the window this closes.
Evidence required
A test proving the create control is refused when the session is
unreadable, and still offered when the registry is merely absent (NotFound→ProfileRegistry::empty()atprofile_session.rs:191) — the absent case is the ordinary first-run state and must NOT be blocked. Both directions, or the guard is vacuous.Related: epic #2398; #2919 (the chain-read absence fix in the same family).
Moved from DIG-Network/dig_ecosystem#2923 so this repo's own PR can close it (CLAUDE.md §1.3). GitHub refuses
a private-to-public issue transfer, so the body was copied and comment history stayed on the
original.
Orchestrator ticket: https://github.com/DIG-Network/dig_ecosystem/issues/2398