Follow-up from #589 and #590 (M4 CoW follow-ups). Both had to encode a representable, recurring adapter condition as venue-error.invalid-body(string) because the surface has no dedicated variant for it.
Evidence
The venue-error variant in wit/videre-types/types.wit is { unknown-venue, invalid-body(string), unsupported, denied(string), rate-limited, unavailable(string), timeout }. Recent adapter work shoved typed conditions into the string payloads:
Both are venue-neutral, representable, recurring conditions wearing a string because the surface has no home for them. A caller cannot branch on them without parsing the message.
The design tension
The wire venue-error is deliberately coarse (see nullislabs/videre-nexum-module#11: denied is intentionally minimal, with venue-specific detail recovered venue-side via classify_denied). That coarseness is right for venue-reported errors whose taxonomy we do not control. It is wrong for adapter-detected conditions that are venue-neutral and finite: an invalid or empty receipt, a receipt-versus-derivation mismatch, an unsupported operation. Those deserve typed variants; the open-ended venue-reported cases keep a stringly escape hatch.
So this is not "make everything typed". It is: give the finite, representable, venue-neutral conditions dedicated variants, and keep invalid-body and denied string payloads only for genuinely custom or previously-unrepresentable errors.
Proposal
Audit the venue-error surface across the adapter (cow-venue) and the SDK, and:
Where this belongs: M5, before the cleave
venue-error is a videre:types WIT vocabulary, so the decisive factor is the repo cut, not the second venue. Adding a variant is an additive, non-breaking WIT change either way, but the cost differs sharply on which side of the cleave it lands:
The two demonstrated cases are self-evidently venue-neutral, so waiting for the second venue to confirm them buys nothing and costs the ripple. Do them now, cheaply, in the monorepo. This must land before the carve (#407 / #549); after that it is no longer a fold.
This does not pre-empt nullislabs/videre-nexum-module#23: the second-venue vocabulary pass in M6 still owns any variant we cannot yet prove venue-neutral, and extends this surface additively. This issue is the cheap precursor, not the freeze. It is also the natural sibling of nullislabs/videre-nexum-module#11 (venue-supplied denial classification): together they define the venue error and retry seam.
Acceptance criteria
Related
Evidence
The
venue-errorvariant inwit/videre-types/types.witis{ unknown-venue, invalid-body(string), unsupported, denied(string), rate-limited, unavailable(string), timeout }. Recent adapter work shoved typed conditions into thestringpayloads:invalid-body("empty receipt"), an adapter-side receipt-validity condition, not a malformed body.invalid-body("orderbook uid ... disagrees with derived uid ..."), a receipt/derivation mismatch, again not a malformed body.Both are venue-neutral, representable, recurring conditions wearing a string because the surface has no home for them. A caller cannot branch on them without parsing the message.
The design tension
The wire
venue-erroris deliberately coarse (see nullislabs/videre-nexum-module#11:deniedis intentionally minimal, with venue-specific detail recovered venue-side viaclassify_denied). That coarseness is right for venue-reported errors whose taxonomy we do not control. It is wrong for adapter-detected conditions that are venue-neutral and finite: an invalid or empty receipt, a receipt-versus-derivation mismatch, an unsupported operation. Those deserve typed variants; the open-ended venue-reported cases keep a stringly escape hatch.So this is not "make everything typed". It is: give the finite, representable, venue-neutral conditions dedicated variants, and keep
invalid-bodyanddeniedstring payloads only for genuinely custom or previously-unrepresentable errors.Proposal
Audit the venue-error surface across the adapter (cow-venue) and the SDK, and:
invalid-receipt(empty or structurally-invalid receipt) and a receipt/uid mismatch variant. These two are self-evidently venue-neutral (any orderbook venue can hand back an invalid receipt, or a UID that disagrees with the local derivation), so they land now; genuinely uncertain or venue-specific cases are left to sdk: prove venue-neutrality with a second venue and freeze the vocabulary videre-nexum-module#23's second-venue pass rather than guessed at here.invalid-body(string)anddenied(string)as the escape hatch for custom or unrepresentable errors; do not force a variant where the condition is open-ended or venue-specific.VenueError, the ownedVenueFaultmirror, and thefaults.rsconversions, and migrate cow: reconcile the accepted receipt uid against the local derivation #589 and venue: restore the dropped empty-receipt guard on status and cancel #590 offinvalid-bodyonto the typed variants.Where this belongs: M5, before the cleave
venue-erroris avidere:typesWIT vocabulary, so the decisive factor is the repo cut, not the second venue. Adding a variant is an additive, non-breaking WIT change either way, but the cost differs sharply on which side of the cleave it lands:VenueError, theVenueFaultmirror andfaults.rs, regenerate goldens, done.videre, re-pin in nexum-runtime, shepherd and the second-venue repo, regenerate goldens cross-repo, re-run the tip oracle per repo.The two demonstrated cases are self-evidently venue-neutral, so waiting for the second venue to confirm them buys nothing and costs the ripple. Do them now, cheaply, in the monorepo. This must land before the carve (#407 / #549); after that it is no longer a fold.
This does not pre-empt nullislabs/videre-nexum-module#23: the second-venue vocabulary pass in M6 still owns any variant we cannot yet prove venue-neutral, and extends this surface additively. This issue is the cheap precursor, not the freeze. It is also the natural sibling of nullislabs/videre-nexum-module#11 (venue-supplied denial classification): together they define the venue error and retry seam.
Acceptance criteria
invalid-body(string), at least venue: restore the dropped empty-receipt guard on status and cancel #590's empty-receipt and cow: reconcile the accepted receipt uid against the local derivation #589's uid mismatch, have dedicatedvenue-errorvariants.invalid-bodyanddeniedstring payloads remain only for genuinely custom or unrepresentable errors.Related
Fromedges between the existing typed errors.