docs(spec): one owned request-normalisation boundary across the five runtime shapes - #27
Draft
antstanley wants to merge 1 commit into
Draft
Conversation
This was referenced Aug 5, 2026
antstanley
force-pushed
the
spec/runtime-parity-across-interfaces
branch
2 times, most recently
from
August 5, 2026 08:22
679c924 to
69d431c
Compare
antstanley
marked this pull request as draft
August 5, 2026 08:25
This was referenced Aug 5, 2026
antstanley
force-pushed
the
spec/runtime-parity-across-interfaces
branch
from
August 5, 2026 09:00
69d431c to
ef1ce74
Compare
antstanley
force-pushed
the
spec/runtime-parity-across-interfaces
branch
from
August 5, 2026 11:29
ef1ce74 to
52d4e49
Compare
…runtime shapes Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
antstanley
force-pushed
the
spec/runtime-parity-across-interfaces
branch
from
August 5, 2026 12:01
52d4e49 to
289e8ee
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
Stacked PR 12 of 16 — part of stack #35, which targets
main.Base: #26 (
spec/harden-admin-plane) · Followed by: #31This PR's diff shows only its own change. Merge the stack bottom-up; do not merge this before its base.
Why it sits at position 12: Touches
06-configuration.md's[server]section and04-http-api.md's bootstrap step 6, both also edited by #29, #24 and #26.Scope of this PR
This PR currently carries the change spec. It will also carry the implementation plan and the build work for that spec — plan and code land as later commits on this same branch, so the spec, its plan, and its implementation review and merge as one unit.
Review order within the PR: spec first, then plan, then implementation.
Change spec proposing one owned request-normalisation boundary across the five runtime shapes.
Problem. The same service is published behind five request shapes — the Axum server, the Lambda runtime, the napi Node binding, and the PyO3 WSGI and ASGI adapters — and each reconstructs the request differently. The defects are not one bug repeated; they are the consequence of normalisation being re-implemented per host with no shared conformance definition:
assert!s on host-suppliedmethod/paththat panic on a legal emptyPATH_INFO, a synchronous napihandleRequestthatblock_ons the whole request and stalls the host process, uncapped body buffering on both Python adapters, two decoded-path reconstructions, two duplicate-header collapses, and three differing Lambda base-path strips.Proposed delta. Hosts hand over raw percent-encoded path bytes, a separate query string, ordered header pairs, and a body already bounded against a published
limits(). The FFI performs every decode, segment-aware base-path strip, header ordering, and body check exactly once, andhandlebecomes async and total — shaping failures return the same status the native server would, so an embedded host never returns 502 where the server returns 404.Adds a differential conformance corpus replayed through all five shapes as a CI merge gate — this is what stops the drift recurring — plus an explicit
server.max_request_body_bytesenforced before buffering on every host, and two-guard panic containment (innerCatchPanicLayerretained forx-request-idcorrelation, a second guard wrapping the base-path service, and an FFI-levelcatch_unwind).A live bug confirmed in passing. The
Some("/")base-path case is genuinely reachable:strip_prefix_at_segment_boundary("/", "/")returnsSome(""),new_pathbecomes/, and theassert_ne!inbase_path.rsthen fires on every request to/.Breaking change, stated plainly. The async signature breaks
@oidc-exchange/nodeand PyPIoidc-exchange. One shared version string means0.2.x → 0.3.0across all three manifests, with sync entry points deprecated for one major cycle and a per-package migration table.Open questions recorded rather than assumed: whether a panic across the napi
extern "C"trampoline aborts Node for this build (catch-unwindis not enabled), and which WSGI/ASGI servers are used in practice and whether they drop underscore headers.Pre-existing divergence found:
server.base_pathexists incrates/core/src/config.rsbut was never added to06-configuration.md— the mergedimplement_lambda_runtime.mdproposed that block and it was not applied. The spec flags it and supplies the text.Drafted with the
spec-creatorplugin from a deep security scan of the repository at53cbdec9. Spec only — no source changes.