C1: Box<dyn TtyControl + Clone> does not compile (Clone is not object-safe). Replace with a TtyControlHandle newtype: #[derive(Clone)] wrapping Arc<dyn TtyControl + Send + Sync>. The trait stays object-safe; the newtype carries the Clone-ability. Updated across tty-backend.md, ADR-053, OQ-43, and the tty README. W1: 'Drop is the cleanup, threads exit on channel close' was false for the local PTY waiter thread (blocked in Child::wait(), does not observe channel close) — a child that ignores stdin EOF would be orphaned on session cancel. New ADR-056 commits a backend cleanup contract: dropping the exit_code future MUST kill the session target. The local backend implements it via a ChildKiller held in the exit_code future's Drop guard (disarmed on resolve). Corrected the lifecycle section in tty-adapter.md, added the mechanism + constraint to tty-local.md, and referenced ADR-056 from tty-backend.md, overview.md, both READMEs. S1: error-frame < 16 MiB stated as a wire-format invariant (not an assumption) so the 0x00-first-byte disambiguation trick is sound by construction. S2: carriage field validation (MUST be "raw" in v1, else malformed_negotiation) specified. S3: NegotiateRequest + TerminalParamsWire Rust structs added with serde defaults and validation rules. S4: modes field annotated 'backends MUST ignore content in v1' in both tty-backend.md and ADR-053. S5: AsyncWrite/Stream qualified with crate origins (tokio::io, futures_core) in the TtyHandle struct definitions.
32 lines
1.8 KiB
Markdown
32 lines
1.8 KiB
Markdown
# OQ-43: `TtyControl` as a `Clone` trait object
|
|
|
|
- **Origin**: [crates/tty/tty-backend.md](crates/tty/tty-backend.md)
|
|
(the `TtyHandle.control` field shape);
|
|
`docs/research/alknet-tty/phase-0-findings.md` OQ-TTY-01 (the trait-
|
|
shape open question the local-PTY POC resolved).
|
|
- **Status**: resolved
|
|
- **Door type**: One-way (the `TtyControl` trait shape is part of the
|
|
`TtyBackend` API surface — ADR-053), two-way (the concrete
|
|
`TtyControlHandle` newtype mechanism)
|
|
- **Priority**: medium
|
|
- **Resolution**: `TtyHandle.control` is `Option<TtyControlHandle>`.
|
|
`TtyControlHandle` is a concrete `#[derive(Clone)]` newtype wrapping
|
|
`Arc<dyn TtyControl + Send + Sync>`; the adapter clones the `Arc` to
|
|
hand a handle to the spawned control-chunk dispatcher. The
|
|
`TtyControl` trait itself is NOT `Clone` — `Clone` is not object-safe
|
|
(`fn clone(&self) -> Self` returns `Self`, which forbids `dyn`
|
|
dispatch), so `Box<dyn TtyControl + Clone>` does not compile. The
|
|
design splits the concerns: the trait stays object-safe (`Send +
|
|
Sync`, no `Clone`); the newtype carries the `Clone`-ability. The
|
|
local-PTY POC used a concrete `PtyControl` struct (inherently `Clone`
|
|
— it held `Arc<Mutex<...>>` fields); the newtype generalizes the POC's
|
|
shape so a backend produces its own control type via
|
|
`TtyControlHandle::new(Arc::new(MyControl))` without the adapter
|
|
knowing the concrete shape. The `Clone` constraint exists because the
|
|
adapter's control-chunk dispatcher needs to be handed off to the
|
|
spawned pump task (the POC's `session::drive_session` clones
|
|
`pty.control` for the client→backend pump). See ADR-053 and
|
|
`tty-backend.md`.
|
|
- **Cross-references**: ADR-053, [tty-backend.md](crates/tty/tty-backend.md),
|
|
`/workspace/alknet-tty-poc/src/local_pty.rs` (`PtyControl`)
|