- five stories under docs/stories/runtime-v2/: 1 streaming subprocess (42's follow-up; five forks incl. the mailbox-cap collision), 2 PTY, 3 signals-as-events (signalfd lean), 4 termios adoption, 5 SCM_RIGHTS fd passing; 00-story states the arc — the plane learned sockets in 8/11/35, files in 6, this adds processes/terminals/signals - build order 1 -> 2 -> 3; 4 and 5 startable alone; all readiness: refine, brainstormed on demand - board: Five tracks; "▸ runtime-v2" pending section; wmux section now points at it; graph section 6 nodes carry runtime-v2 numbers + links - wmux stories re-reference the track; prefix `rt2` claimed - linkcheck: 0 broken Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit e0451cb4889bb3d03429c0276d03c090269a5ced)
3.4 KiB
| track | iteration | status | readiness |
|---|---|---|---|
| runtime-v2 | 1 | pending | refine |
runtime-v2 1 — streaming subprocess: a long-lived child as a peer
Part of Story — runtime-v2: the runtime beyond sockets. Iteration 42's named follow-up, promoted to this track's opening slice. 42 built the machinery a streaming form reuses whole: the
wo_childregistry, the pidfd wait, the epoll bundle, the cap/refusal doctrine, the ownership sweeps (fib_reap/wo_vm_destroy/stop).The problem.
proc.run/proc.run_dlare one-shot: nothing can talk to a child while it runs, and a child that legitimately runs for hours (a shell under wmux, a browser under the CDP driver, a script under skillhost) has no shape at all. Output must reach the owning actor as it happens, stdin must reach the child, and exit must arrive as an event — all without violating a single 42 guarantee.
Info — the forks (open; why this is refine)
- Verb shape. A new
proc.spawn(cmd, args, …)returning a child HANDLE, versus spawn-options onproc.run_dl. Sub-fork: the handle as an actor address (the child looks like an actor —sendto feed stdin,monitorfor exit, iteration 24 machinery free) versus an opaque scalar with its own verb family. - Output transport. PUSH — stdout/stderr chunks delivered as
Bytesmessages into the owner's mailbox (the fd-event pattern) — versus PULL — aread-style verb the fiber parks on, thenet.read_dlmould. Push composes with actors; pull composes with backpressure. - The mailbox-cap collision — the fork that decides whether push is
viable at all: a chatty child versus
wo_mailbox_cap's fail-fast 1024. Drop chunks? Kill the child by name? Or stop reading the pipe and let the KERNEL buffer be the backpressure (the lean — the child blocks on a full pipe exactly as it would under a slow tmux). - stdin and its mirror. Child not reading, pipe full: park the
writing fiber with a deadline (the
net.write_dlmould) versus refuse at a byte cap. - Bounds semantics shift. Total-output cap and total deadline stop
meaning anything for a shell that runs for days — per-chunk caps and
an IDLE deadline replace them; exit notification as a monitor-style
death notice carrying the code, versus a blocking
waitverb.
Ownership does not fork: 42's rule stands — the owner unwinding kills the child; engine stop kills them all; a zombie or an orphan is a bug.
Acceptance sketch (firmed at brainstorm)
- A child that emits a line a second: each line reaches the owning actor while the child lives — not after it exits.
- stdin round trip: feed a
cat-like child, read the echo back. - The chatty child against whatever fork 3 picked: the declared behavior happens, by name, and the shard never stalls.
- Exit: the owner learns the code as an event; the registry slot is released; fd count flat (the 42 measurement legs, streaming edition).
- Stop/unwind: identical guarantees to 42, proven with a LIVE stream.
- Gate legs land in
runtime/test/test_proc.cbeside 42's.
Consumers
wmux 1 (the shell under every pane), skillhost 28 (stdin/stdout transport was half its named gap), the zen study's CDP driver (spawn the browser, then talk to it). The alacritty stage-A "headless PTY runner" is this plus runtime-v2 2.