Skip to content

Adopt control-interface 0.22.0 and implement control.spends.list #385

Description

@MichaelTaylor3d

Task

Adopt dig-node-control-interface 0.22.0 and implement control.spends.list — the sanctioned
reader for the automated-spend audit record.

Parent epic: https://github.com/DIG-Network/dig_ecosystem/issues/3166
Contract: DIG-Network/dig-node-control-interface#30 (merged c9c8bf8c, published 0.22.0)
Consumer waiting on it: DIG-Network/dig-app#289 (PR #290, already coded against the method)

Why this ticket exists — the contract is published, nothing serves it

Measured on main today:

  • dig-node-service/Cargo.toml:92 and dig-wallet/Cargo.toml:53 both declare dig-node-control-interface = "0.21".
  • spends.list / spends_list appears nowhere in crates/.

So a release watcher reporting the crate "live" is reporting the contract, not the capability. §1.3b:
a contract crate is not done when it publishes; it is done when every consumer has adopted it. dig-app
PR#290 calls control.spends.list and receives METHOD_NOT_FOUND from every node until this lands.

What the implementation needs, beyond the dispatch arm

The PR#31 gate measured that this is not merely wiring an existing query to a new method name:

  • SpendQuery carries no after_id. The declared method is paginated by cursor; the existing query
    type cannot express where to resume.
  • SpendLog::query cannot report complete. The contract distinguishes "that is all of them" from
    "we stopped here", and the current query has no way to say which.

Both must be extended, along with their callers. Budget for that rather than discovering it mid-lane.

The shape is already fixed by the published contract — match it exactly

The catalog was verified field-by-field against this repo's shipped spend_audit.rs
(SpendRecord, SpendStatus, FailureStage, Asset, Authority), and the declared ordering is
exactly what spend_audit.rs:539 implements. Do not re-derive the shape; read 0.22.0 and conform.

Two properties in that contract are load-bearing and must survive into the implementation:

  1. The failure-stage distinction. Signing definitively did not spend; Broadcast and
    Confirmation mean a signed bundle went out and money may have moved. That distinction has been
    collapsed and re-fixed twice in this repo and once in dig-app. Use
    FailureStage::money_may_have_moved(); do not re-list the variants anywhere.
  2. An unresolved outcome is a first-class state, not an error. The response must be able to say
    "signed, and we do not know if it landed".

Why the accuracy bar is higher than a normal read method

This method is the compensating control for a §908 carve-out: the node signs mirror-coin spends
without per-spend user approval, at the user's explicit instruction. The audit record is what stands
in for consent. A reader that misreports those spends weakens the only thing substituting for it.

Also

  • Bounding. The audit log grows without limit. Honour the contract's cursor and its complete
    signal — and if a response is truncated, it must say so. A caller cannot distinguish "no more
    spends" from "we stopped telling you" unless that is explicit.
  • Read-only. Never triggers a spend, never signs, never mutates.
  • §2.4b: bring dig-*/chia-* deps to latest in the same PR; chia-* move as a SET. Index checks need
    a User-Agent header or the registry reads as unpublished.
  • SPEC.md (§4.2) and the #426 CLI/RPC parity test kept green.

Acceptance

dign spends and dig-app's Activity tab read the same records through this method and agree. Evidence
is that agreement on a real machine (§2.6) — two surfaces reading one source and disagreeing is the
defect this exists to prevent.

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