From review of #467 (comment r3616741546). Verified against the end-of-train tip (feat/m5-git-tag-pins-umbrella-patch, 24c4d9e).
refusal() returns a Refusal whose AlreadyHeld variant means success on the submit path and failure on every read path. Nothing at the type level enforces which reading a caller takes; the read paths simply remember to call .into_error().
At the tip there are three production call sites, and all three are currently correct.
quote_with: return Err(refusal(&response).into_error());
status_with: return Err(refusal(&response).into_error());
submit_with: match refusal(&response) { ... }, the one site that treats AlreadyHeld as success.
So this is not a live defect. It is a foot-gun for the next read-path call site added to this file, where forgetting .into_error() silently converts an already-held rejection into a success shape.
Options
Split the constructor: refusal_for_submit returning Refusal and refusal_for_read returning VenueError directly, so a read-path caller never holds an unresolved AlreadyHeld.
Or keep one parse and make the collapse explicit at the type level, for example by having the read helper return a type with no AlreadyHeld variant at all.
The first is the smaller change and matches how the two paths already differ.
Timing
Not urgent, and it collides with #473 which also edits cow-venue/src/adapter.rs. Land it after #473 merges, or fold it into #473's own pass.
Acceptance criteria
A read-path caller cannot compile against a refusal that still carries an unresolved already-held meaning.
refusal()returns aRefusalwhoseAlreadyHeldvariant means success on the submit path and failure on every read path. Nothing at the type level enforces which reading a caller takes; the read paths simply remember to call.into_error().At the tip there are three production call sites, and all three are currently correct.
quote_with:return Err(refusal(&response).into_error());status_with:return Err(refusal(&response).into_error());submit_with:match refusal(&response) { ... }, the one site that treatsAlreadyHeldas success.So this is not a live defect. It is a foot-gun for the next read-path call site added to this file, where forgetting
.into_error()silently converts an already-held rejection into a success shape.Options
Split the constructor:
refusal_for_submitreturningRefusalandrefusal_for_readreturningVenueErrordirectly, so a read-path caller never holds an unresolvedAlreadyHeld.Or keep one parse and make the collapse explicit at the type level, for example by having the read helper return a type with no
AlreadyHeldvariant at all.The first is the smaller change and matches how the two paths already differ.
Timing
Not urgent, and it collides with #473 which also edits
cow-venue/src/adapter.rs. Land it after #473 merges, or fold it into #473's own pass.Acceptance criteria
A read-path caller cannot compile against a refusal that still carries an unresolved already-held meaning.