Rust conformance runner
The Rust conformance runner, plus the fixture bug typed decoding exposes. Card: W3 conformance runner. Base of the stack, on rust-sdk; the releng PR (#159) adds the CI job that runs it.
Runner
conformance/runner/rust is its own workspace with a path dependency on ../../../rust/fizzy-sdk. It ports hey-sdk's runner (axum mock server, fixture loader, assertions) and adopts fizzy's generic dispatch, mirroring the Go runner: expand path with pathParams, append queryParams (arrays repeat the key), strip /{accountId} for the scoped client, raw verbs with RequestOptions (no_retry when the route has no retry policy and the method is not POST, idempotent for idempotent POSTs — read off the generated route table rather than a second copy of the behavior model), get_all when the case has several linked responses or a urlOrigin assertion, fast delays unless a delayBetweenRequests assertion exists, and configOverrides.baseUrl with zero mocks means "expect the builder to refuse".
Adaptations from hey's runner, all deliberate: exact path matching (no .json normalization); every retry interval checked and fewer than two requests fails the delay assertion; no maxPages/maxItems (rejected loudly, not ignored); the mock server rewrites a Link target whose parsed origin is exactly the configured one to itself, and every other absolute target to a second loopback listener that stands in for foreign origins — an SDK that wrongly follows a cross-origin link is counted there and fails the case, and no request ever leaves the machine; a follow-on request must ask for the page the previous Link named or it gets a 500; urlOrigin: rejected requires the mocked pages to have been fetched and the error to be usage. All 17 schema assertion types are implemented (fixtures use 11); responseBody compares JSON structurally; name, operation and assertions are required at the type level; an unknown operation or assertion type fails the case. Every request's method must be the case's. Output ends with Passed: N, Failed: M, Total: T.
Makefile: conformance-rust (alias conformance-rs), conformance-runner-tests-rust, membership in conformance and conformance-build.
Fixture fix
Every id in the OpenAPI schemas is a string; 29 mock bodies across 9 fixture files wrote them as numbers (pagination.json's Board.id was the one the plan called out). The raw-JSON runners never noticed; a typed decoder rejects them. Fixed as "id": "1" throughout; Card.number, position and the other integer fields stay numeric as the schema says. Go still passes 127/127 locally.
Result
Transport conformance against rust-sdk @ 320e1c5: 124/127 (runner unit tests 11/11; clippy -D warnings and rustfmt clean). The three failures are SDK retry semantics, reported to the crate branch: two cases get 4 attempts where the behavior model's max: 3 is total attempts (Go: for attempt = 1; attempt <= MaxRetries), and an exhausted 429 maps to api_error instead of rate_limit. This job will be green when those land on rust-sdk.
Adversarial review (Codex, gpt-6-astra, xhigh)
Accepted: substring Link rewrite corrupting prefix-sharing foreign origins (now per-target origin comparison); serving pages by index without checking the request matches the prior Link (now enforced); urlOrigin passing on any usage error before the first fetch (now requires the mocked pages fetched). Declined: making the "protocol downgrade" case test scheme rather than host — against an http://127.0.0.1 mock no runner in this repo can, and the sibling runners share the limitation; scheme comparison is covered by the SDK's own unit tests.
Review round 1 (Copilot, Codex): foreign-origin stand-in listener; structural responseBody comparison; empty path as root; required fixture fields — fixed. Declined with reasons in-thread: dispatching through generated routes and carrying the route's retry budget into raw calls (generic raw-verb dispatch is the family's contract; generated-call coverage lives in the crate's tests/generated_calls).