docs(architecture): OQ-10 premise corrected — the negative exit code IS the signal identity
- OQ-10's seed overstated alktty's exit-chunk design as a 'signal-identity gap': the negative code is the documented signal encoding (alktty ADR-004, ported from alknet ADR-055; src/local/pipe.rs::exit_code_from — Unix ExitStatus::signal() → -sig), a tty/pty-grounded convention - 'alktty widens the chunk' demoted from co-equal candidate to gated exception: it would widen ControlMessage::Exit's one-way parsed shape, the backend-wide exit_code API, and the alknet ADR-055 lineage — requires an alktty ADR with explicit tty/pty-grounded justification, never an alkssh convenience ask - OQ-10 re-scoped to the real remaining detail: −1 (wait failure vs SIGHUP) collision, core-dumped disposition, non-Unix semantics, name derivation - correction notes added in place: poc-3 §D.2, pocs.md, mapping-table.md (both rows); mapping.md exit_signal row updated Verification: cargo doc --no-deps (docs-only change)
This commit is contained in:
1 parent
ff2d69c67b
commit
9217a8b3cf
5 files changed
+43
-13
No files matched your search
@@ -76,7 +76,7 @@ the served listen flow is implementation-phase contract-test territory.*
|
||||
| `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) |
|
||||
| `exit_status` | from the alktty exit chunk — sent **before** close, from the spawned task via `Session::handle()` (POC-3 §D: proven both legs) |
|
||||
| `exit_signal` | only for signal-terminated exits; OQ-10 (chunk carries no signal name — alktty ask + assembly fallback pending) |
|
||||
| `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 |
|
||||
|
||||
## The structural constraint: spawn-and-return
|
||||
|
||||
@@ -123,9 +123,7 @@ under `--all-features`.
|
||||
|
||||
- **OQ-08** (shell convention — status: open): blocks this doc's
|
||||
`shell_request`/`NegotiateRequest.cmd` row detail.
|
||||
- **OQ-10** (exit-chunk signal identity — status: open): blocks the
|
||||
`exit_signal` row's precise encoding; the fallback direction is
|
||||
recorded there.
|
||||
- **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-11** (streamlocal platform decline shape — status: open).
|
||||
- ~~OQ-02~~ (dispatch composition — resolved by ADR-006, as amended).
|
||||
|
||||
|
||||
@@ -94,14 +94,24 @@ alkcall trackers have their own OQ spaces).
|
||||
- **Blocked on**: a concrete consumer use case requiring wire-supplied environment variables.
|
||||
- **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?
|
||||
### OQ-10: ~~"The alktty exit chunk carries no signal identity — widen the chunk or map by assembly policy"~~ — premise corrected; re-scoped
|
||||
|
||||
- **Origin**: [poc-3-mapping-bakeoff.md](../research/poc-3-mapping-bakeoff.md) §D.2, `mapping-table.md` (exit_signal row)
|
||||
- **Status**: open
|
||||
- **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.
|
||||
- **Status**: open — re-scoped to the SSH-fidelity derivation details; the detail decision lands during `mapping.md`
|
||||
- **Priority**: medium
|
||||
- **Impacts**: blocks the `exit-signal` fidelity detail in `mapping.md`; an in-family upstream ask (alktty wire change, third-party-upstream posture applies family-internally too).
|
||||
- **Resolution**: pending. Candidates (per POC-3): alktty widens the exit chunk with the signal name (filed as an ask — alkssh never silently works around), or alkssh maps negative exit codes via assembly policy (fidelity compromise: name inferred/coarse). Also in scope for the same OQ: pipe-mode signals are pid-only vs PTY process-group scope (backend-semantics fidelity note for the session rows). Decide the *fallback* during `mapping.md`; the upstream ask stays open until alktty answers.
|
||||
- **Cross-references**: OQ-08
|
||||
- **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.
|
||||
- **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.
|
||||
- **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.
|
||||
- **What is genuinely missing** (the re-scoped open detail — all alkssh mapping-contract territory):
|
||||
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).
|
||||
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).
|
||||
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.
|
||||
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?
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ request-level extras.
|
||||
|
||||
| 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) |
|
||||
| `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` → `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` → 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]** |
|
||||
@@ -91,7 +91,7 @@ spec detail deferred to phase 1.
|
||||
| `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) |
|
||||
| `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_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 |
|
||||
| `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 |
|
||||
|
||||
## Data-plane / limits contract
|
||||
|
||||
|
||||
@@ -280,6 +280,24 @@ 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
|
||||
an incorrect assumption, surfaced during review and now corrected in
|
||||
the alkssh tracker (OQ-10). The exit chunk's negative code *is* the
|
||||
signal identity, by alktty's documented one-way convention (alktty
|
||||
ADR-004 decision 1, ported from alknet ADR-055;
|
||||
`src/local/pipe.rs::exit_code_from` maps Unix `ExitStatus::signal()`
|
||||
to `-sig`) — the tty/pty ground truth (a reaped wait-status,
|
||||
preserved across one backend-wide `exit_code → i32` API), not an
|
||||
absence. The signal *name* is derivable server-side by alkssh, so
|
||||
"alktty widens the chunk" is not a justified default candidate: it
|
||||
would change `ControlMessage::Exit`'s one-way parsed shape, force the
|
||||
backend-wide API to widen, and ripple the alknet ADR-055 lineage — an
|
||||
alktty ADR with explicit justification, only if a fidelity failure
|
||||
demands it. The genuine gaps — core-dumped (discarded), the `−1`
|
||||
wait-failure/SIGHUP collision (pre-existing, documented in alktty
|
||||
ADR-004 with an additive `exit_error` escape), and non-Unix semantics
|
||||
— are alkssh mapping-contract details.
|
||||
|
||||
### 3. Client-visible mechanics (russh 0.64 API facts from this stage)
|
||||
|
||||
- russh client has `Channel::exec()` (there is no `request_exec`);
|
||||
|
||||
@@ -139,7 +139,11 @@ forms). russh server loopback + vanilla clients; per stage:
|
||||
the load-bearing session-row corrections: the alktty bridge is a
|
||||
**translation bridge** (chunk framing both directions, not a byte
|
||||
pump) and the alktty exit chunk carries no signal identity
|
||||
(`poc-3-mapping-bakeoff.md` §Stage D).
|
||||
(`poc-3-mapping-bakeoff.md` §Stage D). [Corrected 2026-10-27: the
|
||||
"no signal identity" claim overstated the gap — the exit chunk's
|
||||
negative code *is* the documented signal encoding (alktty ADR-004);
|
||||
see `poc-3-mapping-bakeoff.md` §D.2's correction and alkssh
|
||||
OQ-10.]
|
||||
|
||||
**Validates:** the one-seam-per-mapping hypothesis; the parse-then-
|
||||
route dispatch; stderr semantics in pipe vs PTY mode; EOF/close/signal
|
||||
|
||||
Reference in new issue
Block a user