SIGN IN SIGN UP

feat(api): admission, the header limit, and the router that mounts two routes

Dimensions 5.2 and 5.3, plus the router they hang from. Coverage holds at
100.00% for afd_api (608 regions).

## The ceiling is a semaphore, not a counter protocol

`dispatchApi` writes the protocol out by hand — `fetchAdd`, compare, `fetchSub`
in a `defer`, and a second store to keep a gauge in step. It is correct because
four statements agree; an arm that forgets the `defer` leaks a slot and the
instance walks down to serving nothing.

`Semaphore::try_acquire_owned` refuses instantly and hands back a permit that
releases on drop. No arithmetic, no release path to forget, and cancellation
comes free: a caller that hangs up drops the future, which drops the permit.
Zig's `defer` cannot express that — there is no future to drop. A test proves
it by aborting a live request and watching the slot come back.

The route CLASS is resolved when the route is MOUNTED rather than per request:
nothing about it can change between requests, and an unmetered route now
reaches its handler without a branch. `is_metered` is an exhaustive match, so a
new class fails the build — `route_admission.zig` had traded its exhaustive
switch for an `else` arm and a runtime walk over two hand-kept name lists.

`tower::limit::ConcurrencyLimit` + `load_shed` was the off-the-shelf shape and
was rejected: it sheds through an error type that carries no ceiling, so
`X-RateLimit-Limit` could not be filled from it, and axum needs `Infallible`.

## The request id is minted, not borrowed

The first draft read it from a `tower_http`-stamped request extension, so the
id existed only if a layer nobody had written was mounted, and its absence
degraded silently — making `req_unknown` mean three different things.

The Zig shed mints its own id inline, and so does this one. `req_unknown` means
one thing again: entropy failed. A shed is the WORST case for identification —
no principal, no workspace, no route params, nothing has been read yet — so the
id is the entire identity of that record, and it is minted once and used in
both the log line and the envelope. The Zig shed logs no id at all, leaving its
two records uncorrelated.

`afd_crypto` grows a public `Entropy` so this does not become a second
`getrandom` call site.

## The same 16 KiB, for the opposite reason

httpz defaults to 4 KiB and Zig had to RAISE it — a session bearer plus proxy
headers passes 4 KiB routinely. hyper defaults to ~400 KB, so nothing is ever
refused and a client can hold that much buffer per connection. Same number,
inverted argument: a ceiling here where it was a floor there.

Proven over a real socket, because hyper enforces it while PARSING — there is
no request value for a `Service` to see. The Zig test accepts either a 431 or a
transport close; this one requires the 431, because 17 KiB fits in any socket
send buffer and a test that also accepted a dead socket would keep passing if
the 431 path regressed entirely.

## HEAD, and what the router does not claim

`method_routing.rs` tries the `head` route and then falls through to `get`, so
every GET handler answers HEAD unless something stops it. In Zig that trap was
dormant — the request never arrives — and the scope table would have resolved
HEAD to the WRITE rung. Refused once for the whole daemon rather than eighty-one
times, and with `route_layer` so an unserved path is still a 404.

`handler_for` is total over the ten families: a family whose handlers are not
ported says so in an arm rather than by being missing from a list. All 81 routes
are tabled and two are served, which a test asserts rather than describes.

No admission layer is wired yet, deliberately: `Ops` is the only class mounted
and it is never metered, so the metered branch would be an arm no request could
reach.

## Logging

trace on both probes and on admit (per-request, and what predicts a shed),
debug on mounts and the refused HEAD, info once when the router is built, warn
when readiness goes red, error when entropy fails. Every warn and error carries
an `error_code`, per the logging standard's rule for those two levels.

Every call-bearing log field is hoisted to a `let`: `tracing`'s `log` feature
compiles a second copy of the expression and llvm-cov scores the dead one.
Three of these cost the crate its 100% until they were hoisted.
K
Kishore Kumar committed
6f70680cb89107073c62f12b1782d85316fb3c09
Parent: 5e99406