Task
When a mirror coin cannot be created or reclaimed because the operator wallet lacks funds, raise an OS notification. Today it is logged and nothing else, so an operator learns their node stopped collateralising content only by reading logs they have no reason to open.
Why this is a user-facing defect, not a nicety
The mirror pass runs unattended every 10 minutes (MIRROR_PASS_INTERVAL = dig_constants::MIRROR_ROUND_LENGTH_MS = 600,000 ms, server.rs:2855). When funding is short, mirror/funding.rs:25-29 refuses the whole create rather than partially funding it — the correct behaviour — and the pass moves on. It will do that silently, every ten minutes, indefinitely.
The consequence is not a failed operation the user retries. It is that their content quietly stops being bonded, they earn nothing from it, and every surface continues to look healthy. A silent recurring failure on a money path is exactly the class this project treats as a lie by omission.
Scope
Notify on the two funding-related outcomes, and only those:
- A create refused for want of funds —
mirror/funding.rs FundingError (insufficient $DIG, and the TooManyInputs case, where the wallet holds enough but in too many pieces — that one has a different remedy and must say so: consolidate, not top up).
- A reclaim that could not pay its fee. Note reclaims are deliberately not gated on funds and support a zero fee, so verify this state is actually reachable before building for it — if it is not, say so and cover only case 1.
Do NOT notify on:
- the balance being merely unreadable (
FundsUnknown) — that is a different condition with a different remedy, and reporting a shortfall on no evidence is the money lie BalanceUnreadable exists to prevent
- observe-only mode (no operator wallet,
DIG_WALLET_ENABLE_LIVE_BROADCAST off, mirror_enabled false, or no DIG_MIRROR_ADVERTISE_URLS) — the node is configured not to spend, which is not a failure
The thing to get right: do not notify every ten minutes
A notification that repeats 144 times a day is worse than none — it trains the operator to dismiss it, and the one that matters is lost with the rest. Notify on the transition into the funding-short state, and again only when it changes (recovered, or the shortfall materially worsened). The pass runner already holds cross-round state for presence debouncing (runner.rs:243-245), so there is a precedent for where this belongs.
State the chosen policy explicitly in the code, because "how often does this fire" is the whole design.
The message must be actionable
An operator seeing it should know what to do without reading source. Name the amount short, the epoch's requirement, and the remedy — top up versus consolidate are different actions and the code already distinguishes them. Do not name a coin id or an address in a desktop notification.
Context
dig-node already ships desktop notification capability — check how the updater surfaces its own messages and reuse that path rather than adding a second mechanism (§2.0: reuse before building).
- Funding refusal:
crates/dig-node-service/src/mirror/funding.rs.
- Pass runner and its cross-round state:
crates/dig-node-service/src/mirror/runner.rs, spawned at server.rs:2136.
Acceptance
On a node whose operator wallet is short, a person sees an OS notification naming the shortfall and the remedy, once on entering that state — not once per pass. Proven by a test that drives several consecutive short passes and asserts exactly one notification, plus one that asserts a recovered-then-short-again cycle notifies again.
Task
When a mirror coin cannot be created or reclaimed because the operator wallet lacks funds, raise an OS notification. Today it is logged and nothing else, so an operator learns their node stopped collateralising content only by reading logs they have no reason to open.
Why this is a user-facing defect, not a nicety
The mirror pass runs unattended every 10 minutes (
MIRROR_PASS_INTERVAL=dig_constants::MIRROR_ROUND_LENGTH_MS= 600,000 ms,server.rs:2855). When funding is short,mirror/funding.rs:25-29refuses the whole create rather than partially funding it — the correct behaviour — and the pass moves on. It will do that silently, every ten minutes, indefinitely.The consequence is not a failed operation the user retries. It is that their content quietly stops being bonded, they earn nothing from it, and every surface continues to look healthy. A silent recurring failure on a money path is exactly the class this project treats as a lie by omission.
Scope
Notify on the two funding-related outcomes, and only those:
mirror/funding.rsFundingError(insufficient $DIG, and theTooManyInputscase, where the wallet holds enough but in too many pieces — that one has a different remedy and must say so: consolidate, not top up).Do NOT notify on:
FundsUnknown) — that is a different condition with a different remedy, and reporting a shortfall on no evidence is the money lieBalanceUnreadableexists to preventDIG_WALLET_ENABLE_LIVE_BROADCASToff,mirror_enabledfalse, or noDIG_MIRROR_ADVERTISE_URLS) — the node is configured not to spend, which is not a failureThe thing to get right: do not notify every ten minutes
A notification that repeats 144 times a day is worse than none — it trains the operator to dismiss it, and the one that matters is lost with the rest. Notify on the transition into the funding-short state, and again only when it changes (recovered, or the shortfall materially worsened). The pass runner already holds cross-round state for presence debouncing (
runner.rs:243-245), so there is a precedent for where this belongs.State the chosen policy explicitly in the code, because "how often does this fire" is the whole design.
The message must be actionable
An operator seeing it should know what to do without reading source. Name the amount short, the epoch's requirement, and the remedy — top up versus consolidate are different actions and the code already distinguishes them. Do not name a coin id or an address in a desktop notification.
Context
dig-nodealready ships desktop notification capability — check how the updater surfaces its own messages and reuse that path rather than adding a second mechanism (§2.0: reuse before building).crates/dig-node-service/src/mirror/funding.rs.crates/dig-node-service/src/mirror/runner.rs, spawned atserver.rs:2136.Acceptance
On a node whose operator wallet is short, a person sees an OS notification naming the shortfall and the remedy, once on entering that state — not once per pass. Proven by a test that drives several consecutive short passes and asserts exactly one notification, plus one that asserts a recovered-then-short-again cycle notifies again.