docs(tasks): decompose wave 3 — the server mappings
Six implementation tasks + the gate under tasks/implementation/, chained sequentially (the mappings replace stubs in the same Handler impl and share the decline-matrix test binaries): - w3-seam-config: the serve-config's per-feature seam handles (alktty backends/ownership/selector; the alkgit quartet/pipeline/ push-options flag) + the optional sibling deps — wave 3's first course correction to the wave-1 config surface - w3-decline-tracing: the wave-2 gate's booked finding — the decline/serve-path tracing vocabulary, landed before the mappings - w3-git-mapping: the full exec grammar replaces the wave-2 probe + the serve_duplex_resolved dispatch + the store-and-take handoff - w3-tty-session: the translation bridge + the exit-derivation contract (rules 1-6, the signum table) - w3-tunnel-direct: the route-1 bridge (accept only after the fabric open succeeds) + set_identity propagation + the capacity-across- fabric-window mechanics - w3-tunnel-listen: the -R listen flow + the forwarded-tcpip data leg (the POC-untested leg; the stop-and-book provision) - review-wave-3: the gate The plan carries the wave-3 decomposition record with four interpretations flagged for the gate (the serve-config course correction, the already-discharged server-side sftp bullet, the w3-tunnel-listen open mechanics, the booked-items' wave-3 homes). taskgraph validate: 26 tasks, clean. Sibling pins verified against crates.io at decomposition time: alktty 0.8.1 / alkgit 0.1.0 / alktunnels 0.4.1 / alkcall 0.10.1.
This commit is contained in:
1 parent
5b2654f492
commit
d1f755f2d9
8 files changed
+849
-1
No files matched your search
@@ -45,7 +45,7 @@ mappings ∥ client direction) → validation & release.
|
||||
|---|---|---|---|
|
||||
| [1](#wave-1--foundations) | Manifest landing (russh pin, feature graph); error model; config surface (serve-config + dial-config + `Limits`); vault-backed key sources; host-key policy seam; fingerprint; test doubles | — | decomposed |
|
||||
| [2](#wave-2--the-server-stack) | `SshAdapter::handle` mount + `Config` construction; the auth bridge; parse-only dispatch + fail-closed decline core; spawn-and-return plumbing; bounded resources; loopback harness | wave 1 | decomposed |
|
||||
| [3](#wave-3--server-mappings) | session → alktty (translation bridge + exit derivation); git → alkgit (exec grammar + dispatch); tunnel → alktunnels route 1; sftp placeholder declines | wave 2 | pending |
|
||||
| [3](#wave-3--server-mappings) | session → alktty (translation bridge + exit derivation); git → alkgit (exec grammar + dispatch); tunnel → alktunnels route 1; sftp placeholder declines | wave 2 | decomposed |
|
||||
| [4](#wave-4--client-direction) | Dial surface; op rows (exec/pty, direct-tcpip, git exec); the `-R` leg (listen + acceptor registry); lifecycle primitives | wave 1 | pending |
|
||||
| [5](#wave-5--validation--release) | Decline-matrix contract suite; real-tool e2e; fuzzing; docs; **the publish** | waves 3 + 4 | pending |
|
||||
|
||||
@@ -288,6 +288,66 @@ wave 5's:
|
||||
Wave 3 decomposes after the wave-2 gate, absorbing whatever it
|
||||
corrects.
|
||||
|
||||
**Decomposition record** (2026-10-28, after the wave-2 gate closed
|
||||
green): wave 3 decomposed into six task files under
|
||||
`tasks/implementation/` plus the gate. Shape: `w3-seam-config` first
|
||||
(the serve-config's per-feature seam handles + the optional
|
||||
`alktty`/`alkgit` deps — see the interpretations — the mappings
|
||||
dispatch against them, so it lands before the mappings); then
|
||||
`w3-decline-tracing` (the wave-2 gate's booked finding: the decline/
|
||||
serve-path event vocabulary, landed **before** the mappings so they
|
||||
inherit a uniform shape); then the three mapping branches
|
||||
deliberately sequential — `w3-git-mapping` (the full grammar replaces
|
||||
the wave-2 probe + the `serve_duplex_resolved` dispatch + the
|
||||
store-and-take handoff it lands first for the session task to reuse),
|
||||
`w3-tty-session` (the translation bridge + the exit-derivation
|
||||
contract — the biggest single-row surface), `w3-tunnel-direct` (the
|
||||
POC-proven route-1 bridge leg + identity `set_identity` propagation),
|
||||
and `w3-tunnel-listen` (the `-R` listen flow + `forwarded-tcpip`
|
||||
data leg — the POC-untested leg, sized with the stop-and-book
|
||||
provision); and `review-wave-3` (the gate) depending on all six. As
|
||||
with wave 2, the branch DAG is sequential: the three mappings replace
|
||||
stubs in the same `Handler` impl and share the decline-matrix test
|
||||
binaries, so no two tasks hold them in parallel — the branches are
|
||||
parallel *conceptually* (independent seams), sequential
|
||||
*logistically*.
|
||||
|
||||
Interpretations recorded (flagged for the wave-3 gate):
|
||||
|
||||
- **The serve-config extension is wave 3's first course correction to
|
||||
the wave-1 config surface** — the assembly-supplied alktty/alkgit
|
||||
seam handles the mappings' seam signatures take (the tty backends
|
||||
map + selector + ownership provider; the alkgit backend quartet +
|
||||
pipeline semaphore + push-options flag) were never carried by the
|
||||
wave-1 config bullet, and `w3-seam-config` lands them feature-gated
|
||||
with the optional sibling deps (`alktty = "0.8.1"`, `alkgit =
|
||||
"0.1.0"` — crates.io-verified at decomposition) before the
|
||||
mappings; `alktunnels = "0.4.1"` still lands with its first
|
||||
consuming code (`w3-tunnel-direct`) to avoid a dead entry. The
|
||||
unset-declines posture extends to the new handles (unset → the
|
||||
owned rows decline even with the feature on).
|
||||
- **The server-side sftp bullet is already discharged** — the OQ-13
|
||||
decline rows landed with `w2-dispatch-decline-core` (every subsystem
|
||||
name declines in every build) and are already contract-tested per
|
||||
build in `tests/dispatch_core.rs`; no wave-3 task exists for it —
|
||||
the client-side placeholder folds into wave 4's acceptor/op-row
|
||||
work and the wave-5 matrix covers both rows explicitly.
|
||||
- **The `-R` listen flow carries the wave-3 gate's biggest open** —
|
||||
the fabric-side inbound-forwarded mechanics (who dials the
|
||||
forwarded op at the door, whether the assembly-supplied
|
||||
`Arc<ChannelClient>` composition can carry the door-side accept or
|
||||
the serve-config's tunnel handle must grow) is decided in
|
||||
`w3-tunnel-listen` against alkcall 0.10.1 / alktunnels 0.4.1's
|
||||
published surfaces; if the topology does not close, the task stops
|
||||
and books it for the gate — nothing is silently forked or absorbed.
|
||||
- **The wave-2 gate's three booked items all have wave-3 homes** — the
|
||||
decline-path tracing task (`w3-decline-tracing`), the forwarded-
|
||||
tcpip acceptor vocabulary (`w3-tunnel-listen`, with the client-side
|
||||
accept hook landing in the harness), and the deferred identity-
|
||||
landing assertion (each mapping asserts the resolved identity
|
||||
reaches its seam; the tunnel branch additionally propagates it via
|
||||
`set_identity` — auth.md §Server direction step 4).
|
||||
|
||||
## Wave 4 — Client direction
|
||||
|
||||
The door outward (independent of wave 3 — shares only wave 1's
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
id: review-wave-3
|
||||
name: Wave 3 gate — the server-mappings review
|
||||
status: pending
|
||||
depends_on: [w3-seam-config, w3-decline-tracing, w3-git-mapping, w3-tty-session, w3-tunnel-direct, w3-tunnel-listen]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: phase
|
||||
level: review
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
The wave-3 review gate. The server mappings are the crate's spine
|
||||
landed in wire-capable form — the wave-4 client direction reuses the
|
||||
same grammar/rows pointed upstream, wave 5 builds the full matrix on
|
||||
these rows, and the published crate freezes this surface. The gate
|
||||
reads the landed mappings against the architecture line by line:
|
||||
|
||||
- **mapping.md line-by-line** — each of the spine's server rows
|
||||
(session/pty/shell/pipe; git exec; direct-tcpip;
|
||||
direct-streamlocal; forwarded-tcpip; the global listen rows; the
|
||||
request-level table) read against the landed code; the §exit
|
||||
derivation contract rules 1–6 verified in code + rows; the decline
|
||||
matrix green **per feature build** through the harness (including
|
||||
the unset-field rows — feature on, handle unset).
|
||||
- **ADR-006** — route-1 bridge (accept only after the fabric open
|
||||
succeeds; `ConnectFailed` on failure), exec-only git (no subsystem
|
||||
dispatch anywhere in the grammar), parse-only dispatch still
|
||||
structural (no request-less serving), spawn-and-return over the
|
||||
**real** serving paths (the wave-2 constraint re-pinned over
|
||||
mappings, not stubs).
|
||||
- **ADR-003** — the per-build matrices; honest advertisement
|
||||
unchanged (an unfeatured type declines; the sftp feature still
|
||||
gates nothing, its rows still decline in every build — OQ-13);
|
||||
x11/auth-agent never-feature rows untouched.
|
||||
- **Auth.md / identity** — the identity ride observable at every seam
|
||||
(alktty/alkgit params; the channels connection for tunnels),
|
||||
`set_identity` once-only mechanics recorded; the parked wave-2
|
||||
`auth_succeeded` item verified discharged; no username anywhere.
|
||||
- **OQ resolutions in code** — OQ-08 (unset-declines on shell/wrapper
|
||||
rows), OQ-09 (env declined), OQ-10 (derivation rules + the
|
||||
PTY-path fidelity limit documented), OQ-11 (runtime-Unix gates
|
||||
compile-everywhere + clean off-Unix declines), OQ-13 (sftp rows
|
||||
unchanged).
|
||||
- **Bounded resources** — no new unbounded shape: the cap across the
|
||||
fabric window (release-on-failure pinned), the listener bookkeeping
|
||||
bounded, the control-row surfaces bounded, the bridge adapters
|
||||
bounded.
|
||||
- **Tracing** — the uniform event vocabulary across all landed
|
||||
serve/decline paths; the safety posture held (no secrets, no
|
||||
username).
|
||||
- **The smokes** — the three real-tool postures recorded honestly
|
||||
(required/conditionally-skipped with reason); nothing silently
|
||||
green.
|
||||
- **Wave-2 gate's booked items** — every one discharged or explicitly
|
||||
re-booked (decline tracing = landed; acceptor vocabulary = landed
|
||||
in `w3-tunnel-listen`; identity landing = discharged; the
|
||||
inherited-auth-agent-open watch item = unchanged or re-read at any
|
||||
pin touch).
|
||||
- **Docs honesty** — module docs name what each replaced stub now
|
||||
is, what remains wave-4/5 material, and any new upstream notes
|
||||
(portable-pty's PTY-path exit shape; the `take_call_connection`
|
||||
semantics reading).
|
||||
|
||||
Verdict: green (wave 4 decomposes, absorbing corrections) or findings
|
||||
booked (remediation before wave 4 decomposes).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Every ADR/mapping surface above read and confirmed (or
|
||||
corrected with the correction landed)
|
||||
- [ ] The decline matrix verified per build through the harness;
|
||||
the derivation contract verified against its rules; the
|
||||
spawn-and-return constraint re-pinned over real serving paths
|
||||
- [ ] Full verification set green (`cargo test`, `--all-features`,
|
||||
clippy ×2 `-D warnings`, fmt, `cargo doc --no-deps`)
|
||||
- [ ] `taskgraph validate` clean
|
||||
- [ ] Verdict recorded; wave 4 decomposition unblocked or findings
|
||||
booked
|
||||
|
||||
## References
|
||||
|
||||
- docs/plans/implementation.md (wave 3 section + this gate's role)
|
||||
- docs/architecture/mapping.md, auth.md, client.md (the mirror),
|
||||
overview.md, open-questions.md, ADRs 002/003/004/005/006
|
||||
- docs/research/poc-3-mapping-bakeoff.md (stages A/C/D — the evidence
|
||||
the contract tests re-land)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled at gate time.
|
||||
@@ -0,0 +1,73 @@
|
||||
---
|
||||
id: w3-decline-tracing
|
||||
name: Wave 3 — decline-path tracing (the wave-2 gate's booked finding)
|
||||
status: pending
|
||||
depends_on: [w3-seam-config]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: component
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Land the wave-2 review gate's booked finding: observability on the
|
||||
decline paths. `tracing` rides the manifest per the ADR-002 toolkit but
|
||||
so far nothing in `src/` emits — a request-level decline's "reason" is
|
||||
today only the routing decision documented per build. The real serving
|
||||
paths land in this wave's mapping tasks, where serve/decline tracing
|
||||
matters — so the event **vocabulary** lands first and the mappings
|
||||
inherit it.
|
||||
|
||||
- **The family-convention check first** — before choosing the event
|
||||
shape, read the family's established tracing posture (alktty /
|
||||
alkgit / alktunnels / alkcall `src/`: levels, event/field naming,
|
||||
what gets emitted on error and decline paths) and adopt it — no
|
||||
alkssh-private dialect; record what was read and chosen.
|
||||
- **The event vocabulary** — the deciding context on every decline:
|
||||
row + feature build + channel id (+ the decline class — open-level
|
||||
vs request-level vs serving-path, and where applicable the failure
|
||||
shape carried). The mapping tasks then emit at their sites.
|
||||
- **Instrument what exists now** — the open-level declines
|
||||
(unfeatured / never-feature / cap-exceeded), the request-level
|
||||
capability declines (`subsystem`/`env`/`x11`/`agent`, the
|
||||
unfeatured-parse routes), the seam-stub serving declines, and the
|
||||
serve-path skeleton (spawned path started / ended, failure) — the
|
||||
stubs' events carry into the mapping tasks' replaced paths.
|
||||
- **Safety posture** (conventions 6, OQ-03): no secret material ever
|
||||
enters an event, never the username; identity/fingerprint exposure
|
||||
on decline events is decided here against the family posture and
|
||||
recorded (auth.md: log exposure is deployment policy — the crate's
|
||||
events must be safe-by-default at every level).
|
||||
|
||||
Small, cross-cutting unit — one pass over the landed handler/dispatch
|
||||
sites with the vocabulary, so the three mapping branches never land
|
||||
inconsistent events.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] The family tracing posture read and recorded; the event
|
||||
vocabulary established (row + build + channel + decline class)
|
||||
and used at every decline site in `src/`
|
||||
- [ ] Serve-path skeleton events in place (start/ended/failure) so the
|
||||
mapping tasks' spawned paths inherit shaped rows
|
||||
- [ ] The safety posture recorded (no secrets, no username; what
|
||||
identity detail may appear decided)
|
||||
- [ ] A test pins the event presence at the decline sites (or the
|
||||
doc-test convention the family uses — decide + record)
|
||||
- [ ] `cargo test`, `cargo clippy --all-targets -- -D warnings`,
|
||||
`cargo fmt --check`, `cargo doc --no-deps` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/plans/implementation.md §Wave 2 (the booked finding,
|
||||
review-wave-2 §Notes)
|
||||
- docs/architecture/mapping.md §Wire decline reasons (the two decline
|
||||
classes), §Decline matrix
|
||||
- docs/architecture/auth.md §Dispositions (log exposure posture),
|
||||
docs/architecture/decisions/002-russh-pin.md (the toolkit)
|
||||
- sibling `src/` tracing usage — the convention read this task adopts
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled at implementation time.
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
id: w3-git-mapping
|
||||
name: Wave 3 — the git mapping (exec grammar + alkgit dispatch)
|
||||
status: pending
|
||||
depends_on: [w3-decline-tracing]
|
||||
scope: moderate
|
||||
risk: medium
|
||||
impact: phase
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Land the git branch of the spine (ADR-006 decision 2, exec-only) — the
|
||||
alkforge primary purpose: the full exec grammar replaces the wave-2
|
||||
skeleton probe, and the git row becomes a real dispatch to the
|
||||
published alkgit seam. Everything POC-3 stage A proved, re-landed as
|
||||
contract.
|
||||
|
||||
- **The full grammar** (replaces `dispatch::classify_exec` — the
|
||||
wave-2 interpretation's named replacement; its 7 probe unit rows
|
||||
migrate): `git-{upload,receive}-pack '<path>'` — quoted/unquoted
|
||||
paths; strip the quotes and the leading `/` (POC-3 stage A rows:
|
||||
what real OpenSSH git sends); unknown services
|
||||
(`git-send-pack`, `git-upload-archive`) → decline-with-reason, the
|
||||
honest surface; service-only (no repo) → decline-with-reason —
|
||||
POC-3 §A: SSH exec must carry the repo; per-length limits consumed
|
||||
at last — `Limits::max_exec_command_len` enforced **before** any
|
||||
parse or allocation (decline-first, alloc-never; the wave-2
|
||||
carried-not-enforced reservation). Decide the wire shapes per
|
||||
decline class (open/reply vocabulary, whether "unknown service" and
|
||||
"not git at all" share a reason shape) and record.
|
||||
- **Repo path → repo_id, no existence oracle**: the parse validates
|
||||
via `alkgit::validate_repo_id` (1–2 segments, charset, ≤ 100 bytes)
|
||||
and hands the id through — alkssh never resolves; the
|
||||
**collapsed generic denial before any protocol byte** is
|
||||
`serve_duplex_resolved`'s `SubstrateError::AccessDenied` posture,
|
||||
contract-pinned here: over the SSH channel, no pack/ref byte
|
||||
precedes the denial band (the POC-3 §A.5 byte-order evidence, now a
|
||||
test row). Decide the `.git`-suffix normalization against the
|
||||
alkgit registry contract (what vanilla git sends vs
|
||||
`validate_repo_id`'s grammar) and record.
|
||||
- **The dispatch** — the git row becomes real: the taken channel
|
||||
(the store-and-take handoff lands **here first** — the accepted
|
||||
channel is stored at the open, `channels.remove(&id)` →
|
||||
`into_stream()` in the spawned serving task; the session task
|
||||
reuses the store) → `alkgit::serve_duplex_resolved(repo_id,
|
||||
identity, service, duplex, limits, registry, refs, packgen,
|
||||
ingest, push_options_negotiated, pipeline)` — the serve-config's
|
||||
`git` seam handle (`w3-seam-config`), the resolved identity riding
|
||||
the `identity` param. Process-mode dialect: alkgit speaks first
|
||||
(the V0 advertisement, no service prefix) — nothing alkssh-side;
|
||||
verify the dialect holds over the channel duplex with a byte-level
|
||||
row.
|
||||
- **Exit-status both directions** (POC-3 §A.5): clean serve end →
|
||||
`exit-status(0)`... decide the code mapping (`SubstrateError`
|
||||
outcomes → the code — POC evidence: denied → the client observed
|
||||
`ExitStatus{1}`; vanilla git exits 0 on success) — sent before
|
||||
close, from the spawned task via the cloned `Session::handle()`
|
||||
(the wave-2 mechanics reused). Record the decision.
|
||||
- **Identity** — the parked wave-2 deferred item discharges here:
|
||||
the resolved identity (the bridge's `auth_succeeded` ride-along)
|
||||
reaches the seam — assert it live (the authorize-path/witness row
|
||||
the harness can observe; decide the cheapest row) so the
|
||||
visible-surface invariant is observable through the git row.
|
||||
- **Contract rows through the harness, per build** — the
|
||||
`tests/dispatch_core.rs` skeleton rows upgraded: git-only serves
|
||||
the git row through the doubles (clone/push semantics over the
|
||||
in-mem composition), declines plain exec/pty/shell (parse-then-fail,
|
||||
no resource alloc); session-only still declines git-parseable exec;
|
||||
none-build still declines at open; under `--all-features` the
|
||||
routing holds. The declined rows keep their wire shapes
|
||||
(`channel_failure`, channel usable / serving-path failure+close per
|
||||
class).
|
||||
- **The real-tool smoke** — one `git clone` (2.43+) through the
|
||||
harness against hand-rolled in-mem alkgit doubles (alkgit's `Mem*`
|
||||
are test-private — alkssh hand-rolls the minimal quartet per
|
||||
`alkgit/src/backend.rs:164-254`'s noop shapes; never sibling-checkout
|
||||
paths, never copies of the doubles' code). Decide the tooling
|
||||
posture (require git in the environment vs conditional-skip —
|
||||
skipped-with-reason at most, never silently green) and record.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] The full grammar replaces the probe (quoted/unquoted, unknown-
|
||||
service vs non-git decline rows, service-only decline, the
|
||||
`max_exec_command_len` pre-parse cap); the probe's unit rows
|
||||
migrate/extend
|
||||
- [ ] The git row dispatches to `serve_duplex_resolved` over the
|
||||
channel duplex; process-mode dialect verified byte-level;
|
||||
declined routes and the `AccessDenied`-before-protocol-bytes
|
||||
order pinned by contract rows
|
||||
- [ ] The store-and-take handoff lands (channel stored at open, taken
|
||||
in the serving task), structured so the session task reuses it
|
||||
- [ ] The exit-status mapping (clean end / terminal error) decided +
|
||||
recorded; status before close from the spawned task
|
||||
- [ ] The identity ride asserted live through the seam (the parked
|
||||
wave-2 item discharged here)
|
||||
- [ ] The decline-matrix rows per build green through the harness
|
||||
(git-only / session-only / none / all-features), each with its
|
||||
contract stamp; the real-tool clone smoke row
|
||||
- [ ] `cargo test`, `cargo test --features git --test <git rows>`,
|
||||
`cargo test --all-features`, clippy ×2 (`-D warnings`), fmt,
|
||||
`cargo doc --no-deps` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/mapping.md (the git channel-type row; §Session-
|
||||
channel dispatch — decline-first-alloc-never; §the structural
|
||||
constraint)
|
||||
- docs/architecture/decisions/006-mapping-bridge-and-dispatch.md
|
||||
(decision 2 — exec-only; decision 4 — spawn-and-return)
|
||||
- docs/architecture/decisions/004-auth-dispositions.md (the identity
|
||||
ride), docs/architecture/auth.md §Server direction (step 4)
|
||||
- docs/research/poc-3-mapping-bakeoff.md §Stage A (the grammar rows,
|
||||
the denial byte-order, the exit evidence, the spawn rule)
|
||||
- docs/research/mapping-table.md (the validated research ancestor)
|
||||
- alkgit 0.1.0: `serve_duplex_resolved` (`src/duplex.rs:1412`),
|
||||
`SubstrateError` (`src/substrate.rs:116`), `validate_repo_id`
|
||||
(`src/registry.rs:132`), the trait shapes (`src/backend.rs:164-254`)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled at implementation time.
|
||||
@@ -0,0 +1,96 @@
|
||||
---
|
||||
id: w3-seam-config
|
||||
name: Wave 3 — serve-config seam handles (alktty/alkgit per-feature)
|
||||
status: pending
|
||||
depends_on: [review-wave-2, w1-config]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: component
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Extend [`crate::ServeConfig`] with the per-feature family-seam handles
|
||||
the wave-3 mappings consume. This is wave 3's first *course
|
||||
correction* to the wave-1 config surface — the assembly-supplied
|
||||
composition inputs were never carried (mapping.md's seam-entries table
|
||||
names them inside the seam signatures; the wave-1 config bullet
|
||||
pre-dates that reading), and the mappings cannot call
|
||||
`drive_session[_pre_negotiated]` / `serve_duplex_resolved` without
|
||||
them. Landing them here, before the mapping tasks, keeps the
|
||||
un-set-declines posture structural and the review surface unified:
|
||||
|
||||
- **The `session` seam handle** (feature-gated), unset → the session
|
||||
rows decline even with the feature on (the decline matrix's "an
|
||||
unset field declines its row though the feature is on" note,
|
||||
config-driven). Contents, per alktty 0.8.1's actual
|
||||
`drive_session[_pre_negotiated]` signature — decide the exact final
|
||||
shape (flat `Option` fields vs an `Option`-struct per seam; record):
|
||||
- the alktty backends map (`Arc<HashMap<String,
|
||||
Arc<dyn TtyBackend>>>` — assembled by the assembly; alkssh never
|
||||
touches a real backend, the `local` shapes stay alktty-side);
|
||||
- the backend **selector** — the `NegotiateRequest.backend` string
|
||||
alkssh writes (assembly-supplied, never wire-derived; decide and
|
||||
record);
|
||||
- the ownership provider `Option<Arc<dyn
|
||||
alkcall::core::ownership::OwnershipProvider>>` (an alkcall type —
|
||||
no new dep; pass-through to `drive_session_pre_negotiated`,
|
||||
family ACL layer riding along).
|
||||
- **The `git` seam handle** (feature-gated), unset → the git rows
|
||||
decline even with the feature on. Contents, per alkgit 0.1.0's
|
||||
`serve_duplex_resolved` signature: the four backend traits
|
||||
(`GitRegistry` / `GitRefs` / `GitPackGen` / `GitPackIngest`), the
|
||||
caller-owned server-wide `pipeline: Arc<tokio::sync::Semaphore>`,
|
||||
and `push_options_negotiated: bool` (the assembler's config flag;
|
||||
false in the v1 default).
|
||||
- **Manifest** (the wave-1 rule: per-feature sibling deps land with
|
||||
their first consuming wave — the config fields consume them first,
|
||||
so they are not dead entries): optional deps
|
||||
`alktty = "0.8.1"`, `alkgit = "0.1.0"` wired feature-to-dep
|
||||
(`session = ["dep:alktty"]`, `git = ["dep:alkgit"]`) so a git-build
|
||||
never compiles alktty and vice versa; verify the pins against
|
||||
crates.io before committing (verified at decomposition: 0.8.1 /
|
||||
0.1.0, both over the shared `alkcall 0.10` req → 0.10.1; MSRVs 1.88
|
||||
≤ our 1.89; MIT OR Apache-2.0). **alktunnels is NOT landed here** —
|
||||
the config carries no alktunnels types beyond the already-landed
|
||||
`Arc<ChannelClient>`; its optional dep lands with its first
|
||||
consuming code (`w3-tunnel-direct`).
|
||||
|
||||
No construction-time validation (the unset-declines contract lives in
|
||||
the type shape, checked at request time by the mappings); the tunnel
|
||||
handle stays `Option<Arc<ChannelClient>>` as landed; `Debug` impls and
|
||||
the config module docs updated (the direction list now states what
|
||||
each seam handle carries).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `ServeConfig` gains the feature-gated seam handles (the final
|
||||
shape decided and recorded); unset → the owned rows decline,
|
||||
structurally carried, no construction-time validation
|
||||
- [ ] The optional deps + `dep:` feature wiring land with crates.io
|
||||
pins verified; a git-build never compiles alktty and vice versa
|
||||
(no code path outside the cfg gate touches the types)
|
||||
- [ ] The none-build's `ServeConfig::new` shape is unchanged;
|
||||
feature-gated fields absent from featureless builds
|
||||
- [ ] Tests: the per-feature construction shapes, the
|
||||
unset-declines-preserved rows, the `Debug` posture
|
||||
- [ ] `cargo test`, `cargo clippy --all-targets -- -D warnings`,
|
||||
`cargo clippy --all-features --all-targets -- -D warnings`,
|
||||
`cargo fmt --check`, `cargo doc --no-deps` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/plans/implementation.md §Wave 1 (config bullet), §Wave 3
|
||||
- docs/architecture/mapping.md §The seams (the signature shapes),
|
||||
§Session-channel dispatch (the unset note), §Decline matrix
|
||||
- docs/architecture/decisions/002-russh-pin.md (the manifest rule),
|
||||
docs/architecture/decisions/003-feature-graph.md (the feature graph)
|
||||
- alktty 0.8.1: `src/adapter.rs:205-241` (`drive_session[
|
||||
_pre_negotiated]`), `src/negotiation.rs:64-92` (`NegotiateRequest`)
|
||||
- alkgit 0.1.0: `src/duplex.rs:1412-1426` (`serve_duplex_resolved`),
|
||||
`src/backend.rs:31-162` (the four traits)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled at implementation time.
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
id: w3-tty-session
|
||||
name: Wave 3 — session → alktty (translation bridge + exit derivation)
|
||||
status: pending
|
||||
depends_on: [w3-git-mapping]
|
||||
scope: moderate
|
||||
risk: medium
|
||||
impact: phase
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Land the session branch — the biggest single-row surface of the spine
|
||||
(mapping.md's `session` rows): pty/shell/pipe-exec become a real
|
||||
serving path through the published alktty seam, as a **translation
|
||||
bridge, not a byte pump** (POC-3 §D.1). Everything POC-3 stage D
|
||||
proved, re-landed as contract:
|
||||
|
||||
- **The per-channel state + the store-and-take reuse** — the channel
|
||||
store `w3-git-mapping` lands (`channels.remove(&id)` →
|
||||
`into_stream()` in the spawned serving task) gains the session
|
||||
rows' per-channel state: the PTY params a `pty_request` delivered
|
||||
(consumed by the later `shell_request`/`exec_request` on the same
|
||||
channel — `ssh -t host "cmd"` sends pty-then-exec and must serve
|
||||
PTY-mode; a `shell_request` without a preceding pty serves
|
||||
**pipe-mode** `tty = None` — decide whether such a shell serves or
|
||||
declines and record).
|
||||
- **Negotiation, built locally, never wire-derived** (OQ-08 — the
|
||||
serve-config is the whole truth): `pty_request` args →
|
||||
`TerminalParamsWire{term, cols, rows, pixel_w/h, modes}` (SSH
|
||||
ttymodes → the reserved modes JSON — alktty OQ-44's reservation,
|
||||
deferred there); `shell_request` → `NegotiateRequest{carriage:
|
||||
"raw", cmd: shell_argv (the serve-config shell, verbatim), cwd:
|
||||
session_cwd, env: session_env, backend: the seam selector}` →
|
||||
**`drive_session_pre_negotiated(writer, reader, req, backends,
|
||||
ownership, identity)`** spawned; `exec_request` (pipe row) → `cmd =
|
||||
wrapper ++ [cmd]` (the OQ-08 argv append — vanilla quoting
|
||||
semantics; **never naively split**), `tty = None` pipe mode.
|
||||
**Unset-declines** (OQ-08): `shell_argv` unset → `shell_request`
|
||||
declines; `exec_wrapper_argv` unset → the pipe row declines — never
|
||||
a fallback. Decide the wire shape per row (capability decline —
|
||||
channel stays usable — vs the serving-path failure+close shape) and
|
||||
record.
|
||||
- **The translation bridge** — two small adapters around a duplex the
|
||||
serving task drives (the POC-3 §D.1 shape): SSH `data`/EOF →
|
||||
`Chunk::stdin` (decide the EOF translation — the zero-length
|
||||
stdin-chunk sentinel vs alktty's `ControlMessage::Eof` CTRL_IN —
|
||||
verify what alktty's ChunkReader/backend actually consumes and
|
||||
record); stdout chunks → SSH `data`; stderr chunks →
|
||||
`extended_data(1)` (PTY mode merges upstream — the backend's
|
||||
stderr stream is `None` there, so the translation is universal, no
|
||||
mode-switch); the exit chunk (`STREAM_CTRL_OUT`) → the derivation
|
||||
contract. No unbounded buffering in either adapter (convention 9).
|
||||
- **Control rows** — `window_change_request` → `ControlMessage::
|
||||
Resize` CTRL_IN; `signal` → `ControlMessage::Signal` (alktty's
|
||||
uppercase-name vocabulary; name accepted verbatim — decide the
|
||||
decline shape for names alktty's backend semantics reject and
|
||||
record). Mechanics: the requests arrive on the packet loop after
|
||||
the serving task owns the wire — reach them into the spawned bridge
|
||||
through a per-channel control surface (bounded mpsc — decide +
|
||||
record; a silent unbounded proxy is a bounded-resources bug).
|
||||
- **The exit derivation contract** (mapping.md rules 1–6,
|
||||
normative): the alktty exit chunk (`{"type":"exit","code":i32}`,
|
||||
exit-chunk-is-last) is the sole fidelity input, never widened:
|
||||
`code ≥ 0` → `exit-status(N)`; negative `−N`, N ≥ 2 →
|
||||
`exit-signal(name)` via the **server-side Unix signum→name table**
|
||||
(crate-local; not derived from alktty's `signal_from_name` inverse
|
||||
unless that is public and sound — decide the table's form and
|
||||
record; `core_dumped` **never asserted**, the bool stays false);
|
||||
`−1` → `exit-status(255)`, never a signal claim (rule 3 — the
|
||||
SIGHUP collision accepted symmetrically, per the mapping.md
|
||||
rationale); non-Unix adds no other negatives (rule 4); the PTY-path
|
||||
rule-5 fidelity limit documented in the module docs (signal-
|
||||
terminated PTY sessions arrive `exit-status(1)` — portable-pty's
|
||||
exit surface, upstream); unmapped negatives → 255 (rule 6). Sent
|
||||
**before** close, from the spawned task.
|
||||
- **`env_request` stays declined** (OQ-09 — unchanged from wave 2);
|
||||
`session_cwd`/`session_env` ride `NegotiateRequest` only.
|
||||
- **Contract rows through the harness, per build** — the wave-2 stub
|
||||
rows (`pty_row_stub`/`shell_row_stub`/
|
||||
`pipe_row_stub`) replaced; the decline matrix's unset-field rows —
|
||||
feature on + handle unset → the rows decline; featured+set serve
|
||||
through the alkssh-side **TtyBackend shim double** (alktty's
|
||||
`MockBackend`/`testing.rs` are `pub(crate)` + `cfg(test)` — never
|
||||
importable; alkssh hand-rolls the shim: a backend that records
|
||||
`TtyParams`, emits scripted stdout/stderr/exit chunks and consumes
|
||||
stdin/resizes/signals — per the `TtyHandle` field shapes). The
|
||||
identity-landing item (the parked wave-2 note) asserted through the
|
||||
row that observes the identity at `drive_session_pre_negotiated`.
|
||||
- **The real-tool smoke** — one OpenSSH pty session through the
|
||||
harness against the shim (or against a real PTY via a dev-dep
|
||||
`alktty` `local` composition — decide which posture and record; the
|
||||
real bash/`stty size` fidelity was POC stage D's, wave 5 re-lands it
|
||||
as e2e): the smoke owns the wire rows a plain rustsh-client row
|
||||
can't pin (echo paths, `stty size`-grade fidelity are wave-5's
|
||||
matrix; here the pty lifecycle rows only).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] pty/shell/pipe-exec rows serve through
|
||||
`drive_session_pre_negotiated` (spawned, handler fast); the
|
||||
store-and-take + per-channel PTY state reused from the git
|
||||
task's handoff; pipe-less shell decided + recorded
|
||||
- [ ] `pty_request` → `TerminalParamsWire` (ttymodes → the reserved
|
||||
JSON), `shell_request` → shell argv, exec → `wrapper ++ [cmd]`,
|
||||
cwd/env session-side; unset-declines on both OQ-08 rows with
|
||||
recorded wire shapes
|
||||
- [ ] The bridge translated per row (stdin chunks + EOF shape
|
||||
verified against alktty; stdout→data; stderr→`extended_data(1)`;
|
||||
resize/signal CTRL_IN reach the serving path through a bounded
|
||||
per-channel surface)
|
||||
- [ ] The derivation contract rules 1–6 in code with the signum→name
|
||||
table; `−1`→255; `core_dumped` never; PTY-path rule-5 documented;
|
||||
exit-status before close from the spawned task — pinned by rows
|
||||
- [ ] The decline matrix per build green through the harness (unset-
|
||||
field rows included); identity ride asserted; the `env_request`
|
||||
decline unchanged; skeleton stub rows migrated
|
||||
- [ ] The real-tool pty smoke row (posture decided + recorded)
|
||||
- [ ] `cargo test` (+ per-feature + `--all-features` rows), clippy ×2
|
||||
(`-D warnings`), fmt, `cargo doc --no-deps` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/mapping.md (the `session` channel-type row,
|
||||
request-level rows, §Exit chunk → SSH exit reporting — rules 1–6)
|
||||
- docs/architecture/decisions/006-mapping-bridge-and-dispatch.md
|
||||
(decision 4 — spawn-and-return: status before close from the spawned
|
||||
task), docs/architecture/decisions/003-feature-graph.md
|
||||
- docs/architecture/auth.md §Server direction step 4 (the identity
|
||||
ride), §Dispositions (OQ-03)
|
||||
- docs/research/poc-3-mapping-bakeoff.md §Stage D (the bridge shape,
|
||||
control rows, the signal/exit fidelity findings, §D.3 mechanics)
|
||||
- docs/research/reverse-runner.md (pipe-mode pid-only signal caveat —
|
||||
the fidelity note)
|
||||
- alktty 0.8.1: `adapter.rs:234-241` (`drive_session_pre_negotiated`),
|
||||
`negotiation.rs` (`NegotiateRequest`/`TerminalParamsWire`),
|
||||
`wire.rs` (chunks, readers/writers), `control.rs` (`ControlMessage`),
|
||||
`backend.rs` (`TtyHandle`/`TtyParams`/`TtyBackend` shapes)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled at implementation time.
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
id: w3-tunnel-direct
|
||||
name: Wave 3 — tunnel leg 1 (the route-1 bridge — direct-tcpip + streamlocal)
|
||||
status: pending
|
||||
depends_on: [w3-tty-session]
|
||||
scope: moderate
|
||||
risk: medium
|
||||
impact: phase
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Land the tunnel branch's proven leg (ADR-006 decision 1) — the
|
||||
adapter-side route-1 bridge for `direct-tcpip` and `direct-streamlocal`
|
||||
(POC-3 stage C's shape, re-landed as contract):
|
||||
|
||||
- **The route-1 bridge** — the `tunnel_row_stub` replaced with the
|
||||
real flow: per accepted open, the target/substrate are constructed
|
||||
from the SSH open arguments (`direct-tcpip`(host, port) →
|
||||
`SubstrateAddr::HostPort` + `Substrate::Tcp`; `direct-streamlocal`
|
||||
(socket path) → `SubstrateAddr::Path` + `Substrate::Unix`) and
|
||||
spawn the flow POC-3 proved: **`TunnelSession::open_direct(&
|
||||
channel_client, target, substrate)`** → **accept only after the
|
||||
fabric open succeeds** (accept consumes the handle — the reject
|
||||
shape is only possible pre-accept) → on fabric failure the explicit
|
||||
`ConnectFailed` reject (the stub's reason survives as the real
|
||||
decline; `tunnel_seam_stub_decline` retires into it) → on success
|
||||
`take_halves()` pumped against the taken channel's
|
||||
stream (`pump_bidi` — the alkcall primitive the POC recipe used) on
|
||||
the spawned task, per spawn-and-return. The open hook returns fast
|
||||
with the fabric open in flight.
|
||||
- **The cap admission across the fabric window** — the wave-2 stub
|
||||
declined without consuming a count; the real flow admits. Mechanics
|
||||
to get right (record): the admission is taken at the hook (the
|
||||
packet-loop single-writer site — no race window against the cap
|
||||
check) and held across the fabric open; **a fabric failure must
|
||||
release the count inside the spawned task** (the
|
||||
`channel_close`-hook release point only fires for established
|
||||
channels — a rejected open never established one), so a failed
|
||||
bridge cannot leak budget. Decide the release mechanism and
|
||||
record.
|
||||
- **Identity propagation to the family fabric (auth.md §Server
|
||||
direction step 4 — the visible-surface invariant's gate)**: the
|
||||
resolved identity rides the channels connection so the fabric's
|
||||
`AccessControl::check(peer_identity)` gates the mapped opens. The
|
||||
parked wave-2 `auth_succeeded` item lands here: on auth completion
|
||||
the handler propagates **once** via alkcall's `Connection::
|
||||
set_identity` — mechanics decided and recorded (the alkhub
|
||||
`hub_leg.rs` one-time-set precedent: `ChannelClient::
|
||||
take_call_connection()` → `set_identity(identity)`; check the
|
||||
`take` semantics against alkcall 0.10.1's docs — the relay note
|
||||
says the detach is wrong for hubs; verify a door's reading and
|
||||
hook placement, `auth_succeeded` vs the first seam call).
|
||||
- **The runtime-Unix gate** (OQ-11 — universal compile, clean
|
||||
open-decline off-Unix): `direct-streamlocal` compiles wherever
|
||||
`tunnel` compiles; off-Unix a clean open-decline **before any
|
||||
fabric call** (never a partial bridge); on-Unix the real bridge.
|
||||
- **Contract rows through the harness, per build** (the wave-2 gate's
|
||||
booked acceptor vocabulary note is the listen leg's — this task's
|
||||
rows ride plain client opens): a git/session build with `tunnel`
|
||||
off declines the tunnel opens (unfeatured, `AdministrativelyProhibited`);
|
||||
the featured rows: a configured `tunnel` handle (feature + `Arc<
|
||||
ChannelClient>`) serves, an **absent handle declined with a clean
|
||||
error even under the feature** (the unchanged unset-declines
|
||||
posture — the wave-1 config note), the cap rows (cap-gated before
|
||||
spawn — never a leaked count over a failed bridge: the release
|
||||
mechanism pinning row), and the `ConnectFailed` row over a refusing
|
||||
fabric double. The **fabric double** is the POC-3 §C.4 in-process
|
||||
recipe as test composition (ChannelsAdapter + InstallChannelZero +
|
||||
the alktunnels openables + a hand-rolled dial/dial-fail seam) —
|
||||
hand-rolled in `tests/`, never a sibling-checkout path.
|
||||
- **The optional dep lands here** (`alktunnels = "0.4.1"`, wired
|
||||
`tunnel = ["dep:alktunnels"]` — first consuming code; crates.io pin
|
||||
re-verified before committing).
|
||||
- **The real-tool smoke** — one `ssh -L` (+ curl) through the
|
||||
harness against the fabric double (tooling posture decided like the
|
||||
git task — required vs conditional-skip, recorded).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `direct-tcpip` serves through the route-1 bridge: fabric open →
|
||||
accept → `take_halves()` pump on the spawned task; failure → the
|
||||
explicit `ConnectFailed` reject, the stub retired; the open
|
||||
hook returns fast
|
||||
- [ ] The cap admission across the fabric window pinned (admit at the
|
||||
hook, release on fabric failure inside the spawned task — no
|
||||
leaked count, no double-admit)
|
||||
- [ ] The identity propagates to the channels connection once
|
||||
(`set_identity` mechanics + hook placement decided and
|
||||
recorded); the wave-2 `auth_succeeded` item discharged
|
||||
- [ ] `direct-streamlocal` carries the runtime-Unix gate
|
||||
(compile-everywhere, clean open-decline off-Unix before any
|
||||
fabric call)
|
||||
- [ ] The per-build decline-matrix rows green through the harness
|
||||
(unfeatured/unset/fabric-failure/cap/serve classes), each with
|
||||
its contract stamp; the `ssh -L` smoke row
|
||||
- [ ] The `alktunnels` optional dep lands, pin re-verified;
|
||||
`tunnel`-off builds carry no alktunnels types in code paths
|
||||
- [ ] `cargo test` (+ per-feature + `--all-features` rows), clippy ×2
|
||||
(`-D warnings`), fmt, `cargo doc --no-deps` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/mapping.md (the `direct-tcpip` / `direct-
|
||||
streamlocal` channel-type rows; §the structural constraint)
|
||||
- docs/architecture/decisions/006-mapping-bridge-and-dispatch.md
|
||||
(decision 1 — route 1; the reject shape; the wiring recipe pointer)
|
||||
- docs/architecture/decisions/003-feature-graph.md (the tunnel row,
|
||||
the OQ-11 runtime-Unix gate)
|
||||
- docs/architecture/auth.md §Server direction step 4 (set_identity,
|
||||
once), §Open questions (all resolved)
|
||||
- docs/research/poc-3-mapping-bakeoff.md §Stage C (the bridge + the
|
||||
failure shapes + §C.4 the fabric recipe + the identity witness)
|
||||
- alktunnels 0.4.1: `consumer.rs:89-148` (`TunnelSession::open`,
|
||||
`open_direct`), `consumer.rs:235-260` (`take_halves`),
|
||||
`params.rs:105-126` (`SubstrateAddr`/`TunnelDirectParams`),
|
||||
`error.rs` (`TunnelOpenError`)
|
||||
- alkcall 0.10.1: `channels/client.rs` (`take_call_connection`),
|
||||
`core/types.rs:541` (`Connection::set_identity`),
|
||||
`channels/hub_leg.rs:217-220` (the one-time-set precedent)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled at implementation time.
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
id: w3-tunnel-listen
|
||||
name: Wave 3 — tunnel leg 2 (the -R listen flow + the forwarded-tcpip data leg)
|
||||
status: pending
|
||||
depends_on: [w3-tunnel-direct]
|
||||
scope: moderate
|
||||
risk: high
|
||||
impact: phase
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Land the `-R` leg's server direction (mapping.md §Global-request rows +
|
||||
the `forwarded-tcpip` channel-type row) — the one leg the POC only
|
||||
exercised as refusal ("only the refusal shape was exercised"), so this
|
||||
task carries the wave-3 gate's biggest open mechanics. Shape per the
|
||||
family door semantics (vanilla -R: the door's fabric listens, per
|
||||
arrival the data flows back to the vanilla client, which dials its own
|
||||
target):
|
||||
|
||||
- **The listen request rows** — `tcpip_forward` / `streamlocal_forward`
|
||||
(and their cancel forms) go from wave-2's unconditional decline to
|
||||
the real flow under `tunnel` (+ the streamlocal runtime-Unix gate
|
||||
riding its serving flow, OQ-11): the listen is mapped **family-ward**
|
||||
through the alktunnels listen/forwarded shapes — the door owns
|
||||
nothing local. The **exact composition is decided here** against
|
||||
alktunnels 0.4.1's actual producer/consumer surfaces (`TunnelListener::
|
||||
open`'s listen dial + reply fields; the minted listen token in
|
||||
`TunnelForwardedParams`; the bind-first accept dispatcher's
|
||||
`ForwardedOpener` / `make_bindfirst_accept_handler`;
|
||||
`register_tunnel_forwarded_openable`'s `ForwardedHandler`) with
|
||||
POC-3 §C.4 as the template. Decide and record: who dials the
|
||||
`tunnel/forwarded` op at the door, and whether the
|
||||
assembly-supplied `Arc<ChannelClient>` composition can carry the
|
||||
door-side acceptance of the fabric's inbound forwarded opens
|
||||
(alkcall channel-manager openable registration on the door-side
|
||||
connection) or the serve-config's tunnel handle must grow a
|
||||
registration-seam handle — **if the door-side handle shape must be
|
||||
amended, amend it here** (the `w3-seam-config` shape, recorded as
|
||||
this wave's second config course-correction). If the topology does
|
||||
not close over the published alkcall 0.10.1 / alktunnels 0.4.1
|
||||
surfaces, **stop and book it** for the gate — never silently
|
||||
forked, worked around in-family, or re-litigating ADR-006's
|
||||
resolution.
|
||||
- **The `forwarded-tcpip` data leg** (mapping.md's row — "hand the
|
||||
channel duplex to the handler"): per fabric arrival, the door opens
|
||||
a `forwarded-tcpip` channel **toward the vanilla client** with the
|
||||
SSH message's fields mapped per the vanilla -R convention
|
||||
(`host_to_connect`/`port` echoing the target args the original
|
||||
`tcpip_forward` request carried — recorded per pending listen;
|
||||
originator fields carrying the arrival info — decide and record
|
||||
what `TunnelForwardedParams.peer` yields) → accept-or-reject per
|
||||
the in-crate cap (the **acceptor vocabulary** the wave-2 gate
|
||||
booked — the first shape of what wave 4 grows into the client-side
|
||||
acceptor registry) → pump the fabric `BiStream` ↔ the SSH channel
|
||||
(`ForwardedHandler` ownership: the handler owns the pump per
|
||||
alktunnels' shape; correlation-miss → teardown-at-birth, never a
|
||||
half-open SSH channel).
|
||||
- **Cancel forms + bounded bookkeeping** — a per-session listener map
|
||||
(the bound-port handles) drives `cancel_tcpip_forward` /
|
||||
`cancel_streamlocal_forward` 1:1 into the family listener's
|
||||
teardown (`TunnelListener::close` posture); the listener count is a
|
||||
bounded resource (decide the bound relation to
|
||||
`Limits::max_concurrent_channels` or a dedicated cap — record; no
|
||||
unbounded map). The bound-port out-param: `port = 0` → the
|
||||
actually-bound number returned through the `&mut u32` (the
|
||||
family-side listen reply's numbers; the mapping.md/client.md
|
||||
lifecycle spec).
|
||||
- **Identity**: the listen dial rides the propagated identity (the
|
||||
fabric's `AccessControl` gates the listen + forwarded opens the
|
||||
same as leg 1's — the visible-surface invariant across the whole
|
||||
listen flow).
|
||||
- **Contract rows through the harness, per build** — the wave-2 stub
|
||||
rows replaced: featured + configured serve (the listen flow against
|
||||
the fabric double); unfeatured/unset/streamlocal-off-Unix decline
|
||||
cleanly (honest advertisement: a declined listen never left a half
|
||||
state); the cancel rows; the arrival → forwarded-tcpip → pump row;
|
||||
cap rows at the accept point. The **harness grows the client-side
|
||||
accept hook** (russh client
|
||||
`server_channel_open_forwarded_tcpip` — the server-initiated opens
|
||||
the contract rows observe; the wave-2 note said exactly this).
|
||||
- **The real-tool smoke** posture decided + recorded (a real `ssh -R`
|
||||
through the harness's TCP loopback if tooling permits — else the
|
||||
harness rows carry wave 3 and the real-tool `-R` smoke is named
|
||||
wave-5 e2e territory explicitly; never silently dropped).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `tcpip_forward` / `streamlocal_forward` (+ cancel forms) carry
|
||||
the real mapped flow under `tunnel` (+ the runtime-Unix gate
|
||||
where it binds); decline classes keep their wire shapes
|
||||
- [ ] The family-ward listen composition decided against alktunnels
|
||||
0.4.1's actual surfaces and recorded; the door-side inbound-open
|
||||
mechanics closed (or a serve-config amendment landed + recorded;
|
||||
or stopped-and-booked for the gate — nothing silent)
|
||||
- [ ] The `forwarded-tcpip` data leg serves per the handler shape
|
||||
(target-arg echo per pending listen, cap-gated acceptor, the
|
||||
pump, teardown-at-birth on correlation-miss)
|
||||
- [ ] The per-session listener bookkeeping bounded; the bound-port
|
||||
out-param returns the actually-bound number
|
||||
- [ ] The per-build decline-matrix rows green through the harness with
|
||||
the client-side accept hook in place (the wave-2 gate's booked
|
||||
harness item discharged)
|
||||
- [ ] The real-tool smoke posture decided + recorded; the wave-2 stub
|
||||
listen rows migrated
|
||||
- [ ] `cargo test` (+ per-feature + `--all-features` rows), clippy ×2
|
||||
(`-D warnings`), fmt, `cargo doc --no-deps` pass
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/mapping.md §Channel-type rows (`forwarded-tcpip`
|
||||
row), §Global-request rows (the `-R` listen flow, the POC-3 note)
|
||||
- docs/architecture/client.md §Op rows (the `-R` leg, the acceptor
|
||||
framing — the client mirror this leg shares vocabulary with),
|
||||
§Lifecycle primitives (the bound-port spec)
|
||||
- docs/architecture/decisions/006-mapping-bridge-and-dispatch.md
|
||||
(decision 1 — the fabric wiring recipe), docs/architecture/
|
||||
decisions/003-feature-graph.md (the tunnel row + §4 the
|
||||
client-side acceptor symmetry)
|
||||
- docs/research/poc-3-mapping-bakeoff.md §Stage C (the recipe;
|
||||
§C.2's refusal shape this task goes past), OQ seed 4
|
||||
- docs/research/reverse-runner.md (the `-R` row — the client-side
|
||||
mirror of the same wire vocabulary)
|
||||
- alktunnels 0.4.1: `producer.rs:718-772` (`ForwardedOpener`,
|
||||
`make_bindfirst_accept_handler`), `producer.rs:982-1082`
|
||||
(`ForwardedHandler`, `register_tunnel_forwarded_openable`),
|
||||
`consumer.rs:497-543` (`TunnelListener::open` + reply accessors),
|
||||
`params.rs:381-401` (`TunnelForwardedParams`)
|
||||
- alkcall 0.10.1: the channels openable/accept surfaces (the
|
||||
door-side registration question this task resolves)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled at implementation time.
|
||||
Reference in new issue
Block a user