Commit Graph

421 Commits

Author SHA1 Message Date
6f05dd8995 feat(http/adapters/from-openapi-sse-streaming): branch from_openapi forwarding on op_type; Subscription → StreamingHandler (SSE → BoxStream<ResponseEnvelope>)
build_registration now branches on op_type: Subscription ops register a
StreamingHandler (HandlerKind::Stream) via make_streaming_handler that
streams SSE response chunks as ResponseEnvelope::ok() items (one per
data: frame); Query/Mutation ops keep the existing Handler
(HandlerKind::Once) via forward(). Closes the gap where a from_openapi-
imported Subscription returned only the last SSE event.

- forward_stream(): non-async fn returning ResponseStream; sends the
  request with Accept: text/event-stream, then streams SSE chunks via
  stream::unfold over response.bytes_stream(), reusing parse_sse_frames
  (multi-event, partial trailing, comments, multi-line data, BOM).
  HTTP error (non-2xx) → single ResponseEnvelope::error(), stream ends;
  SSE stream end → ResponseStream ends (→ call.completed on wire).
- Removed stream_subscription() (the collect-all placeholder that
  truncated to the last event). parse_sse_frames stays (reused).
- Query/Mutation forwarding unchanged (existing forward() path).
- Tests: Subscription registration is HandlerKind::Stream; Query
  registration is HandlerKind::Once; SSE subscription streams multiple
  ResponseEnvelope::ok() (one per data: frame); HTTP error → single
  error envelope; Query forwarding unchanged (single response).
2026-07-02 09:45:55 +00:00
185ddb82b5 docs(call): mark call/registry/streaming-handler-handlerkind completed — StreamingHandler/HandlerKind foundation 2026-07-02 09:29:11 +00:00
9c81129f24 feat(call): introduce StreamingHandler, HandlerKind, ResponseStream + INVALID_OPERATION_TYPE (ADR-049)
Add the foundational types for ADR-049 streaming handlers:
- StreamingHandler, ResponseStream type aliases and HandlerKind enum
  (Once | Stream) in registration.rs, with make_streaming_handler() helper
- CallError::invalid_operation_type() in wire.rs (sixth protocol code,
  retryable: false)
- HandlerRegistration.handler flipped from Handler to HandlerKind;
  HandlerRegistration::new() now takes HandlerKind
- OperationRegistryBuilder absorbs wrapping: with_local/with_leaf/
  with_leaf_provenance wrap raw Handler in HandlerKind::Once for
  Query/Mutation; new with_local_streaming/with_leaf_streaming take a
  StreamingHandler and wrap in HandlerKind::Stream for Subscription.
  Builder validates kind matches spec.op_type (mismatch = startup error)
- OperationRegistry::register() returns Result<(), String> with a clear
  mismatch message; all call sites updated to handle the Result
- invoke() matches on HandlerKind: Once -> existing path; Stream ->
  INVALID_OPERATION_TYPE error envelope (guards against silent
  truncation; invoke_streaming() added in a downstream task)
- OverlayOperationEnv::invoke_with_policy matches on HandlerKind:
  Once -> dispatch; Stream -> INVALID_OPERATION_TYPE (composition is
  request/response-only)
- Migrated every HandlerRegistration::new() construction site (~95)
  to wrap raw Handler in HandlerKind::Once(handler); the builder sites
  are handled by the builder-absorbs-wrapping change
- Updated two websocket subscription tests that relied on Subscription
  ops dispatching via invoke() to expect INVALID_OPERATION_TYPE
- Added unit tests for invoke/register validation and
  make_streaming_handler
2026-07-02 09:28:05 +00:00
07f7607fbb tasks(decomp): ADR-049 streaming handler — 8 atomic tasks + gitignore .worktrees/
Decompose the ADR-049 streaming handler work into 8 dependency-ordered tasks:
- call/registry/streaming-handler-handlerkind (foundation: StreamingHandler,
  HandlerKind, ResponseStream, INVALID_OPERATION_TYPE, migrate all sites)
