Skip to content

cow: a venue receipt mismatch destroys the commitment permanently #693

Description

@mfw78

Surfaced by the anvil-fork harness in #691, and it is an unfinished item from #682 rather than a new discovery.

The gap in #682

#682 listed in scope: "Decide the retry_action fallback for non-Denied faults, which bypasses the table and drops."

#688 closed #682 without addressing it. The classification table and classify_denied are in crates/cow-venue, but retry_action is in videre-sdk, a different repo, so it was out of the diff and the item was missed.

It still reads:

VenueFault::UnknownVenue
| VenueFault::InvalidBody(_)
| VenueFault::Unsupported
| VenueFault::Denied(_)
| VenueFault::InvalidReceipt
| VenueFault::ReceiptMismatch => RetryAction::Drop,

Why it matters

The fork run reaches Post, submits, and the venue returns a receipt that does not match the order it sent. retry_action maps that to Drop, and the commitment is removed permanently:

poll commitment:0xf39f...:0x8a86... -> Post
submit dropped commitment commitment:0xf39f...:0x8a86... permanently: receipt mismatch

The order was valid, the generator posted it, and the conditional order is intact on chain. The commitment is gone anyway, and only a re-registration brings it back.

By #688's own rule this is wrong

#688 established the line: a commitment mints a fresh order from the same handler, salt and static input on every poll, so only inputs fixed at registration justify removing it.

A receipt mismatch is a fact about the venue's response, not about the registration. An orderbook bug, a truncated response or a deployment mid-rollout would delete every commitment that submits during the window. InvalidReceipt is the same class.

Denied(_) also appears in this arm, though it is unreachable in the CoW path because run.rs routes a denial to classify_denied first. It should not be left as a drop for a venue that does not.

Note on the trigger

The mismatch in the fork run comes from orderbook-mock answering with a synthetic uid rather than one derived from the order, so the venue check is behaving correctly there.
That is a mock limitation, but it is exactly the shape a real venue defect would take, which is why it is worth classifying deliberately rather than dropping.

Scope

  • Reclassify the receipt faults in videre_sdk::keeper::retry_action: a venue-shaped fault should back off, not remove.
  • Decide UnknownVenue, InvalidBody and Unsupported in the same pass; InvalidBody is arguably registration-fixed and may keep its drop.
  • Cross-repo, so it carries a videre pin bump into shepherd.

Done when

AI Assistance: Claude Code used for the analysis.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions