--- id: w4-tty-coverage name: "Wave 4: tty coverage minors (wave-3 gate booked item 3)" status: completed depends_on: [w4-channel-not-held-rows] scope: narrow risk: low impact: component level: implementation --- ## Description Close the wave-3 gate's booked finding item 3 (`review-wave-3` §Booked findings, "minors, one ticket's worth"): - **The `channel_close`-fired per-channel cancel path is unexercised on the wire**; only the teardown signal is. Land the wire row: a channel closing (client-side close on a served tty row) fires the per-channel cancel path (the cap release + the per-channel state teardown observed, the disjoint release sites the gate verified per row, now wire-witnessed for this path). - **The Closed/Break no-exit-chunk close shape has no wire row**, so land the row(s): a session ending via the Closed/Break close shape emits **no exit chunk** (the derivation contract's close-shape class, the absent-report posture pinned, not just the happy paths). - **The tty stdout `write_all` carries no deadline**, recorded as a **known limit only** (module docs): backpressure is bounded, liveness is covered by the inactivity timeout; no code change (the gate's recorded disposition, since a deadline here is a behavior change, not a coverage minor). Depends on `w4-channel-not-held-rows` to keep `tests/tty_mapping.rs` single-writer (that task's rows land first; these land into the settled file). ## Acceptance Criteria - [x] Wire row: the `channel_close`-fired per-channel cancel path (cap release + state teardown observed on the wire) - [x] Wire row(s): the Closed/Break no-exit-chunk close shape - [x] The stdout `write_all` no-deadline limit recorded in module docs (no code change) - [x] `cargo test` (+ per-feature + `--all-features`), clippy ×2 (`-D warnings`), fmt, `cargo doc --no-deps` pass ## References - tasks/implementation/review-wave-3.md §Booked findings item 3 - docs/architecture/mapping.md §The exit derivation contract (the close-shape classes; the PTY-path rule-5 limit, the docs-posture template), src/tty_map.rs, src/channel_cap.rs (the release sites the rows witness) - tests/tty_mapping.rs (the per-build matrix the rows join) ## Notes - **Test + module-docs only, as planned**, hence no production code change; the shapes held on the wire exactly as documented. - **`channel_close`-fired cancel path**, namely `a_client_close_on_a_served_row_fires_the_per_channel_cancel_and_releases_the_cap` (`tests/tty_mapping.rs`, cfg `session`): a served pipe row under a cap of 1; a second open is refused (`AdministrativelyProhibited`, the admission held), the client then closes the served channel, and the row witnesses (a) the per-channel state teardown, with the shim's kill-on-drop witness fires (the bridge surface's cancel → the serving task aborts the alktty session), polled *before* unmount so it is the `channel_close` site, not the teardown; (b) no exit report fabricated on the wire (plain close / channel end); (c) the serving path's ended lifecycle event; (d) the **cap release**, with the next open admits and routes (release site 1, disjoint from the bridge-failure and arrival sites). - **Closed/Break no-exit-chunk close shape**, namely `a_bridge_end_without_an_exit_chunk_reports_nothing_and_closes_plain` (same file): the shape is constructed deterministically through the real path: the shim's stdout carries a payload beyond alktty's own `MAX_CHUNK_LEN` wire bound; alktty's `ChunkWriter` rejects it locally, its drainer shuts the write half down, and the bridge's next read is EOF (`BridgeFrame::Closed`) with the scripted exit (`Some(0)`) never forwarded. The row pins: the in-bounds chunk rode first, the end is a plain close, **no exit-status/exit-signal ever rides** (the absent-report posture, neither 0 nor 255), the session truly served (an allocation happened, so this is the close shape, not a decline), and the ended lifecycle event landed. - **Break's classification row**, which pins `clean_ends_classify_closed_and_oversized_lengths_classify_break` (`src/tty_map.rs` test mod): Break is **unreachable on the wire** through alktty's own validated `ChunkWriter` (an oversized chunk fails local validation → the drainer break → the read sees EOF, exactly the Closed row's construction; a non-EOF duplex read error has no wire-constructible producer at this pin, and the serving-path body of Closed/Break is one arm). So the family's *serving* outcome is wire-witnessed by the Closed row, and the frame-level `Break` classification (bounds-checked, never an oversized read) is pinned at the frame layer by the unit row, recorded here as the reason one wire row + one unit row cover the "row(s)". - **The stdout `write_all` no-deadline limit**, recorded in `src/tty_map.rs`'s module docs (§the translation bridge): the gate's recorded disposition verbatim; backpressure bounded, liveness covered by the inactivity timeout, a deadline would be a behavior change, not a coverage minor. No code change. - A `session_with_limits` / `session_config(limits)` driver variant was added to the binary (the cap row's ceiling of 1); `session_with` delegates unchanged. ## Summary The wave-3 gate's booked item 3 is closed: the `channel_close`-fired per-channel cancel path is now wire-witnessed (a served pipe row under a cap of 1: the refused over-cap open pins the admission, the client close pins the cancel, with the kill-on-drop witness firing before any teardown, no exit report is fabricated, the ended lifecycle event lands, and the succeeding re-open pins the cap release from the established-channel-close release site); the Closed/Break no-exit-chunk close shape landed its wire row (constructed through the real path via an oversized shim chunk dying at alktty's own `ChunkWriter` validation: EOF without an exit chunk → plain close, nothing fabricated, the scripted exit never forwarded) plus the frame-level Break classification row (Break is wire-unreachable through alktty's validated writer at this pin, as recorded); and the stdout `write_all` no-deadline limit is recorded in the module docs per the gate's disposition. No production code change. Verified: `cargo test` (default, `session`, `session,git`, `git`, `tunnel`, `sftp`, `--all-features`, with the tty rows' 5×-repeat flake check included), clippy ×2 (`-D warnings`), `cargo fmt --check`, `cargo doc --no-deps` 0 warnings, `taskgraph validate` ✓ (35 tasks).