Task
mint_status can report a mint that CONFIRMED as one that "can never confirm", and the fix must go
on that CONCLUSION rather than on the read it is derived from. dig-app must refuse to render a
terminal mint failure that rests on an absence no tier warranted.
Context
dig-account 0.13.0, src/mint/did.rs:236-247, concludes:
if did_record.is_none() && source.as_ref().is_some_and(CoinRecord::is_spent) {
return Ok(MintStatus::Failed { reason: "the funding coin was spent by a different spend; this mint can never confirm" });
}
Both reads are coin_record. Per dig-app#169, control.wallet.coinById is NOT scoped to the
wallet, so dig-node's crates/dig-wallet/src/sage/routing.rs:31-40 routes it to the fallback tier
whatever the node's sync state and it reports synced: false on every reply — even for a coin its
own database holds (measured on dig-node 0.118.1 at peak 9148856). So a DID coin can read as absent
without warrant while the funding coin truthfully reads as spent, and the conclusion fires for a
mint that landed: real XCH spent, a permanent on-chain identity created, and the app saying it can
never confirm.
The read-level fix was tried and rejected in dig-app#169, with the trace. Guarding
coin_record makes the read error on every poll, which ChainMint::look
(crates/dig-app-core/src/account/chain_mint.rs:341) maps to Sighting::Unreachable, which
await_confirmation (crates/dig-app-core/src/account/mint.rs:258,281) turns into
MintOutcome::ConnectionLost after twelve looks — so every mint on a healthy machine ends in a
false "the chain could not be reached", well inside a mainnet confirmation window. It also closes
profile creation entirely, because the same read is the lineage probe's first.
Skill/reference of "good"
professional-ui on never asserting a fact the app does not have; #2690's Unknown-is-not-Blocked
split. dig-app/SPEC.md §3.1c now records the open lie and the required rendering.
Scope
The conclusion, not the read. A MintStatus::Failed whose premise is an unwarranted absence must
surface as UNKNOWN / still checking — not as Rejected, not as Blocked, not as ConnectionLost.
ControlChainSource::last_freshness already records the tier that answered; the shape question is
how a ceremony generic over ChainSource gets at it without every test double growing a field.
Upstream alternative worth pricing first: fix dig-node's routing so a wallet-known coin read by id is
answered from the database with an honest synced, which removes the premise instead of filtering
the conclusion. If that lands, the read-level guard becomes correct and dig-app#169's narrowing can
be reverted — its pinning test says so in its own doc comment.
Delegate
Same pass as the dig-app mint wiring (#2398 S1 / dig-app#170) — that PR is what makes this reachable.
Do not ship the wiring without it.
Evidence
A test in which the DID coin reads absent from an unsynced tier beside a spent funding coin, and the
surface still says "still checking". It must fail against today's mapping.
Moved from DIG-Network/dig_ecosystem#2937 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
mint_statuscan report a mint that CONFIRMED as one that "can never confirm", and the fix must goon that CONCLUSION rather than on the read it is derived from. dig-app must refuse to render a
terminal mint failure that rests on an absence no tier warranted.
Context
dig-account 0.13.0,
src/mint/did.rs:236-247, concludes:Both reads are
coin_record. Per dig-app#169,control.wallet.coinByIdis NOT scoped to thewallet, so dig-node's
crates/dig-wallet/src/sage/routing.rs:31-40routes it to the fallback tierwhatever the node's sync state and it reports
synced: falseon every reply — even for a coin itsown database holds (measured on dig-node 0.118.1 at peak 9148856). So a DID coin can read as absent
without warrant while the funding coin truthfully reads as spent, and the conclusion fires for a
mint that landed: real XCH spent, a permanent on-chain identity created, and the app saying it can
never confirm.
The read-level fix was tried and rejected in dig-app#169, with the trace. Guarding
coin_recordmakes the read error on every poll, whichChainMint::look(
crates/dig-app-core/src/account/chain_mint.rs:341) maps toSighting::Unreachable, whichawait_confirmation(crates/dig-app-core/src/account/mint.rs:258,281) turns intoMintOutcome::ConnectionLostafter twelve looks — so every mint on a healthy machine ends in afalse "the chain could not be reached", well inside a mainnet confirmation window. It also closes
profile creation entirely, because the same read is the lineage probe's first.
Skill/reference of "good"
professional-uion never asserting a fact the app does not have; #2690'sUnknown-is-not-Blockedsplit.
dig-app/SPEC.md§3.1c now records the open lie and the required rendering.Scope
The conclusion, not the read. A
MintStatus::Failedwhose premise is an unwarranted absence mustsurface as UNKNOWN / still checking — not as
Rejected, not asBlocked, not asConnectionLost.ControlChainSource::last_freshnessalready records the tier that answered; the shape question ishow a ceremony generic over
ChainSourcegets at it without every test double growing a field.Upstream alternative worth pricing first: fix dig-node's routing so a wallet-known coin read by id is
answered from the database with an honest
synced, which removes the premise instead of filteringthe conclusion. If that lands, the read-level guard becomes correct and dig-app#169's narrowing can
be reverted — its pinning test says so in its own doc comment.
Delegate
Same pass as the dig-app mint wiring (#2398 S1 / dig-app#170) — that PR is what makes this reachable.
Do not ship the wiring without it.
Evidence
A test in which the DID coin reads absent from an unsynced tier beside a spent funding coin, and the
surface still says "still checking". It must fail against today's mapping.
Moved from DIG-Network/dig_ecosystem#2937 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