Skip to content

CI only for yas-run/yas#86 (spawn exit report, on #85) — do not merge - #40

Closed
pcarrier wants to merge 10 commits into
ci-basefrom
spawn-exit
Closed

pcarrier wants to merge 10 commits into
ci-basefrom
spawn-exit

Conversation

@pcarrier

Copy link
Copy Markdown

Fork CI for yas-run#86 (yas-run's Actions are stuck org-wide). Do not merge.

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Coverage

Crate Lines Functions Regions
alacritty-driver 85.6% (1081/1263) 89.4% (84/94) 89.3% (1746/1955)
browser 25.5% (309/1212) 30.4% (34/112) 27.7% (605/2183)
cli 31.8% (6516/20466) 32.8% (598/1824) 32.9% (9634/29263)
client 64.9% (4685/7220) 67.3% (605/899) 63.3% (6079/9603)
composite-transport 96.3% (526/546) 98.4% (60/61) 96.2% (884/919)
compositor 54.9% (11401/20763) 66.1% (833/1261) 54.7% (15787/28844)
desktop 78.4% (4460/5691) 71.6% (393/549) 75.1% (6211/8267)
edge 62.9% (798/1268) 50.9% (82/161) 57.7% (1038/1799)
fonts 77.3% (1257/1626) 82.7% (129/156) 78.9% (2424/3071)
fssync 85.7% (1605/1872) 85.8% (182/212) 86.9% (2827/3255)
git 70.4% (4462/6334) 68.5% (337/492) 67.3% (6313/9386)
guest 67.3% (6829/10148) 67.0% (488/728) 66.6% (8935/13416)
lsp 78.7% (3573/4542) 80.8% (336/416) 76.7% (5408/7054)
proxy 63.0% (1854/2943) 56.2% (180/320) 63.3% (2860/4521)
runtime-dir 93.6% (117/125) 100.0% (14/14) 94.8% (218/230)
sd-notify 73.9% (68/92) 100.0% (6/6) 83.2% (109/131)
server 70.5% (83309/118137) 73.0% (6025/8254) 68.5% (111354/162635)
ssh 67.2% (708/1054) 75.9% (85/112) 67.2% (1105/1645)
terminal-model 49.9% (314/629) 62.3% (38/61) 50.3% (505/1004)
uplink 94.2% (582/618) 92.6% (50/54) 93.1% (1062/1141)
webrtc-forwarder 33.6% (1321/3932) 44.9% (146/325) 36.0% (2279/6336)
webserver 80.7% (1490/1846) 81.1% (193/238) 83.2% (2551/3067)
website 35.1% (355/1012) 34.4% (53/154) 35.8% (607/1694)
xtask 0.0% (0/5131) 0.0% (0/131) 0.0% (0/9124)
yas 88.6% (27626/31174) 93.6% (2114/2258) 83.6% (43394/51877)
Total 66.2% (165246/249644) 69.2% (13065/18892) 64.5% (233935/362420)

yas-run#90)

* Expect TIMEOUT from a terminal command wait nothing started

Since yas-run#54 a command wait that runs out before any command it could
report on has started answers TIMEOUT (NOT_FOUND stays for an exited
terminal or an evicted index). The client_host test still expected
NOT_FOUND, so it failed on main.

* Say what a terminal command wait answers when no command started

Since yas-run#54 the server answers TIMEOUT when a command wait runs out before
any command it could report on has started; wait_terminal_command's
documentation still said NOT_FOUND, which stays for an evicted index or
an exited terminal.

* Capture a surface at the revision its caller listed, in one round trip

capture_surface looks the window's revision up (a WATCH snapshot) before
CAPTURE: two round trips, three for a caller that listed the windows first
to choose one, as Ultimator's screenshots do. capture_surface_at(id,
revision, format) sends CAPTURE with the revision the caller has; when the
window changed since, the server answers STALE and it looks the window up
again and captures that, as capture_surface does.
* Expect TIMEOUT from a terminal command wait nothing started

