Repository navigation
The guest suite is every pull request's guest check, on toolchain stores CI caches by the build system's own keys; a landing during a nightly does not red its release - #671
Conversation
… toolchain ci.yml gains two jobs on every non-draft pull request and in the merge queue: - `toolchain`, `cargo run -- --ci toolchain` on bare ubuntu-24.04, as the nightly's `build` runs it: a lookup when the tree hashes what an earlier run published, a bootstrap of hours when the branch moved the trees the tag hashes (src/release.rs). A runner's toolchain is the release its tree's tag names, and nothing else can install one, so a gate that only installed would red every pull request from the landing that moved main's tag until a nightly published it. - `guest`, `cargo run -- --ci guest` in the nightly's pinned debian:sid container with `/dev/kvm`, restoring the guest cache the nightly's `tcg` writes. It needs `toolchain` and runs whatever that concluded, unless the run was cancelled: GitHub reads a skipped required check as green, so a failed toolchain must reach `guest` as a red install, not skip it. The nightly keeps what the gate does not cover: `tcg` (x86-64 decoded by TCG, and the guest cache's one writer), `build` (the SDK alias on main), `host` and portability. Its `guest` job goes; `tcg` takes the steps it shared through anchors. Two gates in src/ci.rs replace prose: `guest` needs `toolchain` and is not skipped past it, and ci.yml's `guest` and the nightly's `tcg` name one image digest and one cache path list, since a restore whose paths are not its writer's restores nothing, silently. CLAUDE.md, the implementer's and the orchestrator's prompts say the guest suite runs in CI's `guest` check and agents never run QEMU locally; the host-tool rows name ci.yml's jobs beside the nightly's. src/release.rs's "the nightly's `build` job is what publishes one" stays: release.rs is hashed into the toolchain's tag, so any edit to it costs a toolchain bootstrap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
The first runs of the 21-test suite on a GitHub runner went 4 passed and 17 failed, on PR #671's `guest` check (run 36863809437) and on main's own nightly `guest` lane at 0678814 (run 36843762360), with the same reds in both: - every `virt_*` boot takes a Synchronous Exception inside the kernel image before the kernel prints anything, under Debian's AAVMF 2026.05-2, where the dev host's QEMU-bundled edk2-stable202408 boots them green; - `nested_nmi_is_loud` under KVM: the unlocked nested-NMI report and cpu1's "joining scheduler" record interleave byte by byte on the 16550, so "NESTED NMI" never appears whole. Neither is this branch's to fix; each is filed with its exit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
Main's nightly `tcg` lane at 0678814 (job 110374194382) passed `nested_nmi_is_loud` on the same container with no `/dev/kvm`, and its sixteen `virt_*` reds are the KVM lane's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
|
Review, round 1, at CI. No run at Net lines (
The brief
Plan: not acceptable.
Land
BLOCKER
NOTE
REMOVE
SEND BACK |
…nd a vouched commit stand behind, and one definition per lane Security (B1). No job a pull request, the merge queue or the nightly runs holds a token that writes: ci.yml and nightly.yml give their jobs `contents: read` and `actions: read` at the top, and the two workflows they call ask for nothing of their own. The one `contents: write` in any workflow is publish.yml's `release`, and `cargo run -- --ci release` refuses by name before it reads anything unless it runs as publish.yml on main, pushed or dispatched. The nightly's `build`, which published from any branch it was dispatched on, is gone: runs 36709239346 and 36600425263 published wt/toyos-castore's and wt/toyos-notiers' toolchains that way. CI no longer installs a release. toolchain.yml uploads each toolchain it bootstraps whole (upload-artifact v7, `archive: false`), so GitHub's recorded SHA-256 of the artifact is the tarball's own. `release::install` takes the newest build of its tree's tag made by main's publisher; failing that, it takes the newest made by a run of a commit its tree vouches for: its first-parent chain, and the head each merge on that chain took in. It refuses any other, and any download whose bytes hash to anything but GitHub's digest. An artifact is rewritten by nobody. The tag now hashes the build system that builds the toolchain: every module src/toolchain.rs and src/release.rs reach through `crate::`, 18 files, held to the sources by a test that recomputes the closure. Over main's last 100 first-parent landings that moves the tag on 32 where the old trees moved it on 20. The three `SOURCE` constants that existed only for the tag go. Timing (B2). Main publishes on every push (publish.yml's `toolchain` and `release`), not at 03:00. A tree no build answers for bootstraps in its own run's `toolchain` job and publishes nothing: 2h19m to 3h08m in the nightly `build` jobs that bootstrapped since 2026-09-29. Its merge group and every tree in main's window before main's own build lands install that pull request head's build, so the queue never bootstraps unless main moved the toolchain's inputs after the head's last run. One definition (B3). guest.yml is the guest lane, with KVM and the cache save as inputs; toolchain.yml is the toolchain job. ci.yml, nightly.yml and publish.yml call them. The shared-digest test and the cross-file comments go. B4: the guest lanes' gate holds `guest`'s `if:` whole, as `!cancelled()` around `host`'s condition, so the `needs.toolchain.result` mutation reds it. B5: CLAUDE.md and implementer.md say the plain suite runs in CI's `guest` check and the orchestrator runs every guest mutation; orchestrator.md is main's again. The two issue files this branch filed go: #675 and #676, batched with it, close them. The release-tag and install-digest issues close here; the release asset's remaining mutability is filed. The REMOVEd prose is deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…ntry `release_as` takes the workflow and event the runner names, so the test that refuses a pull request's, the merge queue's, the nightly's and a branch dispatch's job calls the release job itself rather than the check it starts with: deleting the check now reds a test, where before only a run of `cargo run -- --ci release` under a pull request's environment showed it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…at drops one reds on its assertion It read each builder back from the fixture, which holds only what `trees()` names, so a tag that stopped hashing the builders panicked on a missing file instead of reporting the module whose commit kept the tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
|
Review, round 2, at CI. Run 36883368774 at Net lines (
The production growth buys provenance that S1 and S2 show it does not have. Main moved. origin/main moved to Round 1
The brief
BLOCKER
NOTE
REMOVE
SEND BACK |
…unless shipped, no rustdoc or rustc debuginfo Round 3's ruling makes every store fit GitHub's 10 GB before CI carries them. Measured on the Linux release asset toolchain-linux-x86_64-48dd24f826263d6c and on this host's stores, compressed as actions/cache v4.3.0 stores an entry (tar, then zstdmt at level 3, as its logs print). a. The LLVM store keeps what builds read of bootstrap's install (`llvm::keep`): llvm-config, clang and llvm-ar, and llvm-objcopy on an Apple host; LLVM's headers; every library llvm-config names, since a compiler links LLVM through it and it refuses to name an absent one; and clang's resource headers. Not LLVM's other tools, clang's libraries and headers, nor CMake's package files. RECIPE moves to 4, so every LLVM key moves. Every compiler build says `llvm-tools = false`, because bootstrap copies its fourteen LLVM tools from llvm-config's bindir and would fail; `clang::provision` now copies llvm-ar, and on an Apple host llvm-objcopy as rust-objcopy, which rustc runs to strip a Darwin binary (rustc_codegen_ssa/src/back/link.rs) and which build scripts read here (the atime of every sysroot's rust-objcopy on this host is past its mtime). This host's LLVM 1425e623e612b348 is 741,348,616 B; what `keep` takes of it, staged by hand with the same selection, is 121,952,968 B. b. The primary builds the ToyOS-hosted rustc only for a build whose config ships it (`ensure`'s `hosted_rustc`). system.toml says no, and build.rs's `shipped` refuses every config that says yes, so no build makes it today, and the release no longer packs it. A compiler rebuild removes the hosted rustc of the compiler it replaced. The primary's bootstrap builds the host alone, as a worktree's compiler already does: every sysroot builds its own guest libraries and replaced the bootstrap's. c. The sysroot's 602,893,995 B was its compiler, 387,515,558 B, and the guest libraries, 215,377,065 B. Of the compiler: rustc's driver, 139,196,011 B alone, of which its line-table debuginfo is 64,174,215 B (stripped by llvm-objcopy --strip-debug, 75,021,796 B); 99,649,817 B of LLVM tools no build runs; rustdoc, 13,738,023 B, which no build runs (the toolchain builds no doc-test). Of the guest libraries, 163,254,188 B is metadata, which every crate compiled for those targets reads: upstream stable's own core metadata is 64,091,289 B raw for aarch64-unknown-none-softfloat, against the fork's 67,346,795 B for x86_64-unknown-none. Their rlibs' debuginfo is 7,222,696 B (38,817,617 B with it, 31,594,921 B without), which the linker reads, so it stays. So the primary builds `compiler/rustc library` and no rustdoc, and every compiler build says `debuginfo-level-rustc = 0`. The compiler RECIPE moves to 6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
… PATH on an Apple host The first build of the previous commit on this host stopped twice, and each stop is a fix here; with both, `cargo run -- --build-only` built LLVM c54c833acd75e98b, compiler a4e3d9b05e1747d8, freestanding libraries 8d5c8b9068ca7480, sysroot 3b3ed0fb252fe96d and the image, EXIT=0. - Bootstrap's sanity check demands LLVM's FileCheck beside an external llvm-config while codegen tests are on (src/bootstrap/src/core/sanity.rs:320). No build runs them, so every compiler build says `codegen-tests = false`, and the LLVM store keeps no FileCheck. - The rust workspace strips lld-wrapper (`strip = true` in its Cargo.toml), and on an Apple host rustc strips by running `rust-objcopy`, which the stage-1 sysroot carries only when bootstrap copies LLVM's tools. Stage 2's lld-wrapper failed with "unable to run `rust-objcopy`". `x_build_compiler` puts the LLVM's llvm-objcopy first on the build's PATH as rust-objcopy, on an Apple host alone. Tests: the generated configs are held to the three lean options, a worktree's compiler config too, and a fake bootstrap reports which rust-objcopy its PATH finds first. Clippy's redundant clone in a test fake is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…ly meets their exits Round 2 deleted both because #675 and #676 were to land in one batch with this branch and close them. The owner has since ruled that #675 and #676 land on their own reviews, with a nightly run on main to confirm them, so nothing closes these two by this branch's landing. They are restored as round 2 found them, at 90a989e^: when this branch lands, each goes only if main's nightly has met its exit, and otherwise stays, corrected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
|
Round 3's mutation patches, each made against m1 diff --git a/src/llvm.rs b/src/llvm.rs
index 7829e1979..3ad225970 100644
--- a/src/llvm.rs
+++ b/src/llvm.rs
@@ -320,10 +320,7 @@ fn place(fork: &Path, key: &Key, dir: &Path, build: &impl Fn(&Path) -> PathBuf)
fn keep(install: &Path, to: &Path) {
let bin = to.join("bin");
fs::create_dir_all(&bin).unwrap_or_else(|e| panic!("create {}: {e}", bin.display()));
- for tool in tools().filter(|tool| *tool != "lld") {
- let from = install.join("bin").join(tool);
- fs::copy(&from, bin.join(tool)).unwrap_or_else(|e| panic!("copy {} -> {}: {e}", from.display(), bin.display()));
- }
+ clone_tree(&install.join("bin"), &bin);
for headers in HEADERS {
clone_tree(&install.join(headers), &to.join(headers));
}m2 diff --git a/src/llvm.rs b/src/llvm.rs
index 7829e1979..49ccbff0a 100644
--- a/src/llvm.rs
+++ b/src/llvm.rs
@@ -329,7 +329,7 @@ fn keep(install: &Path, to: &Path) {
}
let lib = to.join("lib");
fs::create_dir_all(&lib).unwrap_or_else(|e| panic!("create {}: {e}", lib.display()));
- for library in libraries(install) {
+ for library in fs::read_dir(install.join("lib")).unwrap().flatten().map(|e| e.path()).filter(|p| p.is_file()) {
let name = library.file_name().unwrap_or_else(|| panic!("{} names no file", library.display()));
fs::copy(&library, lib.join(name)).unwrap_or_else(|e| panic!("copy {} -> {}: {e}", library.display(), lib.display()));
}m3 diff --git a/src/clang.rs b/src/clang.rs
index ca7207a8e..c875e5eae 100644
--- a/src/clang.rs
+++ b/src/clang.rs
@@ -161,7 +161,7 @@ pub(crate) fn resource_version(llvm: &Path) -> PathBuf {
pub(crate) fn provision(stage2: &Path, llvm: &Path) {
let bin = bin(stage2);
let apple = host_triple().ends_with("apple-darwin").then_some((crate::llvm::APPLE_TOOL, APPLE_STRIP));
- for (tool, name) in [("clang", "clang"), ("llvm-ar", "llvm-ar")].into_iter().chain(apple) {
+ for (tool, name) in [("clang", "clang")].into_iter().chain(apple) {
let (from, to) = (llvm.join("bin").join(tool), bin.join(name));
let _ = fs::remove_file(&to);
// `fs::copy` clones where the filesystem can.m4 diff --git a/src/toolchain.rs b/src/toolchain.rs
index 85a2d8aef..241ae053f 100644
--- a/src/toolchain.rs
+++ b/src/toolchain.rs
@@ -712,9 +712,8 @@ pub(crate) fn x_build_compiler(rust_dir: &Path, args: &[&str], what: &str, llvm:
let caller = std::env::var_os("PATH").unwrap_or_else(|| panic!("PATH is unset, and bootstrap finds its tools on it"));
let path = std::env::join_paths(std::iter::once(strip.to_path_buf()).chain(std::env::split_paths(&caller)))
.unwrap_or_else(|e| panic!("{} cannot lead PATH: {e}", strip.display()));
- x_build_with(rust_dir, args, what, |command| {
- command.env("PATH", path);
- })
+ let _ = path;
+ x_build(rust_dir, args, what)
}
/// [`x_build`], with bootstrap's environment what `environment` makes of thism5 diff --git a/src/toolchain.rs b/src/toolchain.rs
index 85a2d8aef..3451aa5c4 100644
--- a/src/toolchain.rs
+++ b/src/toolchain.rs
@@ -1008,7 +1008,7 @@ pub(crate) const HOST_LINKER_PIN: &str = "default-linker-linux-override = \"off\
/// `clang::provision` puts there the ones a build runs; no debuginfo in rustc,
/// which no build reads; and no codegen test, for which bootstrap demands
/// LLVM's `FileCheck` beside `llvm-config` (`src/bootstrap/src/core/sanity.rs`).
-pub(crate) const LEAN: &str = "llvm-tools = false\ndebuginfo-level-rustc = 0\ncodegen-tests = false";
+pub(crate) const LEAN: &str = "debuginfo-level-rustc = 0\ncodegen-tests = false";
/// The linker every guest target names, as the toolchain at `toolchain` carries
/// it: `lib/rustlib/<host>/bin/rust-lld`, where rustc itself looks for it.m6 diff --git a/src/toolchain.rs b/src/toolchain.rs
index 85a2d8aef..4bf3a587f 100644
--- a/src/toolchain.rs
+++ b/src/toolchain.rs
@@ -130,7 +130,8 @@ fn hosted_stage2(rust_dir: &Path) -> PathBuf {
/// `asked`, and `rustc` is not there or `stamp`, which says it is this
/// compiler's, is not.
fn hosted_rustc_owed(asked: bool, stamp: &Path, rustc: &Path) -> bool {
- asked && (!stamp.exists() || !rustc.exists())
+ let _ = asked;
+ !stamp.exists() || !rustc.exists()
}
/// Remove the hosted rustc a compiler rebuild left stale, and its `stamp`: nom7 diff --git a/src/toolchain.rs b/src/toolchain.rs
index 85a2d8aef..698887771 100644
--- a/src/toolchain.rs
+++ b/src/toolchain.rs
@@ -143,7 +143,7 @@ fn forget_hosted_rustc(rust_dir: &Path, stamp: &Path) {
};
gone(stamp, fs::remove_file(stamp));
let stale = hosted_stage2(rust_dir);
- gone(&stale, fs::remove_dir_all(&stale));
+ let _ = stale;
}
/// Every `toyos-abi`/`toyos` source file a std build under `dep_info` actuallym8 diff --git a/src/toolchain.rs b/src/toolchain.rs
index 85a2d8aef..44a279c18 100644
--- a/src/toolchain.rs
+++ b/src/toolchain.rs
@@ -931,7 +931,7 @@ fn write_config(rust_dir: &Path, host: &str, with_hosted_rustc: bool, llvm: &Pat
} else {
format!("host = [\"{host}\"]")
};
- let (guests, userland) = if with_hosted_rustc {
+ let (guests, userland) = if true {
(GUEST_TARGETS.map(GuestTarget::triple).to_vec(), hosted_targets(llvm))
} else {
(Vec::new(), String::new())m9 diff --git a/src/toolchain.rs b/src/toolchain.rs
index 85a2d8aef..bdec7d558 100644
--- a/src/toolchain.rs
+++ b/src/toolchain.rs
@@ -1008,7 +1008,7 @@ pub(crate) const HOST_LINKER_PIN: &str = "default-linker-linux-override = \"off\
/// `clang::provision` puts there the ones a build runs; no debuginfo in rustc,
/// which no build reads; and no codegen test, for which bootstrap demands
/// LLVM's `FileCheck` beside `llvm-config` (`src/bootstrap/src/core/sanity.rs`).
-pub(crate) const LEAN: &str = "llvm-tools = false\ndebuginfo-level-rustc = 0\ncodegen-tests = false";
+pub(crate) const LEAN: &str = "llvm-tools = false\ncodegen-tests = false";
/// The linker every guest target names, as the toolchain at `toolchain` carries
/// it: `lib/rustlib/<host>/bin/rust-lld`, where rustc itself looks for it.m10 diff --git a/src/llvm.rs b/src/llvm.rs
index 7829e1979..fd6815e54 100644
--- a/src/llvm.rs
+++ b/src/llvm.rs
@@ -249,7 +249,7 @@ fn defect(dir: &Path) -> Option<String> {
.chain(&["lib/clang"])
.map(|k| dir.join(k))
.chain(crate::libcxx::SOURCES.iter().map(|s| dir.join("src").join(s)));
- let tools = tools().map(|t| dir.join("bin").join(t)).filter(|p| !p.is_file());
+ let tools = std::iter::empty::<PathBuf>();
let gone: Vec<String> = kept.filter(|p| !p.is_dir()).chain(tools).map(|p| p.display().to_string()).collect();
(!gone.is_empty()).then(|| format!("{} carries no {}", dir.display(), gone.join(", ")))
}m11 diff --git a/src/llvm.rs b/src/llvm.rs
index 7829e1979..8967a80c4 100644
--- a/src/llvm.rs
+++ b/src/llvm.rs
@@ -236,7 +236,7 @@ fn held_with(root: &Path, rust_dir: &Path, fork: &Path, build: impl Fn(&Path) ->
/// [`TOOLS`], and on an Apple host [`APPLE_TOOL`].
fn tools() -> impl Iterator<Item = &'static str> {
- TOOLS.into_iter().chain(host_triple().ends_with("apple-darwin").then_some(APPLE_TOOL))
+ TOOLS.into_iter()
}
/// Why `dir` is not a finished LLVM, if it is not. |
|
Round 3's size measurements: the scripts and what each printed. The Linux layers are carved from measure-asset.sh measure-asset.out carve.sh carve.out carve2.sh carve2.out slim-llvm.sh slim-llvm.out measure-new.sh measure-llvm-new.out measure-compiler-new.out measure-fs-new.out rustc-libs.txt |
…d the guest jobs keep no target cache CI now caches the toolchain as the four stores the build system already keeps: the LLVM, the primary's compiler, the freestanding targets' libraries and the sysroot. Each one is an actions/cache entry keyed by the build system's own key. GitHub's ref scoping is the provenance. Main's push and main's nightly save into main's scope, which every ref restores. A pull request's run saves only into its own scope, and so does a merge group's. toolchain.yml: `--ci toolchain` clones `rust/` at depth 1 (the helper the licence gate already used, now shared in src/lib.rs) and writes each layer's entry and paths as step outputs. Four restore steps take exactly those. `--ci bootstrap` builds what none restored: nothing at all when the sysroot was restored, since that is all a guest job reads. It refuses a restored layer that is not whole, because a rebuild under that key could never be saved over the entry. It tells each save step `built` or `kept`, and the save's guard reads that. The disk, QEMU and CMake step goes: - the apt CMake 3.28.3 sat behind the image's own /usr/local/bin/cmake 3.31.6 on PATH; - a toolchain build boots nothing; - portability-linux builds the whole toolchain on the same runner without the cleanup (job 110308854428's run, 36843762360). guest.yml keeps no target cache and no registry cache. A cold guest job fetched its 65 crates in under two seconds (tcg job 110374194382). It restores the sysroot by the toolchain job's key, red on a miss, and `release::install` lays that store out as the installed toolchain, after holding its recorded witness to the tree's. The job holds no token. Removed: the artifact listing, `is_mains`, vouching, `choose`, the digest install, the release tag and BUILDERS. The nightly's `release` packs main's restored sysroot, one build and not two. `publish.yml` keeps main's `toolchain` and loses `release`. - The tarball is packed in-process with the tar crate and ruzstd, with sorted entries and no owner or time, so one sysroot packs to one digest. - GitHub's REST API is spoken through curl with the toyos-build user agent. gh, tar and zstd no longer run from ToyOS code. - `put` decides create, carried, upload or replace from the release's JSON. Another writer's asset is replaced. - The release runs only as nightly.yml on main, scheduled or dispatched, and only at main's tip. Keys read what their builds read: - A compiler's key reads its whole build: RECIPE, the bootstrap configuration (`compiler::config_text`, which the primary now writes too) and the tools clang::provision puts beside it. - The primary's record names that build and every KEYED source, not just `compiler/`. It stays git-based: `source` takes 325 ms against `key`'s 850 ms on the development host, and the primary asks it on every build. - The freestanding key reads the compiler's key (`Compiler::key`, its record) in place of its driver's mtime, so every key is known before any store is built. - The LLVM key names n2, the Ninja its build runs, by its pin. - The sysroot key reads libc's cargo invocations, its lockfile and userland's cargo configuration. A stage2 whose rustc runs is linked, not rebuilt, when rustup has no `toyos`, as on a runner that restored it. Bootstrap never sees GITHUB_ACTIONS or CI, from any caller (x_build_with). Gates (src/ci.rs): - only main's runs save what other refs restore; - no low-trust trigger; - no widened cache-mode; - `guest / suite` has no condition of its own; - every job that saves holds to the allow-list; - the one write token is the nightly release's, read whatever YAML spells it; - each store is restored and saved by the entry its job wrote. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
By owner direction, rules a reviewer sees in the diff live in the review prompt, and code stays only where reading cannot see the defect: the layered stores, their keys and the build. `.claude/agents/reviewer.md` gains five sentences under "Workflows": - only main's runs save what other refs restore; - no trigger runs other code on main's ref; - no write-capable `cache-mode`; - `guest / suite` has no `if:` of its own, and its callers run it whatever `toolchain` concluded; - a job that saves runs only the driver. Deleted from src/ci.rs: the seven workflow-reading tests the previous commit added, the YAML readers they used, and this branch's write-token test. Main's `the_required_check_is_a_job_on_every_pull_request` is main's again. `workflows_run_against_main_on_hosted_runners` and `each_cache_has_one_writer` keep the only changes the new workflows force: two more files, and a cache named by a step's output. `release::LAYERS` is private again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…ed's toolchain line says what it runs CI's guest jobs restore the sysroot their toolchain job built, by its key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
No file changed on both sides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
…s since #675 The cause the issue named is past: `nested_nmi` wrote through `serial::panic_raw` until #675 (`bc68e5d78`). The exit stays open until CI's KVM `guest` check shows `nested_nmi_is_loud` green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016t9wjdQkB8SH7bmfUoiy6L
guest check, on toolchain stores CI caches by the build system's own keys
|
Review, round 5, at Read from the runs. Run 36988764929, Where the head stands. Net lines (
The growth is accepted as in round 4: it removes gh, curl, tar and zstd from the build system, and the release download CI installed from. Earlier BLOCKERs
The three things beyond the brief
BLOCKERNone new. NOTE
REMOVE
SEND BACK |
Cargo.lock alone conflicted: both sides kept, main's pcap-file and byteorder_slice beside this branch's ureq, flate2 and tar trees, and cargo left the result as it resolves the merged manifests. Against origin/main the lockfile differs by what it did before the merge, +801 -6. #659 moves the rust gitlink and the kernel, so the freestanding and sysroot keys move with it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
The owner ruled it: one TLS provider everywhere. `release::agent` installed rustls-rustcrypto 0.0.2-alpha, which main's internet-clients track says does not come back and whose exit is that no manifest names it; the root manifest was a third one naming it. ureq's own `rustls` feature is rustls with ring and webpki's roots, so the agent configures no TLS at all and the root manifest names neither provider. The lockfile loses the RustCrypto stack: against origin/main it is +252 -1, where it was +801 -6. ring compiles C and assembly through the host's `cc` in the build system's own build, which needed none: `cargo tree -i cc` printed nothing and now prints cc under ring's build dependencies. The arrival is declared in the `cc` row of issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
Main's nightly 36985427800, at 74a2e70, ended its three-hour toolchain step red: "crates.io holds no toyos-abi of this tree, so no sdk alias can name it". #650 and #659 had landed meanwhile and their pushes had put newer toyos-abi versions up, so the tree the nightly checked out was no longer the one crates.io's newest named. This branch deleted that step and kept the red: `release_as` ran behind `ci::at_tip`, which refuses with "HEAD ... is not main's tip" whenever a landing precedes the `release` job, and `alias` kept the crates.io refusal for a landing whose crates went up after that check. `sdk_at_tip` is now the release's one decision, taken before anything is laid out, packed or put up: it reads crates.io, then main's tip. A tree main has moved past puts nothing up and the job is green, saying so; the tip's nightly publishes. At the tip the plan it read is the one the alias is written from, so nothing read later can disagree with it. crates.io before the tip is the order that matters: a landing whose crates the first read shows has moved the tip the second read sees, and the other order leaves a landing between the two reads refused. What stays refused is the tip's own crates not being up, which publish.yml owes, and a remote that names no main. A run of an older tree still moves no alias back, which is what `at_tip` was put there for; `at_tip` is `publish`'s alone again, and private as on main. `a_landing_during_the_nightly_puts_nothing_up_and_is_no_failure` lands once before the release's first read, between its two reads and not at all, with and without newer SDK crates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
The nightly's one guest lane is TCG; the EPYC KVM guests are every pull request's and the merge queue's. The branch had dropped the same words from two other issues. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
With the tip read before crates.io, the test's first red was the landing that moves no SDK, which that order publishes over rather than refuses. The landing that puts newer crates up is the race, so it is asserted first and the mutation's red is the refusal itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
doom's build script and tests/toyos-rust-tests still name rustls-rustcrypto, as main's internet-clients track records, so "the tree's one TLS provider" was false of the tree. The manifest's comment and the `cc` row say what the owner ruled, and the comment names the track that holds it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
|
Round 6 evidence, at 1. The release's decision, mutated
--- a/src/release.rs
+++ b/src/release.rs
@@ -355,12 +355,12 @@
ls_remote: impl FnOnce() -> String,
head: &str,
) -> Result<Option<Vec<Release>>, String> {
- let sdk = plan()?;
let said = ls_remote();
let tip = said.split_whitespace().next().ok_or("origin names no main")?;
if tip != head {
- return Ok(None);
+ return Err(format!("HEAD {head} is not main's tip {tip:?}"));
}
+ let sdk = plan()?;
match sdk.iter().find(|r| r.publish) {
Some(owed) => Err(format!("crates.io holds no {} of this tree, main's tip, so no sdk alias can name it", owed.krate.name)),
None => Ok(Some(sdk)),
--- a/src/release.rs
+++ b/src/release.rs
@@ -355,8 +355,8 @@
ls_remote: impl FnOnce() -> String,
head: &str,
) -> Result<Option<Vec<Release>>, String> {
- let sdk = plan()?;
let said = ls_remote();
+ let sdk = plan()?;
let tip = said.split_whitespace().next().ok_or("origin names no main")?;
if tip != head {
return Ok(None);
--- a/src/release.rs
+++ b/src/release.rs
@@ -356,6 +356,9 @@
head: &str,
) -> Result<Option<Vec<Release>>, String> {
let sdk = plan()?;
+ if let Some(owed) = sdk.iter().find(|r| r.publish) {
+ return Err(format!("crates.io holds no {} of this tree, so no sdk alias can name it", owed.krate.name));
+ }
let said = ls_remote();
let tip = said.split_whitespace().next().ok_or("origin names no main")?;
if tip != head {2. The agent on ring, one read-only request to GitHub
--- a/src/release.rs
+++ b/src/release.rs
@@ -645,6 +645,22 @@
mod tests {
use super::*;
+ /// Throwaway: one GET of a published release through `Github::call`, read
+ /// by `put` as carrying the digest GitHub records for its asset.
+ #[test]
+ #[ignore = "throwaway probe: one read-only request to GitHub"]
+ fn probe_one_read_of_a_release() {
+ let github = Github::new("ToyOSOrg/ToyOS").unwrap();
+ let tag = "toolchain-linux-x86_64-sdk-0.26.0";
+ let digest = "sha256:68f6a1ac1c1d58a959f9a19959a8849f0491d47e53bdaa8d1a534bb47092db3f";
+ let began = std::time::Instant::now();
+ let release = github.call("GET", &github.api(&format!("releases/tags/{tag}")), None).expect("GET").expect("a release");
+ println!("PROBE {} ms GET releases/tags/{tag}: id {}, tag_name {}, assets {}", began.elapsed().as_millis(), release["id"], release["tag_name"], release["assets"].as_array().map_or(0, Vec::len));
+ println!("PROBE asset {} digest {} size {}", release["assets"][0]["name"], release["assets"][0]["digest"], release["assets"][0]["size"]);
+ assert_eq!(put(Some(&release), "TOOLCHAIN", digest), Ok(Put::Carried));
+ assert!(matches!(put(Some(&release), "TOOLCHAIN", "sha256:00"), Ok(Put::Replace { .. })));
+ }
+
#[test]
fn the_glibc_scan_takes_the_newest_version_and_nothing_else() {
let bytes = b"\0GLIBC_2.17\0GLIBC_2.39\0GLIBC_2.4\0GLIBC_PRIVATE\0GLIBC_\0GLIBC_3.\0";The digest is the one 3.
|
guest check, on toolchain stores CI caches by the build system's own keysguest check, on toolchain stores CI caches by the build system's own keys; a landing during a nightly does not red its release
|
Review, round 6, at Read from the run. Run 37007753187, attempt 1,
The development host's logs, read in
Net lines (
Earlier BLOCKERs
The three things from outside the last review
BLOCKERNone new. NOTE
REMOVE
SEND BACK |
Round 6's review found them recorded only under the pull request body's "Unsure": a nightly whose `release` decides before `publish.yml` has put its own tip's crates up is red for no defect of the tree, and a nightly a landing overtakes puts no release up and moves no alias, green. Each is an issue with its owner, the runs that measure its window and an exit a test or a request can fail. Read for them on 2026-10-02: runs 36843762360, 36988155706 and 36985427800 (`gh run view`), main's publish runs (`gh run list --workflow publish.yml`), main's first-parent log, and the `toolchain / build` jobs of run 36988764929 attempt 2 and run 36934214557. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
The nightly's one guest lane is TCG; the EPYC KVM guests are every pull request's and the merge queue's. Four lines in two issues still said "nightly EPYC guest" after the branch dropped the words from four others. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
"No build compiles it" stopped being true when the build system's HTTP agent moved to rustls on ring: every build of the build system compiles ring for the host. What is untried is the ToyOS target, and the sentence says so: `cargo tree -i ring --target all --workspace` prints nothing for `userland` and for `tests/toyos-rust-tests` (exit 0 each). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
|
Round 7 evidence, at The crates.io index read through the agent on ring, from the development host (macOS, arm64). A throwaway test, checked with diff --git a/src/sdkversion.rs b/src/sdkversion.rs
index 99890315b..33b360326 100644
--- a/src/sdkversion.rs
+++ b/src/sdkversion.rs
@@ -146,6 +146,23 @@ mod tests {
use std::process::Command;
use toyos_tmpdir::TempDir;
+ /// Throwaway: the crates.io index read through the agent, once for a
+ /// published crate and once for a name nobody published.
+ #[test]
+ #[ignore = "throwaway probe: two read-only requests to the crates.io index"]
+ fn probe_the_index_read() {
+ let began = std::time::Instant::now();
+ let abi = index("toyos-abi").expect("GET toyos-abi");
+ let took = began.elapsed().as_millis();
+ let newest = assign(&abi, "").expect("every line parses");
+ println!("PROBE {took} ms index(toyos-abi): {} lines, {} bytes, the minor after its newest {}", abi.lines().count(), abi.len(), newest.0);
+ assert!(abi.lines().count() > 0 && newest.1);
+ let began = std::time::Instant::now();
+ let none = index("toyos-no-such-crate").expect("GET an unpublished name");
+ println!("PROBE {} ms index(toyos-no-such-crate): {} lines, {} bytes", began.elapsed().as_millis(), none.lines().count(), none.len());
+ assert_eq!(none, "");
+ }
+
const TWO: &[Crate] =
&[Crate { name: "toyos-abi", dir: "toyos-abi" }, Crate { name: "toyos", dir: "toyos" }];
const ABI: &str = "[package]\nname = \"toyos-abi\"\n"; |
|
Review, round 7, at Read from the tree and the API, not from the body. Run 37014929723, attempt 1,
The development host's log, read in What this verdict rests on, and what it awaits.
Net lines (
Earlier BLOCKERs
The two things the round left out of the tree
BLOCKERNone. NOTE
REMOVE
LAND AFTER NAMED CHANGES |
…ck is filed Review round 7's second NOTE: `issues/build/no-nightly-runner-has-had-its- cpuid-and-vulnerability-lines-captured.md` named the nightly for the KVM runners in its slug and in its exit. At this branch no nightly job is given `/dev/kvm` (`nightly.yml`'s `tcg` calls `guest.yml` with `kvm: false`); the KVM guests are `ci.yml`'s `guest`. The slug is renamed `no-kvm-runner-...`, the heading and the exit corrected with it, and its one citation, `toyos-cpuvuln/src/tests.rs:605`, moved. The body's "nightly run 36496779560" stays: that run is `nightly.yml`'s, dispatched on 2026-09-28. `issues/build/the-guest-check-gates-nothing.md` is filed on the orchestrator's instruction. Rounds 5 to 7 hold that it is filed if `guest / suite` is not named a required check in the sitting that lands #671, and it will not be: the naming waits on main's cold `toolchain` job. Its evidence is ruleset 20589156 as read at 13:59:20Z on 2026-10-02 (`check_response_timeout_minutes` 240, one required check, `host`) and main's cache scope as read at 14:00:46Z (two `host-sealed-` entries, no toolchain layer); its exit is the ruleset listing `guest / suite`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
Two conflicts, each keeping both sides whole. src/clang.rs: main adds APPLE_STRIP and tools() where this branch adds CMAKE; both stand, main's first. src/sysroot.rs: main splits key() into build_text() and key_of() and has the key read libc's cargo invocations; this branch has it read clang::CMAKE. build_text() is main's with CMake's description of ToyOS between the C++ runtime's options and libc's invocations, and its doc names it. src/libc.rs, src/libcxx.rs and the rest of src/sysroot.rs merged without conflict: over main they differ by write_cmake() in build_c, the toolchain file in the C++ runtime's definitions, and RECIPE's 13. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
…among them) into wt/toyos-winitstall Three content conflicts, each a deletion on main's side of a block this branch had edited: - kernel/src/inbox/mod.rs: main deleted `Staged`, `handler-post`'s ring, with the actuator (#660). This branch's hunks inside it — the `owed` field, `Poll::new`, the `WatchFlags` direction and "fires" for "completes" in its doc — adapted it to the ring's new fields and go with it. `Inbox::complete` keeps this branch's wording and loses main's `raise_if_staged` call. - kernel/src/watch.rs: main deleted the `handler_post` module, `holding`, `note_post` and the `raise_if_staged` call in `IrqLock::with`. This branch's one hunk inside it was "fires" for "completes" in the module's doc, which goes with it. - userland/fsd/src/main.rs: main deleted the four test actuators (`--end-on`, `--end-at-read`, `--end-at-mount`, `--let-go-at-read`) and kept the acceptor probe; this branch deleted the probe and kept the actuators. Both deletions stand: no `caps_len`, no `probe` field, no actuator field, and `accept` is this branch's. Two resolutions no marker asked for: - src/ci.rs: #668 made a control's verdicts `Fails(..)` values, so `post-is-an-answer`'s three verdict strings become three `Fails`. - issues/build: main filed the C++ runtime's scratch removal as an issue of its own (`the-cxx-runtimes-scratch-removal-dies-on-a-finder-file.md`) beside the sweep's, which this branch had merged into one file. Main's two files stand and this branch's file goes. The `rust` gitlink is main's, `95960d6c2`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
Six conflicts, each resolved by taking main's side and applying this branch's deletion to it again: - kernel/src/actuator.rs: main deleted the rows this branch kept around `process-reopen-selftest` and kept that row; the row goes. - kernel/src/syscall/dispatch.rs: main's import list gained `spawn_place`; `sys_process_open` leaves it. - src/metal.rs: `FLASHABLE` is a list of names on main; the `process-reopen-selftest` name goes. - tests/toyos.rs: main moved the QEMU machine test out, so what is left to delete is the metal row, the `SELFTESTS` arm, the `process_reopen` judge and the two counts of that image's actuators. - tests/test-durations: main deleted the file; this branch's one hunk removed a row of it, and goes with it. - the track file: main reworded stage 0 and stage 1; stage 0 is deleted and stage 1 is main's. kernel/src/object/handle.rs and kernel/src/object/mod.rs merge clean, so the `Process` row is sealed again over #659's spawn, whose two installs on a child's object are not ordered for that. The commits after this one make that red and then remove it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm
The 21-test guest suite becomes the
guest / suitecheck on every non-draft pull request and in the merge queue. CI caches the toolchain it runs on as the four stores the build system already keeps, each an actions/cache entry under the build system's own key. Main's nightly packs the sysroot store into the toolchain release, through ureq and flate2: the build system runs no gh, curl, tar or zstd. A landing on main during a nightly no longer reds its release.Head:
a305253e9, on origin/main atc1c504835(#643, #664, #679, #659).68dc21ce2..a305253e9is four commits to seven files underissues/and to one path in a comment oftoyos-cpuvuln/src/tests.rs, a#[cfg(test)]module, and nothing else; what below is measured at68dc21ce2or at281602b72is measured of the head's tree outside those.How a tree gets its toolchain
Four layers, each keyed by the build system's own key (
release::LAYERS):rust/build/llvm/<key>llvm::keyrust/build/<host>/stage2,rust/build/toyos-compilercompiler::primary_key, the hash of the primary's recordrust/build/freestanding/<key>sysroot::freestanding_keyrust/build/sysroots/<key>sysroot::keyEvery key is computed from sources alone, before any store exists. A submodule is keyed by the commit its gitlink records (
sysroot::gitlink), whether or not it is checked out.toolchain.yml, one job, in one concurrency group per ref that never cancels a job in progress and, withqueue: max, never cancels one that waits:--ci toolchainclonesrust/at depth 1 and writes each layer's entry (toolchain-<layer>-<key>) and paths as step outputs.--ci bootstraprefuses a restored layer that is not whole, builds what none restored (nothing when the sysroot was restored), refuses a layer the build left not whole under the key computed first (release::whole), and tells each save stepbuiltorkept.Provenance is GitHub's ref scoping. A run saves into its own ref's scope, and every ref restores the default branch's. Main's scope is written by
publish.yml'stoolchainon a push andnightly.yml's on its schedule; they share the job's group, so one cold key is built once on main.toolchainrestoreslibrary/alone, as #650's and #659's)compiler/)src/bootstrap, the runner's cc, c++ or CMake, or n2's pin)A merge group saves only the sysroot: its scope is read by nothing but its own guest job, which restores the sysroot alone.
The guest job (
guest.yml;ci.yml'sguestand the nightly'stcgcall it) restores only the sysroot, by the toolchain job's key, withfail-on-cache-miss: true.release::installlays it out as the installed toolchain after holding the witness it records against the tree's. It keeps no target or registry cache: main'sguest-entry goes with the nightly'sguestandtcgjobs that carried it.The host cache is #669's, unchanged:
ci.yml'shostreads it and the nightly'shostseals and saves it.The rules a reviewer reads off the workflows are
.claude/agents/reviewer.md's Caches and Workflows. Workflows, a BLOCKER each: only main's runs save an entry other refs restore;nightly.yml'sreleaseis the only job grantedcontents: write; no trigger runs other code on main's ref; nocache-mode: write;guest / suitehas no job-levelif:; a saving job runs onlycargo run -- --ci <job>.The release
nightly.yml'sreleaseruns only on main (if: github.ref == 'refs/heads/main'), restores the sysroot itstoolchainnames and runs--ci release. The driver refuses that job before it reads anything unless it isnightly.ymlonrefs/heads/main, scheduled or dispatched, withGITHUB_REPOSITORYset: the refusal is the boundary, theif:only keeps a branch's nightly from concluding failure.74a2e703b, ended its 2:53:54buildred: "crates.io holds no toyos-abi of this tree, so no sdk alias can name it". libc: the POSIX surface LLVM compiles against, and the headers held to the definitions #650 and A parent's end takes its children down: every end walks its subtree and is published after it, a spawn past its commit lands, and a refused spawn spends no pid #659 had landed during it and their pushes had put toyos-abi 0.27.0 and 0.28.0 up, past the tree's 0.26.0.sdk_at_tipis the release's one decision, taken before anything is laid out, packed or put up. It reads crates.io, then main's tip:<head>, and its tip's nightly is the one that publishes". A re-run of an older nightly therefore still moves no alias back.<crate>of this tree, main's tip, so no sdk alias can name it".publish.ymlowes them.issues/build/a-nightly-a-landing-overtakes-leaves-no-release-and-no-sdk-alias.md: a nightly a landing overtakes puts no release up and moves no alias; both wait for the next nightly whosereleaseruns at the tip, or a dispatch. A nightly overtaken every night publishes nothing until one is not.issues/build/a-release-that-decides-before-its-tips-crates-are-up-reds-the-nightly.md: a nightly whosereleasedecides beforepublish.ymlhas put its own tip's crates up is red for no defect of the tree. The decision comes after the toolchain job, 2:38 at its fastest measured; main's six greenpublishruns of 2026-10-02 took between 1:04 and 1:54 from creation.packstreams the tar crate into flate2's pure-Rust gzip, entries sorted, no owner or time. The asset istoyos-toolchain.tar.gz, taggedtoolchain-linux-x86_64-<sysroot key>, and it carriesx86_64-unknown-linux-gnu/stage2, its witness andTOOLCHAIN. It no longer carriesx86_64-unknown-toyos/stage2, the hosted rustc main's packed: no build reads it unless its config setshosted-rustc, andsystem.tomldoes not.Githubspeaks the REST API through a ureq agent, as doessdkversion::indexfor the crates.io index: rustls on ring with webpki's roots, which is ureq's ownrustlsfeature, and User-Agenttoyos-build (https://github.com/ToyOSOrg/ToyOS).issues/design-debt/the-internet-clients-work-unchanged.mdsaid of ring "no build compiles it", and every build of the build system now compiles it for the host: that one sentence reads "no build for that target compiles it", and nothing else in the file changes.cargo tree --locked --offline --manifest-path <workspace>/Cargo.toml --workspace -i ring --target allprints nothing foruserlandand fortests/toyos-rust-tests(exit 0 each), the two workspaces built for ToyOS whose lockfiles name ring.ccinto the build system's own build, which needed none:cargo tree -i ccprinted nothing before the move (exit 0, at7f2721ac2) and at this head prints cc v1.2.56 under the build dependencies of ring v0.17.14, itself under rustls and rustls-webpki, under ureq (exit 0). The arrival is declared in theccrow ofissues/build/the-build-runs-host-tools-outside-rust-and-qemu.md.releases/tags/toolchain-linux-x86_64-sdk-0.26.0throughGithub::callfrom the development host, answered in 462 ms, exit 0;putreads the answer asCarriedfor the digest GitHub records,sha256:68f6a1ac…, and asReplacefor any other.sdkversion::indexfrom the development host, a throwaway test at68dc21ce2, exit 0 (The guest suite is every pull request'sguestcheck, on toolchain stores CI caches by the build system's own keys; a landing during a nightly does not red its release #671 (comment)): 28 lines fortoyos-abiin 786 ms, each read bysdkversion::assign, and nothing for a name nobody published, in 725 ms.putdecides create, carried, upload or replace from the release's JSON; an existing release is given the tree's notes either way.Packing, measured on the development host (macOS, arm64) over one 1,372,971,008-byte tarball of sysroot
3c77313b0346745c:packgzip -6zstd -3Every method
put_upsends was measured against GitHub at42a823b1f, through the agent's previous provider (#671 (comment)): one draft release onToyOSOrg/ToyOScreated, patched, given a 33-byte asset, read back, and asset and release deleted, each throughGithub::call, exit 0.idandupload_url; PATCH answered it with the new body; both DELETEs answered no content, read asSome(Null); a GET after the delete answered 404, read asNone.digest: the upload's own answer carries"digest": "sha256:b99de743…", with"state": "uploaded", and so does the release read back 307 ms after it:putreads that release asCarried, and asReplacefor any other bytes.shasum -a 256prints the same digest for those bytes.put_upreads a published release by tag, which this head's one GET measures.What CI has measured
No run this body rests on is of the head,
a305253e9. Run 37014929723 is of281602b72, which the head is one commit past: two files underissues/and one path in a comment oftoyos-cpuvuln/src/tests.rs. Run 37007753187 is of68dc21ce2. The head's own run, 37017442164, was created by its push at 14:05:29Z and was in progress at 14:06:00Z, when this was written; nothing here rests on it.Run 37014929723, of
281602b72:pull_request, attempt 1, on mergef528c4bb2of281602b72intoc1c504835, runner imageubuntu-24.0420260927.320.1, concluded success.host(110863352409)host-sealed-Linux-X64-36988155706;[ci] Host: 65 step(s), all greentoolchain / build(110863352757)guest / suite(110864228036)toolchain-sysroot-d0548e109d1e0ef8;/dev/kvm opens, AMD EPYC 7763 64-Core Processor, 4 core(s);test result: ok. 21 passed, 21 total (721.0s)[ci] this tree's toolchain: llvm da88e203716ecb6d restored, compiler 8e57eb89153a182c restored, freestanding 11c213f25b8c6d8c restored, sysroot d0548e109d1e0ef8 restored: the "moves no layer" row, on the four keys run 37007753187 printed.Run 37007753187, of
68dc21ce2:pull_request, attempt 1, on merge27b4428of68dc21ce2intoc1c504835, runner imageubuntu-24.0420260927.320.1.host(110839929948)host-sealed-Linux-X64-36988155706;[ci] Host: 65 step(s), all greentoolchain / build(110839930089)guest / suite(110843582245)toolchain-sysroot-d0548e109d1e0ef8;/dev/kvm opens, AMD EPYC 9V74 80-Core Processor, 4 core(s);test result: ok. 21 passed, 21 total (715.0s)[ci] this tree's toolchain: llvm da88e203716ecb6d restored, compiler 8e57eb89153a182c restored, freestanding 11c213f25b8c6d8c built, sysroot d0548e109d1e0ef8 built: the freestanding row, on the two keys A parent's end takes its children down: every end walks its subtree and is published after it, a spawn past its commit lands, and a refused spawn spends no pid #659'slibrary/stdbump moved. They are the two the throwaway key test printed for a runner at that head before the run (The guest suite is every pull request'sguestcheck, on toolchain stores CI caches by the build system's own keys; a landing during a nightly does not red its release #671 (comment)).The runs below are on
42a823b1fand before.The cold path: run 36934214557,
pull_request, on the merge off1ccb0b3einto76d0d9389, runner imageubuntu-24.0420260927.320.1:host(110610544912)toolchain / build(110610545360)guest / suite(110649069031)[ci] this tree's toolchain: llvm da88e203716ecb6d built, compiler 8e57eb89153a182c built, freestanding 847668c56799bfaa built, sysroot 121d3857d01bcded built.--ci bootstraptook 2:09:01: LLVM 1:29:15, compiler 0:28:06, freestanding 0:06:31, the sysroot's std 0:03:31.virt_*tests andnested_nmi_is_loudpass on a runner.actions/caches, 12:29Z on 2026-10-02): main'shost-sealed-Linux-X64-36988155706at 1,622,150,459 andhost-sealed-Linux-X64-36985427800at 1,619,051,868, and this pull request's six toolchain entries at 1,462,018,348. Main's scope holds no toolchain layer.The restore paths, on a runner: the four attempts of run 36988764929 on
42a823b1f, each on runner image 20260927.320.1 and each concluding success in all three jobs. Between attempts the named entries were deleted withgh cache delete … --ref refs/pull/671/merge. The keys that head computes on a runner of that image: LLVMda88e203716ecb6dand compiler8e57eb89153a182c, unmoved; freestanding5658957050c8b2bband sysrootc882c693da324ad2, moved by #650; every attempt's[ci] the stores of this tree's toolchain:line prints these four. They were predicted from a throwaway test that keys both with the runner's compiler key and host triple; before #650 it printed847668c56799bfaaand121d3857d01bcded, the keys run 36934214557 printed.hosttook 9:58, 7:36, 9:56 and 8:32, each restoringhost-sealed-Linux-X64-36985427800and ending[ci] Host: 60 step(s), all green.[ci] this tree's toolchain:toolchain / buildtookguest / suitetoolchain-llvm-da88e203716ecb6d,toolchain-compiler-8e57eb89153a182cllvm da88e203716ecb6d restored, compiler 8e57eb89153a182c restored, freestanding 5658957050c8b2bb built, sysroot c882c693da324ad2 built21 passed, 21 total (739.0s)llvm da88e203716ecb6d restored, compiler 8e57eb89153a182c restored, freestanding 5658957050c8b2bb restored, sysroot c882c693da324ad2 restored21 passed, 21 total (692.3s)toolchain-sysroot-c882c693da324ad2deletedllvm da88e203716ecb6d restored, compiler 8e57eb89153a182c restored, freestanding 5658957050c8b2bb restored, sysroot c882c693da324ad2 built21 passed, 21 total (704.1s)toolchain-compiler-8e57eb89153a182c,toolchain-freestanding-5658957050c8b2bbandtoolchain-sysroot-c882c693da324ad2deletedllvm da88e203716ecb6d restored, compiler 8e57eb89153a182c built, freestanding 5658957050c8b2bb built, sysroot c882c693da324ad2 built21 passed, 21 total (451.1s)The required check, and the queue's timeout
The required check is the orchestrator's, with no commit, in this order:
check_response_timeout_minutesin ruleset 20589156 raised from 180 to 240, by the orchestrator on 2026-10-02.gh api repos/ToyOSOrg/ToyOS/rulesets/20589156at 13:59:20Z reads 240 and one required check,host.publish.ymltoolchainjob to save its four layers.guest / suitea required check, once one merge group'sguest / suitehas concluded success.gh run list --event merge_groupholds nopr-671group (200 runs back to 2026-09-24, read at 13:39Z on 2026-10-02). Unmeasured, then:toolchain.yml's threegithub.event_name != 'merge_group'save guards, andguest / suiterestoring underfail-on-cache-missa sysroot that only the group's own scope holds. It is the path step 4 makes every landing wait on, and this pull request's own merge group is its first run; whether that run reaches a conclusion is in "Unsure".host: a pull request or a merge group whoseguest / suiteis red still lands. Filed asissues/build/the-guest-check-gates-nothing.md, the orchestrator's, whose exit is step 4: the naming will not be in the sitting that lands this, since it waits on step 3.toolchain / buildtook 2:11:46, 2:09:01 of it--ci bootstrap. One runner label spreads wider than that: LLVM029e544969e88c25built cold onubuntu-24.04in 1:06:24, 1:22:54 and 1:28:26 (portability-linuxjobs 110039882266, 109824960572, 110092278376), ×1.33, and the compiler after it in 0:30:37, 0:39:14 and 0:41:53. At ×1.33 the job is 2:54:21, and 2:58:52 with the slowest measured compiler in place of this run's.guest / suitefollows it, measured between 10:20 and 23:17 and bounded by its own 60 minutes: 178:52 + 60:00 = 238:52. Nothing says which end of the spread this job's two samples are (LLVM 1:29:15 here, 1:29:06 in run 36913380100).Other decisions
.claude/agents/reviewer.mdis main's, with the six Workflows rules after Caches. Caches opened "Each cache has one writer, a nightly.yml job", which is false of the toolchain's layers:toolchain.yml'sbuildsaves them from three workflows. That sentence is now the host cache's alone, and Workflows' first rule holds the layers.CLAUDE.mdsaid "Guests run nightly."; it says where they run now.releaseand itstcgrestored an empty key.queue: maxlets up to 100 wait. GitHub accepts it: a nightly dispatched on this branch at42a823b1f, run 36988266186, started itstoolchain / build, and was cancelled at once having saved nothing.Gates
cargo run -- --ci hosta305253e9git status --porcelain --ignore-submodules=noneempty aftercargo run -- --build-onlya305253e9cargo run -- --build-only68dc21ce2cargo test --test toyos-build, the whole guest suite68dc21ce2cargo run -- --ci host68dc21ce2482d4873f, whosesrc/andCargo.lockare the head's4043f2f3e5ab2053and sysroot8ee6b823bf2f0688built after the merge, compiler4eb88555ff0f85b1kept; "21 passed, 21 total (82.7s)"; "Host: 64 step(s), all green"Mutations. Of
sdk_at_tip, at68dc21ce2, each againsta_landing_during_the_nightly_puts_nothing_up_and_is_no_failure, which is green unmutated (#671 (comment)):At
1a4f3abda(#671 (comment)):9e917f19b's code reverted, its test kepta_submodule_is_the_commit_its_gitlink_records_checked_out_or_notsrc/libc.rspatchcargo test --libWhat the new test sees that reading cannot: which of the release's two reads a landing falls between. m2 is two adjacent lines swapped, and only the staged landing between them tells the orders apart.
High-risk: the two checks
nightly.yml'sreleaseholds the onlycontents: write, andpublish.yml'sid-token: writeis main's. Run as a pull request's job, the merge queue's, main's push or a branch's dispatched nightly,release_asis refused by name before it reads anything (only_mains_publisher_publishes, in--ci host). When it publishes: m1 is the base's decision put back onto this head, and the landing test reds on it. The key fix's control is the reverted9e917f19b, red as CI's run 36913380100 was.digestand the agent's read on ring, andshasumfor the digest's value. Run 36934214557's own key line for the keys. Run 36913380100 for the gitlink fix. GitHub's "Dependency caching reference" for the scoping, and itsactions-group-concurrencytext forqueue: "max: Up to 100 jobs or workflow runs can bependingin the concurrency group."A reader of
mainmust not missguest / suiteis not a required check until the ruleset names it, and the order above is what makes naming it safe.issues/build/the-guest-cache-is-read-by-mtime-and-its-writer-restores-before-it-saves.md, Host cache: read by content, written by main's cold nightly alone, sealed and bounded, with its workflow rules in the review prompt #669's; there is no guest cache.issues/build/the-host-caches-limit-reaches-the-10-gb-only-through-one-measured-ratio.mdnow sums two host entries beside the toolchain's layers where it summed them beside guest entries, andsrc/cicache.rs'sLIMITnames no guest entry.issues/build/a-runner-image-that-moves-cc-or-cmake-makes-every-toolchain-job-cold.md,issues/build/a-toolchain-job-that-does-not-finish-saves-no-layer-it-built.md,issues/build/a-stores-build-code-moves-its-key-only-through-a-recipe-bumped-by-hand.md,issues/build/a-toolchain-releases-asset-is-whatever-its-last-writer-put-there.md,issues/build/a-nightly-a-landing-overtakes-leaves-no-release-and-no-sdk-alias.md,issues/build/a-release-that-decides-before-its-tips-crates-are-up-reds-the-nightly.md,issues/build/the-guest-check-gates-nothing.md.issues/build/no-nightly-runner-has-had-its-cpuid-and-vulnerability-lines-captured.mdisissues/build/no-kvm-runner-has-had-its-cpuid-and-vulnerability-lines-captured.md, its heading and exit corrected and its one citation, intoyos-cpuvuln/src/tests.rs, moved with it: no nightly job is given/dev/kvm, and the KVM guests areci.yml'sguest.Unsure
digestin the answer; the probe's asset was 33 bytes. On ring only reads are measured, one GET of GitHub and two of the crates.io index; the writes were measured on the previous provider, under the same HTTP layer.publish.yml's--ci publishreads the crates.io index on every push to main (src/ci.rs:907), so this landing's own push is the agent's first request from a runner.guest / suitereaches a conclusion before the check is required is unmeasured. Whilehostis the one required check, a merge group merges whenhostconcludes, 7:57 and 10:19 in runs 37014929723 and 37007753187. This pull request's own group is cold, atoolchain / buildof 2:11:46 in run 36934214557, so itsguest / suitehas not started by then. A warm group's follows atoolchain / buildof 2:15 to 2:38 and has itself taken between 10:20 and 23:17, so by every measurement here it too concludes afterhost. On main a merge group runshostalone, so no group has had a job outstanding at its merge, and nothing says whether a merged group's remaining jobs run on or are cancelled.guest / suiteconcludes until the check is required, and step 4's condition never comes. The naming then rests on main'stoolchainsave, step 3, and on one pull request run'sguest / suiteconcluding success, not on a merge group's; and the queue's path first reaches a conclusion in the first merge group after the naming.release'sif:,queue: maxon main, andguest.ymlcalled withkvm: false, the nightly'stcglane. The branch's one dispatched nightly was cancelled withtcgskipped, so that lane has run in no Actions run.🤖 Generated with Claude Code
https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm