docs(arch): hub-wiring cluster — aggregated env, peer_operations, from_call cleanup, alknet-hub crate spec
Three ADRs addressing gaps surfaced by the first hub consumer (alkapi): - ADR-067: Aggregated peer-env wiring — Dispatcher::with_aggregated_env hook so compose_root_env reads a shared PeerCompositeEnv across all calls, not a fresh per-call one. The hub-defining gap (alkapi OQ-08 / G.1). - ADR-068: PeerCompositeEnv::peer_operations override — adds list_operation_names() to OperationEnv, overrides on OverlayOperationEnv and PeerCompositeEnv. Fixes services/list-peers returning empty operation lists for non-local peers (alkapi G.6). - ADR-069: from_call is a manual free function, not auto-wired — reverses the aspirational OQ-27 resolution to match the implementation. Cleans the 'v1 default' hedging language in ADR-017 and client-and-adapters.md (alkapi G.4). New crate spec: alknet-hub — reusable hub pattern (aggregated env, connection lifecycle, worker supervision with backoff, service discovery). Spec fixes: builder API drift (with_local/with_local_streaming separation), ScopedOperationEnv → ScopedPeerEnv type name, OQ count 51→54. Three new OQs: OQ-52 (wait_for_close), OQ-53 (backoff defaults), OQ-54 (inbound hook placement).
This commit is contained in:
1 parent
2282647f8b
commit
87b2c2a5ef
15 files changed
+1052
-47
No files matched your search
@@ -1,15 +1,20 @@
|
||||
# OQ-27: from_call Re-Import Trigger
|
||||
|
||||
- **Origin**: [client-and-adapters.md](crates/call/client-and-adapters.md), ADR-017 Assumption 4
|
||||
- **Status**: **resolved** (2026-06-27)
|
||||
- **Status**: **resolved** (2026-07-09 — amended from 2026-06-27 resolution)
|
||||
- **Door type**: Two-way
|
||||
- **Priority**: low
|
||||
- **Resolution**: The decision is **auto-re-import on connection
|
||||
establishment**. The overlay is per-connection (Layer 2, ADR-024), so a
|
||||
stale overlay dies with the connection; re-import on reconnect is
|
||||
naturally scoped to the new connection. This is the right default for the
|
||||
runner pattern (a worker reconnects → the hub re-discovers the worker's
|
||||
ops automatically). An explicit `CallConnection::refresh()` method is a
|
||||
genuine feature addition — non-breaking, additive — if a deployment
|
||||
needs manual control.
|
||||
- **Resolution**: `from_call` is a **manual free function**; the assembly layer
|
||||
calls it after `connect()`. The overlay is per-connection (Layer 2, ADR-024),
|
||||
so a stale overlay dies with the connection; re-import on reconnect is
|
||||
naturally scoped to the new connection. A `CallConnection::refresh()` method
|
||||
for mid-connection re-discovery is a genuine feature addition —
|
||||
non-breaking, additive — if a deployment needs manual re-discovery without
|
||||
drop-and-reconnect. See [ADR-069](../decisions/069-from-call-manual-free-function.md)
|
||||
for the full rationale.
|
||||
|
||||
The original 2026-06-27 resolution ("auto-re-import on connection
|
||||
establishment") was aspirational — written before the implementation
|
||||
existed. The implementation made the right call (manual free function);
|
||||
this amendment aligns the spec with the implementation.
|
||||
- **Cross-references**: ADR-017, ADR-024, [client-and-adapters.md](crates/call/client-and-adapters.md)
|
||||
@@ -0,0 +1,26 @@
|
||||
# OQ-52: CallConnection::wait_for_close() for Supervision Loop
|
||||
|
||||
- **Origin**: [crates/hub/README.md](crates/hub/README.md)
|
||||
- **Status**: open
|
||||
- **Door type**: Two-way
|
||||
- **Priority**: medium
|
||||
- **Resolution**: Not yet decided.
|
||||
|
||||
The hub's worker supervision loop needs a way to await connection close so it
|
||||
can call `detach_peer` and retry. Today `CallConnection` exposes `connection()`
|
||||
(the underlying `Connection`) but not a "wait for run_loop exit" future.
|
||||
|
||||
Options:
|
||||
- **(a)** Add a `closed()` method to `CallConnection` that returns a
|
||||
`Future<Output = ()>` resolving when `run_loop` exits. The dispatcher
|
||||
signals a `tokio::sync::Notify` on exit; `closed()` awaits it.
|
||||
- **(b)** Use a `tokio::sync::oneshot` channel created by the caller and
|
||||
passed to the dispatcher, signaled on `run_loop` exit.
|
||||
- **(c)** Poll `connection().accept_bi()` in a loop until it returns
|
||||
`ConnectionClosed` — works but is polling, not event-driven.
|
||||
|
||||
Option (a) is the cleanest: a method on `CallConnection` that any caller
|
||||
(not just the hub) can use to await connection close. It is a small additive
|
||||
change to `alknet-call`.
|
||||
|
||||
- **Cross-references**: ADR-067, [crates/hub/README.md](crates/hub/README.md)
|
||||
@@ -0,0 +1,19 @@
|
||||
# OQ-53: BackoffConfig Default Policy
|
||||
|
||||
- **Origin**: [crates/hub/README.md](crates/hub/README.md)
|
||||
- **Status**: open
|
||||
- **Door type**: Two-way
|
||||
- **Priority**: low
|
||||
- **Resolution**: Not yet decided.
|
||||
|
||||
The `BackoffConfig` struct provides configurable backoff for worker
|
||||
reconnection. The default policy (1s initial, 60s max, 2x multiplier) is a
|
||||
starting point. Whether this is the right policy for production deployments
|
||||
is an operational question, not an architectural one.
|
||||
|
||||
The `BackoffConfig` struct shape is committed; the defaults are a starting
|
||||
point that can be changed without breaking the API. The question is whether
|
||||
to change the defaults before the first release, based on operational
|
||||
experience from the alkapi deployment.
|
||||
|
||||
- **Cross-references**: [crates/hub/README.md](crates/hub/README.md)
|
||||
@@ -0,0 +1,26 @@
|
||||
# OQ-54: Inbound Worker on_worker_connected Hook Placement
|
||||
|
||||
- **Origin**: [crates/hub/README.md](crates/hub/README.md)
|
||||
- **Status**: open
|
||||
- **Door type**: Two-way
|
||||
- **Priority**: low
|
||||
- **Resolution**: Not yet decided.
|
||||
|
||||
When a worker connects inbound (via `CallAdapter::handle`), the hub needs to
|
||||
call `from_call`, register the bundles, and `attach_peer`. Two options:
|
||||
|
||||
- **(a) Explicit**: The assembly layer calls `hub.on_worker_connected()` after
|
||||
`CallAdapter::handle` accepts the connection. The hub provides the method;
|
||||
the assembly layer wires it.
|
||||
- **(b) Wrapper**: The hub provides a `HubCallAdapter` wrapper that calls the
|
||||
hook automatically inside `handle()`. The assembly layer uses the wrapper
|
||||
instead of the raw `CallAdapter`.
|
||||
|
||||
Option (a) is simpler and more flexible — the assembly layer controls when
|
||||
the hook fires and can add its own logic (authorization checks, logging)
|
||||
before discovery. Option (b) is more convenient but hides the hook from the
|
||||
assembly layer.
|
||||
|
||||
The explicit approach is the committed interim. A wrapper is additive.
|
||||
|
||||
- **Cross-references**: ADR-067, ADR-068, [crates/hub/README.md](crates/hub/README.md)
|
||||
Reference in new issue
Block a user