Skip to content

Rules and records: the ABI and kernel rulings, the no-panic track, the owner's 2026-09-30 rulings, CPU microcode, the crate track, the LLVM-bytes and TCO-overflow defects - #673

Merged
Japabu merged 36 commits into
mainfrom
wt/toyos-prosebatch
Oct 1, 2026

Conversation

@Japabu

@Japabu Japabu commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Six open pull requests of rules and records land here as one: #666, #665, #645, #613, #604 and #646, each merged in that order with git merge, with #636's firmware clause. Landing this closes all six. Root CLAUDE.md is 16076 bytes, against main's 16077.

Not high-risk: prose, issue files and comments, and one licence row's text in src/licence.rs. No code path changes.

What lands

  • The ABI is free to change, and the kernel takes on only what userland cannot (The ABI is free to change, and the kernel takes on only what userland cannot #666).

    • Root CLAUDE.md's Kernel and Syscall ABI lines say so.
    • implementer.md asks whether userland can own a kernel addition, and drops the ABI-brief sentence.
    • reviewer.md's Fit line makes each of these a BLOCKER: a kernel addition userland could own, and a design made worse to spare the ABI.
    • reviewer.md's "What no gate reads" retires its BLOCKER on a diff that declares a retired ABI name, or reuses a retired syscall, SYS_DEBUG action or inbox op number.
    • issues/design-debt/the-abi-still-keeps-retired-syscall-numbers.md records what still keeps retired numbers, and every plan that still retires one.
  • No panic, by tier (issues: a panic is never an accident, the owner's rule as a track, not yet enforced; seven stale crafted-ELF clauses go #665), the track issues/kernel/a-panic-is-never-an-accident.md.

    • Input boundaries never panic.
    • The kernel, the loader and the system services deny the set. Each deliberate stop is an #[expect] of its own at its site.
    • Apps are normal Rust.
    • A tier holds every crate of this tree its programs link. A system service is a program that any shipped mode's config marks service = true, or whose manifest declares exempt.owns. Every other shipped program is an app, toybox, terminal and the exempt.manages tools included. Today that makes ten services: blockd, compositor, console, filepicker, fsd, init, logd, netd, soundd and sshd.
    • Seven comment clauses that cite crafted-ELF panics no issue holds are deleted, from four manifests and src/build.rs.
  • The owner's 2026-09-30 rulings (The owner's rulings of 2026-09-30 written where they govern #645), written into the child-process, small-kernel and supervisor tracks and into two design-debt issues. Three question files are deleted, and doom.jpg's licence row says it is the owner's own screenshot.

  • CPU microcode is its own case. Vendor firmware a device or CPU verifies by its maker's signature may be shipped: pinned by version and hash, redistributable unmodified, and recorded in NOTICE.

    • A device's firmware is loaded only by its own driver, through its IOMMU domain, and never executes on the CPU.
    • CPU microcode is loaded by the kernel.
  • Operating lessons (Place operating lessons in the role files and the ARM64 ruling in CLAUDE.md #613):

    • line 3 says ToyOS is general-purpose, and that its test machines decide its feature set, never its design;
    • an agent stops what it started, killing only by PID and waiting out a build that holds the global lock;
    • a pull request's evidence never lives only in /tmp.
  • Code used by one program lives in that program (Track: code used by one program lives in that program #604), the track issues/build/code-used-by-one-program-lives-in-that-program.md. An input boundary stays a crate of its own: a step may move one but never merge it.

    • toyos-userpin goes.
    • toyos-pcid, toyos-proclife and toyos-sched become the kernel's library, with the loom and sim crates under kernel/.
    • toyos-libc-copies moves to the tests.
    • Every crate of this tree with exactly one consumer goes under it, a crate of its own. Consumers are counted over every manifest in the tree, excluded packages and tests/ included, and a crate the images ship as a program of its own counts as its own consumer.
    • toyos-fat32-check goes under toyos-fat32/, in a step of its own.

    With it land issues/build/the-pcid-negative-control-runs-nowhere.md, which its step 2 closes, and issues/build/userland-programs-are-never-linted.md, which the no-panic track's stage 4 waits on.

  • Two builds of one LLVM key differ in their bytes (File: two builds of one LLVM key differ in their bytes, a defect M4 waits on #646): a defect, with an exit a host test reaches.

  • A TCO base word near all-ones panics the loader and the kernel: a defect, issues/hardware/a-tco-base-word-near-all-ones-panics-the-loader-and-the-kernel.md.

What was dropped

Until #653 lands

issues/kernel/whether-the-kernel-loads-cpu-microcode-is-the-owners.md:9-10 say that root CLAUDE.md admits no CPU microcode. This landing makes that false, and #653 deletes the file. If #653 lands first, there is no such window.

Gates

  • cargo run -- --ci host at 7131598: EXIT=0, "[ci] Host: 59 step(s), all green". Every FAILED line in its log is a negative control's red, which that control's step demands.
  • No guest run: nothing here reaches a guest.

Round 5's commands, outputs and exits are in issuecomment-5935427621, round 6's in issuecomment-5936162566, and round 7's in issuecomment-5936487478.

Unsure

  • Step 4's rule, measured at 7131598 over every package manifest the tree tracks, yields these crates, each with one consumer:

    • toyos-dma, toyos-gicv3, toyos-pci and toyos-ps2, under the kernel, and toyos-pcid and toyos-proclife, which step 2 takes into the kernel's library;
    • toyos-desktop under the compositor, toyos-mixer under soundd and toyos-mdns under netd;
    • toyos-net-udp under toyos-dhcp, whose tests alone use it, and toyos-transport under toyos-blockring;
    • tls-dep, already under tests/toyos-rust-tests/tls-multi-crate/.

    terminal has two consumers: console links it, and the images ship it as a program of its own. More than one package links each of these: toyos-xhci (the kernel, its sim and the harness's dev edge), toyos-i219 (netd, the harness's dev edge and tests/toyos-rust-tests), toyos-userbound (the kernel and the harness's dev edge) and blockd (fsd and tests/toyos-rust-tests).

  • toyos-fat32-check has two consumers: the build links it, and toyos-fat32's tests dev-depend on it. Step 5 moves it on the one-subject rule.

🤖 Generated with Claude Code

https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L

Japabu and others added 28 commits September 29, 2026 09:31
Almost every single-consumer `toyos-*` crate says, in its manifest or module
doc, that it is a crate so that its tests run on the host. Measured today:

- The gated userland programs already host-test their own modules
  (`src/userlandhost.rs`), and blockd, calc, pkg and terminal carry a lib
  beside their bin.
- A package with a `no_std`/`no_main` bin under a bare-target
  `.cargo/config.toml` and a `cfg_attr(not(test), no_std)` lib builds both for
  `x86_64-unknown-none`. Its lib's tests run under
  `cargo test --lib --target aarch64-apple-darwin`, and a host package that
  depends on it by path builds the lib alone.
- The kernel binary itself runs a `#[cfg(test)]` test on aarch64-apple-darwin.
  That takes `cfg_attr(not(test), no_main)`, the panic handler, the global
  allocator and three aarch64 entry assembly items out under test, and allows
  dead code in the test build. Its x86_64 Linux test object links as a PIE
  under `-z text`, with only libc, unwinder and allocator-shim symbols left
  undefined.
- `#![forbid(unsafe_code)]` is enforced at module scope, including against a
  local `allow`.

The track folds 16 packages away, 95 to 79, and ends in a `src/hostws.rs`
gate. That gate reds on an rlib-only package with fewer than two consumers
unless it declares one of four exception kinds.

Two defects found on the way are filed rather than fixed:
- `toyos-pcid`'s `counting-allocator` control is run by nothing. By hand it
  still reds.
- No userland crate is linted, though the gated ones build for the host.
  soundd shows 8 clippy findings and netd 10.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The owner's direction on the first round: no gate, and push the cleanup as
far as the measured facts allow. The track is renamed from
a-crate-has-two-consumers-or-says-why-it-is-alone, because it no longer
makes that claim, and it is rewritten as five steps, each with an exit and a
check.

- The kernel-only crates become a lib target of the kernel package, in
  kernel/pure/. The loom models become kernel/loom/, and the simulators
  kernel/sim/.
- Single-program userland crates become modules of their program, or its
  library where another program reads them.
- Shared crates on one subject merge: toyos-boot, toyos-log, toyos-block, and
  swap into toyos-manifest.
- toyos-userpin is deleted.

That takes the tree from 95 packages to 66, and the root's toyos-*
directories from 44 to 16.

Trial folds in scratch back the plan:
- Seven kernel crates in kernel/pure/: the kernel builds for both bare
  targets, and the library lists 276 tests, the seven crates' sum. The
  simulator and loom counts are unchanged, four controls still red, the
  harness builds against the library, and both clippy shapes exit 0.
- The mixer in soundd lists 58 tests, and the desktop in the compositor
  95. soundd at opt-level 0 takes 34.31 s, and 3.07 s at 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in CLAUDE.md

Agents kill what they started before reporting, give rg an explicit path in
scripts, and keep PR evidence out of /tmp; the orchestrator acts on a finished
report before dispatching. CLAUDE.md states the general-purpose scope and that
ARM64 is a QEMU target only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U6SVYFkdvV2t38KzNrESxs
Restore "keep the architecture portable" beside the ARM64 sentence and drop
"proving machines"; fold kill-by-PID into "Leave the machine as you found it";
keep the rg and /tmp rules in implementer.md only; drop the ARM-hardware clause
from the process-memory issue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U6SVYFkdvV2t38KzNrESxs
…ragraph

The kill-by-PID rule moves from implementer.md into the CLAUDE.md
"Leave the machine as you found it" bullet, "for ever" becomes "forever",
and the process-memory issue drops its ARM64 clause.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U6SVYFkdvV2t38KzNrESxs
The child-process track's fourteen questions are ruled as recommended,
each written as one line at the stage it governs, and
issues/kernel/the-child-process-track-waits-on-the-owners-rulings.md
goes:

- Q2, Q6d at stage 2: an end reads as an exit, a kill or a fault kind
  alike on every architecture, a bare code reads the last two as
  failures, and no end reads as a quit's reason.
- Q3a, Q3b, Q3c at stage 3: libc imitates SIGCHLD; a handler runs at
  once, beside the program; a C child starts with descriptors 0-2 and
  what its file actions name, a stated departure from POSIX.
- Q5a, Q5b, Q5c at stage 5: a login's session is a program that only
  parents what its user starts; init hands the compositor or sshd the
  right to start programs in it; sshd's right also quits and kills it.
- Q6a, Q6b, Q6c, Q6e, Q6f at stage 6, whose text already said each as
  recommended: a quit carries interrupt, hang-up or terminate, reaches
  the subtree, kills a process that never listens, reaches a Rust
  program through std and ctrlc, and a C program as SIGINT, SIGHUP and
  SIGTERM.
- Q7 at stage 7: a second Ctrl+C kills only a program that has not yet
  taken the first.

Cut as moot: the pointer to the question file, the question labels on
the stage headings, the Ruled block's session clause (now stage 5's
line), stage 6's reason for the shell relaying nothing (now stage 6's
reach line), and stage 7's "Stop and continue need a suspend primitive
and are not proposed", which scoped the proposal the rulings closed. The
track stays at 260 lines.

The supervisor track's open item on the ask's ABI cited Q6a; Q6a is
ruled and its stage 3 already asks by stage 6's quit, so the item goes.

The rest:

- The kernel is to load CPU microcode signed by the CPU's maker and
  pinned by version and hash, as vendor device firmware is. The question
  becomes the defect issues/kernel/the-kernel-loads-no-cpu-microcode.md,
  exit: current microcode loaded early on every CPU, at least as current
  as Linux's. The security track's list follows the rename.
- std::os::toyos::io::{AsRawFd, FromRawFd} are renamed the next time the
  trait is touched in the fork: an open defect with that exit.
- A boot start's device refusal is fatal only for a device the
  [programs] row marks as required; otherwise init logs it loudly and
  starts the program without it: an open defect whose exit is the row's
  mark and the two outcomes.
- doomgeneric's fetch stays; its question file goes.
- doom.jpg is the owner's own screenshot, which he keeps, and no licence
  question applies; its question file goes and its COMMITTED_FILES row
  says so in the column that names where its terms are recorded. The
  terms column stays NOASSERTION.
- The blocked-task dump keeps painting its report on the panel and
  holding it there: one line at the small-kernel track's step 5 replaces
  that step's open question and stage 6's hold on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
Found while scouting whether rustc's bootstrap builds LLVM under n2 in place
of Ninja. `llvm::tests::keyed_and_built` built key 64453b64c91c17c2 (LLVM,
clang and LLD) from a fork checkout at c4c65e3e87a whose src/llvm-project was
a git worktree of the primary's at a79bc52c1d5e, with only an n2 link named
`ninja` reachable; exit 0 in 1693 s. The store holds a Ninja-built LLVM at
the same key, made in toyos-mtime on 2026-09-29, before n2 was first fetched
on this host.

Both hold the same 3841 paths; 3660 are byte-identical. Every one of the
other 181 is explained by something the key does not name: the LLVM
checkout's origin URL (LLVM_REPOSITORY), the build directory (lld's LC_RPATH,
llvm-config's roots), or the dates in 161 archives whose members are
byte-identical. None traces to the build tool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
Review round 1 on 7eb4428.

- The microcode ruling orders the kernel to load what root CLAUDE.md's
  firmware rule still bars: it admits only device firmware that never
  executes on the CPU. PR #636 amends that sentence to admit the CPU's own
  microcode, which the kernel loads, and this branch lands after it. The
  defect regains the deleted question's pointer at that rule, as one line
  saying the rule admits the microcode once #636 lands.
- Step 6 of the small-kernel track loses its heading "The scheduler knows
  nothing about devices": step 5 now keeps the pass painting the panel, a
  device the pass reaches.
- The child-process track's stage headings lose " (ruled)", and stage 3
  loses "ruled; ": every stage carried it, so it distinguished nothing.
  The track is 35 bytes longer than on main (18608 -> 18643), at 260
  lines.
- doom.jpg's row loses "he keeps it, and rules that": the committed file
  shows it is kept, and "no licence question applies" carries the ruling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…y a check that can fail

Review of 90e2b17 on PR #646. The exit named two worktrees, while the
origin that differs is the primary's against a worktree's, and it named no
check.

Which LLVM_REPOSITORY each checkout's build writes, from LLVM's own
GenerateVersionFromVCS.cmake run as llvm/include/llvm/Support/CMakeLists.txt
runs it, exit 0 each:
- the primary's rust/src/llvm-project, gitlink a79bc52c1d5e, checkout
  52ed14fcd56a: https://github.com/rust-lang/llvm-project.git
- toyos-libcllvm's, gitlink and checkout 849da7d62fbc:
  https://github.com/ToyOSOrg/llvm-project.git
The fork's .gitmodules and its shared config both name ToyOSOrg. Bootstrap's
update_submodule, its git commands run on scratch repositories in the
primary's state (cloned from A, .gitmodules and config naming B): with the
checkout behind its gitlink, `submodule sync` and `update` exit 0 and the
script then writes B; with the checkout at its gitlink, bootstrap runs
nothing and it writes A.

The exit now names the check: one key built in two fork checkouts at
different paths whose origins name different repositories, every file of
the two installs byte-identical. Path and origin together cover every pair:
the primary's and a worktree's, two worktrees', a checkout made by hand.

kind: defect. The origin reaches guest bytes: `llvm-readelf -p .comment` on
sysroot d8a0215fc9eae3c5's libstd-1d0a603a43d0da8a.so gives "Linker: LLD
22.1.8 (https://github.com/ToyOSOrg/llvm-project.git 849da7d6...)", and 75 of
the 77 members of its c/lib/libc++.a carry clang's version with the same URL;
the other two are UnwindRegistersSave.S.o and UnwindRegistersRestore.S.o,
which have no .comment.

issues/build/toyos-builds-itself.md points M4 at it. The Ninja row of
issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md takes the
scout's result: bootstrap built LLVM, clang and LLD under n2, exit 0.

The counts that rested on the n2 tree (181 different, 3660 identical, 161
archives differing only in dates) went with it, and the issue carries none of
the comparison's counts. The stored side, rust/build/llvm/64453b64c91c17c2,
reproduces: 3841 paths, 162 archives, 19 files naming
ToyOSOrg/llvm-project, llvm-config and lld naming toyos-mtime, and every
member of all 162 archives dated 2026 by `ar tv`.

Removed as the review asked: "none of them the build tool", "every
--version prints it", the key and toyos-mtime, and the examples of
byte-identical tools.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…rates

The owner decided a rule graded by what a panic costs: no panic at all at
an input boundary, no implicit panic in the kernel or the system services,
normal Rust for apps, ports, tests and tooling. He asked that it be
recorded, not done now. The track carries the rule, what holds today and
the five stages with their exits.

Measured for it:
- `rg -o '\.unwrap\(\)|\.expect\(' kernel/src | wc -l` is 157 (154 lines
  by `rg -c`).
- `cargo clippy --target x86_64-unknown-none -- -W clippy::indexing_slicing
  -W clippy::arithmetic_side_effects -W clippy::unwrap_used
  -W clippy::expect_used -W clippy::panic -W clippy::unreachable
  -W clippy::cast_possible_truncation --message-format=json`, in kernel/,
  counted per lint code with jq: 2,008 findings in the kernel crate.
- `rustc -Z unstable-options --print target-spec-json` gives
  `"panic-strategy": "abort"` for x86_64-unknown-none and
  aarch64-unknown-none-softfloat. The no-panic README calls its attribute
  "useless in code built with panic = abort", so a link proof has to come
  from a host build.
- A scratch crate run under the seven lints drew no warning for `assert!`,
  `copy_from_slice` or `split_at`. It drew one each for `a[3]` and `panic!`.

The brief expected `issues/` to hold the two crafted-ELF panics an overflow
check found, and it holds neither. The closed entry left the tracker at
fa2799d, yet seven comments still cite `issues/` for it, and the tree's
rule is to file that rather than fix it here. The second file records it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…el can do

Two owner rulings of 2026-10-01, written into the prompts that govern agents.

The ABI. "We can change system calls. We can remove them, add them, change
them. I want to have the cleanest, most sustainable ABI." Three lines said the
opposite and steered agents away from the ABI:

- Root CLAUDE.md, "Syscall ABI": "Never add or change a syscall without
  discussion; a deleted syscall's number is retired, never reused." It now says
  the cleanest, most sustainable ABI beats convenience and a removed number is
  free. "read the code" goes with it: the Architecture section's header already
  says it. The line is shorter than the one it replaces. Workflow's "An ABI
  change lands with the work that needs it" stays.
- implementer.md: "Never touch toyos-abi/src, toyos/src or
  userland/libc/src unless the brief is an ABI brief." Deleted. The brief's
  fence already bounds what an implementer touches.
- reviewer.md, "What no gate reads": a BLOCKER for reusing a retired syscall,
  SYS_DEBUG action or inbox op number, or declaring a retired ABI name.
  Deleted. Connect-by-name and pid-as-authority stay banned by root
  CLAUDE.md's Capabilities paragraph, which bans the design whatever it is
  called.

Kernel or server. In the symlink incident, libc's symlink needed "refuse an
existing name". The implementer avoided the kernel change and returned ENOSYS,
and the reviewer asked for the kernel to refuse the name. Neither asked whether
the kernel should own symlinks at all; fsd already resolves them. The owner:
"one less thing for the kernel to do… the reviewer and implementer should know
we try to use userland programs instead of the kernel."

- implementer.md: before adding or keeping kernel behaviour, ask whether a
  userland server can own it. When the clean design changes the ABI, change
  the ABI.
- reviewer.md, "Fit": a BLOCKER each for a kernel addition or a kept kernel
  path a userland server could own, and for a design made worse to spare the
  ABI.

The code still keeps retired numbers: retired_syscalls!, the "formerly …"
entries in toyos-abi, four test sites that use syscall 26 as their logged
refusal, and seven issue files that plan by retirement. That is outside this
branch's fence, so it is filed as
issues/design-debt/the-abi-still-keeps-retired-syscall-numbers.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…llow]; seven crafted-ELF clauses go

Answers the review of 6b2eef1 on PR #665.

The set covers every operation that can panic on input. Each lint name was
checked against clippy 0.1.98 (48a229ceae) on a scratch crate under
`#![deny(unknown_lints)]`. All fifteen drew a finding on their own form. A
bogus `clippy::no_such_lint_control` was refused, and it was the only
error (exit 101). The set adds these to PR #653's nine:
- `string_slice`, because `indexing_slicing` drew nothing on `&s[1..]` and
  `string_slice` did;
- `cast_possible_truncation`, which the owner names;
- `disallowed_methods` naming `slice::split_at` and `slice::copy_from_slice`;
- `disallowed_macros` naming `core::assert`, `assert_eq` and `assert_ne`.
Each of those configured names fired.

What the set does not see, measured: `a << b`, `a >> b`, `1u64 << b`,
`a.pow(b)` and `a.abs()` drew no finding. Built with
`-C overflow-checks=on`, the shift, the `pow` and the `abs` each exit 101:
"attempt to shift left with overflow", "attempt to exponentiate with
overflow", "attempt to negate with overflow".

The gate:
- `#![forbid(clippy::indexing_slicing)]` turns an inner
  `#[expect(…, reason)]` into E0453, and an inner `#![allow(…, reason)]` too.
- With `allow_attributes` and `allow_attributes_without_reason` on, an outer
  `#[allow]` draws the first lint, with or without a reason.
- A bare `#[allow]`, `#![allow]` or `#[expect]` draws the second.
- An inner `#![allow(…, reason = …)]` draws neither. Stage 3's exit closes
  that hole with a `--ci host` step.

clippy.toml: with a parent file listing `copy_from_slice` and a child
listing `split_at`, the child crate drew only `split_at`. With the child's
file removed, it drew only `copy_from_slice`. Only the nearest file is read.

The count. `cargo clippy --target x86_64-unknown-none
--message-format=json` ran in kernel/ with the set as `-W`. The two
methods and three macros were added to a copy of the root clippy.toml,
passed through CLIPPY_CONF_DIR. It exits 101 under the kernel's
`-Dwarnings`. Counted by code with jq:
- 992 arithmetic_side_effects
- 408 indexing_slicing
- 394 cast_possible_truncation
- 208 disallowed_macros (200 assert, 8 assert_eq)
- 109 expect_used
- 60 panic
- 39 disallowed_methods (all copy_from_slice)
- 29 unwrap_used
- 16 unreachable
- 14 panic_in_result_fn
- 5 string_slice
That is 2,274. Beside them are 26 allow_attributes and 28
allow_attributes_without_reason.

Seven clauses cited `issues/` for crafted-ELF panics that the tracker
closed at fa2799d. They sat at Cargo.toml (two), bootloader/, kernel/ and
userland/Cargo.toml, and src/build.rs (two). All are deleted, with the file
that recorded them. None of the five files is a sysroot input.

Also deleted, as REMOVEs:
- the "seven crates" claim;
- the boundary and service lists;
- "where a reviewer sees it";
- the per-crate inventory;
- the rg count;
- the crafted-ELF history;
- the microcode citation;
- the constraint's provenance;
- stage 5;
- the mutation line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
Review of 066e1a0 on #666 sent the branch back.

- CLAUDE.md's Kernel line said new additions are "discussed" and named the
  filesystem a kernel job, against both rulings. It now says the kernel
  takes on only what userland cannot, keeps the job list without the
  filesystem, and points at the Capabilities paragraph, whose "Not yet true
  of files" sentence already records the machine-wide tree the kernel still
  holds. 132 characters replace 135.
- implementer.md's closed list of kernel jobs was a second declaration of
  the kernel's scope that the owner never gave; deleted, along with the
  restated rule, which root CLAUDE.md now carries.
- "or keeping" (implementer.md) and "or a kernel path the branch keeps"
  (reviewer.md) made every kernel-side defect fix a BLOCKER outside its
  fence; deleted. A kernel refusal is still "a kernel addition", and an
  ENOSYS dodge is still "a design made worse to spare the ABI".
- "a userland server" became "userland" in both files: the owner's loader
  move puts relocation in a Ring 3 loader in the target's own address space,
  which is userland but no server.
- implementer.md says a clean design that reaches past the fence blocks the
  implementer, so the ABI sentence does not widen the fence.
- The Syscall ABI line drops "add, change or remove syscalls", which
  "completely unstable" already says.
- issues/design-debt/the-abi-still-keeps-retired-syscall-numbers.md names an
  owner and lists the retired device classes 3 and 4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…nel takes on only what userland cannot

One conflict, reviewer.md's tinycc sentence beside "What no gate reads":
main deleted `hello.c` from the files tracked under `tests/testcases/`,
and #666 deleted the retired-ABI BLOCKER from the bullet below it. Both
are kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…afted-ELF clauses go

Clean merge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…t its microcode files

Clean merge. Three of #645's hunks are left out, because #653 carries the
microcode defect and lands on its own:

- the new `issues/kernel/the-kernel-loads-no-cpu-microcode.md`, an add/add
  conflict with #653's file of that name, whose body is a superset;
- the deletion of
  `issues/kernel/whether-the-kernel-loads-cpu-microcode-is-the-owners.md`,
  which #653 deletes;
- the security track's citation of the new file, which #653 changes.

So the security track still cites a file that exists, and #653 merges
onto this without a conflict.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…d CLAUDE.md

Clean merge; what of it stays is decided in the commit after this one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…n that program

Clean merge; its counts and premises are refreshed against main in a
later commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…heir bytes

One conflict, the host-tools table's Ninja row. #646 added the scout's
n2 result to the row's verdict; main deleted the row when the LLVM build
began running n2 as its only Ninja (b2b1713), which is the row's exit.
Main's side is taken: the row is gone, and with it #646's hunk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…ites are main's

Round 1 of #666's review asked that "the 'only what only a kernel can'
rule replaces that 135-character span, written as a rule on what the
kernel takes on and not as a snapshot". Round 2 kept the job list beside
the rule, less the filesystem, with a "files: see Capabilities" pointer.
The job list is the snapshot the review named, and the rule alone states
what the kernel takes on; the pointer's subject is already the
Capabilities paragraph's own "Not yet true of files". So the span is now
the rule alone: "takes on only what userland cannot."

The ABI issue listed four test sites that take syscall 26 as their logged
refusal. Since #660 landed, `log_hold.rs` and `tests/common/origin.rs` are
gone; `panic_halts_first.rs` and `tests/toyos.rs` remain, and the exit
names both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…admitted

#613's first review sent it back because root CLAUDE.md's line 3 grew and
its ARM64 sentence contradicted the cores issue. Since then main's ARM64
track has stated the ruling itself ("no ARM hardware is a target and no
work goes into one"), and the cores issue no longer says otherwise. What
of #613 stays:

- Line 3 goes back to main's text with two additions: "general-purpose",
  and "Its test machines decide its feature set, never its design." Both
  are the owner's ruling of 2026-09-29 ("ToyOS is a general-purpose OS for
  modern hardware; the T14 may decide the feature set but is not the
  design centre"), recorded at 314f874 in the Raspberry Pi track and
  lost when that track was deleted; nothing on main says it now. #613's
  ARM64 sentence goes: main's track says it.
- "Leave the machine as you found it" says "kills by PID what it started"
  where it said "stops what it started". By PID is the one thing the
  lesson adds to that bullet; "before reporting" is already its "never
  leaves ... running".
- implementer.md keeps the rule that a pull request's evidence never
  lives only in /tmp, and that mutation patches are posted to the pull
  request. Nothing in implementer.md said either.
- implementer.md loses the rule that rg without a path waits forever on
  stdin. In the agents' shell, foreground and background, stdin is a
  character device (`stat -f '%HT' /dev/fd/0`), and `rg -l <needle>` with
  no path searched the working directory and exited 1, no match, in both.
- The process-memory track keeps main's sentence that one paging design
  serves x86-64 and the ARM64 the tree is kept portable for. ARM64 under
  QEMU is still that second architecture; nothing in it contradicts the
  QEMU-only ruling.

#645's one BLOCKER is answered here too: the firmware paragraph now says
vendor firmware "never executes on the CPU, save the CPU's own microcode,
which the kernel loads", #636's clause for the owner's ruling that the
kernel loads CPU microcode signed by its maker and pinned by version and
hash.

Root CLAUDE.md is 16075 bytes; main's is 16077.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…ernel's crates

Answers round 2 of #665's review (f469e90).

Blockers:
- The set names every lossy cast: `cast_possible_wrap`, `cast_sign_loss`
  and `cast_precision_loss` beside `cast_possible_truncation`. Each changes
  a value silently, which "Fail fast" puts below a panic; that is the
  reason the track now gives, in place of "the owner names it".
- Stage 3's `--ci host` step also refuses an `#[expect]` of the set on a
  `mod`, on an `impl`, and as an inner `#![expect]`: any of them passes
  every finding beneath it.
- Stage 3 ends with every crate of this tree that `kernel/Cargo.toml`
  links under the same attributes, unless stage 1 already forbids the
  set in it.

Notes: the set names `slice::split_at_mut` and `slice::clone_from_slice`;
the clause on `issues/design-debt/elf-domain-lint-line-not-yet-added.md`
goes, and that issue is left to its holder; stage 1's "one declaration"
now states what was measured: Cargo's `[lints]` reaches test code and
`cargo clippy --lib -- -F` does not, and neither reaches a single module,
so an input boundary inside the kernel becomes a crate first.

Removed: the clippy version line, "(fail fast)" and the
unrepresentable-type sentence, everything after "No crate carries the
set.", and the ELF clause.

Measured on scratch crates with cargo 1.98.1 and clippy 0.1.98
(48a229ceae), each `cargo clippy -p <crate>` unless named:
- `#![forbid(clippy::indexing_slicing)]` and an `#[expect(…, reason)]` of
  it: E0453, exit 101. The same forbid and an inner `#![allow(…, reason)]`
  in a module: E0453, exit 101.
- With `clippy::allow_attributes` and `allow_attributes_without_reason`
  forbidden: an outer `#[allow(…, reason)]` draws `allow_attributes`, exit
  101; an `#[expect]` with no reason draws the second, exit 101; an inner
  `#![allow(…, reason)]` in a module draws neither, exit 0.
- Under the same attributes and `deny` of indexing and arithmetic, one
  `#[expect(…, reason)]` on `mod drivers;` over five findings, an inner
  `#![expect]` over two and an `#[expect]` on an `impl` over two: exit 0,
  no warning, so every expectation was fulfilled.
- `&s[1..]` on a `str` draws `string_slice`, and `indexing_slicing`, also
  denied, draws nothing: exit 101.
- Shift left and right by a variable, `pow` and `abs` under the whole set
  denied: exit 0. Built with `-C overflow-checks=on`, each exits 101:
  "attempt to shift left with overflow", "attempt to shift right with
  overflow", "attempt to exponentiate with overflow", "attempt to negate
  with overflow".
- `[lints.clippy] indexing_slicing = "forbid"`: `--all-targets` exits 101
  at a `#[cfg(test)]` slice index, `--lib` exits 0; with
  `#![cfg_attr(test, allow(clippy::indexing_slicing))]` added,
  `--all-targets` gives E0453, exit 101.
- `--lib -- -F clippy::indexing_slicing`: exit 101 on the library's index;
  exit 0 on a clean library whose test indexes a slice, which
  `--all-targets -- -F` refuses, exit 101; and E0453, exit 101, on an
  inner `#[expect(…, reason)]` of the lint.
- `CLIPPY_CONF_DIR` naming the four methods and three macros: each of the
  seven fires, exit 101.

The kernel count: in kernel/, with the root clippy.toml plus those
methods and macros through `CLIPPY_CONF_DIR`, `cargo clippy --target
x86_64-unknown-none --message-format=json -- -W <each of the 16 lints>`
exits 101 under the kernel's `-Dwarnings` with 2,282 errors, counted by
code: 984 arithmetic_side_effects, 405 indexing_slicing, 392
cast_possible_truncation, 205 disallowed_macros (198 assert, 7
assert_eq), 107 expect_used, 55 panic, 39 disallowed_methods (all
copy_from_slice), 29 unwrap_used, 20 cast_possible_wrap, 16 unreachable,
14 panic_in_result_fn, 9 cast_sign_loss, 5 string_slice, 2
cast_precision_loss. That is the kernel package alone: clippy lints no
crate it links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
#604 was written against main as of 7e15181, 574 commits back. Each
premise was checked against this branch, and each count was relisted
with `cargo test -p <package> -- --list`, exit 0 for every package.

Premises that moved:
- The network stack's stage 3 landed as `toyos-net-ip`, `toyos-net-udp`
  and `toyos-dhcp`. Nothing but each other depends on them, so step 5
  folds them into netd's library beside the four it already named. Stage
  4's `toyos-net-shard` and `toyos-net-testnet` are what the network track
  still plans.
- `toyos-gicv3` and `toyos-cpuvuln` arrived. `kernel/Cargo.toml` is the one
  manifest that names `toyos-gicv3`. `toyos-cpuvuln` has no dependent yet,
  and its track (`a-pure-function-decides-a-cpus-speculation-mitigations-
  as-linux-does.md`) has it "built by the kernel and by a host test". Both
  go into the kernel's library in step 3.
- `src/redlist.rs` is deleted, so step 1's redlist check goes.
  `munmap_reissues_read_window` is still a test binary and rides
  `shared_metal`.
- Three scheduler tests need a feature, not six, and `check` is the one
  they need: toyos-sched lists 92 tests bare, 95 with `check`, 92 with
  `protocol-port` and 95 with both.

Counts, old and new:
- The kernel's library: 391 becomes 495. dma 17, pci 75, pcid 6,
  proclife 34, ps2 24, sched 95, userbound 34, xhci 150, gicv3 8 and
  cpuvuln 52. toyos-symbols is still 9.
- `kernel/loom`: 81 becomes 79 (kernel-loom 53, sched-loom 26).
  `kernel/sim` is still 99 (sched-sim 53, xhci-sim 46).
- The merged crates, 157, 26, 45, 25 and 67, become 170, 26, 45, 26 and
  67. toyos-boot is acpi 52, bootmap 43, rootimage 21, blackbox 33, tco 13
  and quiesce 8. toyos-log is elide 12 and logstream 14. toyos-block is
  blockhold 9, blockring 19 and transport 17. Manifest 19 and swap 7, and
  fat32-check 67.
- netd's library: 709 becomes 1105. dns 43, mdns 12, net-wire 292,
  net-tcp 363, net-ip 261, net-udp 58 and dhcp 76. The mixer is still 55,
  the desktop 95 and inspect 21.

Still true, so unchanged:
- The pcid issue. `src/ci.rs`'s CONTROLS has no toyos-pcid row, and
  `declared_model_controls` reads no toyos-pcid manifest. `cargo test -p
  toyos-pcid --features counting-allocator` exits 101 with
  `tests::two_live_address_spaces_never_share_a_pcid ... FAILED`.
- The userland-lint issue. `cargo clippy --manifest-path
  userland/<crate>/Cargo.toml --target aarch64-apple-darwin --all-targets
  -- -D warnings` exits 101 with 8 errors in soundd, 10 in netd's test
  target, and 1 in toyos-window under the compositor.
- `the_corpus_is_reproduced_bit_for_bit` is still the mixer's.
- Userland's `[profile.dev]` is still at opt-level 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…es M4

Answers round 2 of #646's review (865239c).

- Told apart from the two-checkouts defect. Each file now says what it
  holds fixed and names the other. The two-checkouts defect holds the
  LLVM fixed and varies rustc's inputs. This one varies the LLVM's build.
  Every checkout on a host links the one LLVM its key names, so the
  two-checkouts gate cannot see an origin, and a comparison of two LLVM
  installs cannot see a panic path.
- A host exit. LLVM's own `GenerateVersionFromVCS.cmake`, at the primary's
  `src/llvm-project` 52ed14fcd56a, ran with `cmake -DNAMES=LLVM
  -DLLVM_SOURCE_DIR=<checkout>/llvm -DHEADER_FILE=<out> -P <script>` on two
  scratch checkouts of one commit, whose origins name `rust-lang` and
  `ToyOSOrg`, exit 0 each:
  - with both forcing variables empty, as `config_text` leaves them today,
    the headers differ in `LLVM_REPOSITORY`;
  - with `LLVM_FORCE_VC_REPOSITORY` alone, they match, but the revision is
    gone: `#undef LLVM_REVISION`;
  - with `LLVM_FORCE_VC_REVISION` set too, they match and both are
    defined.
  So the exit names both variables, and a host test running that script
  on two such checkouts. It is red today, and it has no `update_submodule`
  in it to sync the origins together. The nightly's two full builds stay
  only for what a configure or a build writes, the build directory and
  the archive dates. That check now has to show the two origins still
  differ after each build, because bootstrap syncs a checkout that is
  behind its gitlink.
- M4's line goes. M4's guest side links with the LLD that bootstrap builds
  for a ToyOS host, and no `src/llvm.rs` key builds that LLD, so this exit
  could be met while M4's hashes still differ.

The issue no longer says the primary's checkout names `rust-lang`, which
was a snapshot of this host (round 2's REMOVE). It no longer says one of
the two builds ran under n2 in place of Ninja: on main every
`build_in_fork` build runs n2 (4f2bea1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Scratch crates behind #665's measurements in this batch (cargo 1.98.1, clippy 0.1.98 48a229ceae; edition 2024; one workspace, each crate cargo clippy -p <crate> unless the command says otherwise). Posted here so the evidence does not live only in a temporary directory.

c1

src/lib.rs:

#![forbid(clippy::indexing_slicing)]

#[expect(clippy::indexing_slicing, reason = "one stop")]
pub fn first(v: &[u8]) -> u8 {
    v[0]
}

c2

src/lib.rs:

#![forbid(clippy::indexing_slicing)]

pub mod m {
    #![allow(clippy::indexing_slicing, reason = "a module")]
    pub fn first(v: &[u8]) -> u8 {
        v[0]
    }
}

c3

src/lib.rs:

#![deny(clippy::indexing_slicing)]
#![forbid(clippy::allow_attributes, clippy::allow_attributes_without_reason)]

#[allow(clippy::indexing_slicing, reason = "outer")]
pub fn first(v: &[u8]) -> u8 {
    v[0]
}

c4

src/lib.rs:

#![deny(clippy::indexing_slicing)]
#![forbid(clippy::allow_attributes, clippy::allow_attributes_without_reason)]

pub mod m {
    #![allow(clippy::indexing_slicing, reason = "inner")]
    pub fn first(v: &[u8]) -> u8 {
        v[0]
    }
    pub fn second(v: &[u8]) -> u8 {
        v[1]
    }
}

c5

src/lib.rs:

#![deny(clippy::indexing_slicing)]
#![forbid(clippy::allow_attributes, clippy::allow_attributes_without_reason)]

#[expect(clippy::indexing_slicing)]
pub fn first(v: &[u8]) -> u8 {
    v[0]
}

c6

src/drivers.rs:

pub fn a(v: &[u8]) -> u8 {
    v[0]
}
pub fn b(v: &[u8]) -> u8 {
    v[1]
}
pub fn c(v: &[u8], i: usize) -> u8 {
    v[i]
}
pub fn d(x: u32, y: u32) -> u32 {
    x + y
}
pub fn e(x: u32, y: u32) -> u32 {
    x * y
}

src/inner.rs:

#![expect(clippy::indexing_slicing, reason = "inner")]

pub fn a(v: &[u8]) -> u8 {
    v[0]
}
pub fn b(v: &[u8]) -> u8 {
    v[1]
}

src/lib.rs:

#![deny(clippy::indexing_slicing, clippy::arithmetic_side_effects)]
#![forbid(clippy::allow_attributes, clippy::allow_attributes_without_reason)]

#[expect(clippy::arithmetic_side_effects, clippy::indexing_slicing, reason = "drivers")]
pub mod drivers;
pub mod inner;

pub struct S(pub [u8; 4]);

#[expect(clippy::indexing_slicing, reason = "impl")]
impl S {
    pub fn a(&self, i: usize) -> u8 {
        self.0[i]
    }
    pub fn b(&self, j: usize) -> u8 {
        self.0[j]
    }
}

c7

src/lib.rs:

#![deny(clippy::indexing_slicing, clippy::string_slice)]

pub fn tail(s: &str) -> &str {
    &s[1..]
}

c8

src/lib.rs:

#![deny(
    clippy::indexing_slicing,
    clippy::string_slice,
    clippy::arithmetic_side_effects,
    clippy::unwrap_used,
    clippy::expect_used,
    clippy::panic,
    clippy::unreachable,
    clippy::todo,
    clippy::unimplemented,
    clippy::panic_in_result_fn,
    clippy::cast_possible_truncation,
    clippy::cast_possible_wrap,
    clippy::cast_sign_loss,
    clippy::cast_precision_loss,
    clippy::disallowed_methods,
    clippy::disallowed_macros
)]

pub fn shl(a: u32, b: u32) -> u32 {
    a << b
}
pub fn shr(a: u32, b: u32) -> u32 {
    a >> b
}
pub fn pow(a: u32, b: u32) -> u32 {
    a.pow(b)
}
pub fn abs(a: i32) -> i32 {
    a.abs()
}

src/main.rs:

fn main() {
    let which = std::env::args().nth(1).unwrap_or_default();
    let big: u32 = std::hint::black_box(40);
    let min: i32 = std::hint::black_box(i32::MIN);
    let r = match which.as_str() {
        "shl" => i64::from(c8::shl(1, big)),
        "shr" => i64::from(c8::shr(1, big)),
        "pow" => i64::from(c8::pow(10, big)),
        "abs" => i64::from(c8::abs(min)),
        _ => 0,
    };
    println!("{which} returned {r}");
}

c9

Cargo.toml adds:

[lints.clippy]
indexing_slicing = "forbid"

src/lib.rs:

pub fn first(v: &[u8]) -> Option<&u8> {
    v.first()
}

#[cfg(test)]
mod tests {
    #[test]
    fn indexes() {
        let v: &[u8] = &[1];
        assert_eq!(v[0], 1);
    }
}

c10

Cargo.toml adds:

[lints.clippy]
indexing_slicing = "forbid"

src/lib.rs:

#![cfg_attr(test, allow(clippy::indexing_slicing))]

pub fn first(v: &[u8]) -> Option<&u8> {
    v.first()
}

#[cfg(test)]
mod tests {
    #[test]
    fn indexes() {
        let v: &[u8] = &[1];
        assert_eq!(v[0], 1);
    }
}

c11

src/lib.rs:

pub fn first(v: &[u8]) -> u8 {
    v[0]
}

#[cfg(test)]
mod tests {
    #[test]
    fn indexes() {
        let v: &[u8] = &[1];
        assert_eq!(v[0], 1);
    }
}

c12

src/lib.rs:

pub fn first(v: &[u8]) -> Option<&u8> {
    v.first()
}

#[cfg(test)]
mod tests {
    #[test]
    fn indexes() {
        let v: &[u8] = &[1];
        assert_eq!(v[0], 1);
    }
}

c13

src/lib.rs:

#[expect(clippy::indexing_slicing, reason = "one stop")]
pub fn first(v: &[u8]) -> u8 {
    v[0]
}

c14

src/lib.rs:

#![deny(clippy::disallowed_methods, clippy::disallowed_macros)]

pub fn methods(a: &mut [u8], b: &[u8], m: usize) -> u8 {
    let (x, _) = b.split_at(m);
    let (y, _) = a.split_at_mut(m);
    y.copy_from_slice(x);
    a.clone_from_slice(b);
    a.first().copied().unwrap_or(0)
}

pub fn macros(a: u8, b: u8) {
    assert!(a > 0);
    assert_eq!(a, b);
    assert_ne!(a, b);
}

c14's CLIPPY_CONF_DIR/clippy.toml

disallowed-methods = [
    { path = "slice::split_at", reason = "panics past the length" },
    { path = "slice::split_at_mut", reason = "panics past the length" },
    { path = "slice::copy_from_slice", reason = "panics on a length mismatch" },
    { path = "slice::clone_from_slice", reason = "panics on a length mismatch" },
]
disallowed-macros = [
    { path = "core::assert", reason = "panics" },
    { path = "core::assert_eq", reason = "panics" },
    { path = "core::assert_ne", reason = "panics" },
]

Commands and exits

cargo clippy -p c1                                   101  E0453 expect(clippy::indexing_slicing) incompatible with previous forbid
cargo clippy -p c2                                   101  E0453 allow(clippy::indexing_slicing) incompatible with previous forbid
cargo clippy -p c3                                   101  allow_attributes: #[allow] attribute found
cargo clippy -p c4                                     0  inner #![allow(…, reason)] passes both attribute lints
cargo clippy -p c5                                   101  allow_attributes_without_reason: `expect` attribute without specifying a reason
cargo clippy -p c6                                     0  one #[expect] on `mod drivers;`, an inner #![expect], an #[expect] on an impl: no warning
cargo clippy -p c7                                   101  string_slice only
cargo clippy -p c8 --lib                               0  shl, shr, pow, abs draw nothing from the set
RUSTFLAGS="-C overflow-checks=on" cargo build -p c8 --bin c8   0
./target/debug/c8 shl|shr|pow|abs                    101 each: shift left / shift right / exponentiate / negate with overflow
cargo clippy -p c9 --all-targets                     101  indexing may panic, c9/src/lib.rs:10 (lib test)
cargo clippy -p c9 --lib                               0
cargo clippy -p c10 --all-targets                    101  E0453 allow(clippy::indexing_slicing) incompatible with previous forbid (lib test)
cargo clippy -p c11 --lib -- -F clippy::indexing_slicing      101  indexing may panic, c11/src/lib.rs:2
cargo clippy -p c12 --lib -- -F clippy::indexing_slicing        0
cargo clippy -p c12 --all-targets -- -F clippy::indexing_slicing  101  indexing may panic, c12/src/lib.rs:10 (lib test)
cargo clippy -p c12 --all-targets -- -D warnings                  0
cargo clippy -p c13 --lib -- -F clippy::indexing_slicing      101  E0453 expect(clippy::indexing_slicing) incompatible with previous forbid
CLIPPY_CONF_DIR=<conf> cargo clippy -p c14           101  7 errors: split_at, split_at_mut, copy_from_slice, clone_from_slice, assert, assert_eq, assert_ne

The kernel count (#665's track, "Today")

In kernel/, with CLIPPY_CONF_DIR naming a copy of the root clippy.toml whose lists gain c14's four methods and three macros:

cargo clippy --target x86_64-unknown-none --message-format=json -- \
  -W clippy::indexing_slicing -W clippy::string_slice -W clippy::arithmetic_side_effects \
  -W clippy::unwrap_used -W clippy::expect_used -W clippy::panic -W clippy::unreachable \
  -W clippy::todo -W clippy::unimplemented -W clippy::panic_in_result_fn \
  -W clippy::cast_possible_truncation -W clippy::cast_possible_wrap -W clippy::cast_sign_loss \
  -W clippy::cast_precision_loss -W clippy::disallowed_methods -W clippy::disallowed_macros

Exit 101 under the kernel's -Dwarnings, "could not compile kernel (bin "kernel") due to 2282 previous errors". Errors by code: 984 arithmetic_side_effects, 405 indexing_slicing, 392 cast_possible_truncation, 205 disallowed_macros, 107 expect_used, 55 panic, 39 disallowed_methods, 29 unwrap_used, 20 cast_possible_wrap, 16 unreachable, 14 panic_in_result_fn, 9 cast_sign_loss, 5 string_slice, 2 cast_precision_loss.

LLVM's version script (#646's exit)

Two scratch repositories with one identical commit (d1122f946…), origin set to https://github.com/rust-lang/llvm-project.git and https://github.com/ToyOSOrg/llvm-project.git; the script is the primary's rust/src/llvm-project/llvm/cmake/modules/GenerateVersionFromVCS.cmake at 52ed14fcd56a:

cmake -DNAMES=LLVM -DLLVM_SOURCE_DIR=<repo>/llvm -DLLVM_FORCE_VC_REVISION=<r> -DLLVM_FORCE_VC_REPOSITORY=<u> -DHEADER_FILE=<out> -P <script>

Exit 0 for all six runs. With <r> and <u> empty, the two headers differ in LLVM_REPOSITORY. With <u> = the ToyOSOrg URL alone, they are identical and read #undef LLVM_REVISION. With <r> = the commit as well, they are identical and define both.

@Japabu
Japabu marked this pull request as ready for review October 1, 2026 12:24
…ill of a locked build, and the crate track yields to the no-panic track

Answers issuecomment-5931861144 (review of dc45e23).

BLOCKERs:
- Firmware. The shipping terms are shared and the loading clause splits:
  a device's firmware is loaded only by its own driver through its IOMMU
  domain and never executes on the CPU; CPU microcode is loaded by the
  kernel. Root CLAUDE.md is 16076 bytes, main's 16077.
- Panics. Stage 3's step refuses an #[expect] of the set over more than
  one finding. It lints a copy in which each #[expect] of the set is a
  #[deny] whose reason is its own file and line; rustc attaches that
  reason to every finding the attribute governs. It also refuses a copy
  with fewer findings than --force-warn of the set, which catches an
  #[expect] the copy missed, as one inside cfg_attr. The tier-2 row says
  the stop is spelled out at its site.
- Kill order. src/CLAUDE.md:24 is true: bootstrap recreates stage2
  without its cargo, and reassemble puts it back in the same process
  under the same hold (src/toolchain.rs). Root CLAUDE.md's bullet no
  longer orders a kill: an agent stops what it started, killing only by
  PID and waiting out a build that holds the global lock.
- Conflicting tracks. #604's track yields and names #665's: an input
  boundary is a crate of its own, because tier 1 is forbidden per crate
  and a crate holding a tier-2 stop cannot forbid the set (E0453, c1 of
  issuecomment-5931382112). toyos-userbound, -dma, -pci, -acpi,
  -transport, -blockring and -dns say so at their roots, -ps2 decodes a
  device's wire, and the network crates read the network; no step moves
  them. Step 3 takes 345 tests, step 4 drops acpi from toyos-boot and
  drops toyos-block, step 5 drops netd's library, and the network
  track's stage 4 no longer conflicts.

NOTEs: the ABI issue lists the SYS_DEBUG issue and the small-kernel
track; the boot-start exit asks a host test of the mark and the choice
and a metal row or, where none can, a guest test of the fatal boot, and
its false sentence on refused_claim and pci_function_is_exclusive goes;
step 3 checks declared_model_controls; step 1's grep excludes issues/;
the Fit line carries the layout rule from step 3; stage 4 waits on the
userland-lint issue, whose exit is a src/clippy.rs shape; compile-time
assertions and nested arithmetic are constraints; the mixer's timing is
re-measured.

REMOVEs: ", which is the only question worth asking" and ", so this
build system no longer has the flag" (four manifests).

Measured with cargo 1.98.1, clippy 0.1.98 (48a229ceae), on scratch
crates posted to the pull request:
- The review's patch to c6 (an #[expect] on a fn over v[i] and
  "+ x * x", one on a trait over two indexes): git apply --check 0,
  cargo build 0, cargo clippy -p c6 0 with no warning; reverted, clean.
- The copy of that c6, cargo clippy --message-format=json: 101, every
  one of 13 findings carries its attribute's reason: mod drivers 5, the
  inner #![expect] 2, the impl 2, the fn 2, the trait 2. The same under
  RUSTFLAGS="-D warnings". With #[warn] in place of #[deny] under
  -D warnings no finding carries its reason: two carry "`-D clippy::...`
  implied by `-D warnings`" and eleven nothing.
- --force-warn of the two lints on c6: 0, 13 warnings, those under each
  #[expect] included, no unfulfilled_lint_expectations.
- c15, every #[expect] over one site and one nested in another: clippy 0;
  its copy gives five reasons, one finding each.
- c18, an #[expect] inside cfg_attr over two indexes: clippy 0; the copy
  0 findings; --force-warn 2.
- c16: x * x + y * y - 1 and (a + b) * (c + d) are one
  arithmetic_side_effects finding each; v[i][j] is two indexing_slicing.
  cargo rustc --lib -- -C overflow-checks=on --emit=mir: 0, one overflow
  assert per operator, no source spans.
- c17 with c14's clippy.toml: disallowed_macros fires on
  const _: () = assert!(...), const { assert!(...) } and a run-time
  assert!; clippy::panic passes panic! in a const item and in an inline
  const block; cargo build 0.
  git grep -h -E 'const _: \(\) = assert!|const \{ assert!' -- kernel/src
  | wc -l: 41.
- CARGO_PROFILE_DEV_OPT_LEVEL=<n> cargo test -p toyos-mixer, scratch
  target, twice per level, exit 0 each; libtest's "finished in" for 55
  tests: 9.94 s and 9.99 s at 0, 1.00 s and 1.00 s at 2.
- cargo test -p <package> -- --list, lines ending ": test", exit 0
  each: pcid 6, proclife 34, sched with check 95, xhci 150, gicv3 8,
  cpuvuln 52 (345); bootmap 43, rootimage 21, blackbox 33, tco 13,
  quiesce 8 (118); elide 12, logstream 14; manifest 19, swap 7;
  fat32-check 67; desktop 95; inspect 21; symbols 9. Staying: dma 17,
  pci 75, ps2 24, userbound 34, acpi 52, transport 17, blockring 19,
  blockhold 9.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Scratch measurements behind the answers to issuecomment-5931861144 (cargo 1.98.1, clippy 0.1.98 48a229ceae, rustc 1.98.1; edition 2024; one scratch workspace; cargo clippy -p <crate> unless the command says otherwise). Posted so the evidence does not live only in a temporary directory. c6 and c14's clippy.toml are issuecomment-5931382112's.

The review's patch to c6

--- a/c6/src/lib.rs
+++ b/c6/src/lib.rs
@@ -17,3 +17,6 @@ impl S {
         self.0[j]
     }
 }
+
+#[expect(clippy::arithmetic_side_effects, clippy::indexing_slicing, reason = "fn")] pub fn f(v: &[u8], i: usize, x: u32) -> u32 { u32::from(v[i]) + x * x }
+#[expect(clippy::indexing_slicing, reason = "trait")] pub trait T { fn a(&self, v: &[u8]) -> u8 { v[0] } fn b(&self, v: &[u8]) -> u8 { v[1] } }
cargo clippy -p c6                     0   (unpatched, as before)
git apply --check                      0
git apply                              0
cargo build -p c6                      0
cargo clippy -p c6                     0   no warning: the old step refuses neither
git apply -R --check, git apply -R     0, 0; git status --porcelain: 0 lines
cargo clippy -p c6                     0   (restored)

The copy that tells one site from several

In a copy of the crate's sources, every #[expect( and #![expect( becomes #[deny( and #![deny(, and its reason = "…" becomes reason = "<file>:<line>" of that attribute. cargo clippy -p <crate> --message-format=json, and each clippy error is grouped by its note without a span, which is the reason of the attribute that set its level.

Patched c6, its copy (#[deny(clippy::arithmetic_side_effects, clippy::indexing_slicing, reason = "lib.rs:4")] and so on):

cargo clippy -p c6 --message-format=json                       101
  lib.rs:4  (mod drivers;)     5: index drivers.rs:2, :5, :8; arithmetic drivers.rs:11, :14
  inner.rs:1 (#![expect])      2: index inner.rs:4, :7
  lib.rs:10 (impl S)           2: index lib.rs:13, :16
  lib.rs:20 (fn f)             2: arithmetic lib.rs:20 (u32::from(v[i]) + x * x), index lib.rs:20 (v[i])
  lib.rs:21 (trait T)          2: index lib.rs:21, lib.rs:21
  findings with no reason:     0
RUSTFLAGS="-D warnings", same command                           101, the same grouping
#[warn( in place of #[deny(, RUSTFLAGS="-D warnings"           101, 13 errors: 2 carry "`-D clippy::…` implied by `-D warnings`", 11 carry nothing
cargo clippy -p c6 --message-format=json -- --force-warn clippy::indexing_slicing --force-warn clippy::arithmetic_side_effects
                                                                 0, 13 warnings (10 index, 3 arithmetic), those under each #[expect] included, no unfulfilled_lint_expectations

c15, every #[expect] over one site and one nested in another:

#![deny(clippy::indexing_slicing, clippy::arithmetic_side_effects)]
#![forbid(clippy::allow_attributes, clippy::allow_attributes_without_reason)]

pub fn f(v: &[u8], i: usize, x: u32) -> u32 {
    #[expect(clippy::indexing_slicing, reason = "i < v.len()")]
    let b = v[i];
    #[expect(clippy::arithmetic_side_effects, reason = "x < 2^16")]
    let y = x * x;
    #[expect(clippy::arithmetic_side_effects, reason = "y < 2^32 - 255")]
    let z = u32::from(b) + y;
    z
}

#[expect(clippy::indexing_slicing, reason = "the one index the inner expect leaves")]
pub fn g(v: &[u8; 4], i: usize) -> u8 {
    #[expect(clippy::indexing_slicing, reason = "i < 4")]
    let a = v[i];
    a ^ v[i]
}
cargo clippy -p c15                                  0
its copy, --message-format=json                    101: lib.rs:5, :7, :9, :14, :16 one finding each; none without a reason

c18, an #[expect] the copy's rewrite does not reach:

#![deny(clippy::indexing_slicing)]
#![forbid(clippy::allow_attributes, clippy::allow_attributes_without_reason)]

#[cfg_attr(all(), expect(clippy::indexing_slicing, reason = "two sites"))]
pub fn two(v: &[u8]) -> u8 {
    v[0] ^ v[1]
}
cargo clippy -p c18                                                       0
its copy, --message-format=json                                         0, no finding
--message-format=json -- --force-warn clippy::indexing_slicing         0, 2 findings

Nested arithmetic (c16)

#![deny(clippy::arithmetic_side_effects)]

pub fn one(x: u32, y: u32) -> u32 {
    x * x + y * y - 1
}
pub fn two(a: u32, b: u32, c: u32, d: u32) -> u32 {
    (a + b) * (c + d)
}
pub fn three(a: u32, b: u32) -> u32 {
    let t = a + b;
    t * 2
}
pub fn four(v: &[&[u8]], i: usize, j: usize) -> u8 {
    v[i][j]
}
cargo clippy -p c16 --message-format=json -- -D clippy::indexing_slicing      101
  arithmetic_side_effects 4:5-4:22 (the whole of one), 7:5-7:22 (the whole of two), 10:13-10:18, 11:5-11:10
  indexing_slicing 14:5-14:12 and 14:5-14:9
cargo rustc -p c16 --lib -- -C overflow-checks=on --emit=mir                    0
  one: MulWithOverflow, MulWithOverflow, AddWithOverflow, SubWithOverflow, each with its assert; two: three; no source spans

Compile-time assertions (c17), with c14's clippy.toml through CLIPPY_CONF_DIR

#![deny(clippy::disallowed_macros, clippy::panic)]

const _: () = assert!(core::mem::size_of::<u64>() == 8);

pub fn inline<const N: usize>() -> usize {
    const { assert!(N > 0) };
    N
}

pub fn runtime(x: u8) {
    assert!(x > 0);
}

const _: () = if core::mem::size_of::<u32>() != 4 {
    panic!("u32 is four bytes")
};

pub fn inline_panic<const N: usize>() -> usize {
    const {
        if N == 0 {
            panic!("N is not zero")
        }
    };
    N
}

pub fn use_both() -> usize {
    inline::<1>() + inline_panic::<1>()
}
CLIPPY_CONF_DIR=<conf> cargo clippy -p c17          101: disallowed_macros at 3:15, 6:13, 11:5; nothing at either panic!
cargo build -p c17                                    0
git grep -h -E 'const _: \(\) = assert!|const \{ assert!' -- kernel/src | wc -l      41

The mixer's tests

CARGO_TARGET_DIR=<scratch> CARGO_PROFILE_DEV_OPT_LEVEL=<n> cargo test -p toyos-mixer in the worktree, twice per level, EXIT=0 each. libtest's own line for the 55 tests: "finished in 9.94s" and "9.99s" at 0, "1.00s" and "1.00s" at 2.

Test counts

cargo test -p <package> -- --list, lines ending in : test, EXIT=0 for each, at af9fe18's tree: pcid 6, proclife 34, sched with --features check 95, xhci 150, gicv3 8, cpuvuln 52; bootmap 43, rootimage 21, blackbox 33, tco 13, quiesce 8; elide 12, logstream 14; manifest 19, swap 7; fat32-check 67; desktop 95; inspect 21; symbols 9. The crates that stay: dma 17, pci 75, ps2 24, userbound 34, acpi 52, transport 17, blockring 19, blockhold 9.

@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Round-2 review of 77a8f1208 (wt/toyos-prosebatch) against .claude/agents/reviewer.md. It covers the four BLOCKERs of issuecomment-5931861144, round 2's own diff (77a8f1208^1..77a8f1208), and contradictions with main, #674 and #669.

CI: host passes at 77a8f1208 (run 36869489634, conclusion success, 13m12s, "[ci] Host: 56 step(s), all green"; gh pr checks 673 exit 0). No test added, no hardware targeted.
Net (git diff --shortstat origin/main...HEAD): 24 files, +414 −489.

  • Production +13 −28: comments, and one src/licence.rs string.
  • Tests 0, issues/ +383 −447, prompts +18 −14.
  • Round 2 alone: 11 files, +81 −68.

The merge af9fe18 resolves nothing by hand: git show --cc has no hunk. origin/main moved to a97ff80 (#672) during this review, and git merge-tree merges this head into it with no conflict.

Earlier BLOCKERs

  • Firmware — CLOSED. CLAUDE.md:63 gives device firmware and CPU microcode a loading clause each. wc -c CLAUDE.md is 16076, against main's 16077.

  • Kill — CLOSED. CLAUDE.md:77 waits out a build that holds the global lock, as src/CLAUDE.md:24 orders.

  • An #[expect] over many findings — CLOSED for the kernel, by issues/kernel/a-panic-is-never-an-accident.md:78-87. issuecomment-5932520362 measures the copy:

    • patched c6 exits 101, with 5/2/2/2/2 findings per reason and none without a reason;
    • c15 has one finding per reason;
    • c18's cfg_attr gives 0 findings against --force-warn's 2.

    Nested arithmetic is recorded at :43-45. The services keep the hole (first BLOCKER).

  • Conflicting tracks — OPEN. Every crate round 1 named now stays, but step 3 still moves toyos-xhci and step 4 still merges toyos-blackbox (second BLOCKER).

  • Round 1's NOTEs and REMOVEs are applied:

    • The ABI issue's :30-31 names both plans, and both plan by retirement (sys-debug-…:31, the small-kernel track's :97).
    • The boot-start issue's exit is at :18-21. refused_claim is at tests/common/iommu.rs:304, and no file has pci_function_is_exclusive.
    • In the crate track: pcid's second exit clause is in step 3's check (:48-50), the userpin grep excludes issues/ (:32), and the Fit line is at :11-13,44.
    • The userland lint has one plan, and src/clippy.rs:3-5 holds that --clippy and --ci host run one list.
    • The compile-time assertions are at the panic track's :46-49 (c17), and the mixer's timing at the crate track's :63-64.
    • No round-1 REMOVE phrase is left: git grep exits 1, and the body grep finds 0 of each.

BLOCKER

  • issues/kernel/a-panic-is-never-an-accident.md:88-90 — the services' exit passes while their rule fails.
    • Tier 3 is "The same rule as the kernel" (:13). Yet a service's exit is only "its crate root under stage 3's attributes".
    • Those attributes pass an inner #![allow(…, reason)] (c4, exit 0) and an #[expect] on a fn over two findings (patched c6, exit 0).
    • Stage 3 refuses both with a --ci host step, not an attribute. This is the hole round 1 sent back for the kernel.
    • Fix: the exit is the crate root under stage 3's attributes and its step.
  • issues/build/code-used-by-one-program-lives-in-that-program.md:18,37,53-54 — "no step here moves one" is false for two crates that steps 3 and 4 still move.
    • toyos-xhci decodes a USB device's bytes. identity.rs:82-96 slices and copies a string descriptor "as it arrived", and kernel/src/drivers/xhci/wait/msc.rs:1604 calls it with device bytes. scsi.rs:5-6 reads "Everything a device answers is checked and never believed". That is the class :20 keeps -ps2 for.
    • Main's small-kernel track also moves "the whole xHCI" to usbd (issues/kernel/the-kernel-is-small-interrupts-post-and-threads-wait.md:127). That move takes xHCI back out of kernel/pure/.
    • toyos-blackbox's root reads "Nothing here believes it" (lib.rs:15), and its recover takes its length from the page (:705). Step 4 merges it into a five-subject toyos-boot, against :15's "a crate of its own".
    • :17-18's "That track says which crates are boundaries" is false: the no-panic track names no crate.
    • Fix: drop -xhci from step 3 (345 → 195 tests) and -blackbox from step 4 (118 → 85). Or make steps 3 and 4 wait until the no-panic track's stage 1 names its tier-1 crates, and say so.

NOTE

REMOVE

  • PR body — "toyos-xhci still moves, since its root names no untrusted input": its scsi.rs:5-6 says otherwise, and this line becomes main's record.

SEND BACK

…k merges no crate that reads what a device, a previous boot or a program wrote

The no-panic track's stage 4 gave a service only stage 3's attributes.
Those attributes pass an inner `#![allow(…, reason)]` and an `#[expect]`
on a `fn` over two findings. Stage 3 refuses both with its `--ci host`
step, so a service's exit now names that step as well:

- c4 is an inner `#![allow]` under stage 3's attributes. `cargo clippy`
  exits 0. Its copy reports 0 findings and `--force-warn` reports 2
  (lib.rs:7, :10), so the step's count refuses it.
- Patched c6's copy puts two findings under the one reason of the `fn`'s
  `#[expect]` (issuecomment-5932520362).

The crate track said the no-panic track names the boundary crates. It names
none, so that clause goes. The track now says no step merges an input
boundary into a program or another crate, and lists the ones it keeps.

- `toyos-xhci` leaves step 3, because it decodes a USB device's answers
  (`scsi.rs:5-6`, `identity.rs:82-85`).
- `toyos-blackbox` leaves step 4, because it decodes a previous boot's page
  (`lib.rs:15`, and `recover` takes its length from the page at `:705`).
- The same test is a crate's own source saying it does not believe what it
  reads. It finds four more crates that steps 4 and 5 merged:
  - `toyos-swap`: `Request::decode` refuses "the requester's claim"
    (`lib.rs:241-244`);
  - `toyos-logstream`: whose line a line is is decided "never by its
    words", and "no program's bytes" reach a line's head (`lib.rs:6-11`);
  - `toyos-mixer`: a client's gain "crossed the trust boundary"
    (`gain.rs:8`);
  - `toyos-desktop`: a client's rectangle crosses "a trust boundary", and
    every verdict on a window request "is an answer to untrusted input, so
    none of them is a panic" (`rect.rs:34`, `budget.rs:52-53`).
- So step 4 makes no `toyos-log`, and `toyos-manifest` takes nothing in.
  Step 5 moves neither the mixer nor the desktop. The opt-level line goes
  with them, since only the mixer's tests needed it.
- `toyos-xhci/sim` stays with xhci, so `kernel/sim` is `toyos-sched/sim`
  alone.

Each count is from `cargo test -p <package> -- --list` at 77a8f12, which
exits 0 for every package:
- step 3: pcid 6, proclife 34, sched with `check` 95, gicv3 8 and cpuvuln
  52 make 195;
- step 4: bootmap 43, rootimage 21, tco 13 and quiesce 8 make 85, and
  fat32-check lists 67;
- step 5: inspect 21;
- the models: toyos-sched-sim 53 and toyos-xhci-sim 46, kernel-loom 53 and
  toyos-sched-loom 26, so 79.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Scratch measurements behind the answers to issuecomment-5932882581 (cargo 1.98.1, clippy 0.1.98 48a229ceae, rustc 1.98.1; edition 2024). Posted so the evidence does not live only in a temporary directory.

c4 through stage 3's step

Cargo.toml: package c4, edition 2024, an empty [workspace]. src/lib.rs is issuecomment-5931382112's c4:

#![deny(clippy::indexing_slicing)]
#![forbid(clippy::allow_attributes, clippy::allow_attributes_without_reason)]

pub mod m {
    #![allow(clippy::indexing_slicing, reason = "inner")]
    pub fn first(v: &[u8]) -> u8 {
        v[0]
    }
    pub fn second(v: &[u8]) -> u8 {
        v[1]
    }
}

c4 holds no #[expect], so the step's copy is the crate as written.

cargo clippy                                                                  0   no finding
cargo clippy --message-format=json                                            0   0 clippy::indexing_slicing findings: the copy
cargo clippy --message-format=json -- --force-warn clippy::indexing_slicing   0   2 findings, lib.rs:7 and lib.rs:10

The copy's 0 findings against --force-warn's 2 is the shortfall stage 3's step refuses.

Test counts

cargo test -p <package> -- --list in the worktree at 77a8f12, with --features check for toyos-sched. The count is the lines ending in : test, and every command exits 0.

toyos-pcid          6     toyos-bootmap       43    toyos-mixer         55
toyos-proclife     34     toyos-rootimage     21    toyos-desktop       95
toyos-sched        95     toyos-blackbox      33    toyos-inspect       21
toyos-gicv3         8     toyos-tco           13    toyos-sched-sim     53
toyos-cpuvuln      52     toyos-quiesce        8    toyos-xhci-sim      46
toyos-symbols       9     toyos-elide         12    kernel-loom         53
toyos-xhci        150     toyos-logstream     14    toyos-sched-loom    26
toyos-manifest     19     toyos-swap           7    toyos-fat32-check   67

Step 3's library is 6 + 34 + 95 + 8 + 52 = 195, and kernel/sim is toyos-sched-sim's 53. kernel/loom is 53 + 26 = 79. Step 4's toyos-boot is 43 + 21 + 13 + 8 = 85.

#674

git merge-tree --write-tree --name-only 75bf09675 16ba29562 exits 1, with conflicts in .claude/agents/implementer.md and .claude/agents/reviewer.md and nowhere else.

@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Round-3 review of 75bf09675 (wt/toyos-prosebatch) against .claude/agents/reviewer.md. It covers the BLOCKERs, NOTEs and REMOVE of issuecomment-5932882581, round 3's own diff (77a8f1208..75bf09675, no merge), the four crates round 3 keeps, and #674.

CI: host passes at 75bf09675 (run 36875696028, conclusion success, 9m14s, "[ci] Host: 56 step(s), all green"; gh pr checks 673 exit 0). No test added, no hardware targeted.
Net (git diff --shortstat origin/main...HEAD): 24 files, +412 −489.

  • Production +13 −28: comments, and one src/licence.rs string.
  • Tests 0, issues/ +381 −447, prompts +18 −14.
  • Round 3 alone: 2 files, +23 −25.

Earlier BLOCKERs

  • The services' exit — CLOSED for the two holes it named. issues/kernel/a-panic-is-never-an-accident.md:88-90 puts a service's crate in stage 3's step.
    • In issuecomment-5933412069, c4's copy reports 0 findings and --force-warn reports 2, so the step refuses it.
    • In issuecomment-5932520362, patched c6 puts the fn's two findings under one reason.
    • The exit still stops at the service's own crate (second BLOCKER).
  • Conflicting tracks — CLOSED for -xhci and -blackbox.
    • Steps 3 and 4 no longer name either. toyos-xhci/sim is the workspace member that path names.
    • 195, 79, 53, 85 and 67 add up from issuecomment-5933412069's --list counts.
    • The clause saying the panic track names the boundary crates is gone. The sentence that BLOCKER tested is still false for two other crates (first BLOCKER).

Earlier NOTEs and REMOVE

The four keeps

Each reads a program's words, by its own source:

  • toyos-swap/src/lib.rs:241-262: init decodes the swap program's request, and :248-249 hold a split_at and an expect from the set.
  • toyos-logstream/src/lib.rs:175-198,223-243: logd writes every program's bytes through Text, which escapes them.
  • toyos-mixer/src/format.rs:18-23, gain.rs:21-29: soundd decodes a client's period and refuses a client's NaN gain.
  • toyos-desktop/src/budget.rs:50-74, input.rs:146: the compositor answers a client's window size and folds event bytes.

Dropping toyos-log and toyos-manifest's intake is forced. toyos-elide/src/limit.rs:44 holds an assert! and toyos-manifest/src/lib.rs:366-397 holds panic!s, and neither can be kept in a crate that forbids the set. Where the mixer and the desktop live is a NOTE.

BLOCKER

  • issues/build/code-used-by-one-program-lives-in-that-program.md:17-18,55-57 — "No step here merges one into a program or another crate" is false: step 4 merges -tco and -bootmap into toyos-boot.
    • -tco decodes a PCI function's config words. Chipset::port (toyos-tco/src/lib.rs:275-289) refuses all-ones by name. It takes two words read from the PCH (kernel/src/arch/x86_64/watchdog.rs:51-58, bootloader/src/watchdog.rs:141-148), and toyos-pci/src/lib.rs:4-8 calls such words untrusted.
    • -tco panics on one such word. In the a0a3 row (base_mask: !1, :249-258), a base word of 0xFFFF_FFFE passes the all-ones check. :284's base + 0x13 then overflows u32. The kernel's and the loader's [profile.toyos] both set overflow-checks, so both panic.
    • -bootmap's refusals answer firmware's memory map and framebuffer (toyos-bootmap/src/lib.rs:148-168, x86_64.rs:17-25). toyos-acpi/src/lib.rs:3 calls firmware-supplied input untrusted.
    • -bootmap also holds two expects (lib.rs:464,472). The merged crate then holds a tier-2 stop and cannot forbid the set: the hazard :15-17 names.
    • Round 3 tested a root's wording. The track's own list keeps -ps2 and -xhci for what they decode, and the commit title says it "merges no crate that reads what a device … wrote".
    • Fix: drop -tco and -bootmap from step 4, which leaves -rootimage (21 tests) and -quiesce (8). Or take round 2's other fix: steps 3 and 4 wait until the no-panic track's stage 1 names its tier-1 crates, and the track says so. Either way, the same test decides -gicv3, whose walk reads the GICR_TYPER words the kernel read (toyos-gicv3/src/lib.rs:44-61).
  • issues/kernel/a-panic-is-never-an-accident.md:88-90 — the services' exit holds a service's own crate and no crate it links. Stage 3 (:74-76) holds every crate of this tree that the kernel links, and tier 3 is "The same rule as the kernel" (:13).
    • Between them, init, logd, the compositor, soundd and netd link toyos, toyos-inspect, toyos-manifest, toyos-update, toyos-window, toyos-font and sprite. kernel/Cargo.toml links none of them, so no stage holds them.
    • Among them is toyos/src/ipc.rs:466's FrameRx, which every server reads a client's frames through (userland/CLAUDE.md:5).
    • Fix: the exit also holds every crate of this tree a service links, unless stage 1 or 3 already does, as stage 3 does for the kernel.

NOTE

  • issues/build/code-used-by-one-program-lives-in-that-program.md:21-22 — -mixer serves soundd alone and -desktop the compositor alone, as -ps2 and -xhci serve the kernel alone. The panic track needs each to be a crate of its own, and nothing more.
    • Step 5 makes filepicker-api and toyos-inspect their programs' libraries, which the body counts as crates of their own. Step 3 puts kernel/loom/ and kernel/sim/ under the kernel.
    • Either move would keep the owner's rule for these crates. "Stay where they are" drops it, and the panic track gives no reason to.
  • toyos-tco/src/lib.rs:284 — the overflow above is on main: a device's answer panics the kernel and the loader. Fixing it is not this branch's job; it needs an issue.

REMOVE

  • PR body — "Every crate that steps 3 to 5 merge was put to it" and the line ending "but none of them calls its source untrusted": -tco reads a device's config words and -bootmap reads firmware's map, so on main both lines would be false.

SEND BACK

… tier is every crate of this tree it links, and a TCO base word that panics is filed

The third review found step 4 merging `toyos-tco`, which decodes a PCH's
configuration words, and `toyos-bootmap`, which reads firmware's memory map,
into `toyos-boot`. Round 3 had judged a crate by its wording. This round puts
every crate a step moved, merged or deleted to one question about its own
source: does it decode or refuse input from outside its trust? Hardware
registers, firmware tables, disk bytes, network bytes and what another program
sent, a syscall's arguments included, all count. The track now states that
test and moves no crate that meets it.

- Eleven crates meet it and leave every step:
  - step 3: `toyos-proclife` refuses a tid the joining program named
    (`join.rs:11-13`, `:43`); `toyos-gicv3` walks `GICR_TYPER` words
    (`lib.rs:44-61`); `toyos-cpuvuln` decodes CPUID and MSR words
    (`lib.rs:48-49`, `:61-83`); `toyos-symbols` bounds every extent an ELF
    file declares (`lib.rs:71-77`, `:92-102`);
  - step 4: `toyos-bootmap` refuses ranges of firmware's map
    (`x86_64.rs:17-25`, `lib.rs:165-167`); `toyos-rootimage` checks the
    loader's extent against firmware's map and takes the media's granularity
    (`handoff.rs:14-34`, `chunk.rs:33-35`); `toyos-tco` decodes a PCI
    function's ids and configuration words (`lib.rs:261-289`);
    `toyos-quiesce` parses a log line off a stick (`lib.rs:14-16`,
    `:126-129`); `toyos-fat32-check` judges a volume's bytes
    (`lib.rs:181-187`);
  - step 5: `filepicker-api` refuses the picker's reply by type and by UTF-8
    (`lib.rs:75-84`); `toyos-inspect` decodes another owner's snapshot
    (`wire.rs:13-15`).
- Seven do not: `toyos-userpin`, `toyos-pcid`, `toyos-sched`, `kernel-loom`,
  `toyos-sched-loom`, `toyos-sched-sim` and `toyos-libc-copies`. The
  simulator's `replay` decodes a trace, but only one it wrote itself.
- So the kernel's library is `toyos-pcid` and `toyos-sched`: at least 101
  tests, 6 and 95 with `check`. Step 4 goes whole. Step 5 keeps
  `toyos-libc-copies` alone, and its check names no count: the package lists
  14 tests on this AArch64 host, one of them in a module only AArch64 builds.
- Step 2, "Lint userland first", goes. No step moves code into a userland
  program now, and the userland lint reads `userland/` alone. Each remaining
  move's check says `--clippy` lints what it moved.
- The sentence reconciling the supervisor track before step 5 goes with
  step 5.

The no-panic track's stage 4 held a service's own crate and nothing it
links. Tiers 2 to 4 are now processes: a tier holds every crate of this tree
its processes link, and a crate in two tiers is held to the stricter. The
system services are init and every program `system.toml` starts at boot or
marks `service = true`. Stage 4 ends when every crate of this tree a service
links, `toyos` included, is linted under stage 3's attributes and passes
stage 3's step. The step finds them from `system.toml` and `cargo metadata`
over userland's workspace: it walks the normal edges as `src/licence.rs`
does, and keeps the packages whose manifests lie in this repository.

Measured at 75bf096, the nine services' closures name 38 packages of this
tree, and `kernel/Cargo.toml` links none of 27 of them, `toyos` among them.
`--filter-platform x86_64-unknown-toyos` gives the same sets.

The review's NOTE on `toyos-tco/src/lib.rs:284` is filed as a defect. Under
`8086:a0a3`, the 17 base words from `0xFFFF_FFEE` to `0xFFFF_FFFE` overflow
`u32` there, as a host program calling `port` with every `u32` word shows.
q35's row has no such word.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Evidence for the answers to issuecomment-5933706988. Measured at 75bf09675; e3013a33e changes only three issue files. Host: aarch64-apple-darwin.

The services' closure

cargo +stable metadata --format-version 1 --locked --offline --manifest-path userland/Cargo.toml > userland-meta.json   # EXIT=0
cargo +toyos metadata --format-version 1 --locked --offline --filter-platform x86_64-unknown-toyos --manifest-path userland/Cargo.toml > userland-meta-toyos.json   # EXIT=0
cargo +stable metadata --format-version 1 --locked --offline --manifest-path kernel/Cargo.toml > kernel-meta.json   # EXIT=0
jq --arg root "$PWD" --argjson names '["init","logd","blockd","fsd","compositor","soundd","netd","filepicker","sshd"]' -f closure.jq userland-meta.json > closure.json   # EXIT=0
jq --arg root "$PWD" --argjson names '["init","logd","blockd","fsd","compositor","soundd","netd","filepicker","sshd"]' -f closure.jq userland-meta-toyos.json > closure-toyos.json   # EXIT=0
jq --arg root "$PWD" --argjson names '["kernel"]' -f closure.jq kernel-meta.json > kclosure.json   # EXIT=0

closure.jq walks the normal edges (dep_kinds[].kind == null) from each root and keeps a package whose source is null and whose manifest lies under the repository:

(.packages | map({key: .id, value: .}) | from_entries) as $pkg
| (.resolve.nodes | map({key: .id, value: [.deps[] | select(any(.dep_kinds[]; .kind == null)) | .pkg]}) | from_entries) as $edges
| def intree($id): ($pkg[$id].source == null) and ($pkg[$id].manifest_path | startswith($root + "/"));
  def reach($start):
    {seen: [$start], todo: [$start]}
    | until(.todo | length == 0;
        .todo[0] as $cur
        | .todo |= .[1:]
        | reduce ($edges[$cur] // [])[] as $n (.;
            if (.seen | index($n)) then . else .seen += [$n] | .todo += [$n] end))
    | .seen;
  [ $names[] as $name
    | ($pkg | to_entries | map(select(.value.name == $name and intree(.key))) | .[0].key) as $id
    | { root: $name,
        intree: [reach($id)[] | select(intree(.)) | $pkg[.] | {name, kinds: [.targets[].kind[]] | unique, path: (.manifest_path | ltrimstr($root + "/"))}] | sort_by(.name),
        thirdparty: [reach($id)[] | select(intree(.) | not)] | length } ]

Each service's in-tree closure, every cfg:

init: init, toyos, toyos-abi, toyos-blockhold, toyos-blockring, toyos-gpt, toyos-logstream, toyos-manifest, toyos-quiesce, toyos-swap, toyos-transport, toyos-untrusted, toyos-update
logd: logd, toyos, toyos-abi, toyos-elide, toyos-inspect, toyos-logstream, toyos-wallclock
blockd: blockd, toyos, toyos-abi, toyos-blockhold, toyos-blockring, toyos-gpt, toyos-transport, toyos-untrusted
fsd: bcachefs, blockd, fsd, toyos, toyos-abi, toyos-blockhold, toyos-blockring, toyos-fat32, toyos-gpt, toyos-transport, toyos-untrusted, toyos-wallclock
compositor: compositor, sprite, toyos, toyos-abi, toyos-desktop, toyos-font, toyos-inspect, toyos-keymap, toyos-manifest, toyos-window
soundd: soundd, toyos, toyos-abi, toyos-hda, toyos-inspect, toyos-mixer
netd: netd, toyos, toyos-abi, toyos-dns, toyos-i219, toyos-inspect, toyos-mdns, toyos-tco
filepicker: filepicker, filepicker-api, toyos, toyos-abi, toyos-font, toyos-keymap, toyos-window
sshd: sshd, toyos, toyos-abi

The kernel's, for comparison:

kernel: bcachefs, kernel, toyos-abi, toyos-acpi, toyos-blackbox, toyos-blockhold, toyos-bootmap, toyos-dma, toyos-elf, toyos-elide, toyos-fat32, toyos-gicv3, toyos-gpt, toyos-hda, toyos-pci, toyos-pcid, toyos-proclife, toyos-ps2, toyos-quiesce, toyos-rootimage, toyos-sched, toyos-symbols, toyos-tco, toyos-untrusted, toyos-userbound, toyos-wallclock, toyos-xhci
  • The services' union is 38 packages (jq '[.[] | .intree[].name] | unique | length').
  • comm -23 of that union against the kernel's names 27 packages the kernel does not link: blockd, compositor, filepicker, filepicker-api, fsd, init, logd, netd, soundd, sprite, sshd, toyos, toyos-blockring, toyos-desktop, toyos-dns, toyos-font, toyos-i219, toyos-inspect, toyos-keymap, toyos-logstream, toyos-manifest, toyos-mdns, toyos-mixer, toyos-swap, toyos-transport, toyos-update, toyos-window.
  • Every in-tree target kind is lib, bin or test: no proc-macro.
  • diff <(jq -c '[.[] | {root, intree: [.intree[].name]}]' closure.json) <(jq -c '[.[] | {root, intree: [.intree[].name]}]' closure-toyos.json) exits 0. The platform filter changes only the third-party counts, for example sshd's from 222 to 163.

toyos-tco/src/lib.rs:284

Cargo.toml of a scratch crate outside the tree:

[package]
name = "tcoover"
version = "0.1.0"
edition = "2021"

[dependencies]
toyos-tco = { path = "/Users/jan/Dev/jan/toyos-prosebatch/toyos-tco" }

[profile.dev]
overflow-checks = true

[workspace]

First src/main.rs:

fn main() {
    let row = toyos_tco::chipset(0x8086, 0xa0a3).expect("Tiger Lake-LP's row");
    // The enable bit set, so `port` reaches the base arithmetic.
    let enable = u32::from(1u16 << 8);
    for base in [0x0000_0401u32, 0xFFFF_FFFFu32, 0xFFFF_FFFEu32] {
        println!("base {base:#010x}: asking");
        println!("base {base:#010x}: {:?}", row.port(base, enable));
    }
}

cargo +stable run exits 101:

base 0x00000401: asking
base 0x00000401: Ok(1024)
base 0xffffffff: asking
base 0xffffffff: Err(Absent)
base 0xfffffffe: asking

thread 'main' (68104072) panicked at /Users/jan/Dev/jan/toyos-prosebatch/toyos-tco/src/lib.rs:284:19:
attempt to add with overflow

Second src/main.rs, every base word against each row:

fn main() {
    std::panic::set_hook(Box::new(|_| {}));
    for row in toyos_tco::CHIPSETS {
        let mut panicked = Vec::new();
        // Every enable word with the row's bit set, against every base word.
        let enable = row.enable.bit;
        let mut base: u32 = 0;
        loop {
            if std::panic::catch_unwind(|| row.port(base, enable)).is_err() {
                panicked.push(base);
            }
            if base == u32::MAX {
                break;
            }
            base += 1;
        }
        println!(
            "{:04x}:{:04x}: {} base word(s) panic, first {:#010x?}, last {:#010x?}",
            row.vendor,
            row.device,
            panicked.len(),
            panicked.first(),
            panicked.last()
        );
    }
}

cargo +stable run --release --config 'profile.release.overflow-checks=true' exits 0:

8086:2918: 0 base word(s) panic, first None, last None
8086:a0a3: 17 base word(s) panic, first Some(
    0xffffffee,
), last Some(
    0xfffffffe,
)

Test counts

cargo test -p <package> -- --list, each exiting 0:

package tests
toyos-pcid 6
toyos-sched --features check 95
kernel-loom 53
toyos-sched-loom 26
toyos-sched-sim 53
toyos-libc-copies 14, long_double::strtold_widens_as_compiler_builtins_does among them, whose module is #[cfg(all(test, target_arch = "aarch64"))]

@Japabu Japabu changed the title Rules and records: the ABI and kernel rulings, the no-panic track, the owner's 2026-09-30 rulings, CPU microcode, the crate track, the LLVM-bytes defect Rules and records: the ABI and kernel rulings, the no-panic track, the owner's 2026-09-30 rulings, CPU microcode, the crate track, the LLVM-bytes and TCO-overflow defects Oct 1, 2026
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Round-4 review of e3013a33e (wt/toyos-prosebatch) against .claude/agents/reviewer.md. It covers:

  • round 3's BLOCKERs, NOTEs and REMOVE (issuecomment-5933706988), judged against git diff 75bf09675..e3013a33e;
  • the 18 verdicts;
  • the mixer/desktop decline;
  • the toyos-proclife call.

CI: host passes at e3013a33e: run 36881180069, conclusion success, 13m6s, "[ci] Host: 56 step(s), all green". gh pr checks 673 exits 0. No test is added and no hardware is targeted.

Net lines (git diff --shortstat origin/main...HEAD): 25 files, +436 −489.

  • Production: +13 −28, which is comments and one src/licence.rs string.
  • Tests: 0.
  • issues/: +405 −447.
  • Prompts: +18 −14.
  • Round 4 alone: 3 issue files, +62 −38.

Earlier BLOCKERs

  • -tco and -bootmap merged: CLOSED.
    • Step 4 is deleted whole.
    • -gicv3, -cpuvuln, -proclife and toyos-symbols leave the kernel's library.
    • What steps 1-3 still touch decodes no device's, firmware's, disk's or other program's word, by its source. The one exception is the provenance call on toyos-sched-sim below.
  • The services' exit: CLOSED.
    • issues/kernel/a-panic-is-never-an-accident.md:16-20,94-104 hold every crate of this tree that a service links, toyos included.
    • The closures in issuecomment-5934162027 recount to 38 packages: 11 the kernel links and 27 it does not. They come from jq over cargo metadata --locked --offline, and every command exits 0.
    • The nine services match root system.toml's [boot] start (:24) and its service = true rows (:53, :58, :64, :74, :81, :110, :183).

Earlier NOTEs and REMOVE

The 18 verdicts

I read 14 against their source:

  • -pcid, -sched, -proclife, -gicv3, -cpuvuln, -symbols, -tco;
  • -bootmap, -quiesce, -inspect, filepicker-api;
  • kernel-loom, toyos-sched-sim, toyos-libc-copies.

By the test the track states, 17 of the 18 stand. The details:

  • toyos-sched, none. Nothing in src/ decodes bytes, deadlines are only compared, and Nanos saturates (hw.rs:28-37). Watch::post_n takes a FUTEX_WAKE count straight from futex_wake (kernel/src/scheduler.rs:526-527) and only compares it (watch.rs:234-256).
  • toyos-pcid, none. Pcid's field is private, and only alloc builds one (lib.rs:28, :81-95).
  • toyos-symbols. locate also bounds a process ELF's extents (lib.rs:92-102). kernel/src/symbols.rs:17 owns process pages.
  • toyos-gicv3. find_redistributor steps by what the GICR_TYPER words it read say (lib.rs:48-60).
  • toyos-sched-sim, none. This holds only by provenance.
    • replay reads any path its command line names (main.rs:257-263), and shrink::decode parses it under expect and assert! (shrink.rs:106-123).
    • By the stated test, that is disk bytes, as for -fat32-check.
    • It is harmless: the step moves the crate as a crate of its own.
  • toyos-proclife. Right by the stated test, wrong by its purpose (next section).

toyos-proclife

Move it with the scheduler.

  • The refusal is a lookup. It is ok_or on a lookup (join.rs:42-43), over a trait the kernel answers with self.threads.get(tid) (kernel/src/process.rs:382-383). The crate never decodes the tid, indexes by it or does arithmetic on it.
  • toyos-sched does the same thing. It takes a syscall's FUTEX_WAKE count the same way, and the sweep calls it none. One reading has to decide both crates.
  • It holds tier-2 stops. There are six deliberate stops on the kernel's own invariants (teardown.rs:75, :76-80, :85, :112, :114-118, :144). By the track's own premise (:17), a tier-1 proclife would have to drop stops that a kernel bug should crash on.
  • Only the kernel links it: kernel/Cargo.toml:372.

The mixer/desktop decline

The decline is not right.

  • The reason it gives is the new sentence itself.
  • The paragraph's own reason (:15-17: tier 1 is forbidden per crate) constrains merges. It says nothing about where a crate's directory sits.
  • Step 2 itself puts crates of their own under kernel/: kernel/loom/ and kernel/sim/.
  • Each of these crates has one consumer:
    • -mixer: only userland/soundd/Cargo.toml:10 links it;
    • -desktop: only userland/compositor/Cargo.toml:11;
    • -ps2 (kernel/Cargo.toml:373), -gicv3 (:366) and -xhci (:381, beside its own sim): only the kernel.
  • Each could sit under its one consumer as a crate of its own and keep both rules.
  • Nothing moved is wrong, so this is a NOTE.

BLOCKER

None.

NOTE

  • issues/build/code-used-by-one-program-lives-in-that-program.md:20-21: "moves or merges" goes further than the reason at :15-17, which stops merges only.
    • "Moves" keeps -mixer, -desktop, -ps2, -xhci and -gicv3 out of the layout the owner ruled. It also keeps toyos-fat32-check out, though that step was only a directory move to toyos-fat32/check/.
    • toyos-sched-sim's step survives it only through the provenance call above.
    • Fix: drop "moves", and give each single-consumer crate a step that puts it under its consumer as a crate of its own.
  • issues/build/code-used-by-one-program-lives-in-that-program.md:18-20,30: "refuses" catches a lookup of a key a program named, toyos-proclife above.
    • Read as "decodes a word, or bounds it by its form", the test leaves the other 17 verdicts unchanged.
    • With that reading, -proclife joins step 2.
  • issues/kernel/a-panic-is-never-an-accident.md:18-19,99: "system.toml" names one of the three shipped modes' configs (src/build.rs:1094).
    • console/system.toml:19 starts console at boot, and diag/system.toml:29 starts toybox. The nine services omit both.
    • src/build.rs:2230-2231 keeps a test because "a reader that drops a mode or init loses one".
    • Fix: the step reads the modes as build::shipped does, and the definition says which boot-started programs count.
  • issues/kernel/a-panic-is-never-an-accident.md:9-20: the loader is not a process, and no stage reaches bootloader/src.
    • It reads firmware's memory map and the MCFG, and decodes PCI config words (bootloader/src/watchdog.rs:60-80, :136-152).
    • The defect this round files is a loader panic.
    • Stages 3 and 4 reach only the crates the loader shares with the kernel or a service.
  • issues/kernel/a-panic-is-never-an-accident.md: the track is 104 lines, and round 4 added 16 of them. issues/README.md:82-88 says a track "that has grown past a screen is a plan again, and is cut back".

REMOVE

  • issues/kernel/a-panic-is-never-an-accident.md:19-20: ", so tier 3 holds toyos and every crate of this tree one of them links". It restates :16-17, and :96 names toyos again.
  • issues/kernel/a-panic-is-never-an-accident.md:103-104: "A registry or git package is third-party and is held by CLAUDE.md's "Dependencies", not by this track." :102-103 already keep only the packages in this repository, and "Dependencies" holds no panic rule.

LAND

Japabu and others added 2 commits October 1, 2026 17:44
Two hunks conflict, and each keeps both sides' changes.

- `implementer.md`: this branch drops the ABI-brief sentence, and #674's
  dependency sentence replaces "No new dependency.".
- `reviewer.md`'s Fit line: this branch's two BLOCKER clauses stay, and
  #674's dependency clause replaces "No new dependency or fetch.".

The rest of #674 merged clean. `git diff origin/main -- .claude
userland/CLAUDE.md` shows only this branch's own changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…-panic track, cut to a screen; proclife moves with the scheduler, and five single-consumer crates go under their consumer

The no-panic track, `issues/kernel/a-panic-is-never-an-accident.md`, goes
from 104 lines to 54.

- The loader is tier 2. It is not a process, yet
  `bootloader/src/watchdog.rs` decodes PCI configuration words and checks
  the MCFG's word against firmware's memory map. Tiers 2 to 4 are now
  programs. Stage 1 moves an input boundary out of the loader as well, and
  stage 3 ends with `bootloader/src/main.rs` and every crate of this tree
  its manifest links. The loader's `--clippy` shapes exist for both
  architectures.
- The services are read from the three modes' configs, as `build::shipped`
  reads them, and every boot start counts. That adds `console`, which the
  console mode starts and which owns the framebuffer as the compositor
  does, and `toybox`, which the diag mode starts with nobody asking.
- Both REMOVEs are applied: the clause restating that tier 3 holds `toyos`,
  and the sentence on registry and git packages.
- Cut to a screen. These go: "Today" and its counts, the rationale clauses,
  the constraints, the stage-3 step's copy mechanism and stage 4's metadata
  walk. The tiers, the set, what the set does not see, and every stage's
  exit stay. `git log -p` of the file keeps what went.

The crate track, `issues/build/code-used-by-one-program-lives-in-that-program.md`:

- The boundary test now reads "decodes a word from outside its trust, or
  bounds it by its form", and a lookup of a key a program named is neither.
  `toyos-proclife`'s only refusal is `ok_or` on `threads.get(tid)`
  (`join.rs:42-43`, `kernel/src/process.rs:382-384`), and the crate indexes
  only in its interleaving model. So it moves into the kernel's library
  with the scheduler.
- The library's floor is 135 tests. `cargo test -p` lists 6 for
  `toyos-pcid`, 95 for `toyos-sched` with `check`, and 34 for
  `toyos-proclife`, each exit 0. Re-read against their sources, the other
  17 verdicts stand under the new test.
- "moves" goes, so a step may move a boundary but never merge one.
- Step 4 puts each crate under its consumer as a crate of its own. Measured
  with jq over `cargo metadata --locked --offline` of the root, kernel,
  loader, userland and `toyos` workspaces, each exit 0:
  - `toyos-mixer` is linked only by soundd;
  - `toyos-desktop` only by the compositor;
  - `toyos-ps2` and `toyos-gicv3` only by the kernel;
  - `toyos-xhci` by the kernel, its own sim, and the harness's dev edge.
- `toyos-fat32-check` is not single-consumer. `toyos-build` links it
  (`image::certify`, `src/metal.rs`), and `toyos-fat32`'s tests
  dev-depend on it. It goes to `toyos-fat32/check/` on the one-subject
  rule, as the step says.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Round 5's commands, outputs and exits, at 42f3fb5.

Host gate. cargo run -- --ci host > ci-host.log 2>&1; echo EXIT=$? printed EXIT=0, and the log ends [ci] Host: 59 step(s), all green. Its FAILED lines run from log line 5071 to 6356. All of them fall inside the 39 negative-control steps (lines 5064 to 6359), each of which reports [ci] control …: N verdict(s) reached for its own red. The two error: lines outside them, at 73 and 502, are stderr from passing tests: an unclosed [package table, and a worktree removal.

Consumers. cargo metadata --locked --offline --format-version 1 ran in the root, kernel/, bootloader/, userland/ and toyos/, exit 0 each. Then, over the five dumps:

jq -s -r '[.[] | .packages[] | select(.source == null) | . as $p | .dependencies[] | select(.path != null) | {dep: .name, user: $p.name, kind: (.kind // "normal")}] | unique | group_by(.dep) | map({dep: .[0].dep, users: (map("\(.user)[\(.kind)]") | unique)}) | .[] | "\(.users | length)\t\(.dep)\t\(.users | join(", "))"' root.json kernel.json bootloader.json userland.json toyos.json | sort -n

It exited 0 and printed every local crate that has a local dependent, as the count, the crate, and each dependent with its edge:

1	blockd	fsd[normal]
1	terminal	console[normal]
1	toyos-desktop	compositor[normal]
1	toyos-dma	kernel[normal]
1	toyos-gicv3	kernel[normal]
1	toyos-mdns	netd[normal]
1	toyos-mixer	soundd[normal]
1	toyos-net-udp	toyos-dhcp[dev]
1	toyos-pci	kernel[normal]
1	toyos-pcid	kernel[normal]
1	toyos-proclife	kernel[normal]
1	toyos-ps2	kernel[normal]
1	toyos-transport	toyos-blockring[normal]
2	sprite	compositor[normal], files[normal]
2	toyos-acpi	bootloader[normal], kernel[normal]
2	toyos-dns	netd[normal], toyos-mdns[normal]
2	toyos-fat32-check	toyos-build[normal], toyos-fat32[dev]
2	toyos-hda	kernel[normal], soundd[normal]
2	toyos-i219	netd[normal], toyos-build[dev]
2	toyos-net-ip	toyos-dhcp[dev], toyos-net-udp[normal]
2	toyos-rootimage	bootloader[normal], kernel[normal]
2	toyos-symbols	kernel[normal], toyos-build[normal]
2	toyos-untrusted	kernel[normal], toyos-transport[normal]
2	toyos-userbound	kernel[normal], toyos-build[dev]
3	filepicker-api	editor[normal], filepicker[normal], paint[normal]
3	toyos-blackbox	bootloader[normal], kernel[normal], toyos-build[normal]
3	toyos-blockhold	blockd[normal], kernel[normal], toyos-blockring[normal]
3	toyos-blockring	blockd[normal], fsd[normal], init[normal]
3	toyos-bootmap	bootloader[normal], kernel[normal], toyos-acpi[normal]
3	toyos-elide	kernel[normal], logd[normal], toyos-symbols[normal]
3	toyos-keymap	toybox[normal], toyos-build[normal], toyos-window[normal]
3	toyos-quiesce	init[normal], kernel[normal], toyos-build[normal]
3	toyos-sched	kernel[normal], toyos-build[dev], toyos-sched-sim[normal]
3	toyos-swap	init[normal], swap[normal], toyos-build[normal]
3	toyos-xhci	kernel[normal], toyos-build[dev], toyos-xhci-sim[normal]
4	bcachefs	bootloader[normal], fsd[normal], kernel[normal], toyos-build[normal]
4	toyos-elf	bootloader[normal], kernel[normal], toyos-build[normal], toyos-symbols[normal]
4	toyos-fat32	fsd[normal], kernel[normal], toyos-build[normal], update[normal]
4	toyos-logstream	console[normal], init[normal], logd[normal], toyos-build[normal]
4	toyos-net-wire	toyos-dhcp[normal], toyos-net-ip[normal], toyos-net-tcp[normal], toyos-net-udp[normal]
4	toyos-update	bootloader[normal], init[normal], toyos-build[normal], update[normal]
5	toyos-inspect	compositor[normal], inspect[normal], logd[normal], netd[normal], soundd[normal]
5	toyos-tmpdir	pkg[dev], sshd[dev], toyos-build[normal], toyos-fat32[dev], toyos-ld[dev]
5	toyos-wallclock	bootloader[normal], kernel[normal], logd[normal], toyos-build[normal], toyos-fat32[normal]
6	toyos-gpt	blockd[normal], bootloader[normal], fsd[normal], init[normal], kernel[normal], toyos-build[normal]
6	toyos-manifest	compositor[normal], init[normal], pkg[normal], shell[normal], toyos-build[normal], toyos-swap[normal]
6	toyos-tco	bootloader[normal], kernel[normal], metalprobe[normal], netd[normal], test-runner[normal], toyos-build[normal]
8	toyos-window	compositor[normal], console[normal], editor[normal], filepicker[normal], files[normal], paint[normal], terminal[normal], toybox[normal]
10	toyos-font	calc[normal], compositor[normal], console[normal], editor[normal], filepicker[normal], files[normal], paint[normal], snake[normal], terminal[normal], toyos-window[normal]
19	toyos	blockd[normal], compositor[normal], console[normal], filepicker-api[normal], filepicker[normal], fsd[normal], init[normal], inspect[normal], logd[normal], metalprobe[normal], netd[normal], shell[normal], soundd[normal], swap[normal], terminal[normal], test-runner[normal], toybox[normal], toyos-window[normal], update[normal]
28	toyos-abi	blockd[normal], bootloader[normal], compositor[normal], console[normal], fsd[normal], init[normal], inspect[normal], kernel-loom[normal], kernel[normal], logd[normal], metalprobe[normal], netd[normal], soundd[normal], test-runner[normal], toybox[normal], toyos-acpi[normal], toyos-bootmap[normal], toyos-build[normal], toyos-desktop[normal], toyos-inspect[normal], toyos-logstream[normal], toyos-manifest[normal], toyos-pci[normal], toyos-proclife[normal], toyos-symbols[normal], toyos-window[normal], toyos[normal], update[normal]

A grep of every tracked manifest outside rust/ for the candidates found the same edges, exit 0: Cargo.toml:133 (toyos-fat32-check) and :179 (toyos-xhci), kernel/Cargo.toml:366, :372, :373 and :381, toyos-fat32/Cargo.toml:31, toyos-xhci/sim/Cargo.toml:11, userland/compositor/Cargo.toml:11 and userland/soundd/Cargo.toml:10.

The library's floor of 135.

  • cargo test --locked --offline -p toyos-pcid -- --list exited 0: 6 tests.
  • cargo test --locked --offline -p toyos-sched --features check -- --list exited 0: 91 tests from the library and 4 tests from tests/watch_list.rs.
  • cargo test --locked --offline -p toyos-proclife -- --list exited 0: 34 tests.

toyos-proclife decodes nothing. Its one refusal is ok_or on a lookup (join.rs:42-43), which the kernel answers with self.threads.get(tid) (kernel/src/process.rs:382-384). A grep of toyos-proclife/src for from_*_bytes, parse, an integer as, indexing and checked_, wrapping_ or saturating_ arithmetic matches #[test] and #![no_std] attributes. Beside those, it matches only interleave.rs:280 and :296-297, the model's indexing of its own op list.

Stage 1's "its own copy". git grep -n -E 'clippy::(indexing_slicing|arithmetic_side_effects|unwrap_used|expect_used|string_slice|panic_in_result_fn)' -- '*.rs' '*.toml' ':!rust' ':!issues' exited 0. It matches seven crates that carry part of the set at their roots: toyos-dhcp, -gpt, -net-ip, -net-tcp, -net-udp, -net-wire and -transport.

Lines. git show <rev>:<file> | wc -l gives:

  • the no-panic track: 104 at e3013a3 and 54 at 42f3fb5;
  • the crate track: 50 and 59.

@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Round-5 review of 42f3fb53a (wt/toyos-prosebatch) against .claude/agents/reviewer.md. It covers the merge e07ca9b1f, round 4's findings (issuecomment-5934546708), the PR body and git diff e3013a33e..42f3fb53a.

CI: host passes at 42f3fb53a: run 36889615500, conclusion success, 15m0s, and the log ends "[ci] Host: 59 step(s), all green". It was still pending when this review began; gh pr checks 673 now exits 0. No test is added and no hardware is targeted.

Net lines (git diff --shortstat origin/main...HEAD): 25 files, +397 −490.

  • Production: +13 −28, which is comments and one src/licence.rs string.
  • Tests: 0.
  • issues/: +364 −447.
  • Prompts: +20 −15.
  • Round 5 alone (e07ca9b1f..42f3fb53a): 2 files, +48 −89.

The merge

Earlier findings

No BLOCKER was open.

  • NOTE, "moves or merges": CLOSED.
    • issues/build/code-used-by-one-program-lives-in-that-program.md:21 reads "No step here merges one".
    • Step 4 (:50-57) moves the five crates and toyos-fat32-check.
    • A grep of every tracked manifest finds no edge to them beyond the ones the evidence names.
  • NOTE, "refuses": CLOSED.
    • :18-21 now test whether a crate decodes a word or bounds it by its form, and say a lookup is neither.
    • join.rs:42-43, read against kernel/src/process.rs:382-384, is a lookup.
    • Step 2's floor is 135 = 6 + 95 + 34.
  • NOTE, one config: CLOSED. issues/kernel/a-panic-is-never-an-accident.md:18-20 read the modes build::shipped reads (src/build.rs:1097). Ruling 1 replaces the definition.
  • NOTE, the loader: CLOSED. It is at :17-18, :34-35 and :42-44, and src/clippy.rs:129-135 lint the loader for both architectures.
  • NOTE, length: CLOSED at 54 lines.
    • The tier table, the sixteen lints, the cast override, what the set does not see and every stage's exit all stand.
    • What went is design, rationale and counts, except the two limits in NOTE 1.
  • Both REMOVEs: CLOSED. Neither text is in the file.
  • toyos-microcode: Intel microcode update files validated and matched to a CPU, pure, and no input can panic it; the kernel step's design in its issue #653: still open at e2cd27682, and it carries the three microcode files. The body records the window.

The PR body

For the rulings (not findings)

  • Ruling 1: fsd is a boot start in all three configs, and none of them marks it service = true (system.toml:191-192, console/system.toml:80-81, diag/system.toml:48-49). A definition read from the marker alone puts the file server in tier 4.

  • Ruling 2: by the same metadata, two more crates have one consumer each:

    • toyos-transport, linked only by toyos-blockring (toyos-blockring/Cargo.toml:43);
    • toyos-net-udp, linked only by toyos-dhcp's dev edge (toyos-dhcp/Cargo.toml:14).

    NOTE 4 covers the packages under tests/.

BLOCKER

None.

NOTE

  1. issues/kernel/a-panic-is-never-an-accident.md:12,47-48 — the cut dropped two measured limits that exits still standing rest on:

    • One arithmetic_side_effects finding spans a whole expression (e3013a33e:49-51), so an #[expect] the stage-3 step accepts can cover four overflow stops.
    • disallowed_methods and disallowed_macros read only the nearest clippy.toml, and the root's reaches tier 4 (:62-63). That bounds stage 1's one declaration.

    issues/README.md:83-85 keeps such constraints in a track. Restore both.

  2. issues/build/code-used-by-one-program-lives-in-that-program.md:51-52,56-57 — step 4 cannot pass its own check.

    • toyos-mixer and toyos-desktop hold tests in src/ and land in userland/soundd/mixer/ and userland/compositor/desktop/.
    • There, src/userlandhost.rs:104-107 lists every test of a nested crate as an escape, and every_userland_test_is_in_the_gate (:454-463) reds host on one.
    • The check fails until the survey or the destination changes, and the step names neither.
  3. PR body, The ABI is free to change, and the kernel takes on only what userland cannot #666 — the body never says this landing deletes reviewer.md's BLOCKER on a retired ABI name, or on a reused retired syscall, SYS_DEBUG action or inbox op number ("What no gate reads"). The ABI is free to change, and the kernel takes on only what userland cannot #666 removes it (git diff fa134154c ec166f1b4), and main's record should name the review rule it retires.

  4. PR body, Unsure, "toyos-i219, linked by netd, plus the harness's dev edge" — the consumer count is short.

    • tests/toyos-rust-tests/Cargo.toml:13 links toyos-i219 too.
    • The five cargo metadata dumps of issuecomment-5935427621 read no package under the excluded tests/, so any count taken from them is short wherever a guest test links a crate.

REMOVE

  1. issues/kernel/a-panic-is-never-an-accident.md:18 — "the three", and the same words in the body's issues: a panic is never an accident, the owner's rule as a track, not yet enforced; seven stale crafted-ELF clauses go #665 bullet. It is a count the next mode's landing moves, and build::shipped already names the set.
  2. PR body, Gates — "Its answers to the round-4 review are in 42f3fb5's message." It is review history, not main's record.
  3. PR body, "From issues: a panic is never an accident, the owner's rule as a track, not yet enforced; seven stale crafted-ELF clauses go #665" — "stage 3's copy mechanism and stage 4's metadata walk" and "(104 lines to 54)". issues: a panic is never an accident, the owner's rule as a track, not yet enforced; seven stale crafted-ELF clauses go #665's head f469e9022 has neither and is 68 lines. This branch added both in its own rounds, so neither is a drop from issues: a panic is never an accident, the owner's rule as a track, not yet enforced; seven stale crafted-ELF clauses go #665.

LAND AFTER NAMED CHANGES

…owns`, step 4 moves every crate with one consumer, and two clippy limits return

The no-panic track, `issues/kernel/a-panic-is-never-an-accident.md`:

- A system service is a program whose manifest declares `exempt.owns`,
  read as `src/userlandhost.rs` reads it. Every other program that gate
  reads is an app, `toybox` and the `exempt.manages` tools too. The config
  marker could not be the rule: `fsd` is a boot start in all three configs
  and none marks it `service = true`. `cargo metadata --no-deps
  --offline` over every package manifest, exit 0 each, reads
  `exempt.owns` from blockd, compositor, console, fsd, init, logd, netd
  and soundd, and `exempt.manages` from inspect, swap and update. sshd and
  filepicker, which the shipped config marks `service = true`, declare
  nothing, so they are apps.
- Two measured limits return, each at the stage whose exit it bounds.
  Stage 1: `disallowed_methods` and `disallowed_macros` read the nearest
  `clippy.toml` alone. Stage 3: one `arithmetic_side_effects` finding spans
  a whole expression. clippy 0.1.98 shows both on scratch crates. A crate
  with no `clippy.toml` of its own, under a directory whose file disallows
  `core::assert`, warns on `assert!`. One with an empty `clippy.toml` of its
  own does not. `x * x + y * y - 1` draws one warning.
- "the three" goes, with the boot-start rule it counted.

The crate track, `issues/build/code-used-by-one-program-lives-in-that-program.md`:

- Step 4 states its rule and how it is measured, not a list. Every crate of
  this tree with exactly one consumer moves under it, as a crate of its
  own. A consumer is a package whose manifest names the crate as a
  dependency of any kind, under any `cfg`. They are counted over every
  manifest `git ls-files '*Cargo.toml'` lists, excluded packages and
  `tests/` included. `cargo metadata --no-deps --offline` ran on each of the
  98 package manifests, exit 0 each. Counted over their path dependencies,
  the rule yields `terminal`, `tls-dep`, `toyos-desktop`, `toyos-dma`,
  `toyos-gicv3`, `toyos-mdns`, `toyos-mixer`, `toyos-net-udp`,
  `toyos-pci`, `toyos-pcid`, `toyos-proclife`, `toyos-ps2` and
  `toyos-transport`. `git grep -F <name> -- '*Cargo.toml'` finds exactly
  one dependency line for each. `toyos-xhci` has three consumers: the
  kernel, its sim and the harness's dev edge. So does `toyos-i219`: netd,
  the harness's dev edge and `tests/toyos-rust-tests`. `toyos-userbound`
  has two, and so does `blockd`.
- The step names what must change with a move under a userland program:
  `src/userlandhost.rs`'s survey lists every test of a nested crate as an
  escape, and `every_userland_test_is_in_the_gate` reds `host` on one.
- `toyos-fat32-check` has two consumers and keeps a step of its own, step 5.
- The exit counts step 4's rule, since that step no longer names a
  directory.
- "the feature three scheduler tests need" loses its count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Round 6's commands, outputs and exits, at d974223.

Host gate. cargo run -- --ci host > ci-host.log 2>&1; echo EXIT=$? printed EXIT=0, and the log ends [ci] Host: 59 step(s), all green. Its 88 FAILED lines run from log line 5065 to 6350. All of them fall inside the 39 negative-control steps (lines 5060 to 6353), each of which reports [ci] control …: N verdict(s) reached for its own red. The error: and fatal: lines outside them, at 73, 499 and 500, are stderr from passing tests: an unclosed [package table, and two worktree removals.

Merge. After git fetch origin, git merge-tree --write-tree HEAD origin/main exited 0. origin/main is 1a8cd4a53, an ancestor of the head, so nothing was merged.

Every package's metadata. git ls-files '*Cargo.toml' lists 99 manifests. 98 of them declare [package]; the 99th is userland/Cargo.toml, a virtual workspace. For each of the 98:

RUSTUP_TOOLCHAIN=stable cargo metadata --no-deps --offline --format-version 1 --manifest-path "$PWD/$m"

Each exited 0, and the dumps hold 98 distinct packages, one per manifest, tests/ included. git status --porcelain was empty after them.

The services. Over the dumps:

jq -s -r '[.[].packages[]] | unique_by(.manifest_path) | .[] | select(.metadata.toyos.host != null) | "\(.name)\t\(.metadata.toyos.host | if .exempt then "exempt." + (.exempt | keys | join(",")) else "fails=" + (.fails | join(",")) end)"'

It exited 0 and printed:

blockd	exempt.owns
compositor	exempt.owns
console	exempt.owns
doom	fails=linux,macos,windows
fsd	exempt.owns
init	exempt.owns
inspect	exempt.manages
logd	exempt.owns
netd	exempt.owns
proctest	fails=linux,macos,windows
shell	fails=linux,macos,windows
soundd	exempt.owns
swap	exempt.manages
terminal	fails=linux,macos,windows
toybox	fails=linux,macos,windows
update	exempt.manages

All eight exempt.owns programs are ones build::shipped names: config_crates (src/build.rs:333-363) adds init to every mode's [programs] rows. sshd and filepicker are rows marked service = true (system.toml:80-81, :109-110) and declare no host table, so the gate reads both as apps.

The consumers. The dumps were merged into one list, one entry per manifest, exit 0:

jq -s '[.[].packages[]] | unique_by(.manifest_path) | map({name, manifest_path, deps: [.dependencies[] | {name, rename, kind, target, path, source}]})' *.json > packages.json

Every dependency carrying a path was mapped to the package at that path. No dependency named a tree package without a path.

jq -r '(map({key: .manifest_path, value: .name}) | from_entries) as $byman | [ .[] as $p | $p.deps[] | select(.path != null) | {dep: $byman[.path + "/Cargo.toml"], user: $p.name, kind: (.kind // "normal")} ] | unique | group_by(.dep) | map({dep: .[0].dep, users: (map("\(.user)[\(.kind)]") | unique)}) | .[] | "\(.users | length)\t\(.dep)\t\(.users | join(", "))"' packages.json | sort -n

It exited 0 and printed every tree crate that some tree package names, with its count and each consumer's edge:

1	terminal	console[normal]
1	tls-dep	tls-multi-crate[normal]
1	toyos-desktop	compositor[normal]
1	toyos-dma	kernel[normal]
1	toyos-gicv3	kernel[normal]
1	toyos-mdns	netd[normal]
1	toyos-mixer	soundd[normal]
1	toyos-net-udp	toyos-dhcp[dev]
1	toyos-pci	kernel[normal]
1	toyos-pcid	kernel[normal]
1	toyos-proclife	kernel[normal]
1	toyos-ps2	kernel[normal]
1	toyos-transport	toyos-blockring[normal]
2	blockd	fsd[normal], toyos-rust-tests[normal]
2	sprite	compositor[normal], files[normal]
2	toyos-acpi	bootloader[normal], kernel[normal]
2	toyos-fat32-check	toyos-build[normal], toyos-fat32[dev]
2	toyos-hda	kernel[normal], soundd[normal]
2	toyos-net-ip	toyos-dhcp[dev], toyos-net-udp[normal]
2	toyos-rootimage	bootloader[normal], kernel[normal]
2	toyos-symbols	kernel[normal], toyos-build[normal]
2	toyos-untrusted	kernel[normal], toyos-transport[normal]
2	toyos-userbound	kernel[normal], toyos-build[dev]
3	filepicker-api	editor[normal], filepicker[normal], paint[normal]
3	toyos-blackbox	bootloader[normal], kernel[normal], toyos-build[normal]
3	toyos-blockhold	blockd[normal], kernel[normal], toyos-blockring[normal]
3	toyos-bootmap	bootloader[normal], kernel[normal], toyos-acpi[normal]
3	toyos-dns	netd[normal], toyos-mdns[normal], toyos-rust-tests[normal]
3	toyos-elide	kernel[normal], logd[normal], toyos-symbols[normal]
3	toyos-i219	netd[normal], toyos-build[dev], toyos-rust-tests[normal]
3	toyos-keymap	toybox[normal], toyos-build[normal], toyos-window[normal]
3	toyos-sched	kernel[normal], toyos-build[dev], toyos-sched-sim[normal]
3	toyos-xhci	kernel[normal], toyos-build[dev], toyos-xhci-sim[normal]
4	bcachefs	bootloader[normal], fsd[normal], kernel[normal], toyos-build[normal]
4	toyos-blockring	blockd[normal], fsd[normal], init[normal], toyos-rust-tests[normal]
4	toyos-elf	bootloader[normal], kernel[normal], toyos-build[normal], toyos-symbols[normal]
4	toyos-logstream	console[normal], init[normal], logd[normal], toyos-build[normal]
4	toyos-net-wire	toyos-dhcp[normal], toyos-net-ip[normal], toyos-net-tcp[normal], toyos-net-udp[normal]
4	toyos-quiesce	init[normal], kernel[normal], toyos-build[normal], toyos-rust-tests[normal]
4	toyos-swap	init[normal], ssh-client-host[normal], swap[normal], toyos-build[normal]
4	toyos-update	bootloader[normal], init[normal], toyos-build[normal], update[normal]
5	toyos-fat32	fsd[normal], kernel[normal], toyos-build[normal], toyos-rust-tests[normal], update[normal]
5	toyos-tmpdir	pkg[dev], sshd[dev], toyos-build[normal], toyos-fat32[dev], toyos-ld[dev]
5	toyos-wallclock	bootloader[normal], kernel[normal], logd[normal], toyos-build[normal], toyos-fat32[normal]
6	toyos-gpt	blockd[normal], bootloader[normal], fsd[normal], init[normal], kernel[normal], toyos-build[normal]
6	toyos-inspect	compositor[normal], inspect[normal], logd[normal], netd[normal], soundd[normal], toyos-rust-tests[normal]
6	toyos-manifest	compositor[normal], init[normal], pkg[normal], shell[normal], toyos-build[normal], toyos-swap[normal]
7	toyos-tco	bootloader[normal], kernel[normal], metalprobe[normal], netd[normal], test-runner[normal], toyos-build[normal], toyos-rust-tests[normal]
9	toyos-window	compositor[normal], console[normal], editor[normal], filepicker[normal], files[normal], paint[normal], terminal[normal], toybox[normal], toyos-rust-tests[normal]
10	toyos-font	calc[normal], compositor[normal], console[normal], editor[normal], filepicker[normal], files[normal], paint[normal], snake[normal], terminal[normal], toyos-window[normal]
21	toyos	blockd[normal], compositor[normal], console[normal], filepicker-api[normal], filepicker[normal], fsd[normal], init[normal], inspect[normal], logd[normal], metalprobe[normal], netd[normal], shell[normal], soundd[normal], swap[normal], terminal[normal], test-runner[normal], toybox[normal], toyos-libc[normal], toyos-rust-tests[normal], toyos-window[normal], update[normal]
30	toyos-abi	blockd[normal], bootloader[normal], compositor[normal], console[normal], fsd[normal], init[normal], inspect[normal], kernel-loom[normal], kernel[normal], logd[normal], metalprobe[normal], netd[normal], soundd[normal], test-runner[normal], toybox[normal], toyos-acpi[normal], toyos-bootmap[normal], toyos-build[normal], toyos-desktop[normal], toyos-inspect[normal], toyos-libc[normal], toyos-logstream[normal], toyos-manifest[normal], toyos-pci[normal], toyos-proclife[normal], toyos-rust-tests[normal], toyos-symbols[normal], toyos-window[normal], toyos[normal], update[normal]

toyos-build is the root package, whose dev edges are the harness's.

git grep -n -F <name> -- '*Cargo.toml' for each crate with one consumer exited 0. Apart from workspace member lists, name = lines and comments, it finds exactly one dependency line for each:

  • userland/console/Cargo.toml:8 (terminal);
  • tests/toyos-rust-tests/tls-multi-crate/Cargo.toml:10 (tls-dep, already at dep/ beneath it);
  • userland/compositor/Cargo.toml:11 (toyos-desktop);
  • kernel/Cargo.toml:359, :366, :369, :370, :372 and :373 (toyos-dma, -gicv3, -pci, -pcid, -proclife and -ps2);
  • userland/netd/Cargo.toml:11 (toyos-mdns);
  • userland/soundd/Cargo.toml:10 (toyos-mixer);
  • toyos-dhcp/Cargo.toml:14 (toyos-net-udp);
  • toyos-blockring/Cargo.toml:43 (toyos-transport).

A search of every Cargo.toml under the fork clones, ~/.cargo/git/checkouts/ and rust/library for those names finds them only in ~/.cargo/git/checkouts/toyos-b407e7a14e68aa06/6115718/, a cargo checkout of this repository itself. No fork names one.

The two clippy limits. clippy 0.1.98 (48a229ceae) ran cargo clippy --offline on scratch crates, exit 0 each:

  • With -W clippy::arithmetic_side_effects, pub fn f(x: i32, y: i32) -> i32 { x * x + y * y - 1 } draws one warning, whose span is the whole of x * x + y * y - 1.
  • A parent directory's clippy.toml holds disallowed-macros = ["core::assert"]. With -W clippy::disallowed_macros, a crate beneath it with no clippy.toml of its own warns on assert!(x > 1). A sibling crate with an empty clippy.toml of its own draws no warning.

Lines. wc -l gives 59 for the no-panic track and 66 for the crate track.

…service = true` or whose manifest declares `exempt.owns`, and a shipped program is its own consumer

The no-panic track's services tier is now the union of two classes. Round
6's rule, a program whose manifest declares `exempt.owns`, made `sshd` and
`filepicker` apps, though the shipped config marks both `service = true` and
`sshd` takes untrusted input from the network. The config marker alone
misses `fsd`, which starts at boot without it. Read as `build::shipped`
reads the three modes and as `src/userlandhost.rs` reads the manifests, the
rule yields ten services today: blockd, compositor, console, filepicker,
fsd, init, logd, netd, soundd and sshd. Every other shipped program is an
app: calc, doom, editor, files, host, input-test, inspect, paint, pkg,
proctest, shell, snake, swap, terminal, toybox, toyos-ld and update.

The crate track's step 4 counts a crate the images ship as a program of its
own as its own consumer, so `terminal`, which console links, has two
consumers and stays where it is. Over the 98 package manifests
`git ls-files '*Cargo.toml'` lists, twelve crates have exactly one
consumer, each of them another package: `toyos-dma`, `toyos-gicv3`,
`toyos-pci`, `toyos-pcid`, `toyos-proclife` and `toyos-ps2` (the kernel),
`toyos-desktop` (compositor), `toyos-mixer` (soundd), `toyos-mdns` (netd),
`toyos-net-udp` (`toyos-dhcp`'s tests), `toyos-transport`
(`toyos-blockring`) and `tls-dep` (`tls-multi-crate`, already beneath it).
A shipped program that no package names is its own one consumer, so it
moves nowhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Round 7's commands, outputs and exits, at 7131598.

Host gate. cargo run -- --ci host > ci-host.log 2>&1; echo EXIT=$? printed EXIT=0, and the log ends [ci] Host: 59 step(s), all green. Its 88 FAILED lines run from log line 5065 to 6350. All of them fall inside the 39 negative-control steps (lines 5060 to 6353), and each of those steps reports [ci] control …: N verdict(s) reached for its own red. The error: and fatal: lines outside them, at 73, 499 and 502, are stderr from tests that pass: an unclosed [package table, and two worktree removals.

Merge. After git fetch origin (exit 0), git merge-tree --write-tree HEAD origin/main exited 0. origin/main is 1a8cd4a53, an ancestor of the head, so nothing was merged.

The services. The worktree's absolute path is written <worktree> below. A scratch crate that depends on toyos-build by path calls toyos_build::build::shipped and toyos_build::userlandhost::programs themselves. ProgramConfig's service is private to src/build.rs, so the crate reads each mode's config with the same serde shape (rename_all = "kebab-case", default) and finds a row's directory by crate_dir's rule. It asserts two things: every marked row is a shipped program, and userlandhost::programs returns Host::Exempt exactly where the manifest has an exempt table. cargo build --offline exited 0. svc-measure <worktree> exited 0 at d974223 and again at 7131598, and diff of the two outputs exited 0. Its verdict lines:

  program toyos-ld (toyos-ld) features=Default: app, nothing declared; service = true in None
  program blockd (userland/blockd) features=Default: exempt.owns; service = true in Some(["system.toml", "console/system.toml"])
  program calc (userland/calc) features=Default: app, nothing declared; service = true in None
  program compositor (userland/compositor) features=Default: exempt.owns; service = true in Some(["system.toml"])
  program console (userland/console) features=Default: exempt.owns; service = true in None
  program doom (userland/doom) features=Default: app, fails on ["linux", "macos", "windows"]; service = true in None
  program editor (userland/editor) features=Default: app, nothing declared; service = true in None
  program filepicker (userland/filepicker) features=Default: app, nothing declared; service = true in Some(["system.toml"])
  program files (userland/files) features=Default: app, nothing declared; service = true in None
  program fsd (userland/fsd) features=Default: exempt.owns; service = true in None
  program host (userland/host) features=Default: app, nothing declared; service = true in None
  program init (userland/init) features=Default: exempt.owns; service = true in None
  program input-test (userland/input-test) features=Default: app, nothing declared; service = true in None
  program inspect (userland/inspect) features=Default: exempt.manages; service = true in None
  program logd (userland/logd) features=Default: exempt.owns; service = true in Some(["system.toml", "diag/system.toml", "console/system.toml"])
  program netd (userland/netd) features=Default: exempt.owns; service = true in Some(["system.toml"])
  program paint (userland/paint) features=Default: app, nothing declared; service = true in None
  program pkg (userland/pkg) features=Default: app, nothing declared; service = true in None
  program proctest (userland/proctest) features=Default: app, fails on ["linux", "macos", "windows"]; service = true in None
  program shell (userland/shell) features=Default: app, fails on ["linux", "macos", "windows"]; service = true in None
  program snake (userland/snake) features=Default: app, nothing declared; service = true in None
  program soundd (userland/soundd) features=Default: exempt.owns; service = true in Some(["system.toml"])
  program sshd (userland/sshd) features=Default: app, nothing declared; service = true in Some(["system.toml"])
  program swap (userland/swap) features=Default: exempt.manages; service = true in None
  program terminal (userland/terminal) features=Default: app, fails on ["linux", "macos", "windows"]; service = true in None
  program toybox (userland/toybox) features=Default: app, fails on ["linux", "macos", "windows"]; service = true in None
  program update (userland/update) features=Default: exempt.manages; service = true in None
services (10): blockd, compositor, console, filepicker, fsd, init, logd, netd, soundd, sshd
apps (17): calc, doom, editor, files, host, input-test, inspect, paint, pkg, proctest, shell, snake, swap, terminal, toybox, toyos-ld, update
The reader's whole output at 7131598, then its source
build::shipped: 27 (dir, features) programs, 27 distinct dirs
  shipped program toyos-ld Default
  shipped program userland/blockd Default
  shipped program userland/calc Default
  shipped program userland/compositor Default
  shipped program userland/console Default
  shipped program userland/doom Default
  shipped program userland/editor Default
  shipped program userland/filepicker Default
  shipped program userland/files Default
  shipped program userland/fsd Default
  shipped program userland/host Default
  shipped program userland/init Default
  shipped program userland/input-test Default
  shipped program userland/inspect Default
  shipped program userland/logd Default
  shipped program userland/netd Default
  shipped program userland/paint Default
  shipped program userland/pkg Default
  shipped program userland/proctest Default
  shipped program userland/shell Default
  shipped program userland/snake Default
  shipped program userland/soundd Default
  shipped program userland/sshd Default
  shipped program userland/swap Default
  shipped program userland/terminal Default
  shipped program userland/toybox Default
  shipped program userland/update Default
  row system.toml:blockd path=None service=true
  row system.toml:calc path=None service=false
  row system.toml:compositor path=None service=true
  row system.toml:doom path=None service=false
  row system.toml:editor path=None service=false
  row system.toml:filepicker path=None service=true
  row system.toml:files path=None service=false
  row system.toml:fsd path=None service=false
  row system.toml:host path=None service=false
  row system.toml:input-test path=None service=false
  row system.toml:inspect path=None service=false
  row system.toml:logd path=None service=true
  row system.toml:netd path=None service=true
  row system.toml:paint path=None service=false
  row system.toml:pkg path=None service=false
  row system.toml:proctest path=None service=false
  row system.toml:shell path=None service=false
  row system.toml:snake path=None service=false
  row system.toml:soundd path=None service=true
  row system.toml:sshd path=None service=true
  row system.toml:swap path=None service=false
  row system.toml:terminal path=None service=false
  row system.toml:toybox path=None service=false
  row system.toml:toyos-ld path=Some("toyos-ld") service=false
  row system.toml:update path=None service=false
  row diag/system.toml:fsd path=None service=false
  row diag/system.toml:logd path=None service=true
  row diag/system.toml:toybox path=None service=false
  row console/system.toml:blockd path=None service=true
  row console/system.toml:console path=None service=false
  row console/system.toml:fsd path=None service=false
  row console/system.toml:logd path=None service=true
  row console/system.toml:shell path=None service=false
  row console/system.toml:toybox path=None service=false
  program toyos-ld (toyos-ld) features=Default: app, nothing declared; service = true in None
  program blockd (userland/blockd) features=Default: exempt.owns; service = true in Some(["system.toml", "console/system.toml"])
  program calc (userland/calc) features=Default: app, nothing declared; service = true in None
  program compositor (userland/compositor) features=Default: exempt.owns; service = true in Some(["system.toml"])
  program console (userland/console) features=Default: exempt.owns; service = true in None
  program doom (userland/doom) features=Default: app, fails on ["linux", "macos", "windows"]; service = true in None
  program editor (userland/editor) features=Default: app, nothing declared; service = true in None
  program filepicker (userland/filepicker) features=Default: app, nothing declared; service = true in Some(["system.toml"])
  program files (userland/files) features=Default: app, nothing declared; service = true in None
  program fsd (userland/fsd) features=Default: exempt.owns; service = true in None
  program host (userland/host) features=Default: app, nothing declared; service = true in None
  program init (userland/init) features=Default: exempt.owns; service = true in None
  program input-test (userland/input-test) features=Default: app, nothing declared; service = true in None
  program inspect (userland/inspect) features=Default: exempt.manages; service = true in None
  program logd (userland/logd) features=Default: exempt.owns; service = true in Some(["system.toml", "diag/system.toml", "console/system.toml"])
  program netd (userland/netd) features=Default: exempt.owns; service = true in Some(["system.toml"])
  program paint (userland/paint) features=Default: app, nothing declared; service = true in None
  program pkg (userland/pkg) features=Default: app, nothing declared; service = true in None
  program proctest (userland/proctest) features=Default: app, fails on ["linux", "macos", "windows"]; service = true in None
  program shell (userland/shell) features=Default: app, fails on ["linux", "macos", "windows"]; service = true in None
  program snake (userland/snake) features=Default: app, nothing declared; service = true in None
  program soundd (userland/soundd) features=Default: exempt.owns; service = true in Some(["system.toml"])
  program sshd (userland/sshd) features=Default: app, nothing declared; service = true in Some(["system.toml"])
  program swap (userland/swap) features=Default: exempt.manages; service = true in None
  program terminal (userland/terminal) features=Default: app, fails on ["linux", "macos", "windows"]; service = true in None
  program toybox (userland/toybox) features=Default: app, fails on ["linux", "macos", "windows"]; service = true in None
  program update (userland/update) features=Default: exempt.manages; service = true in None
services (10): blockd, compositor, console, filepicker, fsd, init, logd, netd, soundd, sshd
apps (17): calc, doom, editor, files, host, input-test, inspect, paint, pkg, proctest, shell, snake, swap, terminal, toybox, toyos-ld, update
  shipped manifest <worktree>/toyos-ld/Cargo.toml
  shipped manifest <worktree>/userland/blockd/Cargo.toml
  shipped manifest <worktree>/userland/calc/Cargo.toml
  shipped manifest <worktree>/userland/compositor/Cargo.toml
  shipped manifest <worktree>/userland/console/Cargo.toml
  shipped manifest <worktree>/userland/doom/Cargo.toml
  shipped manifest <worktree>/userland/editor/Cargo.toml
  shipped manifest <worktree>/userland/filepicker/Cargo.toml
  shipped manifest <worktree>/userland/files/Cargo.toml
  shipped manifest <worktree>/userland/fsd/Cargo.toml
  shipped manifest <worktree>/userland/host/Cargo.toml
  shipped manifest <worktree>/userland/init/Cargo.toml
  shipped manifest <worktree>/userland/input-test/Cargo.toml
  shipped manifest <worktree>/userland/inspect/Cargo.toml
  shipped manifest <worktree>/userland/logd/Cargo.toml
  shipped manifest <worktree>/userland/netd/Cargo.toml
  shipped manifest <worktree>/userland/paint/Cargo.toml
  shipped manifest <worktree>/userland/pkg/Cargo.toml
  shipped manifest <worktree>/userland/proctest/Cargo.toml
  shipped manifest <worktree>/userland/shell/Cargo.toml
  shipped manifest <worktree>/userland/snake/Cargo.toml
  shipped manifest <worktree>/userland/soundd/Cargo.toml
  shipped manifest <worktree>/userland/sshd/Cargo.toml
  shipped manifest <worktree>/userland/swap/Cargo.toml
  shipped manifest <worktree>/userland/terminal/Cargo.toml
  shipped manifest <worktree>/userland/toybox/Cargo.toml
  shipped manifest <worktree>/userland/update/Cargo.toml

Cargo.toml:

[package]
name = "svc-measure"
version = "0.0.0"
edition = "2021"
publish = false

[dependencies]
toyos-build = { path = "<worktree>" }
toml = "0.8"
serde = { version = "1", features = ["derive"] }

[workspace]

src/main.rs:

//! The services rule of `issues/kernel/a-panic-is-never-an-accident.md`, measured:
//! a shipped program is a service when any mode's config marks its row
//! `service = true`, or its manifest declares `exempt.owns`.
//!
//! The program set is `toyos_build::build::shipped` itself; the host verdict is
//! `toyos_build::userlandhost::programs` itself. `service` is private to
//! `src/build.rs`, so it is read here with the same serde shape
//! `ProgramConfig` has (`rename_all = "kebab-case"`, `default`), and a row's
//! directory with `ProgramConfig::crate_dir`'s rule.

use std::collections::{BTreeMap, BTreeSet};
use std::path::{Path, PathBuf};

use serde::Deserialize;
use toyos_build::userlandhost::Host;

#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
struct Config {
    #[serde(default)]
    programs: BTreeMap<String, Row>,
}

#[derive(Deserialize, Default)]
#[serde(default, rename_all = "kebab-case")]
struct Row {
    path: Option<String>,
    service: bool,
}

fn manifest(dir: &Path) -> toml::Value {
    let text = std::fs::read_to_string(dir.join("Cargo.toml")).expect("read manifest");
    text.parse().expect("manifest is TOML")
}

fn main() {
    let arg = std::env::args().nth(1).expect("usage: svc-measure <root>");
    let root = std::fs::canonicalize(arg).expect("canonical root");

    let shipped = toyos_build::build::shipped(&root).expect("build::shipped");
    let program_dirs: BTreeSet<PathBuf> = shipped.programs.iter().map(|(d, _)| d.clone()).collect();
    println!("build::shipped: {} (dir, features) programs, {} distinct dirs", shipped.programs.len(), program_dirs.len());
    for (dir, features) in &shipped.programs {
        println!("  shipped program {} {:?}", dir.strip_prefix(&root).unwrap().display(), features);
    }

    // Every row any mode's config marks `service = true`, by crate directory.
    let mut marked: BTreeMap<PathBuf, Vec<String>> = BTreeMap::new();
    for mode in ["", "diag", "console"] {
        let at = root.join(mode).join("system.toml");
        let config: Config =
            toml::from_str(&std::fs::read_to_string(&at).expect("read config")).expect("config");
        for (name, row) in &config.programs {
            println!(
                "  row {}:{name} path={:?} service={}",
                at.strip_prefix(&root).unwrap().display(),
                row.path,
                row.service
            );
            if row.service {
                let dir = match &row.path {
                    Some(p) => root.join(p),
                    None => root.join("userland").join(name),
                };
                marked
                    .entry(dir)
                    .or_default()
                    .push(format!("{}", at.strip_prefix(&root).unwrap().display()));
            }
        }
    }
    for dir in marked.keys() {
        assert!(program_dirs.contains(dir), "{} is marked service and not shipped", dir.display());
    }

    // The real host reader's verdict for every shipped program.
    let hosts = toyos_build::userlandhost::programs(&root).expect("userlandhost::programs");
    let mut services = BTreeSet::new();
    let mut apps = BTreeSet::new();
    for p in &hosts {
        let dir = root.join(&p.dir);
        let m = manifest(&dir);
        let name = m["package"]["name"].as_str().expect("package name").to_string();
        let exempt = m
            .get("package")
            .and_then(|p| p.get("metadata"))
            .and_then(|m| m.get("toyos"))
            .and_then(|t| t.get("host"))
            .and_then(|h| h.get("exempt"))
            .and_then(|e| e.as_table())
            .map(|t| t.keys().cloned().collect::<Vec<_>>());
        let owns = exempt.as_ref().is_some_and(|k| k == &["owns".to_string()]);
        let manages = exempt.as_ref().is_some_and(|k| k == &["manages".to_string()]);
        // The real reader agrees: an `exempt` table is `Host::Exempt`, else an app.
        assert_eq!(exempt.is_some(), p.host == Host::Exempt, "{name}: reader disagrees");
        let by_marker = marked.get(&dir);
        let declared = match (&p.host, owns, manages) {
            (Host::Exempt, true, false) => "exempt.owns".to_string(),
            (Host::Exempt, false, true) => "exempt.manages".to_string(),
            (Host::App(on), false, false) if on.is_empty() => "app, nothing declared".to_string(),
            (Host::App(on), false, false) => {
                format!("app, fails on {:?}", on.iter().map(|o| o.name()).collect::<Vec<_>>())
            }
            other => panic!("{name}: unexpected {other:?}"),
        };
        println!(
            "  program {name} ({}) features={:?}: {declared}; service = true in {:?}",
            p.dir, p.features, by_marker
        );
        if owns || by_marker.is_some() {
            services.insert(name);
        } else {
            apps.insert(name);
        }
    }
    let both: BTreeSet<_> = services.iter().cloned().collect();
    println!("services ({}): {}", both.len(), both.into_iter().collect::<Vec<_>>().join(", "));
    println!("apps ({}): {}", apps.len(), apps.into_iter().collect::<Vec<_>>().join(", "));
    for dir in &program_dirs {
        println!("  shipped manifest {}", dir.join("Cargo.toml").display());
    }
}

The consumers. git ls-files '*Cargo.toml' lists 99 manifests. 98 of them declare [package]; the 99th is userland/Cargo.toml, a virtual workspace. For each of the 98:

RUSTUP_TOOLCHAIN=stable cargo metadata --no-deps --offline --format-version 1 --manifest-path "$PWD/$m"

Each exited 0, at d974223 and again at 7131598, and git status --porcelain was empty after them. Round 6's merge, jq -s '[.[].packages[]] | unique_by(.manifest_path) | map({name, manifest_path, deps: [.dependencies[] | {name, rename, kind, target, path, source}]})', exited 0. It holds 98 packages, and their manifest paths are exactly those 98.

No dependency names a tree package without a path. The dependencies that carry no path and share a tree package's name, or that name a ToyOSOrg git source, are three fork edges, none of them to a tree package:

ssh-client-host -> russh source=git+https://github.com/ToyOSOrg/russh?branch=toyos kind=null target=null
toyos-rust-tests -> cpal source=git+https://github.com/ToyOSOrg/cpal?branch=toyos-0.18.0 kind=null target=null
toyos-rust-tests -> libloading source=git+https://github.com/ToyOSOrg/rust_libloading?branch=toyos-sdk-0.12 kind=null target=null

No tree edge sits under a cfg: the only edges with a target are calc's, doom's and snake's to softbuffer and winit.

The count is now taken once per package rather than once per edge. Over these dumps that changes no number from round 6's: group_by(.dep), comparing each crate's unique users with its unique edges, found 0 mismatches. The 27 manifests the reader prints as shipped programs count as their own consumer:

# Step 4's count: a tree crate's consumers are the tree packages that name it as
# a dependency of any kind under any cfg, counted once per package; a crate the
# images ship as a program of its own counts as its own consumer.
($shipped[0]) as $ship
| (map({key: .manifest_path, value: .name}) | from_entries) as $byman
| [ .[] as $p | $p.deps[] | select(.path != null)
    | {dep: (.path + "/Cargo.toml"), user: $p.manifest_path,
       edge: "\($p.name)[\(.kind // "normal")\(if .target then " " + .target else "" end)]"} ] as $edges
| .[] | .manifest_path as $m
| ([$edges[] | select(.dep == $m)]) as $in
| ([$in[].user] | unique | length) as $users
| (if any($ship[]; . == $m) then 1 else 0 end) as $self
| "\($users + $self)\t\($byman[$m])\tpackages=\($users)\tshipped-program=\($self)\t\([$in[].edge] | unique | join(", "))"

jq -r --slurpfile shipped shipped.json -f consumers.jq packages.json | sort -n -k1,1 -k2,2 exited 0 at d974223 and again at 7131598, and diff of the two outputs exited 0. It prints every tree package with its count, its packages, whether it counts itself, and each edge in:

0	bootloader	packages=0	shipped-program=0	
0	kernel	packages=0	shipped-program=0	
0	kernel-loom	packages=0	shipped-program=0	
0	metalprobe	packages=0	shipped-program=0	
0	ssh-client-host	packages=0	shipped-program=0	
0	test-runner	packages=0	shipped-program=0	
0	tls-cranelift	packages=0	shipped-program=0	
0	tls-dlopen-lib	packages=0	shipped-program=0	
0	tls-lib	packages=0	shipped-program=0	
0	tls-multi-crate	packages=0	shipped-program=0	
0	toyos-build	packages=0	shipped-program=0	
0	toyos-cpuvuln	packages=0	shipped-program=0	
0	toyos-dhcp	packages=0	shipped-program=0	
0	toyos-libc	packages=0	shipped-program=0	
0	toyos-libc-copies	packages=0	shipped-program=0	
0	toyos-net-tcp	packages=0	shipped-program=0	
0	toyos-rust-tests	packages=0	shipped-program=0	
0	toyos-sched-loom	packages=0	shipped-program=0	
0	toyos-sched-sim	packages=0	shipped-program=0	
0	toyos-userpin	packages=0	shipped-program=0	
0	toyos-xhci-sim	packages=0	shipped-program=0	
1	calc	packages=0	shipped-program=1	
1	compositor	packages=0	shipped-program=1	
1	console	packages=0	shipped-program=1	
1	doom	packages=0	shipped-program=1	
1	editor	packages=0	shipped-program=1	
1	filepicker	packages=0	shipped-program=1	
1	files	packages=0	shipped-program=1	
1	fsd	packages=0	shipped-program=1	
1	host	packages=0	shipped-program=1	
1	init	packages=0	shipped-program=1	
1	input-test	packages=0	shipped-program=1	
1	inspect	packages=0	shipped-program=1	
1	logd	packages=0	shipped-program=1	
1	netd	packages=0	shipped-program=1	
1	paint	packages=0	shipped-program=1	
1	pkg	packages=0	shipped-program=1	
1	proctest	packages=0	shipped-program=1	
1	shell	packages=0	shipped-program=1	
1	snake	packages=0	shipped-program=1	
1	soundd	packages=0	shipped-program=1	
1	sshd	packages=0	shipped-program=1	
1	swap	packages=0	shipped-program=1	
1	tls-dep	packages=1	shipped-program=0	tls-multi-crate[normal]
1	toybox	packages=0	shipped-program=1	
1	toyos-desktop	packages=1	shipped-program=0	compositor[normal]
1	toyos-dma	packages=1	shipped-program=0	kernel[normal]
1	toyos-gicv3	packages=1	shipped-program=0	kernel[normal]
1	toyos-ld	packages=0	shipped-program=1	
1	toyos-mdns	packages=1	shipped-program=0	netd[normal]
1	toyos-mixer	packages=1	shipped-program=0	soundd[normal]
1	toyos-net-udp	packages=1	shipped-program=0	toyos-dhcp[dev]
1	toyos-pci	packages=1	shipped-program=0	kernel[normal]
1	toyos-pcid	packages=1	shipped-program=0	kernel[normal]
1	toyos-proclife	packages=1	shipped-program=0	kernel[normal]
1	toyos-ps2	packages=1	shipped-program=0	kernel[normal]
1	toyos-transport	packages=1	shipped-program=0	toyos-blockring[normal]
1	update	packages=0	shipped-program=1	
2	sprite	packages=2	shipped-program=0	compositor[normal], files[normal]
2	terminal	packages=1	shipped-program=1	console[normal]
2	toyos-acpi	packages=2	shipped-program=0	bootloader[normal], kernel[normal]
2	toyos-fat32-check	packages=2	shipped-program=0	toyos-build[normal], toyos-fat32[dev]
2	toyos-hda	packages=2	shipped-program=0	kernel[normal], soundd[normal]
2	toyos-net-ip	packages=2	shipped-program=0	toyos-dhcp[dev], toyos-net-udp[normal]
2	toyos-rootimage	packages=2	shipped-program=0	bootloader[normal], kernel[normal]
2	toyos-symbols	packages=2	shipped-program=0	kernel[normal], toyos-build[normal]
2	toyos-untrusted	packages=2	shipped-program=0	kernel[normal], toyos-transport[normal]
2	toyos-userbound	packages=2	shipped-program=0	kernel[normal], toyos-build[dev]
3	blockd	packages=2	shipped-program=1	fsd[normal], toyos-rust-tests[normal]
3	filepicker-api	packages=3	shipped-program=0	editor[normal], filepicker[normal], paint[normal]
3	toyos-blackbox	packages=3	shipped-program=0	bootloader[normal], kernel[normal], toyos-build[normal]
3	toyos-blockhold	packages=3	shipped-program=0	blockd[normal], kernel[normal], toyos-blockring[normal]
3	toyos-bootmap	packages=3	shipped-program=0	bootloader[normal], kernel[normal], toyos-acpi[normal]
3	toyos-dns	packages=3	shipped-program=0	netd[normal], toyos-mdns[normal], toyos-rust-tests[normal]
3	toyos-elide	packages=3	shipped-program=0	kernel[normal], logd[normal], toyos-symbols[normal]
3	toyos-i219	packages=3	shipped-program=0	netd[normal], toyos-build[dev], toyos-rust-tests[normal]
3	toyos-keymap	packages=3	shipped-program=0	toybox[normal], toyos-build[normal], toyos-window[normal]
3	toyos-sched	packages=3	shipped-program=0	kernel[normal], toyos-build[dev], toyos-sched-sim[normal]
3	toyos-xhci	packages=3	shipped-program=0	kernel[normal], toyos-build[dev], toyos-xhci-sim[normal]
4	bcachefs	packages=4	shipped-program=0	bootloader[normal], fsd[normal], kernel[normal], toyos-build[normal]
4	toyos-blockring	packages=4	shipped-program=0	blockd[normal], fsd[normal], init[normal], toyos-rust-tests[normal]
4	toyos-elf	packages=4	shipped-program=0	bootloader[normal], kernel[normal], toyos-build[normal], toyos-symbols[normal]
4	toyos-logstream	packages=4	shipped-program=0	console[normal], init[normal], logd[normal], toyos-build[normal]
4	toyos-net-wire	packages=4	shipped-program=0	toyos-dhcp[normal], toyos-net-ip[normal], toyos-net-tcp[normal], toyos-net-udp[normal]
4	toyos-quiesce	packages=4	shipped-program=0	init[normal], kernel[normal], toyos-build[normal], toyos-rust-tests[normal]
4	toyos-swap	packages=4	shipped-program=0	init[normal], ssh-client-host[normal], swap[normal], toyos-build[normal]
4	toyos-update	packages=4	shipped-program=0	bootloader[normal], init[normal], toyos-build[normal], update[normal]
5	toyos-fat32	packages=5	shipped-program=0	fsd[normal], kernel[normal], toyos-build[normal], toyos-rust-tests[normal], update[normal]
5	toyos-tmpdir	packages=5	shipped-program=0	pkg[dev], sshd[dev], toyos-build[normal], toyos-fat32[dev], toyos-ld[dev]
5	toyos-wallclock	packages=5	shipped-program=0	bootloader[normal], kernel[normal], logd[normal], toyos-build[normal], toyos-fat32[normal]
6	toyos-gpt	packages=6	shipped-program=0	blockd[normal], bootloader[normal], fsd[normal], init[normal], kernel[normal], toyos-build[normal]
6	toyos-inspect	packages=6	shipped-program=0	compositor[normal], inspect[normal], logd[normal], netd[normal], soundd[normal], toyos-rust-tests[normal]
6	toyos-manifest	packages=6	shipped-program=0	compositor[normal], init[normal], pkg[normal], shell[normal], toyos-build[normal], toyos-swap[normal]
7	toyos-tco	packages=7	shipped-program=0	bootloader[normal], kernel[normal], metalprobe[normal], netd[normal], test-runner[normal], toyos-build[normal], toyos-rust-tests[normal]
9	toyos-window	packages=9	shipped-program=0	compositor[normal], console[normal], editor[normal], filepicker[normal], files[normal], paint[normal], terminal[normal], toybox[normal], toyos-rust-tests[normal]
10	toyos-font	packages=10	shipped-program=0	calc[normal], compositor[normal], console[normal], editor[normal], filepicker[normal], files[normal], paint[normal], snake[normal], terminal[normal], toyos-window[normal]
21	toyos	packages=21	shipped-program=0	blockd[normal], compositor[normal], console[normal], filepicker-api[normal], filepicker[normal], fsd[normal], init[normal], inspect[normal], logd[normal], metalprobe[normal], netd[normal], shell[normal], soundd[normal], swap[normal], terminal[normal], test-runner[normal], toybox[normal], toyos-libc[normal], toyos-rust-tests[normal], toyos-window[normal], update[normal]
30	toyos-abi	packages=30	shipped-program=0	blockd[normal], bootloader[normal], compositor[normal], console[normal], fsd[normal], init[normal], inspect[normal], kernel-loom[normal], kernel[normal], logd[normal], metalprobe[normal], netd[normal], soundd[normal], test-runner[normal], toybox[normal], toyos-acpi[normal], toyos-bootmap[normal], toyos-build[normal], toyos-desktop[normal], toyos-inspect[normal], toyos-libc[normal], toyos-logstream[normal], toyos-manifest[normal], toyos-pci[normal], toyos-proclife[normal], toyos-rust-tests[normal], toyos-symbols[normal], toyos-window[normal], toyos[normal], update[normal]

Twelve crates have exactly one consumer, and it is another package: tls-dep, toyos-desktop, toyos-dma, toyos-gicv3, toyos-mdns, toyos-mixer, toyos-net-udp, toyos-pci, toyos-pcid, toyos-proclife, toyos-ps2 and toyos-transport. terminal counts 2: console, and itself. Every other count of 1 is a shipped program that no package names, which is its own one consumer and moves nowhere. The set is round 6's without terminal, so round 6's search of the fork clones and ~/.cargo/git/checkouts/ covered every name in it.

Lines. wc -l gives 60 for the no-panic track and 67 for the crate track.

@Japabu
Japabu added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit 63cb34a Oct 1, 2026
1 check passed
@Japabu
Japabu deleted the wt/toyos-prosebatch branch October 1, 2026 17:33
Japabu added a commit that referenced this pull request Oct 1, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
Japabu added a commit that referenced this pull request Oct 1, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
Japabu added a commit that referenced this pull request Oct 2, 2026
Three modify/delete conflicts, each hunk of this branch's side accounted for:

- tests/toyos-rust-tests/src/bin/log_hold.rs, deleted by 520c0d1: the one
  hunk moved its 192 records from syscall 26 to `SYS_DEBUG` `LOG_PATTERNED`.
  The binary and `log_program_line_after_its_records` are gone, so it goes.
- tests/common/origin.rs, deleted by 520c0d1: `staged_job`, `one_job` on it,
  `PATTERNED` in `RETIRED`'s place and `after_records` on the test kernel with
  its per-index count all served that one test. They go.
- issues/build/no-device-class-answers-for-a-block-device.md, deleted on main:
  the one hunk dropped "(3 and 4 are retired.)". It goes.

Content conflicts:

- tests/common/logstream.rs and tests/common/qemu.rs are main's: this branch's
  `stage_on_test_kernel`, `write_staged` and `build_test_kernel_image` had
  `origin::after_records` as their only caller.
- issues/build/the-boot-census-guesses-a-staged-images-kernel.md, which this
  branch filed against `build_test_kernel_image` and a staged
  `BootOptions::boot_image`, goes: main has neither.
- CLAUDE.md and .claude/agents/reviewer.md are main's: #673 landed this
  branch's half of both.
- issues/kernel/a-childs-end-is-an-event-and-a-parent-takes-its-children-down.md
  is main's: this branch's hunk edited stage 0, which #642 landed and deleted.
- issues/kernel/the-capability-end-state-is-twelve-answers.md: main deleted the
  sentence this branch's first hunk edited; the second hunk, which drops "85
  `SYS_LISTEN` and 87 `SYS_CONNECT` are retired numbers", is kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
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