Since yas-run#54 a command wait that runs out before any command it could
report on has started answers TIMEOUT (NOT_FOUND stays for an exited
terminal or an evicted index). The client_host test still expected
NOT_FOUND, so it failed on main.

* Say what a terminal command wait answers when no command started

Since yas-run#54 the server answers TIMEOUT when a command wait runs out before
any command it could report on has started; wait_terminal_command's
documentation still said NOT_FOUND, which stays for an evicted index or
an exited terminal.

* Write small files in place in one APPLY round trip

APPLY WRITE_INLINE items take item flag APPLY_ITEM_IN_PLACE (2), offered
with CAPABILITY_APPLY_IN_PLACE (32): the item writes as COMMIT of a
STAGE_IN_PLACE stage does (open with create and truncate through a final
symlink, no temporary, no rename), through one shared write_in_place. An
in-place write onto a directory is CONFLICT with {EISDIR, open} in the
item's ApplyOsErrors entry, as COMMIT's. The flag is INVALID on other item
kinds and with APPLY_ITEM_CREATE_PARENTS; APPLY_ITEM_EXTENDED_FLAGS lists it
beside the v1 baseline's APPLY_ITEM_FLAGS.

yas-client's write_in_place sends it for content within the server's
inline limit and stages the rest, so a write tool call that already spends
a round trip resolving or reading the file takes two in all, not three.
TypeScript codec parity (inPlace) and golden vector
fs.apply.in_place.payload.

* Allow InPlace::mode unread on Windows; wrap the capabilities paragraph

Review of yas-run#89: the mode an in-place write gives a file it creates is read
under cfg(unix) alone, so Windows' -D warnings build failed on dead_code
(Stage::mode had atomic_replace to read it). Windows files take their
directory's ACL; say so on the field. Rewrap yas.md's opt-in paragraph at 80
columns.
…un#85)

* Expect TIMEOUT from a terminal command wait nothing started

Since yas-run#54 a command wait that runs out before any command it could
report on has started answers TIMEOUT (NOT_FOUND stays for an exited
terminal or an evicted index). The client_host test still expected
NOT_FOUND, so it failed on main.

* Say what a terminal command wait answers when no command started

Since yas-run#54 the server answers TIMEOUT when a command wait runs out before
any command it could report on has started; wait_terminal_command's
documentation still said NOT_FOUND, which stays for an evicted index or
an exited terminal.

* Pace process output by its owner; drop a lagging watcher alone

A command that wrote faster than its spawning session read lost its
output and wedged that session's Process endpoint:

- output_reader read each pipe with no backpressure, so once the
  owner's binding was 1 MiB (or 1024 frames) behind, it was evicted
  like any watcher. Its ACKs then found no binding, the stdout Transfer
  was reset NOT_FOUND "process not found", and the exit never came.
- The eviction kicked the whole endpoint: route_outbound closed the
  session and returned, dropping the endpoint's event receiver. The
  session still accepted SPAWNs, but no later process on it ever
  reported output or an exit.

Now the owner paces the child: before each read, output_reader waits
until the owner's binding has a frame of room in its window (and at
most 32 unacknowledged frames), and reserves its queue slot, so the
owner is never evicted and a fast writer blocks on its pipe. Watchers
of other sessions are still dropped when they fall a window behind,
but alone: the endpoint reports evicted process IDs, their routes
fail, and their attachments reset their Transfers RESOURCE_EXHAUSTED.
A full route queue fails that route rather than the session, output
for a route that already left is dropped, and a WAIT whose route
left looks again instead of failing. close_session keeps its error
(send_replace: nobody subscribes to it).

Server-only; clients are unchanged.

* Keep a paced owner's output past the exit; free an evicted watcher's slot

Review of yas-run#85 (four paths it left):

- An evicted watcher's binding left its endpoint slot behind, so a
  session that kept watching ran out of its 16 process slots. The
  eviction now frees the slot.
- Detach answered Conflict once the child had exited, while its output
  could still be draining. A route that failed then (its queue full)
  left a binding whose exit found no route and closed the session; an
  owner that dropped its stream then left a binding nobody acknowledged,
  and its WAIT answered Conflict. Detach now goes through until the exit
  is queued, and an exit for a route that already failed is dropped
  rather than closing the session.
