feat: per-session fork registry, connect-side serving loop, op/register (review 004 Units 1-3)

Remediates all six findings of review 004 (per-connection dispatch
resolution and client-side op serving). All claims re-verified in
source before remediation; F-02's member list gains ScopedPeerEnv
(also Clone — fork surface simpler than estimated).

- OperationRegistry: interior mutability (parking_lot RwLock on both
  maps); register takes &self; registration/list_operations return
  owned clones; fork() deep-copies registrations + cached publish-schema
  validators (F-02/F-03); OperationRegistryBuilder::from_registry.
- install_bootstrap_discovery: services/list, services/list-peers,
  services/schema registered closed over the fork itself, so
  per-session openables are discoverable and services/schema answers
  from the fork (F-06).
- Dispatcher::serve_single_stream: full-duplex single-stream loop —
  call.requested dispatches inbound; responded/completed/error resolve
  outbound pendings; aborted tries both tables (in-flight sink aborts
  + pending cascade); published routes inbound sinks (F-04).
- ChannelClient::from_connection_with_serving(connection,
  Option<ServingConfig>): opt-in serving; from_connection keeps the
  pure-consumer default.
- registry::op_register: OpRegisterRequest wire DTO (spec in
  services/schema JSON + replace flag), op_register_spec,
  op_register_handler (rebuild -> forwarding stub -> register_imported,
  forced Internal/FromCall), announce_op; CallError::already_exists;
  spec_to_json_pub; from_call's rebuild_spec_for + forwarding-handler
  constructors crate-shared (F-05).
- ADR-047 §4 amendment #2: per-session fork is the dispatch-registry
  mechanism; overlay stays nested-invocation/peer-announced landing
  zone (F-01/F-02).
- ADR-022 amendment 2026-09-03: bootstrap-op set (services/list,
  services/schema, op/register), opt-in connect-side serving, op/register
  wire shape (F-04/F-05).
- alkhttp ADR-048 reconciliation note + OQ-05 re-pointed at the alkcall
  ADRs (Unit 1b).
- Review 004 status -> remediated; remediation log with gates.

Verification:
- cargo test: 581 passed, 0 failed (565 baseline + 16 new)
- cargo test --all-features: 598 passed, 0 failed
- cargo clippy --all-targets -- -D warnings: clean
- cargo clippy --all-features --all-targets -- -D warnings: clean
- cargo clippy --target wasm32-unknown-unknown -- -D warnings: clean
- cargo fmt --check: clean
- cargo doc --no-deps: clean

