Skip to content

Sage-parity action methods all return an empty ActionResponse — a no-op is indistinguishable from success (incl. increase_derivation_index) #256

Description

@MichaelTaylor3d

Task

Every Sage-parity action method returns the same empty ActionResponse {} (crates/dig-wallet/src/sage/types.rs:1693-1695), so a caller cannot tell "I did the thing" from "there was nothing to do." Enumerate the affected methods, then give each one an outcome it can actually report.

Sibling of #254, parent
https://github.com/DIG-Network/dig_ecosystem/issues/2870.

This is the same defect the trusted-peer work just fixed

control.chiaPeers.remove answered removed: true unconditionally, so the only un-trust remedy
reported success whether or not it removed anything. That was a HIGH, gating finding — a surface lying
about whether a privileged action took effect — and it was closed by replacing the boolean with
ChiaPeerRemovalOutcome ("removed" | "no_such_peer", no boolean companion, so a consumer must
match).

ActionResponse {} is that shape generalised: its own doc-comment says "An empty response shared by
every action method above ({})"
.

Confirmed members, and step 1 is to complete the list

Measured directly above the definition:

  • update_nft
  • update_nft_collection
  • redownload_nft
  • increase_derivation_index

The list is almost certainly longer — "every action method above" is a comment, not a bound. Step 1 is
enumerating the real set from the dispatch table rather than from the comment, and stating the count.

Why increase_derivation_index is the one that makes this money-class

The HD derivation index decides which addresses this node scans. If the call silently no-ops — a
malformed request, a clamp, an unwritten row — the operator is told it succeeded and funds at higher
indices stay invisible
. There is no error, no retry, and no way for the caller to know. That is a
surface lying about money, which is the narrow class §2.6 keeps as a stop even during end-to-end-first
work.

redownload_nft on a nonexistent NFT and update_nft on an unknown id have the same structure with a
lower blast radius.

Scope

  1. Enumerate every method returning ActionResponse, from the dispatch table.
  2. For each, decide whether "nothing to do" is distinguishable and worth reporting. Where it is, give
    it a typed outcome — model it on ChiaPeerRemovalOutcome rather than inventing a second shape, and in
    particular do not add a bool companion: the reason that enum works is that a consumer cannot
    ignore it.
  3. Where an empty response is genuinely right — a true idempotent no-op with no observable difference —
    say so in the doc comment, so the next reader does not re-litigate it.

The constraint that makes this harder than it looks

This is a Sage-PARITY surface. A third-party client may parse these bodies strictly, so changing a
response shape is a compatibility question, not just a correctness one. Establish what Sage itself returns
for each method before changing any shape — matching Sage may be the right answer even where it is
less informative, and if so that is a finding worth writing down rather than a defect to fix.

Note the same PR already changed this wire once: PeerRecord.peak_height became null and banned was
added on get_peers, reasoned as safe because the old value was always 0 and nothing writes peer
telemetry. Use the same standard of evidence here.

Evidence

Per changed method, a test proving the "nothing to do" case is reported differently from the success
case — and, for any method left as {}, the recorded reason.

Effort

Medium. Step 1 is mechanical; step 2 is a per-method judgement with a compatibility constraint.

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind: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