Skip to content

buyer: no gate between delivery and payment — the delivery watcher is unconditionally armed and auto-settles, so an award IS an instruction to pay #245

Description

@orveth

Summary

There is no point between a delivery arriving and the buyer paying for it. The delivery watcher is armed unconditionally at daemon boot, and it accepts and settles on its own. A buyer therefore has exactly one decision point in the whole money path — the award — and an award is in effect a standing instruction to pay whatever arrives.

For testnut that is a design choice. For a buyer holding real sats it means there is no path where a human or an adjudicator sits between delivery and payment.

Observed

Live at main 9caa941, testnut. A job was posted with max_sats: 0 (held), then awarded manually on an explicit authorization. Nothing else was called — no collect, no accept, no pay.

Roughly two seconds after the delivery landed:

buyer: delivery watcher settled 38ed7862… — paid 10 sat for commit c411618a… (2 file(s))

get_job then showed accepted populated with an accept_event_id, and spent.jsonl had been written. Wallet balance moved. The operator's only action in the entire sequence was the award.

Cause

crates/mobee-core/src/buyer/mod.rs:249:

// Start watching for delivered results. Its own first action is a sweep of awarded-unsettled
// jobs, which is what collects a delivery that landed while this daemon was down.
spawn_delivery_watcher(context.clone());

Unconditional — no config field, no flag, no report-only mode. Grepping home.rs for auto_accept / auto_settle / manual_accept / any review-mode knob returns nothing.

The watcher's own sweep also collects deliveries that arrived while the daemon was down, so stopping the daemon defers settlement rather than preventing it. And accept_claim / authorize_pay are not independently callable (they return NOT_IMPLEMENTED; the documented path is collect), so there is no supported way to drive accept manually while declining to pay.

The design intent is explicit in-tree (mod.rs:1638):

"THE MONEY TOOTH for the delivery watcher. The watcher settles with no human in the loop, so the question that matters is whether its entry to the spend gate is as gated as the RPC's."

That framing is right as far as it goes, and the integrity protection is real and well tested — a forged seller co-signature costs nothing. But integrity is not review. The watcher guarantees you only pay for a delivery that is authentically from the awarded seller; it makes no provision for deciding whether what arrived is worth paying for.

Why this matters more than it looks

The natural reading of "award reserves funds" is that a reservation is reviewable — that the buyer commits funds and then decides. It is not. The correct mental model is:

post (free) → AWARD = the irrevocable decision to pay → delivery → accept → pay, all automatic.

Consequences for anyone building buyer-side policy on top of this:

  • An acceptance specification is a pre-award document, not a post-hoc gate. Any criterion that can only be evaluated once the artifact exists cannot be load-bearing on the spend.
  • A reviewer can decide whether to merge the work, but not whether to pay for it. Those are different powers and the API shape invites conflating them.
  • The only real risk control is job size, since each award is an unbounded-quality bet with a bounded price.
  • Pre-award filters (e.g. mcp: the harness field is a hard award filter, not a recorded preference #206's proposal to make harness a hard award filter) become disproportionately important, because they are the only gates that fire before the money decision.

Suggested direction

Not prescribing an implementation:

  • A report-only / manual-accept mode for the watcher — it detects and surfaces the delivery, and settlement waits for an explicit collect. Even opt-in would be enough.
  • Failing that, a config field that disarms auto-settlement for a given home, so a real-money buyer can choose review-before-pay.
  • At minimum, document the model plainly where buyers will read it: an award is an instruction to pay on delivery. The current wording around reservations invites the opposite assumption.

Related

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