docs: missing_docs sweep — 0 warnings + deny gate + publish-prep decisions (HY-02, HY-04, HY-11)

- document every public-API item across 18 files (openapi_spec model,
  HttpAuthScheme/HttpServiceConfig, HttpClientBuildError + SharedHttpClient
  accessors, RetryAfterMiddleware, GatewayDispatch, gateway error
  mapping, CallRequest/SchemaQuery/SubscribeStream, HttpAdapter +
  ALPNs + builders, decoy/healthz/state, WsSessions/WsPumps,
  from_openapi/from_jsonschema/from_mcp/from_wss/to_mcp, lib.rs module
  docs)
- enforcement: #![deny(missing_docs)] at crate root — stronger than CI
  rustdocflags (every build incl. cfg(test), where rustdoc misses the
  test-support module docs)
- HY-10 (opportunistic): all 8 docs.rs/alkhttp placeholder ADR links +
  the one relative ../docs link converted to plain text; the 10
  pre-existing private/redundant intra-doc-link warnings fixed —
  RUSTDOCFLAGS="-D warnings" cargo doc is fully clean
- HY-11 decision: docs/ + tasks/ excluded from the published package
  (contributor-facing design/process material; ADR references degrade
  to plain text uniformly). cargo publish --dry-run: 38 files, ~889 KiB,
  zero docs/ or tasks/ entries
- HY-04 decision: keep + document — frame_channel0_chunk's unwrap is
  on serializing the acyclic EventEnvelope (unreachable failure);
  # Panics on it and the adjacent WsClient senders state the contract

Verified: cargo test (299 + 5 TLS), --all-features (370 + suites),
--no-default-features (299), clippy --all-targets -D warnings
(default + all-features), fmt --check, cargo doc -D warnings clean,
cargo publish --dry-run --allow-dirty clean.

