writeonce/docs/stories/runtime-v2/02-pty.md
shoney.arickathil 6e997759e5 docs(rt2): close out runtime-v2 1-5
- five stories status: done; 00-story records the one-run landing
- spec History: three implementation amendments (Signal record not
  scalar, caller-owned stdio fds, handler-latch instead of signalfd)
- board NEXT PLAN entry with measured findings (zero transport code
  added; the tty-across-the-socket handover proven; the double-raw
  refusal restoring the terminal — the "bug" that was the design
  working); section rows flipped; graph nodes green
- CODE-LOGIC.md: the runtime-v2 section
- full belt quoted on the board: suites 0 fail both flavors (test_proc
  193/0, test_term 60/0), woc 557/0, subprocess 12/0, site 23/0

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit bc1b4f070693eb755ad6a9fd0c853fb3e2bda347)
2026-09-15 01:15:30 +02:00

47 lines
1.9 KiB
Markdown

---
track: runtime-v2
iteration: "2"
status: done
readiness: ready
---
# runtime-v2 2 — PTY: a child that believes it owns a terminal
> Part of [Story — runtime-v2: the runtime beyond sockets](00-story.md).
> After [1](01-streaming-subprocess.md): a streaming child whose stdio
> is a pseudo-terminal instead of pipes. A shell run over pipes disables
> its prompt, its line editing and its job control; a multiplexer is
> pointless without them.
>
> **The problem.** Nothing can allocate a PTY pair, place the child on
> the slave side as its controlling terminal, or resize it. The
> reference reading is `.dev/reference/tmux` `spawn.c` +
> `compat/fdforkpty.c` (~450 lines of C covering five platforms; Linux
> alone is far smaller).
## Info — the forks, settled (brainstorm 2026-09-01; spec:
[`2026-09-01-runtime-v2-design.md`](../../superpowers/specs/2026-09-01-runtime-v2-design.md))
1. **Separate verb**: `proc.spawn_pty(cmd, args, cols, rows) -> ?Child`
— its own builtin id (static arity table stays static), same Child
record with `in` and `out` both the master fd, `err` nil.
2. **Resize ships HERE**: `proc.resize(id, cols, rows)` → TIOCSWINSZ on
the slot; refusal by name on a pipe child.
3. **Transport settled by iteration 1's pull decision** — the master fd
is driven by the existing net verbs, nothing new.
4. **Master raw by default, no knobs** — until a consumer asks by name.
(`openpty` may need `-lutil` — the plan verifies the link line
before assuming.)
## Acceptance sketch
- A real shell spawned on a PTY prints a PROMPT (it never does over
pipes) — asserted on the bytes.
- Resize: the child (a script reading TIOCGWINSZ) observes the new size.
- `isatty` inside the child answers yes on all three fds.
- Kill/reap/stop legs identical to 1's, PTY edition; fd count flat.
## Consumers
wmux 1 (every pane), the alacritty study's stage A (the headless
expect-clone is exactly "spawn on a PTY, script it, assert").