Skip to content

The host's toolchains live in one store outside every checkout, and every compiler is keyed - #769

Merged
Japabu merged 11 commits into
mainfrom
wt/toyos-pinfile
Oct 8, 2026
Merged

Japabu merged 11 commits into
mainfrom
wt/toyos-pinfile

Conversation

@Japabu

@Japabu Japabu commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Every LLVM, compiler and sysroot on a host becomes a product of one store outside every checkout, and no checkout's compiler is special. This is the first step of moving the rust fork's pin into a file; the rest is the track issues/the-forks-pin-is-a-file-and-a-worktree-checks-no-fork-out.md, filed here.

At 9a7d15900, on a merge of origin/main d83ab1398. The production code is b7cb92153's: git diff --name-only b7cb92153 9a7d15900 is src/CLAUDE.md (one sentence), three files under issues/, and one test line each in src/compiler.rs and src/keystore.rs, both inside mod tests; no key reads any of them. Those two lines are what CI's first host run was red on, at b83eb464b (run 37794832085, clippy, warnings denied: a redundant clone and an unchecked Duration subtraction, which this host's older clippy raises neither of). At b7cb92153 the toolchain was built into the store, the same build again built nothing, a second worktree found every product, and the std type-check recipe ran; at 3def81032, which differs from this head by one issue file and those two test lines, the whole guest suite is green on that toolchain with target/.deps-stamp byte-equal to b7cb92153's. cargo run -- --ci host and CI's toolchain path are CI's, read on the ready pull request. What is and is not measured is the last section.

Net against origin/main (git diff --shortstat origin/main...9a7d15900): 43 files, +1213 −2355. Rust: 12 files, +882 −2098. Split at each changed .rs file's first #[cfg(test)]: production 6360 → 5675 lines (−685), tests 8187 → 7656 (−531).

What changed, per decision

  • The store (src/keystore.rs). ~/.cache/toyos (owner: "Yes, store in ~/.cache/toyos (Recommended)"), and nothing in the environment names another. llvm/<key>, compilers/<key>, freestanding/<key>, sysroots/<key>, and the key locks in locks/<kind>/<key>, which were in the repository's git directory and so were per clone. Every function that took the primary's rust/ as where products live takes the store instead; tests pass a temporary directory, so no host test touches the real one.
  • Every compiler is keyed (src/compiler.rs, src/toolchain.rs). What its key reads of the fork is compiler::KEYED, listed under the second review below. The primary's in-place stage2, its toyos-compiler record, Compiler::primary, the global lock, buildlock::Scope, compiler_shared, global_exclusive and the bootstrap decisions (Bootstrap, runs, reassemble, rebuild_compiler, full_bootstrap, write_config) go. The primary resolves its compiler by key, as a worktree does; whichever checkout first names a key builds it in its own fork checkout and places it by rename.
  • The two drops (owner, of the in-place hosted rustc build and the rustup link: "Drop both for now (Recommended)"). The hosted rustc's build, the hosted-rustc key, collect_hosted_rustc and the licence refusal that guarded it go, and build::shipped no longer fails. issues/nothing-builds-the-toyos-hosted-rustc.md replaces the two issues that described the old build and carries what they owed. rustup toolchain link toyos goes on dev hosts and on runners: every build names its sysroot by directory.
  • The sweep (orchestrator: 14 days). A use or a make dates the key's lock file, and a sweep, which every placement runs for its kind, takes a product nothing has used for 14 days and nobody is making or using, deciding under the key's lock. The records, their writer and git worktree list go, and llvm::held with them.
  • LLVM's stamp (owner: "Yes, pin it (Recommended)"). llvm::config_text sets LLVM_FORCE_VC_REVISION to the gitlink's commit and LLVM_FORCE_VC_REPOSITORY to the URL the fork's committed .gitmodules names.
  • The fork's URL text. Fork commit 6d6ad8c7190, on main of ToyOSOrg/rust, appended on cc9c8b1be68: every changed line a URL, from a personal account to the organisation. The gitlink moves to it.
  • CI (src/release.rs). A runner's store is rust/build in its checkout, named by release::store and by nothing in the environment. toolchain.yml and guest.yml are unchanged.

The first review's findings, and what the round after it did

  1. The red at 9552f5e3a. Reproduced, and narrowed to a holder that exists only while other test threads run and lives under 3 ms; lsof named no holder at any red, so the holder's identity at a red is inferred, not read. The measurement is the section "The loop" below.
    • The mechanism, staged, which is not the red's cause read at a red. A test of the loop's patch holds a child between its fork and its exec while the test process drops a key's lock. After the drop the key was still held; lsof on the lock file named one holder, the child (pid 88324, command still the test binary; the test process was 88323); after the child's exec the key was free. light2/mechanism.log, EXIT=0. So a descriptor copied into a child not yet exec'd does hold a key's lock past its owner's drop on this host.
    • The tests, restructured either way, since src/buildlock.rs's tests forbid asserting free a lock this process held: a_product_used_again_is_kept decides a used and an unused product in one sweep; an_llvm_is_swept_once_nothing_used_it_for_the_keep_time sweeps once, after its user let go (its "a use by b dates it again" step is cut, which a_product_used_again_is_kept holds for every kind, llvm::choose having no dating of its own); a_sweep_removes_…'s last sweep, which showed only what its unused product already shows, is cut. No assertion in the tree now needs a sweep to take a key whose lock an earlier sweep of the same process held; a_sweep_removes_…'s second sweep still meets two such keys, and their skip changes no asserted result.
  2. compiler::place's refusal had no test. a_compiler_whose_sources_moved_while_it_was_built_is_not_stored: a stand-in build edits and commits compiler/ before returning; the refusal is asserted, and that compilers/ holds only <key>.partial. Mutation m4 deletes the assert! and reds it.
  3. Root CLAUDE.md names what a build may have to wait out in place of the global lock: a key's lock in the host's store, or its worktree's.
  4. A product names no checkout. A stored compiler carried bootstrap's lib/rustlib/src/rust and lib/rustlib/rustc-src/rust, links to the fork checkout that built it, and every sysroot cloned them; SOURCES recorded that path. compiler::place drops the two links, and SOURCES is the key and the witness. By reading (rustc_session/src/config.rs, real_source_base_dir; rustc_metadata's decoder): rustc reads either link only to translate a library source's path to or from its remapped form, which needs remap-debuginfo or -Z simulate-remapped-rust-src-base, and neither configuration here sets one; src/CLAUDE.md's std type-check names its sources by __CARGO_TESTS_ONLY_SRC_ROOT. Mutation m5 keeps the links and reds one_compiler_per_key_whichever_checkout_names_it.
  5. TOYOS_STORE and XDG_CACHE_HOME are removed, with their test.
  6. sysroot::publish retires a refused sysroot, as llvm::place does.
  7. A compiler's key reads library/ (orchestrator's ruling: fixed here). The stage2 a store keeps carries a std for the host, built from the fork's library/, which every guest crate's build scripts and proc macros link; the key read none of it, so a fork commit moving only library/ kept a compiler with the std of the commit before. KEYED gains library; every_source_of_a_compiler_moves_its_key holds it and mutation m6 reds it. The cost: a fork commit that moves std now builds a compiler too. By the phases of one build on an idle host, 5:19 on top of the 2:14 and about 1:30 such a commit already costs, so about 9 minutes against 3:45; an estimate from those phase times, no library/-only commit was built. A runner pays its compiler layer cold for such a commit.
  8. Issues. Closed, exits met: the-primary-rebuilds-its-compiler-on-compiler-alone (every_source_of_a_compiler_moves_its_key, for every checkout) and a-finder-file-in-a-store-directory-panics-its-sweep (a_sweep_leaves_hidden_names_and_refuses_names_no_key_owns; its rule is in src/keystore.rs's header). Corrected: the fixture issue's citation, and the two cargo +toyos commands. The track is the orchestrator's. Filed: issues/the-primary-still-holds-the-toolchain-nothing-reads-any-more.md (below), and issues/two-refusals-of-a-product-whose-sources-moved-have-no-test.md, for sysroot.rs's build and build_freestanding, which run bootstrap inline so that no test can stand in for it.
  9. src/CLAUDE.md loses the sentence describing the store. The stage1-std caveat stays out, by the code: the only build that writes a stage1-std is compiler::build_in_fork (stage 2; sysroot::build_std is stage 0 and LLVM's builds no std), reached only through compiler::place, which holds buildlock::worktree_exclusive(root) around it and builds in <root>/rust/build/toyos-compiler; so no two builds this build system starts write one stage1-std. Not measured.

The second review's findings, and what this round did

  1. The compiler's key reads what runs and versions its build. KEYED gains the fork's root Cargo.toml (the workspace the compiler is compiled in, its profiles and its [patch.crates-io]), src/version (the release bootstrap gives rustc), src/ci/channel, src/build_helper (bootstrap's path dependency outside src/bootstrap), and the two launchers toolchain::x_build_with runs, x and x.py, which the review did not name. Each has a case in every_source_of_a_compiler_moves_its_key and a mutation (m7 to m12). src/ci/channel is keyed because bootstrap reads it and refuses without it; its content reaches a build only from a tarball, since a git checkout with no rust.channel is dev (the stored a3df641184b6a414 prints rustc 1.99.0-dev, commit-hash: unknown), so the fork's HEAD is no input either.
    What else x.py build --stage 2 compiler/rustc library reads, checked in the fork at 6d6ad8c7190 and not keyed, by reading bootstrap and the lockfile:

    • src/llvm-project/compiler-rt (the host std's builtins) and src/bootstrap: named through the LLVM's key, which is part of the compiler's.
    • src/librustdoc, src/rustdoc-json-types, src/doc, src/etc, src/gcc, tests/, the licence files, license-metadata.json: read by steps this build does not run; a stored stage2/bin holds rustc and cargo and no rustdoc.
    • src/rustc-std-workspace: workspace members with no dependent in Cargo.lock.
    • .gitmodules: decides which submodules bootstrap updates, nothing of what it compiles.
    • The worktree's toyos-abi, which the workspace patches in by path: a dependency only under cfg(target_os = "toyos") in each fork that names it (getrandom twice, libloading, stacker; read in ~/.cargo/git/checkouts), so a host-only build resolves its manifest and compiles none of it. The same holds for library/std's toyos-abi and toyos.
    • bin/cargo, a link to the host's own cargo: provisioning, not a product of the build.
    • Two inputs outside the fork that the key does not name, filed as issues/a-compilers-build-reads-an-environment-and-a-cargo-configuration-its-key-does-not-name.md: bootstrap gets the caller's whole environment where the LLVM build gets PATH and TMPDIR, and cargo, run in <worktree>/rust, reads the worktree's .cargo/config.toml and through it the untracked local.toml a fork clone under edit is listed in. Both are main's shape; the host's store widens who is served. Owner: the track's step that builds from an export.
    • The LLVM's key still names only src/bootstrap of bootstrap, not src/build_helper, x or x.py: left, because naming them moves every LLVM key, and filed as issues/an-llvms-key-names-of-bootstrap-only-src-bootstrap.md with the track's first step, which moves every key anyway, as owner.
  2. The key is read under the worktree's shared lock. compiler::resolve reads it before without_shared, with the reason at the site, so no bootstrap of the same worktree has the fork's lockfiles rewritten while it is read. No test: observing the lock during the read needs the key's reader passed in, a parameter that would ship for the test alone.

  3. A compiler's build directory starts clean for another build or LLVM, done instead of filed. compiler::place calls sysroot::forget_another_compiler, the function the std build directory already has, with the build text and the LLVM's key: rust/build/toyos-compiler is emptied of all but bootstrap's downloads unless its compiled-by records both. A source edit alone keeps the directory. a_build_directory_another_llvm_filled_starts_from_nothing holds both halves and mutation m13 reds it. The cost: the first compiler build in every existing build directory is cold, and so is each one after a change of RECIPE, the bootstrap configuration, the provisioned tools or the LLVM; this round paid it once, 4:06 by bootstrap's own timing against the 13 s of the round before.

  4. issues/two-refusals-of-a-product-whose-sources-moved-have-no-test.md is owned by the track's step that rewrites the std build ("A pinned build reads an export").

  5. The std type-check recipe, run, and its sentence corrected. Against ~/.cache/toyos/sysroots/8618c089fa736cb0, in a scratch crate, __CARGO_TESTS_ONLY_SRC_ROOT=<root> RUSTUP_TOOLCHAIN=<sysroot> CARGO_TARGET_DIR=<scratch> cargo build -Z build-std=std,panic_abort --target x86_64-unknown-toyos --offline, with three source roots (pinfile-r2/heavy/typecheck-{A,B,C}.log):

    the source root exit
    A the sentence as it stood: a tree with a copy of rust/library and a written workspace Cargo.toml naming library/std 101
    B the same with five members and library/Cargo.toml's four patches, as issues/the-build-system-does-not-compile-on-windows.md spells it 101
    C the copied library itself, no manifest written 0, Finished in 14.62 s, a libstd-*.rlib left

    A and B fail alike, before compiling anything: failed to select a version for the requirement moto-rt = "^0.16", version 0.16.4 is yanked. A written manifest has no lockfile, so cargo resolves std's dependencies afresh, and offline the only candidate is yanked; the copied library's own Cargo.lock pins it. So the sentence was false before this branch respelled it, and that the sysroot lost lib/rustlib/src/rust is not why: C runs without it. src/CLAUDE.md now words C, and so does the judge of issues/the-build-system-does-not-compile-on-windows.md, whose manifest was B (the third review, below).

  6. Body prose: the sentence about in-process sweeps is corrected above, and the opening no longer says "Draft".

The third review's findings

  1. issues/the-build-system-does-not-compile-on-windows.md: its judge is spelled in the recipe's tree with no added manifest, and was run once that way against sysroots/8618c089fa736cb0 (pinfile-r2/suite/judge.log): cargo check -Z build-std=std,panic_abort --target x86_64-pc-windows-msvc --offline -p toyos-build --all-targets, EXIT=101. It builds core, std and test for Windows and stops at the 37th crate with its one error, failed to run custom build command for ring v0.17.14: ring's build script compiles C for the target with the host's cc, which has no assert.h for it. So the judge does not reach src/tether.rs or any source of the build system; the issue now says so, and that it needs the target's C headers (a download) or a toyos-build none of whose dependencies compiles C for its target. Its heading no longer says it needs no download.
  2. issues/a-compiler-key-reads-no-symbolic-link.md cites compiler::KEYED, its evidence is re-read at the pin 6d6ad8c7190 (the same five links of mode 120000, all under src/tools), and it is owned by and exits at the track's first step, where a key's fork parts become git tree ids. Links::Skipped stays: taking it here moves the key.
  3. issues/the-primary-still-holds-the-toolchain-nothing-reads-any-more.md names compiler::place as what creates rust/build/toyos-compiler/.
  4. The guest suite at the landing head's code: under Gates.

The loop: what held the key at the red

build-request-loop.sh at 3250e8a22, run by the orchestrator, with loop-the-old-shapes.patch (in the patches comment) applied for its length and reversed after (restore 0, compile after 0). The patch brings back, as old_* tests beside the head's, the four tests in which a sweep must take a key an earlier sweep of the same process held: the red one as it stood at 9552f5e3a, three as they stood at 754117e9c. At a red it reads how long the key stays held with nobody acting (a spin of keyed_idle), then runs lsof on the lock file. Each iteration is cargo test --lib -- <filters>; logs under the scratchpad's pinfile-r1/loop/.

arm what ran iterations with a red exit of a red
A, natural the old shapes beside the module tests (buildlock:: keystore:: compiler:: llvm:: sysroot:: toolchain:: release:: build:: userlandhost::) 5 in 39 s, stopped at its 3rd red as bounded 3 (iterations 2, 3, 5) 101
B, control the four old shapes alone, --test-threads=1 196 in 902 s, stopped by its 15-minute bound 0
C, pressure arm A with eight threads spawning true for 5 s 10 in 82 s, stopped at its 10th red as bounded 10 101

Host load (1-minute) was 14 to 17 during A, 7 to 14 during B, 10 to 21 during C.

What the 13 reds are. Every one is llvm::tests::old_a_stopped_sweep_leaves_no_llvm_that_passes_for_whole, the test and the assertion of the red at 9552f5e3a, and each iteration's result is 127 passed; 1 failed: no other old shape and no test of the head was red in any of the 15 iterations of A and C. At each, the store held exactly <key>.swept (the stopped sweep had done its part) and the next sweep took nothing. Each probe then found the key free with nobody acting, after 0.44 ms to 2.84 ms (A: 1.53 ms, 0.49 ms, 1.54 ms; C: 0.44 to 2.84 ms), at its 2nd to 42nd try. The deciding line, the same shape at all 13:

LOOP RED stopped-sweep: the next sweep took [] of ["edb8c0a49e4a1de4.swept"]; PROBE …/locks/llvm/edb8c0a49e4a1de4: free after Some(1.526375ms), at try 7, with nobody acting; … lsof then (exit Some(1)): "" ""

What lsof named: nobody, at all 13. It exited 1 with no output each time. That is the probe's own order and not a finding about the holder: it spins first and runs lsof once the key is free, and lsof takes longer to start than this holder lives. So no probe names a not-yet-exec'd child, and none names anything else.

What the three arms show.

  • The lock was kept by something that lets go by itself within 3 ms: nothing in the test acted between the red and the key being free.
  • That something exists only while other test threads run: the same four tests, the same panic path, 196 iterations × 4 on one thread, no red.
  • The store is a temporary directory only that test's thread knows, and a key's lock file is opened only through buildlock::keyed_lock_path (the three keyed_* functions and the tests' last_used, each given that store); so no other thread opens that path, and the only way another thread's activity puts a descriptor on it is a copy made by a spawn while the stopped sweep held it. A copy of a O_CLOEXEC descriptor lives until its child's exec, which is the lifetime the probes read, and the staged mechanism shows such a copy holds the lock on this host.
  • Why this test and not the other three: its sweep holds the key through a panic (the hook's formatting and the unwind) and the next sweep asks immediately; the others hold a key for one flock and a stat.

What they do not show. No reading at a red names the holder: that it was a not-yet-exec'd child of the test process is inferred from the three points above and the staged mechanism, by elimination, not observed. Arm C does not discriminate: 10 of 10 against 3 of 5 is the predicted direction on samples too small to call a rate. A probe that could name the holder would have to list the test process's children and their descriptors in-process within the holder's lifetime (libproc), which lsof cannot; it was not built.

What follows for the code. Whatever the holder, a sweep that finds a key held skips it for that sweep and removes and serves nothing wrongly (keystore::sweep_by's continue), so the production consequence is the one the first review named: one key kept one sweep longer. The head's tests no longer have the shape: none was red beside 13 reds of the old one.

The keys, and the first build after this lands

Each round moved the compiler's key, and with it each freestanding libraries' and each sysroot's; the LLVM's never moved: 1670055c5e508eba, built by the first round, was found by every later build. This head's are the compiler 3d1cb62e54e18406, the freestanding libraries dc7c468f0c07446e and the sysroot 8618c089fa736cb0. The two earlier rounds' (compilers 57730ac698e049ff and a3df641184b6a414, freestanding 6fc478ae40e3b5c4 and 11781b8326310eac, sysroots e8e676e1327c6331 and 98a89bccae42525e) are named by no tree any more and go by the sweep 14 days after their last use.

target/.deps-stamp's compiler line is not the compiler's key, by design. The build log's Building compiler 3d1cb62e54e18406 names the store's key, compiler::key: the sources and the build. The stamp's compiler 56c6ecf6364660be is Key::of(Compiler::identity()) (src/sysroot.rs, Keys::of; src/compiler.rs, identity): that key together with the built driver's file name, size and modification time, so a compiler made again under its key after a sweep leaves every crate target stale, cargo keying nothing on it itself. Both are main's; the round before read the same pair (a3df641184b6a414 in the log, 192b66b33fec9d05 in the stamp).

  • This host. A worktree that merges this and pins the same fork commit finds all four products, as the second worktree below did, and builds only its guest crates; one whose sources differ builds what they name beyond the LLVM and the compiler.
  • Any other machine, or this one with the store empty. One LLVM (15:19 here, idle, plus a 52 s clone of src/llvm-project), one compiler (5:19), the freestanding libraries (2:14) and the sysroot (about 1:30): 25:58 for cargo run -- --build-only, measured once at the first round's head. Under load the earlier figures were about twice that.
  • A worktree that has not merged this is untouched: it keeps building with the primary's rust/build and its git directory's toyos-build-locks, which this branch neither reads nor writes.
  • CI. All four layers are cold once on this pull request, once in the merge group and once on main's nightly: LLVM about 1:29 and the compiler about 0:41 on a runner, by the design's earlier measurements, not this branch's.
  • Left behind, filed as issues/the-primary-still-holds-the-toolchain-nothing-reads-any-more.md with the orchestrator as owner, the commands that remove each and when that is safe: the primary's rust/build (20G by du -sh at this round, not the 92.9 GiB the design read a week earlier), whose toyos-compiler is a file where a compiler build wants a directory, so the primary's first compiler build is refused by the OS until it goes; toyos-build-locks in its git directory; and the rustup toyos link, which would go on running the last in-place compiler without a word.
  • From then on a sysroot stays 14 days after its last use instead of going with its worktree: 1.3G each as du counts it, most of it blocks cloned from its compiler.

Checks named for this change (high-risk: the build system)

  • Oracle, run at the first round's head 754117e9c: std's ToyOS backend lives in sdk/std, and the fork names it by #[path] #745's comparison of the sysroot built in the store (e8e676e1327c6331) against one main's layout built in place, whose recorded witness was byte-identical: the 30 rlibs and libstd-*.so of each userland target, by GNU nm --defined-only -S. 11,453 defined symbols on each side for x86-64 and 9,691 for AArch64; with hashes, disambiguators and numbered labels blanked, no symbol added, removed, resized or retyped. It is not byte identity and it is not a boot, and it is of the compiler before this round dropped two links from it.
  • Oracle for the stamp, run at 754117e9c: clang --version and lld -flavor gnu --version of the stored LLVM both print https://github.com/ToyOSOrg/llvm-project.git ceaf0fbb8440c733a98691a88e39b3ce74443677, and so does its VCSRevision.h. That LLVM is this head's too.
  • Negative controls, host tests: a product not whole is made again or refused; a product is swept only when unused for the keep time and idle; a stopped sweep leaves nothing reading as whole; a compiler whose sources moved while it was built is not stored.
  • Mutations, run at b7cb92153 (m1 to m5 in the first patches comment, m6 to m13 in the second; each git apply --check 0, cargo test --lib --no-run 0, reversed 0, tree clean after; logs under the scratchpad's pinfile-r2/light/). Each red is its named test alone, read in its log; m6 to m12 each fail on their own file's "kept the key" assertion.
patch reverts test it reds exit
m1 a product is renamed away before anything in it is removed a_stopped_retire_leaves_nothing_at_its_name, a_stopped_sweep_leaves_no_llvm_that_passes_for_whole 101
m2 a sweep reads a key's age a_sweep_removes_what_nobody_used_for_the_keep_time_and_nobody_uses 101
m3 a use dates its key a_product_used_again_is_kept 101
m4 a compiler whose sources moved while it was built is refused a_compiler_whose_sources_moved_while_it_was_built_is_not_stored 101
m5 a stored compiler carries no link to its checkout one_compiler_per_key_whichever_checkout_names_it 101
m6 to m12 a compiler's key reads library, Cargo.toml, src/version, src/ci/channel, src/build_helper, x, x.py, one patch each every_source_of_a_compiler_moves_its_key 101 each
m13 a compiler's build directory starts clean for another build or LLVM a_build_directory_another_llvm_filled_starts_from_nothing, alone of the nine compiler tests 101

Gates

At b7cb92153, run by the orchestrator in 126 s (pinfile-r2/light/):

  • cargo test --lib --no-run: EXIT=0.
  • cargo test --lib -- buildlock:: keystore:: compiler:: llvm:: sysroot:: toolchain:: release:: build:: userlandhost::: EXIT=0.
  • cargo clippy --all-targets -- -D warnings: EXIT=0, on this host's clippy, which is older than CI's; the diff was read for is_multiple_of and isolate_lowest_one and has neither shape.

At 9a7d15900, by the orchestrator in 17 s (pinfile-r2/lint/): cargo test --lib --no-run EXIT=0, cargo test --lib -- compiler:: keystore:: EXIT=0, cargo clippy --all-targets -- -D warnings EXIT=0 on this host's clippy, which raises neither of the two lints CI's did: CI's host is their judge.

At the first round's head 754117e9c: cargo run -- --build-only with ~/.cache/toyos empty, EXIT=0 in 25:58, every product built by the branch (LLVM 15:19, compiler 5:19, freestanding 2:14, sysroot about 1:30).

The toolchain in the store

build-request-heavy.sh at b7cb92153, run by the orchestrator in 515 s (pinfile-r2/heavy/), host load 10.37 8.42 9.79 when the build ended:

  • cargo run -- --build-only: EXIT=0, 16:11:33 to 16:19:45. No line names an LLVM being built: 1670055c5e508eba was found. It built compiler 3d1cb62e54e18406 (bootstrap: 4:06, cold, in a build directory place had emptied), the freestanding libraries dc7c468f0c07446e (1:30) and sysroot 8618c089fa736cb0 (0:57), the last two from ~/.cache/toyos/compilers/3d1cb62e54e18406/stage2.
  • cargo run -- --build-only again: EXIT=0, no toolchain product built.
  • target/.deps-stamp after: compiler 56c6ecf6364660be, 8618c089fa736cb0 for both userland targets, dc7c468f0c07446e for the four freestanding ones.
  • The stored compiler and sysroot hold bin/cargo to the host's own cargo and ld.lld -> rust-lld, and no link into a checkout; the build directory's compiled-by holds the build text and 1670055c5e508eba (heavy/sysroot.log).
  • The std type-check recipe: EXIT=0 in the spelling src/CLAUDE.md now words (the table above).
  • Worktree and fork checkout clean after.

The guest suite on the store's toolchain

At 3def81032, run by the orchestrator in this worktree (pinfile-r2/suite/), host load 33.54 22.82 16.50 when it ended:

  • cargo test --test toyos-build (the command src/ci.rs runs for --ci guest, without its --jobs 1, a four-core runner's sizing): EXIT=0, 16:31:18 to 16:33:41. The harness's own line: test result: ok. 36 passed, 36 total (137.1s; workers: 1147s building, 321s testing).
  • No toolchain product was built during it (grep -c of Building (LLVM|compiler|the freestanding libraries|sysroot) : 0), and the store's four lists of names before and after: cmp EXIT=0.
  • target/.deps-stamp after it against the one recorded at b7cb92153: cmp EXIT=0, so it compiled against compiler 3d1cb62e54e18406, sysroot 8618c089fa736cb0 and freestanding libraries dc7c468f0c07446e; that sysroot key's lock, which a use dates, read 16:20:52 before the suite and 16:33:20 after.
  • Worktree and fork checkout clean after.

9a7d15900 differs from 3def81032 by issues/the-build-system-does-not-compile-on-windows.md and the two test lines CI's clippy refused, neither of which a guest build reads. The suite before it, at 3250e8a22 on the sysroot 98a89bccae42525e: EXIT=0, 34 passed, 34 total.

CI, on the ready pull request

At 9a7d15900: run 37800146983, ci on pull_request, on a merge into d83ab1398; every job ran and none was skipped.

  • host (cargo run -- --ci host): red at b83eb464b, run 37794832085, 1 of 78 step(s) red: clippy, warnings denied, on src/compiler.rs:379 (redundant clone) and src/keystore.rs:271 (unchecked subtraction of a Duration), both test lines, fixed in 9a7d15900. At 9a7d15900:
  • host at 9a7d15900: job 113390157791, success, [ci] Host: 78 step(s), all green.
  • toolchain / build: job 113390158736, success. [ci] the stores of this tree's toolchain: llvm a2cc063281d9f279, compiler 6c76c19e5ffcc869, freestanding 0f5a5faab7bbc78c, sysroot 5f85c696604b34b5; four Cache not found for input keys:, one per layer; [ci] this tree's toolchain: llvm a2cc063281d9f279 built, compiler 6c76c19e5ffcc869 built, freestanding 0f5a5faab7bbc78c built, sysroot 5f85c696604b34b5 built; [ci] Bootstrap: 1 step(s), all green (79 min 46 s); four Cache saved with key:, the same four keys.
  • guest / suite: job 113428345579, success. Cache hit for: toolchain-sysroot-5f85c696604b34b5; [ci] the toolchain: installed sysroot 5f85c696604b34b5; running 36 tests; [ci] the suite: test result: ok. 36 passed, 36 total; [ci] Guest: 5 step(s), all green. 36 is what main's merge group for d83ab1398 printed (run 37783473132), the same 36 names.

A second worktree finds the products

By the orchestrator, in a worktree made at b7cb92153 beside this one and removed after, in 85 s (pinfile-r2/second/):

  • cargo run -- --build-only: EXIT=0. Its log holds Making …/toyos-pinfile-second/rust a fork checkout at 6d6ad8c71906c4e7ddb67e34720f297704d6c282 (a git worktree of the primary's), Build finished. and a Boot image: line, and no line Building (LLVM|compiler|the freestanding libraries|sysroot) : grep -c 0.
  • The store's four lists of names before and after: cmp EXIT=0.
  • Its target/.deps-stamp against this worktree's: cmp EXIT=0, so both compile against one compiler, one sysroot and one set of freestanding libraries; no path of a checkout reaches a key.
  • git status: 0 lines.

Not built, not measured

  • cargo run -- --ci host on this host: not run locally (orchestrator's ruling); CI's run is under "CI, on the ready pull request" above.
  • The Windows judge reaching the build system's own sources: it stops at ring's C (above).
  • The holder at a red of the loop is inferred, not read (above).
  • None of the six new key inputs was measured to change a compiler: each is keyed from reading bootstrap, and src/ci/channel is known not to reach this build's bytes today.
  • A compiler rebuilt after its build text or LLVM changed: the directory's emptying has its host test; no such real build ran, this round's cold one being a directory with no record. That bootstrap unpacks its stage 0 again from the kept cache/ with no fetch is what the 4:06 build did.
  • The two filed inputs (the environment, the worktree's cargo configuration) are from reading; no compiler was built under either.
  • A library/-only fork commit's cost is an estimate from cold phase times.
  • The symbol-table oracle is of the first round's sysroot; this head's was built and type-checked against, not compared.
  • Whether an LLVM swept after 14 days while its compiler is still in daily use is a cost worth dating against: a sweep of a kind runs only when that kind is placed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A

…very compiler is keyed

Every LLVM, compiler, freestanding library set and sysroot is a product of
one store per host, `$TOYOS_STORE`, else `$XDG_CACHE_HOME/toyos`, else
`~/.cache/toyos`, with its key locks beside it. Whichever checkout or
clone first needs a product makes it and every other finds it. A runner's
store stays in its checkout, `rust/build`, where the cache action's paths
and the container guest job find it.

No checkout's compiler is special. The primary's in-place `stage2`, its
record, the global lock, the `Scope` of an exclusive phase and the
bootstrap decisions built on them go: the primary resolves its compiler by
key as a worktree does. With the in-place build go the two things the
owner ruled dropped with it, the ToyOS-hosted rustc's build (and the
`hosted-rustc` key and its collection into an image) and the rustup
`toyos` link.

A product is no longer named by a record in a registered worktree's
`target/`: a use dates its key's lock, and a sweep takes what nothing has
used for 14 days and nobody is making or using.

LLVM, clang and LLD are stamped with the commit and the URL the fork's
commit names (`LLVM_FORCE_VC_REVISION`, `LLVM_FORCE_VC_REPOSITORY`), where
LLVM's CMake asked git in the checkout that built them and wrote that
checkout's `origin` into every binary. This moves the LLVM's key, and with
it every compiler's and sysroot's.

The fork moves to 6d6ad8c7190, which fetches its eight ToyOS dependencies
from the organisation instead of a personal account; no dependency changes
its commit.

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

Japabu commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Mutation patches against 754117e9c, not yet run; request 2 applies each as a checked patch, builds, runs the named tests and restores.

m1-retire-in-place: must red llvm::tests::a_stopped_sweep_leaves_no_llvm_that_passes_for_whole and keystore::tests::a_stopped_retire_leaves_nothing_at_its_name

diff --git a/src/keystore.rs b/src/keystore.rs
index 835c50474..6ad1dff32 100644
--- a/src/keystore.rs
+++ b/src/keystore.rs
@@ -186,8 +186,7 @@ fn retire_by(path: &Path, remove: impl Fn(&Path)) {
         remove(&away);
     }
     if path.exists() {
-        fs::rename(path, &away).unwrap_or_else(|e| panic!("rename {} -> {}: {e}", path.display(), away.display()));
-        remove(&away);
+        remove(path);
     }
 }
 

m2-age-never-read: must red keystore::tests::a_sweep_removes_what_nobody_used_for_the_keep_time_and_nobody_uses

diff --git a/src/buildlock.rs b/src/buildlock.rs
index 95920dbee..df034dbba 100644
--- a/src/buildlock.rs
+++ b/src/buildlock.rs
@@ -269,7 +269,8 @@ impl Guard {
     /// nothing had locked before is dated by the lock that asks.
     pub(crate) fn used_within(&self, kept: Duration) -> bool {
         let used = self.file.metadata().and_then(|meta| meta.modified()).unwrap_or_else(|e| panic!("build lock: stat: {e}"));
-        !used.elapsed().is_ok_and(|unused| unused >= kept)
+        let _ = (used, kept);
+        false
     }
 }
 

m3-a-use-dates-nothing: must red keystore::tests::a_product_used_again_is_kept

diff --git a/src/buildlock.rs b/src/buildlock.rs
index 95920dbee..ce1dc72b6 100644
--- a/src/buildlock.rs
+++ b/src/buildlock.rs
@@ -226,7 +226,6 @@ fn keyed_using(store: &Path, kind: Keyed, key: &Key) -> Guard {
         announce(&lock, &what, &holder);
         take_lock_announcing(&file, LOCK_SH, &path, &lock, &what);
     }
-    file.set_modified(SystemTime::now()).unwrap_or_else(|e| panic!("build lock: date {}: {e}", path.display()));
     Guard { file, records_holder: false }
 }
 

@Japabu

Japabu commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Review of #769 at 754117e9c against origin/main b26542c26, round 1. Read only: no test, build or boot was run for this review.

Net (git diff --shortstat origin/main...754117e9c): 33 files, +892 −2251. By the body's split of the ten changed src/ files: production 7030 → 6306 (−724), tests 7234 → 6657 (−577). The fork commit 6d6ad8c7190 has cc9c8b1be68 (main's gitlink) as its one parent, is the tip git ls-remote gives for ToyOSOrg/rust main, and changes 17 lines in 6 files, every one a URL.

BLOCKER

  • PR body, "Not built, not measured" — cargo run -- --ci host has not run at this head — reviewer.md Evidence names it a BLOCKER when missing; the only clippy was this host's older one, and the pull request is a draft, which ci.yml's host skips.
  • PR body, "Not built, not measured" — no guest has booted on a toolchain from the store — every guest binary is now made by an LLVM configured differently (LLVM_FORCE_VC_*), a compiler built another way and a sysroot from both, so the change reaches every guest test; the symbol-table comparison is, in the body's own words, "not a boot". Owed before landing: cargo test (the whole suite), exit code and log, at this head on this host with TOYOS_STORE unset, whose build log names ~/.cache/toyos/sysroots/<key> as the sysroot it compiled against. CI's guest / suite does not stand in for it: a runner's toolchain is Linux-hosted and laid out as Owner::Installed, and never goes through keystore::host.
  • src/llvm.rs:1113-1128, src/keystore.rs:283-298, src/keystore.rs:305-317, src/llvm.rs:1103-1106 — the red at 9552f5e3a was answered by a guess, and by that guess three more assertions in this diff are the same flake — the body says the cause "is inferred from the test being green since". If the inference is right (a key's lock this process held is kept by a descriptor another test thread's spawn copied), then a_sweep_removes_what_nobody_used_for_the_keep_time_and_nobody_uses (its third sweep must take undated, whose lock this process held in the two sweeps before), a_product_used_again_is_kept (its last sweep must take a key the sweep before held) and an_llvm_is_swept_once_nothing_used_it_for_the_keep_time (its second swept() must take what the first held) each assert free a lock this process has held, which src/buildlock.rs:528-530 forbids in so many words; only two of the five sites were moved to a child. If the inference is wrong, the stopped sweep's lock was kept by something nobody has named, in the code that decides what is removed from a store every checkout shares. One measurement tells: the test as it stood at 9552f5e3a, looped beside the rest of the lib tests until it reds, with the holder of locks/llvm/<key> read at the red (lsof on the lock file), and the same loop over the three tests named here. Root CLAUDE.md: a flaky test is deleted at once, never re-run; a red is a defect until its cause is shown.
  • CLAUDE.md:73 — "waiting out a build that holds the global lock" names a lock this branch deletes (buildlock::global_exclusive, Scope::Global) — reviewer.md Instructions: a prompt left naming a step that is gone is a BLOCKER; it says what to wait out instead (a build holding a key's lock in the store, or the worktree's), in this diff.
  • src/compiler.rs:144-150 — mutation I expect to pass every test: delete the assert!(again == *key, …) in compiler::place. No compiler test moves a source during build (fake_build never does; llvm.rs's moving arm is the LLVM's only). This branch makes that function the only way any compiler on the host comes to be, the primary's included, and the store's contract (src/keystore.rs:10-15) is that a product found under its key is the one the key names: a compiler built while its compiler/ was being edited, stored under the key of the sources before the edit, is then served to every checkout that names that key. It must turn red a test in src/compiler.rs whose stand-in build edits and commits a KEYED source before returning, and that asserts the refusal and that compilers/ holds no <key>/. The implementer runs it.

NOTE

  • PR body, "A second checkout or clone finding these products" unmeasured — the change's first sentence rests on host fixtures alone. Before landing: a second worktree at this head (or one that merges it) runs cargo run -- --build-only; its log holds no line beginning Building LLVM, Building compiler, Building the freestanding libraries or Building sysroot, and ls ~/.cache/toyos/{llvm,compilers,freestanding,sysroots} is the same four names before and after. That is also the only measurement that no path of a checkout reaches a key.
  • CI's path (--ci toolchain, bootstrap, guest with rust/build as the store, the one-line <name>-path= outputs) has only host tests — it may be read after the pull request leaves draft, but before the merge: toolchain / build cold and green, its four actions/cache/save steps each saving one directory, and guest / suite green on the sysroot that run saved. Nothing else of CI is owed before landing; main's first nightly being cold is a cost the body states.
  • ~/.cache/toyos/compilers/<key>/stage2/lib/rustlib/{src,rustc-src}/rust and the same two in sysroots/<key>/ are symbolic links into the fork checkout of the worktree that built them (read off the store this branch filled: both point into this branch's worktree), and SOURCES records that path too — src/keystore.rs:6-8 says nothing in a store names the checkout that made it; the orchestrator removes this worktree after landing, and every checkout on the host then builds with a compiler whose two links dangle. Either the links are not cloned into a product, or an issue says what reads them and what a dangling one costs.
  • PR body, "Left behind" — omits the rustup toyos link, which on this host still names the primary's in-place stage2 and which nothing rebuilds after this lands: cargo +toyos then runs a compiler and std frozen at the last pre-landing build, without a word. It goes in the by-hand removal, and the leftover list (92.9 GiB under the primary's rust/build, .git/toyos-build-locks, the link) is filed in issues/ with the orchestrator as owner and an exit a command can read; a pull request body is not where a compromise is recorded (root CLAUDE.md, "Zero silent debt").
  • issues/the-build-system-does-not-compile-on-windows.md:15 and issues/toyos-runs-on-arm64.md:219 — a judge and an exit that run cargo +toyos, the command this change stops providing; by the note above they would now read the stale link. They take src/CLAUDE.md's RUSTUP_TOOLCHAIN=<sysroot> spelling in this diff.
  • PR body, "a compiler build in the primary itself is refused by the OS, because rust/build/toyos-compiler is a file where it wants a directory" — the refusal is an OS error on that path, which names no cause; it bites the first time the primary is first to name a compiler (a fork bump built there, or a host tool update moving the LLVM's key). Removing the file is in the same by-hand step and the same issue, which says that worktrees still on main's layout are then refused until they merge.
  • issues/the-primary-rebuilds-its-compiler-on-compiler-alone.md — still open and assigned, describing compiler::record and the primary's stamp, both deleted here; its exit (a fork moving only src/tools gets a compiler of its own) is what every_source_of_a_compiler_moves_its_key now holds for every checkout. Closed in this diff, by issues/README.md's procedure.
  • issues/a-compiler-fixtures-git-commit-could-not-create-a-temporary-file.md:9 — cites a_missing_primary_record_is_refused_and_builds_nothing, a test this diff deletes; the fixture it is about (estate) remains, so the citation moves to a test that still runs it.
  • issues/a-finder-file-in-a-store-directory-panics-its-sweep.md — cites <primary>/.git/toyos-build-locks/llvm/, a path this diff stops using, and its exit is already met on main (a_sweep_leaves_hidden_names_and_refuses_names_no_key_owns); stale before this branch, false of one more thing after it. Closed here or filed for whoever closes it.
  • issues/the-forks-pin-is-a-file-and-a-worktree-checks-no-fork-out.md — names no owner; status: open says nobody holds it, and four steps with exits and no owner is the shape reviewer.md refuses. Each ruling it quotes is attributed as given (the owner's "Yes to the pin file"; the orchestrator's for the full commit id and "within N of main").
  • src/keystore.rs:83-91 — TOYOS_STORE and XDG_CACHE_HOME are two knobs beyond the ruling ("store in ~/.cache/toyos"); no test needs either (tests pass a directory), and a process whose environment differs in one of them builds a second 26-minute toolchain into a second store without a word, which is the hazard the relative-path refusal beside it exists for. The body says who sets each, or they go and the store is $HOME/.cache/toyos.
  • src/compiler.rs:43 — KEYED holds no library/, and RECIPE on line 40 says the build is "stage 2 of compiler/rustc and library": the host std a compiler carries, which every guest crate's build scripts and proc macros link, is built from sources its key does not read, so a fork commit that moves only library/ keeps a stored compiler whose host std is the commit's before. On main since ARM64 port, stages 0 to 3: shared groundwork, aarch64-unknown-toyos with std and the userland, and the loader and kernel reach the PL011 on virt #524 for a worktree's compiler; this branch makes it every compiler's and writes the contract it breaks (src/keystore.rs:15: "An input a build reads and its key does not is a defect of the key"). Filed, with the two refusals of the same shape that have no test either (src/sysroot.rs:782-787, 808-813).
  • src/CLAUDE.md:16 — the bullet gains a sentence describing the store, which src/keystore.rs's header already is; the rule the edit stands on covers the command it replaces (cargo +toyos, done on line 18) and the clause that became false, not an addition. The stage1-std caveat's removal is outside the letter of that rule as well and right on substance only if no build here can produce that error any more, which nothing measured.
  • src/sysroot.rs:836 — publish removes a refused sysroot in place (keystore::remove(dir)) where llvm::place retires it; a removal stopped there leaves SOURCES in a directory that may still pass toolchain_defect. Unchanged from main, and now in the store every checkout reads: keystore::retire(dir) is the one-word change, or it is filed.
  • Production in-process hazard asked of this review: none found. A key's descriptor is O_CLOEXEC, so a spawned child keeps a copy only until its exec; in keyed_made that delays a blocking flock by that long, and in a sweep it skips one key for one sweep. Neither removes or serves anything wrongly.
  • Deleted invariants asked of this review: the global lock guarded the primary's in-place rust/build, which nothing builds in or reads any more; two builds of one fork checkout are still serialised by that worktree's exclusive lock (compiler::place, sysroot::build, build_freestanding, and every llvm::resolve is under one of them); a product's .partial is beside it in the store, so its placing rename never crosses a volume, and a worktree on another volume costs a copy in clone_tree, not atomicity.

SEND BACK

Japabu and others added 3 commits October 8, 2026 14:45
…mpiler has a test

Answers the first review of the store.

A stored compiler carried bootstrap's two links to the sources of the
checkout that built it (lib/rustlib/src/rust and rustc-src/rust), and a
sysroot cloned them; a sysroot's and the freestanding libraries' SOURCES
recorded that checkout's path. The orchestrator removes a worktree once its
branch lands, so every checkout on the host would then have built with
links that dangle. rustc reads either only to translate a library source's
path to or from its remapped form, which no build here asks for, so a
stored compiler now carries neither, and SOURCES is the key and the
witness. The compiler's RECIPE moves for it, and with it every compiler's,
freestanding libraries' and sysroot's key; the LLVM's stays.

The store is ~/.cache/toyos and nothing else: TOYOS_STORE and
XDG_CACHE_HOME were two ways to build a second toolchain into a second
store without a word, and nothing in the tree set either. A runner's store
is release::store, named there.

compiler::place refused a compiler whose sources moved while it was built,
and no test moved one: a_compiler_whose_sources_moved_while_it_was_built_
is_not_stored does, and reds when the refusal is deleted.

sysroot::publish retires a refused sysroot as llvm::place does, so a
removal stopped halfway leaves nothing under the key.

Three sweep tests asserted free a key whose lock an earlier sweep of the
same process had held, which buildlock's tests forbid: a descriptor
another test thread's spawn copied keeps the lock until that child's exec.
Each now takes a key only with the first lock this process puts on it:
a_product_used_again_is_kept decides a used and an unused product in one
sweep, the LLVM's sweeps once after its user let go, and the assertion
that an undated product goes once it is old, which the unused one already
makes, is gone.

Root CLAUDE.md names the locks a build may have to wait out, in place of
the global lock; src/CLAUDE.md loses the sentence describing the store.

Issues: the primary's compiler key and the Finder file are closed, their
exits met by every_source_of_a_compiler_moves_its_key and
a_sweep_leaves_hidden_names_and_refuses_names_no_key_owns; the track has
an owner; what the old layout left in the primary, and a compiler's key
reading no library/, are filed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
A compiler is bootstrap's stage 2 of compiler/rustc and library, so the
stage2 a store keeps carries a std for the host, which every guest crate's
build scripts and proc macros link, and its key read nothing of library/:
a fork commit moving only library/ kept the stored compiler with the std
of the commit before. True of a worktree's compiler since #524 and of
every compiler since the primary's became keyed. The orchestrator's
ruling: fixed here, at the price of a compiler build for a fork commit
that moves std (about 5 minutes on an idle host, on top of the
freestanding libraries and the sysroot such a commit builds already).

every_source_of_a_compiler_moves_its_key holds it. Every compiler's key
moves, and each freestanding libraries' and sysroot's with it; the LLVM's
does not.

The two refusals in sysroot.rs of a product whose sources moved while it
was built stay untested, since both run bootstrap inline: filed.

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

Japabu commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Mutation and measurement patches of fix round 1, each applied, built, run and reversed at 3250e8a22 by the light request (m1 to m6: test EXIT=101). m1 to m3 are the first round's, unchanged. The last is not a mutation: it is the loop's instrumentation (the four tests as they stood before this round, a probe at each red, the spawn-pressure arm, and the staged mechanism test), applied only for the measurement and never landed.

m1-retire-in-place.patch
diff --git a/src/keystore.rs b/src/keystore.rs
index 835c50474..6ad1dff32 100644
--- a/src/keystore.rs
+++ b/src/keystore.rs
@@ -186,8 +186,7 @@ fn retire_by(path: &Path, remove: impl Fn(&Path)) {
         remove(&away);
     }
     if path.exists() {
-        fs::rename(path, &away).unwrap_or_else(|e| panic!("rename {} -> {}: {e}", path.display(), away.display()));
-        remove(&away);
+        remove(path);
     }
 }
 
m2-age-never-read.patch
diff --git a/src/buildlock.rs b/src/buildlock.rs
index 95920dbee..df034dbba 100644
--- a/src/buildlock.rs
+++ b/src/buildlock.rs
@@ -269,7 +269,8 @@ impl Guard {
     /// nothing had locked before is dated by the lock that asks.
     pub(crate) fn used_within(&self, kept: Duration) -> bool {
         let used = self.file.metadata().and_then(|meta| meta.modified()).unwrap_or_else(|e| panic!("build lock: stat: {e}"));
-        !used.elapsed().is_ok_and(|unused| unused >= kept)
+        let _ = (used, kept);
+        false
     }
 }
 
m3-a-use-dates-nothing.patch
diff --git a/src/buildlock.rs b/src/buildlock.rs
index 95920dbee..ce1dc72b6 100644
--- a/src/buildlock.rs
+++ b/src/buildlock.rs
@@ -226,7 +226,6 @@ fn keyed_using(store: &Path, kind: Keyed, key: &Key) -> Guard {
         announce(&lock, &what, &holder);
         take_lock_announcing(&file, LOCK_SH, &path, &lock, &what);
     }
-    file.set_modified(SystemTime::now()).unwrap_or_else(|e| panic!("build lock: date {}: {e}", path.display()));
     Guard { file, records_holder: false }
 }
 
m4-a-moved-compiler-is-stored.patch
diff --git a/src/compiler.rs b/src/compiler.rs
index c8a00cb1a..493e77b83 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -151,13 +151,6 @@ fn place(root: &Path, fork: &Path, key: &Key, dir: &Path, build: &impl Fn(&Path)
     for link in CHECKOUT_LINKS {
         keystore::remove(&partial.join("stage2").join(link));
     }
-    // The sources the key named are the ones built, or this is not that key's.
-    let again = self::key(fork);
-    assert!(
-        again == *key,
-        "the fork's compiler sources moved while compiler {key} was being built (they are now \
-         {again}); nothing was kept, and the next build makes the one they name"
-    );
     fs::write(partial.join(SOURCE), format!("{key}\n"))
         .unwrap_or_else(|e| panic!("write {}: {e}", partial.join(SOURCE).display()));
     fs::rename(&partial, dir).unwrap_or_else(|e| panic!("rename {} -> {}: {e}", partial.display(), dir.display()));
m5-a-stored-compiler-keeps-its-checkout-links.patch
diff --git a/src/compiler.rs b/src/compiler.rs
index c8a00cb1a..081aff73c 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -148,9 +148,6 @@ fn place(root: &Path, fork: &Path, key: &Key, dir: &Path, build: &impl Fn(&Path)
     let partial = dir.with_extension("partial");
     keystore::remove(&partial);
     clone_tree(&stage2, &partial.join("stage2"));
-    for link in CHECKOUT_LINKS {
-        keystore::remove(&partial.join("stage2").join(link));
-    }
     // The sources the key named are the ones built, or this is not that key's.
     let again = self::key(fork);
     assert!(
m6-a-compilers-key-reads-no-library.patch
diff --git a/src/compiler.rs b/src/compiler.rs
index 8d85f4f21..c69104455 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -42,7 +42,7 @@ const RECIPE: &str = "bootstrap stage 2 of compiler/rustc and library, profile c
 /// What a compiler's key is the identity of, in its fork checkout: `library`
 /// for the host's std its `stage2` carries, which every guest crate's build
 /// scripts and proc macros link.
-const KEYED: [&str; 5] = ["compiler", "library", "src/tools", "src/stage0", "Cargo.lock"];
+const KEYED: [&str; 4] = ["compiler", "src/tools", "src/stage0", "Cargo.lock"];
 
 /// What a compiler build is beyond its sources, as every key reads it:
 /// [`RECIPE`], the configuration bootstrap is given ([`config_text`]) with no
loop-the-old-shapes.patch
diff --git a/src/buildlock.rs b/src/buildlock.rs
index 95920dbee..c8a563301 100644
--- a/src/buildlock.rs
+++ b/src/buildlock.rs
@@ -928,6 +928,108 @@ pub(crate) mod tests {
             .expect("locked, the build's write must not land in a cleaned directory");
     }
 
+    /// What a red of the loop reads: how long `kind`'s `key` in `store` stays
+    /// held with nobody acting, and what `lsof` lists for its lock file then.
+    pub(crate) fn probe(store: &Path, kind: Keyed, key: &Key) -> String {
+        let path = keyed_lock_path(store, kind, key);
+        let asked = Instant::now();
+        let mut tries = 0u32;
+        let mut freed = None;
+        while freed.is_none() && asked.elapsed() < Duration::from_secs(5) {
+            tries += 1;
+            if keyed_idle(store, kind, key).is_some() {
+                freed = Some(asked.elapsed());
+            }
+        }
+        let lsof = Command::new("lsof").arg(&path).output().expect("run lsof");
+        format!(
+            "PROBE {}: free after {freed:?}, at try {tries}, with nobody acting; this process is pid {}; lsof then (exit {:?}): {:?} {:?}",
+            path.display(),
+            std::process::id(),
+            lsof.status.code(),
+            String::from_utf8_lossy(&lsof.stdout),
+            String::from_utf8_lossy(&lsof.stderr),
+        )
+    }
+
+    /// Spawns for the loop's pressure arm: `TOYOS_LOOP_PRESSURE` threads, each
+    /// spawning `true` again and again for five seconds, beside the other
+    /// tests; nothing without it.
+    #[test]
+    fn loop_pressure() {
+        let Ok(threads) = std::env::var("TOYOS_LOOP_PRESSURE") else { return };
+        let until = Instant::now() + Duration::from_secs(5);
+        let spawners: Vec<_> = (0..threads.parse::<usize>().unwrap())
+            .map(|_| {
+                std::thread::spawn(move || {
+                    let mut spawned = 0u32;
+                    while Instant::now() < until {
+                        assert!(Command::new("true").status().unwrap().success());
+                        spawned += 1;
+                    }
+                    spawned
+                })
+            })
+            .collect();
+        let spawned: u32 = spawners.into_iter().map(|s| s.join().unwrap()).sum();
+        println!("LOOP PRESSURE: {spawned} spawns of `true` in 5 s on {threads} threads");
+    }
+
+    /// The mechanism, staged: a child forked while this process holds a key's
+    /// lock keeps it, by its copy of the descriptor, until its exec, though
+    /// this process dropped its own. Run alone: while the child waits it holds
+    /// a copy of every descriptor this process had open.
+    #[test]
+    #[ignore = "holds every descriptor of the process in a child; run alone"]
+    fn loop_a_child_not_yet_execd_holds_a_lock_this_process_dropped() {
+        use std::os::unix::process::CommandExt;
+        unsafe extern "C" {
+            fn mkdir(path: *const std::ffi::c_char, mode: u32) -> i32;
+            fn access(path: *const std::ffi::c_char, mode: i32) -> i32;
+            fn usleep(usec: u32) -> i32;
+        }
+        let root = scratch("copied");
+        let key = Key::of(b"copied");
+        let c_path = |name: &str| std::ffi::CString::new(root.join(name).as_os_str().as_encoded_bytes()).unwrap();
+        let (forked, go) = (c_path("forked"), c_path("go"));
+        let mine = keyed_idle(&root, Keyed::Sysroot, &key).expect("nobody else knows this store");
+        let spawner = std::thread::spawn(move || {
+            let mut child = Command::new("true");
+            // SAFETY: between fork and exec the closure calls only mkdir,
+            // access and usleep, which are async-signal-safe, and allocates
+            // nothing.
+            unsafe {
+                child.pre_exec(move || {
+                    mkdir(forked.as_ptr(), 0o700);
+                    let mut waited = 0;
+                    while access(go.as_ptr(), 0) != 0 && waited < 20_000 {
+                        usleep(1000);
+                        waited += 1;
+                    }
+                    Ok(())
+                });
+            }
+            child.status().expect("spawn true")
+        });
+        assert!(appeared(&root.join("forked"), Duration::from_secs(20)), "the child never forked");
+        drop(mine);
+        let held = keyed_idle(&root, Keyed::Sysroot, &key).is_none();
+        let path = keyed_lock_path(&root, Keyed::Sysroot, &key);
+        let lsof = Command::new("lsof").arg(&path).output().expect("run lsof");
+        touch(&root.join("go"));
+        assert!(spawner.join().unwrap().success(), "the child failed");
+        let free = keyed_idle(&root, Keyed::Sysroot, &key).is_some();
+        println!(
+            "LOOP MECHANISM: this process is pid {}. After it dropped its lock and before the child's exec, the key was held: {held}. lsof {} (exit {:?}):\n{}{}After the child's exec the key was free: {free}.",
+            std::process::id(),
+            path.display(),
+            lsof.status.code(),
+            String::from_utf8_lossy(&lsof.stdout),
+            String::from_utf8_lossy(&lsof.stderr),
+        );
+        assert!(held && free, "a copy in a child not yet exec'd did not hold the lock, or held it past the exec");
+    }
+
     fn clean_racing_a_build(locked: bool) -> io::Result<()> {
         let root = scratch(if locked { "race-locked" } else { "race-unlocked" });
         let target = root.join("crate/target");
diff --git a/src/keystore.rs b/src/keystore.rs
index 0b8dead1c..051e1cd7c 100644
--- a/src/keystore.rs
+++ b/src/keystore.rs
@@ -308,6 +308,61 @@ pub(crate) mod tests {
         assert!(dir.join(&again).is_dir());
     }
 
+    /// `a_sweep_removes_what_nobody_used_for_the_keep_time_and_nobody_uses` as
+    /// it stood at `754117e9c`: its last sweep must take a key the two before
+    /// it held in this process.
+    #[test]
+    fn old_a_sweep_removes_what_nobody_used_for_the_keep_time_and_nobody_uses() {
+        let store = TempDir::new("old-sweep");
+        let dir = Keyed::Sysroot.store(&store);
+        let [used, in_use, undated, unused, gone] =
+            ["used", "in-use", "undated", "unused", "gone"].map(|name| Key::of(name.as_bytes()));
+        let at = |key: &Key, rest: &str| dir.join(format!("{key}{rest}"));
+        for (key, rest) in [(&used, ""), (&in_use, ""), (&undated, ""), (&unused, ""), (&used, ".partial"), (&gone, ".swept"), (&unused, ".swept")] {
+            fs::create_dir_all(at(key, rest).join("sub")).unwrap();
+        }
+        for read_only in [at(&unused, "/sub"), at(&unused, ""), at(&used, ".partial")] {
+            fs::set_permissions(read_only, fs::Permissions::from_mode(0o555)).unwrap();
+        }
+        last_used(&store, Keyed::Sysroot, &used, KEPT - Duration::from_secs(3600));
+        last_used(&store, Keyed::Sysroot, &unused, LONG_AGO);
+        let user = buildlock::tests::sysroot_used_elsewhere(&store, &in_use);
+        last_used(&store, Keyed::Sysroot, &in_use, LONG_AGO);
+
+        let mut removed = sweep(&store, Keyed::Sysroot);
+        removed.sort();
+        let mut want = [at(&gone, ".swept"), at(&used, ".partial"), at(&unused, ""), at(&unused, ".swept")];
+        want.sort();
+        assert_eq!(removed, want);
+        user.release();
+        assert_eq!(sweep(&store, Keyed::Sysroot), [dir.join(&in_use)]);
+
+        last_used(&store, Keyed::Sysroot, &undated, LONG_AGO);
+        let got = sweep(&store, Keyed::Sysroot);
+        if got != [dir.join(&undated)] {
+            panic!("LOOP RED sweep-removes: the last sweep took {got:?}; {}", buildlock::tests::probe(&store, Keyed::Sysroot, &undated));
+        }
+    }
+
+    /// `a_product_used_again_is_kept` as it stood at `754117e9c`: its last
+    /// sweep must take a key the sweep before it held in this process.
+    #[test]
+    fn old_a_product_used_again_is_kept() {
+        let store = TempDir::new("old-sweep-used");
+        let key = Key::of(b"a product");
+        let dir = Keyed::Sysroot.store(&store).join(&key);
+        fs::create_dir_all(&dir).unwrap();
+        last_used(&store, Keyed::Sysroot, &key, LONG_AGO);
+        assert_eq!(sweep(&store, Keyed::Compiler), Vec::<PathBuf>::new());
+        buildlock::tests::sysroot_used_elsewhere(&store, &key).release();
+        assert_eq!(sweep(&store, Keyed::Sysroot), Vec::<PathBuf>::new(), "a product was swept after a use");
+        last_used(&store, Keyed::Sysroot, &key, LONG_AGO);
+        let got = sweep(&store, Keyed::Sysroot);
+        if got != [dir] {
+            panic!("LOOP RED used-again: the last sweep took {got:?}; {}", buildlock::tests::probe(&store, Keyed::Sysroot, &key));
+        }
+    }
+
     /// **A key is the 16 lowercase hex digits [`Key::of`] gives, and no other
     /// name parses as one.**
     #[test]
diff --git a/src/llvm.rs b/src/llvm.rs
index cb55f7a39..8f1004a66 100644
--- a/src/llvm.rs
+++ b/src/llvm.rs
@@ -1125,6 +1125,62 @@ mod tests {
         assert_eq!(keystore::sweep(&store, Keyed::Llvm), [dir.with_extension("swept")], "the stopped sweep left {left:?}");
     }
 
+    /// `a_stopped_sweep_leaves_no_llvm_that_passes_for_whole` as it stood at
+    /// `9552f5e3a`, where it was red once: the stopped sweep runs in this
+    /// process, and the next must take the key it held.
+    #[test]
+    fn old_a_stopped_sweep_leaves_no_llvm_that_passes_for_whole() {
+        let scratch = Scratch::new("old-llvm-sweep-stopped");
+        let (_primary, store, [_same, a, _b]) = estate_built(&scratch);
+        elsewhere("use", &a, &store).release();
+        let unused = key(&a.join("rust"));
+        let dir = Keyed::Llvm.store(&store).join(&unused);
+        last_used(&store, Keyed::Llvm, &unused, LONG_AGO);
+        let halfway = |path: &Path| {
+            keystore::writable(path);
+            fs::remove_file(path.join("lib/libLLVMCore.a")).unwrap();
+            panic!("stopped");
+        };
+        let stopped = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| keystore::sweep_by(&store, Keyed::Llvm, halfway)));
+        assert!(stopped.is_err(), "the stand-in removal was never asked");
+        assert!(defect(&dir).is_some(), "a stopped sweep left {} passing for whole", dir.display());
+        let left: Vec<_> = fs::read_dir(Keyed::Llvm.store(&store)).unwrap().map(|e| e.unwrap().file_name()).collect();
+        let got = keystore::sweep(&store, Keyed::Llvm);
+        if got != [dir.with_extension("swept")] {
+            panic!("LOOP RED stopped-sweep: the next sweep took {got:?} of {left:?}; {}", buildlock::tests::probe(&store, Keyed::Llvm, &unused));
+        }
+    }
+
+    /// `an_llvm_is_swept_once_nothing_used_it_for_the_keep_time` as it stood
+    /// at `754117e9c`: its second sweep must take a key its first held in this
+    /// process.
+    #[test]
+    fn old_an_llvm_is_swept_once_nothing_used_it_for_the_keep_time() {
+        let scratch = Scratch::new("old-llvm-sweep");
+        let (_primary, store, [_same, a, b]) = estate_built(&scratch);
+        let user = elsewhere("use", &a, &store);
+        let unused = key(&a.join("rust"));
+        let first = Keyed::Llvm.store(&store).join(&unused);
+        last_used(&store, Keyed::Llvm, &unused, LONG_AGO);
+
+        let fork = a.join("rust");
+        pin_llvm(&fork, "B");
+        let second = choose(&store, &fork, fake_build);
+        assert_ne!(second.dir, first);
+        assert!(first.is_dir(), "placing an LLVM swept one still in use");
+
+        user.release();
+        elsewhere("use", &b, &store).release();
+        let swept = || keystore::sweep(&store, Keyed::Llvm);
+        assert_eq!(swept(), Vec::<PathBuf>::new(), "the sweep took an LLVM used since");
+        last_used(&store, Keyed::Llvm, &unused, LONG_AGO);
+        let got = swept();
+        if got != [first] {
+            panic!("LOOP RED llvm-swept-once: the second sweep took {got:?}; {}", buildlock::tests::probe(&store, Keyed::Llvm, &unused));
+        }
+        assert!(second.dir.is_dir());
+    }
+
     /// **What an LLVM says it was built from is the commit and the URL its
     /// fork's commit names**: both are in the configuration its key reads and
     /// its build is given, so git in the checkout that builds it decides

@Japabu

Japabu commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Review of #769 at 3250e8a22 against origin/main f2131918f, round 2. Read only: no test, build or boot was run for this review; git and the round's logs were read.

Net (git diff --shortstat origin/main...3250e8a22): 40 files, +1015 −2315. Rust: 12 files, +795 −2085; split at each changed file's first #[cfg(test)], production 6232 → 5523 (−709), tests 8315 → 7734 (−581). This round (git diff fcda6a0b1 3250e8a22): 16 files, +194 −135. The merge of main (fcda6a0b1) resolved nothing by hand (git show --remerge-diff is empty), and brought no line of src/compiler.rs, src/llvm.rs, src/sysroot.rs, src/toolchain.rs or src/clang.rs. main has moved one pull request past the merged base (#768: tests/, src/testargs.rs, one issue), none of it a file this branch touches.

Round 1's BLOCKERs

  1. cargo run -- --ci host — OPEN. No run of it exists at any head. The pull request is a draft and its three checks at 3250e8a22 are SKIPPED (host, toolchain, guest), which is not green. What ran is the module filter (light2/tests.log: 123 passed; 0 failed; 7 ignored, EXIT=0) and a clippy older than CI's. Nothing in the code holds this: it closes on the host job of a ready pull request, green at the head that lands, with its run in the body.
  2. A guest booted on a store toolchain — CLOSED. heavy/suite.log: cargo test --test toyos-build EXIT=0, 34 passed, 34 total, at 3250e8a22. The line the first review asked for does not exist in a build that finds its sysroot; what stands in for it is enough: heavy/build.log built sysroot 98a89bccae42525e from ~/.cache/toyos/compilers/a3df641184b6a414/stage2, target/.deps-stamp names 98a89bccae42525e for both userland targets and 11781b8326310eac for the four freestanding ones, and that key's lock moved from 15:30:34 to 15:32:15 across the suite.
  3. The red at 9552f5e3a — CLOSED, and no read of the holder is owed. The measurement the first review named was run as named (the old shape looped, lsof at the red) and lsof lost the race at all 13 reds; the body says so and claims no more. What the three arms do establish is enough to rule on, because it leaves one cause standing and no decision in the code turns on which child it was:
    • arm B (loop/B.tsv: 196 iterations, every one EXIT=0) is the same four tests and the same panic path on one thread, so nothing the test's own thread does keeps the lock;
    • at each red the key was free unaided after 0.44 to 2.84 ms (loop/A-*.log, C-*.log, 13 probes read);
    • a flock belongs to its open file description, the store is a directory only that thread knows, and a description outlives its owner's close only through a duplicate; the only duplicates other threads make of a descriptor they do not know are a spawn's, until the child's exec (O_CLOEXEC);
    • light2/mechanism.log shows such a copy holding the lock on this host: held after the drop, lsof naming one holder that is not the test process, free after its exec.
      An in-process probe is not cheap and may not be possible: the natural spawns here are posix_spawn, whose half-made child exists only inside the kernel. Production is safe whoever holds it: keystore::sweep_by skips a held key (src/keystore.rs:149) and buildlock::keyed_made blocks (src/buildlock.rs:250); no production path asserts a key free.
      The restructured tests are free of the hazard, by reading every sweep and keyed_idle in a test at this head: each assertion that needs a key taken names one only a child process ever locked (in_use, never, orphan, replaced, the two LLVM tests' unused), and every key this process did lock that a later sweep meets is one whose skip changes no asserted result (a live guard's, or one kept either way). They can still fail on what they claim: m1 reds a_stopped_retire_leaves_nothing_at_its_name and a_stopped_sweep_leaves_no_llvm_that_passes_for_whole (the latter at its defect assertion, src/llvm.rs:1123), m2 reds a_sweep_removes_… at src/keystore.rs:280, m3 reds a_product_used_again_is_kept at src/keystore.rs:307, each EXIT=101 with that test alone failing (light2/m*.test.log). The step cut from the LLVM test (a use by b dates it) is held by a_product_used_again_is_kept, since llvm::choose dates through buildlock::keyed_using and nothing of its own.
  4. Root CLAUDE.md:73 — CLOSED. It names a key's lock in the host's store or the worktree's; no CLAUDE.md or .claude/agents/*.md at this head names the global lock, the rustup link, cargo +toyos, TOYOS_STORE or the hosted rustc.
  5. compiler::place's refusal — CLOSED. light2/m4-…test.log: the assert! deleted, a_compiler_whose_sources_moved_while_it_was_built_is_not_stored FAILED, EXIT=101; the test asserts the refusal's text and that compilers/ holds <key>.partial alone.

Round 1's NOTEs, each read: the second worktree (second/second.log: 0 lines building a product, Build finished., the store's lists cmp-equal; it was a linked worktree, so Owner::Us on the store is first measured by the primary's build after landing and by CI); the checkout links (m5 reds; heavy/sysroot.log lists bin/cargo and ld.lld and nothing into a checkout for a3df641184b6a414 and 98a89bccae42525e); TOYOS_STORE and XDG_CACHE_HOME gone; publish retires; library keyed (m6 reds); the issues closed with no citation left (git grep of each slug and of primary_record, Compiler::primary, global_exclusive, sysroots_dir: nothing); the two cargo +toyos commands respelled; the track owned. All closed.

Rulings asked

  • stage1-std caveat left out: right. sysroot::build_std builds --stage 0 into build/toyos-std/<host>/stage0-std (src/sysroot.rs:855-860); the only stage-2 build is compiler::build_in_fork (src/compiler.rs:180), called only from place under buildlock::worktree_exclusive(root) (src/compiler.rs:146), and fork is always root.join("rust"), so two builds this build system starts never share a stage1-std. Worktrees still on main's layout keep main's src/CLAUDE.md and the caveat with it.
  • A cold compiler build at this head is not owed. git diff 754117e9c 3250e8a22 changes no line of build_in_fork, config_text, x_build_compiler or clang::provision, the fork commit and the LLVM (1670055c5e508eba) are the ones the 5:19 cold build at 754117e9c used, and the one new step after the build (dropping two links) ran on real bootstrap output here. CI's toolchain / build is the cold build of this head on the other host, and is owed for its own reason.
  • Can reuse of a build directory store a compiler built from other inputs than its key names: not here, yes in general. Here the key moved by its definition alone. In general place re-reads the sources and nothing asks whether the stage2 reflects them; that is cargo's and bootstrap's freshness in build/toyos-compiler. A source edit is seen (git writes a new mtime); a change of config_text or of the LLVM directory is seen only where bootstrap or a build script happens to key on it, and nothing here measures that. Std's build directory has the answer already (compiled-by, sysroot::forget_another_compiler); the compiler's has none. See the NOTE.
  • issues/two-refusals-of-a-product-whose-sources-moved-have-no-test.md: filing is enough. Both asserts and their missing tests are main's (src/sysroot.rs:782-787, 808-813; this diff changes only the text they return), and main's stores were already shared by every worktree. Its owner is the NOTE below.

BLOCKER

  • PR body, "Not built, not measured" — cargo run -- --ci host has not run at this head — round 1's first, still open; reviewer.md Evidence. It closes without a code change.

NOTE

  • src/compiler.rs:45 — KEYED still reads less than the build does: the fork's root Cargo.toml (the workspace's members, its [profile.*] and [patch.crates-io]; fork commit 6d6ad8c7190 itself changes 12 lines of it), src/version and src/ci/channel (the version a rustc reports; the fork's src/bootstrap/src/core/config/config.rs:1685-1686) and src/build_helper (bootstrap's path dependency outside src/bootstrap, which is all the LLVM key names of it; src/bootstrap/Cargo.toml:38) — read in the fork at 6d6ad8c7190, none measured; a fork commit moving only one of them keeps a stored compiler, which is what library was. Keyed here, where CI is cold anyway and this host's compiler layer rebuilds in seconds, or filed with an owner; every later move of this key is a cold toolchain on each host and three on CI.
  • src/compiler.rs:129,136 — resolve puts the worktree lock down and choose reads the key after, so the key is read while another build of the same worktree may hold the lock exclusively and run bootstrap, which rewrites library/Cargo.lock and Cargo.lock until toolchain::x_build_with's Restore puts them back (src/toolchain.rs:476-479); a key read in that window names a compiler nobody has, builds it, and is refused at place's re-read as "sources moved". Main's shape with Cargo.lock; this round's library extends it from compiler builds to every std build. Loud and stores nothing wrong. The key read moves above without_shared, where the shared lock excludes a bootstrap, or it is filed.
  • PR body, "a compiler rebuilt in a build directory whose inputs changed" — a compromise the branch found and recorded only in the body; root CLAUDE.md wants it in issues/ with an owner, the evidence (this head's 13 s compiler phase, heavy/build.log:4-225) and an exit (the compiler's build directory records the build_text and LLVM key it last built with and starts clean on another, as compiled-by does for std, with a test).
  • issues/two-refusals-of-a-product-whose-sources-moved-have-no-test.md:17 — "Owner: the keyed stores (src/keystore.rs)" names a module, which holds nothing; the step of issues/the-forks-pin-is-a-file-and-a-worktree-checks-no-fork-out.md that rewrites the std build ("A pinned build reads an export") is where build_std becomes something a test can stand in for, or the orchestrator owns it.
  • src/CLAUDE.md:18 — the std type-check is respelled (RUSTUP_TOOLCHAIN=<sysroot>) and its sysroot lost lib/rustlib/src/rust this round; that it still runs is argued from cargo's and rustc's source (__CARGO_TESTS_ONLY_SRC_ROOT is read before the sysroot's rust-src) and not run. One run of the recipe against sysroots/98a89bccae42525e, command and exit code in the body, before an agent is told to use it.
  • PR body, "No in-process sweep in the tree now takes a key whose lock an earlier one of the same process held" — broader than the tree: a_sweep_removes_…'s second sweep meets used and undated, which its first held. True is that no assertion needs such a key taken. Prose.

The landing

1. What it rests on, and what to read.

  • host (ci.yml): it ran, not SKIPPED; cargo run -- --ci host exit 0. This is the first clippy of this branch at CI's version and the first run of every host suite outside the module filter.
  • toolchain / build: the keys step prints four keys and writes <name>-path=rust/build/<kind>/<key>, one line each; all four actions/cache/restore steps miss (a hit on compiler, freestanding or sysroot would be wrong: their keys moved this round); cargo run -- --ci bootstrap exit 0 and says built four times; four actions/cache/save steps each save one directory under toolchain-<name>-<key>. By the body's runner figures the job is hours, not minutes (LLVM about 1:29, compiler about 0:41), inside its 350-minute limit. This is the only measurement of Owner::Us on a store, of the Linux build with LLVM_FORCE_VC_*, and of a stored compiler without the checkout links on Linux.
  • guest / suite: its restore step hits toolchain-sysroot-<key> with the key toolchain / build printed (fail-on-cache-miss), and cargo run -- --ci guest exit 0 with the whole suite's count. It runs whatever toolchain concluded, so a red toolchain shows here as a cache miss: read both.
  • In the merge group the same three, cold again (a merge group restores only its own scope and main's): there only the sysroot's save step runs, by design.
  • A third round reads those runs and the NOTE changes. If a NOTE change moves a key (KEYED), this host's cargo run -- --build-only and the guest suite are owed again at that head, about 8 minutes by heavy/'s 465 s; if it moves none, the suite at 3250e8a22 stands for any head whose target/.deps-stamp is byte-equal.

2. The order on this host.

  1. Close the BLOCKER and the NOTEs; mark the pull request ready; read the three checks as above; correct the body (it still opens "Draft … have not run"); queue it.
  2. Once merged, in the primary: git pull. Run no git submodule there or anywhere: the first build moves rust/ itself. Read today: the primary's fork repository holds 6d6ad8c7190, its rust/ is at cc9c8b1be68 and clean.
  3. Start main's toolchain entries at once: gh workflow run nightly.yml --ref main (or wait for the 03:00 UTC schedule). Until that run's toolchain / build has saved its four entries, every other pull request that has merged main builds the whole toolchain cold on its own ref and again in its merge group. Hold other pull requests in draft until it has.
  4. The primary need not build: it is no workspace, and worktrees read only its fork repository's objects. To verify the landing, cargo run -- --build-only there once. Expect …/rust was at cc9c8b1…, and this tree pins 6d6ad8c…: checked it out, no line Building (LLVM|compiler|the freestanding libraries|sysroot) , then every guest crate once: two to three minutes idle (the second worktree took 70 s from its fork checkout to Build finished.). That holds while main carries the toyos-abi, toyos and sdk sources of 3250e8a22, which f2131918f does. If it prints Building sysroot, main's sources moved: 2:14 plus about 1:30 idle, twice that under load, after it empties the primary's rust/build/toyos-std. If it prints Building compiler it dies at create rust/build/toyos-compiler: File exists: nothing is damaged, the primary's key is not a3df641184b6a414, and the answer is to stop and find why, not to remove the file (step 7).
  5. A worktree that does not merge main keeps working exactly as before: it reads the primary's rust/build/toyos-compiler record and in-place stage2, keeps its products in the primary's rust/build/{llvm,compilers,freestanding,sysroots} and locks in toyos-build-locks in the git directory. No build on the new layout reads, writes or removes any of those: in the primary it touches only the fork checkout's HEAD and rust/build/toyos-std, and the record compares content, not the primary's HEAD. So the two layouts run side by side for as long as step 7 has not happened. Its builds also need no rustup toyos (main names its sysroot by directory).
  6. A worktree that merges origin/main (wt/toyos-fullerboots and every later one): with no build of its own running, merge; the gitlink moves to 6d6ad8c7190 without conflict for the four open today (wt/toyos-fullerboots and wt/toyos-scoutec pin cc9c8b1be68; wt/toyos-hdaresume and wt/toyos-scoutf pin ancestors of it, so none carries fork commits). Its next build moves its fork checkout to the pin (refused, by name, if that checkout holds uncommitted work), finds LLVM 1670055c5e508eba and compiler a3df641184b6a414, builds freestanding libraries and a sysroot only if its toyos-abi, toyos, sdk or manifests differ from a stored key's, and rebuilds every guest crate once, since its sysroot moved. One that edits the fork's compiler/, library/, src/tools, src/stage0 or Cargo.lock builds a compiler in its own rust/build/toyos-compiler, 5:19 cold on an idle host. Its agent rereads root CLAUDE.md and src/CLAUDE.md: cargo +toyos and the global lock are gone. What it left in the primary's old stores is garbage from then on.
  7. The leftovers go when both are true: no build runs in the primary, and this prints nothing, run in the primary: git worktree list --porcelain | sed -n 's/^worktree //p' | while read w; do grep -q 'pub fn host' "$w/src/keystore.rs" || echo "$w"; done. Today it prints the primary's own line until step 2 and the four worktrees of step 6; the set changed while this review ran, so read it at the time. Then, in the primary, the three commands of issues/the-primary-still-holds-the-toolchain-nothing-reads-any-more.md (chmod -R u+w rust/build && rm -rf rust/build; rm -rf "$(git rev-parse --git-common-dir)/toyos-build-locks"; rustup toolchain uninstall toyos), its four exit tests, and the issue deleted by a pull request. Nothing at this head names toyos-build-locks, the harness included, so the whole directory goes. Removing toyos-compiler earlier strands every worktree of step 5.
  8. Nothing is owed for the first round's products (compiler 57730ac698e049ff, freestanding 6fc478ae40e3b5c4, sysroot e8e676e1327c6331): each goes at the first placement of its kind 14 days after its last use.

3. What later steps of the track undo. Nothing this diff adds has to be reverted. Three things it leaves are costs to plan for:

  • The track's first step reads a key's fork parts as git tree ids. sysroot::tree_identity hashes file content, committed or not, so unless that step is written to reproduce today's hash every key moves again: one cold toolchain on each host and three on CI. Batch it with any other key move (the KEYED NOTE).
  • The argument for dropping the stage1-std caveat, and every build's serialisation, is one fork checkout per root under worktree_exclusive(root). The step that builds from an export breaks that premise if the export is shared by pin: its build directories then need a lock by key, and the caveat's cause returns without one.
  • keystore::host() now reads HOME alone and toolchain::ensure calls it directly (src/toolchain.rs:389), while a runner names its store in release::store. The step that removes toolchain::Owner ("a runner keys and finds its sysroot as a dev host does") needs one place that chooses between the two, since a cache entry's path is relative to the workspace and a container job has another home; release::store, lay_out and install are what that step rewrites.
    CHECKOUT_LINKS stays needed (bootstrap links whatever source directory it is given), and the bare repository is a new name at the store's top level, which no sweep reads.

SEND BACK

Japabu and others added 2 commits October 8, 2026 15:57
…rktree's lock, and its build directory starts clean for another build or LLVM

Review round 2 of #769.

The key. `KEYED` gains the fork's root `Cargo.toml` (the workspace the
compiler is compiled in, its profiles and its `[patch.crates-io]`),
`src/version` (bootstrap gives it to rustc as its release), `src/ci/channel`
(bootstrap reads it beside the version; its content reaches a build only
from a tarball, since a git checkout with no `rust.channel` is `dev`, which
the stored rustc's `1.99.0-dev` and `commit-hash: unknown` show),
`src/build_helper` (bootstrap's path dependency outside `src/bootstrap`) and
the launchers `toolchain::x_build_with` runs, `x` and `x.py`. A fork commit
moving only one of them kept a stored compiler, as one moving only `library/`
did before the last round. Every compiler key moves, and with it every
freestanding libraries' and sysroot's key; no LLVM key does.

What else `x.py build --stage 2 compiler/rustc library` reads, checked in the
fork at 6d6ad8c7190 and not keyed: `src/llvm-project/compiler-rt` and
`src/bootstrap` are named through the LLVM's key; `src/librustdoc`,
`src/rustdoc-json-types`, `src/doc`, `src/etc`, `src/gcc`, `tests/` and the
licence files are read by steps this build does not run (a stored `stage2/bin`
holds `rustc` and `cargo` and no `rustdoc`); `src/rustc-std-workspace` has no
dependent in `Cargo.lock`; `.gitmodules` decides which submodules bootstrap
updates and nothing of what it compiles; the worktree's `toyos-abi`, which
the workspace patches in, is a dependency only under `cfg(target_os =
"toyos")` in each of the four forks that name it, so a host-only build
resolves its manifest and compiles none of it. Two inputs outside the fork
are filed: the caller's environment and the worktree's cargo configuration.
The LLVM's key still names only `src/bootstrap` of bootstrap; filed, since
naming the rest moves every LLVM.

The lock. `resolve` read the key after putting the worktree's shared lock
down, so it could be read while another build of the same worktree held the
lock exclusively and bootstrap had the fork's lockfiles rewritten; the build
that followed was refused at `place` as "sources moved". The key is read
before the lock is put down.

The build directory. A compiler was built in `build/toyos-compiler` over
whatever the last build left there, and whether bootstrap and cargo noticed
another configuration or another LLVM directory was theirs to decide. `place`
now empties it of all but bootstrap's downloads unless the build text and the
LLVM's key are the ones recorded there, with the function the std build
directory already has. A source edit alone keeps the directory. The cost: the
first compiler build in every existing build directory is cold, and so is
each one after a change of `RECIPE`, the bootstrap configuration, the
provisioned tools or the LLVM.

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

Japabu commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Mutation patches of fix round 2, each against b7cb92153 (m1 to m5 are the earlier rounds', unchanged; m6 is remade for KEYED's new shape). All thirteen: git apply --check 0, cargo test --lib --no-run 0, test EXIT=101 with only the named test failing, reversed 0, tree clean.

m6-a-compilers-key-reads-no-library

diff --git a/src/compiler.rs b/src/compiler.rs
index 2f105640b..f805d234a 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -48,9 +48,8 @@ const RECIPE: &str = "bootstrap stage 2 of compiler/rustc and library, profile c
 /// in, with its profiles and patches; the version it gives rustc and the
 /// channel file it reads beside it; and what runs bootstrap, with the crate
 /// bootstrap itself is built with.
-const KEYED: [&str; 11] = [
+const KEYED: [&str; 10] = [
     "compiler",
-    "library",
     "src/tools",
     "src/stage0",
     "Cargo.lock",

m7-a-compilers-key-reads-no-workspace-manifest

diff --git a/src/compiler.rs b/src/compiler.rs
index 2f105640b..eab6f31c1 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -48,13 +48,12 @@ const RECIPE: &str = "bootstrap stage 2 of compiler/rustc and library, profile c
 /// in, with its profiles and patches; the version it gives rustc and the
 /// channel file it reads beside it; and what runs bootstrap, with the crate
 /// bootstrap itself is built with.
-const KEYED: [&str; 11] = [
+const KEYED: [&str; 10] = [
     "compiler",
     "library",
     "src/tools",
     "src/stage0",
     "Cargo.lock",
-    "Cargo.toml",
     "src/version",
     "src/ci/channel",
     "src/build_helper",

m8-a-compilers-key-reads-no-version

diff --git a/src/compiler.rs b/src/compiler.rs
index 2f105640b..1af0617f7 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -48,14 +48,13 @@ const RECIPE: &str = "bootstrap stage 2 of compiler/rustc and library, profile c
 /// in, with its profiles and patches; the version it gives rustc and the
 /// channel file it reads beside it; and what runs bootstrap, with the crate
 /// bootstrap itself is built with.
-const KEYED: [&str; 11] = [
+const KEYED: [&str; 10] = [
     "compiler",
     "library",
     "src/tools",
     "src/stage0",
     "Cargo.lock",
     "Cargo.toml",
-    "src/version",
     "src/ci/channel",
     "src/build_helper",
     "x",

m9-a-compilers-key-reads-no-channel

diff --git a/src/compiler.rs b/src/compiler.rs
index 2f105640b..58d6195af 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -48,7 +48,7 @@ const RECIPE: &str = "bootstrap stage 2 of compiler/rustc and library, profile c
 /// in, with its profiles and patches; the version it gives rustc and the
 /// channel file it reads beside it; and what runs bootstrap, with the crate
 /// bootstrap itself is built with.
-const KEYED: [&str; 11] = [
+const KEYED: [&str; 10] = [
     "compiler",
     "library",
     "src/tools",
@@ -56,7 +56,6 @@ const KEYED: [&str; 11] = [
     "Cargo.lock",
     "Cargo.toml",
     "src/version",
-    "src/ci/channel",
     "src/build_helper",
     "x",
     "x.py",

m10-a-compilers-key-reads-no-build-helper

diff --git a/src/compiler.rs b/src/compiler.rs
index 2f105640b..485fd5b1a 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -48,7 +48,7 @@ const RECIPE: &str = "bootstrap stage 2 of compiler/rustc and library, profile c
 /// in, with its profiles and patches; the version it gives rustc and the
 /// channel file it reads beside it; and what runs bootstrap, with the crate
 /// bootstrap itself is built with.
-const KEYED: [&str; 11] = [
+const KEYED: [&str; 10] = [
     "compiler",
     "library",
     "src/tools",
@@ -57,7 +57,6 @@ const KEYED: [&str; 11] = [
     "Cargo.toml",
     "src/version",
     "src/ci/channel",
-    "src/build_helper",
     "x",
     "x.py",
 ];

m11-a-compilers-key-reads-no-x

diff --git a/src/compiler.rs b/src/compiler.rs
index 2f105640b..13931592f 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -48,7 +48,7 @@ const RECIPE: &str = "bootstrap stage 2 of compiler/rustc and library, profile c
 /// in, with its profiles and patches; the version it gives rustc and the
 /// channel file it reads beside it; and what runs bootstrap, with the crate
 /// bootstrap itself is built with.
-const KEYED: [&str; 11] = [
+const KEYED: [&str; 10] = [
     "compiler",
     "library",
     "src/tools",
@@ -58,7 +58,6 @@ const KEYED: [&str; 11] = [
     "src/version",
     "src/ci/channel",
     "src/build_helper",
-    "x",
     "x.py",
 ];
 

m12-a-compilers-key-reads-no-x-py

diff --git a/src/compiler.rs b/src/compiler.rs
index 2f105640b..391587a78 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -48,7 +48,7 @@ const RECIPE: &str = "bootstrap stage 2 of compiler/rustc and library, profile c
 /// in, with its profiles and patches; the version it gives rustc and the
 /// channel file it reads beside it; and what runs bootstrap, with the crate
 /// bootstrap itself is built with.
-const KEYED: [&str; 11] = [
+const KEYED: [&str; 10] = [
     "compiler",
     "library",
     "src/tools",
@@ -59,7 +59,6 @@ const KEYED: [&str; 11] = [
     "src/ci/channel",
     "src/build_helper",
     "x",
-    "x.py",
 ];
 
 /// What a compiler build is beyond its sources, as every key reads it:

m13-a-build-directory-is-built-over-whatever-filled-it

diff --git a/src/compiler.rs b/src/compiler.rs
index 2f105640b..e3e25cbf3 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -34,7 +34,7 @@ use std::path::{Path, PathBuf};
 
 use crate::buildlock::{self, Guard, Held, Keyed};
 use crate::keystore::{self, Key};
-use crate::sysroot::{clone_tree, forget_another_compiler, tree_identity, Links};
+use crate::sysroot::{clone_tree, tree_identity, Links};
 use crate::toolchain::{self, host_triple};
 
 /// What changes how a key's sources become a compiler and is neither them nor
@@ -169,7 +169,6 @@ fn place(root: &Path, fork: &Path, key: &Key, dir: &Path, build: &impl Fn(&Path)
     fs::create_dir_all(&build_dir).unwrap_or_else(|e| panic!("create {}: {e}", build_dir.display()));
     // Bootstrap and cargo reuse what the directory holds whatever configuration
     // and LLVM built it; only a source that moved do they see.
-    forget_another_compiler(&build_dir, &host_triple(), &format!("{}\n{}", build_text(), crate::llvm::key(fork)));
     let stage2 = build(fork);
     crate::llvm::retire_in_tree(&build_dir);
     let partial = dir.with_extension("partial");

The recipe's sentence asked for a workspace `Cargo.toml` written above the
copy of `rust/library`. Run against the store's sysroot 8618c089fa736cb0 at
b7cb921, that spelling exits 101, and so does the fuller manifest with five
members and the library's four patches: a written manifest has no lockfile,
cargo resolves std's dependencies afresh, and offline the only `moto-rt
^0.16` it finds is yanked. Pointing `__CARGO_TESTS_ONLY_SRC_ROOT` at the
copied library itself, whose workspace and `Cargo.lock` cargo then uses,
builds std for x86_64-unknown-toyos and exits 0 in 14.62 s.

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

Japabu commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Review of #769 at d5947fd20 against origin/main d83ab1398, round 3. Read only: no test, build or boot was run for this review; git, the fork checkout's index and the round's logs were read.

Net (git diff --shortstat origin/main...d5947fd20): 42 files, +1175 −2328. Rust: 12 files, +882 −2098; split at each changed file's first #[cfg(test)], production 6360 → 5675 (−685), tests 8187 → 7656 (−531), recounted here. Since the last reviewed head (git diff 3250e8a22 d5947fd20, less what the merge of main brought): src/compiler.rs, eleven lines of src/sysroot.rs, one sentence of src/CLAUDE.md, two issues filed and one re-owned. git diff b7cb92153 d5947fd20 is that one sentence of src/CLAUDE.md and nothing else, so every measurement at b7cb92153 is this head's code. The merge f9cbf2072 resolved nothing by hand (git show --remerge-diff: 6 lines, no hunk), and origin/main is the merged base: the branch is current.

Round 2's BLOCKER

  1. cargo run -- --ci host — OPEN. No run exists at any head. The pull request is a draft and its three checks at d5947fd20 read skipping (host, toolchain, guest), which is not green. What ran at b7cb92153 is the module filter (light/tests.log: 124 passed; 0 failed; 7 ignored, EXIT=0) and a clippy older than CI's (EXIT=0). It closes with no code change, on the host job of the ready pull request at the head that lands, its run in the body.

Round 2's NOTEs

  1. KEYED reads what the build does — CLOSED. Eleven entries; m6 to m12 each EXIT=101, every_source_of_a_compiler_moves_its_key alone failing, each at src/compiler.rs:627 on its own file's "kept the key" (builds/pinfile-r2-light.log). What is still unkeyed is filed twice with a step of the track as owner and an exit a test can fail.
  2. The key is read under the shared lock — CLOSED, by reading: src/compiler.rs:149 reads it before without_shared on line 150, and sysroot.rs:695 is resolve's only caller. No test, and none is owed: the old order was loud and stored nothing wrong.
  3. The build directory starts clean — CLOSED. m13 EXIT=101, a_build_directory_another_llvm_filled_starts_from_nothing alone of nine at src/compiler.rs:486; heavy/sysroot.log holds the record place wrote (the build text, then 1670055c5e508eba), and the cold build that followed fetched nothing (heavy/build.log has no download line) and finished in 4:06.
  4. The two-refusals issue's owner — CLOSED. A step of an assigned track.
  5. The std type-check recipe — CLOSED. A and B EXIT=101 at resolution (moto-rt = "^0.16", 0.16.4 is yanked), C EXIT=0 with a libstd-*.rlib (heavy/typecheck-{A,B,C}.log); the sentence at src/CLAUDE.md:18 words C as build-request-heavy.sh ran it (the copy at <tree>/src/library, the three links in <tree>, the source root the copy, a crate outside the worktree).
  6. Body prose — CLOSED.

Asked of this round

  • The log's compiler key against the stamp's compiler line: two things, as the body says, and both main's. Building compiler 3d1cb62e54e18406 prints compiler::key. The stamp's 56c6ecf6364660be is Key::of(compiler.identity()) (src/sysroot.rs:432), and identity() is that key with the stored driver's name, size and modification time (src/compiler.rs:104-118); origin/main has the same line at src/sysroot.rs:449. The round before read the same pair (a3df641184b6a414 built, 192b66b33fec9d05 in heavy/deps-stamp.before). The second worktree's stamp is byte-equal because both read one driver in one store; on another host, or after a sweep and a rebuild, the stamp's line differs and the key does not, which is what it is for.
  • The implementer's two corrections to the landing hold. The keys: heavy/deps-stamp, heavy/store.built and the build's three Building lines agree on compiler 3d1cb62e54e18406, freestanding dc7c468f0c07446e, sysroot 8618c089fa736cb0, LLVM 1670055c5e508eba found. The cold first build: forget_another_compiler empties a directory whose compiled-by is not this build's (src/sysroot.rs:899-919), and main's src/compiler.rs writes no such record, so every rust/build/toyos-compiler made on main's layout is emptied once. The procedure is restated below.
  • The two issue files: both must be corrected in this pull request. Neither is somebody else's record that happened to be stale; this diff is what made each false. They are the first two NOTEs.

BLOCKER

  • PR body, "Not built, not measured" — cargo run -- --ci host has not run at this head — round 1's first, still open; reviewer.md Evidence.
  • PR body, "The guest suite, at the head before this round" — no guest has booted at b7cb92153 or d5947fd20 — reviewer.md Evidence asks every guest test the change reaches green at the head. The suite's one run was at 3250e8a22 on compiler a3df641184b6a414; since then the compiler's key moved and 3d1cb62e54e18406 was built cold in an emptied directory, and the merge brought Power-off goes through the ACPI server: the claim's holder supplies the sleep type, and the kernel's S5 byte scan is deleted #764's ABI and kernel changes under it. Round 2 said so in advance (its landing step 1: a NOTE change that moves a key owes this host's build and guest suite again). The build ran; the suite did not. 3d1cb62e54e18406 is the compiler every checkout on a development host is served after this lands, and nothing it compiled has booted. Owed: cargo test --test toyos-build in this branch's worktree at the landing head, exit code and count in the body. CI's guest / suite does not stand in, for round 1's reason, unchanged: a runner's compiler is Linux-hosted and its store is release::store, never keystore::host. It closes with no code change.

NOTE

  • issues/the-build-system-does-not-compile-on-windows.md:13-24 — its judge is spelled in a shape this branch measured red for a reason that is not Windows, and now contradicts the recipe it defers to — this diff rewrote line 15 of that command, and rewrote src/CLAUDE.md:18, which the issue cites as "src/CLAUDE.md's std-src-root recipe with one addition: a workspace Cargo.toml"; that recipe now says a manifest written above the copy has no lockfile and does not resolve offline, and heavy/typecheck-B.log is the issue's own manifest exiting 101 before it compiles a line. "Not this branch's to edit" does not hold for a file the branch edits and a citation the branch broke. Corrected here: <scratch> is the recipe's copied library with no addition, and the command run once in that shape against sysroots/8618c089fa736cb0 (--target x86_64-pc-windows-msvc -p toyos-build --all-targets), its exit and first error in the body; the judge is right when that error is in src/tether.rs or its like and not in cargo's resolution. If it is not, the issue says what the judge needs instead.
  • issues/a-compiler-key-reads-no-symbolic-link.md:9-10,20-22 — false of the tree twice by this diff — it says compiler::key reads "compiler/, src/tools/, src/stage0 and Cargo.lock", which is now eleven entries, and its exit is "landed with the next change to compiler.rs's RECIPE, which moves every compiler key anyway": origin/main's RECIPE ends ; 6 and this head's ; 7, so this branch is that change, moved every compiler key in each of its three rounds, and neither lands the exit nor says who does. Read at the fork pin 6d6ad8c7190: git ls-files -s over the eleven KEYED paths lists the same five entries of mode 120000, all under src/tools, so the widening put no new link outside the key. Either Links::Skipped goes here (one more key move: the build and the suite again), or the issue is corrected here: it cites compiler::KEYED, its evidence is re-read at the pin, and its exit names the track's first step, where a key's fork parts become git tree ids and a link's target text is in the key by construction.
  • issues/the-primary-still-holds-the-toolchain-nothing-reads-any-more.md:22 — "compiler::build_in_fork creates rust/build/toyos-compiler/": since b7cb92153 it is compiler::place (src/compiler.rs:169), before anything is emptied, so the refusal still removes nothing. Prose.
  • PR body, "The Windows issue's variant is B's shape and is not this branch's to edit" — it is, by the first NOTE. Prose.

The landing, as it stands for d5947fd20

Steps 1, 4, 6 and 8 changed; 2, 3, 5 and 7 are round 2's, restated.

  1. Before the queue. Correct the two issues (issue files only: no key moves, target/.deps-stamp stays byte-equal, and every measurement at b7cb92153 stands). Run the guest suite in this worktree. Mark the pull request ready and read three checks at that head: host ran and is green; toolchain / build prints four keys, misses all four restores, says built four times and saves four entries; guest / suite hits toolchain-sysroot-<key> with the key toolchain printed and is green with the whole suite's count. A runner's keys are its own: they are not this host's 3d1cb62e54e18406 and 8618c089fa736cb0. Put the runs in the body, then queue. The merge group runs all three cold again.
  2. Once merged, in the primary: git pull, and no git submodule there or anywhere.
  3. Start main's cache entries at once: gh workflow run nightly.yml --ref main, or wait for the schedule. Until its toolchain / build has saved four entries, every pull request that has merged main builds the toolchain cold on its own ref and again in its merge group; hold the others in draft until then.
  4. The primary need not build. To verify, cargo run -- --build-only there once: it moves rust/ from cc9c8b1be68 to 6d6ad8c7190, prints no line Building (LLVM|compiler|the freestanding libraries|sysroot) , and builds every guest crate once (the second worktree: 58 s from its fork checkout to Build finished., second/second.log). That holds while main carries this head's toyos-abi, toyos, sdk and std manifests; if another pull request lands first and moves one, it prints Building the freestanding libraries or Building sysroot (1:30 and 0:57 at this round's load). If it prints Building compiler the primary's key is not 3d1cb62e54e18406 and it dies at create …/rust/build/toyos-compiler: File exists, now raised by compiler::place before anything is emptied: nothing is damaged; stop and find why the key differs, and do not remove the file (step 7).
  5. A worktree that does not merge main works as before, on the primary's rust/build and toyos-build-locks, which no build on the new layout reads, writes or removes.
  6. A worktree that merges origin/main, with no build of its own running: its next build moves its fork checkout to 6d6ad8c7190 (refused by name over uncommitted work), finds LLVM 1670055c5e508eba and compiler 3d1cb62e54e18406, builds freestanding libraries and a sysroot only where its toyos-abi, toyos, sdk or manifests differ from dc7c468f0c07446e's and 8618c089fa736cb0's, and rebuilds every guest crate once. One whose fork differs in any of the eleven KEYED paths (compiler, library, src/tools, src/stage0, Cargo.lock, Cargo.toml, src/version, src/ci/channel, src/build_helper, x, x.py), so now any worktree that edits std in the fork, builds a compiler in its own rust/build/toyos-compiler, and the first such build there is cold whatever the directory held: 5:19 idle by round 1, 4:06 this round. Later ones are incremental until the build text or the LLVM changes. Its agent rereads root CLAUDE.md and src/CLAUDE.md.
  7. The leftovers go when no build runs in the primary and no worktree git worktree list names lacks pub fn host in its src/keystore.rs: the three commands and four exit tests of issues/the-primary-still-holds-the-toolchain-nothing-reads-any-more.md, and the issue deleted by a pull request. Removing toyos-compiler earlier strands every worktree of step 5.
  8. Nothing is owed for the two earlier rounds' products (compilers 57730ac698e049ff and a3df641184b6a414, freestanding 6fc478ae40e3b5c4 and 11781b8326310eac, sysroots e8e676e1327c6331 and 98a89bccae42525e): no tree names them, and each goes at the first placement of its kind 14 days after its last use. 57730ac698e049ff still carries the two links into this branch's fork checkout (heavy/sysroot.log); they dangle once the worktree is removed and nothing reads them.

What later steps of the track meet is round 2's, with one addition: the track's first step is now also where the symbolic-link issue and issues/an-llvms-key-names-of-bootstrap-only-src-bootstrap.md exit, so that one key move pays for all three.

SEND BACK

Japabu and others added 2 commits October 8, 2026 16:30
The Windows judge deferred to the std type-check recipe "with one addition",
a written workspace manifest; the recipe now says such a manifest does not
resolve offline, and that manifest exited 101 at resolution when this branch
ran it. The judge is the recipe's tree with no addition.

The symbolic-link issue named four keyed paths and exited at "the next
change to RECIPE": the key reads eleven (`compiler::KEYED`), re-read at fork
commit 6d6ad8c7190 for links (the same five, all under `src/tools`), and this
branch changed `RECIPE` without landing the exit. Its exit is the track's
first step, which reads keys as git tree ids and moves every key anyway.

The primary's `toyos-compiler` file is refused by `compiler::place`, which
creates the directory since the build directory's record went in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
Run once in the std type-check recipe's tree against the store's sysroot
8618c089fa736cb0, `cargo check -Z build-std=std,panic_abort --target
x86_64-pc-windows-msvc --offline -p toyos-build --all-targets` builds std for
Windows and exits 101 at the 37th crate: ring 0.17.14's build script compiles
C for the target with the host's `cc`, which has no `assert.h` for it. No
source of the build system is reached, so the judge needs the target's C
headers, and its heading no longer says it needs no download.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
@Japabu
Japabu marked this pull request as ready for review October 8, 2026 14:39
@Japabu

Japabu commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Review of #769 at 5a407d6be against origin/main d83ab1398, round 4. Read only: no test, build or boot was run for this review; git, the fork checkout's index, the round's logs and the pull request's check runs were read.

Net (git diff --shortstat origin/main...5a407d6be): 43 files, +1211 −2352. Rust is round 3's, no .rs file having changed since: 12 files, +882 −2098, production 6360 → 5675 (−685), tests 8187 → 7656 (−531). Since the last reviewed head (git diff d5947fd20 5a407d6be): three files under issues/, +38 −26, and nothing else. git diff b7cb92153 5a407d6be is those three and src/CLAUDE.md's one sentence, so every measurement at b7cb92153 is this head's code. origin/main has not moved: the branch is current.

Round 3's BLOCKERs

  1. cargo run -- --ci host — OPEN. No run has finished at any head. The pull request is ready, and the ci run for pull_request at 5a407d6be that started on it has host and toolchain / build in progress and guest / suite not yet created. It closes with no code change and no further review, on the reading set out under "What closes it" below.
  2. The guest suite at the landing head's code — CLOSED. pinfile-r2/suite/suite.log, at 3def81032: cargo test --test toyos-build, suite EXIT=0 printed by the line after the command; running 36 tests, 12 wide, 36 RUN lines, 36 PASS lines, no FAIL, STALL, panic or error line, and the harness's 36 passed, 36 total. No line Building (LLVM|compiler|the freestanding libraries|sysroot) (count 0); target/.deps-stamp after it is byte-equal to the one recorded at b7cb92153 (cmp 0, re-run here on the two saved copies: sysroot 8618c089fa736cb0, freestanding dc7c468f0c07446e), and the store's four name lists before and after are byte-equal (cmp 0, re-run here). git diff --stat 3def81032 5a407d6be is issues/the-build-system-does-not-compile-on-windows.md alone, which no build reads. The command is src/ci.rs's suite_args without --jobs 1, as the body says.

Round 3's NOTEs

  1. The Windows issue's judge — CLOSED. The command is the recipe's tree with no added manifest, and it ran once in that shape against sysroots/8618c089fa736cb0: judge EXIT=101; pinfile-r2/suite/judge.log has 37 Compiling lines, core, std, windows-link and test from the copied library among them, and one error, failed to run custom build command for ring v0.17.14, under check.h:27:11: fatal error: 'assert.h' file not found from cc --target=x86_64-pc-windows-msvc. No line of it names a source of toyos-build. The issue's heading and its new paragraph say exactly that, and what the judge needs instead.
  2. The symbolic-link issue — CLOSED. It cites compiler::KEYED; git -C rust ls-files -s over the eleven paths at 6d6ad8c7190, re-read here, lists the five entries of mode 120000 the issue now names (rustc_tools_util's and lsp-server's two licence files, rust-analyzer's AGENTS.md); its owner is a step that exists (issues/the-forks-pin-is-a-file-and-a-worktree-checks-no-fork-out.md:20, of an assigned track), and its exit is a deletion and a test, both of which a build can fail.
  3. compiler::place in the primary's issue — CLOSED. src/compiler.rs:169 creates the directory and line 172 is the first thing that empties anything.
  4. Body, "not this branch's to edit" — CLOSED. The sentence is gone and the third review's section says what was done.

BLOCKER

  • PR body, "CI, on the ready pull request" — cargo run -- --ci host has not finished at this head, and the section is empty — round 1's first, still open; reviewer.md Evidence.

NOTE

  • issues/the-build-system-does-not-compile-on-windows.md:42 — cites link_host_target, which this branch deletes with the rustup link (git grep link_host_target 5a407d6be finds this line and no source; origin/main:src/toolchain.rs:1037 had it) — a citation that points at nothing, in a file this diff edits. Prose. Correcting it is one issue line and moves the head: the run in progress is cancelled and the three checks below are read at the new head, the local measurements standing as they do now.

What closes it

Nothing but BLOCKER 1 is open. It is closed, and the branch lands with no further review, when all of the following are read at one head, that head being the one queued (5a407d6be, or its successor if the NOTE is taken, differing from it only under issues/), and are put in the body's "CI, on the ready pull request" with each run's URL:

Which run. The ci run on pull_request whose headSha is that head and whose jobs ran. A second ci run exists at 5a407d6be, made while the pull request was still a draft, in which host, toolchain and guest all concluded skipped; gh pr checks lists its guest and toolchain beside the live run's jobs today. A skipped job is a green check and is not this evidence. Each job below is read by its own conclusion and log, never by the pull request's rollup.

  1. host concluded success. The step cargo run -- --ci host exits 0, its log ends [ci] Host: <n> step(s), all green, and no line of it begins - RED:.
  2. toolchain / build concluded success.
    • The keys step prints [ci] the stores of this tree's toolchain: llvm <K1>, compiler <K2>, freestanding <K3>, sysroot <K4>. The keys are the runner's own and are not this host's.
    • Each of the four actions/cache/restore steps misses: toolchain-llvm-<K1>, toolchain-compiler-<K2>, toolchain-freestanding-<K3>, toolchain-sysroot-<K4>. The LLVM's too: its key reads config_text, which this branch gives the stamp, so no entry of main's has it.
    • The build step prints [ci] this tree's toolchain: llvm <K1> built, compiler <K2> built, freestanding <K3> built, sysroot <K4> built and [ci] Bootstrap: 1 step(s), all green, with the same four keys as the keys step.
    • All four actions/cache/save steps run and each reports its entry saved.
    • If the job was re-run after a red attempt and a layer reads restored or not needed, the attempt that saved that layer is read for its built instead; a layer restored from anything but this pull request's own earlier attempt is a red, since it means a key of main's names it.
  3. guest / suite ran and concluded success; skipped is a red here.
    • Its restore step hits exactly toolchain-sysroot-<K4>, the key toolchain / build printed.
    • The step cargo run -- --ci guest exits 0 and prints [ci] the toolchain: with no refusal, [ci] the suite: test result: ok. <N> passed, <N> total (…) and [ci] Guest: <n> step(s), all green.
    • <N> is the suite's own running <N> tests and equals what main's last guest / suite printed at d83ab1398: the branch adds and cuts no guest test, its one change under tests/ being an argument of one call in tests/common/compile.rs.

Any of these red, or any line differing from the above, is the implementer's and another round. The merge group then runs all three cold again; round 3's landing steps 2 to 8 are unchanged by this round.

SEND BACK

Japabu and others added 2 commits October 8, 2026 16:43
`link_host_target` went with the in-place compiler; of the two symlink
callers the issue named, `provision_toolchain_cargo` is the one left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
CI's clippy 1.99 denies a clone of a value dropped without further use
(`primarys.stage2.clone()` in an `assert_eq!`) and a `Duration` subtracted
from a `Duration` unchecked (`KEPT - Duration::from_secs(3600)`); this
host's older clippy raises neither. The assertion compares references, and
the duration is built from seconds as `LONG_AGO` beside it is. Both lines are
in `mod tests`.

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

Japabu commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

CI at 9a7d15900, read against round 4's list (orchestrator): run 37800146983, event pull_request, conclusion success, each job read by its own conclusion and log. The first host run, at b83eb464b (run 37794832085), was red on two clippy lints in test code (src/compiler.rs:379, src/keystore.rs:271); this head fixes those two lines and nothing else.

  1. host: success. [ci] Host: 78 step(s), all green; no RED: line.
  2. toolchain / build: success.
    • [ci] the stores of this tree's toolchain: llvm a2cc063281d9f279, compiler 6c76c19e5ffcc869, freestanding 0f5a5faab7bbc78c, sysroot 5f85c696604b34b5
    • four restores, each Cache not found for input keys: toolchain-llvm-a2cc063281d9f279, toolchain-compiler-6c76c19e5ffcc869, toolchain-freestanding-0f5a5faab7bbc78c, toolchain-sysroot-5f85c696604b34b5
    • [ci] this tree's toolchain: llvm a2cc063281d9f279 built, compiler 6c76c19e5ffcc869 built, freestanding 0f5a5faab7bbc78c built, sysroot 5f85c696604b34b5 built and [ci] Bootstrap: 1 step(s), all green (15:25:05 to 16:44:51)
    • four Cache saved with key: lines, the same four keys.
  3. guest / suite: success, not skipped. Cache hit for: toolchain-sysroot-5f85c696604b34b5; [ci] the toolchain: installed sysroot 5f85c696604b34b5; running 36 tests; [ci] the suite: test result: ok. 36 passed, 36 total; [ci] Guest: 5 step(s), all green.

@Japabu

Japabu commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Review of #769 at 9a7d15900 against origin/main 809c33c0c, round 5, narrow. Read only: no test, build or boot was run for this review; git, the pull request's record, the repository's cache list and ruleset, and the job logs of runs 37800146983, 37794832085, 37794223102, 37783473132, 37799233280 and 37786414236 were read (the three logs of 37800146983 fetched here are byte-equal to the orchestrator's copies, cmp 0 each).

Net (git diff --shortstat origin/main...9a7d15900): 43 files, +1213 −2355. Rust is round 3's split, the two changed lines being one for one in test modules: production 6360 → 5675 (−685), tests 8187 → 7656 (−531).

Round 4's BLOCKER

  1. cargo run -- --ci host, and CI's three checks — CLOSED on the measurement. Run 37800146983, ci on pull_request, headSha 9a7d15900, every job run and none skipped, read item by item below. What round 4 also asked, the readings in the body's "CI, on the ready pull request", is not done: that is the one NOTE that is not prose, and it is the orchestrator's edit, not the implementer's.

Round 4's NOTE

  1. link_host_target in the Windows issue — CLOSED. b83eb464b rewrites the sentence to name provision_toolchain_cargo alone, which exists at this head (src/toolchain.rs:331); git grep link_host_target 9a7d15900 finds nothing.

1. What changed since 5a407d6be

  • git diff 5a407d6be 9a7d15900 is three hunks and nothing else: the issue's sentence (issues/the-build-system-does-not-compile-on-windows.md:42-43), src/compiler.rs:379, src/keystore.rs:271. Both .rs lines are inside #[cfg(test)] pub(crate) mod tests.
  • src/compiler.rs:379: (&primarys.stage2, builds.get()) == (&mine.stage2, 1). A reference's PartialEq and Debug are its referent's, so it compares the two paths by value and prints what it printed; it is the assertion it was, without two clones.
  • src/keystore.rs:271: KEPT is Duration::from_secs(14 * 24 * 60 * 60) (:72), whole seconds, so Duration::from_secs(KEPT.as_secs() - 3600) is 1_206_000 s, the same Duration as KEPT - Duration::from_secs(3600): no sub-second part to lose, no underflow, and the form LONG_AGO already had on line 251. used is still dated one hour inside the keep time and the sweep's expected list is untouched.
  • CI ran both at this head: keystore::tests::a_sweep_removes_what_nobody_used_for_the_keep_time_and_nobody_uses ... ok and compiler::tests::one_compiler_per_key_whichever_checkout_names_it ... ok, and both workspace clippy steps green. The red at b83eb464b (job 113371853219) was those two lints and no third: could not compile toyos-build (lib test) due to 2 previous errors, 1 of 78 step(s) red.
  • No toolchain key reads either file, by reading and by measurement. A key reads the fork (compiler::KEYED, library and src/bootstrap, all paths under rust/), SYSROOT_SOURCES, SYSROOT_MANIFESTS and constants of production code; none names a source of the build system. And the keys step printed the same four at all three heads: llvm a2cc063281d9f279, compiler 6c76c19e5ffcc869, freestanding 0f5a5faab7bbc78c, sysroot 5f85c696604b34b5 at 5a407d6be (job 113369334763), b83eb464b (113371853505) and 9a7d15900 (113390158736).
  • The local suite at 3def81032 stands: git diff --stat 3def81032 9a7d15900 is the issue file and these two test lines, and the harness links the build system's library without its test modules.

2. Run 37800146983 against round 4's list

All three jobs checked out 36c483c, Merge 9a7d15900… into d83ab1398…: the base is main before #770.

  1. host (job 113390157791): success. Step cargo run -- --ci host success; [ci] Host: 78 step(s), all green; no line - RED:. Matches the orchestrator's reading.
  2. toolchain / build (job 113390158736): success.
    • keys: the four above. Matches.
    • Four restores, each Cache not found for input keys: with toolchain-llvm-a2cc063281d9f279, toolchain-compiler-6c76c19e5ffcc869, toolchain-freestanding-0f5a5faab7bbc78c, toolchain-sysroot-5f85c696604b34b5. main's scope today holds toolchain-llvm-de9832f20dcfb55a, toolchain-compiler-ab3cd31ffabc7761, toolchain-freestanding-d2fa8dd3a5314850 and five sysroots, none of these keys, so the LLVM's key moved as round 4 said it must.
    • [ci] this tree's toolchain: llvm a2cc063281d9f279 built, compiler 6c76c19e5ffcc869 built, freestanding 0f5a5faab7bbc78c built, sysroot 5f85c696604b34b5 built, then [ci] Bootstrap: 1 step(s), all green; the step ran 15:25:05 to 16:44:51, 79 min 46 s.
    • Four Cache saved with key: lines, the same four keys; the cache list holds them under refs/pull/769/merge and nowhere else.
    • First attempt, so the re-run clause does not arise; the two earlier runs were cancelled before any save.
  3. guest / suite (job 113428345579): success, ran.
    • Cache hit for: toolchain-sysroot-5f85c696604b34b5, Cache Size: ~401 MB (420620028 B), which is to the byte the entry toolchain / build saved under refs/pull/769/merge 2 min earlier.
    • [ci] the toolchain: installed sysroot 5f85c696604b34b5, no refusal; running 36 tests, 1 wide; [ci] the suite: test result: ok. 36 passed, 36 total; [ci] Guest: 5 step(s), all green.
    • 36 is main's: guest / suite of the merge group that made d83ab1398 (run 37783473132) printed running 36 tests and 36 passed, 36 total, and so did The T14 profile goes from 30 boots to 27: the orderly-reboot rows ride metalcase, the self-tests arm shared-debug, and netstack's lease probe is deleted #770's (run 37799233280, 809c33c0c). The 36 names of each of the three runs, sorted, are identical (diff 0 twice).
    • One line differs from main's by design and is no refusal: main prints installed sysroot 19a2dfe20f00a376 as \toyos`, this branch installed sysroot 5f85c696604b34b5`, the rustup name being what it deletes.

No toolchain layer came from anything but a miss. The one restore that hit an entry of main's is host's: Cache hit for restore-key: host-sealed-Linux-X64-37778826093. That restore is right, and is not what round 4's clause calls a red. The clause is about the four layers of toolchain / build, where a hit would mean a key of main's names a product of this branch. The host cache is cargo's registry and target, restored by ci.yml's restore-keys prefix from the one writer, nightly's host on main (run 37778826093, workflow_dispatch on main at 8a883a142; the run reads cancelled for its macOS job, its host job concluded success), and this branch changes neither workflow nor src/cicache.rs. It holds no toolchain product and is trusted by content, not by key: [ci] the cache entry, read by content: built from 8a883a14…: 763 of 2524 sources dated as built; 62 changed, 8 added, 9 removed, in 9 packages. Recounted here, git diff --name-status 8a883a142 <the tree of d83ab1398 merged with 9a7d15900> is 8 added, 9 deleted and 63 modified, the 63rd being the rust gitlink, which is no file. So every source this branch touches was dated now, and the build system's package was compiled from this head's bytes.

3. main has moved

NOTE

  • PR body, "CI, on the ready pull request" — the three bullets are empty past At 9a7d15900: — reviewer.md Evidence wants the measurement in the body, which becomes main's record; the measurement exists and is read above. To write: host: run 37800146983, job 113390157791, success, [ci] Host: 78 step(s), all green. toolchain / build: job 113390158736, success, the keys line, four Cache not found, the built line, [ci] Bootstrap: 1 step(s), all green, four Cache saved with key:. guest / suite: job 113428345579, success, Cache hit for: toolchain-sysroot-5f85c696604b34b5, running 36 tests, 36 passed, 36 total, [ci] Guest: 5 step(s), all green, and that 36 is run 37783473132's. Each with its URL.
  • PR body, "Not built, not measured", first two bullets — say cargo run -- --ci host and CI's toolchain path are yet to be read on CI — false of the record once the bullets above are filled. Prose.

The landing, for 9a7d15900

Steps 2 and 4 to 8 stand word for word as round 3 gave them and round 4 left them: the two test lines and the issue line move no key and no file a build reads. Step 1 is restated for what is left of it. Step 3 was wrong in its mechanism and too narrow in its scope, in rounds 2 and 3 alike, and is replaced.

  1. Before the queue. Fill the body as the first NOTE says. Queue when nothing is ahead: toyos-net-node: the node and its DHCP lease on ToyOS's own stack, host-tested and shipped in nothing #771 is first in the queue now, and a red ahead of this branch rebuilds its merge group, which is cold. The group runs all three checks cold again, about 97 minutes by this run (15:22 to 16:59), inside the queue's 240-minute check timeout (ruleset main, check_response_timeout_minutes), and saves the sysroot alone in its own scope.
  2. main's entries start themselves, and nothing is dispatched. publish.yml runs on every push to main and calls toolchain.yml: the landing's own publish run has a toolchain / build on refs/heads/main, which misses four times, builds cold (79 min 46 s here) and, the event not being merge_group, saves all four. Run 37786414236 is that job after Power-off goes through the ACPI server: the claim's holder supplies the sleep type, and the kernel's S5 byte scan is deleted #764 (13:42 to 13:51), and refs/heads/main's toolchain-sysroot-19a2dfe20f00a376, created 13:51:34Z, is what it saved. A dispatched nightly adds nothing: its toolchain / build waits behind that one in toolchain-refs/heads/main and then restores. The event to wait for is four Cache saved with key: lines in the toolchain / build of the publish run on the landing commit.
    Until then every ci run that starts on any pull request is cold, whether or not its branch merged main: a pull_request run checks out the merge of its head into main as main then stands (this run: Merge 9a7d15900… into d83ab1398…), so the tree it keys carries this change from the first event after the landing. All four keys moved, so all four layers miss; each such run is about 80 minutes before its guest suite starts, is cancelled and started over by the next push to the same pull request, and saves 913 MB (this run's four entries: 912,576,781 bytes) into a store that holds 9.52 GB of its 10 GB today (22 entries, 9,519,768,280 bytes). Every merge group is cold the same way and saves 421 MB. A run that started before the landing keeps the tree it checked out and main's present entries.
    So all seven, toyos-net-node: the node and its DHCP lease on ToyOS's own stack, host-tested and shipped in nothing #771 to toyos-net-node: listeners on the own stack's accept queue, and one bound on the streams, listeners and datagram sockets clients make the node hold (stage E) #777, build cold on their next event inside that window; none is exempt, and none needs to merge main for it. What to do with each:

What later steps of the track meet is round 3's, unchanged.

LAND AFTER NAMED CHANGES

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