Tasks: review-001-missing-docs-sweep (final pending task; 42/42)
This commit is contained in:
2026-08-30 08:25:18 +00:00
parent 7ce1ca6fbd
commit 91483a74b4
22 changed files with 395 additions and 31 deletions
+26 -3
View File
@@ -17,8 +17,8 @@
//! sends must match what `/schema` advertises, so peer-supplied input
//! cannot add upstream query parameters, headers, or craft a request body
//! the contract does not declare. Declared keys route by designation: a
//! property marked [`HEADER_PARAM_IN_MARKER`]` = "header"` is sent as a
//! request header, the declared [`GATEWAY_BODY_KEY`] property becomes the
//! property marked with the `HEADER_PARAM_IN_MARKER` marker key set to "header" is sent as a
//! request header, the declared `GATEWAY_BODY_KEY` property becomes the
//! request body, and every other declared key becomes an upstream query
//! parameter.
@@ -79,17 +79,40 @@ pub(crate) const GATEWAY_BODY_KEY: &str = "body";
pub(crate) const HEADER_PARAM_IN_MARKER: &str = "wire";
pub(crate) const HEADER_PARAM_MARKER_VALUE: &str = "header";
/// The credential scheme forwarded handlers apply to outbound requests
/// (ADR-014). The credential value itself flows through
/// `OperationContext.capabilities` at call time — never through this
/// config.
#[derive(Clone)]
pub enum HttpAuthScheme {
/// `Authorization: Bearer <token>` from the caller's `Bearer`
/// capability.
Bearer,
ApiKey { header_name: String },
/// A named API-key header (e.g. `x-api-key`) carrying the caller's
/// `ApiKey` capability value.
ApiKey {
/// The upstream header the key is sent in.
header_name: String,
},
/// HTTP Basic auth from the caller's `username`/`password`
/// capability pair.
Basic,
}
/// Assembly-time configuration for one imported HTTP service: the
/// registry namespace its operations land under, where traffic goes,
/// and how credentials attach.
pub struct HttpServiceConfig {
/// Registry namespace for the imported operations (the
/// `<namespace>/<operationId>` op names).
pub namespace: String,
/// Outbound base URL every path template is resolved against.
pub base_url: String,
/// Credential scheme for outbound requests; `None` sends an
/// unauthenticated request.
pub auth: Option<HttpAuthScheme>,
/// Static headers attached to every outbound request (e.g. a
/// required `User-Agent`).
pub default_headers: HashMap<String, String>,
}
+5 -1
View File
@@ -35,6 +35,10 @@ use serde_json::Value;
use super::forward::{forward, forward_stream, HttpServiceConfig};
use crate::client::SharedHttpClient;
/// The HTTP-backed single-endpoint adapter (ADR-066): one caller-built
/// [`OperationSpec`] forwarded to one HTTP endpoint. Eagerly validated
/// at construction; the caller's spec visibility is forced to
/// `Internal` (ADR-015).
pub struct FromJsonSchema {
spec: OperationSpec,
config: HttpServiceConfig,
@@ -61,7 +65,7 @@ impl FromJsonSchema {
/// are rejected at call time. Mark a property with
/// `"wire": "header"` to route it as an upstream HTTPS header
/// instead of a query parameter (review 001 OAI-03). Input key
/// [`GATEWAY_BODY_KEY`](super::forward::GATEWAY_BODY_KEY) carries
/// `GATEWAY_BODY_KEY` ("body") carries
/// the request body.
pub fn new(
spec: OperationSpec,
+10
View File
@@ -50,6 +50,9 @@ const MCP_CAPABILITY_KEY: &str = "mcp";
/// timed out. Payload is the array-of-content-blocks shape; retryable.
const MCP_TRANSPORT_ERROR: &str = "MCP_TRANSPORT_ERROR";
/// The `from_mcp` adapter (mcp feature): imports a remote MCP server's
/// tools as call-protocol operations under one namespace, with the
/// auth token injected per-call from `Capabilities` (ADR-014).
pub struct FromMCP {
endpoint: String,
auth_token: Option<Secret<String>>,
@@ -57,6 +60,8 @@ pub struct FromMCP {
}
impl FromMCP {
/// Assemble the adapter for a streamable-HTTP MCP `endpoint`,
/// registering its tools under `namespace`.
pub fn new(endpoint: impl Into<String>, namespace: impl Into<String>) -> Self {
Self {
endpoint: endpoint.into(),
@@ -65,19 +70,24 @@ impl FromMCP {
}
}
/// Set the auth token sent as the MCP endpoint's `Authorization:
/// Bearer` header (wrapped in `Secret` so it never logs).
pub fn with_auth_token(mut self, token: impl Into<String>) -> Self {
self.auth_token = Some(Secret::new(token.into()));
self
}
/// The configured MCP endpoint URL.
pub fn endpoint(&self) -> &str {
&self.endpoint
}
/// The namespace imported operations register under.
pub fn namespace(&self) -> &str {
&self.namespace
}
/// The configured token, for introspection (never logged).
pub fn auth_token(&self) -> Option<&Secret<String>> {
self.auth_token.as_ref()
}
+5
View File
@@ -88,6 +88,9 @@ fn reject_collisions(
Ok(())
}
/// The `from_openapi` adapter (ADR-051 input format): turns a parsed
/// OpenAPI document into forwarding-handler registrations under one
/// namespace — the credential injection point per ADR-014.
pub struct FromOpenAPI {
spec: OpenAPISpec,
config: HttpServiceConfig,
@@ -95,6 +98,8 @@ pub struct FromOpenAPI {
}
impl FromOpenAPI {
/// Assemble the adapter over a parsed spec, service config, and the
/// shared outbound client.
pub fn new(
spec: OpenAPISpec,
config: HttpServiceConfig,
+13
View File
@@ -78,6 +78,9 @@ fn connection_closed_error() -> CallError {
CallError::new("CONNECTION_CLOSED", "from_wss connection dropped", true)
}
/// The `from_wss` consumer adapter (wss feature): dials a remote WS
/// endpoint speaking the channels protocol and imports its operations
/// under an optional namespace (discovered when omitted).
pub struct FromWss {
endpoint: String,
auth_token: Option<Secret<String>>,
@@ -86,6 +89,8 @@ pub struct FromWss {
}
impl FromWss {
/// Assemble the adapter for a `wss://` (or explicit `ws://`)
/// channel endpoint.
pub fn new(endpoint: impl Into<String>) -> Self {
Self {
endpoint: endpoint.into(),
@@ -95,11 +100,15 @@ impl FromWss {
}
}
/// Set the auth token injected per-call from `Capabilities`
/// (wrapped in `Secret` so it never logs).
pub fn with_auth_token(mut self, token: impl Into<String>) -> Self {
self.auth_token = Some(Secret::new(token.into()));
self
}
/// Pin the namespace imported operations register under; without
/// it the remote's discovery advertises namespaces per operation.
pub fn with_namespace(mut self, namespace: impl Into<String>) -> Self {
self.namespace = Some(namespace.into());
self
@@ -114,14 +123,17 @@ impl FromWss {
self
}
/// The configured channel endpoint URL.
pub fn endpoint(&self) -> &str {
&self.endpoint
}
/// The pinned namespace, when one was set.
pub fn namespace(&self) -> Option<&str> {
self.namespace.as_deref()
}
/// The configured token, for introspection (never logged).
pub fn auth_token(&self) -> Option<&Secret<String>> {
self.auth_token.as_ref()
}
@@ -134,6 +146,7 @@ impl FromWss {
/// in-flight pending calls with retryable `CONNECTION_CLOSED`.
pub struct WssSession {
_client: ChannelClient,
/// The live channel-0 connection the consumer drives calls through.
pub call_connection: Arc<CallConnection>,
_monitor: WssDropMonitor,
}
+59
View File
@@ -16,50 +16,89 @@ use serde_json::Value;
/// exhausting the stack.
pub(crate) const MAX_REF_RESOLUTION_DEPTH: usize = 64;
/// The `paths`-level HTTP methods the adapter models. `trace` is
/// deliberately absent (OAI-06): a path carrying only unsupported
/// methods is skipped with a warning, not imported as a mis-behaving op.
pub(crate) const HTTP_METHODS: &[&str] =
&["get", "post", "put", "patch", "delete", "head", "options"];
/// The `info` block of an OpenAPI document.
#[derive(Clone, Debug)]
pub struct OpenAPIInfo {
/// Human-readable title (OpenAPI `info.title`).
pub title: String,
/// Declared spec/API version (OpenAPI `info.version`).
pub version: String,
}
/// One entry of a path item: a concrete path plus the operations
/// declared on it.
#[derive(Clone, Debug)]
pub struct PathItem {
/// `(method, operation)` pairs, methods lowercase as declared in the
/// document (`get`, `post`, ...), in parsed order.
pub operations: Vec<(String, Operation)>,
}
/// One OpenAPI operation parsed into the shared model.
#[derive(Clone, Debug)]
pub struct Operation {
/// `operationId` when declared; `from_openapi` falls back to
/// `method_path_derived` naming when absent.
pub operation_id: Option<String>,
/// Operation-level (non-`$ref`) parameters; `parameter $ref`s are
/// resolved before this model is built.
pub parameters: Vec<Parameter>,
/// `requestBody` when declared; `requestBody $ref`s are resolved
/// before this model is built.
pub request_body: Option<RequestBody>,
/// Responses keyed by their declared key — concrete statuses
/// (`"200"`, `"404"`), wildcards (`"4XX"`), or `"default"`. Consumers
/// must decide how to treat non-numeric keys (OAI-06).
pub responses: BTreeMap<String, Response>,
}
/// One OpenAPI parameter (`name`/`in`/`required`/`schema`).
#[derive(Clone, Debug)]
pub struct Parameter {
/// Declared parameter name; must be unique per location per
/// operation in a valid document.
pub name: String,
/// Parameter location: `path`, `query`, `header`, or `cookie`
/// (the last unsupported and rejected loudly at import).
pub in_: String,
/// Whether the operation fails without the parameter.
pub required: bool,
/// The parameter's schema as declared (unresolved `$ref`s are
/// resolved by the consumer via `resolve_refs_recursive`).
pub schema: Option<Value>,
}
/// An OpenAPI request body — the media-type → schema map of its
/// `content` field.
#[derive(Clone, Debug)]
pub struct RequestBody {
/// Media type (e.g. `application/json`) → the body schema.
pub content: BTreeMap<String, Value>,
}
/// An OpenAPI response — the media-type → schema map of its `content`
/// field.
#[derive(Clone, Debug)]
pub struct Response {
/// Media type (e.g. `application/json`) → the response schema.
pub content: BTreeMap<String, Value>,
}
/// The `components` block: reusable schemas, parameters, and request
/// bodies keyed by name.
#[derive(Clone, Debug)]
pub struct Components {
/// `components/schemas` entries.
pub schemas: HashMap<String, Value>,
/// `components/parameters` entries.
pub parameters: HashMap<String, Value>,
/// `components/requestBodies` entries.
pub request_bodies: HashMap<String, Value>,
}
@@ -73,15 +112,29 @@ fn index_component_map(raw: Option<&Value>) -> HashMap<String, Value> {
map
}
/// A parsed OpenAPI 3.x document: the typed model (`info`, `paths`,
/// `components`) plus the untouched `raw` document for `$ref`
/// resolution.
#[derive(Debug)]
pub struct OpenAPISpec {
/// The parsed `info` block.
pub info: OpenAPIInfo,
/// The path items keyed by their literal path string (with
/// placeholders).
pub paths: BTreeMap<String, PathItem>,
/// The `components` block, when the document declares one.
pub components: Option<Components>,
/// The full document as parsed — the lookup target for `$ref`
/// resolution.
pub raw: Value,
}
impl OpenAPISpec {
/// Parse a JSON OpenAPI document.
///
/// Fails with [`AdapterError::SchemaParse`] for malformed JSON or an
/// invalid document structure (missing `info`/`paths`, unresolvable
/// parameter `$ref`s).
pub fn from_json(doc: &str) -> Result<Self, AdapterError> {
let raw: Value = serde_json::from_str(doc).map_err(|e| AdapterError::SchemaParse {
message: format!("invalid JSON: {e}"),
@@ -127,6 +180,12 @@ impl OpenAPISpec {
}
}
/// Parse an already-deserialized OpenAPI document.
///
/// Validation mirrors [`from_json`](Self::from_json): the object
/// shape, `info`/`paths` presence, parameter `$ref` resolvability,
/// and the OAI-06 loud-feature gates (`servers` overrides,
/// non-default `style`/`explode`) all apply.
pub fn from_value(raw: Value) -> Result<Self, AdapterError> {
if !raw.is_object() {
return Err(AdapterError::SchemaParse {
+8
View File
@@ -119,15 +119,20 @@ fn batch_input_schema() -> Value {
})
}
/// The `to_mcp` projection (ADR-041): the local call-protocol
/// operations exposed as 4 fixed MCP gateway tools (`search`, `schema`,
/// `call`, `batch`) over the streamable-HTTP transport.
pub struct ToMcpGateway {
dispatch: Arc<GatewayDispatch>,
}
impl ToMcpGateway {
/// Assemble the gateway over a dispatch spine.
pub fn new(dispatch: Arc<GatewayDispatch>) -> Self {
Self { dispatch }
}
/// The dispatch spine the tools invoke through.
pub fn dispatch(&self) -> &Arc<GatewayDispatch> {
&self.dispatch
}
@@ -480,8 +485,11 @@ impl rmcp::handler::server::ServerHandler for ToMcpGateway {
}
}
/// The ready-to-mount rmcp service wrapping [`ToMcpGateway`] over the
/// streamable-HTTP transport.
pub type ToMcpService = StreamableHttpService<ToMcpGateway, LocalSessionManager>;
/// Build the mountable MCP service for a dispatch spine.
pub fn to_mcp_service(dispatch: Arc<GatewayDispatch>) -> ToMcpService {
let gateway = ToMcpGateway::new(dispatch);
StreamableHttpService::new(