- call/registry/invoke-streaming (OperationRegistry::invoke_streaming)
- call/protocol/dispatch-streaming-branch (server-side op_type branch)
- call/client/from-call-streaming-forwarding (Subscription → subscribe())
- http/gateway/invoke-streaming (GatewayDispatch::invoke_streaming)
- http/server/subscribe-sse-streaming (/subscribe pipes BoxStream to SSE)
- http/adapters/from-openapi-sse-streaming (SSE → StreamingHandler)
- review-streaming-impl (phase review checkpoint)

Validated with taskgraph: 86 tasks, no cycles. Also ignore .worktrees/ so
agents' worktree workspaces don't leak into git status.
2026-07-02 08:23:27 +00:00
7ecc11610a docs(arch): ADR-049 — streaming handler for subscription operations
The call protocol spec describes streaming (call.responded*N +
call.completed, PendingRequestMap::Subscribe, CallConnection::subscribe),
but the server-side Handler type returned a single ResponseEnvelope —
a Subscription op had no way to produce a stream. The TS predecessor
(@alkdev/operations) had separate OperationHandler / SubscriptionHandler
types; the Rust port collapsed them, losing the streaming path. This
restores it end-to-end: StreamingHandler type, HandlerKind on
HandlerRegistration validated against op_type, invoke_streaming() on
OperationRegistry, server-side dispatch branches on op_type, new
INVALID_OPERATION_TYPE protocol code for wrong-dispatch-path misuse,
GatewayDispatch::invoke_streaming() for /subscribe SSE, from_call stream
forwarding via CallConnection::subscribe(), from_openapi SSE forwarding.
OperationEnv::invoke() stays request/response-only (stream composition is
handler-level, not protocol-level). Amends ADR-023's protocol-code list
(five → six). Tracks the stream-operators library as OQ-41 (feature
extension, not an unmade decision).
2026-07-02 07:43:01 +00:00
139c651eaa docs(http): mark http/review-http-final completed — alknet-http crate review complete
Final crate-wide review passes all 9 checklist areas: crate structure, feature gate
isolation, dependencies, cross-cutting concerns, pattern consistency, ADR conformance
(003-048), absence of deferred/out-of-scope items, test coverage (277+2 alknet-call,
230 default, 265+5 mcp), build cleanliness (fmt/clippy/build all clean).
2026-07-01 23:40:29 +00:00
5a51734291 docs(http): mark http/review-websocket and http/review-http completed 2026-07-01 23:39:40 +00:00
b3ab6ef097 docs(http): mark http/adapters/to-openapi completed + fix formatting
to_openapi gateway projection merged: 5-endpoint OpenAPI doc (ADR-042/045), pure
projection, info.version 1.0.0, error fidelity (ADR-023). 230 tests pass. Clippy clean.
2026-07-01 23:37:35 +00:00
ccaac7e157 Merge feat/http-to-openapi: to_openapi gateway projection (5-endpoint OpenAPI doc, ADR-042/045)
Implements to_openapi(registry) -> OpenAPISpec in src/adapters/to_openapi.rs — pure
projection generating fixed 5-endpoint gateway doc (/search, /schema, /call, /batch,
/subscribe) with info.version = 1.0.0 (ADR-045). /call responses carry protocol-level
errors + operation-level errors mapped by http_status (ADR-023). Per-caller operation
surface NOT preloaded (discovered via /search, ADR-042). /subscribe response is
text/event-stream. Wired GET /openapi.json in adapter.rs. 16 new tests.
2026-07-01 23:36:48 +00:00
18156ac9d2 Merge origin/develop: integrate connection-overlay (resolve adapter.rs test conflict, keep /openapi.json route test) 2026-07-01 20:17:06 +00:00
dd6aacc598 feat(http): complete to_openapi gateway projection with error fidelity and route wiring
Refine to_openapi to project operation-level errors (with http_status)
onto /call and /subscribe responses via oneOf merge with protocol-level
errors, preserving HTTP_<status> prefix codes without collision. Fix
BTreeMap→serde_json::Map for Value::Object compatibility. Wire GET
/openapi.json route test. Apply cargo fmt across the crate.
2026-07-01 20:11:09 +00:00
2695a19502 feat(http): implement to_openapi gateway projection (5-endpoint OpenAPI doc, info.version 1.0.0)
to_openapi(registry) -> OpenAPISpec generates the fixed 5-endpoint
gateway doc (/search, /schema, /call, /batch, /subscribe) — pure
projection (ADR-017 §5), gateway pattern (ADR-042). info.version is
1.0.0 tracking the gateway contract (ADR-045). /call responses carry
protocol-level errors (400/401/403/404/500/504) plus operation-level
errors mapped by http_status (ADR-023). GET /openapi.json wired to
serve the generated spec.
2026-07-01 19:52:57 +00:00
0b0bceec7a docs(http): mark http/websocket/connection-overlay completed 2026-07-01 19:48:36 +00:00
468bd84f86 Merge feat/http-connection-overlay: Connection-local Layer 2 overlay for browser-registered ops
Adds AccessControl::check to OverlayOperationEnv::invoke_with_policy in alknet-call
so hub's calls to browser-registered ops are gated by the browser's AccessControl.
Creates src/websocket/overlay.rs with 19 integration tests: overlay scoping (not
PeerCompositeEnv), no PeerId, register_imported/all, overlay_env() routing,
PeerRef::Specific→NOT_FOUND, AccessControl gating, overlay drop on WS close,
ADR-016 abort cascade, bidirectionality, no-ops use-case scoping.
2026-07-01 19:46:56 +00:00
ad279693ce feat(http): connection-local Layer 2 overlay for browser-registered ops (ADR-024/034/044)
Enforce AccessControl on overlay ops in OverlayOperationEnv::invoke_with_policy
(alknet-call) so the hub's calls to browser-registered ops are gated by the
browser's AccessControl — matching OperationRegistry::invoke semantics for
internal composition (caller identity = parent handler_identity.as_identity()).

