docs(architecture): OQ-10 resolved as a decided mapping contract; tracker statements made accurate

- OQ-10 resolved: alkssh derives SSH exit-signal from the alktty exit
  chunk's negative code (−N = signal N, pipe path) server-side; −1
  (alktty's could-not-determine sentinel) → exit-status(255), never a
  signal claim; core_dumped never asserted in v1; no alktty wire change
- new verified backend finding recorded: portable-pty 0.9 reduces
  PTY-mode signal termination to a plain exit code 1 (signal number
  unrecoverable through its trait surface) — faithful exit-signal on
  the PTY row is an alktty/portable-pty upstream ask, not an alkssh one
- research docs (poc-3 §D.2, pocs.md, mapping-table rows) restated
  accurately instead of carrying inline correction scaffolding

Verification: cargo doc --no-deps earlier this session (docs-only change)
This commit is contained in:
glm-5.3-flash committed 2026-10-27 14:19:02 +00:00
1 parent 9217a8b3cf
commit 1a40bfb498
5 files changed
+64 -64

No files matched your search

+3 -3
View File
@@ -75,8 +75,8 @@ the served listen flow is implementation-phase contract-test territory.*
| `window_change_request` | resize control (POC-3 §D.1: live resize proven) | | `window_change_request` | resize control (POC-3 §D.1: live resize proven) |
| `signal` | signal control (alktty names verbatim); PTY mode reaches the process group, pipe mode is pid-only (backend semantics, recorded in OQ-10) | | `signal` | signal control (alktty names verbatim); PTY mode reaches the process group, pipe mode is pid-only (backend semantics, recorded in OQ-10) |
| data / `extended_data(1)` | the translation bridge (rows table) | | data / `extended_data(1)` | the translation bridge (rows table) |
| `exit_status` | from the alktty exit chunk — sent **before** close, from the spawned task via `Session::handle()` (POC-3 §D: proven both legs) | | `exit_status` | from the alktty exit chunk — sent **before** close, from the spawned task via `Session::handle()` (POC-3 §D: proven both legs). `−1` (alktty's could-not-determine sentinel — alktty ADR-004 §4) → `exit-status(255)`, never a signal claim |
| `exit_signal` | only for signal-terminated exits; derived from the exit chunk's negative code — `−N` = terminated by signal N on Unix (alktty ADR-004's documented convention). Details pending OQ-10: the `−1` wait-failure/SIGHUP collision, core-dumped (discarded by alktty; likely never asserted in v1), non-Unix shift | | `exit_signal` | signal-terminated exits on the **pipe** path: the exit chunk's negative code is the signal — `−N` → name via a Unix signal-number→name table (OQ-10 resolved; POC-3 §D.2 observed `−15` → `exit-signal("TERM")` live). `core_dumped` always `false` (v1 — alktty discards `ExitStatus::core_dumped()`). **PTY path**: signal-terminated children arrive as a plain code 1 (portable-pty's exit surface; the signal number is unrecoverable there today) → `exit-status(1)` — faithful `exit-signal` on the PTY row is an alktty-backend/portable-pty ask, upstream |
## The structural constraint: spawn-and-return ## The structural constraint: spawn-and-return
@@ -123,7 +123,7 @@ under `--all-features`.
- **OQ-08** (shell convention — status: open): blocks this doc's - **OQ-08** (shell convention — status: open): blocks this doc's
`shell_request`/`NegotiateRequest.cmd` row detail. `shell_request`/`NegotiateRequest.cmd` row detail.
- **OQ-10** (exit-signal derivation details — status: open, **premise corrected**): the negative code *is* the signal identity by alktty's documented convention, so no chunk widening is justified by default (the upstream option's gate and consequence analysis are recorded there). This blocks only the `exit_signal` row's derivation detail — the `−1` disposition, core-dumped assertion, non-Unix note. - ~~OQ-10~~ (exit-signal derivation — resolved: the negative code is the signal encoding on the pipe path; the PTY path's signal-identity loss is recorded upstream, alktty-side).
- **OQ-11** (streamlocal platform decline shape — status: open). - **OQ-11** (streamlocal platform decline shape — status: open).
- ~~OQ-02~~ (dispatch composition — resolved by ADR-006, as amended). - ~~OQ-02~~ (dispatch composition — resolved by ADR-006, as amended).
+12 -17
View File
@@ -94,24 +94,19 @@ alkcall trackers have their own OQ spaces).
- **Blocked on**: a concrete consumer use case requiring wire-supplied environment variables. - **Blocked on**: a concrete consumer use case requiring wire-supplied environment variables.
- **Resolution**: Not yet decidable — no use case; decline stands. - **Resolution**: Not yet decidable — no use case; decline stands.
### OQ-10: ~~"The alktty exit chunk carries no signal identity — widen the chunk or map by assembly policy"~~ — premise corrected; re-scoped ### OQ-10: ~~SSH `exit-signal` fidelity over the alktty exit-code convention~~ — resolved
- **Origin**: [poc-3-mapping-bakeoff.md](../research/poc-3-mapping-bakeoff.md) §D.2, `mapping-table.md` (exit_signal row). **Premise corrected 2026-10-27**: the POC's "signal-identity gap" framing was an incorrect assumption, surfaced during review; the incorrect assumption is documented here, not silently edited. - **Origin**: `mapping-table.md` (exit_signal row), [poc-3-mapping-bakeoff.md](../research/poc-3-mapping-bakeoff.md) §D.2
- **Status**: open — re-scoped to the SSH-fidelity derivation details; the detail decision lands during `mapping.md` - **Status**: resolved — the alkssh mapping contract is decided (below, and in `mapping.md`'s exit rows). The PTY-path fidelity limit recorded in point 4 is an alktty-backend/portable-pty matter and belongs in their trackers; alkssh adapts automatically with no contract change if the convention ever holds on that path.
- **Priority**: medium - **Resolution**: alkssh adds nothing to the alktty wire — the exit chunk is alktty's contract (`{"type":"exit","code":N}` on ctrl-out, exit-chunk-is-last — alktty ADR-004, ported from alknet ADR-055) — and derives all SSH fidelity from the code the chunk already carries:
- **The incorrect assumption, explicitly**: the OQ seed treated the exit chunk's lack of a signal *name* as a design gap, with "alktty widens the chunk" as a co-equal candidate casually offered ("filed as an ask"). Both halves were wrong.
- **The chunk does carry signal identity.** The negative exit code *is* the signal encoding, by a deliberate documented one-way convention (alktty ADR-004 decision 1, ported from alknet ADR-055; implemented in alktty `src/local/pipe.rs::exit_code_from` — on Unix, `ExitStatus::signal() → -sig`). The rationale is tty/pty-ground: the backend reaps a Unix wait-status, and the negative-code encoding preserves exactly that ground truth across every backend behind a single `exit_code → i32` API. The OQ's claim "carries no signal identity" overstated an *information-preserving* encoding as an absence. 1. **The negative code is the signal encoding on the pipe path.** alktty's pipe backend maps Unix `ExitStatus` signal termination to `−N` (`pipe.rs::exit_code_from`, `ExitStatusExt::signal() → -sig`; the alknet ADR-055 convention). POC-3 stage D observed it live on the wire: signal TERM → `−15` → SSH `exit-signal("TERM")` via the cloned `Session::handle()`.
- **Upstream widening is not a justified candidate by default.** It is not a wire-only tweak: widening `ControlMessage::Exit`'s shape is a one-way-surface change every ctrl-out consumer parses; the backend API (`TtyHandle.exit_code → i32`, shared by every backend) would have to widen with it — changing how every backend reaps and reports; and the negative-code convention is shared with alknet's docker-carriage lineage (alknet ADR-055). "It would be easier for alkssh" is not a tty/pty-grounded justification; alkssh cannot shift alktty's contract for its own fidelity convenience, and will not silently work around the wire either. 2. **Name derivation is alkssh server-side work, not a wire change**: `−N` → the SSH `exit-signal` name from a Unix signal-number→name table (signal semantics belong to the serving platform, where the backend reaps). `core_dumped` is always `false` in v1 — alktty discards `ExitStatus::core_dumped()`, so nothing better is knowable from the chunk; no error message rides.
- **The tty/pty conventions alkssh consumes, never repurposes**: the exit control chunk (JSON, never zero-length, "exit chunk is last" invariant) and the data-plane sentinels (zero-length stdin = client EOF — the form alkssh's SSH-EOF translation uses; zero-length stdout = stdout-drained). Both have tty/pty rationale in alktty's ADR-004/`tty-wire.md`; they are upstream decisions, not alkssh levers. 3. **`−1` is never a signal claim.** Per alktty ADR-004 §4, `−1` is the backend could-not-determine sentinel — it collides with a real SIGHUP termination (signal 1). Alkssh renders `−1` as `exit-status(255)` (OpenSSH's conventional failure value): fabricating `exit-signal("HUP")` for a wait failure would invent a signal that never happened. The SIGHUP information loss inside the sentinel is alktty's documented edge — alktty's additive `exit_error` control type is its own extension seam if it ever becomes load-bearing.
- **What is genuinely missing** (the re-scoped open detail — all alkssh mapping-contract territory): 4. **PTY path — the real fidelity limit, backend-side.** portable-pty 0.9 converts a signal-terminated child's wait status with `code = status.code().unwrap_or(1)` → **1**, keeping the signal only in a separate humanized (`strsignal`) string field that alktty's PTY waiter discards (`pty.rs` reads `exit_code()` only; the number is unrecoverable through portable-pty 0.9's trait surface). So a signal-killed PTY session arrives as a plain exit 1 → alkssh maps `exit-status(1)`; faithful `exit-signal` for the `session`/PTY row needs the PTY backend to conform to alktty's own negative-code convention — an alktty/portable-pty ask with tty/pty-grounded justification, not an alkssh convenience ask.
1. **Name derivation**: SSH `exit-signal` requires a name; `−N → name` is alkssh server-side work (a Unix signal table — signal semantics belong to the server's platform, where the backend reaps). 5. **Non-Unix**: no signal termination; `−1` is the only negative that can appear → rule 3.
2. **Core-dumped**: alktty discards `ExitStatus::core_dumped()`; SSH's `exit-signal` carries a bool. Currently unrecoverable — disposition decided during `mapping.md` (likely direction: never asserted, v1). 6. **Pipe-mode pid-only vs PTY process-group signal scope** is backend semantics, not a mapping change — recorded as a fidelity note on `mapping.md`'s `signal` row.
3. **The `−1` collision** (pre-existing, documented in alktty ADR-004's consequences): `−1` is the backend wait-failure sentinel, colliding with a real SIGHUP termination. The SSH mapping must pick a disposition (`exit-status` with an opaque value, no exit request, or a diagnostic band). alktty has an *additive* escape (`exit_error` message type) recorded in its own ADR — an upstream improvement, not an alkssh ask by default. - **Cross-references**: OQ-08, [mapping.md](mapping.md) (`exit_signal`, `exit_status`, `signal` rows), alktty ADR-004 / alknet ADR-055
4. **Non-Unix platforms**: the negative-code convention is `#[cfg(unix)]`; Windows backends report `code()` only (signal termination essentially does not occur) — the mapping detail records the graceful shift.
5. **Pipe-mode pid-only vs PTY process-group signal scope** (carried from the POC): backend semantics, not a mapping change — a fidelity note on the `signal` row.
- **Impacts**: blocks the `exit-signal` fidelity detail in `mapping.md` only; no upstream ask stands by default.
- **Resolution**: pending. Direction fixed: alkssh derives exit-signal fidelity from the existing wire (the documented negative-code convention). Decide the derivation details (−1 disposition, core-dumped assertion, non-Unix note) when writing `mapping.md`; record them as an ADR-006 amendment or a dedicated ADR. Any *upstream* widening of the exit chunk would require its own alktty ADR with the full consequence analysis above of the tty/pty rationale — that gate is stated here so it cannot be skipped.
- **Cross-references**: OQ-08, [mapping.md](mapping.md) (`exit_signal`, `signal` rows), alktty ADR-004 / `tty-wire.md` (alktty repo), alknet ADR-055
### OQ-11: `direct-streamlocal` platform surface — compile-time or runtime decline shape? ### OQ-11: `direct-streamlocal` platform surface — compile-time or runtime decline shape?
+3 -3
View File
@@ -36,7 +36,7 @@ request-level extras.
| SSH channel type | Vanilla use | Feature (candidate) | Family seam | Notes | | SSH channel type | Vanilla use | Feature (candidate) | Family seam | Notes |
|---|---|---|---|---| |---|---|---|---|---|
| `session` → `pty_request`+`shell_request` | `ssh host` interactive shell | `session` | alktty producer: `NegotiateRequest` constructed locally → `drive_session` (or pre-allocated variant) | `pty_request` args → `TerminalParamsWire` (term/cols/rows/pixels; SSH modes → `modes` JSON reserved); shell case needs a cmd convention (OQ); PTY mode merges stderr into stdout (kernel PTY). **[POC-3 corrected]** the data-plane mapping is a *translation bridge*, not a byte pump: alktty's plane is chunk-framed both directions (stdin/stdout/stderr + CTRL_IN/CTRL_OUT chunks), so alkssh encodes SSH data→stdin chunks and decodes stdout→data, stderr→extended_data, exit chunk→exit-status/exit-signal. New OQ: the exit chunk carries no signal identity (negative code only). **[Corrected 2026-10-27]** the negative code *is* the signal encoding (alktty ADR-004); the OQ is about server-side derivation details, not chunk widening | `session` → `pty_request`+`shell_request` | `ssh host` interactive shell | `session` | alktty producer: `NegotiateRequest` constructed locally → `drive_session` (or pre-allocated variant) | `pty_request` args → `TerminalParamsWire` (term/cols/rows/pixels; SSH modes → `modes` JSON reserved); shell case needs a cmd convention (OQ); PTY mode merges stderr into stdout (kernel PTY). **[POC-3 corrected]** the data-plane mapping is a *translation bridge*, not a byte pump: alktty's plane is chunk-framed both directions (stdin/stdout/stderr + CTRL_IN/CTRL_OUT chunks), so alkssh encodes SSH data→stdin chunks and decodes stdout→data, stderr→extended_data, exit chunk→exit-status/exit-signal. The exit chunk encodes pipe-path signal termination as the negative code `−N` (alktty ADR-004's convention — `pipe.rs::exit_code_from`); the PTY path reduces signal termination to a plain exit code (portable-pty's exit surface), so PTY-mode `exit-signal` fidelity is an alktty-backend question |
| `session` → `exec_request` (non-git command) | `ssh host "cmd"` | `session` | alktty pipe mode: `terminal: None`, separate stderr | stderr flows back as SSH `extended_data` code 1 — only valid without PTY | | `session` → `exec_request` (non-git command) | `ssh host "cmd"` | `session` | alktty pipe mode: `terminal: None`, separate stderr | stderr flows back as SSH `extended_data` code 1 — only valid without PTY |
| `session` → `exec_request`/`subsystem_request` git | `git push/clone ssh://` | `git` | alkgit: parse command → `Service` + repo (same grammar as `preamble.rs`, without `\0host=`) → `serve_duplex_resolved(repo_id, identity, service, duplex, ...)` | Process-mode dialect is correct (SSH supplies service+repo out of band; server speaks first = advertisement). **[POC-3 corrected]** git over SSH is exec-only: a `subsystem` request carries the service *name* but no repo id, so even a git-service subsystem must decline — vanilla git always executes `git-upload-pack '/repo'`. POC-3: vanilla clone/push/second-push through the published seam + substrate composition, exit-status in both directions | | `session` → `exec_request`/`subsystem_request` git | `git push/clone ssh://` | `git` | alkgit: parse command → `Service` + repo (same grammar as `preamble.rs`, without `\0host=`) → `serve_duplex_resolved(repo_id, identity, service, duplex, ...)` | Process-mode dialect is correct (SSH supplies service+repo out of band; server speaks first = advertisement). **[POC-3 corrected]** git over SSH is exec-only: a `subsystem` request carries the service *name* but no repo id, so even a git-service subsystem must decline — vanilla git always executes `git-upload-pack '/repo'`. POC-3: vanilla clone/push/second-push through the published seam + substrate composition, exit-status in both directions |
| `session` → SOCKS5-in-channel | (n/a — retired) | ~~`dynamic-forward`~~ **retired (ADR-003 §1a)** | was alksocks: `serve_socks5_over` | **Post-architecture retirement:** no consumer is ever the family-native client shape this row served. Vanilla `ssh -D` does SOCKS client-side and opens plain `direct-tcpip` (POC-3 correction 2 → the `tunnel` row); the family `-D` behavior is a *client-local* alksocks door over the alkssh client's `direct-tcpip` opens (assembly composition). POC-3 stage B remains the evidence that SOCKS-in-channel is feasible if a family client ever wants a remote SOCKS door (back via explicit ADR). **[ADR-003 amended]** | | `session` → SOCKS5-in-channel | (n/a — retired) | ~~`dynamic-forward`~~ **retired (ADR-003 §1a)** | was alksocks: `serve_socks5_over` | **Post-architecture retirement:** no consumer is ever the family-native client shape this row served. Vanilla `ssh -D` does SOCKS client-side and opens plain `direct-tcpip` (POC-3 correction 2 → the `tunnel` row); the family `-D` behavior is a *client-local* alksocks door over the alkssh client's `direct-tcpip` opens (assembly composition). POC-3 stage B remains the evidence that SOCKS-in-channel is feasible if a family client ever wants a remote SOCKS door (back via explicit ADR). **[ADR-003 amended]** |
@@ -90,8 +90,8 @@ spec detail deferred to phase 1.
| `window_change_request` | `TtyControlHandle::resize(cols, rows, pixel_w, pixel_h)` | | `window_change_request` | `TtyControlHandle::resize(cols, rows, pixel_w, pixel_h)` |
| `signal` | `TtyControlHandle::signal(name)` (alktty's `signal_from_name` accepts the HUP/INT/TERM/... names verbatim) | | `signal` | `TtyControlHandle::signal(name)` (alktty's `signal_from_name` accepts the HUP/INT/TERM/... names verbatim) |
| data / `extended_data(1)` | channel duplex in/out; stderr only meaningful in pipe mode (PTY merges) | | data / `extended_data(1)` | channel duplex in/out; stderr only meaningful in pipe mode (PTY merges) |
| `exit_status` | from `TtyHandle.exit_code` (`TtySession.wait()` semantics: i32; negative = signal-terminated) — alkssh sends the SSH `exit-status` request before channel close (POC-3: proven both directions via the cloned `Session::handle()` from the spawned serving task) | | `exit_status` | from `TtyHandle.exit_code` (`TtySession.wait()` semantics: i32; negative = signal-terminated on the pipe path — `pipe.rs::exit_code_from` maps Unix `ExitStatus::signal()` to `−sig`; the PTY path reduces signal termination to a plain exit code, see the exit_signal row) — alkssh sends the SSH `exit-status` request before channel close (POC-3: proven both directions via the cloned `Session::handle()` from the spawned serving task); `−1` (alktty's could-not-determine sentinel, alktty ADR-004 §4) → `exit-status(255)` |
| `exit_signal` | Only reachable in signal-termination cases; mapped from the same exit-code path (OQ: exact encoding). **[POC-3]** the alktty exit chunk is `{"type":"exit","code":N}` — a negative code implies signal termination but carries no *name*, so the faithful `exit-signal` mapping needs alktty to widen the chunk or an assembly-policy default. **[Corrected 2026-10-27]** the "needs widening" premise was wrong: the negative code *is* the documented signal encoding (alktty ADR-004, ported from alknet ADR-055; `pipe.rs::exit_code_from` — Unix `ExitStatus::signal() → -sig`), so the name is derivable server-side by alkssh; no chunk change is justified by default. The genuine gaps (core-dumped discarded, the `−1` wait-failure/SIGHUP collision, non-Unix) are alkssh mapping-contract details — alkssh OQ-10 | | `exit_signal` | derived server-side from the exit chunk's negative code — `−N` → name via a Unix signal-number→name table; `core_dumped` never asserted (alktty discards `ExitStatus::core_dumped()`); no chunk change is needed or proposed (the encoding is alktty's documented contract, alknet ADR-055 lineage). POC-3 observed `−15` → `exit-signal("TERM")` live on the pipe path. PTY path: portable-pty 0.9's `ExitStatus` conversion yields `code = status.code().unwrap_or(1)` (**1**) for signal-terminated children, keeping the signal only in a separate humanized (`strsignal`) string field alktty's waiter discards — faithful `exit-signal` on the PTY row needs the alktty backend to conform to its own ADR convention (upstream ask: alktty/portable-pty trackers; the alkssh contract adapts automatically) |
## Data-plane / limits contract ## Data-plane / limits contract
+42 -35
View File
@@ -266,37 +266,41 @@ against a **real PTY** (`LocalTtyBackend` over portable-pty):
(parse-then-route: the git parse is the `git` feature's gate) — (parse-then-route: the git parse is the `git` feature's gate) —
the feature-split failure matrix holds in this build too. the feature-split failure matrix holds in this build too.
### 2. The signal-identity gap (new OQ) ### 2. Signal/exit fidelity over the alktty exit-code convention
The exit chunk is `{"type":"exit","code":N}` — a negative code says The exit chunk is `{"type":"exit","code":N}` (alktty ADR-004, ported
*signal-terminated* but **carries no signal name**. The adapter cannot from alknet ADR-055). Findings of this stage, verified against the
map SSH `exit-signal` faithfully from the chunk alone (the POC's check published sources:
asserts TERM because the *request* was TERM, not because the chunk
said so). Options for the ADR: alktty widens the exit chunk with the
signal name, or alkssh fixes the exit-signal name by assembly policy.
Also recorded: pipe-mode signals are **pid-only** (a SIGTERM to `sh -c
"sleep 60"` leaves the orphaned `sleep` holding the stdout pipe — no
exit chunk until the whole group dies); PTY-mode signals reach the
process group (correct terminal semantics). The signal row's fidelity
therefore depends on the tty/pipe mode split the table already notes.
**[Corrected 2026-10-27]** The "signal-identity gap" framing above was - **Pipe path — the negative code is the signal encoding.** Pipe-mode
an incorrect assumption, surfaced during review and now corrected in signal-terminated children arrive as the negative signal number
the alkssh tracker (OQ-10). The exit chunk's negative code *is* the verbatim from std's `ExitStatusExt` (`pipe.rs::exit_code_from` maps
signal identity, by alktty's documented one-way convention (alktty `ExitStatus::signal()` to `−sig`; the alknet ADR-055 convention).
ADR-004 decision 1, ported from alknet ADR-055; So SSH `exit-signal` needs no wire change: the adapter's check
`src/local/pipe.rs::exit_code_from` maps Unix `ExitStatus::signal()` mapped `−15` → `exit-signal("TERM")` — the name derivation is a
to `-sig`) — the tty/pty ground truth (a reaped wait-status, server-side number→name table lookup, not an alktty ask.
preserved across one backend-wide `exit_code → i32` API), not an - **PTY path — the signal number does not survive the backend.**
absence. The signal *name* is derivable server-side by alkssh, so portable-pty 0.9's `ExitStatus` conversion records
"alktty widens the chunk" is not a justified default candidate: it `code = status.code().unwrap_or(1)` → **1** for signal-terminated
would change `ControlMessage::Exit`'s one-way parsed shape, force the children, keeping the signal only in a separate humanized
backend-wide API to widen, and ripple the alknet ADR-055 lineage — an (`strsignal`-text) string field that alktty's PTY waiter discards
alktty ADR with explicit justification, only if a fidelity failure (`pty.rs` reads `exit_code()` only; the number is unrecoverable
demands it. The genuine gaps — core-dumped (discarded), the `−1` through portable-pty 0.9's trait surface). Alktty's own PTY signal
wait-failure/SIGHUP collision (pre-existing, documented in alktty tests assert `code != 0`, never the encoding. Consequence: faithful
ADR-004 with an additive `exit_error` escape), and non-Unix semantics `exit-signal` for signal-killed PTY sessions needs the alktty
— are alkssh mapping-contract details. backend to conform to its own ADR's negative-code convention — an
alktty/portable-pty ask with tty/pty-grounded justification (upstream
trackers; the alkssh mapping adapts automatically, no hedge needed).
- **The `−1` sentinel** (backend wait failure) collides with a real
SIGHUP termination (signal 1) — documented in alktty ADR-004 §4,
with an additive `exit_error` control type as its recorded extension
seam. Alkssh renders `−1` as `exit-status(255)` — it fabricates no
signal for a wait failure.
- **Pipe-mode signals are pid-only** (a SIGTERM to `sh -c "sleep 60"`
leaves the orphaned `sleep` holding the stdout pipe — no exit chunk
until the whole group dies); PTY-mode signals reach the process
group (correct terminal semantics). The signal row's fidelity
depends on the tty/pipe mode split the table already notes.
### 3. Client-visible mechanics (russh 0.64 API facts from this stage) ### 3. Client-visible mechanics (russh 0.64 API facts from this stage)
@@ -334,7 +338,7 @@ ADR-004 with an additive `exit_error` escape), and non-Unix semantics
per bridged route. per bridged route.
- "stage D may surface PTY-merge stderr surprises that reshape the - "stage D may surface PTY-merge stderr surprises that reshape the
request-level mapping rows" — partially: no surprises in the request-level mapping rows" — partially: no surprises in the
PTY/pipe split, but the **signal-identity gap** and the PTY/pipe split, but the **signal/exit-fidelity details** and the
**translation-bridge shape** (two adapters, not a pump) do reshape **translation-bridge shape** (two adapters, not a pump) do reshape
the session row's implementation notes. the session row's implementation notes.
@@ -350,16 +354,19 @@ ADR-004 with an additive `exit_error` escape), and non-Unix semantics
family-native clients; vanilla `-D` rides the `tunnel` row. family-native clients; vanilla `-D` rides the `tunnel` row.
3. `mapping-table.md` session/pty row implementation notes: the 3. `mapping-table.md` session/pty row implementation notes: the
alktty bridge is a **translation bridge** (chunk framing both alktty bridge is a **translation bridge** (chunk framing both
directions), not a byte pump; plus the exit-chunk signal-identity directions), not a byte pump; plus the exit/signal fidelity
gap above. findings above (pipe-path `−N` encoding holds; PTY path reduces
signal termination to a plain code — portable-pty's exit surface).
## OQ seeds carried forward ## OQ seeds carried forward
1. Session-channel dispatch shape for SOCKS (first-byte sniff vs 1. Session-channel dispatch shape for SOCKS (first-byte sniff vs
in-band preamble vs exec marker; the detect window's bound). in-band preamble vs exec marker; the detect window's bound).
2. Exit-chunk signal identity (alktty exit chunk widening vs 2. Exit/signal fidelity over the alktty exit-code convention (the
assembly-policy mapping; pipe-mode pid-only vs PTY process-group `−N` encoding holds on the pipe path — name derivation is
scope). server-side; the PTY path's signal-identity loss is an
alktty/portable-pty matter; pipe-mode pid-only vs PTY
process-group scope).
3. Shell command convention (already seeded; the POC's stand-in — 3. Shell command convention (already seeded; the POC's stand-in —
`bash` for shell, `sh -c <cmd>` for exec — is an explicit assembly `bash` for shell, `sh -c <cmd>` for exec — is an explicit assembly
policy, not wire-derived). policy, not wire-derived).
+4 -6
View File
@@ -138,12 +138,10 @@ forms). russh server loopback + vanilla clients; per stage:
original plan was unnecessary — stage D completed 13/13 and produced original plan was unnecessary — stage D completed 13/13 and produced
the load-bearing session-row corrections: the alktty bridge is a the load-bearing session-row corrections: the alktty bridge is a
**translation bridge** (chunk framing both directions, not a byte **translation bridge** (chunk framing both directions, not a byte
pump) and the alktty exit chunk carries no signal identity pump) and the exit/signal findings over the alktty exit-code
(`poc-3-mapping-bakeoff.md` §Stage D). [Corrected 2026-10-27: the convention (pipe-path signal termination rides the negative code
"no signal identity" claim overstated the gap — the exit chunk's `−N`; the PTY path reduces signal termination to a plain exit
negative code *is* the documented signal encoding (alktty ADR-004); code — `poc-3-mapping-bakeoff.md` §D.2).
see `poc-3-mapping-bakeoff.md` §D.2's correction and alkssh
OQ-10.]
**Validates:** the one-seam-per-mapping hypothesis; the parse-then- **Validates:** the one-seam-per-mapping hypothesis; the parse-then-
route dispatch; stderr semantics in pipe vs PTY mode; EOF/close/signal route dispatch; stderr semantics in pipe vs PTY mode; EOF/close/signal