From 7b06dc7aac5de034657b87e8ad5d0f22ebe5c750 Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Sun, 20 Sep 2026 08:31:47 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20review=20002=20doc-sync=20=E2=80=94=20D?= =?UTF-8?q?-1=20schema=20bounds=20in=20wire.md=20+=20D-2=20ADR-007=20oneOf?= =?UTF-8?q?=20erratum?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - D-1: wire.md's Direct Op + Forwarded Op sections record the shipped schema constraints (port bounds, additionalProperties: false per branch, listen minimum: 1) and the registry-side gate ordering - D-2: ADR-007 §2 corrected in place + a dated erratum (oneOf was wrong-shaped; validation is registry-side, not establisher-time); wire.md's mirrored sentence corrected Verified: cargo doc --no-deps clean; cargo fmt --check --- .../decisions/007-direct-open-op.md | 34 ++++++++++++++-- docs/architecture/wire.md | 39 ++++++++++++++++--- tasks/tunnels/review-002-doc-sync.md | 28 ++++++++++++- 3 files changed, 90 insertions(+), 11 deletions(-) diff --git a/docs/architecture/decisions/007-direct-open-op.md b/docs/architecture/decisions/007-direct-open-op.md index ac10635..86f686a 100644 --- a/docs/architecture/decisions/007-direct-open-op.md +++ b/docs/architecture/decisions/007-direct-open-op.md @@ -79,10 +79,13 @@ amendment 3). - `unix` → `{ "path": }` — the socket path on the producer's filesystem. - The schema pins both fields required; the target sub-schema is - per-substrate (`oneOf` on the sibling `substrate` value, validated at - establisher time — see Consequences). Malformed targets are the - typed `invalid_input`-class failure; **`unknown_resource` can never - fire on the direct op** (there is no registry lookup). + per-substrate (an `allOf` of two `if`/`then` branches keyed on the + sibling `substrate` value, validated **registry-side** — the schema + gate runs before the establisher; the establisher's serde parse + re-checks as the backstop; see the Erratum below and Consequences). + Malformed targets are the typed `invalid_input`-class failure; + **`unknown_resource` can never fire on the direct op** (there is no + registry lookup). - Encoding choice over the RFC-1928 ATYP byte string: the ATYP form is SOCKS5's wire carrier and alksocks maps `TargetAddr` → this JSON trivially (`to_target_addr` decomposes to host/port at the adapter), @@ -177,6 +180,29 @@ sentence (also ADR-006 amendment). `open_direct` — the graduation's §4 table, now with the stand-in dissolved. +## Erratum (2026-09-20, review 002 D-2) + +§2's original wording said the target sub-schema is "`oneOf` on the +sibling `substrate` value, validated at establisher time". Both +halves of that sentence were stale against the shipped schema +(the decision itself was not — the code is the wire-stable side and +is correct): + +1. **The shipped structure is an `allOf` of two `if`/`then` + branches**, not `oneOf`. `oneOf` of full-target-schemas would + actually be wrong here: a `unix`-substrate open would need to FAIL + the `tcp` branch, and plain `oneOf` on sibling-conditioned + subschemas is awkward (exactly-one-branch-matches semantics does + not compose with the base `properties`/`required`); + `if`/`then` composes correctly with them. +2. **Validation is registry-side, not establisher-time.** The + registry's `input_schema` gate runs BEFORE the establisher + (`malformed_target_is_schema_class_and_leaves_no_channel` asserts + the establisher's dial never runs on a malformed target); the + establisher's serde parse re-checks as the backstop. §2's text + above is corrected in place; wire.md §The Direct Op carries the + same corrected sentence. + ## References - `docs/research/tunnels-graduation.md` §2 (the ask, options, and the diff --git a/docs/architecture/wire.md b/docs/architecture/wire.md index 0359563..54b2eec 100644 --- a/docs/architecture/wire.md +++ b/docs/architecture/wire.md @@ -1,6 +1,6 @@ --- status: draft -last_updated: 2026-09-18 (the graduation wire surface: direct + forwarded ops, `bound`/`listen` reply fields — ADR-007/008 as amended) +last_updated: 2026-09-20 (review 002 D-1/D-2 sync: the params schemas' port bounds, `additionalProperties: false` gates, `listen` `minimum: 1`, and the registry-side gate ordering recorded; ADR-007's oneOf wording corrected to the shipped allOf/if-then) --- # alktunnels — Wire Format @@ -93,9 +93,24 @@ same establishment phase and wrapper as `…/sub`. Scope gate: ssh `-D` semantic); - `unix` → `{ "path": }`. - `input_schema` pins both required; the target sub-schema is - per-substrate, validated at establisher time. Malformed targets are - the `invalid_input`-class failure; **`unknown_resource` can never - fire on the direct op** (no registry lookup). + per-substrate — an `allOf` of two `if`/`then` branches keyed on the + sibling `substrate` value, validated **registry-side** (the schema + gate runs before the establisher — the behavior + `malformed_target_is_schema_class_and_leaves_no_channel` pins; the + establisher's serde parse re-checks as the backstop). Malformed + targets are the `invalid_input`-class failure; **`unknown_resource` + can never fire on the direct op** (no registry lookup). +- Schema bounds (wire-stable — the target sub-schema is part of the + one-way door, ADR-007 §"Wire-stable"): each branch's target object + carries `"type": "object"` and `"additionalProperties": false` — + - `tcp`/`udp` → `{ "host": {"type": "string"}, "port": {"type": + "integer", "minimum": 0, "maximum": 65535} }`, both required; + - `unix` → `{ "path": {"type": "string"} }`, required. + + The `additionalProperties: false` gate is what makes a cross-shape + target (a `unix` open carrying `host`) fail the registry's + `INVALID_INPUT` class *before* the establisher — not a serde-level + quirk. ### Reply / errors @@ -156,12 +171,26 @@ Scope gate (opener side): `["tunnel:forwarded"]` - `listen`: integer > 0, required — the correlation token from the listen open's `listen` reply field (ADR-008 Amendment 1; the producer-minted token, relay-transparent). The opener correlates - the accept to its waiting listener session by matching it. + the accept to its waiting listener session by matching it. The + schema pins `"minimum": 1` and the serde type pins it as the + backstop (a `listen: 0` on the wire is a malformed open, rejected + at parse time — never silently accepted). - `substrate`: string, required, enum — the listen tunnel's substrate; shapes the forwarded channel's data-plane framing. - `peer`: object, required — the accepted connection's remote address, substrate-shaped (`{host, port}` / `{path}`). Reply#2-class fidelity's carrier (ask #2). +- Schema bounds (wire-stable, mirroring the direct op's target + sub-schema): the per-substrate `peer` sub-schema is an `allOf` of + two `if`/`then` branches keyed on the sibling `substrate`, each + branch's object carrying `"type": "object"` and + `"additionalProperties": false` — + - `tcp`/`udp` → `{ "host": {"type": "string"}, "port": {"type": + "integer", "minimum": 0, "maximum": 65535} }`, both required; + - `unix` → `{ "path": {"type": "string"} }`, required. + + Malformed peers fail the registry's schema gate before the + opener-side handler runs. ### Reply / errors diff --git a/tasks/tunnels/review-002-doc-sync.md b/tasks/tunnels/review-002-doc-sync.md index 22d8c2e..6bc82db 100644 --- a/tasks/tunnels/review-002-doc-sync.md +++ b/tasks/tunnels/review-002-doc-sync.md @@ -1,7 +1,7 @@ --- id: tunnels/review-002-doc-sync name: "D-1 + D-2 — sync wire.md's schema bounds + ADR-007's oneOf→if/then + the establisher-time→registry-gate sentence" -status: pending +status: completed depends_on: [] scope: narrow risk: low @@ -93,4 +93,28 @@ gate-ordering correction in wire.md §The Direct Op's ## Notes -> Agent fills during implementation. \ No newline at end of file +> Agent fills during implementation. + +## Implementation Notes (2026-09-20) + +- **D-1 (wire.md §The Direct Op + §The Forwarded Op)**: both sections + now record the exact shipped schema constraints — the per-branch + target/peer objects (`type: object`, `additionalProperties: false`, + `port` bounds `minimum: 0`/`maximum: 65535`, the `unix` `path` + branch) and the forwarded `listen` `minimum: 1` + its serde-pin + backstop — with the gate-ordering sentence (registry-side schema + gate before the establisher, serde backstop) and the + cross-shape-INVALID_INPUT behavior the integration test pins. No + second source existed for these bounds (bast.md covers only the + data-plane codec); wire.md now is the complete record. +- **D-2 (ADR-007 §2)**: the stale sentence corrected in place + (`oneOf` → the shipped `allOf` of two `if`/`then` branches; + "validated at establisher time" → registry-side gate + serde + backstop), plus a dated **Erratum** section documenting why `oneOf` + would actually be wrong (exactly-one-branch-matches does not + compose with the base `properties`/`required`) and citing the + pinning test. wire.md §The Direct Op's mirrored sentence corrected + in the same edit. ADR-008 was checked and needs no change (it never + stated the `oneOf`/establisher-time claim). +- Verification: `cargo doc --no-deps` clean (0 warnings); + `cargo fmt --check` clean. \ No newline at end of file