Skip to content

The staleness marker stops at balance: coins, coinsByParent, arrivals and coinById still answer from an unbounded tier, and complete asserts more than they know #490

Description

@MichaelTaylor3d

Origin: #416, found by the gate that closed it.

Task

#454 taught control.wallet.balance to say when its answer is not current. Its four siblings were
not taught, and they answer from the same tier. A person reading them still gets a confident figure
with nothing bounding it - which is the defect #416 existed to remove, one method over.

Measured on this machine, installed node 0.206.0, 2026-09-01, same address and same moment as
the reading that closed #416:

$ dign wallet coins --asset dig xch16grurcglcwcv6arjarr720yd9wqhp9gkx3k8h25lhwg8pl7vl6ysuax0gy
0 unspent coin(s) - complete

$ dign wallet coins --asset dig --json xch16gru...
{"coins":[],"complete":true,"cursor":null,"source":"fallback","synced":false,"peak_height":null}

complete: true is a positive claim, and it is the part that matters. A bare 0 merely fails to
qualify itself; complete asserts that nothing was left out - from a tier that has just said
synced: false and peak_height: null, i.e. that it cannot say what height the answer reflects. The
human line carries no marker at all, so the two states #416 was filed to separate are again
indistinguishable: no coins, and cannot see coins.

Context

  • coins_wire - crates/dig-node-service/src/control.rs:3259-3284 - emits source, synced and
    peak_height but not network_peak_height or stale_by, the two fields fix(wallet): distinguish unknown from zero across the wallet surface #454 added.
  • CLI summaries that render no staleness: control_cli.rs:819-822 (coins), :823
    (coinsByParent), :774-780 (arrivals), :782 (coinById).
  • coinById's negative answer is the sharpest case: it renders "no such coin on chain", an
    assertion about the chain, from a replica that may not have reached the height the coin was created
    at.
  • The shape to copy already exists and is proven: stale_by (control.rs:1669), its null-vs-zero
    contract, and the NOT CURRENT rendering with the (None, _) arm at control_cli.rs:1502 and
    amount() at :1452, which returns unknown rather than 0 for a missing field.
  • rpc.rs:1536-1539 calls the coins read "the exact sibling of balance_for_address - a balance is
    this read reduced to a sum"
    , which is why the omission is an oversight rather than a design line.

Skill / reference of good

#454 is the reference implementation; follow its contract exactly rather than inventing a second one.
The load-bearing distinction it established: stale_by: 0 and stale_by: null are opposite
claims
- zero says this figure is level with the network, absence says nothing bounds this
figure
. Do not collapse them. Additive wire fields only, with an old-consumer parse test.

Scope

The four reads above. Each gains the two additive wire fields and a rendered marker when its answer
is not current; complete must not read as an unqualified claim when the tier cannot bound the
answer's height.

Not in scope: changing what any read RETURNS, or the sync path itself.

Two things to record while in this file

  1. A rustdoc the code now contradicts. balance_for_address's doc comment
    (crates/dig-wallet/src/sage/rpc.rs:1394-1401) still says "Wallet-owned address, DB synced ->
    source = "db", synced = true"
    / "Otherwise -> synced = false". Since rpc.rs:1486
    computes synced from replica_answer_is_current(peak_height) (currency) rather than from
    eligibility, the state {source: "db", synced: false} is real and reachable - and it is exactly
    the state the most useful CLI line renders. The doc denies a state production produces. Fix it in
    the same PR.
  2. A pointer that would otherwise be buried. rpc.rs:1076-1081 records that
    control.wallet.syncStatus can still emit {phase: "synced", peak_height: null} - the pairing
    abolished on the money reads - deliberately out of scope, formerly tracked by
    https://github.com/DIG-Network/dig_ecosystem/issues/2761, which is now CLOSED. Re-home it here
    or file it deliberately; do not let it vanish because both of its former tickets closed.

Evidence

Every "done" cites a real run. The bar is the live command above producing a marked answer on a real
machine, not a green suite - and a test at the DECISION (does this read qualify its answer) rather
than at the plumbing.

Acceptance

dign wallet coins, coins-by-parent, arrivals and coin-by-id each say when their answer is not
current, in both --json and human output, and a reader cannot confuse "there is nothing there" with
"this node cannot see". complete and "no such coin on chain" are not asserted unqualified from an
unbounded tier.

Parent

No live super-repo epic: this ticket's two natural parents,
https://github.com/DIG-Network/dig_ecosystem/issues/3166 and
https://github.com/DIG-Network/dig_ecosystem/issues/2761, are both CLOSED. Recorded here rather than
left implicit - a super-repo epic may be owed for the wallet-read-honesty family.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingkind:businessa person can DO something new, or money moves, or a shipped surface stops lying to them

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions