chore(deps): consume alkcall 0.3 — per-session fork, serving loop, op/register

Bump alkcall 0.2 -> 0.3 (published 2026-09-04; the remediation of
alkcall reviews 004-005, the upstream resolution of alkhttp review 003
WS-24/WS-25). Two source-break classes, both mechanical:

- take_call_connection now returns Option<Arc<CallConnection>>
  (was bare value) — drop the double-wrap in WssSession::connect.
- register/register_on/register_openable take &OperationRegistry
  (was &mut) — drop 51 stale `mut` bindings (clippy --fix), which is
  the interior-mutability change that makes the per-session fork
  surface possible.

No behavior change in this crate yet; the 0.3 mechanisms (fork,
serve_single_stream, op/register, install_bootstrap_discovery,
collision policy) are the composition surface for alkhttp review 003
Unit 2 (WS-20..22, WS-26 wiring) — not wired here yet.

Verification: cargo test 453 passed (default) / 575 passed
(all-features), clippy both sides -D warnings clean, fmt clean,
cargo doc --no-deps clean.
This commit is contained in:
2026-09-04 14:55:19 +00:00
parent 5b62307be9
commit 3dee46aead
10 changed files with 50 additions and 51 deletions
Generated
+2 -2
View File
@@ -27,9 +27,9 @@ dependencies = [
[[package]]
name = "alkcall"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83e91782140beee66656cda7c5bfb1248f76302225b51538d3523b51d178ac7d"
checksum = "d0e415a03f77446ba446b3a758dc7846283b217a356376499a74a836b10e875a"
dependencies = [
"async-trait",
"bytes",
+1 -1
View File
@@ -42,7 +42,7 @@ h2 = ["server", "dep:hyper", "hyper-util/http2", "hyper/http2"]
http1 = ["server", "dep:hyper", "hyper-util/http1", "hyper/http1"]
[dependencies]
alkcall = { version = "0.2", features = ["gateway"] }
alkcall = { version = "0.3", features = ["gateway"] }
arc-swap = { version = "1", optional = true }
axum = { version = "0.8", optional = true, features = ["ws"] }
bytes = "1"
+4 -5
View File
@@ -272,7 +272,6 @@ impl WssSession {
.ok_or_else(|| AdapterError::Transport {
message: "channel client closed before channel 0 was installed".to_string(),
})?;
let call_connection = Arc::new(call_connection);
let (close_tx, mut close_rx) = tokio::sync::oneshot::channel();
let pending = Arc::clone(call_connection.pending());
@@ -512,7 +511,7 @@ mod tests {
/// A producer registry: `echo/run` (open), `admin/run` (admin scope),
/// plus the discovery ops the importer calls over channel 0.
fn producer_registry() -> Arc<OperationRegistry> {
let mut inner = OperationRegistry::new();
let inner = OperationRegistry::new();
inner
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -556,7 +555,7 @@ mod tests {
.unwrap();
let inner = Arc::new(inner);
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
services_list_spec(),
@@ -596,7 +595,7 @@ mod tests {
/// A producer registry with a never-responding `slow/op`.
fn slow_producer_registry() -> Arc<OperationRegistry> {
let mut inner = OperationRegistry::new();
let inner = OperationRegistry::new();
inner
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -620,7 +619,7 @@ mod tests {
))
.unwrap();
let inner = Arc::new(inner);
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
services_list_spec(),
+8 -8
View File
@@ -585,7 +585,7 @@ mod tests {
fn full_registry_with_ops(
specs: Vec<(String, OperationType, AccessControl)>,
) -> Arc<OperationRegistry> {
let mut inner = OperationRegistry::new();
let inner = OperationRegistry::new();
for (name, op_type, acl) in specs {
inner
.register(HandlerRegistration::new(
@@ -600,7 +600,7 @@ mod tests {
}
let inner = Arc::new(inner);
let mut dispatch_registry = OperationRegistry::new();
let dispatch_registry = OperationRegistry::new();
for op in inner.list_operations() {
dispatch_registry
.register(HandlerRegistration::new(
@@ -932,7 +932,7 @@ mod tests {
#[tokio::test]
async fn schema_denies_internal_op_with_not_found_symmetrically_with_http() {
let mut inner = OperationRegistry::new();
let inner = OperationRegistry::new();
inner
.register(HandlerRegistration::new(
internal_spec("secret/op"),
@@ -944,7 +944,7 @@ mod tests {
))
.unwrap();
let inner = Arc::new(inner);
let mut dispatch_registry = OperationRegistry::new();
let dispatch_registry = OperationRegistry::new();
dispatch_registry
.register(HandlerRegistration::new(
internal_spec("secret/op"),
@@ -1188,7 +1188,7 @@ mod tests {
#[tokio::test]
async fn call_tool_via_services_schema_with_internal_name_returns_not_found() {
let mut inner = OperationRegistry::new();
let inner = OperationRegistry::new();
inner
.register(HandlerRegistration::new(
internal_spec("secret/op"),
@@ -1200,7 +1200,7 @@ mod tests {
))
.unwrap();
let inner = Arc::new(inner);
let mut dispatch_registry = OperationRegistry::new();
let dispatch_registry = OperationRegistry::new();
dispatch_registry
.register(HandlerRegistration::new(
internal_spec("secret/op"),
@@ -1261,7 +1261,7 @@ mod tests {
#[tokio::test]
async fn batch_tool_via_services_schema_with_internal_name_yields_not_found_entry() {
let mut inner = OperationRegistry::new();
let inner = OperationRegistry::new();
inner
.register(HandlerRegistration::new(
internal_spec("secret/op"),
@@ -1283,7 +1283,7 @@ mod tests {
))
.unwrap();
let inner = Arc::new(inner);
let mut dispatch_registry = OperationRegistry::new();
let dispatch_registry = OperationRegistry::new();
dispatch_registry
.register(HandlerRegistration::new(
internal_spec("secret/op"),
+1 -1
View File
@@ -1548,7 +1548,7 @@ mod tests {
#[test]
fn internal_operations_excluded_from_error_projection() {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
OperationSpec::new(
+21 -21
View File
@@ -888,7 +888,7 @@ mod tests {
}
fn registry_with_echo() -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
external_spec("echo/run", AccessControl::default()),
@@ -903,7 +903,7 @@ mod tests {
}
fn registry_with_restricted_op() -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
external_spec(
@@ -924,7 +924,7 @@ mod tests {
}
fn registry_with_internal_op() -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
internal_spec("secret/op"),
@@ -977,7 +977,7 @@ mod tests {
name: &str,
outputs: Vec<Value>,
) -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
subscription_spec(name, Visibility::External, AccessControl::default()),
@@ -992,7 +992,7 @@ mod tests {
}
fn registry_with_subscription_error(name: &str, error: CallError) -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
subscription_spec(name, Visibility::External, AccessControl::default()),
@@ -1009,12 +1009,12 @@ mod tests {
fn registry_with_discovery_and_ops(
inner_ops: Vec<HandlerRegistration>,
) -> Arc<OperationRegistry> {
let mut inner = OperationRegistry::new();
let inner = OperationRegistry::new();
for op in inner_ops {
inner.register(op).unwrap();
}
let inner = Arc::new(inner);
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
services_list_spec(),
@@ -1053,7 +1053,7 @@ mod tests {
}
fn registry_with_discovery_and_internal_op() -> Arc<OperationRegistry> {
let mut inner = OperationRegistry::new();
let inner = OperationRegistry::new();
inner
.register(HandlerRegistration::new(
internal_spec("secret/op"),
@@ -1075,7 +1075,7 @@ mod tests {
))
.unwrap();
let inner = Arc::new(inner);
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
services_list_spec(),
@@ -1620,7 +1620,7 @@ mod tests {
#[tokio::test]
async fn batch_internal_op_returns_not_found_in_array() {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
internal_spec("secret/op"),
@@ -1828,7 +1828,7 @@ mod tests {
name: &str,
error: CallError,
) -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
subscription_spec(name, Visibility::External, AccessControl::default()),
@@ -1950,7 +1950,7 @@ mod tests {
#[test]
fn is_internal_op_detects_registered_internal_op() {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
internal_spec("secret/op"),
@@ -1967,7 +1967,7 @@ mod tests {
#[test]
fn is_internal_op_false_for_external_op() {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
external_spec("echo/run", AccessControl::default()),
@@ -2003,7 +2003,7 @@ mod tests {
#[tokio::test]
async fn call_error_envelope_carries_retry_after_on_retryable_503() {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
external_spec("flaky/op", AccessControl::default()),
@@ -2228,7 +2228,7 @@ mod tests {
use alkcall::registry::registration::make_sink_handler;
fn publish_registry() -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -2401,7 +2401,7 @@ mod tests {
#[tokio::test]
async fn publish_unauthorized_restricted_op_returns_403() {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
pub_spec(
@@ -2540,7 +2540,7 @@ mod tests {
#[tokio::test]
async fn publish_error_envelope_maps_to_http_status() {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -2641,7 +2641,7 @@ mod tests {
#[tokio::test]
async fn publish_line_exceeding_cap_yields_invalid_input_chunk_error() {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -2690,7 +2690,7 @@ mod tests {
}
fn registry_with_cap_witness_sink() -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -2928,7 +2928,7 @@ mod tests {
/// no `/publish` request to fail and no fail-open window.
#[test]
fn uncompilable_publish_schema_is_rejected_at_registration() {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
let result = registry.register(HandlerRegistration::new(
OperationSpec::new(
"ingest/broken",
@@ -2961,7 +2961,7 @@ mod tests {
#[tokio::test]
async fn publish_hot_reload_replacement_schema_is_picked_up() {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
OperationSpec::new(
+1 -1
View File
@@ -855,7 +855,7 @@ mod tests {
async fn openapi_json_serves_the_gateway_projection() {
use tokio::io::{AsyncReadExt, AsyncWriteExt};
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
let spec = alkcall::registry::spec::OperationSpec::new(
"echo/run",
alkcall::registry::spec::OperationType::Query,
+3 -3
View File
@@ -65,7 +65,7 @@ fn provider_with(tokens: Vec<(&str, Identity)>) -> Arc<dyn IdentityProvider> {
/// and echo-restricted variants), a streaming sub op, and the discovery
/// ops the adapters need.
fn local_registry() -> Arc<OperationRegistry> {
let mut inner = OperationRegistry::new();
let inner = OperationRegistry::new();
inner
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -119,7 +119,7 @@ fn local_registry() -> Arc<OperationRegistry> {
.unwrap();
let inner = Arc::new(inner);
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
services_list_spec(),
@@ -351,7 +351,7 @@ async fn from_openapi_import_then_gateway_call() {
// a wire call to them is NOT_FOUND (ADR-015 §2). The assembly layer
// composes them under an External facade. Verify Internal-not-callable
// through the gateway, then compose the External facade and call that.
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
for b in bundles {
registry.register(b).unwrap();
}
+2 -2
View File
@@ -58,7 +58,7 @@ fn echo_handler() -> alkcall::registry::registration::Handler {
}
fn echo_registry() -> Arc<alkcall::registry::registration::OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
external_spec("echo/run", AccessControl::default()),
@@ -510,7 +510,7 @@ async fn disconnect_drops_session_cleanly_subsequent_reach_fails_cleanly() {
}
fn slow_and_echo_registry() -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
external_spec("slow/op", AccessControl::default()),
+7 -7
View File
@@ -30,7 +30,7 @@ fn echo_handler() -> Handler {
}
fn echo_registry() -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -54,7 +54,7 @@ fn echo_registry() -> Arc<OperationRegistry> {
}
fn slow_and_echo_registry() -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -100,7 +100,7 @@ fn slow_and_echo_registry() -> Arc<OperationRegistry> {
}
fn internal_registry() -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -124,7 +124,7 @@ fn internal_registry() -> Arc<OperationRegistry> {
}
fn restricted_registry() -> Arc<OperationRegistry> {
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
OperationSpec::new(
@@ -151,12 +151,12 @@ fn restricted_registry() -> Arc<OperationRegistry> {
}
fn registry_with_services_list(inner_ops: Vec<HandlerRegistration>) -> Arc<OperationRegistry> {
let mut inner = OperationRegistry::new();
let inner = OperationRegistry::new();
for op in inner_ops {
inner.register(op).unwrap();
}
let inner = Arc::new(inner);
let mut registry = OperationRegistry::new();
let registry = OperationRegistry::new();
registry
.register(HandlerRegistration::new(
services_list_spec(),
@@ -696,7 +696,7 @@ async fn ws_sessions_registry_tracks_and_aborts_live_sessions() {
async fn session_cap_rejects_over_limit_with_503_and_frees_slots_on_end() {
use alkhttp::server::HttpAdapter;
let mut registry_val = OperationRegistry::new();
let registry_val = OperationRegistry::new();
registry_val
.register(HandlerRegistration::new(
OperationSpec::new(