diff --git a/.claude/agents/implementer.md b/.claude/agents/implementer.md index 4b1b82fc040..a4d1bb91c6a 100644 --- a/.claude/agents/implementer.md +++ b/.claude/agents/implementer.md @@ -55,7 +55,8 @@ Fork sources live outside this repository: a search for callers must also cover ## Commits and the pull request `git commit -F `, never `-m`. No `--amend`, no rebase, no force: merge `origin/main`, never -rebase onto it. Never touch `toyos-abi/src`, `toyos/src` or `userland/libc/src` unless the brief is +rebase onto it. Never run `git submodule` in a linked worktree: it writes `core.worktree` into the +fork's shared config and breaks git in the primary checkout's `rust/`. Never touch `toyos-abi/src`, `toyos/src` or `userland/libc/src` unless the brief is an ABI brief. No new dependency. Push from your branch, never `main`, with `git status --porcelain` empty: `git push -u origin diff --git a/.claude/agents/orchestrator.md b/.claude/agents/orchestrator.md index bf08cc0f1ad..f80b4948ae2 100644 --- a/.claude/agents/orchestrator.md +++ b/.claude/agents/orchestrator.md @@ -53,8 +53,10 @@ settles it and decide. Glance before every merge: the title and body as `main`'s record, the diff's size against the brief's fence, tests added or deleted, CI. Then `gh pr ready` and `gh pr merge --auto --merge`. -After a landing, sync the primary checkout. A red that is not about the diff is fixed at its -owner, never re-run away, and nothing but a defect may turn `main` red. +After a landing, sync the primary checkout. When a landing changes how agents work, every running +agent is told the new way in one line and merges main before its next round. +A red that is not about the diff is fixed at its owner, never re-run away, and nothing but a defect +may turn `main` red. A fix for a red lands ahead of feature work. A nightly name red three nights running gets an owner issue that day, and is deleted if nobody owns it a week later. diff --git a/.claude/agents/reviewer.md b/.claude/agents/reviewer.md index cdc50feddcb..c780b0dee34 100644 --- a/.claude/agents/reviewer.md +++ b/.claude/agents/reviewer.md @@ -50,11 +50,19 @@ above; otherwise it is a NOTE. `arch::aarch64` in no generic kernel code; and none of them in a crate whose manifest `description` says pure. A `4096` in the kernel that means a page is a private copy of `mm::PAGE_SIZE`. -- **Arrivals.** A binary outside Rust's toolchain, git, QEMU and this repository's own Rust is - refused, whether the host starts it — `Command::new`, `libc::system`, an `exec` or - `posix_spawn`, a tool a build script or `cc::Build` drives — or `.github/` installs it, by - whatever manager or `sh -c`. The ones that stand are those - `issues/build/python-and-cc-are-declared.md` declares. +- **Instructions.** A change that removes or renames a command, flag or step an agent runs updates + every prompt that names it — each `CLAUDE.md` and `.claude/agents/*.md` — in the same diff, + saying what to do instead. Such an instruction is not the prose "Prose is removed, never + reviewed" governs, and `CLAUDE.md`'s "Stale or false prose is deleted", "an agent edits one + only when briefed to" and "a `CLAUDE.md` never grows" do not bar the implementer updating it: + one left naming what is gone is a BLOCKER. +- **Arrivals.** A host tool outside Rust and QEMU arrives by `Command::new`, `libc::system`, + `exec`, `posix_spawn`, a build script or `cc::Build`, a `.github/` `run:` step or package + manager, or `sh -c`, and is declared in + `issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md` and nowhere else. A BLOCKER + each: an undeclared host tool; one, like Go's `gh`, not built from C or C++ source ToyOS can + one day build and run; a binary for one host OS alone; a C or C++ tool taken where a Rust tool + does the job; new Python, Perl or shell of ToyOS's own. A third-party action `main` does not use is refused, and every `uses:` pins a 40-hex commit with its tag in a trailing comment or names a local path that resolves. A file added to or deleted from `tests/testcases/tinycc/` moves the count diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 76c06a11952..558bcb2bfe1 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -176,9 +176,8 @@ jobs: key: guest-${{ github.run_id }} - *serial - # "Only Rust and QEMU", run rather than argued: `cargo run -- --build-only` - # from a fresh machine. `sid` as it stands, image and archive both, and no - # cache — a fresh machine is the premise. + # `cargo run -- --build-only` from a fresh machine. `sid` as it stands, + # image and archive both, and no cache — a fresh machine is the premise. portability-linux: runs-on: ubuntu-24.04 timeout-minutes: 350 diff --git a/CLAUDE.md b/CLAUDE.md index 117bca0825d..285817eedf0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -58,11 +58,11 @@ A subdirectory `CLAUDE.md` loads when a file in that subtree is `Read`, and not ## Dependencies -Only **Rust** and **QEMU** (for development), on any host OS and architecture — the development machine is nothing special. The rules: no binary outside those two — a macOS binary is a hard no, and "only for tests" does not soften it; only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; no Python; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: nothing — build, test, or verification — rests on a host binary. Ask of anything new: could this ever run inside ToyOS? Self-hosting means ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. +**Rust** and **QEMU** for development, on any host OS and architecture — the development machine is nothing special. Beside them, where no Rust tool does the job, only C or C++ tools ToyOS can one day build and run (Python, Perl, CMake, Ninja, make), each declared. No binary for one host OS alone: a macOS binary is a hard no, and "only for tests" does not soften it. ToyOS's own code is Rust; it writes no Python, Perl or shell of its own. Only general and widely used crates — one that does *our* job we write ourselves, and a driver crate never; third-party crates are used as published, and a fork carries a change written to upstream quality and goes when upstream has it. No upstream pull requests are sent for now: ToyOS needs more attention and more contributors before upstream projects take it seriously, and upstreams tend to refuse AI-first projects and their contributions. A third-party source ToyOS cannot build without changing it is carried as an unmodified-source packaging mirror with a byte-identity gate, not as a fork. The north star is **self-hosting**: nothing — build, test, or verification — rests on a host binary. Ask of anything new: could this ever run inside ToyOS? Self-hosting means ToyOS rebuilds itself on ToyOS and reproduces the host's bytes; a bootstrap from source with no binary seed is out of scope. Vendor firmware a device verifies by its maker's signature may be shipped: pinned by version and hash, redistributable unmodified, recorded in `NOTICE`, and loaded only by that device's own driver through its IOMMU domain; it never executes on the CPU. -The bar is not yet the tree. The standing failures are declared rather than removed — Python via `rust/x`, `cc` for every host link, two macOS FAT tools. `NOTICE` names every committed third-party file with its hash, upstream and licence; an image carrying `DOOM1.WAD` may not be sold. +The bar is not yet the tree: `.claude/agents/reviewer.md`, "Arrivals", says where every host tool and every standing failure is declared. `NOTICE` names every committed third-party file with its hash, upstream and licence; an image carrying `DOOM1.WAD` may not be sold. - **toyos-ld** — frozen: everything links with rust-lld, and toyos-ld stays only as the linker inside ToyOS until lld runs there, then goes. - **rust/** — Rust compiler/std fork with ToyOS platform support (submodule). Auto-bootstraps; kept current with upstream. Its rules: `.claude/agents/implementer.md`, "A fork". diff --git a/README.md b/README.md index 23e8468bd21..670bfac6b13 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ cargo run ``` One command, and a complete OS boots. No Make, no Docker, no LLVM to install, -no cross-toolchain to assemble, no system linker. Everything that boots is +no cross-toolchain to assemble. Everything that boots is built by a toolchain in this repository. Rust and QEMU, plus the four things `rustc`'s own bootstrap needs on every @@ -225,8 +225,7 @@ same font the kernel blits. - A C compiler on `PATH` as `cc`, and a Python 3 - CMake and Ninja -The last two lines are `rustc`'s and not ToyOS's, and nothing that boots touches -them. `rustc` links every **host** binary through `cc`, which rustup does not +`rustc` links every **host** binary through `cc`, which rustup does not install. `rust/x`, the entry point to rustc's own bootstrap, is a shell script whose whole job is to find a Python to run `bootstrap.py` with — so a clean clone needs one, and so does every toolchain change. And that bootstrap builds diff --git a/issues/build/python-and-cc-are-declared.md b/issues/build/python-and-cc-are-declared.md deleted file mode 100644 index cc45f0c0939..00000000000 --- a/issues/build/python-and-cc-are-declared.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -status: open -kind: tooling -opened: 2026-08-08 ---- - -# Every toolchain build runs Python, CMake and Ninja, and every host link runs `cc` - -**The owner ruled on 2026-08-08: *"its required by rusts toolchain i guess we can -be transparent about that."*** Both are named in the README's Prerequisites -section and by `check_prerequisites` in `src/main.rs`, which is now two lists — -`REQUIRED`, which exits (`git`, `rustup`, `qemu-system-x86_64`, `cc`), and -`ALSO_USED`, which names what is absent and continues (a Python, `df`, `ps`, -`find`). The README's opening no longer claims Rust and QEMU are the whole -setup. - -**The entry stays open because declaring is not removing.** The hole is the -same size: `bootstrap.py` still cannot run inside ToyOS, and the second option -below — a Rust bootstrap in the `rust/` fork — is still the only thing that -closes it. - -Two details the fix had to get right. The preflight looks for *any* of -`python3 python py python2 uv`, because that is what `rust/x` searches and a -machine with only `python` builds fine; and it scans `PATH` rather than running -`--version`, because asking macOS for `py` opens the Command Line Tools -installer. `cc` is stated with its scope attached wherever it appears — no guest -binary links through it — because *"ToyOS needs a C compiler"* is false and -reads as a far larger claim than the truth. - -This is the entry that says the two largest holes in *"Rust and QEMU, one -command"* are real, and what follows is the whole of both. - -**The owner ruled on 2026-09-01: it stays declaration-only, and it stays -open.** Closing the Python half means a Rust bootstrap inside the `rust/` fork — -a large delta carried against upstream forever, for no product benefit today. -That is a real cost and this is a real hole, so the entry is not downgraded: it -remains a present-state weakness on the self-hosting track, to be sequenced when -that track is funded rather than taken opportunistically. Do not propose the -Rust bootstrap again as an incidental fix; do not soften the entry either. - -`src/toolchain.rs:749` picks `./x` when `rust/x` exists, which it does. That file -is a `/bin/sh` script whose whole job is `SEARCH="python3 python py python2 uv"`, -and it execs `x.py` → `rust/src/bootstrap/bootstrap.py`. So a clean -clone cannot build a toolchain without Python 3. It is upstream's bootstrap and -not our code, which is why it is stated rather than blamed — but the bar has no -upstream exemption, and `bootstrap.py` can never run inside ToyOS. - -Separately, and measured with `rustup run toyos rustc --print link-args` on a -trivial host binary: rustc invokes `"cc"` and sets -`SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk`. rustup installs -neither. Every *host* binary goes through it — the build system, the harness, -`toyos-ld`, rustc stage2, clang. **No guest binary does**: every guest binary -links through the toolchain's `rust-lld`, so nothing that boots is touched. - -The cheap half of the fix — a preflight and a README that say what the machine -actually needs — is done. `REQUIRED` carries `cc` and `ALSO_USED` carries the -Python search list (`src/main.rs:18`, `:28`). The expensive half is untouched. - -**CMake and Ninja joined the list on 2026-09-27, by the owner's ruling**: rustc's -LLVM is built from source, from `ToyOSOrg/llvm-project`, with clang beside it, -and rustc's bootstrap builds LLVM with CMake driving Ninja. Both are declared -where the others are — CMake in `REQUIRED` in `src/main.rs`, because every -build keys the host's LLVM on `cmake --version` (`src/llvm.rs`), and Ninja in -`ALSO_USED`, because a build whose LLVM this host has already built runs it -not — and in the README's Prerequisites. On macOS they come from Homebrew (`brew install cmake ninja`), -with no workaround; on the nightly's toolchain runner at the versions -`.github/workflows/nightly.yml` pins from Ubuntu 24.04's archive (`cmake -3.28.3-1build7`, `ninja-build 1.11.1-2`); the two portability jobs install -their platform's own, which is their premise. Neither reaches a guest. The -exit condition is Python's: they go when the build no longer needs a host, -which is the self-hosting track's last stage -(`issues/build/toyos-builds-itself.md`). - -**What removing each takes.** - -- **Python.** Upstream has no Python-free entry: `x`, `x.py` and - `src/tools/x` all end in `bootstrap.py`. But `src/bootstrap` builds with - rustup's stable cargo, `--locked`, and no Python, and the binary downloads - its own stage0 (`download_beta_toolchain`) and looks for a Python only to run - tests. So `src/toolchain.rs` could build and run it in place of - `bootstrap.py`, with no change to the fork, taking over `bootstrap.py`'s - environment contract at every fork bump. That removes Python only from a - build that reuses a keyed LLVM: LLVM's own CMake requires a Python 3 - (`find_package(Python3 … REQUIRED)`), so building an LLVM needs one until CMake goes. -- **`cc` has two jobs**: it links every host binary, and it is - the C++ compiler of LLVM, clang, LLD and `rustc_llvm` (`bootstrap.toml`'s - `cc`/`cxx`, named in `src/llvm.rs`, with `xcrun` asked for the SDK). It also - compiles `ring`'s C for `tests/https-server-host` and - `tests/https-fetch-host`. `rust-lld` can take only the link. Nothing replaces the compile but a clang the host did not build. -- **CMake and Ninja.** LLVM, clang and LLD are described in CMake. The only other build - descriptions upstream carries are an unsupported GN overlay (`BUILD.gn`) - and a Bazel one. Replacing CMake means writing one of those and keeping it - in Rust, which is M5's. - -**Every other binary outside Rust and QEMU that this tree runs is declared -here too**, because a reviewer refuses any one that is not -(`.claude/agents/reviewer.md`, Arrivals). `newfs_msdos` and `hdiutil` are -`issues/filesystem/fat32-suite-needs-macos-binaries.md`'s, and `diskutil` and -`plutil` are `issues/build/the-owners-flash-script-runs-diskutil.md`'s. - -- **`gh`** — `src/release.rs` asks GitHub whether a toolchain release exists, - creates it and moves the `sdk-` alias with it, on a runner only. - Exit: `src/release.rs` speaks GitHub's REST API itself. -- **`curl`**, and **`ca-certificates`**, the trust store it verifies against — - `src/release.rs` downloads the toolchain release, `src/sdkversion.rs` asks - the crates.io index, and the nightly's container and macOS jobs fetch - `rustup-init.sh` with it. Exit: those fetches are Rust's, and a job - installs rustup without it. -- **`tar`** and **`zstd`** — `src/release.rs` packs and unpacks the toolchain - release. Exit: both are done in Rust, in-process. -- **`ssh`** — `src/metal.rs` reaches the T14's Ubuntu with it, only when the - metal loop is asked for. Exit: that loop drives the repository's own russh - client, `crate::build::ssh_client_host`, which `src/metaltalk.rs` already - drives at a booted T14. -- **`ovmf-generic`** — the guest container's UEFI firmware - (`src/firmware.rs`), which Debian packages apart from QEMU. Exit: the - instrument's QEMU carries its own firmware. -- **`build-essential`** — Debian's package for `cc` and `c++`, which the - nightly's guest containers and `portability-linux` install: every host - binary those jobs build links through `cc`, `ring`'s C compiles with it, and - `portability-linux` builds LLVM with `c++`. Exit: it goes with `cc`. diff --git a/issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md b/issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md new file mode 100644 index 00000000000..77ff0585707 --- /dev/null +++ b/issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md @@ -0,0 +1,49 @@ +--- +status: open +kind: tooling +opened: 2026-09-29 +--- + +# The build runs host tools outside Rust and QEMU + +Every tool `main`'s build, tests, workflows and metal loop run outside Rust and +QEMU, and every one `diag/flash.sh` and the README's flashing steps run by hand, +with the verdict of `CLAUDE.md`'s Dependencies on each; a refused row is a +standing failure. A workflow's package manager, `apt-get` or `brew`, is how a row +arrives and is not one. M4 and M5 are stages of `issues/build/toyos-builds-itself.md`. + +| tool | runs | verdict | exit | +|---|---|---|---| +| Python | LLVM's CMake, whenever this host builds an LLVM (`src/llvm.rs`) | admitted: no Rust tool does the job, LLVM's CMake requires one (`find_package(Python3 … REQUIRED)` in `rust/src/llvm-project/llvm/CMakeLists.txt`) | M5 runs it in the guest | +| CMake | rustc's bootstrap, for LLVM and clang; `src/llvm.rs`, for the LLVM's key | admitted: no Rust tool does the job, LLVM, clang and LLD are described in CMake, and upstream's only other descriptions are a GN overlay it does not support and a Bazel one | M5 runs it in the guest | +| Ninja | runs the build CMake generates for LLVM | refused: a Rust tool does it, n2 (`github.com/evmar/n2` at `b1fead5`), named `ninja` as its README directs for CMake: CMake's Ninja generator configured `rust/src/llvm-project/llvm` for it and it built `llvm-tblgen`, exit 0 each; named `n2`, CMake refuses its version, exit 1 | rustc's bootstrap builds LLVM under n2 | +| `git` for worktrees, submodules, checkouts, fixtures and rustc's bootstrap | adds, removes and prunes worktrees (`src/worktree.rs`, `src/sysroot.rs`); updates submodules (`src/lib.rs`, `src/sysroot.rs`, `src/licence.rs`, `src/release.rs`); fetches the fork from the primary's and checks it out (`src/sysroot.rs`); fast-forwards the primary (`src/sync.rs`); makes the tests' fixture repositories; runs inside rustc's bootstrap | admitted: no Rust tool does the job, gitoxide 0.85 adds, removes and prunes no worktree, updates no submodule, stages, resets and pushes nothing, checks out only a fresh clone and fetches a local path by spawning `git`; a fixture must be what `git` makes, and bootstrap runs `git` itself | M4 runs it in the guest | +| `git` for reads, a config write, and clones and fetches over HTTPS | `rev-parse`, `show-ref`, `for-each-ref`, `rev-list`, `log`, `branch --contains`, `merge-base`, `ls-tree`, `ls-files`, `cat-file`, `config --get-regexp`, `worktree list`, `status`, `diff`, `ls-remote` and `grep`, in the build system and its tests; `config --global --add safe.directory` in the nightly's containers; `src/sync.rs`'s fetch of `origin`; every workflow's checkout | refused: a Rust tool does it, gitoxide 0.85, which reads refs, objects, the index, config, worktrees and status, adds a value to a config file and writes it (gix-config 0.58's `File::section_mut_or_create_new`, `SectionMut::push`, `File::write_to`), walks history, diffs, and lists, fetches and clones a remote over HTTPS; `grep` is a search of the files its index names | those are gitoxide's | +| `cc`, `c++` and `ar` on a Linux host, `build-essential` on the nightly's runners | rustc links every host binary through `cc`; `cc` and `c++` compile LLVM, clang, LLD and `rustc_llvm` (`src/llvm.rs` names both to bootstrap) and `ring`'s C for `tests/https-server-host` and `tests/https-fetch-host`; `ar` archives what `cc::Build` compiles | admitted: no Rust tool compiles C or C++, or takes rustc's host link | M5: no host in the loop | +| the toolchain's own `clang`, `llvm-ar`, `rust-lld` and `llvm-config`, built from `ToyOSOrg/llvm-project` | rustc links every guest binary with `rust-lld`; `clang` compiles the C corpus and `hello.c` (`tests/common/compile.rs`, `tests/common/clang.rs`) and, with `llvm-ar`, doomgeneric through `cc::Build` (`src/clang.rs`); rustc's bootstrap asks `llvm-config` how to link LLVM | admitted: our fork's C++, which ToyOS can one day build and run; no Rust tool compiles C, `cc::Build` archives with an `ar`, bootstrap reads LLVM through `llvm-config`, and `CLAUDE.md` links everything with `rust-lld` | M5: no host in the loop | +| `ovmf-generic` | the UEFI firmware of the nightly's guest containers (`src/firmware.rs`), packaged by Debian apart from QEMU | admitted: QEMU's own firmware, and no Rust firmware does its job | the instrument's QEMU carries its own firmware | +| `ca-certificates` | the trust store `git` and `curl` verify against in the nightly's containers | admitted: data both of them need | goes when neither runs there | +| `env` | the two portability jobs run `cargo run -- --build-only` under it, with `GITHUB_ACTIONS` and `CI` unset | refused: a Rust tool does it, the build system, which already runs that build with both removed (`src/release.rs`) | the build system removes both itself | +| the T14's Ubuntu and every tool `src/metal.rs` runs on it over `ssh` | the metal loop, on the T14 and never on a development host | outside the rule: recovery equipment on a test machine, not the build's host | they leave with Ubuntu (`issues/boot-media/the-machine-updates-itself-without-ubuntu.md`) | +| `sh` running `rust/x`, and Python running `x.py` and `bootstrap.py` | every toolchain build (`src/toolchain.rs`) | refused: a Rust tool does it, upstream's bootstrap binary, which builds with stable cargo, fetches its own stage0 (`rust/src/bootstrap/src/core/download.rs`) and needs no Python | `src/toolchain.rs` runs the bootstrap binary | +| `curl` in rustc's bootstrap | fetches the stage0 `rust/src/stage0` pins, for a compiler or LLVM build whose build directory lacks it, whichever bootstrap runs | refused: a Rust tool does it, rustup installs the dated beta the pin names, and bootstrap takes a stage0 through `build.rustc` and `build.cargo`, as `src/sysroot.rs` hands it one | no toolchain build fetches with `curl` | +| `curl` in `src/release.rs` and `src/sdkversion.rs` | the toolchain release's lookup and download and the crates.io index, on CI runners only | refused: a Rust tool does it, `ureq`, which `userland/doom/build.rs` already fetches with | those fetches are Rust's | +| `tar` and `zstd` | `src/release.rs` packs and unpacks the toolchain release, on CI runners only | refused: a Rust tool does it, the `tar` crate `userland/doom/build.rs` already unpacks with, and a zstd crate | both are done in Rust, in-process | +| `gh` | `src/release.rs` asks whether a toolchain release exists, creates it and moves the `sdk-` alias, on the nightly's `build` runner | refused: not C or C++ source, it is Go | `src/release.rs` speaks GitHub's REST API itself | +| `ssh` | `src/metal.rs` reaches the T14's Ubuntu with it, only in the metal loop | refused: a Rust tool does it, the repository's own russh client `crate::build::ssh_client_host`, which `src/metaltalk.rs` already drives | `src/metal.rs` drives that client, or Ubuntu leaves the loop | +| `cc`, `c++`, `ar` and `xcrun` on a macOS host, Apple's Command Line Tools | what the Linux row's tools do, and rustc asks `xcrun` for the SDK on every host link that names no `SDKROOT` (`rust/compiler/rustc_codegen_ssa/src/back/apple.rs`), as `src/llvm.rs` does for the LLVM's key | refused: one host OS alone | M5: no host in the loop | +| `newfs_msdos` and `hdiutil` | `toyos-fat32`'s host tests format and mount their fixtures with them (`toyos-fat32/tests/common/mod.rs`), which keeps the `host` job on `macos-latest` | refused: one host OS alone | `issues/filesystem/fat32-suite-needs-macos-binaries.md` | +| `diag/flash.sh` | the owner's flash of a stick by hand: `bash`, and the `stat`, `seq`, `tr`, `grep`, `cut` and `sync` it strings together | refused: shell of our own | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `diskutil` and `plutil` | `diag/flash.sh`, and `diskutil` in the README's flashing steps | refused: one host OS alone | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `shasum`, a Perl script on macOS | `diag/flash.sh` hashes the image with it | refused: a Rust tool does it, `sha2`, which `src/release.rs` hashes with | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `lsblk` | the README's Linux flashing steps find the stick with it | refused: one host OS alone | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `dd` | `diag/flash.sh` and the README's flashing steps write the stick with it | refused: a Rust tool does it, the build system can write the image itself | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `sync` | the README's Linux flashing steps flush the stick with it | refused: a Rust tool does it, the build system can flush what it writes | `issues/build/the-owners-flash-script-runs-diskutil.md` | +| `sudo` on macOS | `diag/flash.sh` and the README's macOS flashing steps run `dd` under it | admitted: no Rust tool raises a process to root on macOS; sudo-rs "is targeted for FreeBSD and Linux-based operating systems only" (its README at `89bae8a`) | goes with both flashes by hand | +| `sudo` on Linux | the README's Linux flashing steps run `dd` under it | refused: a Rust tool does it, sudo-rs | the README's Linux steps run sudo-rs | +| `sh` running rustup's `rustup-init.sh` | the nightly's three rustup installs, fetched with `curl` | refused: a Rust tool does it, rustup's own `rustup-init` binary | a job installs rustup without it | +| `nightly.yml`, job `build`, step "disk, QEMU, CMake and Ninja" | `sudo rm -rf` of five preinstalled SDK directories, then `sudo apt-get update` and `install` | refused: shell of our own | each step is one command | +| `nightly.yml`, step `deps`, which jobs `guest` and `tcg` share | the snapshot archive read out of `debian.sources` with `sed`, checked with `test` and written back with `echo` and `rm`, a three-attempt `apt-get` loop with `sleep` and `cat`, `git config`, and rustup through `curl`, `sh` and `echo` | refused: shell of our own | each step is one command | +| `nightly.yml`, job `portability-linux`, step "deps" | the same loop, `git config`, and rustup the same way | refused: shell of our own | each step is one command | +| `nightly.yml`, job `portability-macos`, the rustup step | `curl`, `sh rustup-init.sh`, and `echo` into `$GITHUB_PATH` | refused: shell of our own | each step is one command | +| `umask 077 && cat > ` | `src/metal.rs` stages the sudoers rule on the T14 with it | refused: shell of our own | Ubuntu leaves the metal loop | diff --git a/issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md b/issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md new file mode 100644 index 00000000000..96b22d6b0f2 --- /dev/null +++ b/issues/build/the-fork-checkout-runs-git-submodule-in-a-linked-worktree.md @@ -0,0 +1,27 @@ +--- +status: open +kind: tooling +opened: 2026-09-30 +--- + +# The fork checkout runs `git submodule` in a linked worktree + +`sysroot::fork_checkout` makes a worktree's `rust/` a linked worktree of the +primary's `rust` (`git worktree add --detach`). When the primary's +`library/backtrace` lacks the commit the fork pins, it runs +`git submodule update --init library/backtrace` inside that linked worktree, +which `.claude/agents/implementer.md` forbids: `git submodule` in a linked +worktree writes `core.worktree` into shared config and breaks git in the +primary checkout's `rust/`. The orchestrator measured that for +`git submodule update rust` in a linked worktree of the monorepo, which set the +primary's `.git/modules/rust/config` `core.worktree` to a path that does not +exist; this arm is the same command one level down and is unmeasured. + +`ensure_submodule` (`src/lib.rs`) runs `git submodule update --init +library/backtrace` in the same fork checkout, from `sysroot::build_std` and +`compiler::build_in_fork`, whenever that checkout's `library/backtrace` is +empty or gone: what a first `fork_checkout` leaves when it stops after adding +the fork's worktree and before adding `library/backtrace`. + +**Exit**: the build system runs no `git submodule` in a linked worktree's fork +checkout. diff --git a/issues/build/the-owners-flash-script-runs-diskutil.md b/issues/build/the-owners-flash-script-runs-diskutil.md index 120ea0913cd..fbdefbdda12 100644 --- a/issues/build/the-owners-flash-script-runs-diskutil.md +++ b/issues/build/the-owners-flash-script-runs-diskutil.md @@ -4,12 +4,12 @@ kind: tooling opened: 2026-09-29 --- -# The owner's flash script runs `diskutil`, and no ledger declares it +# The owner's flash script runs `diskutil` `diag/flash.sh` writes an image to a USB stick through `diskutil` and `plutil`, which are macOS binaries, and through `shasum`, `dd` and `sudo`. The README's -flashing steps also run `diskutil`. None of these is in CLAUDE.md's standing -failures. The metal loop does not use this script: it flashes +flashing steps also run `diskutil`, `dd` under `sudo` on both hosts, and `lsblk` +and `sync` on Linux. The metal loop does not use this script: it flashes the T14's stick over `ssh` from Ubuntu. The script's two gates are what keep it off an internal drive: it takes only @@ -17,5 +17,6 @@ disks that `diskutil list external physical` names, and it writes only to a disk that reports `Internal=false` and `BusProtocol=USB` on its own account. A replacement keeps both. -**Exit**: `rg -l "diskutil|plutil"` over the tree outside `rust/` finds nothing, and -the build system writes the stick. +**Exit**: `rg -l "diskutil|plutil"` over the tree outside `rust/` finds nothing, the +README's flashing steps run no `lsblk`, `dd` or `sync`, and the build system +writes the stick. diff --git a/issues/build/toyos-builds-itself.md b/issues/build/toyos-builds-itself.md index f784c60c289..06e3fd75fa6 100644 --- a/issues/build/toyos-builds-itself.md +++ b/issues/build/toyos-builds-itself.md @@ -35,9 +35,9 @@ AArch64 one step behind, on `issues/kernel/toyos-runs-on-arm64.md`'s track. bytes equal the host's. *Exit*: a guest build of the image whose hashes match the host build of the same commit. - **M5 — ToyOS rebuilds its own compilers to a fixed point; the host is no - longer needed.** The guest's toolchain builds the next toolchain, and that - one builds itself again to the same bytes. Python (`bootstrap.py`), CMake and - Ninja leave the build (`issues/build/python-and-cc-are-declared.md`). + longer needed.** The guest's toolchain builds the next toolchain, its LLVM + with Python and CMake built for ToyOS, and that one builds itself + again to the same bytes. *Exit*: the fixed point, reached with no host in the loop. **Blocked on other tracks.** M2 needs packages over HTTPS diff --git a/issues/filesystem/fat32-suite-needs-macos-binaries.md b/issues/filesystem/fat32-suite-needs-macos-binaries.md index e5aae9c72d2..0606aefe00a 100644 --- a/issues/filesystem/fat32-suite-needs-macos-binaries.md +++ b/issues/filesystem/fat32-suite-needs-macos-binaries.md @@ -9,9 +9,7 @@ opened: 2026-08-08 **The judge is ours as of 2026-08-08.** `fsck_msdos` is gone from all three places it was used — `src/image.rs`, `tests/common/volumes.rs` and `toyos-fat32/tests/common/mod.rs` — replaced by `toyos-fat32-check/`, written -from fatgen103 and derived from neither our writer nor our reader. The owner's -rule that made that mandatory: "no dependencies on binaries that dont come with -rust or qemu". The stale FAT mirror and duplicate 8.3 names, both of which +from fatgen103 and derived from neither our writer nor our reader. The stale FAT mirror and duplicate 8.3 names, both of which `fsck_msdos` silently accepted, are among the twelve corruptions the new checker catches and it did not. diff --git a/src/main.rs b/src/main.rs index 8b1afe6d8a4..3ed298f68d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,7 +36,7 @@ const REQUIRED: &[Tool] = &[ /// `rust/src/llvm-project` with, under CMake, which it does only when this /// host has not built that LLVM. Both are host tools like `cc`, and never in a /// guest: on macOS from Homebrew, on CI's toolchain runner at the versions -/// `.github/workflows` pins. They go when the build no longer needs a host. +/// `.github/workflows` pins. const ALSO_USED: &[Tool] = &[ Tool { any: &["python3", "python", "py", "python2", "uv"],