Commit Graph

403 Commits

Author SHA1 Message Date
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
9c959cd863 docs(http): mark http/gateway/gateway-dispatch-spine completed 2026-07-01 17:07:53 +00:00
33fecd5470 feat(http): implement CallError-to-HTTP error mapping (ADR-023)
Add gateway/error.rs with call_error_to_http_status,
call_error_to_http_status_with_identity, and call_error_to_http_response.
Maps the five protocol codes (NOT_FOUND/FORBIDDEN/INVALID_INPUT/TIMEOUT/
INTERNAL) to fixed HTTP statuses, splits FORBIDDEN into 401 (no identity) /
403 (identity present), maps HTTP_<status>-prefixed operation-level codes
to the status number (from_openapi fidelity), and defaults unknown
operation-level codes to 500. Retryable 503/429 errors carry a Retry-After
header when details.retry_after is present.
2026-07-01 17:06:49 +00:00
117085de4e Merge feat/http-gateway-dispatch-spine: GatewayDispatch shared dispatch spine
Concrete struct (not a trait) holding Arc<OperationRegistry> + Arc<dyn IdentityProvider>
with resolve_bearer() and invoke() returning ResponseEnvelope. Builds root
OperationContext for wire-ingress (internal:false, forwarded_for:None, fresh
request_id, 30s deadline). 14 unit tests covering dispatch, AccessControl
filtering, NOT_FOUND for unregistered/Internal ops, FORBIDDEN for unauthorized.
2026-07-01 17:06:22 +00:00
a4ce2c8173 feat(http): implement GatewayDispatch shared dispatch spine
Thin concrete struct (not a trait) holding Arc<OperationRegistry> +
Arc<dyn IdentityProvider>. Exposes resolve_bearer() (delegates to
identity_provider.resolve_from_token) and invoke() which builds a root
OperationContext for wire-ingress (internal: false, forwarded_for: None,
fresh UUID v4 request_id, deadline now+30s) carrying the registration
bundle's composition_authority/capabilities/scoped_env, then calls
OperationRegistry::invoke. Dispatches services/list and services/schema
unchanged (registered ops); AccessControl filtering in services/list
sees the caller's resolved identity. Re-exported from lib.rs.

Duplicates Dispatcher::build_root_context construction (the alknet-call
version is pub(crate) and tangled with CallConnection peer/session
overlays); the invariants (internal: false, forwarded_for: None) are
the load-bearing part and identical to the wire-ingress path.
2026-07-01 17:05:10 +00:00
1900c72deb docs(http): mark http/crate-init completed 2026-07-01 16:44:57 +00:00
87bfaf159a Merge feat/http/crate-init: Initialize alknet-http crate (ADR-039)
Adds crates/alknet-http with Cargo.toml, src/lib.rs, and five subsystem
module skeletons (server, gateway, client, adapters, websocket). Workspace
members list updated. Dependencies: alknet-core, alknet-call (workspace path),
axum, hyper, reqwest stack, openapiv3; rmcp optional behind mcp feature
(streamable HTTP only, ADR-037). h3/WebTransport absent (ADR-044).
2026-07-01 16:42:38 +00:00
c2e6ba5b96 feat(http): initialize alknet-http crate with module skeleton
Add crates/alknet-http with Cargo.toml, src/lib.rs, and the five
subsystem modules (server, gateway, client, adapters, websocket) per
ADR-039 (server + client host colocated). The mcp feature gate pulls in
rmcp with streamable HTTP transport features only (ADR-037 — no stdio);
h3/WebTransport is absent (deferred per ADR-044). alknet-core and
alknet-call use workspace path deps. The crate is added to the workspace
members list.
2026-07-01 16:41:14 +00:00
e855c8c7eb docs(http): decompose alknet-http spec into 19 implementation tasks
Break the alknet-http architecture spec into atomic, dependency-ordered
tasks in tasks/http/, following the taskgraph frontmatter conventions
used by the call/core/vault crates.

Tasks span 7 phases across 5 module subdirectories (server/, gateway/,
client/, adapters/, websocket/):
- Phase 0: crate-init (foundation)
- Phase 1: gateway-dispatch-spine, error-mapping, shared-http-client
  (shared infrastructure)
- Phase 2: http-adapter, bearer-auth-middleware, gateway-endpoints,
  healthz-decoy (HTTP server surface)
- Phase 3: to-openapi (OpenAPI gateway projection)
- Phase 4: from-openapi (OpenAPI adapter, reqwest forwarding)
- Phase 5: dispatcher-transport-abstraction, upgrade-handler,
  connection-overlay (WebSocket browser bidirectional path)
- Phase 6: from-mcp, to-mcp (MCP adapters, feature-gated)
- Phase 7: review-http, review-websocket, review-mcp, review-http-final
  (quality checkpoints)

The gateway-dispatch-spine task implements the thin shared core
recommended by the gateway-factoring research (concrete struct, not a
trait). The dispatcher-transport-abstraction task is a cross-crate
change to alknet-call (exposes EventEnvelope-level dispatch API for
non-QUIC transports) — the highest-risk task. WebTransport/h3 is
deferred per ADR-044 and has no tasks; from_wss is out of scope.

Validated: 19 tasks, no cycles, 8 parallel generations, critical path
length 8 (through the WebSocket strand).
2026-07-01 07:11:17 +00:00
e0c6f61e6a docs(http): pre-decomposition sanity check fixes — /subscribe POST, direct-call cleanup, from_mcp output handling
Three issues found in the http crate spec sanity check that would have
caused problems during task decomposition, now fixed:

C1 — /subscribe GET→POST: the gateway's /subscribe is an invoke endpoint
carrying { operation, input } in the body, but was listed as GET (which
has no body). Flipped to POST with Accept: text/event-stream negotiating
the SSE response, consistent with /call's flat-JSON-body invariant.
Browsers using EventSource can't POST but use WebSocket for the
bidirectional path; the HTTP gateway's /subscribe is for non-browser
HTTP clients (fetch + ReadableStream). Touches ADR-042, ADR-047,
ADR-048, http-adapters.md, http-server.md.

C2 — stale direct-call references: three spots contradicted ADR-047
(which removed the POST /{service}/{op} direct-call surface) and
ADR-046 §3 (which states /{service}/{op} is no longer reserved).
Cleaned up in http-server.md (custom-routes intro + collision list) and
ADR-046 §6 (default-surface list).

W2 — from_mcp output handling: the spec's fallback for tools without
outputSchema was Type.Unknown(), but the correct fallback is the MCP
ContentBlock union (text|image|audio|resource|resource_link) — a
well-defined MCP type, not Unknown. Fixed http-mcp.md with the full
structuredContent-preferred-over-content-blocks logic (matching the TS
adapter and rmcp SDK), enriched references with specific rmcp source
files. Also added shared-dispatch-spine notes to http-mcp.md and
http-adapters.md cross-referencing the new research findings.

Research (docs/research/alknet-http-gateway-factoring/findings.md):
to_mcp and to_openapi share a dispatch spine (resolve → invoke → map).
Recommendation: extract a thin shared struct now, not a GatewayDispatch
trait — the server-integration layers (axum routes vs rmcp
StreamableHttpService) and wire-framing stay per-gateway. A third
gateway is not on the horizon; if one appears its server-integration
needs its own shape anyway.

Minor: WS route precedence note (websocket.md), OpenAPISpec
shared-type-not-shape clarification (http-adapters.md), date bumps.
2026-07-01 05:41:07 +00:00
3edc42e3b4 docs(compute): add wonnx + handlebars/wgpu reference implementations
Document the two codebases that inform the ShaderGenerator's op table
and the wgpu+handlebars+remote-GPU patterns:

- wonnx (MIT/Apache-2.0, archived): comprehensive ONNX op set in
  Tera-templated WGSL at wonnx/templates/ — arithmetic, activation,
  gemm, conv, batchnorm, softmax, etc. Port the shader implementations,
  swap Tera for handlebars. compiler.rs's add_raw_template +
  include_str! pattern maps 1:1 to handlebars-rs register_template_string.

- Handlebars + wgpu + remote-GPU patterns (private reference, patterns
  reusable): validates the handlebars-rs side and the vast.ai deployment
  shape. Patterns carried over: {{> partial}} includes for shared
  fragments, inline-able constant tables via switch statements (SHA-256
  k-values, universal across wgpu versions), default-valued template
  parameters, wgpu-on-remote-GPU sync. sha256 as a base shader
  demonstrating non-ML compute on the same dispatch surface.

Updated the WGSL codegen probe POC to reference wonnx's op set as the
porting source.
2026-06-30 13:05:54 +00:00
303b9a58e2 docs(research): split alknet-tensor into alknet-runtime + alknet-compute + alknet-tensor
Extract the shared JS+wgpu substrate (verified by the alknet-desktop POCs)
as alknet-runtime — the generalized QuickJS-NG + wgpu runtime that both
alknet-desktop (render) and alknet-compute (tensor compute) build on. Key
property driving the split: wgpu on llvmpipe is genuinely useful compute
with no physical GPU (WGSL → optimized SIMD beats JS for non-trivial
workloads), so wgpu is unconditional in the runtime rather than a feature
flag.

Reframes the original alknet-tensor architecture-summary as alknet-compute
(builds on alknet-runtime + alknet-tensor) with ShaderGenerator as a trait
(WGSL first impl, SPIR-V/GLSL/naga-IR later per wgpu multi-input-language
support). alknet-tensor/metatensor-format.md is now clearly the pure binary
format crate (no JS or wgpu dep), usable standalone by a pure-Rust model
server.

Layering: alknet-runtime depends on alknet-call (registry authority stays
per ADR-013); alknet-compute and alknet-desktop depend on alknet-runtime;
alknet-tensor is a pure-format sibling.
2026-06-30 12:44:39 +00:00
b71db99753 docs(http): add ADR-048 and websocket.md — WS carries native session, not gateway
Promote the WebSocket browser path from a section in http-server.md to a
first-class spec (websocket.md) and commit the contract-pattern decision
(ADR-048): a WS connection carries the native EventEnvelope call-protocol
session, not the HTTP gateway shape. The gateway endpoints are HTTP-only;
discovery on WS is via services/list/services/schema as ordinary call-protocol
ops; subscriptions project as native call.responded events (no SSE).

ADR-044 already decided WS as the v1 browser bidirectional path; ADR-048
clarifies the shape of what ADR-044 committed (§1 implies native session;
the ADR makes it an explicit implementer-visible rule). The from_wss adapter
(importing a remote node's ops over WS) is recorded as out-of-scope with a
concrete reversal trigger so it is not re-derived later.

Spec cleanup: http-server.md WS section collapsed to a stub pointer;
websocket.md Why section references ADRs rather than re-arguing them;
length-prefix decision made canonical (no prefix on WS — message boundary
is the delimiter); default upgrade path pinned (/alknet/call) with HTTP/2
extended CONNECT noted; indexes (README, http/README, overview) updated.
2026-06-30 12:27:00 +00:00
bfd1621b9b feat(call): add ScopedPeerEnv peer-pinned reachability (ADR-029 §4, call/scoped-peer-env) 2026-06-30 11:07:41 +00:00
5c4feff468 tasks: add call/scoped-peer-env — ScopedPeerEnv peer-pinned reachability (ADR-029 §4) 2026-06-30 10:31:19 +00:00
850ac6b7bc fix(call): remove dead test helper and unused mut (clippy -D warnings clean) 2026-06-30 10:30:52 +00:00
2a6e4c371a docs(http): resolve OQ-39; add ADRs 045-047; record pubsub prior art for WS path
OQ-39 (to_openapi published-spec versioning) resolved by ADR-045:
info.version semver tracks the gateway endpoint contract, not the
operation set — per-caller operations discovered via /search do not
bump the version. The gateway pattern (ADR-042) dissolved most of the
original churn concern.

ADR-046: assembly-layer custom HTTP routes on HttpAdapter. The HTTP
router had no documented extension point for deployment-specific
endpoints (e.g., an OAI-compatible proxy at /v1/chat/completions). Adds
extra_routes: Option<Router> at construction; raw HTTP, not operations;
default surface takes precedence on collision. The mechanism is the
one-way door; specific routes are two-way.

ADR-047: remove the direct-call POST /{service}/{op} HTTP surface. The
gateway /call is the sole invoke path — the simplified contract is a
few fixed endpoints, not a per-operation REST tree. The direct-call
surface re-introduced the 'dump the full API regardless of privs'
failure mode at the HTTP level that the gateway /search was built to
escape. ADR-036's routing decision is superseded; its non-routing
clauses (SSE, Bearer auth, /healthz, stealth, error mapping) survive.
A deployment wanting a REST-like per-operation surface builds it as a
custom route projection (ADR-046).

ADR-044 updated with the tradeoff framing (WSS is the right tool for
the call-protocol-from-browser case; WebTransport is the right tool for
the generalized ALPN-stream-proxy case we don't have yet — coexist, not
migrate) and the @alkdev/pubsub concrete prior art (the EventEnvelope
{type,id,payload} the call protocol was derived from already has a
working WebSocket client/server; the sync is a small adjustment, not a
from-scratch build).

call-protocol.md references the pubsub lineage for the
transport-agnosticism claim.
2026-06-30 09:49:25 +00:00
3327d585da docs(http): resolve OQ-40 reqwest client config — ClientWithMiddleware + retry/retry-after middleware stack
OQ-40 resolved: alknet-http owns a shared reqwest_middleware::ClientWithMiddleware
(not a bare reqwest::Client) with a two-layer middleware stack —
RetryTransientMiddleware (reqwest-retry, exponential backoff on transient
failures) + inlined RetryAfterMiddleware (from melotic/reqwest-retry-after, MIT,
~50 lines, inlined to bound the upstream's unbounded HashMap storage). The two
are complementary: reqwest-retry's default strategy does not honor Retry-After.

Hot-reload is rebuild-and-swap via ArcSwap (same pattern as
ConfigIdentityProvider, ADR-035); a rebuild drops the connection pool, which
is acceptable since a config change wanting a fresh pool is the trigger. The
three one-way constraints stand unchanged: alknet-http owns its client (no
env-var config, no shared global), credentials inject per-request from
OperationContext.capabilities, outbound TLS uses the system trust store.

Records the downstream layering boundary: the agent crate's provider SSE
normalization (the solid part of aisdk's pattern — Vercel-UI-message
normalization) sits on top of this client, consuming the reqwest::Response
stream; it does not replace the client. The aisdk core/client.rs reference for
client construction is dropped (env-var config + hand-rolled retry are the
anti-patterns discarded); the from_openapi.ts SSE normalization reference in
the forwarding-handler section is kept (separate, solid pattern).

No ADR — the decision is internal to alknet-http: the client type does not
cross crate boundaries (alknet-call never sees reqwest), the library choice is
reversible, and it does not touch the system's structure, constraints, or
cross-crate API surface.

Updates: http-adapters.md (HTTP client section rewritten, references updated,
constraints/OQ bullets updated), http-mcp.md (OQ-40 status flip), open-
questions.md (OQ-40 resolved with full config-shape table), README.md (OQ-40
folded into the existing two-way-doors bucket), and three secondary docs
(crates/http/README.md, overview.md, http-server.md) that carried stale 'open'
OQ-40 references.
2026-06-30 08:02:30 +00:00
125cb49cc4 docs(http): defer h3/WebTransport (ADR-044); browsers use WebSocket for v1
Working through the WebTransport implementation path surfaced a scope
question distinct from the hedging-as-deferral anti-pattern ADR-038 was
written to correct. Three findings drove the re-evaluation:

1. The browser bidirectional call-protocol path doesn't require
   WebTransport — WebSocket is full-duplex, EventEnvelope fits a WS
   binary message boundary cleanly, and the Dispatcher is stream-
   agnostic (ADR-012). What WebTransport gives over WebSocket (native
   multi-stream multiplexing, the ALPN-as-stream substrate) benefits the
   proxy use case, not the call protocol.
2. WebTransport is a draft standard (-07, not RFC) on an experimental
   Rust dependency stack (wtransport/h3 both self-describe as not
   production-ready). Either choice puts a draft protocol on the
   security surface of the first release.
3. The ALPN-stream-proxy (ADR-040) is speculative — its WASM parser
   consumers (browser SSH/SFTP/git clients) don't exist yet, and the
   downstream crates WebTransport deferral blocks (SSH, git, SFTP)
   expose their ALPNs natively over QUIC regardless.

This is a scope decision (per ADR-009: a decision that 'genuinely
doesn't need to be made yet because the use case isn't concrete'), not
hedging. The reversal trigger is concrete: a real deployment needing
the ALPN-stream-proxy.

ADR-038 is superseded (its anti-pattern correction stands; its specific
'h3 in scope now' decision is reversed). ADR-040 and ADR-043 are
parked, not superseded — their designs revive unchanged when WebTransport
revives, with §2 (bidirectionality) and §3 (no-PeerId overlay) of ADR-043
transferring to WebSocket for v1.

ADR-044 §5 also states the 'browser is not a peer' rationale that
ADR-034 §4 closed without arguing: peer = addressable node in the
call-protocol peer graph (stable PeerId, PeerRef::Specific-reachable,
identity stable across reconnects), not 'any endpoint that exchanges
calls during a live session.' A browser is the second but not the first
(no stable crypto identity of its own, ephemeral, not addressable from
other nodes). ADR-034 §4 and Assumption 2 are amended by reference.

The wtransport-vs-hyperium dependency question is recorded (not
resolved — WebTransport is deferred) in ADR-044 §'Research note' and
webtransport.md so the revival doesn't re-derive it: wtransport probably
isn't the right choice (axum-bridge friction — it owns its own HTTP
serving path); the hyperium stack (h3 + h3-quinn + h3-webtransport) fits
the axum integration better but its server-side WebTransport API needs
verification before commitment.

Reviewed by architecture-review subagent; all critical cross-reference
issues (ADR-034 §5 stale 'in scope' assertion, ADR-036 Context listing
h3 as implemented, webtransport.md Design Decisions table) resolved.
2026-06-30 05:55:55 +00:00