Skip to content

fix(dig-app): a mint on an UNREADABLE registry is journalled to memory only — the paid DID is forgotten on restart #209

Description

@MichaelTaylor3d

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 MemoryRegistryStorecrates/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

  1. Registry read fails for a non-NotFound reason (IO error, or a corrupt file → ProfileError::Corrupt, profile_session.rs:186-197).
  2. Session boots unreadable, backed by MemoryRegistryStore.
  3. User creates a profile. Real XCH is spent; a DID singleton and dig-store are minted on chain.
  4. The journal and the resulting profile record exist only in memory.
  5. 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 (NotFoundProfileRegistry::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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions