# Changelog All notable changes to this crate are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this crate adheres to [Semantic Versioning](https://semver.org/). ## [0.8.1] — 2026-10-22 ### Changed - **`alkcall` dependency consumed at 0.10.1** (patch pickup; the adoption-window ordering fix, alkcall review 013, routed from alkgit's wave-2 gate). A chunk routed by the channels demux inside the `adopt_channel` install→drain window was delivered **ahead of** earlier-parked early arrivals, inverting the channel's byte-stream order, and a related loss variant parked a chunk forever after the drain had removed its queue. This crate reaches the fixed paths via the shared `ChannelManager`; no alkcall API surface used here changed — no code change in this crate. The dependency requirement is tightened `0.10` → `0.10.1` so downstream projects composing this crate with alkcall resolve the fixed version rather than an older 0.10.x lockfile entry. Patch bump 0.8.0 → 0.8.1 per the dep-wave convention (0.4.1 rode alkcall 0.7.1): alkcall 0.10.1 is a patch release with no API or wire-format change (`EventEnvelope`, the channels 8-byte chunk header), so nothing semver-relevant moves on this crate's surface. ## [0.8.0] — 2026-10-17 ### Added - **Door-surface Basic auth tolerance (review 008 AH-1, ADR-073).** The extras-door surface now resolves `Authorization: Basic base64(user:pass)` — the password field acts as the token and rides the same `IdentityProvider::resolve_from_token()` backend as Bearer (the GitHub-PAT shape `git-lfs` and git's smart-HTTP transport authenticate with). No new trait method; the provider's grant table governs exactly as it does for Bearer, and "unparseable / unresolvable → None" fallback semantics are preserved. Basic is scoped to the door surface: `bearer_auth_middleware` stays Bearer-only on the gateway endpoints, `/openapi.json`, `/healthz`, and the MCP nest, and the WS upgrade path is untouched — a Basic credential contributes no identity on any path a deployment has not explicitly mounted doors on. New public API: `server::door_auth_middleware`, `server::extract_door_identity` (`bearer_auth_middleware` / `extract_bearer_identity` keep their Bearer-only semantics and their coverage). ### Changed - **`alkcall` dependency bumped to 0.10.0** (the gateway ownership-seam release, alkcall review 012) and the loud ownership default passes through to the HTTP surface (ADR-072): `HttpAdapter::with_ownership_provider` / `HttpAdapter::with_static_ownership_fallback` thread the provider into both spines this crate constructs — the gateway endpoints' per-request spine and the MCP nest's spine (single wiring point in `GatewayState::dispatch`). An unwired, undeclared spine now refuses a `resource_type`-gated op with a `FORBIDDEN` envelope (**403** with identity / **401** without) — the behavior break is inherited, not re-decided; the WS native-session path is untouched (it consults ownership natively). - The gateway test-state builder threads ownership configuration; the three dispositions (unwired refusal, live grant table, declared static fallback) are pinned at the HTTP surface by `call_resource_gated_*` regression tests. ### Documented - **Extras door route tables are static (review 008 AH-2).** One doc line on the door-facing surface (`HttpAdapter::with_extra_routes`) and in ADR-046: the merged router already owns the decoy fallback and axum refuses a second, so a door attempting `fallback_layer` panics at construction — enumerate multi-segment namespace shapes (`{user}/{repo}/...`) as pattern routes. Not a mechanism ask; the next door author should not rediscover the panic. ### Fixed - `HttpAdapter::with_ws_max_sessions` never stored the freshly built session-slot semaphore on the adapter — any subsequent builder call rebuilt the router with the pre-cap-change semaphore, silently reverting the cap. Builder state is now assembled in one shared `router_state()` helper, so every `with_*` rebuild sees the current configuration. Pinned by the WS session-cap integration test running with a builder call after `with_ws_max_sessions`, and by an ownership-wiring-survives-rebuild test at the HTTP surface. - Door-surface Basic parsing no longer requires the password field to be UTF-8: the decoded password bytes reach `IdentityProvider::resolve_from_token()` byte-faithfully, so RFC 7617 legacy ISO-8859-1 credentials (e.g. a latin-1 user password) that a provider resolves still authenticate instead of parsing to `None`. Minor bump 0.7.0 → 0.8.0 per the dep-wave convention (0.4.0 rode alkcall 0.7.0, 0.5.0 rode 0.8.0, 0.7.0 rode 0.9.0): the re-exported alkcall types are on this crate's public API, so a semver-moving upstream is semver-relevant here. ## [0.7.0] — 2026-10-14 ### Changed - **`alkcall` dependency bumped to 0.9.0** (the stub-sweep release: the four registered-but-always-failing stubs across nine published versions are replaced with real implementations — the marked-pub open contract (S-01), `channel/control` (S-02), `channel/resources/subscribe` (S-03), and `op/register` forward-through (S-04)). No code change in this crate — none of the 0.9.0 breaking surfaces are constructed or pattern-matched here: no `ManagerError` match arms (the new `InvalidAdopt` variant changes nothing), no `RelayError` matching (the removed `PubTypedOpen` variant is unreachable from this crate), no `Establishment` construction or `Debug` dependence (the WS ferry passes `Option` through unchanged), and the `op/register` forward-through refactor does not touch the `from_wss` import filter or the adapter-registered leaf bundles. The S-01 marked-pub machinery is consumer-side assembly, not an HTTP-surface concern; the four gateway operations and the WS session shape are unchanged. ### Fixed - `tests/ws_overlay_ops.rs` now expects `register_imported`'s new `Result<(), String>` return (alkcall 0.9.0 API change): the eight connection-overlay registration sites assert success instead of discarding the value. Test-only. - `fuzz/shared` follows the main crate to alkcall 0.9 (the harness replay previously resolved alkcall 0.8.1 alongside alkhttp's 0.9.0, two incompatible copies in one build). Infra-only. 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. ## [0.6.0] — 2026-09-29 ### Added - **Fuzzing infrastructure adopted** (the sibling-crate pattern: alkcall, alktty, alktunnels, alksocks). The `fuzz/` subtree holds five nightly targets (`sse_parser`, `ws_chunk_framing`, `spec_import`, `ws_session_opseq`, `retry_throttle`), a stable toolchain shared crate replaying every committed seed (80 + 42 + 16 committed) through the identical invariant functions as plain `cargo test` — the standing fuzz gate, `cargo test --manifest-path fuzz/shared/Cargo.toml` — plus a detached campaign runner and a deterministic seed generator. `fuzz/` is excluded from publish; nightly stays confined to the subtree (MSRV 1.88 unchanged). - **New public API for the tested parse surfaces.** The incremental SSE parser widens `pub(crate)` → `pub` (`SseParser`, `SseEvent`, `SseParseError`, `SSE_EVENT_BUFFER_CAP`, `sse_event_envelope`) and the WS write pump's chunk walk is extracted as public API (`WriteChunkWalk`, `Walk`) — both direct-drive test targets. Five `fuzzing` re-export hubs (`adapters::forward::fuzzing`, `adapters::openapi_spec::fuzzing`, `adapters::input_validation::fuzzing` with the opaque `FuzzCompiledValidator`, `adapters::from_mcp::fuzzing` (\`mcp\`), `client::fuzzing` + `websocket::byte_adapter::fuzzing` with the mock-socket pump drive) gather the harness access surface at one named path each; the underlying crate-internal items keep their visibility. ### Fixed - **SSE dribble drain was quadratic in the dribbled bytes (FWD-20).** `SseParser::feed` re-walked the whole reassembly buffer per feed, so a subscription drip-feeding one giant unterminated line paid O(n²) (64 KiB ≈ 12.5 s CPU per connection; 1 MiB ran to minutes) with no per-stream total-CPU bound. Line assembly now walks only the arriving chunk — the reassembly buffer holds just the current line — measured linear (1 MiB dribble: 21 ms). Regression test: `sse_parser_dribble_feeds_do_not_rescan_the_buffer`. - **`WriteChunkWalk` failure arms discarded the already-drained pieces (FWD-21).** One feed that drained complete chunks and then hit an oversize header (or the pending cap) returned `Walk::Oversize`/`PendingOverCap` empty, dropping bytes the mux had already counted as written (the walk's consumption-accounting contract was violated; production could not reach the shape, but `WriteChunkWalk` is public API and the silent drop broke it). The failure variants now carry the pre-failure pieces (`Vec>`) and the write pump emits them before failing the stream (1011 close). Regression seeds cover the drain-then-fail shape in both chunk harnesses. - **FWD-22 (harness-assert fix):** the fuzz harness's SSE re-frame round-trip probe is now total over anything JSON-encodable (`frame_event` emits a guard CR as the line terminator; the terminal-CR skip is dropped). No crate change. ### Changed - **`alkcall` dependency consumed at 0.8.1** (patch pickup): the duplicate adopt/open collision fix found by alkcall's `manager_routing` fuzz campaign — a duplicate adopt/open no longer replaces the live channel's state. This crate reaches the fixed paths via the shared `ChannelManager`; no alkcall API surface used here changed. ### Changed - **`alkcall` dependency bumped to 0.8.0** (review 008's remediation wave: the graduation upstream asks + the in-tree channel relay). No code change in this crate — alkcall 0.8.0 is additive on the call-plane JSON and the registry seams, and none of its new surfaces are constructed here: this crate builds no `Establishment` reply fields (the WS ferry passes `Option` through unchanged; reply-field projection is an establisher-supplier feature), imports no marked specs through `from_call` (the `from_wss` operation filter excludes the protocol-session ops; any domain op the remote serves imports as a forwarding bundle exactly as before), and consumes neither `ChannelRelay` nor `HubLegImports`/`HubLegTemplate` (hub-leg assembly remains the consumer's concern at the assembly layer). One ride-through visible on this crate's discovery surface: for a deployment's `with_ws_openable_alpns` open-op specs whose names are not standard `channels//(sub|pub)` shapes, the served `services/list` / `services/schema` output now carries an explicit `channel_open_alpn` string alongside the boolean marker (alkcall 0.8.0's U-1, ADR-047 amendment 3) — so hubs relaying through a `from_call` import of those ops reconstruct the marker instead of seeing plain forwarding stubs. Standard-shape open-op names stay byte-stable. Minor bump per the dep-wave convention (0.3.0 rode alkcall 0.6.0; 0.4.0 rode 0.7.0). ## [0.4.1] — 2026-09-10 ### Changed - **`rust-version` floor raised 1.85 → 1.88** (patch bump, no API change). 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, so 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; recorded for alktls in OQ-TLS-08) and breaks no downstream that could build the crate before. Verified: 1.88 toolchain `cargo test --locked` + clippy `--all-targets -D warnings` clean; one 1.88 clippy lint fixed (`uninlined_format_args` in a `forward.rs` test). - **`alkcall` dependency consumed at 0.7.1** (lockfile bump; the `version = "0.7"` requirement already covered it). No code change forced — alkcall 0.7.1's changes are its own MSRV-floor raise plus the cf-006/cf-007 feature work already consumed in the 0.7.0 wave. ## [0.4.0] — 2026-09-07 ### Changed - **`alkcall` dependency bumped to 0.7.0** (CF-005/006/007 — the connect-side caller-identity seam + the downstream-findings sweep). No code change in this crate: it constructs no `ServingConfig` (the one struct-literal break — `from_wss` keeps the pure-consumer `ChannelClient::from_connection`; opt-in serving remains the review-006 Part C deferred decision) and the per-call opener-identity overlay (CF-006) is behavior-only upstream — hub-forwarded opens on the WS ferry now resolve the end client's identity instead of the hub's, the intended effect. alkcall 0.7.0's ADR-016 amendment (the protocol-code list is eight codes) resolves the upstream half of review-006 Part C's doc-drift note. ### Changed (wire-surface behavior) - **Gateway error table maps `CONNECTION_CLOSED` → 503 Service Unavailable** (the alkcall 0.7.0 CF-007 amendment makes it the eighth protocol code; ADR-023 amended). Previously it fell to the catch-all 500, which misreported a retryable, provably-undelivered call as a permanent server failure. Reachable through the gateway when an imported op's forwarding handler calls into a dropped transport (`from_wss`'s pending-call fail-all is retryable `CONNECTION_CLOSED`). The code is `retryable: true`, so the existing `retry_after` details path applies on 503. Tests pin the mapping and the `Retry-After` passthrough. Behavioral break for HTTP callers matching on the 500 previously emitted for this code — hence a minor bump, not a patch. ## [0.3.0] — 2026-09-07 ### Changed - **`alkcall` dependency bumped to 0.6.0** (review 007's establishment follow-ups sweep). One consumer-visible change: the `OpenHandler` signature gained a plan parameter — `Fn(Value, Option, Connection, AuthContext) -> JoinHandle<()>` — so `OpenableAlpn::new` callers' handler closures gain a `_plan` argument (mechanical). With an establisher attached (ADR-049), its `Establishment.plan` (a typed-opaque `Arc`) is threaded process-locally to the handler's plan parameter: ALPN crates dial/allocate in the establisher and deliver the live handle without a side-channel handoff. This crate's WS ferry passes the `Option` through unchanged and constructs no `Establishment` itself, so the ride is otherwise additive — alkcall 0.6.0's `channels::pump_bidi` helper (ADR-050) is available to data-plane handlers this crate ferries. Docs updated (websocket.md, `OpenableAlpn` field docs, adapter.rs). ## [0.2.0] — 2026-09-06 ### Changed - **`alkcall` dependency bumped to 0.2** with the `gateway` feature enabled. The transport-neutral dispatch spine now comes from `alkcall::gateway` (promoted from this crate per alkcall ADR-048): `GatewayDispatch`, `schema_disclosure_denial`, and `DEFAULT_DEADLINE` are re-exported from `alkhttp::gateway`; the local copy (`gateway/dispatch.rs`) was deleted. The spine is used with the 30 s default deadline (identical behavior to the local version). alkcall 0.2 also carries the consumer-findings fixes CF-001..004 documented in `alkcall/docs/reviews/consumer-findings-ledger.md`. - **`alkcall` dependency bumped to 0.4.1** (through 0.3, 0.4.0): - 0.3 — per-session fork, serving loop, and `op/register` (the WS op/register ACL surface in this crate builds on it); 0.3.1 — `PeerCompositeEnv::peer_operations` so `list-peers` sees peer-announced ops (UP-03). - 0.4.0 — the registry enforces `input_schema` at call time (ADR-016 `INVALID_INPUT` leg); adapters no longer need to validate before dispatch. - 0.4.1 — early-arrival chunks are parked for un-adopted channels, closing the open/first-data race on the WS overlay. - 0.5.0 — the channels establisher phase (ADR-049): `OpenableAlpn` gains `establisher: Option` and `establisher_timeout: Option` (both default `None` via `OpenableAlpn::new`, so existing constructions compile unchanged) plus a `with_establisher(establisher, timeout)` builder; the WS ferry calls `register_openable_with_establisher`, threading both fields through. With an establisher attached, the open op awaits the bounded establishment phase before the reply and resolves `channel:open_failed` with `details.reason` on failure — the channel never exists consumer-side. Without one, behavior is the pre-0.5 shape. The alkcall 0.5.0 `open_channel` error-type change needs no alkhttp change (this crate never calls `open_channel`; `from_wss` uses `ChannelClient::from_connection` only). - **`/publish` chunk validation uses the registry-owned validator** (CF-003). The local compile-once `PublishSchemaCache` (`gateway/schema_cache.rs`) is removed — `publish_schema` is compiled at **registration time** by alkcall and exposed as `OperationRegistry::publish_validator`; an un-compilable schema is now a registration error, so the fail-open window this cache closed GW-side cannot exist upstream either. The `/publish` chunk stream resolves against the registry's cached validator. - The from_wss drop monitor and the WS overlay tests use `CallError::connection_closed` (CF-001), and the review-001-ws-eof-signal race tests now assert retryable `CONNECTION_CLOSED` on **both** resolution paths (the drop monitor and the undelivered-request write failure) — the previously tolerated non-retryable `INTERNAL: failed to write request frame` outcome on the race path is gone. ### Notes - **CF-004 convergence:** the alkhttp-local `services/schema` defense-in-depth guard remains, but its shared check (`schema_disclosure_denial`) is now alkcall's promoted implementation (ADR-048); the alkhttp-local copy is gone. See ADR-071 for the updated disposition.