v0.34.0 — conformance proves 401 codes are discriminated
Conformance proves the 401 codes are discriminated
v0.33.0 gave every 401 a reason code from a closed set. The conformance suite checked that the code was a member of that set — which a server stamping unauthorized on every single 401 satisfies completely. The reference worker raised a bare ValueError, so unauthorized and proxy_required were the only codes the suite ever observed. Every port could hardcode one constant and pass the whole group.
That defeats the point of the closed set. A client that refreshes a token on expired_credential and gives up on insufficient_scope needs the two told apart.
Four new tests in TestUnauthorized fail exactly that server:
| Test | Asserts |
|---|---|
test_requested_reason_is_honoured |
Each request-classifiable reason round-trips onto both the header and the JSON body. |
test_reason_codes_are_distinct |
N distinct requests produce N distinct codes. |
test_unclassified_failure_is_unauthorized |
A rejection naming no reason lands on the fallback, not a guess. |
test_proxy_required_is_not_request_driven |
A caller cannot summon proxy_required on a service with no proxy dependency. |
They are gated on a new optional conformance_http_auth_reason_port fixture — a worker whose authenticate reads an X-Conformance-Auth-Reason request header and fails with the reason named. That header is a fixture affordance, never a protocol behaviour: a production server must never let a request steer its reason code. Two values are deliberately not requestable, and both are asserted separately — proxy_required, which §5 derives from server configuration, and unauthorized, which is what the absence of a requested reason must produce.
Ports that have adopted the 401 contract should add the fixture; without it these four tests skip, which is a real gap rather than a pass. See §7.1 of docs/unauthorized-spec.md and the ~10-line reference worker in tests/serve_conformance_http_auth.py.
The call/cursor token split, pinned from both ends
A stream's state travels as two tokens split by lifetime: a call token minted once by /init, and a cursor re-minted every turn. Two new groups pin it:
TestCallTokenSplitreads the wire directly and fails a server that packs everything into the cursor.TestColdCallStateCachefails a client that does not echo the call token. This is the sneaky half — a splitting server may resolve the call from a per-process cache, so a non-echoing client passes every test you are likely to write, then fails in production the first time a continuation lands on a restarted worker or a node that never saw the/init.
call_state_cache_entries is new on make_wsgi_app, serve_http and make_sync_client. It defaults to the value the cache already used, so no existing caller changes behaviour. Setting it to 0 disables the cache outright, turning that load-dependent client bug into a deterministic one — every continuation takes the miss path. That is how the cold-cache conformance worker is booted, and it is the supported way to prove your client is stateless-relay safe.
Every served page carries the mark
The logo block was inlined in five HTML templates. The 401 page was the only page in the codebase with no branding assertion at all — the 404, landing and describe pages each had one — which is backwards, since the 401 is the only page a caller reaches by accident.
All five templates now share one constant, and the test discovers page templates by sweeping the package for doctypes rather than listing them, so a page added later is covered without anyone remembering to extend it.
Upgrading: no action required. The new kwarg is additive at its existing default, and the 401 wire contract is unchanged from v0.33.0. Cross-language ports should add the conformance_http_auth_reason_port fixture to close the discrimination gap.