Files
alkhttp/CHANGELOG.md
T
glm-5.3-flash dfa0216186 review: post-adoption pass over the alkcall-0.10 wiring pair (0766f4b, ad63507)
Three inline findings from the session review of ADR-072/ADR-073:

- fix(auth): Basic door parsing no longer requires UTF-8 — the decoded
  password bytes pass through to resolve_from_token byte-faithfully, so
  RFC 7617 legacy ISO-8859-1 credentials resolve instead of parsing to
  None. ADR-073 already specced raw-bytes passthrough ("decoded and fed
  as the AuthToken raw bytes"); the String::from_utf8 round-trip
  contradicted it.
- test: pin the with_ws_max_sessions fix against the shape it fixed —
  a builder call after with_ws_max_sessions (the pre-router_state()
  builder silently reverted the cap).
- test: pin that ownership wiring survives a later HttpAdapter builder
  rebuild at the HTTP surface.

Verified: cargo test (451), --all-features (530), clippy --all-targets
-D warnings, fmt --check, fuzz corpus replay 21/21, cargo doc.
2026-10-17 16:25:07 +00:00

17 KiB

Changelog

All notable changes to this crate are documented here. The format is based on Keep a Changelog, and this crate adheres to Semantic Versioning.

[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<OpenEstablisher> 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<Vec<u8>>) 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<OpenEstablisher> 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/<seg>/(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<ChannelPlan>, 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<dyn Any + Send + Sync>) 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<OpenEstablisher> 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<OpenEstablisher> and establisher_timeout: Option<Duration> (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.