- version bump 0.6.0 -> 0.7.0 (minor per the dep-wave convention:
0.5.0 rode alkcall 0.8.0; see the preceding consume commit)
- README usage snippet 0.5.0 -> 0.7.0
- changelog: cut [0.7.0] with the alkcall 0.9.0 consumption under
Changed (the stub-sweep audit: no ManagerError/RelayError matching,
no Establishment construction, no marked-pub surface reached through
the HTTP API) and the two ride-through fixes under Fixed
(register_imported Result in the WS overlay tests, fuzz/shared spec
alignment)
Verification: cargo test/clippy/fmt/doc green in the preceding deps
commit; no source change in this commit
- bump alkcall 0.8.1 -> 0.9 (gateway feature unchanged). No code change
forced: none of the 0.9.0 breaking surfaces are constructed or
pattern-matched in this crate — no ManagerError match arms (the new
InvalidAdopt variant changes nothing here), no RelayError matching
(the removed PubTypedOpen variant is unreachable from this crate),
no Establishment construction or Debug dependence (the WS ferry
passes Option<OpenEstablisher> through unchanged, per the 0.8.0
audit), and the op/register forward-through refactor does not touch
the from_wss import filter or the adapter-registered leaf bundles
- ride-through fixes: tests/ws_overlay_ops.rs now expects
register_imported's new Result<(), String> return (8 sites assert
registration success instead of discarding the value — the bool
return they consumed was ignored anyway); fuzz/shared follows the
main crate to alkcall 0.9 so the harness replay resolves one
alkcall version (the stale 0.8.1 spec pinned two copies against
alkhttp's requirement and broke the shared-crate build)
- minor bump 0.6.0 -> 0.7.0 per the dep-wave convention (0.3.0 rode
alkcall 0.6.0, 0.4.0 rode 0.7.0, 0.5.0 rode 0.8.0): this crate's
public API carries alkcall types through re-exports and the
ProtocolHandler impl, so a semver-breaking upstream is
semver-relevant here
Verification: cargo test 441+70 pass (default), 520+70 pass
(all-features), clippy --all-features --all-targets -D warnings clean,
fmt --check clean, doc --no-deps clean, fuzz corpus replay 21/21
Adopt the alk*/fuzzing posture (alkcall 0.8.1 precedent) — the dep
bump this ride-along builds on was 4005517:
- docs/plans/fuzzing.md: the four-target plan (sse_parser,
ws_chunk_framing this session; spec_import + the stateful wave
later), the infrastructure blueprint, and the corpus/campaign
policies (§3's table tracks progress)
- fuzz/ workspace (the sibling layout): nightly-pinned subtree,
stable fuzz/shared invariant library (corpus replay = the standing
fuzz gate), detached runner (never a foreground child of an agent
session), JSON dict, deterministic seed generator; 80 committed seeds
- two wave-1 targets: sse_parser (SseParser::feed + the FWD-17
envelope mapping — the parser every subscription forwards through)
and ws_chunk_framing (WriteChunkWalk, the write pump's chunk walk)
- crate-side surfacing: SseParser/SseEvent/sse_event_envelope are pub
behind the adapters::forward::fuzzing re-export hub; the write
pump's inline chunk loop extracted as WriteChunkWalk (pump byte
behavior unchanged — 441 tests green); retained_bytes() diagnostic
(the alktunnels/alksocks posture)
- root Cargo.toml gains the explicit [workspace] table with
fuzz/ excluded (auto-discovery would pull the nightly-consumed
dev-deps into the stable build — the alkcall trap); fuzz/ joins the
publish exclude list
- AGENTS.md verification checklist gains the corpus-replay line
FWD-20 fix, found by driving the new sse_parser harness: feed()
rescanned the whole reassembly buffer per feed — a dribble-fed
subscription (one unterminated line over many small chunks) cost
quadratic CPU (1 MiB dribble ≈ minutes per connection, unbounded
total). Line assembly now walks only the arriving chunk: the buffer
holds just the current line, the scan never revisits drained bytes.
1 MiB dribble: ~5 min (quadratic) → 21 ms (linear). Regression test
sse_parser_dribble_feeds_do_not_rescan_the_buffer.
Verification: cargo test 441 passed; cargo test --all-features ok;
clippy --all-targets -- -D warnings (main + fuzz/shared) clean;
fmt --check (main, fuzz, fuzz/shared) clean; cargo fuzz build clean;
corpus replay (cargo test --manifest-path fuzz/shared/Cargo.toml) 80
seeds green.
Refs: alkcall docs/research/fuzzing.md (§7.9 posture), alksocks
08a3694 (the sibling wave-1 shape), docs/plans/fuzzing.md §2
Picks up the duplicate adopt/open collision fix found by alkcall's
manager_routing fuzz campaign (alkcall CHANGELOG 0.8.1): a duplicate
adopt_channel/open_channel no longer replaces the live channel's
state. alkhttp reaches the fixed paths via the shared ChannelManager;
no alkcall API surface used by this crate changed.
Verified: cargo test (456 passed), cargo test --all-features,
clippy --all-targets -- -D warnings, fmt --check.
- bump alkcall 0.7 -> 0.8 (gateway feature unchanged). No code change
forced: alkcall 0.8.0 is additive on the call-plane JSON and the
registry seams (review 008's remediation — the establisher reply
projection, flavor-form open-op ids in discovery, the in-tree
ChannelRelay + hub-leg install template) and none of the new
surfaces are constructed in this crate: no Establishment reply
fields (the WS ferry passes Option<OpenEstablisher> through
unchanged), no marked specs imported through from_call (the from_wss
filter excludes the protocol-session ops), no ChannelRelay /
HubLegImports / HubLegTemplate consumption (hub-leg assembly stays
at the assembly layer)
- one ride-through on this crate's discovery surface: a deployment's
with_ws_openable_alpns open-op specs with non-standard names now
serve an explicit channel_open_alpn string through services/list +
services/schema (alkcall 0.8.0 U-1, ADR-047 amendment 3) so hubs
relaying via from_call reconstruct the marker; standard-shape names
stay byte-stable
Verification: cargo test 456 pass (default) / 589 (all-features),
clippy --all-targets -D warnings clean (default + all-features),
fmt --check clean, doc --no-deps clean
- version bump 0.4.0 -> 0.4.1 (patch: the MSRV raise is a metadata
change that breaks no downstream able to build the crate before)
- README usage snippet 0.4 -> 0.4.1
- changelog: cut [0.4.1] with the alkcall 0.7.1 consumption + the
rust-version 1.85 -> 1.88 floor raise under Changed
Verification: cargo publish --dry-run --allow-dirty (cargo test/clippy/
fmt green in the preceding deps commit)
- the 1.85 claim was already false at the dependency level: the resolved
lockfile pulls icu_* 2.x (MSRV 1.86 via jsonschema -> idna) and, since
alkcall 0.7.1, alkcall itself declares 1.88 — 1.85 toolchains cannot
build the tree regardless of what Cargo.toml declared
- raising the floor to 1.88 aligns with the ecosystem MSRV decision
(noq QUIC path, per the alknet MSRV audit; recorded for alktls in
OQ-TLS-08) and breaks no downstream that could build the crate before
- alkcall 0.7.1 rides in via the lockfile (version = "0.7" already
covered it); no code change forced — 0.7.1 is its own MSRV raise plus
the cf-006/cf-007 work consumed in the 0.7.0 wave
- one 1.88 clippy lint fixed: uninlined_format_args in a forward.rs test
Verification: 1.85 check fails as documented (icu_* 1.88 floors); 1.88
toolchain check/test/clippy --all-targets -D warnings clean; stable 1.94
test 456 (default) / 589 (all-features), clippy -D warnings (default +
all-features), fmt --check, doc --no-deps
- version bump 0.3.0 -> 0.4.0 (the CONNECTION_CLOSED -> 503 gateway
mapping is a wire-visible behavior change for HTTP callers matching
on the previously-emitted 500 — a minor bump, not a patch)
- README usage snippet 0.3 -> 0.4
- changelog: cut [0.4.0] with the alkcall 0.7.0 wave entry
(CF-005/006/007, no code change forced) + the CONNECTION_CLOSED
mapping under Changed (wire-surface behavior)
Verification: cargo test (456 passed), cargo test --all-features
(589 passed), clippy -D warnings (default + all-features), fmt
--check, cargo publish --dry-run --allow-dirty
Dependency wave + one wire-surface behavior fix:
- bump alkcall 0.6 -> 0.7 (gateway feature unchanged). No code change
forced: this crate constructs no ServingConfig (the one 0.7.0
struct-literal break — from_wss keeps the pure-consumer
from_connection; opt-in serving remains the review-006 Part C
deferred decision), and the CF-006 per-call opener-identity overlay
is behavior-only upstream (hub-forwarded WS-ferry opens now resolve
the end client's identity, the intended effect)
- gateway error table maps CONNECTION_CLOSED -> 503 Service
Unavailable: alkcall 0.7.0's CF-007 amendment makes it the eighth
protocol code (ADR-016's list is formal at eight); it previously
fell to the catch-all 500, misreporting a retryable,
provably-undelivered call as a permanent server failure. retryable:
true, so the retry_after details path applies on 503. Tests pin the
mapping and the Retry-After passthrough
- ADR-023 amended: the protocol-code list is eight (ALREADY_EXISTS +
CONNECTION_CLOSED rows added to the §3 table, normative rule and
call.error code list updated); http-adapters.md six-code references
de-staled
Verification: cargo test (456 passed), cargo test --all-features
(589 passed), clippy -D warnings (default + all-features), fmt
--check, cargo doc --no-deps (0 warnings)
Mechanical pass for the alkcall 0.6.0 bump (review 007's
establishment follow-ups sweep: R-01 Establishment plan payload,
R-02 OpenHandler lifetime doc note, R-03 pump_bidi extraction):
- bump alkcall 0.5 -> 0.6 (gateway feature unchanged)
- the OpenHandler signature gained a plan parameter —
Fn(Value, Option<ChannelPlan>, Connection, AuthContext) ->
JoinHandle<()> — so the test's echo_open_handler closure gains
`_plan` (the only closure-construction site in this crate)
- no ferry change: this crate constructs no Establishment and passes
the Option<OpenEstablisher> through unchanged (OpenableAlpn fields
and register_openable_with_establisher threading are unchanged in
0.6.0); the establisher's Establishment.plan now reaches the pump
handler's second parameter process-locally (ADR-049 amendment 2)
- docs updated: websocket.md (plan threading + pump_bidi pointer),
OpenableAlpn field docs, with_ws_openable_alpns doc comment
- CHANGELOG [Unreleased] consumption-wave entry
Verification: cargo test (454 passed), cargo test --all-features
(587 passed), clippy -D warnings (default + all-features),
fmt --check, cargo doc --no-deps clean
AGENTS.md, lib.rs, the README, and adapters/mod.rs docs all state
openapi is the shared spec model implied by both feature sides, and
the README's client row claims from_openapi under client — but the
feature graph only had server -> openapi. A lean client-only build
compiled yet silently lacked from_openapi (gated all(client,
openapi)).
Verification: cargo test (default + all-features), clippy both
feature sets -D warnings, fmt, publish --dry-run — all green.
alkcall 0.4.0 now enforces OperationSpec.input_schema at dispatch
(INVALID_INPUT). All 438+16 tests pass; the gateway path is
unaffected because alkhttp's imported ops validate through their own
CompiledInputSchema closure, which composes with the new registry
check (registry = raw JSON Schema semantics, adapter = closed by
default).
Bump alkcall 0.2 -> 0.3 (published 2026-09-04; the remediation of
alkcall reviews 004-005, the upstream resolution of alkhttp review 003
WS-24/WS-25). Two source-break classes, both mechanical:
- take_call_connection now returns Option<Arc<CallConnection>>
(was bare value) — drop the double-wrap in WssSession::connect.
- register/register_on/register_openable take &OperationRegistry
(was &mut) — drop 51 stale `mut` bindings (clippy --fix), which is
the interior-mutability change that makes the per-session fork
surface possible.
No behavior change in this crate yet; the 0.3 mechanisms (fork,
serve_single_stream, op/register, install_bootstrap_discovery,
collision policy) are the composition surface for alkhttp review 003
Unit 2 (WS-20..22, WS-26 wiring) — not wired here yet.
Verification: cargo test 453 passed (default) / 575 passed
(all-features), clippy both sides -D warnings clean, fmt clean,
cargo doc --no-deps clean.
- README covering the gateway surface, both import/export adapter
families, feature flags, and security posture (all claims verified
against the current code)
- standard MIT and Apache-2.0 license texts matching the
license = "MIT OR Apache-2.0" manifest field
- Cargo.toml: point the manifest at README.md and exclude scripts/
from the published package
Split the feature graph so consumers pulling only the import adapters
(from_openapi / from_jsonschema / from_mcp) no longer compile the axum
/ hyper server stack, and server-only deployments no longer compile
reqwest. One crate, one import path — sides cut by features, not by a
crate split.
Feature graph:
- server (default): axum host, gateway, WS upgrade, to_openapi, to_mcp
- client (default): client host, forward, from_jsonschema, from_openapi
- openapi: shared OpenAPISpec model (implied by both sides)
- mcp: from_mcp needs client, to_mcp needs server
- wss: tungstenite transport (from_wss); tungstenite half of the
shared WS↔byte-stream adapter
- h2/http1: hyper protocol features; imply server
Wire-contract neutral: gateway endpoints, ALPNs, and all public API
shapes unchanged; defaults keep both sides on.
Supporting changes:
- forward.rs drops its axum::body::Bytes type leak (bytes crate types)
- bounded_join + error-echo caps move to input_validation (usable by
both sides; openapi_spec no longer imports from forward)
- byte_adapter: axum flavor compiles under server, tungstenite under
wss; the generic pumps stay shared (WS-11)
- input_validation / openapi_spec import-only internals gated to the
side that consumes them
- http-body-util moves to dev-dependencies (was test-only)
- integration-test required-features updated for the new sides
- from_wss unit tests (axum producer harness) gated to server
Verified: cargo test (defaults, 453) and --all-features (575) pass;
lean side builds (client / server / client,mcp / client,wss /
server,wss / openapi-only) build clean with zero warnings;
clippy -D warnings clean across all feature combinations; fmt clean.
Bump the alkcall dependency to 0.2 (with the gateway feature) and
converge on the promoted shared pieces:
- The local dispatch spine (gateway/dispatch.rs, 721 lines) is deleted;
GatewayDispatch, schema_disclosure_denial, and DEFAULT_DEADLINE are
re-exported from alkcall::gateway (alkcall ADR-048). The 30 s default
deadline preserves the previous behavior exactly.
- gateway/schema_cache.rs (PublishSchemaCache) is deleted: alkcall CF-003
compiles publish_schema at registration time and exposes
OperationRegistry::publish_validator; the /publish chunk stream
resolves against it. Un-compilable schemas are now rejected at
registration, so the two end-to-end fail-closed tests were reworked
into a registration-rejection test (a stronger guarantee).
- schema_disclosure_denial consumers (to_mcp, routes) use alkcall's
promoted implementation; the alkhttp-local copy is gone (ADR-071
updated: the guard stays as defense-in-depth, the implementation no
longer forks).
- CF-001: from_wss drop monitor and the WS overlay tests use
CallError::connection_closed; the review-001-ws-eof-signal race tests
now assert retryable CONNECTION_CLOSED on both resolution paths (the
tolerated non-retryable INTERNAL write-failure outcome is gone).
- Added CHANGELOG.md (Keep a Changelog), Unreleased section records the
bump and convergence.
Verification: cargo test default 453 ok, wss 470 ok, mcp 526 ok,
all-features 575 ok; clippy -D warnings clean (default + all-features,
all-targets); fmt clean; cargo doc warning-free.
Net: -1093 lines.
- percent-encode path-parameter values with a WHATWG path-segment
superset (/, %, ?, #, \\, controls): traversal values, query/fragment
structure, and later-placeholder strings can no longer alter the
request line (FWD-01)
- single-pass template rendering; rendered values are never
re-substituted; unbound or unterminated placeholders error loudly
- append the request path to the base URL directory (https://host/v1
+ /chat/completions keeps /v1) instead of Url::join semantics,
with a post-assembly origin-equality check (FWD-02)
- base_url validation: https/http-only scheme allowlist, explicit
host required, userinfo rejected (credentials flow via
Capabilities only); request_path is never empty
Verification: cargo test (238 lib tests incl. 8 new FWD-01/02 tests),
cargo clippy --all-targets -- -D warnings, cargo fmt --check
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.
- 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.
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.