docs(review 005): serving-loop concurrency + op/register composition findings
Post-remediation review of f84d214 (review 004 Units 1-3). Five
findings, verified in source and (for G-01) empirically via a probe
test that was added, run, and removed:
- G-01 [major]: serve_single_stream awaits dispatch inline; a
wire-dispatched handler composing a peer-announced op (or a
from_call import) over the same connection deadlocks — the nested
call resolves only via the 30s sweeper (probe: TIMEOUT at 30.0007s).
- G-02 [major]: the F-05 e2e gate calls the announced op directly,
bypassing the forwarding stub — the one path G-01 breaks.
- G-03 [major]: op/register's collision gate is overlay-only;
PeerCompositeEnv resolves connections before base, so an announced
op can shadow the serving side's own ops in nested composition.
- G-04 [minor]: resource_id_path does not survive the spec wire
round-trip (pre-existing shape, load-bearing for op/register).
- G-05 [minor]: install_bootstrap_discovery registers
services/list-peers; ADR-022's bootstrap set doesn't name it.
Non-findings bound the re-review: fork surface lock discipline,
bootstrap discovery closure, frame-arm equivalence of the composed
loop, unchanged pure-consumer default, alkhttp cross-repo claims,
CJK sweep (none), all gates reproduce (581/598, clippy, fmt, wasm,
doc).
Remediation plan: Unit 1 (concurrent serving loop + stub-exercising
gate) gates Unit 4 downstream; Unit 2 (collision policy); Unit 3
(round-trip completeness + doc alignment).
Verification: cargo doc --no-deps clean; tree unchanged apart from
this review doc.
This commit is contained in:
1 parent
f84d214173
commit
435ae9da2f
1 file changed
+448
@@ -0,0 +1,448 @@
|
||||
# Review 005 — Serving-Loop Concurrency and `op/register` Composition (post-remediation review of `f84d214`)
|
||||
|
||||
## Status
|
||||
|
||||
Verified, open for remediation.
|
||||
|
||||
## Scope
|
||||
|
||||
Post-remediation review of commit `f84d214` (review 004 Units 1–3:
|
||||
per-session fork registry, connect-side serving loop, `op/register`).
|
||||
The remediation landed all six F-findings' mechanisms; this pass
|
||||
reviews the landed implementation against the decided spec (ADR-022
|
||||
amendment 2026-09-03, ADR-047 §4 amendment #2, review 004's
|
||||
acceptance gates) rather than re-litigating the findings.
|
||||
|
||||
Every finding below was verified directly in source at tree
|
||||
`f84d214`. The headline finding (G-01) was verified **empirically**:
|
||||
a probe test was added to the tree, run, observed to reproduce the
|
||||
defect, and removed — the tree at this review's baseline carries no
|
||||
source changes. Findings continue alkcall review numbering with the
|
||||
new prefix `G` (001–004 used P/C/R/A/B/C/D/F — each review numbers
|
||||
independently).
|
||||
|
||||
Cross-repo context: the alkhttp re-pointing claimed by the remediation
|
||||
log was verified in that repo (`5b62307` — `open-questions.md:102-112`,
|
||||
`decisions/048…md:19-25`). Unit 4 (alkhttp wiring) remains downstream
|
||||
and is not reviewed here.
|
||||
|
||||
## Baseline verification (this pass)
|
||||
|
||||
```
|
||||
cargo test → 581 passed, 0 failed
|
||||
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 fmt --check → clean
|
||||
cargo check --target wasm32-unknown-unknown → clean
|
||||
cargo clippy --target wasm32-unknown-unknown -- -D warnings → clean
|
||||
cargo doc --no-deps → clean
|
||||
```
|
||||
|
||||
All gates the remediation log claims reproduce. The suite is green —
|
||||
and again the green is partial: the gates test the flows they name,
|
||||
and the one flow the ADR amendment promises most loudly (nested
|
||||
composition of peer-announced ops) is the one no gate exercises. See
|
||||
G-02 for why the existing gate cannot catch G-01.
|
||||
|
||||
## Verdict
|
||||
|
||||
- **Unit 2's fork surface is solid.** Interior mutability, lock
|
||||
discipline, fork independence, validator carry, and the
|
||||
self-referential bootstrap-discovery closure are all correct and
|
||||
tested (see Non-findings).
|
||||
- **Unit 3's serving loop resolves the F-04 frame gap but inherits the
|
||||
dispatch loop's serial-inline shape** — and the F-05 flow it exists
|
||||
to enable is exactly the shape that deadlocks under it. The ADR-022
|
||||
amendment's "invocable via nested composition" promise is
|
||||
unmechanized for wire-dispatched handlers (the primary caller
|
||||
shape); a 30s sweeper timeout masquerades as resolution.
|
||||
- **The F-05 acceptance gate does not exercise the forwarding stub** —
|
||||
the one component that is genuinely new protocol surface. It
|
||||
verifies announce-lands-in-overlay and the consumer serves, by
|
||||
calling the announced op *directly*, bypassing the stub entirely.
|
||||
- **`op/register`'s collision gate is overlay-only**, so a
|
||||
peer-announced op can shadow the serving side's own ops in nested
|
||||
composition (connections resolve before base in `PeerCompositeEnv`).
|
||||
|
||||
The architecture decisions (fork as dispatch registry; overlay as
|
||||
landing zone; bootstrap-op set; opt-in serving) remain sound. The
|
||||
defects are in the serving loop's concurrency model and in what the
|
||||
gates measure.
|
||||
|
||||
## Severity legend
|
||||
|
||||
Same scale as review 004:
|
||||
|
||||
- **[critical]** — a decided spec invariant is violated in a way that
|
||||
makes a promised capability unreachable end-to-end; or corrupts
|
||||
data.
|
||||
- **[major]** — a core protocol path cannot serve a decided behavior;
|
||||
works only via shapes the spec does not describe.
|
||||
- **[minor]** — drift, doc/spec inconsistency, or a missing
|
||||
convenience with no correctness impact.
|
||||
|
||||
---
|
||||
|
||||
# Part A — The serving loop's concurrency model
|
||||
|
||||
## G-01 [major] — Same-connection nested composition deadlocks the serving loop; the forwarding stub's nested call resolves only via the 30s sweeper
|
||||
|
||||
**ADR drift:** ADR-022 amendment (2026-09-03) §`op/register`: the
|
||||
announced op is *"invocable via nested composition (`env.invoke`)"*;
|
||||
the amendment's whole point is that the hub's handlers compose
|
||||
peer-announced ops. Review 004 F-05's recommendation said the same:
|
||||
the hub-side handler wraps announcements *"as a forwarding handler
|
||||
that issues a nested `call.requested` back over channel 0"*.
|
||||
|
||||
**Verified:** YES, by code trace and by an empirical probe (see
|
||||
Verification log).
|
||||
|
||||
Mechanism, in four steps:
|
||||
|
||||
1. `Dispatcher::serve_single_stream` awaits `dispatch()` **inline** in
|
||||
its read loop for `call.requested` frames
|
||||
(`src/protocol/dispatch.rs:1009-1014`) — the same serial-inline
|
||||
shape as the pre-existing accept-side `run_loop_single_stream`
|
||||
(`:765-770`). Only the Sink arm is spawned
|
||||
(`:1031-1053`); Once responses and Sub pumps
|
||||
(`pump_stream_single_stream`, awaited inline at `:1027-1029`)
|
||||
hold the loop.
|
||||
2. The F-05 forwarding stub (`make_forwarding_handler`,
|
||||
`src/client/from_call.rs:392-415`) issues its nested call via
|
||||
`connection.call_with_payload` (`:408`) — over **the same
|
||||
connection** whose loop dispatched the parent. In single-stream
|
||||
mode the pending resolves only when *some* loop reads the
|
||||
`call.responded` frame (`connection.rs:274-303` — register
|
||||
pending, write frame, await receiver; resolution is the reader's
|
||||
job).
|
||||
3. The only reader of that connection is the serving loop itself —
|
||||
which is blocked in step 1 awaiting the parent dispatch, whose
|
||||
handler is blocked in step 2 awaiting the nested call. Circular
|
||||
wait. The transport buffers the response frame; nobody reads it.
|
||||
4. The 30s sweeper (`DEFAULT_CALL_TIMEOUT`, `connection.rs:32`;
|
||||
`evict_expired`, run every 10s per `SWEEPER_INTERVAL`,
|
||||
`dispatch.rs:44`) is the only thing that breaks the cycle —
|
||||
the nested call resolves as `CallError::timeout`.
|
||||
|
||||
**Empirical probe (this pass):** hub serves `op/register` + a
|
||||
`hub/compose` handler that invokes the connection overlay's
|
||||
registration (the forwarding stub — the exact resolution
|
||||
`PeerCompositeEnv` → `OverlayOperationEnv` produces for nested
|
||||
composition) from inside a wire-dispatched handler; consumer announces
|
||||
`consumer/exec`, then calls `hub/compose` over the wire. Result:
|
||||
|
||||
```
|
||||
PROBE: hub/compose resolved after 30.000761619s:
|
||||
Err(CallError { code: "TIMEOUT", message: "request timed out", retryable: true })
|
||||
```
|
||||
|
||||
A second run with an 8s timeout confirmed the hang is unconditional
|
||||
(not load-dependent): zero progress until the sweeper. The probe was
|
||||
removed after evidence capture; the tree is unchanged.
|
||||
|
||||
**Consequences (verified):**
|
||||
|
||||
- The ADR-022 amendment's flagship flow — a hub handler composing a
|
||||
peer-announced op — fails for every wire-dispatched parent handler.
|
||||
It "works" only for parents dispatched from *in-process* contexts
|
||||
(where the serving loop is idle and free to resolve the nested
|
||||
call's response) — a shape the ADR does not describe. Per the
|
||||
severity legend this is a decided behavior served only via an
|
||||
undescribed shape; it borders [critical] for the composition flow
|
||||
specifically.
|
||||
- The same circular wait applies to composition of `from_call`
|
||||
*imports* on the accept side: `run_loop_single_stream` has the same
|
||||
inline shape, and the connection overlay's imported-op stubs ride
|
||||
the same connection. That hazard is **latent pre-`f84d214`** (the
|
||||
accept side had the inline loop and `register_imported` before this
|
||||
commit) — `f84d214` makes it load-bearing by (a) adding the wire
|
||||
path that populates overlays with stubs, (b) putting serving loops
|
||||
on the connect side where both directions are live by design, and
|
||||
(c) writing the composition promise into ADR-022.
|
||||
- The same starvation is not limited to the stub: while the loop
|
||||
serves *any* Sub (`pump_stream_single_stream` inline), the side's
|
||||
own outbound pendings queue unresolved. A serving-enabled consumer
|
||||
that calls out while serving a long-lived Sub to the same peer eats
|
||||
30s timeouts on its own calls. The F-04 gate tests the two
|
||||
directions only **sequentially** (hub→consumer resolves, *then*
|
||||
consumer→hub) — never interleaved.
|
||||
- Head-of-line blocking: the peer's subsequent requests queue behind
|
||||
each inline dispatch.
|
||||
|
||||
**Fix (Unit 1):** spawn the Once dispatch and the Sub pump the way the
|
||||
Sink arm already is (the `SharedFrameWriter` already serializes
|
||||
concurrent frame writes, so per-request frame ordering is preserved);
|
||||
track spawned task handles for teardown on loop exit (the Sink arm's
|
||||
`in_flight_sinks` pattern, generalized). Keep read-loop resolution
|
||||
unblocked at all times. Apply the same rework to
|
||||
`run_loop_single_stream` (or factor the shared loop) — the accept side
|
||||
has the identical latent hazard via imported-op composition.
|
||||
Acceptance: the probe above (recreated as a permanent gate) resolves
|
||||
in < 1s; a concurrent-interleaving gate (outbound call resolving while
|
||||
a Sub is being served) passes without sweeper intervention.
|
||||
|
||||
## G-02 [major] — The F-05 acceptance gate bypasses the forwarding stub it claims to prove
|
||||
|
||||
**Verified:** YES. `op_register_announce_then_hub_call_routes_back_to_consumer`
|
||||
(`src/channels/client.rs:1412-1543`) asserts the announce resolves and
|
||||
the overlay holds the op — then calls
|
||||
`accept_conn.call("consumer/exec", …)` (`:1529`). That is a **direct
|
||||
wire call**: the hub's dispatcher resolves `consumer/exec`… which is
|
||||
not on the hub at all — the frame crosses to the consumer, whose
|
||||
serving loop dispatches it from its *local* registry. The forwarding
|
||||
stub (`op_register_handler`'s `register_imported` bundle) is never
|
||||
invoked. The gate's comment — *"the forwarding stub routes the nested
|
||||
call back over channel 0"* — describes a path the test does not take.
|
||||
|
||||
**Consequence:** the one behavior that is genuinely new protocol
|
||||
surface (stub routing) is untested, and the one defect it hides (G-01)
|
||||
is precisely in that path. This is the same failure class review 001
|
||||
flagged ("all coverage is unit-level / the integration seams are where
|
||||
the real problems live") — the remediation added e2e gates, but the
|
||||
F-05 gate measures an adjacent, easier path. The F-04 gate is
|
||||
likewise sequential-only (see G-01's third consequence).
|
||||
|
||||
**Fix (fold into Unit 1):** add a gate that exercises the stub —
|
||||
announce → a wire-dispatched hub handler composes the announced op via
|
||||
`ctx.env` (or directly via the overlay registration) → resolves from
|
||||
the consumer. This is the removed probe, productized; it is the
|
||||
acceptance test G-01's fix must pass. Optionally extend the F-04 gate
|
||||
with an interleaved-directions phase.
|
||||
|
||||
---
|
||||
|
||||
# Part B — The `op/register` composition surface
|
||||
|
||||
## G-03 [major] — Announced ops can shadow the serving side's own ops in nested composition; the collision gate checks the overlay only
|
||||
|
||||
**ADR drift:** ADR-018 (composition authority) and ADR-019 (the
|
||||
overlay is the *landing zone* for imported ops — a layer beneath the
|
||||
deployment's own registry, not a rival to it); ADR-022 amendment
|
||||
(silent on name collisions with the serving side's base registry).
|
||||
|
||||
**Verified:** YES. `op_register_handler`'s collision gate is
|
||||
`connection.overlay_contains(&request.spec.name)`
|
||||
(`src/registry/op_register.rs:142`) — it consults **only the
|
||||
connection overlay**. The serving registry (the fork the session
|
||||
dispatches over) is not consulted. Meanwhile `PeerCompositeEnv`
|
||||
resolves **connections before base** (`src/registry/env.rs:230-245` —
|
||||
session, then `connection_order`, then base), and `compose_root_env`
|
||||
attaches the dispatching connection's overlay
|
||||
(`dispatch.rs:207-214`).
|
||||
|
||||
Consequence: a peer announces an op named `fs/readFile` (or any name
|
||||
the serving side has registered — `services/list` itself is fair
|
||||
game). The registration lands in the overlay (forced `Internal`,
|
||||
`FromCall` — both per spec). From then on, every handler
|
||||
**wire-dispatched from that peer's connection** that nested-composes
|
||||
that name via `ctx.env` resolves to the peer's forwarding stub instead
|
||||
of the serving side's own op. The forced `Visibility::Internal` does
|
||||
not help here — it blocks wire invocation, not `env.invoke`
|
||||
(`OverlayOperationEnv` gates on `AccessControl` only,
|
||||
`connection.rs:749-836`; the composed child context is `internal:
|
||||
true` by design).
|
||||
|
||||
Concretely: a hub handler processing peer A's request composes
|
||||
`fs/readFile` expecting *its own* registry op (with the deployment's
|
||||
`scoped_env`, capabilities, and ACL); it silently gets peer A's stub —
|
||||
peer A chooses where the call goes and what it returns. Composition
|
||||
authority (ADR-018) is decided by the composing handler's *deployer*;
|
||||
a same-name peer registration silently rewrites it. The effect is
|
||||
scoped to handlers whose root context is that connection's
|
||||
(`compose_root_env` attaches that connection's overlay), which bounds
|
||||
the blast radius — but that is exactly the flagship F-05 flow.
|
||||
|
||||
**Fix (Unit 2):** decide the collision policy and record it in the
|
||||
ADR-022 amendment. Recommended: `op_register_handler` also rejects
|
||||
names registered on the serving registry (pass the fork — or a
|
||||
name-set closure — into the handler alongside the connection, the
|
||||
same way `install_bootstrap_discovery` closes over its registry);
|
||||
`ALREADY_EXISTS` for base collisions regardless of `replace` (the
|
||||
reconnect path needs to re-announce *peer* ops, not to overwrite the
|
||||
deployment's). The alternative — changing `PeerCompositeEnv` to
|
||||
resolve base before connections — would break `from_call`'s
|
||||
namespace-prefixed imports (prefixed names don't collide) is not
|
||||
needed for that, but would change long-decided layering semantics; the
|
||||
registration-side gate is the cheaper, narrower door.
|
||||
|
||||
## G-04 [minor] — `resource_id_path` does not survive the spec wire round-trip
|
||||
|
||||
**Verified:** YES. `spec_to_json_pub` serializes
|
||||
name/namespace/op_type/visibility/schemas/error_schemas/access_control
|
||||
(+ `channel_open`/`publish_schema` markers;
|
||||
`src/registry/discovery.rs:211-234`) — `resource_id_path` is not
|
||||
serialized. `rebuild_spec_for` cannot parse it
|
||||
(`src/client/from_call.rs:209-286`), and the field exists on
|
||||
`OperationSpec` (`src/registry/spec.rs:190`). An announced (or
|
||||
`from_call`-imported) op that declares ownership-scoped resource
|
||||
extraction silently loses it; the rebuilt spec's ACL checks run with
|
||||
`resource_id: None`.
|
||||
|
||||
This is a pre-existing gap in the `from_call` import shape, not
|
||||
introduced by `f84d214` — but `op/register` makes it load-bearing for
|
||||
a second wire surface (peer-announced specs) that explicitly promises
|
||||
"the serializable parts" of a registration. Note `namespace` *is*
|
||||
serialized but `rebuild_spec_for` ignores it in favor of the
|
||||
`namespace_prefix` parameter — consistent for `op/register`
|
||||
(`replace`/re-announce uses `None`), worth a comment either way.
|
||||
|
||||
**Fix (Unit 3):** add `resource_id_path` to both halves of the
|
||||
round-trip plus a round-trip test. Additive optional field in the
|
||||
`services/schema` JSON shape — no existing consumer breaks.
|
||||
|
||||
## G-05 [minor] — `install_bootstrap_discovery` registers `services/list-peers`; the ADR-022 amendment's bootstrap set doesn't name it
|
||||
|
||||
**Verified:** YES. `install_bootstrap_discovery` registers
|
||||
`services/list`, `services/list-peers`, and `services/schema`
|
||||
(`src/registry/discovery.rs:290-313`; `list-peers` at `:300`). The
|
||||
ADR-022 amendment's bootstrap set lists exactly three ops —
|
||||
`services/list`, `services/schema`, `op/register`
|
||||
(`022-…contract.md:380-393`). Review 004's remediation log says
|
||||
"list-peers" too; the ADR text was never updated.
|
||||
|
||||
Consequence: none at runtime (installing a fourth op is strictly
|
||||
additive, and `services/list-peers` is what makes F-05's
|
||||
"peer-announced ops are discoverable" true). It is a
|
||||
doc/spec-consistency drift on a set the ADR declares *"closed."*
|
||||
|
||||
**Fix (Unit 3):** add `services/list-peers` to the ADR-022
|
||||
amendment's bootstrap-op list (recommended — `from_call`-import
|
||||
discovery already relies on it) or stop installing it; one line
|
||||
either way.
|
||||
|
||||
---
|
||||
|
||||
# Non-findings (verified correct, recorded to bound the re-review)
|
||||
|
||||
- **The fork surface (F-02/F-03) is solid.** Lock discipline is
|
||||
correct: `registration()` clones under a read guard and drops it
|
||||
before handler invocation (`registration.rs:190-192`), so
|
||||
self-referential discovery handlers cannot deadlock their own
|
||||
registry; `register` takes the two maps' write locks sequentially
|
||||
and never across an `await`. `fork()` deep-copies both maps
|
||||
(handlers are `Arc` closures — cheap, and the F-03 constraint that
|
||||
closures must carry is met); validators carry; fork independence is
|
||||
tested both directions; `OperationRegistryBuilder::from_registry`
|
||||
seeds the builder path.
|
||||
- **`install_bootstrap_discovery` (F-06) is correct** — handlers
|
||||
closed over the same `Arc` they're registered on, so post-install
|
||||
per-session registrations are visible at call time; ACL filtering
|
||||
stays per-caller; the fork gate
|
||||
(`fork_registry_open_op_resolves_and_is_discoverable`) exercises
|
||||
exactly the review-004 acceptance shape.
|
||||
- **`serve_single_stream`'s pending-resolution arms match the two
|
||||
half-loops they compose.** Frame by frame against
|
||||
`run_loop_single_stream` (`dispatch.rs:765-905`) and
|
||||
`dispatch_envelope` (`connection.rs:717-741`): responded/completed/
|
||||
error resolve pendings; aborted tries both tables (in-flight sink
|
||||
aborts, then the pending cascade via `handle_abort`); published
|
||||
routes inbound sinks with the same validation/keep semantics; teardown
|
||||
(fail_all + sink drop + sweeper abort) matches. The direction
|
||||
disambiguation by table membership (documented at
|
||||
`dispatch.rs:940-966`) is correct as written — G-01 is *not* a
|
||||
frame-routing bug; the arms are right, the loop's scheduling is the
|
||||
defect.
|
||||
- **The pure-consumer default is unchanged.** `from_connection`
|
||||
delegates with `None` and keeps the resolution-only read pump; no
|
||||
behavior change for existing callers.
|
||||
- **`op/register`'s DTO and unit semantics are clean** — one spec
|
||||
serialization on the wire (`spec_to_json` shape), forced
|
||||
`Internal`/`FromCall` on landing (unit-tested), `replace` semantics
|
||||
tested, `ALREADY_EXISTS` collision gate tested (against the
|
||||
overlay — see G-03 for the gap).
|
||||
- **The alkhttp cross-repo claims check out.** `open-questions.md`
|
||||
OQ-05 and ADR-048's re-point are present in that repo at `5b62307`.
|
||||
- **No non-English text reached the tree.** The remediation session's
|
||||
language slip (reported anecdotally) did not land in any code,
|
||||
doc, or metadata: a CJK-range regex sweep over all `.rs`/`.md`/
|
||||
`.toml`/`.json` in the repo returns zero matches at `f84d214`.
|
||||
- **Gates reproduce.** All commands in Baseline verification pass at
|
||||
the review tree, matching the remediation log's claims
|
||||
(581 default / 598 all-features).
|
||||
|
||||
---
|
||||
|
||||
# Remediation plan
|
||||
|
||||
Sequenced by dependency. All units are alkcall work; Unit 4 (alkhttp
|
||||
wiring) stays downstream and should **not** start before Unit 1 —
|
||||
alkhttp's serving consumers would compose over the same connection
|
||||
and hit G-01 immediately.
|
||||
|
||||
## Unit 1 — Concurrent serving loop + a stub-exercising gate (G-01, G-02)
|
||||
|
||||
- Rework `serve_single_stream`'s `EVENT_REQUESTED` arm: spawn the Once
|
||||
dispatch and the Sub pump (the Sink arm's existing pattern,
|
||||
generalized; `SharedFrameWriter` serializes frames; track handles
|
||||
for teardown). Apply the same rework to `run_loop_single_stream` or
|
||||
extract the shared loop.
|
||||
- Add the G-02 gate: announce → wire-dispatched hub handler composes
|
||||
the announced op via nested composition → resolves from the
|
||||
consumer. This is the removed probe, productized; it is the
|
||||
acceptance test for G-01.
|
||||
- Optional: an interleaved-directions phase on the F-04 gate
|
||||
(outbound call resolving while a Sub is being served).
|
||||
- Gate: the probe recipe (Verification log) resolves in < 1s; no
|
||||
sweeper evictions in the gates.
|
||||
|
||||
## Unit 2 — `op/register` collision policy (G-03)
|
||||
|
||||
- `op_register_handler` gains a serving-registry name-set (closure or
|
||||
`Arc<OperationRegistry>`); base-registry name collisions reject
|
||||
with `ALREADY_EXISTS` regardless of `replace`.
|
||||
- ADR-022 amendment: record the collision policy (peer-announced ops
|
||||
may collide with peer-announced ops — `replace` governs; never with
|
||||
the serving side's own registrations).
|
||||
- Gates: announcing a base-registered name (External *and* Internal)
|
||||
fails loudly; announcing a distinct name still lands; nested
|
||||
composition of a base op is unaffected by an unrelated announce.
|
||||
|
||||
## Unit 3 — Round-trip completeness + doc alignment (G-04, G-05)
|
||||
|
||||
- `resource_id_path` through `spec_to_json_pub` + `rebuild_spec_for`
|
||||
+ round-trip test.
|
||||
- ADR-022 bootstrap list gains `services/list-peers` (or drop it from
|
||||
the installer; recommend adding).
|
||||
|
||||
---
|
||||
|
||||
## Verification log (this pass)
|
||||
|
||||
- All gates in Baseline verification reproduced at tree `f84d214`
|
||||
(clean working tree; the probe was added, run, and removed —
|
||||
`git status` verified clean after removal).
|
||||
- G-01 verified by code trace (the four steps above, each line
|
||||
read at `f84d214`) **and** empirically: probe
|
||||
`probe_hub_handler_composes_peer_announced_op` (in
|
||||
`src/channels/client.rs#[cfg(test)]`, since removed) — hub registry
|
||||
carries `op/register` + `hub/compose` (whose handler invokes the
|
||||
connection overlay's registration for the announced op, the shape
|
||||
`PeerCompositeEnv` → `OverlayOperationEnv` resolution produces);
|
||||
consumer announces `consumer/exec` then calls `hub/compose`.
|
||||
8s-timeout run: `Elapsed` (no progress). 45s-cap run: resolved at
|
||||
**30.0007s** with `CallError::TIMEOUT` (retryable) — the
|
||||
`DEFAULT_CALL_TIMEOUT` sweeper eviction, not live resolution.
|
||||
- The existing gates' blind spot verified by reading both e2e gates'
|
||||
call directions: `serving_loop_hub_to_consumer_call_resolves`
|
||||
(`client.rs:1373-1399`) and
|
||||
`op_register_announce_then_hub_call_routes_back_to_consumer`
|
||||
(`client.rs:1529`) — the latter's `accept_conn.call("consumer/exec")`
|
||||
crosses the wire to the consumer's local registry; the forwarding
|
||||
stub is unreachable from it.
|
||||
- G-03 verified by reading the collision gate (`op_register.rs:142`)
|
||||
against `PeerCompositeEnv::invoke_with_policy`'s resolution order
|
||||
(`env.rs:230-245`) and `compose_root_env`'s attach
|
||||
(`dispatch.rs:207-214`).
|
||||
- G-04 verified by field audit: `OperationSpec`'s fields
|
||||
(`spec.rs:175-206`) vs `spec_to_json_pub` (`discovery.rs:211-234`)
|
||||
vs `rebuild_spec_for` (`from_call.rs:209-286`).
|
||||
- G-05 verified against `discovery.rs:290-313` and ADR-022
|
||||
amendment's set (`022-…contract.md:380-393`).
|
||||
- Frame-arm equivalence of `serve_single_stream` vs the two half-loops
|
||||
verified read-through (Non-findings).
|
||||
- alkhttp cross-repo claims verified in `/workspace/@alkdev/alkhttp`
|
||||
at `5b62307` (OQ-05 `open-questions.md:102-112`; ADR-048
|
||||
`decisions/048-…md:19-25`).
|
||||
- CJK sweep: no CJK-range codepoints in any `.rs`/`.md`/`.toml`/
|
||||
`.json` under the repo at `f84d214`.
|
||||
Reference in new issue
Block a user