Explicit custom composition. Execute supplies exactly one reply per command.
Batch
Batch(value, decode_err) :: # (opaque)
An ordered wire batch with a pure semantic decoder. The transport drains all expected replies before this decoder runs, so element errors cannot strand later replies on the connection.
one : Request(value, error) -> Batch(value, [ServerError(Bytes), ReplyDecodeFailure(error), ReplyCountMismatch({ expected : U64, actual : U64 })])
Lift one request into a batch plan for heterogeneous composition.
map2 : Batch(a, left_err), Batch(b, right_err), (a, b -> value) -> Batch(value, [LeftFailure(left_err), RightFailure(right_err)])
Compose independently typed plans into one exchange and semantic value. Their error types stay distinct. The complete wire batch is drained before either semantic decoder runs; this does not provide transaction atomicity.
Preserve every element's success, server error, or custom decoder failure.
all : List(Request(value, error)) -> Batch(List(value), [ElementFailed({ index : U64, error : Error(error) }), ReplyCountMismatch({ expected : U64, actual : U64 })])
Return the first semantic failure after the full batch has been drained.
map : Batch(a, error), (a -> b) -> Batch(b, error)
CountError : [ReplyCountMismatch({ expected : U64, actual : U64 })]