Skip to content

fix(cow): keep a commitment the orderbook can still be asked about - #695

Closed
mfw78 wants to merge 1 commit into
mainfrom
cow/693-cow-policy
Closed

fix(cow): keep a commitment the orderbook can still be asked about#695
mfw78 wants to merge 1 commit into
mainfrom
cow/693-cow-policy

Conversation

@mfw78

@mfw78 mfw78 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Closes #693. Consumes the seam from nullislabs/videre-nexum-module#88; bumps the videre pin from fd8af02 to 9ab1515 across all eight declarations.

The bug

A receipt this keeper could not correlate removed the commitment. The fork run in #691 reached Post, submitted, got a receipt that did not match the order it sent, and the commitment was destroyed:

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

The order was valid, the generator posted it, the conditional order was intact on chain. Only a re-registration brought the commitment back.

Why the fix belongs here and not upstream

The first attempt changed videre's default so receipt faults backed off everywhere, justified like this:

a venue that did accept the order reports it as already held

That is CoW behaviour. Videre is the venue platform and a venue is not necessarily an orderbook: repeating a submission at one that buys a label or books a slot repeats the act. videre#88 therefore keeps its conservative default and adds FaultPolicy as the seam; this PR supplies the CoW one, where the claim is actually true.

The orderbook keys an order by its uid and dedupes on that uid, so re-sending one it already holds comes back as already held rather than executed twice. That idempotency is what makes the retry safe.

What CowFaults does

fault platform default CoW why
ReceiptMismatch, InvalidReceipt drop backoff 300 uid dedup makes a resubmit safe, and the order may be on the book
Denied(_) drop the shipped table classification.toml already classifies these by errorType
everything else unchanged unchanged the venue has nothing to add

InvalidBody and Unsupported keep the default drop deliberately: both are re-derived from the commitment on every poll, so the next submission is byte-identical and refused the same way. UnknownVenue keeps it too, since the composition root registers the cow venue at boot and a missing one fails there.

A second bug this closes

Denials now route through the table for the reconcile pass as well as the submit path.

They did not before. run.rs classified Denied with classify_denied on the submit path, but reconcile used the platform default internally, which knows nothing of classification.toml. So a stranded reservation for a clearable refusal like InsufficientBalance was released, while the same refusal arriving on the submit path backed off. One policy now feeds both, which is what is_terminal deriving from action in videre#88 is for.

Verification

237 tests pass, up from 232 on main.
cargo fmt --check, cargo clippy --workspace --all-targets --all-features -- -D warnings, RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps, just build-modules and the doctests all exit 0.

Three mutations are each caught: receipt faults dropping again, denials bypassing the table, and the reconcile call site falling back to the platform default.

That last one initially was not caught. Swapping &CowFaults for &DefaultFaultPolicy at the reconcile call site left all 236 tests green, which is the same gap I raised reviewing videre#88 and had to fix here too. reconcile_keeps_a_reservation_the_cow_policy_can_retry drives a stranded reservation through run with a receipt fault and asserts the marker survives.

Note for #691

#691 also touches crates/composable-cow/src/run.rs and is based on main, so whichever lands second needs a rebase. The regions differ, so no conflict is expected.

AI Assistance: Claude Code used for the policy and the tests.

Bumps the videre pin to 9ab1515 and supplies the CoW fault policy the
seam there exists for.

A receipt this keeper cannot correlate used to remove the commitment.
The fork run reached `Post`, submitted, got a receipt that did not match
the order, and destroyed a commitment whose order may well have been
accepted. Only a re-registration brought it back.

The orderbook keys an order by its uid and dedupes on that uid, so
re-sending one it already holds comes back as already held rather than
executed twice. That idempotency is what makes the retry safe, and it is
a fact about this venue rather than about venues, which is why it is
asserted here and not in the platform default.

Denials now route through the shipped table for the reconcile pass as
well as the submit path. They did not before: reconcile took the
platform default, which knows nothing of `classification.toml`, so a
stranded reservation for a clearable refusal was released while the same
refusal on the submit path backed off.

Closes #693.

AI Assistance: Claude Code used for the policy and the tests.
@mfw78

mfw78 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Rolled into #691, which is where the receipt-mismatch bug was found and where the harness that found it lives. The commit rides there unchanged.

It changed shape on the way, and the change matters. It classified ReceiptMismatch as a backoff, which does not survive scrutiny: the uid is keccak(order) ++ owner ++ validTo, a pure function of the body that was sent, so re-posting it yields the same disagreement every time. reconcile does not re-park a non-terminal fault either, so the reservation would have been re-posted on every tick forever. That is worse than the drop it replaced.

It now ends the submission and keeps the commitment: the reservation is released, and the commitment takes a one-block grace because its next poll mints a later part with a different uid.

@mfw78 mfw78 closed this Sep 9, 2026
@mfw78
mfw78 deleted the cow/693-cow-policy branch September 9, 2026 05:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cow: a venue receipt mismatch destroys the commitment permanently

1 participant