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.
1.8 KiB
1.8 KiB
OQ-43: TtyControl as a Clone trait object
- Origin: crates/tty/tty-backend.md
(the
TtyHandle.controlfield shape);docs/research/alknet-tty/phase-0-findings.mdOQ-TTY-01 (the trait- shape open question the local-PTY POC resolved). - Status: resolved
- Door type: One-way (the
TtyControltrait shape is part of theTtyBackendAPI surface — ADR-053), two-way (the concreteTtyControlHandlenewtype mechanism) - Priority: medium
- Resolution:
TtyHandle.controlisOption<TtyControlHandle>.TtyControlHandleis a concrete#[derive(Clone)]newtype wrappingArc<dyn TtyControl + Send + Sync>; the adapter clones theArcto hand a handle to the spawned control-chunk dispatcher. TheTtyControltrait itself is NOTClone—Cloneis not object-safe (fn clone(&self) -> SelfreturnsSelf, which forbidsdyndispatch), soBox<dyn TtyControl + Clone>does not compile. The design splits the concerns: the trait stays object-safe (Send + Sync, noClone); the newtype carries theClone-ability. The local-PTY POC used a concretePtyControlstruct (inherentlyClone— it heldArc<Mutex<...>>fields); the newtype generalizes the POC's shape so a backend produces its own control type viaTtyControlHandle::new(Arc::new(MyControl))without the adapter knowing the concrete shape. TheCloneconstraint exists because the adapter's control-chunk dispatcher needs to be handed off to the spawned pump task (the POC'ssession::drive_sessionclonespty.controlfor the client→backend pump). See ADR-053 andtty-backend.md. - Cross-references: ADR-053, tty-backend.md,
/workspace/alknet-tty-poc/src/local_pty.rs(PtyControl)