fix(review 005 Unit 2): op/register serving-registry collision gate (G-03)

- op_register_handler takes the serving registry alongside the
  connection and rejects announced names that collide with the serving
  side's own registrations (ALREADY_EXISTS regardless of replace).
  Peer-announced ops may collide with peer-announced ops (replace
  governs, the reconnect path) but never shadow the deployment's own
  ops: the connection overlay resolves before base in PeerCompositeEnv,
  so an unscreened same-name announce would silently rewrite what a
  wire-dispatched handler's ctx.env.invoke resolves. Composition
  authority (ADR-018) stays with the deployer.
- ADR-022 amendment (2026-09-04): collision policy recorded in the
  2026-09-03 amendment's op/register section (rationale + visibility
  irrelevance); status line notes the sub-amendment.
- Gates: base-External collision rejected even with replace (overlay
  stays clean, serving registration untouched); Internal base op
  equally protected; overlay/overlay collisions still follow replace;
  nested composition of a base op resolves the serving side's own op
  after an unrelated announce (real compose_root_env env shape).
- PeerCompositeEnv resolution order deliberately unchanged.

Verification: cargo test 587 / --all-features 604, clippy
(all-targets, all-features, wasm32) clean, fmt clean, doc clean.

Refs docs/reviews/005-...md (G-03; Unit 3 open).
This commit is contained in:
glm-5.3-flash committed 2026-09-04 09:40:11 +00:00
1 parent 1cbb7c6536
commit 23c9b28c6b
4 files changed
+330 -11

No files matched your search

@@ -2,7 +2,7 @@
## Status
Accepted (amended 2026-06-26, 2026-07-13, and 2026-07-16 — see "Amendments" below; the 2026-07-16 amendment per ADR-045 §5 removes `CallClient::connect`; amendment 2026-09-03 — the bootstrap-op set and the connect-side serving loop, see "Amendment (2026-09-03)" below)
Accepted (amended 2026-06-26, 2026-07-13, and 2026-07-16 — see "Amendments" below; the 2026-07-16 amendment per ADR-045 §5 removes `CallClient::connect`; amendment 2026-09-03 — the bootstrap-op set and the connect-side serving loop, see "Amendment (2026-09-03)" below; amendment 2026-09-04 — the `op/register` collision policy, in that amendment's "Collision policy" paragraph)
## Context
@@ -443,6 +443,21 @@ unless `replace: true` (the reconnect path re-announces). The
overlay dies with the connection (Layer 2), so reconnect re-announce
is naturally scoped.
Collision policy (amended 2026-09-04, review 005 G-03): a
peer-announced op may collide with other *peer-announced* ops on the
same connection (`replace` governs) but **never** with the serving
side's own registrations — a name present on the serving registry
rejects with `ALREADY_EXISTS` regardless of `replace`. The connection
overlay shadows the base registry in `PeerCompositeEnv` (connections
resolve before base, ADR-024 §1), so an unscreened same-name announce
would silently rewrite what a wire-dispatched handler's
`ctx.env.invoke` resolves for any name the deployment registered:
composition authority (ADR-018) belongs to the composing handler's
deployer, not the connected peer. Visibility is irrelevant to this
gate (`Internal` ops are as shadowable as `External` —
`OverlayOperationEnv` gates on `AccessControl`, not visibility; the
composed child is `internal: true` by design).
The envelope kind set stays closed at six — bootstrap ops over channel
0 are the door (AGENTS.md §7 allows adding kinds; none is needed).