Add src/websocket/overlay.rs with 19 integration tests covering the connection-
local overlay acceptance criteria: browser ops land in the per-CallConnection
overlay (not PeerCompositeEnv), no PeerId for the browser, register_imported()/
register_imported_all() populate the overlay, hub outgoing calls route through
overlay_env() (not PeerRef::Specific), PeerRef::Specific('browser-X') routes to
NOT_FOUND, AccessControl gates hub calls (allowed/forbidden/default), overlay is
per-connection isolated and dropped on WS close, WS close aborts in-flight calls
with ADR-016 cascade, bidirectionality, and browser-with-no-ops use-case scoping.
2026-07-01 19:45:36 +00:00
58e16d088b review(http): mark http/review-mcp completed + fix formatting across crate
Review-mcp verification complete: all 12 checklist items pass (from_mcp/to_mcp
conformance, ADR-037/041/014/023/034, feature gate isolation, GatewayDispatch
concrete struct, test coverage 223+5). Applied cargo fmt across crate.
2026-07-01 19:32:42 +00:00
48ead6950b docs(http): mark http/review-mcp completed 2026-07-01 19:31:49 +00:00
643f8727d2 review(http): fix formatting in from_mcp/mod.rs (review-mcp finding) 2026-07-01 19:31:27 +00:00
86752ba242 docs(http): mark http/adapters/to-mcp completed 2026-07-01 19:24:50 +00:00
b127699aad Merge feat/http-to-mcp: to_mcp gateway projection (4-tool gateway, rmcp StreamableHttpService)
Implements src/adapters/to_mcp.rs: ToMcpGateway rmcp ServerHandler with 4 fixed
gateway tools (search/schema/call/batch). search dispatches services/list (ACL-
filtered, excludes Subscriptions), schema dispatches services/schema, call/batch
dispatch via GatewayDispatch::invoke with ResponseEnvelope→CallToolResult mapping.
Bearer auth via shared middleware around nest_service. Identity survives rmcp
framing (research §6 #2 confirmed). Feature-gated behind mcp; stdio NOT built
(ADR-037). Pure projection. 16 unit tests.

# Conflicts:
#	crates/alknet-http/src/server/adapter.rs
2026-07-01 19:24:33 +00:00
974fcde923 docs(http): mark http/server/gateway-endpoints completed 2026-07-01 19:20:21 +00:00
31291bd2d9 Merge feat/http-gateway-endpoints: 5 fixed gateway endpoints (search/schema/call/batch/subscribe)
Implements src/server/gateway_routes.rs: POST /call, GET /search, GET /schema,
POST /batch, POST /subscribe (SSE). All delegate to GatewayDispatch::invoke; auth
via ResolvedIdentity extractor; errors mapped via call_error_to_http_response
(identity-aware 401/403 split). Internal ops → 404. /schema adds ACL pre-check.
/subscribe projects ResponseEnvelope as SSE. /batch loops over invoke. Wired real
handlers into adapter.rs replacing placeholder 501s. 157 tests pass.

Note: /subscribe SSE completes after single event (registry invoke returns single
ResponseEnvelope, no streaming handler yet — research §6 OQ#5).

# Conflicts:
#	crates/alknet-http/src/server/adapter.rs
2026-07-01 19:19:50 +00:00
64696fec97 feat(http): implement to_mcp 4-tool gateway projection (rmcp ServerHandler, StreamableHttpService at /mcp)
to_mcp is the MCP-direction gateway projection (ADR-041): exposes 4 fixed
gateway tools (search, schema, call, batch) over rmcp StreamableHttpService
nested into the axum Router at /mcp, not one MCP tool per registry operation.
The LLM discovers operations on demand via search+schema.

- ToMcpGateway implements rmcp ServerHandler (call_tool, list_tools, get_info)
- tools/list returns the 4 fixed gateway tools, never the registry's ops
- search dispatches services/list via GatewayDispatch::invoke, excludes
  Subscription ops (ADR-041 §2), returns names + descriptions
- schema dispatches services/schema, returns the full OperationSpec
- call dispatches via GatewayDispatch::invoke (shared spine), maps
  ResponseEnvelope -> CallToolResult::structured (Ok) /
  CallToolResult::structured_error (Err(CallError))
- batch loops over invoke, returns an array of results
- Bearer auth via shared bearer_auth_middleware applied around nest_service
  (rmcp simple_auth_streamhttp pattern); Identity read from
  RequestContext.extensions -> http::request::Parts.extensions
  (research §6 #2 identity-survives-framing assumption, confirmed via test)
- to_mcp is a pure projection (consumes registry, produces no entries)
- Feature-gated behind mcp; stdio NOT built (ADR-037)
- /mcp route wired in adapter.rs replacing the placeholder 501

cargo test -p alknet-http --features mcp: 172 passed
cargo clippy -p alknet-http --features mcp --all-targets: clean
cargo check -p alknet-http (no mcp): clean
2026-07-01 19:18:19 +00:00
5a629a48e5 feat(http): implement 5 gateway endpoints (search/schema/call/batch/subscribe)
Implement the sole HTTP invoke path (ADR-042/047) in
src/server/gateway_routes.rs: POST /call reads { operation, input },
resolves identity via the shared ResolvedIdentity extractor, dispatches
via GatewayDispatch::invoke, and returns ResponseEnvelope as JSON with
errors mapped via call_error_to_http_response. GET /search dispatches
services/list (AccessControl-filtered); GET /schema dispatches
services/schema with an ACL pre-check (unauthorized -> 403). POST /batch
loops over invoke returning an array; POST /subscribe projects the
response as SSE (text/event-stream) with data frames for call.responded
and an error event for call.aborted. Internal ops return 404. Wire the
real handlers into adapter.rs router, replacing the placeholder 501s.
2026-07-01 19:17:59 +00:00
f0710f8a04 docs(http): mark http/websocket/upgrade-handler completed 2026-07-01 19:16:37 +00:00
4306a046fe Merge feat/http-upgrade-handler: WebSocket upgrade handler (native EventEnvelope session, no length prefix)
Implements src/websocket/upgrade.rs: WS upgrade at /alknet/call using axum
WebSocketUpgrade, bearer auth (no token → 401), CallConnection::new_overlay_only,
native EventEnvelope over binary WS messages (no length prefix, text → close 1002),
Dispatcher::dispatch_requested for call.requested (AccessControl gates), handle_abort
for call.aborted, PendingRequestMap correlation, fail_all_pending on disconnect
(ADR-016 cascade), bidirectionality via connection-local overlay. Wired /alknet/call
route into adapter.rs. 168 tests pass.
2026-07-01 19:15:46 +00:00
384ad03619 feat(http): implement WebSocket upgrade handler (native EventEnvelope session, no length prefix, bearer auth) 2026-07-01 19:15:11 +00:00
539a812c12 docs(http): mark http/server/bearer-auth-middleware completed 2026-07-01 18:52:06 +00:00
ccbff3c7f8 Merge feat/http-bearer-auth-middleware: Shared Bearer auth middleware
Implements src/server/auth.rs: bearer_auth_middleware (from_fn_with_state over
Arc<dyn IdentityProvider>, stashes Option<Identity> in request extensions),
extract_bearer_identity (Bearer-only: no/malformed/Basic/unresolvable → None,
not an error), ResolvedIdentity axum extractor. Wired into HttpAdapter router
via route_layer around gateway/openapi/mcp routes, excluding /healthz. 11 tests.

# Conflicts:
#	crates/alknet-http/Cargo.toml
#	crates/alknet-http/src/server/adapter.rs
#	crates/alknet-http/src/server/mod.rs
2026-07-01 18:51:29 +00:00
36f74dd31b feat(http): implement shared Bearer auth middleware (resolve_from_token, stash Identity in request extensions)
Add src/server/auth.rs with bearer_auth_middleware axum layer that
extracts the Authorization: Bearer header, resolves via
IdentityProvider::resolve_from_token, and stashes Option<Identity> in
request extensions. Shared by HTTP gateway routes and the to_mcp rmcp
service (research §4.4). No token, malformed header, or failed
resolution all yield None (unauthenticated, not an error) — Bearer-only
auth mechanism (ADR-004).

Includes ResolvedIdentity axum extractor reading from extensions, and
wires the middleware into the HttpAdapter router around the
gateway/openapi/mcp routes (excluding the raw /healthz route).
2026-07-01 18:48:00 +00:00
35a7a37ba6 docs(http): mark http/server/healthz-decoy completed 2026-07-01 18:41:14 +00:00
78344d9280 Merge feat/http-healthz-decoy: /healthz raw route + stealth decoy fallback
Implements GET /healthz (src/server/healthz.rs, 200 OK text/plain 'ok', no auth,
no OperationContext) and stealth decoy fallback (src/server/decoy.rs: DecoyConfig
NotFound=nginx 404 / StaticSite=serve files / Redirect). Wired real handlers into
HttpAdapter router replacing placeholder 501s. 125 tests pass.
2026-07-01 18:40:35 +00:00
3702da1aee feat(http): implement /healthz raw route and stealth decoy fallback
GET /healthz: raw route, no auth, no OperationContext, returns 200 OK
with plain-text 'ok' (ADR-036). Decoy fallback for unknown paths via
DecoyConfig: fake nginx 404 (default), static site serving, or redirect.
Decoy does not leak alknet presence (no alknet headers/format). Custom
routes take precedence over decoy (decoy is fallback only). Wire real
handlers into HttpAdapter router replacing placeholder 501s.
2026-07-01 18:40:01 +00:00
a65afb0dfb docs(http): mark http/adapters/from-mcp completed 2026-07-01 18:24:14 +00:00
3eb2a51184 Merge feat/http-from-mcp: from_mcp adapter (rmcp streamable HTTP, tools/list, structuredContent handling)
Implements FromMCP (feature-gated behind mcp) in src/adapters/from_mcp/: rmcp
StreamableHttpClientTransport connects to MCP endpoint, calls tools/list, builds
HandlerRegistration bundles (provenance FromMCP, leaf, Internal, Mutation,
capabilities=bearer token). Forwarding handler calls client.call_tool, maps
CallToolResult per structuredContent-preferred-over-content-blocks rule (declared
outputSchema → structuredContent; absent → ContentBlock union; no heuristic
JSON.parse; isError→CallError). No-env-vars (reads context.capabilities).
Streamable HTTP only (ADR-037). 19 unit + 5 integration tests.

# Conflicts:
#	crates/alknet-http/src/adapters/mod.rs
2026-07-01 18:22:32 +00:00
c9e5ea1c75 feat(http): implement from_mcp adapter (rmcp streamable HTTP client, tools/list discovery, structuredContent handling)
FromMCP (OperationAdapter, feature-gated behind mcp) discovers remote MCP
tools over streamable HTTP via rmcp's StreamableHttpClientTransport, calls
tools/list, and registers each as a HandlerRegistration bundle with a
forwarding handler that calls the remote tool via tools/call. Output
handling follows the structuredContent-preferred-over-content-blocks rule:
declared outputSchema + structuredContent is the composable result; absent
outputSchema falls back to the MCP ContentBlock union. isError:true maps to
a CallError with the error content. No-env-vars invariant: the handler reads
context.capabilities (injected at registration), never std::env::var (ADR-014).
Streamable HTTP only — stdio is not built (ADR-037). Provenance is FromMCP
(leaf: composition_authority None, scoped_env None, Internal by default,
ADR-015/022). Includes unit tests for schema/mapping logic and an integration
test that spins up a real rmcp streamable HTTP server and exercises the
forwarding handler end-to-end.
2026-07-01 18:21:45 +00:00
4905c06f4b docs(http): mark http/adapters/from-openapi completed 2026-07-01 18:20:23 +00:00
ad8d7879ae Merge feat/http-from-openapi: from_openapi adapter (OpenAPI parser, reqwest forwarding, no-env-vars)
Implements FromOpenAPI in src/adapters/from_openapi.rs: OpenAPISpec/HttpServiceConfig/
HttpAuthScheme types, $ref resolution, OperationAdapter::import() producing
HandlerRegistration bundles (Internal visibility, FromOpenAPI provenance,
HTTP_<status> error codes per ADR-023). Reqwest forwarding handlers read credentials
from OperationContext.capabilities (no-env-vars ADR-014) via SharedHttpClient.
JSON/text/binary response branching, SSE subscription streaming, Bearer/ApiKey/Basic
auth injection. 98 tests pass.
2026-07-01 18:19:44 +00:00
6b30e2ac15 feat(http): implement from_openapi adapter (OpenAPI parse + reqwest forwarding handlers)
Parses OpenAPI 3.x documents into HandlerRegistration bundles with
reqwest-backed forwarding handlers that inject credentials from
OperationContext.capabilities (no-env-vars invariant, ADR-014).
Error codes are prefixed HTTP_<status> (ADR-023); ops are Internal
leaves with FromOpenAPI provenance (ADR-015/022). SSE subscriptions
are consumed via parseSSEFrames; JSON/text/binary response branching
mirrors the TS prior art.
2026-07-01 18:18:28 +00:00
6b96852e4e docs(http): mark http/server/http-adapter completed 2026-07-01 18:09:57 +00:00
1fea747305 Merge feat/http-http-adapter: HttpAdapter (ProtocolHandler for h2/http1.1) — axum over QUIC
Implements HttpAdapter in src/server/adapter.rs: axum-over-QUIC bridge via
hyper-util auto Builder, DecoyConfig (NotFound/StaticSite/Redirect),
with_extra_routes merge (ADR-046), router state holds Arc<OperationRegistry> +
Arc<dyn IdentityProvider>, placeholder 501 handlers for gateway endpoints/
healthz/openapi.json/MCP. h3 ALPN not registered (ADR-044). 78 tests pass.
2026-07-01 18:08:50 +00:00
b313dcbf20 feat(http): implement HttpAdapter (ProtocolHandler for h2/http1.1, axum over QUIC)
Wires the axum Router (gateway endpoints + /healthz + /openapi.json + MCP +
custom routes via extra_routes merge ADR-046) and drives hyper's HTTP/1.1 or
HTTP/2 connection driver over a single QUIC bidirectional stream. The
QUIC-to-hyper bridge wraps the (SendStream, RecvStream) pair as a
TokioIo-compatible duplex and feeds it to hyper-util's auto Builder (which
auto-detects HTTP/1.1 vs HTTP/2). h3 ALPN is not registered (ADR-044).

Route handlers, healthz/decoy logic, openapi.json, the MCP route, and the WS
upgrade handler are wired as 501 Not Implemented placeholders for their
respective tasks. The router state holds Arc<OperationRegistry> +
Arc<dyn IdentityProvider>; the router is built once at construction and
cloned per connection (cheap Arc clone). DecoyConfig defaults to NotFound.

Adds hyper-util dependency (server, service, tokio features).
2026-07-01 18:07:56 +00:00
9df9900bb9 docs(http): mark http/client/shared-http-client completed 2026-07-01 17:23:42 +00:00
ea38f81c12 Merge feat/http-shared-http-client: Shared HTTP client with retry + Retry-After middleware
Implements SharedHttpClient (ArcSwap<ClientWithMiddleware>) with HttpClientConfig
(pool/timeout/retry/optional CA bundle+client cert), RetryTransientMiddleware from
reqwest-retry, and inlined RetryAfterMiddleware (~90 lines, bounded HashMap with LRU
eviction, parses Retry-After seconds + HTTP-date, sleeps on 429/503). reload() via
ArcSwap. No env-var reads; per-request credential injection only. 24 unit tests.
2026-07-01 17:21:55 +00:00
081fc911ef feat(http): implement shared HTTP client (ClientWithMiddleware + retry + Retry-After, OQ-40)
Adds SharedHttpClient wrapping ArcSwap<ClientWithMiddleware> with a
RetryTransientMiddleware + inlined RetryAfterMiddleware stack.
HttpClientConfig covers pool, timeout, retry policy, and optional CA
bundle/client cert. reload() rebuilds and swaps via ArcSwap. No env-var
reads; credential injection is per-request, not at construction.
2026-07-01 17:20:49 +00:00
0da76d4dd5 docs(http): mark http/websocket/dispatcher-transport-abstraction completed 2026-07-01 17:19:44 +00:00
9512e61e73 Merge feat/http-dispatcher-transport-abstraction: Expose EventEnvelope-level dispatch API for non-QUIC transports
Cross-crate change (alknet-call): expose Dispatcher::dispatch_requested as pub,
extract abort-cascade handling into pub handle_abort method, add
CallConnection::new_overlay_only(identity) constructor (Option A) for non-QUIC
transports. Existing QUIC path (CallAdapter, CallClient, run_loop, handle_stream)
unchanged. 13 unit tests in alknet-call + 6 integration tests in alknet-http.
2026-07-01 17:17:54 +00:00
ef53a03589 feat(call,http): expose EventEnvelope-level dispatch API for non-QUIC transports
Make Dispatcher::dispatch_requested pub and extract abort-cascade handling
into a pub handle_abort method so the WebSocket handler can feed deserialized
EventEnvelopes directly to the shared Dispatcher without a QUIC Connection.

CallConnection gains a new_overlay_only(identity) constructor (Option A) that
holds the Layer 2 overlay, PendingRequestMap, and resolved bearer Identity
without a QUIC Connection; identity() reads the stored field for the non-QUIC
case. compose_root_env uses the new identity() accessor for both paths.

The existing QUIC path (CallAdapter, CallClient, run_loop, handle_stream) is
unchanged — outgoing client methods guard on connection().is_none().
2026-07-01 17:17:02 +00:00
8b8b8e8234 docs(http): mark http/gateway/error-mapping completed 2026-07-01 17:10:44 +00:00
81781d89fa Merge feat/http-error-mapping: CallError-to-HTTP status error mapping (ADR-023)
Implements call_error_to_http_status, call_error_to_http_status_with_identity,
and call_error_to_http_response in src/gateway/error.rs. Five protocol codes
map to fixed statuses (404/422/504/500 + 401/403 split for FORBIDDEN).
HTTP_<status>-prefixed operation-level codes parse status from prefix. Unknown
operation-level codes default to 500. Retry-After header for retryable 503/429.
21 unit tests.

# Conflicts:
#	crates/alknet-http/src/gateway/mod.rs
2026-07-01 17:09:25 +00:00