Docs ADR 0007 · Request scope in extensions

DocsReference

#ADR 0007: Request scope travels in axum extensions, never in shared state

Status: accepted, 2026-09-05

#Context

The discarded TypeScript v1 kept "the current request" in a closure variable that was saved and restored around each request. A review test proved that two concurrent requests in one isolate swapped request ids in their logs and one lost its waitUntil. Rust makes the same mistake possible with a thread_local! or a static RefCell.

#Decision

Core middleware creates a Scope { request_id, defer, span } per request and stores it in the request's extensions. Handlers receive it through the Scope extractor. EventBus::emit_in(&scope, ..) and Defer take the scope explicitly. cratefield-core and every module carry #![forbid(unsafe_code)] and a clippy lint deny on thread_local! and static mut.

#Consequences

  • No ambient request context; a handler that needs the request id asks for it.
  • The conformance kit includes a two-concurrent-requests test that asserts each request logs its own id.

Mirrored from docs/adr/0007-request-scope-in-extensions.md at b6f50cd. The harness is the source of truth: a correction goes there first.