The /mcp nest (to_mcp streamable HTTP service) collects the raw body
itself, so axum's extractor-based DefaultBodyLimit never applies and a
multi-GB chunked POST buffers entirely in memory (review-001 SRV-03).
Wrap the nest with an explicit counting-body middleware: 8 MiB cap
(headroom over the gateway's 2 MiB for JSON-RPC batch payloads),
Content-Length-declared oversizes rejected before reading, streaming
oversizes cut off mid-read and answered 413 (rmcp maps body-read errors
to 500, so the middleware sources the status itself).
Verification: cargo check (default + mcp + all-features); mcp test
suite pending tree unstuck from parallel agent's WIP.
Replace per-chunk parse_sse_frames with SseParser holding raw bytes
across chunks: reassembles frames split at TCP boundaries (the review's
silently-losing case), decodes UTF-8 per complete line so multi-byte
chars split across chunks survive, caps the buffer at 1 MiB
(SSE_EVENT_BUFFER_CAP) and dispatches a pending event at EOF.
forward_stream threads the parser through its unfold state and emits a
terminal error envelope on cap overflow. Existing single-chunk SSE test
assertions preserved; added multi-chunk, split-UTF-8, EOF-dispatch, and
cap tests.
Verified: cargo test (219 pass), clippy -D warnings, fmt --check.
- apply bearer_auth_middleware route_layer AFTER the extra_routes merge,
so assembly-layer custom routes resolve the bearer token by default
(ADR-046 §4); per-route opt-out via the route's own layer remains
- enforce RESERVED_PATHS per-method at build time: a probe MethodRouter
occupied on all methods is pre-merged against extras, so a custom
POST /search panics like a same-method overlap (ADR-046 §3)
- tests: auth resolves through an extra route; an extra route with its
own layer opts out; reserved-path merge panics; non-reserved
different-method merge stays legal; MCP bearer-gate test stays green
- ADR-046 §3: one sentence restating the per-method rejection rule
Verification: cargo test (215) ok, cargo test --all-features (260 +
integration) ok, clippy -D warnings (default + all-features) ok,
cargo fmt --check ok.
- GW-01: /publish validates every NDJSON chunk against the op's
publish_schema (incl. the first-line chunk) via NdjsonChunkStream —
terminal Err(INVALID_INPUT)/422 on violation, matching the wire
dispatcher's per-chunk contract. Route-level fix; the alkcall spine
was explored and rejected (wire validation is pump-side by design).
- GW-06: the body is streamed, not buffered — Body::into_data_stream()
-> newline-framed BufferedLines -> lazily parsed chunk stream.
ADR-068 documents the streamed semantics and the 2 MiB per-line cap.
- GW-08: /batch capped at 100 operations (INVALID_INPUT 400).
- GW-09: internal-op batch entries now carry generated UUID request ids.
- GW-10: first publish line missing `chunk` is rejected INVALID_INPUT.
- GW-11: redundant /publish pre-checks removed; enforcement rides on
invoke_sink via the shared dispatch spine.
- HY-13: the vacuous stub test was replaced by a body-cut-short test.
- Adjacent: INVALID_OPERATION_TYPE now maps 422 (with identity) / 401
(without) in error.rs — the route relies on the shared mapper since
the pre-checks are gone (GW-03's finding; was a 500 fall-through).
Verification: cargo test 211 passed; cargo clippy --all-targets -- -D
warnings clean; cargo fmt --check clean.
resolve_refs_recursive recursed with no cycle detection and no depth
budget; a self-referential OpenAPI component stack-overflowed and
aborted the process (uncatchable, kills import()).
- add branch-scoped visited set on the JSON-pointer ref path: a ref
re-entering its own expansion chain errors cleanly with
AdapterError::SchemaParse naming the offending ref (OAI-01)
- add depth budget (MAX_REF_RESOLUTION_DEPTH = 64) bounding $ref hop
chains and schema nesting height; over-deep specs error cleanly
instead of exhausting the stack (OAI-01)
- clean loud error over depth-limited expansion: recursive schemas
(trees, linked lists, cursor pagination) fail import rather than
expand unboundedly
- shared refs to a common schema (diamond/repeated) still resolve —
visited set is branch-scoped, not global
- OAI-08: replace the two guarded expects in from_value
("paths is object", "schemas is object") with if-let paths
Verification: cargo test 188 passed / 0 failed; clippy
--all-targets -D warnings clean; fmt --check clean
21 review-001 tasks across server/adapters/client/gateway/websocket/infra,
chunked from the 7-unit remediation plan in
docs/reviews/001-initial-implementation-review.md.
- Scope split by mechanism, not one-per-finding: 15 tasks in generation 1
(parallelizable), 6 sequenced after their file-sharing precursors
- Deliberately deferred until dependent fixes land: projection/doc
fidelity partial (Unit 6 beyond dependency hygiene), coverage backfills
(COV-01..07 via in-task acceptance for forward.rs), and per-finding
minors (OAI-06/07, HY-02/04/06/10/11, CON-08)
- Cross-crate WS-12 (alkcall demux 4 GiB discard alloc) noted for filing
in alkcall, not here
taskgraph: validate clean, no cycles, 6 generations
Full-surface integration suite (tests/full_surface.rs, mcp feature):
- one HttpAdapter over real TCP (ProtocolHandler::handle path) serving
gateway endpoints, /openapi.json, /mcp, and the WS channels session
- gateway: search/schema/call/subscribe/batch/publish presence,
envelope shapes, error fidelity end-to-end
- from_openapi import -> Internal-by-default invisible from the wire ->
External facade composes it via env.invoke -> upstream HTTP API
called end-to-end (ADR-015 composition model exercised)
- to_openapi 6-path doc validated against openapiv3 over the wire
- to_mcp: MCP client connects to /mcp on the served adapter, lists the
4 gateway tools, search returns ACL-filtered ops (Sub excluded)
Production fix: the WS upgrade route was reserved but never wired into
HttpAdapter's router (the ws-upgrade-session tests built their own
router). Now wired with ws_bearer_auth (401 without a resolvable
token) around ws_upgrade_handler.
Docs sync: all 28 'Port notes' sections/blockquotes stripped from
ported ADRs/specs; OQ-01/OQ-02 statuses corrected to resolved in
overview.md, websocket.md, and the README table (open-questions.md was
already current).
Publish prep: cargo publish --dry-run --allow-dirty succeeds;
cargo doc --no-deps warning-free (ADR link targets fixed); feature
combinations (default / test-support / mcp / wss / all) compile
warning-free under clippy -D warnings.
Verified: cargo test (182 lib default), --all-features (227 lib + 29
integration), clippy -D warnings x3 feature sets, fmt, doc,
publish --dry-run.
Ported the alknet-http overlay verification to the channels-over-WS
session (tests/ws_overlay_ops.rs, test-support feature, 8 tests):
- overlay mechanism: browser-registered ops land in the connection's
Layer 2 overlay (register_imported), exposed via overlay_env() —
no PeerIds (browsers are not peers); PeerRef::Specific to a browser
id routes to nothing (NOT_FOUND)
- hub→browser call through compose_root_env's attached overlay
- AccessControl on browser ops gates hub calls (scope match allows,
missing scope FORBIDDEN)
- overlay dies with the connection; no leak between connections;
in-flight calls to browser ops resolve on close
- wire-level: 10 interleaved concurrent calls across two WS sessions
— no cross-correlation, no deadlock; disconnect mid-call resolves
and a fresh session works (no listener wedge)
byte_adapter: read_eof Notify now gated to the wss feature (its only
consumer is from_wss) so a test-support-only build is warning-free.
Verified: cargo test (182 lib), --all-features (227 lib + 5 MCP + 8
overlay + 10 WS integration), clippy -D warnings (default,
test-support, all-features), fmt.
Spike against alkcall source resolved ADR-067 assumptions:
- write_chunk issues header+payload as separate write_alls; channel
0's write_frame issues prefix+body separately — a logical write can
surface as multiple chunks, so the WS adapter must parse outgoing
chunk boundaries (byte-stream treatment both directions), not assume
write-per-chunk or message-per-chunk
- MAX_CHUNK_LEN is 16 MiB; the WS path needs a practical message cap
with oversized chunks split across messages
- install_channel_zero + run_loop_single_stream confirmed as the exact
server-side seam; EOF/teardown invariants already specified by
alkcall (REQ-CH-01/02)
Corrections applied to websocket.md, ADR-067, OQ-01.
docs/plans/implementation.md: scoped plan guiding task decomposition —
spike findings, 4-phase build order, OQ dispositions, task conventions.