feat(cow-ext): typed cow-api-error owned by the extension package#216
Open
mfw78 wants to merge 1 commit into
Open
feat(cow-ext): typed cow-api-error owned by the extension package#216mfw78 wants to merge 1 commit into
mfw78 wants to merge 1 commit into
Conversation
Replace the unified host-error envelope on shepherd:cow/cow-api with a typed cow-api-error variant built on the shared nexum:host/types fault vocabulary. The interface gains http-failure (raw non-2xx, foreign orderbook JSON kept as a string) and order-rejection (status, error-type, description parsed once host-side), and request/submit-order return result over cow-api-error. ext_cow projects the orderbook client errors into the typed cases: a rejection envelope is decoded once into order-rejection, so the guest never re-parses a failure body. shepherd-sdk mirrors CowApiError with a HostFault impl that recovers the embedded fault and a stable label, and classify_api_error now takes an OrderRejection. The cow bind macro grows the fault and cow-api-error conversion ladder. ethflow-watcher and twap-monitor match http.status == 404 for the indexer-lag and appData-not-mirrored checks, and the stop-loss submit path dispatches on the typed rejection. This proves the extension seam: nexum WIT is untouched; the richer error lives entirely in the shepherd:cow package and its SDK.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #210; part of the typed-fault train stacked on the epic-80 stack, merges in stack order.
This gives the
shepherd:cow/cow-apiextension interface a typed error shape instead of the unifiedhost-errorenvelope. The guest no longer re-parses the orderbook rejection JSON itself; the host parses it once and hands the guest a typedorder-rejection, and a submit failure now discriminates transport faults, HTTP failures, and orderbook rejections as distinct cases instead of a single opaque string.Changes
wit/shepherd-cow/cow-api.witdropshost-errorin favour of the sharednexum:host/types.fault, and addsrecord http-failure { status: u16, body: option<string> },record order-rejection { status: u16, error-type: string, description: string }, andvariant cow-api-error { fault(fault), http(http-failure), rejected(order-rejection) }. Bothrequestandsubmit-ordernow returnresult<string, cow-api-error>.shepherd-cow-host/src/ext_cow.rsaddscow_error_to_witandorderbook_error_to_witprojectors so the host maps its own error types onto the three wit cases; the orderbook rejection envelope is parsed once, host-side, intoorder-rejectionrather than being re-parsed by every guest.shepherd-sdk/src/cow/error.rsmirrors the wit shape asCowApiError(Fault,Http,Rejected) plusHttpFailureandOrderRejectionstructs, implementsHostFault(theFaultcase refines to the embedded fault's own label so metrics stay granular), and replacestry_decode_api_errorwithclassify_api_error(&OrderRejection), which now takes the already-typed rejection instead of re-parsing a string.shepherd-sdk/src/cow/mod.rsandapp_data.rsupdateCowApiHostandresolve_app_datato returnCowApiError(a 404 now surfaces asHttp { status: 404, .. }).shepherd-sdk/src/wit_bindgen_macro.rsadds theconvert_cow_errconversion ladder, binding to the fault conversion the nexum host macro already emits rather than duplicating it.modules/twap-monitor,modules/ethflow-watcher, andmodules/examples/stop-lossare updated to dispatch on the typed cases: the app-data 404 checks becomehttp.status == 404, andtwap-monitor's submit retry classification dispatches onRejectedand otherwise stays transient (TryNextBlock), preserving the old safe default.shepherd-backtestpicks up ashepherd-sdkdependency so its replay fixture can construct the typed 404 case.Test plan
cargo fmt --all --checkcargo clippy --workspace --all-targets --all-features -- -D warningscargo test --workspace --all-features(all green, including theclassify_api_errordoctest)example,twap-monitor,ethflow-watcher,stop-loss, and the harness fixtures) rebuilt in-tree against the updatedcow-api.wit; the e2e supervisor subset passes against the rebuilt wasm, includingtwap_monitor_without_cow_extension_fails_to_bootand thee2e_*boot/dispatch tests, so the wit-bindgen adapter link is exercised in a real componentcargo build --release --target wasm32-wasip2for the three consuming modules succeeds against the regenerated bindingsNotes for reviewer
Only
CowApiError::Rejectedclassifies viaerror_typein the retry policy; transportFaults and rawHttpfailures fall through toTryNextBlockat both call sites, matching the oldclassify_api_error(None) -> TryNextBlocksafe default. This was inlined as a two-line match rather than a new helper, so the SDK surface stays exactlyclassify_api_error(&OrderRejection)as specced.convert_faultis not duplicated in the cow bind macro; it binds to the conversion the nexum host macro already emits, since a per-extension copy would drift from the shared vocabulary.nexum-sdk's own WIT and macro are untouched by this change, which is the extension-seam property the issue asks to prove.order-rejectiondrops the orderbookApiError.datafield the old envelope carried; the retry classifier never consulted it, and the wit shape in the issue defines onlystatus/error-type/description.Follow-ups intentionally left out of this PR: refreshing the cow-api sequence diagrams and ADRs, which still show the old
result<string, host-error>/try_decode_api_errorflow; aretry_after_ms-awareRetryAction::Backoffproducer, sinceFault::RateLimitednow carries structured backoff guidance end to end but nothing consumes it yet; and projecting host-side reqwest timeout and 429 responses ontoFault::Timeout/Fault::RateLimitedrather than the current blanketFault::Unavailable.AI Assistance: Claude Code (Opus 4.8 implementation and adversarial review, Sonnet 5 PR authoring) used for the full change.