Merge branch 'wt/review-002-fwd17-19-contract-decisions'

This commit is contained in:
2026-08-30 22:03:02 +00:00
2 changed files with 380 additions and 11 deletions
@@ -149,6 +149,56 @@ error projection and the success sweep (SSE detection +
output-schema selection), where the precedence order is: concrete 2XX
statuses, then `2XX`, then `default`.
### Forwarding contract decisions (review 002 FWD-17/18/19)
The shared forwarding core (`src/adapters/forward.rs`) used by both
`from_openapi` and `from_jsonschema` pins three contracts. Each is a
decision the code half-implied; the module doc carries the full normative
text, this section records the reasoning at the assembly-trust boundary
that ADR-066 establishes: an assembly's spec/template/base-URL inputs
are trusted configuration, while peer call-time input never is.
**FWD-17 — SSE payload contract (decided: carry raw payload + event
name for non-JSON frames).** A subscription frame's `data:` payload
that is itself valid JSON surfaces as the decoded value (`123` stays a
number, `"123"` stays a string). Any other payload surfaces as the
`{"data": <raw>, "event": <name|null>}` wrapper: a legitimately
non-JSON stream stays field-addressable and an upstream's named-event
conventions (`event: error`) are visible instead of indistinguishable
from data. The `event` value is the frame's `event:` field under
WHATWG last-wins semantics — `null` when absent, never the implicit
`message` default, so "named" and "default" stay distinguishable. JSON
frames surface as themselves even under a named event; consequence:
the event name is only visible on non-JSON frames. Chosen over the
alternative (document the old JSON-or-string contract) because the old
behavior silently erased payload shape and made an upstream's error
convention unobservable — a fidelity loss on the same axis ADR-023
already rejects for status mapping.
**FWD-18 — placeholder routing rule (decided: fix + structural-value
error).** A key matching a path-template placeholder is consumed by the
path and never also emits as a query parameter, whatever its value's
shape (the renderer's placeholder check precedes query routing — fixed
behavior, pinned by test). A placeholder renders exactly one literal
path segment, so a structural value (object/array) under a placeholder
key fails with `INVALID_INPUT` rather than splicing minified JSON into
the path. Scalar values (string/number/boolean/null) render
percent-encoded as before.
**FWD-19 — literal `%` in template text (decided: documented
trade-off, not rejection).** A `%` inside a *value* is always encoded
(`%``%25`), so a value can never inject or fake percent escapes. A
`%` in *template or base text* survives verbatim: an assembly writing
`%2F` into a template is presumed to intend a pre-encoded segment for
upstreams that route `%2F` differently from `/`. Inputs are
assembly-supplied (this ADR's trust boundary), so the strict shape
(call-time rejection of raw `%` in template text) is rejected — it
would break legitimate pre-encoded templates without adding safety:
the surviving `%2F` still renders as a single literal segment, cannot
change the origin, and cannot be forged from peer input. The trade-off
(upstream-dependent routing of bare percent escapes) is the
assembly's choice, not this crate's.
## Consequences
**Positive**: