Await Windows JSONL stdin the way each handle allows
Class
Windows JSONL input used a blocking stdin adapter for every handle. Overlapped named pipes now use IOCP, console text uses an owned handle with streaming UTF-16 decoding, and synchronous files/pipes use one persistent cancellable reader.
Readiness did not protect an inherited blocking descriptor: a competing reader could drain it before read. Dropping the detached worker then left it consuming input after ownership had returned. Recycling short batches also repeated initialization of already initialized storage.
Why it cannot recur
- Linux privately reopened nonblocking input stays on AsyncFd. Shared descriptions and files use one native worker without changing shared flags.
- The worker enables deferred POSIX cancellation only in its C poll/read frames, and disables it during every Rust callback. Pending cancellation covers admission; cancellation releases a read already in flight. Drop closes the bounded handoff, cancels and joins before freeing the file or storage.
- Unix async reads enter through a narrow read-only RestoreGuard method, so they cannot increment the screen invalidation counter. The merged redraw regression and its tracked-read negative control exercise real PTY frames.
- InputBatch owns initialized storage and a separate valid prefix. Both Harness and TUI handoffs return the complete storage for the next read; neither truncates or resizes it.
- Windows console input avoids the process-wide stdin lock; Ctrl+Z terminates input, and split surrogate pairs retain their decoder state. Disk reads stay off the runtime.
- Terminal input retains epoll/kqueue on Unix and the persistent console waiter on Windows. The shared decoder, lifecycle fences and mode restoration remain in use.
Verification
Linux at #910 descendant 35b742dc8: stdin 34/34 in 0.31 s; InputBatch properties 2/2 in <0.01 s; terminal units 17/17 in 0.09 s; PTY input 6/6 in 0.89 s; signals 7/7 in 0.04 s; CLI 6/6 in 0.31 s. Native build 14m00s. Dedicated production-reader models/properties passed 13/13 in 0.23 s (direct compile 0.617 s); terminal models and negative controls passed 45/45 in 2.41 s (build 20.75 s). Exactly zero idle wakeups; input p50 19.580 us, p99 44.317 us, max 61.693 us. Windows GNU libraries/tests for Harness, TUI, native-runtime and GraphCoder: passed at bb4ac5464 in 333.23 s on bb2 (cold target; queue excluded).
Syscall-controlled production-reader tests steal readiness before read, require acknowledged shutdown, then write a byte after Drop and verify it remains unread. The detached-reader negative control consumes that byte. The earlier sleep-based drop check covered an idle poll, but missed a competing reader stealing readiness before the blocking read. This belongs in native reader regression coverage: the new controlled interleaving calls the production reader at that admission boundary and requires shutdown acknowledgment before post-drop input. Real-channel Loom models cover shutdown, queue-space notification and atomic waker registration, with deliberately broken controls.
Both handoffs require exactly zero warm allocations and zero tail writes. Negative controls restore exactly 65,535 and 1,023 writes and fail the same zero-work assertions. Independently initialized Vec baselines compare complete bytes, exact errors and read/publication/receive order through acyclic_test_support::differential. InputBatch proptests check generated valid prefixes and unchanged initialized storage.
macOS: 12 production-reader/property/native checks passed in 0.381 s (existing target compiled directly in 0.212 s), including the strengthened admitted-read probe and its negative control. Terminal units and both handoff checks passed 17/17 in 0.22 s (build 2.43 s), including exactly zero redundant PTY redraw bytes and the tracked-read negative control. Real macOS PTY input passed 8/8 in 0.90 s and signals 7/7 in 0.19 s (build 3.01 s). Input p50 3.5 us, p99 12.125 us, max 48.375 us, with exactly zero idle wakeups. After all macOS jobs ended, the lane target ~/mac-target/tui-async and source ~/tui-async-src were deleted under the updated disk rule; free space was 19 GiB. Future runs use RUSTC_WRAPPER=/opt/homebrew/bin/sccache and remove the target and source after validation.
Real Windows at final bb4ac5464: waiter checks 5/5 in 0.22 s (build 8.45 s); frame checks 5/5 in 0.07 s and handoff differential/work checks 3/3 in <0.01 s, all using the same binary. ConPTY break/close/blocked-output restoration passed in 1.363 s. Warm allocations and idle wakeups were exactly zero; handoff p50 2.6 us, p99 510.4 us, max 518.7 us. The Windows-only owner-field migration preserves the single shared console owner. Linux/macOS source is unchanged from validated 35b742dc8.
Windows stdin's unchanged production path passed 6/6 in 0.04 s; ConPTY Unicode/surrogate-pair, Ctrl+Z and cancellation under stdin lock passed in 1.493 s. The full MSVC Harness unit compiler crashed with STATUS_ACCESS_VIOLATION; the focused existing production-reader target compiled in 1.83 s against fresh native dependencies and passed the same Windows tests and host script.
Commands: cargo test --locked -p acyclic-harness -p graphcoder -p acyclic-native-runtime -p acyclic-harness-tui --features acyclic-harness/filesystem-local,acyclic-harness/native-execution,acyclic-harness/test-support,acyclic-harness/terminal,acyclic-harness/tui --lib --test cli --test terminal_input --test terminal_signals --no-run; run the emitted focused binaries directly. Reader models: rustc --edition=2024 --test --crate-name stdin_reader_model rust/crates/harness/tests/stdin_reader_model.rs --cfg acyclic_harness_loom, with --extern and -L dependency paths from that native build JSON, then run the emitted binary with reader::. Terminal models: RUSTFLAGS='--cfg acyclic_harness_tui_loom' cargo test --locked -p acyclic-harness-tui --features tui --lib term::. Paired work/behavior checks: reader::tests::recycled_ and term::handoff::reuse_tests:: in the ordinary binaries.
Review fix relative to 47cde843c: 191 lines deleted across native reader and handoff paths, including the detached Unix reader and cancel-pipe path.
Decisions
- Native cancellation stays within the existing native-runtime OS boundary; no new unsafe lint exceptions, application signal handlers or shared descriptor flag changes.
- Preserve published history through signed merges. The shared fixes are on #869, and #910 carries them with its Windows stdin implementation.
- #874 and #957 remain drafts under the lane's two-PR review limit. #871 was closed because main #885 superseded it.
Live steps
The full macOS GraphCoder CLI qualification was attempted: build 13m50s; 1/6 passed and 5/6 failed in 1.32 s before input handling with "source does not support original native work custody". Filesystem and CLI test sources match main 66ddfd542. The custody invariant is preserved. Every focused changed macOS native check passed. No lane target, source copy or tarball remains on ivar. Future builds use RUSTC_WRAPPER=/opt/homebrew/bin/sccache and delete their target and source after validation.