Public: anyone can read this; nobody can change it.
An app that runs without a cell stops with everything it started, and leaves no child running once it has gone #63
Check · Review · Land done · Live — Landed; nothing deploys from this branch, so this is the end of its path.
Where the host cannot hold a cell, an app ran as a plain child in the forge's own process group, and stop() signalled its pid alone. A child it had started (a worker, `bun run`'s script, a `sleep`) was re-parented and kept running on the environment's data and token after the forge called it stopped; one that outlived a crash ran beside the restart.
shipped merged
Sign in to join this conversation.
Where the host cannot hold a cell, an app ran as a plain child in the forge's own process group, and stop() signalled its pid alone. A child it had started (a worker,
bun run's script, asleep) was re-parented and kept running on the environment's data and token after the forge called it stopped; one that outlived a crash ran beside the restart.The app now leads a process group of its own (
detached, without a cell only), stop() asks and then kills the group, and once the app has exited, however it went, what is left of the group is killed. A cell is unchanged: its tree is bubblewrap's.Since a terminal's hangup no longer reaches those apps directly, the forge takes SIGHUP the way it takes Ctrl-C: it drains and stops them.
test/apps-stop-tree.test.ts: red on main (3 of 3), green here.
Regression test
test/apps-stop-tree.test.ts(3 tests: a stop ends the app's children; a child that ignores SIGTERM is killed once the app has gone; an app that dies on its own takes its children with it). Pinned bun 1.3.14:dc68048esource + this test: 0 pass, 3 fail (each child still alive 3 s after the stop/exit)Also on the box, CI-shaped PATH (no bwrap, so every app runs uncelled — the path this changes): all 24 gated
test/apps*.test.ts+app.test.ts+standing-every-process.test.ts: 212 pass, 0 fail.SIGHUP: the forge started in a pty, the pty then killed: this branch logs
forge draining … why=SIGHUPand exits; main dies on the hangup without draining.Security
Process control. The group signal is only ever
-proc.pidof a group this spawn just made the app lead (detached, i.e. setsid), never the forge's own group, and a cell's spawn is unchanged. Linux keeps a pid from reuse while it is any live process's pgid, so the kill after exit reaches only what is left of the app's group, or nothing (ESRCH, ignored). What it closes: an app's children outliving a stop or a crash, still running on the environment's data dir and forge token after the forge recorded it stopped (or its token revoked) — and beside its restart. An app that calls setsid itself still escapes, as before; a cell is the containment for that.<!-- pipeline:validation -->
Validation
pipeline/validateon077b8561: baseline in 595s — bun 1.3.14, CI-shaped env (scrubbed vars, runner PATH), exact check.yml shard + forge.json commands.bun install --frozen-lockfileforge.json check.fastcheck.yml gate (1) pull_requestcheck.yml gate (2) pull_requestcheck.yml gate (3) pull_requesttest output (failures, totals)