From d346d9defcce27bd84458d26c5a1716ce0a262ae Mon Sep 17 00:00:00 2001 From: japabu Date: Mon, 28 Sep 2026 13:32:52 +0200 Subject: [PATCH 1/4] File the supervisor track: init's decisions host-tested, the stop init's, the rename One new kind: track issue, issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md, recording the owner's decision to plan three things: init's decisions moved into a pure host-tested crate, graceful shutdown owned by init, and the program rename (init -> supervisor, netd -> netstack, logd -> logkeeper, soundd -> mixer, blockd -> disks, fsd -> files, sshd -> sshserver), each with an exit a machine can check. No code changes; nothing is renamed. Verified against the tree at af817e51 and #536's head 5235eda7: - userland/init/src/main.rs is 1,746 lines with no #[test] and no tests/. - On main the kernel's quiesce runs writeback::drain_all and vfs sync_all after freezing userland; on #536 those lines are gone and init's Init::stop runs sync_files (one Dir::sync per role but boot, bounded by toyos_quiesce::SYNC_MS) after logd's flush. - #536 deletes quiesce_leaves_the_volume_whole and registers no test for the stop's sync. - src/redlist.rs disables two of the six quiesce tests (quiesce_dump_holds_the_stopped, quiesce_wakes_on_the_last_exit); two more (quiesce_stops_the_machine, quiesce_wakes_on_the_last_park) run with open findings. - The name `files` is already [programs.files] / userland/files. Gate: cargo test --lib, EXIT=0. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01W6rME2DoqwjcYFStYHHY4j --- ...rvisor-is-host-tested-and-owns-the-stop.md | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md diff --git a/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md b/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md new file mode 100644 index 00000000000..2660bc3b8d0 --- /dev/null +++ b/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md @@ -0,0 +1,134 @@ +--- +status: assigned +kind: track +opened: 2026-09-28 +--- + +# The supervisor is host-tested and owns the machine's stop + +Held by the orchestrator. Stage 2 is blocked by PR #536 (`wt/toyos-fsd`); +#536 changes `userland/init/src/main.rs` by 835 added and 249 deleted lines, so +stage 1 cut before it lands is a merge against it. + +## What is true + +- `/system/bin/init` (`userland/init/src/main.rs`, 1,746 lines, one file, no + `#[test]` and no `tests/`) is the root of authority. The kernel starts it + holding the one full-rights `SysCap` (`spawn_init`, + `kernel/src/loader/mod.rs`). It builds every program's namespace, device + claims and narrowed `SysCap` from `system.toml`'s rendered manifest (`start`, + `build_namespace`, `swap_namespace`, `slot_grant`), starts `[boot] start`, + swaps a service and restores the binary a failed swap replaced + (`accept_swap`, `cut_over`, `end_probation`, `restore`), and answers + `launcher` (`serve_launch`, `resolve`, `declared`). +- On `main` a service that ends is not started again: its kept acceptors close + (`close_when_it_ends`). #536 adds `restart = true` rows, started again until + `toyos_manifest::RESTARTS` ends inside `RESTART_WINDOW_SECS`. +- Nothing in the kernel watches init's end: `kernel/src/main.rs` logs its pid + and keeps nothing. Once init ends, `launcher`, `swap` and `power` have no + server and no service is swapped or restarted. The machine can no longer be + stopped from userland, because only init's `SysCap` carries `Rights::POWER`. +- The stop on `main`: `/system/bin/shutdown` or `reboot` (toybox, the one row + that receives `power`) asks init. init has `logd` flush, bounded by + `FLUSH_BOUND`, then calls `SYS_SHUTDOWN` or `SYS_REBOOT` (`Init::stop`). The + kernel's `quiesce` (`kernel/src/syscall/machine.rs`) freezes every userland + thread at its next return to Ring 3 (`kernel/src/quiesce.rs`), then drains + writeback, runs `sync_all` over the volumes it holds, flushes USB disk caches + and cuts power. No program but `logd` hears of the stop. +- On #536 the kernel's `quiesce` syncs nothing: `drain_all` and `sync_all` are + gone. Its `Init::stop` flushes `logd` and then runs `sync_files`: one + `Dir::sync` per writable file-server role (every role but `boot`), bounded + together by `toyos_quiesce::SYNC_MS`. Only then does it call the kernel, and + a role that has not answered by then is stopped unsynced. Every other service + still gets no notice. #536 deletes `quiesce_leaves_the_volume_whole` and + registers no test for the stop's sync. + +## Stages + +1. **Decisions in a pure crate.** Init's decisions move into a host-tested + crate, as `toyos-proclife` and `toyos-desktop` did, and the binary keeps + only handles, spawns and the loop. The decisions are: + - namespace and claim selection from a manifest row; + - the claims a restart is owed; + - `SysCap` narrowing; + - launch resolution and every launcher refusal (`resolve`, `declared`, + handle count, relative `cwd`, `MAX_PENDING_LAUNCHES`, + `HANDSHAKE_TIMEOUT`); + - the swap ladder and probation; + - restart policy. + + The crate carries the decided name, `toyos-supervisor`. + **Exit**: the crate's tests pass in + `cargo test --workspace --exclude toyos-build`. Each refusal has a mutation + that reds it, named in the PR. `git grep -nE 'fn (resolve|declared)\b' + userland/init` answers nothing. +2. **The supervisor owns the stop.** The supervisor asks each service it + started to finish, in reverse dependency order, storage last, each ask + bounded. Only then does it call `SYS_SHUTDOWN` or `SYS_REBOOT`, and the + kernel's part is to stop whatever is left and cut power. The order is not + in the manifest today: + - `[boot] start`'s own comment says its order "means nothing"; + - `compositor` and `filepicker` each receive the other; + - `logd` writes `/log` through the `log` role, whose server's lines reach + `logd`, and only #536's flush-then-sync breaks that cycle. + + So the order is declared in `system.toml`, or derived from the edges with + the cycles broken by declaration. + **Exit**: a guest test in which a service holding unwritten state is asked + to finish, answers, and has its state on disk after the reboot. Its negative + control is the same service never answering: the stop still lands at the + bound, and the supervisor's line names the service. +3. **The quiesce coverage comes back.** Two of the six are disabled in + `src/redlist.rs`: + - `quiesce_dump_holds_the_stopped` + (`issues/kernel/quiesce-dump-holds-the-stopped-reds-wide-with-usb-transport-breaks.md`); + - `quiesce_wakes_on_the_last_exit` + (`issues/build/quiesce-wakes-on-the-last-exit-lost-its-serial-ready-beside-other-guests.md`). + + Two more run with open findings: + - `quiesce_stops_the_machine` + (`issues/kernel/quiesce-stops-the-machine-stayed-up-beside-other-guests.md`); + - `quiesce_wakes_on_the_last_park` + (`issues/build/quiesce-wakes-on-the-last-park-lost-its-serial-ready-beside-other-guests.md`). + + `quiesce_leaves_the_volume_whole` goes with #536. These defects are the + kernel's stop beside a loaded host, not the missing notice, so stage 2 does + not close them by itself. + **Exit**: `cargo run -- --known-red` lists no `quiesce_` test, and stage 2's + test is registered where `quiesce_leaves_the_volume_whole` was. +4. **The rename.** The owner has decided it: each program is named for what it + does, not with the Unix daemon suffix. It lands as one mechanical PR after + the large in-flight PRs, #536 first. + + | today | becomes | + |---|---| + | `init` | `supervisor` | + | `netd` | `netstack` | + | `logd` | `logkeeper` | + | `soundd` | `mixer` | + | `blockd` | `disks` | + | `fsd` | `files` | + | `sshd` | `sshserver` | + | `compositor` | unchanged | + + `files` is already taken: `[programs.files]`, `userland/files` (package + `files`, the file manager) and `/system/bin/files`. That program needs a new + name first. Issue slugs carrying an old name are renamed with their + citations. + **Exit**: `git grep -nwE 'netd|logd|soundd|blockd|fsd|sshd'` and + `git grep -nE '/system/bin/init|userland/init|programs\.init|INIT_PATH|"init: '` + both answer nothing outside this file. + +## Decided with stage 2: the ask's ABI + +No syscall is proposed. The precedents are IPC over a connection init holds: +`logd`'s `FLUSH`/`FLUSHED` (`toyos-logstream`) and #536's `Dir::sync`. The +candidate is one connection per started service, endowed under a label as +`ORIGINS` is, carrying a finish word and its answer. Its protocol lives in a +crate beside `toyos-swap`, not in `toyos/src`. Still open: + +- whether a program started through `launcher` is asked or only stopped; +- whether `SYS_SHUTDOWN`/`SYS_REBOOT` change at all. + +`issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md`'s +inhibitors would ride the same connection. From 883a15f5bf766aa62e1baaa2e0c0c29e43e07289 Mon Sep 17 00:00:00 2001 From: japabu Date: Mon, 28 Sep 2026 14:01:03 +0200 Subject: [PATCH 2/4] Supervisor track round 2: the rename first, exits that fail today, fsd's name open Answers the SEND BACK on #575 at d346d9de. - fsd's new name is open with the owner (candidate `fileserver`, `files` kept for the file manager); the invented rename of the file manager goes. - The rename is stage 1, first after #536, briefed as an ABI brief since it touches toyos/src, toyos-abi/src, userland/libc/src and the rust fork's ToyOS files. Its exit is a case-insensitive substring search over the six daemon names and a letter-bounded search for `init`, each with an explicit exclusion list judged per match; issue bodies are excluded as recorded evidence. Measured outside issues/ at 62e7e8c7: 3641 daemon substring hits (3419 outside the exclusions), 2289 `init` substring hits, 1589 letter-bounded (1073 outside the exclusions). - Stage 2's exit names the crate `toyos-supervisor` and its decisions, now including the stop-order derivation and a host test refusing an undeclared cycle; it is unmet today and cannot go vacuous under the rename. - Stage 3's exit adds a two-service reverse-order test that reds on forward and all-at-once order. - Stage 4's exit names the five claims the stop's coverage must assert, by a host test or a guest test at Tier::Fast or Tier::Nightly with no redlist row, so it cannot be met by deleting tests; the per-test lists that conflicted with #564 and #574 go. - The power-broker track loses its false parenthetical and item 1: toybox holds the `power` connector, not the bit. - Every REMOVE the review listed is taken. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01W6rME2DoqwjcYFStYHHY4j --- ...oker-authority-with-a-human-in-the-loop.md | 10 +- ...rvisor-is-host-tested-and-owns-the-stop.md | 188 +++++++----------- 2 files changed, 80 insertions(+), 118 deletions(-) diff --git a/issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md b/issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md index f4d3f3dab17..3d0ef061f54 100644 --- a/issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md +++ b/issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md @@ -13,21 +13,17 @@ privileged service, a policy engine, an authentication agent) because its base model only knows identities. ToyOS's capability model IS the mechanism, so the native shape is smaller: -1. **No user-facing program holds `POWER`.** One small daemon — the power - broker — is endowed it in `system.toml`, and its whole job is deciding. - (Today the toybox shutdown applet holds the bit directly; the broker - moves that single endowment one level up, behind judgment.) -2. **Programs request, the broker decides** — a port/connection like every +1. **Programs request, the broker decides** — a port/connection like every other daemon protocol in the tree, under the server-never-blocks doctrine. -3. **The confirmation rides the trusted UI path.** The broker asks the +2. **The confirmation rides the trusted UI path.** The broker asks the compositor to present it, and the tree's own architecture is what makes that mean something: the compositor owns the panel and the kernel delivers key transitions per surface, so no ordinary program can draw a fake dialog or fake the click on a real one. "A human physically present confirmed" is the single-user machine's honest equivalent of Linux's password prompt. -4. **Inhibitors**: a program may register "unsaved work" with the broker; +3. **Inhibitors**: a program may register "unsaved work" with the broker; the broker delays, or names the holdouts in the dialog. Registration is a connection, so a crashed registrant releases its inhibit by the same teardown that releases everything else. diff --git a/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md b/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md index 2660bc3b8d0..445adcf8c4a 100644 --- a/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md +++ b/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md @@ -6,99 +6,19 @@ opened: 2026-09-28 # The supervisor is host-tested and owns the machine's stop -Held by the orchestrator. Stage 2 is blocked by PR #536 (`wt/toyos-fsd`); -#536 changes `userland/init/src/main.rs` by 835 added and 249 deleted lines, so -stage 1 cut before it lands is a merge against it. +Held by the orchestrator. Every stage waits on PR #536 (`wt/toyos-fsd`). -## What is true - -- `/system/bin/init` (`userland/init/src/main.rs`, 1,746 lines, one file, no - `#[test]` and no `tests/`) is the root of authority. The kernel starts it - holding the one full-rights `SysCap` (`spawn_init`, - `kernel/src/loader/mod.rs`). It builds every program's namespace, device - claims and narrowed `SysCap` from `system.toml`'s rendered manifest (`start`, - `build_namespace`, `swap_namespace`, `slot_grant`), starts `[boot] start`, - swaps a service and restores the binary a failed swap replaced - (`accept_swap`, `cut_over`, `end_probation`, `restore`), and answers - `launcher` (`serve_launch`, `resolve`, `declared`). -- On `main` a service that ends is not started again: its kept acceptors close - (`close_when_it_ends`). #536 adds `restart = true` rows, started again until - `toyos_manifest::RESTARTS` ends inside `RESTART_WINDOW_SECS`. -- Nothing in the kernel watches init's end: `kernel/src/main.rs` logs its pid - and keeps nothing. Once init ends, `launcher`, `swap` and `power` have no - server and no service is swapped or restarted. The machine can no longer be - stopped from userland, because only init's `SysCap` carries `Rights::POWER`. -- The stop on `main`: `/system/bin/shutdown` or `reboot` (toybox, the one row - that receives `power`) asks init. init has `logd` flush, bounded by - `FLUSH_BOUND`, then calls `SYS_SHUTDOWN` or `SYS_REBOOT` (`Init::stop`). The - kernel's `quiesce` (`kernel/src/syscall/machine.rs`) freezes every userland - thread at its next return to Ring 3 (`kernel/src/quiesce.rs`), then drains - writeback, runs `sync_all` over the volumes it holds, flushes USB disk caches - and cuts power. No program but `logd` hears of the stop. -- On #536 the kernel's `quiesce` syncs nothing: `drain_all` and `sync_all` are - gone. Its `Init::stop` flushes `logd` and then runs `sync_files`: one - `Dir::sync` per writable file-server role (every role but `boot`), bounded - together by `toyos_quiesce::SYNC_MS`. Only then does it call the kernel, and - a role that has not answered by then is stopped unsynced. Every other service - still gets no notice. #536 deletes `quiesce_leaves_the_volume_whole` and - registers no test for the stop's sync. +On #536 the stop is init's `Init::stop`: it has `logd` flush, then `Dir::sync`s +every writable file-server role, bounded together, then calls `SYS_SHUTDOWN` or +`SYS_REBOOT`. No other service hears of the stop. ## Stages -1. **Decisions in a pure crate.** Init's decisions move into a host-tested - crate, as `toyos-proclife` and `toyos-desktop` did, and the binary keeps - only handles, spawns and the loop. The decisions are: - - namespace and claim selection from a manifest row; - - the claims a restart is owed; - - `SysCap` narrowing; - - launch resolution and every launcher refusal (`resolve`, `declared`, - handle count, relative `cwd`, `MAX_PENDING_LAUNCHES`, - `HANDSHAKE_TIMEOUT`); - - the swap ladder and probation; - - restart policy. - - The crate carries the decided name, `toyos-supervisor`. - **Exit**: the crate's tests pass in - `cargo test --workspace --exclude toyos-build`. Each refusal has a mutation - that reds it, named in the PR. `git grep -nE 'fn (resolve|declared)\b' - userland/init` answers nothing. -2. **The supervisor owns the stop.** The supervisor asks each service it - started to finish, in reverse dependency order, storage last, each ask - bounded. Only then does it call `SYS_SHUTDOWN` or `SYS_REBOOT`, and the - kernel's part is to stop whatever is left and cut power. The order is not - in the manifest today: - - `[boot] start`'s own comment says its order "means nothing"; - - `compositor` and `filepicker` each receive the other; - - `logd` writes `/log` through the `log` role, whose server's lines reach - `logd`, and only #536's flush-then-sync breaks that cycle. - - So the order is declared in `system.toml`, or derived from the edges with - the cycles broken by declaration. - **Exit**: a guest test in which a service holding unwritten state is asked - to finish, answers, and has its state on disk after the reboot. Its negative - control is the same service never answering: the stop still lands at the - bound, and the supervisor's line names the service. -3. **The quiesce coverage comes back.** Two of the six are disabled in - `src/redlist.rs`: - - `quiesce_dump_holds_the_stopped` - (`issues/kernel/quiesce-dump-holds-the-stopped-reds-wide-with-usb-transport-breaks.md`); - - `quiesce_wakes_on_the_last_exit` - (`issues/build/quiesce-wakes-on-the-last-exit-lost-its-serial-ready-beside-other-guests.md`). - - Two more run with open findings: - - `quiesce_stops_the_machine` - (`issues/kernel/quiesce-stops-the-machine-stayed-up-beside-other-guests.md`); - - `quiesce_wakes_on_the_last_park` - (`issues/build/quiesce-wakes-on-the-last-park-lost-its-serial-ready-beside-other-guests.md`). - - `quiesce_leaves_the_volume_whole` goes with #536. These defects are the - kernel's stop beside a loaded host, not the missing notice, so stage 2 does - not close them by itself. - **Exit**: `cargo run -- --known-red` lists no `quiesce_` test, and stage 2's - test is registered where `quiesce_leaves_the_volume_whole` was. -4. **The rename.** The owner has decided it: each program is named for what it - does, not with the Unix daemon suffix. It lands as one mechanical PR after - the large in-flight PRs, #536 first. +1. **The rename**, one mechanical PR, first after #536. It touches `toyos/src`, + `toyos-abi/src`, `userland/libc/src` and the `rust/` fork's ToyOS files, so + it is briefed as an ABI brief, and its `CLAUDE.md` edits are placed in the + same PR by an agent briefed for them. Issue slugs carrying an old name are + renamed with every citation. | today | becomes | |---|---| @@ -107,28 +27,74 @@ stage 1 cut before it lands is a merge against it. | `logd` | `logkeeper` | | `soundd` | `mixer` | | `blockd` | `disks` | - | `fsd` | `files` | + | `fsd` | open with the owner | | `sshd` | `sshserver` | | `compositor` | unchanged | - `files` is already taken: `[programs.files]`, `userland/files` (package - `files`, the file manager) and `/system/bin/files`. That program needs a new - name first. Issue slugs carrying an old name are renamed with their - citations. - **Exit**: `git grep -nwE 'netd|logd|soundd|blockd|fsd|sshd'` and - `git grep -nE '/system/bin/init|userland/init|programs\.init|INIT_PATH|"init: '` - both answer nothing outside this file. - -## Decided with stage 2: the ask's ABI - -No syscall is proposed. The precedents are IPC over a connection init holds: -`logd`'s `FLUSH`/`FLUSHED` (`toyos-logstream`) and #536's `Dir::sync`. The -candidate is one connection per started service, endowed under a label as -`ORIGINS` is, carrying a finish word and its answer. Its protocol lives in a -crate beside `toyos-swap`, not in `toyos/src`. Still open: - -- whether a program started through `launcher` is asked or only stopped; -- whether `SYS_SHUTDOWN`/`SYS_REBOOT` change at all. - -`issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md`'s -inhibitors would ride the same connection. + **Exit**: over every tracked path and every text file's content, in the + superproject and the fork's ToyOS files, excluding the bodies of `issues/` + files (recorded evidence), no hit remains outside the exclusions, each + judged per match and not per line: + - a case-insensitive substring search for `netd`, `logd`, `soundd`, + `blockd`, `fsd`, `sshd`, excluding an identifier containing `klogd`, + `blockdev`, `VirtioSoundDev`, `netdev`, `netdb`, `ENETDOWN` or `fsdir`; + - a case-insensitive search for `init` with no letter on either side (so + `spawn_init`, `struct Init`, `INIT_PATH` and "asks init" all hit), + excluding a function named `init` (`fn init`, `::init`, `init(`), + `git init`, `init.defaultBranch`, `rustup-init`, `zero-init`, `init-tls`; + ELF's `init_array`, `DT_INIT_ARRAY*`, `SHT_INIT_ARRAY` and toyos-elf's + `init_at`, `init_sz`, `init_info`, `init_count`, `init_out`, `n_init`, and + `INIT`/`init` in `toyos-elf/tests/fuzz.rs`; `assume_init*`, + `get_or_init`, `atomic_init`, `sem_init`, `pthread_*_init`, + `PTHREAD_ONCE_INIT`, `init_routine`, and SFTP's `INIT`/`FXP_INIT`; the + processor's `INIT` signal (`INIT IPI`, `INIT-SIPI`, what `INIT` leaves an + AP) and `init_bsp`, `init_ap`, `init_cr0`, `init_pcid`, `INIT_AS`, + `init_tss_descriptor`, `init_timer`, `X2APIC_TIMER_INIT`, `send_init`, + `AFTER_INIT`, `init_early`, `init_wall`, `init_reset`, `init_power`, + `init_budget_ms`, `init_one`, `init_device`, `init_entry`, + `init_dot_entries`, `Tr2init`; and the C ports' `DG_Init`, `Z_Init`, + `toyos_music_init`, `toyos_init_sound`, `log_zeroed_init`, and + `tests/testcases/`' `*_init` names. Prose that says "init" for a bring-up + (i8042's "Init treats the controller") is reworded, not excluded. +2. **Decisions in a pure crate.** The supervisor's decisions live in + `toyos-supervisor`, with host tests; `userland/supervisor` keeps only + handles, spawns and the loop. The decisions: namespace and claim selection + from a manifest row; the claims a restart is owed; `SysCap` narrowing; + launch resolution and every launcher refusal; the swap ladder and + probation; restart policy; the stop order derived from the manifest, with a + cycle broken only by declaration. + **Exit**: the crate's tests pass in + `cargo test --workspace --exclude toyos-build`; a host test refuses a + manifest whose dependencies form an undeclared cycle; and each refusal and + each decision above has a mutation that reds a host test, named in the PR. +3. **The supervisor owns the stop.** It asks each service it started to + finish, in reverse dependency order, storage last, each ask bounded; only + then does it call the kernel, whose part is to stop whatever is left and + cut power. The order is not in the manifest today: `[boot] start` says its + order "means nothing", `compositor` and `filepicker` each receive the + other, and `logd` writes `/log` through the `log` role, whose server's lines + reach `logd`. + **Exit**: two guest tests. In one, two non-storage services with a declared + dependency are asked to finish in reverse dependency order; it reds when + they are asked in forward order, and when they are asked all at once with + storage still last. In the other, a service holding unwritten state is + asked to finish, answers, and has its state on disk after the reboot; its + negative control is the same service never answering, where the stop still + lands at the bound and the supervisor's line names the service. +4. **The stop's coverage comes back.** **Exit**: each claim below is asserted + by a host test, or by a guest test registered at `Tier::Fast` or + `Tier::Nightly` with no `src/redlist.rs` row, and a mutation named in the + PR reds it. A deleted or disabled test covers nothing. + - a thread's transition wakes the stop; + - no block operation is open at the stop; + - the thread count; + - the console drain; + - storage made durable before power-off. + +## Open with the owner + +- `fsd`'s new name. The orchestrator's candidate is `fileserver`; `files` stays + the file manager's. +- Before stage 3: the ask's ABI (no syscall is proposed); whether a program + started through `launcher` is asked or only stopped; whether + `SYS_SHUTDOWN`/`SYS_REBOOT` change at all. From e8ba2219affe410629891b44268fa00a2ddc1460 Mon Sep 17 00:00:00 2001 From: japabu Date: Mon, 28 Sep 2026 14:26:52 +0200 Subject: [PATCH 3/4] Supervisor track round 3: a categorical init rule, one home per decision, claims as sentences The rename's init exclusions become one rule: a match stays only where init means initialise, initial or the CPU's INIT signal, or sits in third-party text; every other match names the program. The search is bounded so CamelCase joins hit: no lowercase letter follows, and a letter precedes only a capital I. The review's literal "no lowercase letter on either side" misses TimerInit, which occurs 6 times outside issues/ at origin/main cd2e6307; this bound catches it. Stage 2's exit now requires each decision deleted from userland/supervisor, which calls the crate for it. Stage 4's claims are sentences. The tier-and-redlist clause covers every guest test the track names. "The fork's delta" is forkcheck's definition. soundd's and blockd's new names reopen with the owner beside fsd's: mixer and disks are words the tree already uses. Removed: the stop on #536, the manifest's current order, the file manager's name, and the power-broker clause citing the deleted applet. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01W6rME2DoqwjcYFStYHHY4j --- ...oker-authority-with-a-human-in-the-loop.md | 3 +- ...rvisor-is-host-tested-and-owns-the-stop.md | 90 +++++++++---------- 2 files changed, 42 insertions(+), 51 deletions(-) diff --git a/issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md b/issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md index 3d0ef061f54..c8d0702143c 100644 --- a/issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md +++ b/issues/isolation/the-power-broker-authority-with-a-human-in-the-loop.md @@ -30,5 +30,4 @@ so the native shape is smaller: Unstaffed until the owner opens it; sequenced naturally with the userland/ product era. What must not happen meanwhile is the accident this track -exists to prevent: `POWER` spreading to more manifest rows because asking -the applet is inconvenient — the broker is the answer to that itch. +exists to prevent: `POWER` spreading to more manifest rows. diff --git a/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md b/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md index 445adcf8c4a..d57f05aff76 100644 --- a/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md +++ b/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md @@ -8,54 +8,46 @@ opened: 2026-09-28 Held by the orchestrator. Every stage waits on PR #536 (`wt/toyos-fsd`). -On #536 the stop is init's `Init::stop`: it has `logd` flush, then `Dir::sync`s -every writable file-server role, bounded together, then calls `SYS_SHUTDOWN` or -`SYS_REBOOT`. No other service hears of the stop. - ## Stages +Every guest test this track names is registered at `Tier::Fast` or +`Tier::Nightly` with no `src/redlist.rs` row. A deleted or disabled test covers +nothing. + 1. **The rename**, one mechanical PR, first after #536. It touches `toyos/src`, - `toyos-abi/src`, `userland/libc/src` and the `rust/` fork's ToyOS files, so - it is briefed as an ABI brief, and its `CLAUDE.md` edits are placed in the - same PR by an agent briefed for them. Issue slugs carrying an old name are - renamed with every citation. + `toyos-abi/src`, `userland/libc/src` and the `rust/` fork's delta, so it is + briefed as an ABI brief, and its `CLAUDE.md` edits are placed in the same PR + by an agent briefed for them. Issue slugs carrying an old name are renamed + with every citation. | today | becomes | |---|---| | `init` | `supervisor` | | `netd` | `netstack` | | `logd` | `logkeeper` | - | `soundd` | `mixer` | - | `blockd` | `disks` | + | `soundd` | open with the owner | + | `blockd` | open with the owner | | `fsd` | open with the owner | | `sshd` | `sshserver` | | `compositor` | unchanged | **Exit**: over every tracked path and every text file's content, in the - superproject and the fork's ToyOS files, excluding the bodies of `issues/` - files (recorded evidence), no hit remains outside the exclusions, each - judged per match and not per line: + superproject and the `rust/` fork's delta as `src/forkcheck.rs` defines it, + excluding the bodies of `issues/` files (recorded evidence), no hit remains + outside the exclusions, each judged per match and not per line: - a case-insensitive substring search for `netd`, `logd`, `soundd`, - `blockd`, `fsd`, `sshd`, excluding an identifier containing `klogd`, - `blockdev`, `VirtioSoundDev`, `netdev`, `netdb`, `ENETDOWN` or `fsdir`; - - a case-insensitive search for `init` with no letter on either side (so - `spawn_init`, `struct Init`, `INIT_PATH` and "asks init" all hit), - excluding a function named `init` (`fn init`, `::init`, `init(`), - `git init`, `init.defaultBranch`, `rustup-init`, `zero-init`, `init-tls`; - ELF's `init_array`, `DT_INIT_ARRAY*`, `SHT_INIT_ARRAY` and toyos-elf's - `init_at`, `init_sz`, `init_info`, `init_count`, `init_out`, `n_init`, and - `INIT`/`init` in `toyos-elf/tests/fuzz.rs`; `assume_init*`, - `get_or_init`, `atomic_init`, `sem_init`, `pthread_*_init`, - `PTHREAD_ONCE_INIT`, `init_routine`, and SFTP's `INIT`/`FXP_INIT`; the - processor's `INIT` signal (`INIT IPI`, `INIT-SIPI`, what `INIT` leaves an - AP) and `init_bsp`, `init_ap`, `init_cr0`, `init_pcid`, `INIT_AS`, - `init_tss_descriptor`, `init_timer`, `X2APIC_TIMER_INIT`, `send_init`, - `AFTER_INIT`, `init_early`, `init_wall`, `init_reset`, `init_power`, - `init_budget_ms`, `init_one`, `init_device`, `init_entry`, - `init_dot_entries`, `Tr2init`; and the C ports' `DG_Init`, `Z_Init`, - `toyos_music_init`, `toyos_init_sound`, `log_zeroed_init`, and - `tests/testcases/`' `*_init` names. Prose that says "init" for a bring-up - (i8042's "Init treats the controller") is reworded, not excluded. + `blockd`, `fsd`, `sshd`, excluding, case-insensitively, an identifier + containing `klogd`, `blockdev`, `VirtioSoundDev`, `netdev`, `netdb`, + `ENETDOWN` or `fsdir`; + - a case-insensitive search for `init` followed by no lowercase letter and + preceded by a letter only where it starts with a capital `I` (so + `spawn_init`, `struct Init`, `SpawnInit`, `TimerInit`, `InitPort` and + "asks init" all hit). A match stays only where `init` means initialise, + initial or the CPU's INIT signal (a function, method or field named + `init`, an identifier of that meaning, ELF's init arrays, bring-up prose, + a log string a test matches such as `init budget`), or where it sits in + third-party text (`tests/testcases/`, the C ports); every other match + names the program and goes. 2. **Decisions in a pure crate.** The supervisor's decisions live in `toyos-supervisor`, with host tests; `userland/supervisor` keeps only handles, spawns and the loop. The decisions: namespace and claim selection @@ -65,15 +57,15 @@ every writable file-server role, bounded together, then calls `SYS_SHUTDOWN` or cycle broken only by declaration. **Exit**: the crate's tests pass in `cargo test --workspace --exclude toyos-build`; a host test refuses a - manifest whose dependencies form an undeclared cycle; and each refusal and - each decision above has a mutation that reds a host test, named in the PR. + manifest whose dependencies form an undeclared cycle; each refusal and + each decision above has a mutation that reds a host test, named in the PR; + and the stage deletes each decision from `userland/supervisor`, which calls + the crate for it, named per decision in the PR. No decision exists in two + places. 3. **The supervisor owns the stop.** It asks each service it started to finish, in reverse dependency order, storage last, each ask bounded; only then does it call the kernel, whose part is to stop whatever is left and - cut power. The order is not in the manifest today: `[boot] start` says its - order "means nothing", `compositor` and `filepicker` each receive the - other, and `logd` writes `/log` through the `log` role, whose server's lines - reach `logd`. + cut power. **Exit**: two guest tests. In one, two non-storage services with a declared dependency are asked to finish in reverse dependency order; it reds when they are asked in forward order, and when they are asked all at once with @@ -82,19 +74,19 @@ every writable file-server role, bounded together, then calls `SYS_SHUTDOWN` or negative control is the same service never answering, where the stop still lands at the bound and the supervisor's line names the service. 4. **The stop's coverage comes back.** **Exit**: each claim below is asserted - by a host test, or by a guest test registered at `Tier::Fast` or - `Tier::Nightly` with no `src/redlist.rs` row, and a mutation named in the - PR reds it. A deleted or disabled test covers nothing. - - a thread's transition wakes the stop; - - no block operation is open at the stop; - - the thread count; - - the console drain; - - storage made durable before power-off. + by a host test or a guest test, and a mutation named in the PR reds it. + - A held thread's transition wakes the stop. + - No block operation is open at the stop. + - A dump served during the stop counts every thread it stopped as held. + - Every record reaches the console, `Rebooting.` last. + - Storage is durable before power is cut. ## Open with the owner -- `fsd`'s new name. The orchestrator's candidate is `fileserver`; `files` stays - the file manager's. +- The new names of `fsd`, `soundd` and `blockd`. The orchestrator's candidate + for `fsd` is `fileserver`. `mixer` and `disks` are refused: both are words + the tree already uses (`flush_disks`), so a search for either program would + be as ambiguous as one for `init` is today. - Before stage 3: the ask's ABI (no syscall is proposed); whether a program started through `launcher` is asked or only stopped; whether `SYS_SHUTDOWN`/`SYS_REBOOT` change at all. From 0e49e251931316bb1e1868a9406c743cf763e65a Mon Sep 17 00:00:00 2001 From: japabu Date: Mon, 28 Sep 2026 14:53:30 +0200 Subject: [PATCH 4/4] Supervisor track round 4: the inits bound, tinycc's own scope, a neutral fsd note The init bound missed a possessive s (a_boot_record_without_inits_stop_is_not_a_pass, inits_lines_are_heard_in_every_form_the_log_renders_them at origin/main); it now allows one trailing s. The third-party exclusion named tests/testcases/ broadly, which also covers our own system.toml; it now names tests/testcases/tinycc/. The stay/goes rule is replaced with the reviewer's sentence, which covers matches that are neither the program nor third-party text. Stage 1 now measures the rust/ fork's delta before it is briefed, not only the superproject. The fsd bullet records only the open question, not a rejected candidate nobody decided on. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01W6rME2DoqwjcYFStYHHY4j --- ...rvisor-is-host-tested-and-owns-the-stop.md | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md b/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md index d57f05aff76..a9c410d9d9c 100644 --- a/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md +++ b/issues/isolation/the-supervisor-is-host-tested-and-owns-the-stop.md @@ -14,7 +14,9 @@ Every guest test this track names is registered at `Tier::Fast` or `Tier::Nightly` with no `src/redlist.rs` row. A deleted or disabled test covers nothing. -1. **The rename**, one mechanical PR, first after #536. It touches `toyos/src`, +1. **The rename**, one mechanical PR, first after #536. Before stage 1 is + briefed, the exit's search below runs once over the `rust/` fork's delta as + well as the superproject, so its hits are known going in. It touches `toyos/src`, `toyos-abi/src`, `userland/libc/src` and the `rust/` fork's delta, so it is briefed as an ABI brief, and its `CLAUDE.md` edits are placed in the same PR by an agent briefed for them. Issue slugs carrying an old name are renamed @@ -39,15 +41,12 @@ nothing. `blockd`, `fsd`, `sshd`, excluding, case-insensitively, an identifier containing `klogd`, `blockdev`, `VirtioSoundDev`, `netdev`, `netdb`, `ENETDOWN` or `fsdir`; - - a case-insensitive search for `init` followed by no lowercase letter and - preceded by a letter only where it starts with a capital `I` (so - `spawn_init`, `struct Init`, `SpawnInit`, `TimerInit`, `InitPort` and - "asks init" all hit). A match stays only where `init` means initialise, - initial or the CPU's INIT signal (a function, method or field named - `init`, an identifier of that meaning, ELF's init arrays, bring-up prose, - a log string a test matches such as `init budget`), or where it sits in - third-party text (`tests/testcases/`, the C ports); every other match - names the program and goes. + - a case-insensitive search for `init` followed by no lowercase letter + other than one `s` (so `inits` hits alongside `init`) and preceded by a + letter only where it starts with a capital `I` (so `spawn_init`, + `struct Init`, `SpawnInit`, `TimerInit`, `InitPort` and "asks init" all + hit). A match goes where it names the program and stays otherwise; + third-party text (`tests/testcases/tinycc/`, the C ports) stays. 2. **Decisions in a pure crate.** The supervisor's decisions live in `toyos-supervisor`, with host tests; `userland/supervisor` keeps only handles, spawns and the loop. The decisions: namespace and claim selection @@ -83,10 +82,7 @@ nothing. ## Open with the owner -- The new names of `fsd`, `soundd` and `blockd`. The orchestrator's candidate - for `fsd` is `fileserver`. `mixer` and `disks` are refused: both are words - the tree already uses (`flush_disks`), so a search for either program would - be as ambiguous as one for `init` is today. +- The new names of `fsd`, `soundd` and `blockd`. - Before stage 3: the ask's ABI (no syscall is proposed); whether a program started through `launcher` is asked or only stopped; whether `SYS_SHUTDOWN`/`SYS_REBOOT` change at all.