Gates: fork_registry_open_op_resolves_and_is_discoverable (open op via
fork + services/list shows openable + services/schema validates),
serving_loop_hub_to_consumer_call_resolves (hub->consumer call through
consumer's serving loop, consumer->hub still resolves),
op_register_announce_then_hub_call_routes_back_to_consumer (announce ->
overlay -> hub call -> forwarding stub -> consumer serves).
This commit is contained in:
glm-5.3-flash committed 2026-09-03 17:32:45 +00:00
1 parent c0dbf82518
commit f84d214173
18 files changed
+2024 -138

No files matched your search

@@ -2,7 +2,9 @@
## Status
Verified, open for remediation.
Verified, remediated (2026-09-03 — Units 1–3; Unit 4 remains
downstream in alkhttp). See "Remediation log (2026-09-03)" at the
bottom for the landing summary and the gates.
## Scope
@@ -444,4 +446,82 @@ notes).
`peer_operations()`, populated by `compose_root_env` at
`dispatch.rs:211-213`).
- Baseline gates re-run for this pass: cargo test (565), clippy
(all-targets), fmt — all clean. No source changes.
(all-targets), fmt — all clean. No source changes.
## Remediation log (2026-09-03)
Units 1–3 landed in one pass. Every claim above was re-verified
against the source before remediation began; all six findings
confirmed (F-02's member-type list was missing `ScopedPeerEnv`
(`context.rs:53`) — also Clone, which made the fork surface simpler
than the review estimated).
**Unit 1 — decision recording (F-01/F-02 direction, F-04/F-05 scope):**
- ADR-047 §4 amendment #2 (2026-09-03): the per-connection registration
mechanism is the **per-session fork of the base registry installed as
the session's dispatch registry** (option (a)); the overlay registry
stays the nested-invocation / peer-announced-ops landing zone.
- ADR-022 amendment (2026-09-03): the bootstrap-op set (`services/list`,
`services/schema`, `op/register`), the opt-in connect-side serving
loop, and the `op/register` wire shape (spec in `services/schema`
JSON + `replace` flag; forwarding-handler wrap into the connection
overlay; `ALREADY_EXISTS` collision gate).
- alkhttp ADR-048's reconciliation note and OQ-05 re-pointed at these
ADRs (Unit 1b).
**Unit 2 — fork surface + per-session composition (F-02, F-03, F-06):**
- `OperationRegistry` gained interior mutability (`parking_lot::RwLock`
around the operations and validators maps) so a registry can live
behind an `Arc` and be self-referential. `register` now takes
`&self`; `registration`/`list_operations` return owned clones
(handlers are `Arc` closures — the clone is cheap).
- `OperationRegistry::fork()` — deep copy of registrations (handlers,
provenance, composition authority, capabilities, `scoped_env`) and
the cached publish-schema validators. `OperationRegistryBuilder::
from_registry` seeds the builder path from an existing registry.
- `install_bootstrap_discovery(&Arc<OperationRegistry>)` — registers
`services/list` / `services/list-peers` / `services/schema` closed
over the fork itself, so per-session openables are discoverable
(F-06) and `services/schema` answers from the fork.
- Gate: `fork_registry_open_op_resolves_and_is_discoverable`
(`src/channels/client.rs`) — open op registered on the fork resolves
over a live channels connection; the openable appears in
`services/list` on the fork; `services/schema` on the fork still
answers. Unit tests: fork independence both directions, validator
carry, post-dispatch registration through a shared `Arc`.
**Unit 3 — client serving half + bootstrap registration (F-04, F-05):**
- `Dispatcher::serve_single_stream` — the full-duplex single-stream
loop: `call.requested` → dispatch + response frames (the
`run_loop_single_stream` arms); `call.responded`/`completed`/`error`
→ pending resolution (the read-pump arms); `call.aborted` → both
tables (in-flight sink aborts and the pending map's cascade);
`call.published` → inbound in-flight sinks. Disconnect fails
pendings and drops in-flight sinks (teardown identical to the two
half-loops it composes).
- `ChannelClient::from_connection_with_serving(connection,
Option<ServingConfig>)` — opt-in serving; `from_connection`
preserves the pure-consumer default (resolution-only read pump).
Gate: `serving_loop_hub_to_consumer_call_resolves` — hub→consumer
call resolves through the consumer's serving loop, consumer→hub
still resolves in the same loop.
- `registry::op_register` — `OpRegisterRequest` wire DTO,
`op_register_spec`, `op_register_handler` (rebuild → forwarding stub
→ `register_imported` into the connection overlay, forced
`Internal`/`FromCall`), `announce_op`. `CallError::already_exists`
added for the collision gate. `spec_to_json_pub` made the
`services/schema` wire shape public; `rebuild_spec_for` and the
forwarding-handler constructors are crate-shared with `from_call`.
Gates: `op_register_announce_then_hub_call_routes_back_to_consumer`
(announce → overlay → hub call → forwarding stub → consumer serves)
plus unit tests (round-trip, collision, replace, forced
visibility/provenance).
**Baseline after remediation:** cargo test 581 passed / 0 failed;
clippy (all-targets, `-D warnings`) clean; `cargo fmt --check` clean;
wasm target gate re-run below. No wire-format changes: the envelope
kind set stays closed at six; the bootstrap ops ride channel 0's call
registry.