Skip to content

Seller's drive_advance silently requires real token delivery before accepting the probe, contradicting dexdo status's own printed guidance #71

Description

@kevinushana

Summary

dexdo status's next field for an opened, unaccepted-probe deal prints:

next=seller_advance_probe_after_timeout command="keep dexdo seller running for {deal}; it calls TokenContract.advance() after PROBE_WINDOW" reason=buyer_silent_probe

This strongly implies pure timeout-based silence-equals-consent, which matches what TokenContract.advance() actually allows on-chain (TokenContract.sol: require(block.timestamp >= _prepaidTime + advanceWindow, ...) — no delivery check at all, by design, per the contract's own doc comment: "After SETTLE_WINDOW of buyer silence... accept the probe").

The CLI's actual driver (crates/dexdo/src/seller/advance.rs::drive_advance) does not do this. It gates on real delivered tokens first:

tokio::time::sleep(windows.probe).await;
loop {
    if billed_ticks(delivered.load(Ordering::Acquire), tick_size) >= 1 {
        break; // requires >=1 REAL delivered token
    }
    if delivery_done.load(Ordering::Acquire) || deal_closed(chain, token_contract).await {
        return Ok(0);
    }
    tokio::time::sleep(windows.settle).await; // otherwise loops forever, silently
}
chain.accept_probe(token_contract).await?;

If the buyer never sends a single real inference request through the gateway (for any reason — their own bug, they gave up, they're just testing), this loop sleeps indefinitely with zero log output, making a perfectly healthy, correctly-running seller process indistinguishable from a hung/broken one from the outside. last_advance_unix in dexdo status --json never advances, across any number of seller restarts, for as long as the buyer stays silent.

There is no exposed dexdo subcommand to call advance() directly, bypassing this gate — checked dexdo --help in full, only dexdo seller's embedded daemon logic can trigger it. So the seller has no way to ever force settlement on a deal the buyer opened, funded, and then abandoned, even though the underlying contract explicitly supports exactly that scenario (silence-after-timeout = consent).

This is very likely a deliberate anti-abuse safeguard (protecting the buyer from being charged for content never actually delivered) rather than a pure bug — but the mismatch between it and the CLI's own status message cost significant debugging time to trace to source, since every symptom (healthy process, reachable gateway, zero log output, frozen last_advance_unix) looks identical to a genuinely hung/crashed process.

Environment

  • dexdo 0.0.12 (SHA256-verified) and 0.0.14 (fresh download, checksum-verified)
  • Network: Shellnet, post the 2026-07-17 restart
  • OS: Windows 11

Repro

  1. Open/fund any deal as seller (real buyer match, opened=true).
  2. Don't send a real request through the gateway as that buyer.
  3. Wait well past PROBE_WINDOW (180s) — even hours.
  4. dexdo status --json shows last_advance_unix frozen at the funding time indefinitely, probe_accepted=false, with next.action=seller_advance_probe_after_timeout still printed as if it will resolve on its own.
  5. Restarting the seller process does not change this — it resumes cleanly (readiness=resumed_funded_tc) but the advance loop restarts in the same blocked state.

Ask

  1. Is the delivery-gate intentional (anti-abuse) or an oversight?
  2. If intentional, could dexdo status's next message be corrected to not imply pure timeout-based resolution, and/or could the seller log something (even at DEBUG) while waiting in this loop, so it's distinguishable from a genuinely hung process?
  3. Is there any seller-side recourse at all for a deal the buyer opened/funded and then never sent traffic to?

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