- Once the child exited, the cleanup stopped waiting for its streams
  after the kill grace (or a LEAVE_RESIDUE grace), and dropped what the
  pipe still held for an owner slow to take its window: a slow link, or
  a client that waits for the exit first. With nothing of the group left,
  the readers the owner paces now go on until the pipes close, however
  slowly it takes them; the cleanup stops waiting only when no reader has
  waited for the owner for 250 ms (a holder outside the group, nothing
  coming) or a stream has given 1 MiB more (such a holder writing on).
  The graces still bound the group's residue.

Each has a test in yas_process::tests that fails without the change
(from the review's probes), plus one that a residue writing on still
ends its grace though the owner reads nothing.

* Say what a WAIT answers when its route failed as the exit was queued
* Expect TIMEOUT from a terminal command wait nothing started

Since yas-run#54 a command wait that runs out before any command it could
report on has started answers TIMEOUT (NOT_FOUND stays for an exited
terminal or an evicted index). The client_host test still expected
NOT_FOUND, so it failed on main.

* Say what a terminal command wait answers when no command started

Since yas-run#54 the server answers TIMEOUT when a command wait runs out before
any command it could report on has started; wait_terminal_command's
documentation still said NOT_FOUND, which stays for an evicted index or
an exited terminal.
A SPAWN with the new opt-in flag REPORT_EXIT (16) gets its process's exit as
an EXIT Event (Process 0x0002, sensitive) once it is final: the record a WAIT
would return then. A command's SPAWN Result, output and exit thus all come
from one request, where a client had to send WAIT and wait a round trip more.

- Servers advertise it in a new optional family limit, LAUNCHER_FLAGS_EXTENDED
  (tag 19), since clients from before accept at most 12 in tag 11; a client sets
  REPORT_EXIT only when tag 19 offers it, so either side may be older.
- The report takes none of the session's pending WAITs, is sent once (a SPAWN
  retried under its operation ID shares it), and outlives the streams: when the
  spawning session's attachment goes before the exit (its streams dropped, their
  route failed), the server waits for the exit itself and still sends it.
- The streams go on at the pace of their credit, so the EXIT may arrive before
  their last bytes and CLOSE.
- yas-client sets the flag whenever offered; Process::wait/wait_timeout then
  take no request and keep the reported exit. Attached processes, and servers
  without the flag, still WAIT.

Tests (client_host): a_spawned_process_reports_its_exit_without_a_wait (with
the only WAIT held, a non-zero exit with stderr, output beyond the stream
buffer read while the exit is awaited, a signal, and another session's
attachment that still WAITs), and a_server_from_before_report_exit_is_waited_for
(ignored; YAS_OLD_SERVER=<yas without the flag>).
Review of yas-run#86: the server's fallback wait, for a REPORT_EXIT process whose
attachment went before its exit, bound the process again (a detached one's
slot was taken back and ATTACH answered CONFLICT), hung Process::wait when
that wait failed, and an attachment aborted mid-send lost the EXIT.

The fallback is gone: the attachment reports the exit, from a task of its
own so removing the attachment meanwhile cannot cut the EXIT short. When the
attachment goes first (a Transfer RESET on any of its streams, stdin
included, sent or received, or a DETACH) no EXIT comes, and yas-client
knows: its router marks the process's report lost, and Process::wait and
wait_timeout then WAIT, after taking an EXIT that already arrived.
LAUNCHER_FLAGS_EXTENDED's hard maximum was 28, the flags it carries
today: a later server adding one would have failed the HELLO of every
client from this PR, as tag 11's maximum of 12 would have failed older
clients for REPORT_EXIT. Its hard maximum is now 65535 (any u16 of SPAWN
flags) and Limits::from_extensions keeps only the flags it knows, so the
next flag needs no new tag.
@pcarrier

pcarrier commented Oct 1, 2026

Copy link
Copy Markdown
Author

Upstream PR merged into yas-run/yas main (now dd33f04): this CI-only draft is done.

@pcarrier pcarrier closed this Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant