wai http origin: a refusal ends cleanly, and origin_per_peer_limit waits for its state #657

Merged
dcharlot merged 1 commit from fix/origin-503-reset into main 2026-11-06 03:40:12 -05:00
Owner

wai http origin ended a refusal in a reset, and origin_per_peer_limit failed under load.

The origin

It answered 503 and closed with the request unread, so the connection ended in a reset after the answer. Clients on Linux and macOS still read the 503, but one reading to the close then got an error. A refused request that wrote at once saw this 300 times in 300, on both systems. For a client past --max-per-peer or --max-connections, the origin now stops sending and reads a little more before closing, which the 431 path already did. Both share drain_before_close.

With this change, 300 of 300 refused requests on each system read the 503 and a clean close, both writing at once and 20 ms late. A refused connection's thread can now last up to about 1 s, bounded by the same limits as the 431 path.

The test

origin_per_peer_limit could fail in three ways under load:

  • a third connection could overtake the idle two, so one of them was refused and the count never reached the limit;
  • the fixed 200 ms could run out;
  • the 2 s read timeout could drop the idle two first.

It now retries an attempt overtaken and waits for each state, with a 30 s deadline and a read timeout that outlasts it. It also requires 200 refusals to read their 503 with no read error and no retry.

Verified

On a Linux build host, Rust 1.99.1:

  • origin_per_peer_limit: 12 of 12, and 49 of 50 with ten copies running at once. The one failure was those copies sharing a scratch folder (NotFound), which CI doesn't do.
  • All of cli_http: 22 passed.
  • Planted, no drain on the 503: fails at once, refusal 0: ... ConnectionReset.
  • Planted, a limit never reached: fails at the deadline.

The changelog entry is wai/changes/2026-11-05-origin-refusal-ends-cleanly.md.

🤖 Generated with Claude Code

`wai http origin` ended a refusal in a reset, and `origin_per_peer_limit` failed under load. ## The origin It answered 503 and closed with the request unread, so the connection ended in a reset after the answer. Clients on Linux and macOS still read the 503, but one reading to the close then got an error. A refused request that wrote at once saw this 300 times in 300, on both systems. For a client past `--max-per-peer` or `--max-connections`, the origin now stops sending and reads a little more before closing, which the 431 path already did. Both share `drain_before_close`. With this change, 300 of 300 refused requests on each system read the 503 and a clean close, both writing at once and 20 ms late. A refused connection's thread can now last up to about 1 s, bounded by the same limits as the 431 path. ## The test `origin_per_peer_limit` could fail in three ways under load: - a third connection could overtake the idle two, so one of them was refused and the count never reached the limit; - the fixed 200 ms could run out; - the 2 s read timeout could drop the idle two first. It now retries an attempt overtaken and waits for each state, with a 30 s deadline and a read timeout that outlasts it. It also requires 200 refusals to read their 503 with no read error and no retry. ## Verified On a Linux build host, Rust 1.99.1: - `origin_per_peer_limit`: 12 of 12, and 49 of 50 with ten copies running at once. The one failure was those copies sharing a scratch folder (`NotFound`), which CI doesn't do. - All of `cli_http`: 22 passed. - Planted, no drain on the 503: fails at once, `refusal 0: ... ConnectionReset`. - Planted, a limit never reached: fails at the deadline. The changelog entry is `wai/changes/2026-11-05-origin-refusal-ends-cleanly.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
wai http origin: a refusal ends cleanly, and origin_per_peer_limit waits for its state
All checks were successful
wai-quantum studio and desktop / desktop app · macos (pull_request) Successful in 4m24s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (pull_request) Successful in 15m20s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (pull_request) Successful in 27m16s
WAI Studio / Studio in Chromium and Firefox · macos (pull_request) Successful in 12m13s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 1m27s
joule-moq-remote host agent / joule-moq-remote, every target (linux-arm64) (pull_request) Successful in 2m1s
WAI conformance / v2 vocabulary · manifests validate as stated (pull_request) Successful in 36s
joule-moq-room room service / joule-moq-room, every target (pull_request) Successful in 3m48s
WAI conformance / delivery telemetry · CMCD and CMSD against an independent library (pull_request) Successful in 14s
WAI conformance / cross-arch byte-equality · linux-arm64 (pull_request) Successful in 27s
WAI conformance / C2PA manifest emission · signed, read back, validated (pull_request) Successful in 1m46s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 6m3s
wai-pack / wai-pack · the floor through a media prober (pull_request) Successful in 34s
wai-pack / wai-pack · dependency licences (pull_request) Successful in 2m9s
wai-pack / wai-pack · linux-arm64 (pull_request) Successful in 2m47s
WAI examples / WAI examples · android-app · linux-arm64 (pull_request) Successful in 5m13s
WAI HTTP delivery / cache rules · controls and labelled caches (pull_request) Successful in 2m52s
WAI energy receipts / energy receipts · linux-arm64 (pull_request) Successful in 11m11s
WAI HTTP delivery / HTTP corpus · verified both ways, and the differential (pull_request) Successful in 4m21s
wai-pack / wai-pack · independent verifier (Python) (pull_request) Successful in 10m58s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (pull_request) Successful in 5m33s
WAI conformance / each feature of the independent verifiers' steps compiles alone (pull_request) Successful in 19m26s
WAI conformance / cargo-class corpora · linux-arm64 (pull_request) Successful in 26m40s
WAI HTTP delivery / HTTP corpus · falsify patches 1/3 (pull_request) Successful in 16m37s
WAI HTTP delivery / HTTP corpus · falsify patches 0/3 (pull_request) Successful in 26m48s
WAI HTTP delivery / HTTP corpus · falsify patches 2/3 (pull_request) Successful in 26m47s
WAI HTTP delivery / HTTP corpus · falsify mutations 2/3 (pull_request) Successful in 40m28s
WAI HTTP delivery / HTTP corpus · falsify mutations 1/3 (pull_request) Successful in 40m31s
WAI HTTP delivery / HTTP corpus · falsify mutations 0/3 (pull_request) Successful in 41m6s
WAI conformance / independent verifiers · claims, JWP, key discovery and integer payloads (Python) (pull_request) Successful in 1h15m34s
19c4bd0d01
The origin answered 503 and closed with the request unread, so the connection ended
in a reset after the answer. Clients on Linux and macOS still read the 503, but a
client reading to the close then saw an error: 300 of 300 refused requests that
wrote at once. With this change, none of 300 on either system. The 431 path already
stopped sending and read on before closing; both now share that.

origin_per_peer_limit failed under load because a third connection could overtake
the idle two, so one of them was refused and the count never reached the limit, and
because a fixed 200 ms and a 2 s read timeout could both run out. It now retries an
attempt overtaken and waits for each state. It also requires 200 refusals to read
their 503 with no read error and no retry.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!657
No description provided.