Skip to content

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

Merged
Japabu merged 38 commits into
mainfrom
wt/toyos-guestci
Oct 2, 2026

Conversation

@Japabu

@Japabu Japabu commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

The 21-test guest suite becomes the guest / suite check 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 at c1c504835 (#643, #664, #679, #659). 68dc21ce2..a305253e9 is four commits to seven files under issues/ and to one path in a comment of toyos-cpuvuln/src/tests.rs, a #[cfg(test)] module, and nothing else; what below is measured at 68dc21ce2 or at 281602b72 is 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):

layer paths key
LLVM rust/build/llvm/<key> llvm::key
compiler rust/build/<host>/stage2, rust/build/toyos-compiler compiler::primary_key, the hash of the primary's record
freestanding libraries rust/build/freestanding/<key> sysroot::freestanding_key
sysroot rust/build/sysroots/<key> sysroot::key

Every 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, with queue: max, never cancels one that waits:

  • --ci toolchain clones rust/ at depth 1 and writes each layer's entry (toolchain-<layer>-<key>) and paths as step outputs.
  • Four restore steps take exactly those outputs.
  • --ci bootstrap refuses 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 step built or kept.

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's toolchain on a push and nightly.yml's on its schedule; they share the job's group, so one cold key is built once on main.

the tree toolchain restores builds, and saves into its own scope
moves no layer all four nothing
moves the sysroot only (an ABI or libc change) LLVM, compiler, freestanding the sysroot
moves the freestanding libraries (a fork bump to library/ alone, as #650's and #659's) LLVM, compiler freestanding, sysroot
moves the compiler (a fork bump to compiler/) LLVM compiler, freestanding, sysroot
moves the LLVM (an LLVM bump, src/bootstrap, the runner's cc, c++ or CMake, or n2's pin) nothing all four

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's guest and the nightly's tcg call it) restores only the sysroot, by the toolchain job's key, with fail-on-cache-miss: true. release::install lays it out as the installed toolchain after holding the witness it records against the tree's. It keeps no target or registry cache: main's guest- entry goes with the nightly's guest and tcg jobs that carried it.

The host cache is #669's, unchanged: ci.yml's host reads it and the nightly's host seals 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's release is the only job granted contents: write; no trigger runs other code on main's ref; no cache-mode: write; guest / suite has no job-level if:; a saving job runs only cargo run -- --ci <job>.

The release

  • nightly.yml's release runs only on main (if: github.ref == 'refs/heads/main'), restores the sysroot its toolchain names and runs --ci release. The driver refuses that job before it reads anything unless it is nightly.yml on refs/heads/main, scheduled or dispatched, with GITHUB_REPOSITORY set: the refusal is the boundary, the if: only keeps a branch's nightly from concluding failure.
  • A landing on main during a nightly is not that nightly's failure. Main's nightly 36985427800, at 74a2e703b, ended its 2:53:54 build red: "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_tip is the release's one decision, taken before anything is laid out, packed or put up. It reads crates.io, then main's tip:
    • Main has moved past HEAD: nothing is put up, and the job is green, saying "main has moved past <head>, and its tip's nightly is the one that publishes". A re-run of an older nightly therefore still moves no alias back.
    • HEAD is the tip and crates.io's newest SDK crates are its own: the release is put up, and the alias is written from the plan that read returned, so nothing read later can disagree with it.
    • HEAD is the tip and they are not: refused, "crates.io holds no <crate> of this tree, main's tip, so no sdk alias can name it". publish.yml owes them.
    • crates.io before the tip is the order that closes the race: a landing whose crates the first read shows has moved the tip the second read sees.
    • The cost, filed as 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 whose release runs at the tip, or a dispatch. A nightly overtaken every night publishes nothing until one is not.
    • The refusal's cost, filed as issues/build/a-release-that-decides-before-its-tips-crates-are-up-reds-the-nightly.md: a nightly whose release decides before publish.yml has 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 green publish runs of 2026-10-02 took between 1:04 and 1:54 from creation.
  • pack streams the tar crate into flate2's pure-Rust gzip, entries sorted, no owner or time. The asset is toyos-toolchain.tar.gz, tagged toolchain-linux-x86_64-<sysroot key>, and it carries x86_64-unknown-linux-gnu/stage2, its witness and TOOLCHAIN. It no longer carries x86_64-unknown-toyos/stage2, the hosted rustc main's packed: no build reads it unless its config sets hosted-rustc, and system.toml does not.
  • Github speaks the REST API through a ureq agent, as does sdkversion::index for the crates.io index: rustls on ring with webpki's roots, which is ureq's own rustls feature, and User-Agent toyos-build (https://github.com/ToyOSOrg/ToyOS).
    • ring is the owner's ruling (2026-10-02), for one TLS provider everywhere. The root manifest names neither provider. issues/design-debt/the-internet-clients-work-unchanged.md said 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 all prints nothing for userland and for tests/toyos-rust-tests (exit 0 each), the two workspaces built for ToyOS whose lockfiles name ring.
    • ring brings cc into the build system's own build, which needed none: cargo tree -i cc printed nothing before the move (exit 0, at 7f2721ac2) 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 the cc row of issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md.
    • The agent on ring, against GitHub: one GET of releases/tags/toolchain-linux-x86_64-sdk-0.26.0 through Github::call from the development host, answered in 462 ms, exit 0; put reads the answer as Carried for the digest GitHub records, sha256:68f6a1ac…, and as Replace for any other.
    • The agent on ring, against the crates.io index: sdkversion::index from the development host, a throwaway test at 68dc21ce2, exit 0 (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 (comment)): 28 lines for toyos-abi in 786 ms, each read by sdkversion::assign, and nothing for a name nobody published, in 725 ms.
  • put decides 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:

encoder bytes
flate2, pack 413,389,598 (36.4 s; 35.9 s again, the same bytes)
gzip -6 412,043,203
zstd -3 379,443,021

Every method put_up sends was measured against GitHub at 42a823b1f, through the agent's previous provider (#671 (comment)): one draft release on ToyOSOrg/ToyOS created, patched, given a 33-byte asset, read back, and asset and release deleted, each through Github::call, exit 0.

  • POST of JSON answered the release with its id and upload_url; PATCH answered it with the new body; both DELETEs answered no content, read as Some(Null); a GET after the delete answered 404, read as None.
  • digest: the upload's own answer carries "digest": "sha256:b99de743…", with "state": "uploaded", and so does the release read back 307 ms after it: put reads that release as Carried, and as Replace for any other bytes. shasum -a 256 prints the same digest for those bytes.
  • Nothing is left: 108 releases and no draft before and after, the listings byte for byte the same, as are the 108 tags; the release and the asset answer 404.
  • The probe's release was a draft, which GitHub does not find by its tag (measured: 404), so it was read back by id; put_up reads 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 of 281602b72, which the head is one commit past: two files under issues/ and one path in a comment of toyos-cpuvuln/src/tests.rs. Run 37007753187 is of 68dc21ce2. 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 merge f528c4bb2 of 281602b72 into c1c504835, runner image ubuntu-24.04 20260927.320.1, concluded success.

job started → completed (UTC) took conclusion
host (110863352409) 13:43:51 → 13:51:48 7:57 success: restored host-sealed-Linux-X64-36988155706; [ci] Host: 65 step(s), all green
toolchain / build (110863352757) 13:43:51 → 13:46:06 2:15 success: four layers restored, nothing built
guest / suite (110864228036) 13:46:09 → 14:03:17 17:08 success: restored 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 merge 27b4428 of 68dc21ce2 into c1c504835, runner image ubuntu-24.04 20260927.320.1.

job started → completed (UTC) took conclusion
host (110839929948) 12:37:04 → 12:47:23 10:19 success: restored host-sealed-Linux-X64-36988155706; [ci] Host: 65 step(s), all green
toolchain / build (110839930089) 12:37:03 → 12:48:03 11:00 success: LLVM and compiler restored, freestanding and sysroot built and saved
guest / suite (110843582245) 12:48:06 → 13:04:37 16:31 success: restored toolchain-sysroot-d0548e109d1e0ef8; /dev/kvm opens, AMD EPYC 9V74 80-Core Processor, 4 core(s); test result: ok. 21 passed, 21 total (715.0s)

The runs below are on 42a823b1f and before.

The cold path: run 36934214557, pull_request, on the merge of f1ccb0b3e into 76d0d9389, runner image ubuntu-24.04 20260927.320.1:

job started → completed (UTC) took conclusion
host (110610544912) 22:18:12 → 22:33:38 15:26 success
toolchain / build (110610545360) 22:18:12 → 00:29:58 2:11:46 success: four restores missed, four layers built and saved
guest / suite (110649069031) 00:30:01 → 00:51:26 21:25 success: "test result: ok. 21 passed, 21 total", under KVM
  • [ci] this tree's toolchain: llvm da88e203716ecb6d built, compiler 8e57eb89153a182c built, freestanding 847668c56799bfaa built, sysroot 121d3857d01bcded built. --ci bootstrap took 2:09:01: LLVM 1:29:15, compiler 0:28:06, freestanding 0:06:31, the sysroot's std 0:03:31.
  • The sixteen virt_* tests and nested_nmi_is_loud pass on a runner.
  • The layers' sizes, as saved: LLVM 163,580,991 B, compiler 211,977,105 B, freestanding 118,212,285 B, sysroot 424,938,175 B; 918,708,556 B a set.
  • The budget: the repository holds 4,703,220,675 B of its 10 GB (actions/caches, 12:29Z on 2026-10-02): main's host-sealed-Linux-X64-36988155706 at 1,622,150,459 and host-sealed-Linux-X64-36985427800 at 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 with gh cache delete … --ref refs/pull/671/merge. The keys that head computes on a runner of that image: LLVM da88e203716ecb6d and compiler 8e57eb89153a182c, unmoved; freestanding 5658957050c8b2bb and sysroot c882c693da324ad2, 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 printed 847668c56799bfaa and 121d3857d01bcded, the keys run 36934214557 printed. host took 9:58, 7:36, 9:56 and 8:32, each restoring host-sealed-Linux-X64-36985427800 and ending [ci] Host: 60 step(s), all green.

run the pull request's cache scope before it the row [ci] this tree's toolchain: toolchain / build took guest / suite
0 (attempt 1) as it stands: toolchain-llvm-da88e203716ecb6d, toolchain-compiler-8e57eb89153a182c LLVM and compiler restored; freestanding and sysroot built llvm da88e203716ecb6d restored, compiler 8e57eb89153a182c restored, freestanding 5658957050c8b2bb built, sysroot c882c693da324ad2 built 10:53 success, 19:49, 21 passed, 21 total (739.0s)
1 (attempt 2) as run 0 left it four restored, nothing built llvm da88e203716ecb6d restored, compiler 8e57eb89153a182c restored, freestanding 5658957050c8b2bb restored, sysroot c882c693da324ad2 restored 2:38 success, 16:20, 21 passed, 21 total (692.3s)
2 (attempt 3) toolchain-sysroot-c882c693da324ad2 deleted three restored, the sysroot built llvm da88e203716ecb6d restored, compiler 8e57eb89153a182c restored, freestanding 5658957050c8b2bb restored, sysroot c882c693da324ad2 built 7:13 success, 20:29, 21 passed, 21 total (704.1s)
3 (attempt 4) toolchain-compiler-8e57eb89153a182c, toolchain-freestanding-5658957050c8b2bb and toolchain-sysroot-c882c693da324ad2 deleted LLVM restored, three built llvm da88e203716ecb6d restored, compiler 8e57eb89153a182c built, freestanding 5658957050c8b2bb built, sysroot c882c693da324ad2 built 41:27 success, 10:20, 21 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:

  1. Done: check_response_timeout_minutes in ruleset 20589156 raised from 180 to 240, by the orchestrator on 2026-10-02. gh api repos/ToyOSOrg/ToyOS/rulesets/20589156 at 13:59:20Z reads 240 and one required check, host.
  2. Land this pull request.
  3. Wait for main's publish.yml toolchain job to save its four layers.
  4. Name guest / suite a required check, once one merge group's guest / suite has concluded success.
  • The merge queue's path has run in no Actions run. gh run list --event merge_group holds no pr-671 group (200 runs back to 2026-09-24, read at 13:39Z on 2026-10-02). Unmeasured, then: toolchain.yml's three github.event_name != 'merge_group' save guards, and guest / suite restoring under fail-on-cache-miss a 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".
  • Until step 4 the guest check gates nothing. The ruleset names one required check, host: a pull request or a merge group whose guest / suite is red still lands. Filed as issues/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.
  • Until step 3 every toolchain job off main is cold. Main's scope holds no layer, so every ready pull request's run and every merge group, this pull request's own included, builds all four, 2:11:46 measured, and each pull request's run saves a 918,708,556 B set into its own scope. A check named before step 3 makes every merge group cold.
  • Why 240. The cold toolchain / build took 2:11:46, 2:09:01 of it --ci bootstrap. One runner label spreads wider than that: LLVM 029e544969e88c25 built cold on ubuntu-24.04 in 1:06:24, 1:22:54 and 1:28:26 (portability-linux jobs 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 / suite follows 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).
  • The queue is cold only when a landing moves the LLVM's key, or when the runner image moves cc, c++ or CMake (filed, below).

Other decisions

  • .claude/agents/reviewer.md is 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's build saves them from three workflows. That sentence is now the host cache's alone, and Workflows' first rule holds the layers.
  • Root CLAUDE.md said "Guests run nightly."; it says where they run now.
  • A toolchain job that waits is never cancelled. A concurrency group holds one pending job, and a third arriving cancelled it; when that was the nightly's, the nightly ran no release and its tcg restored an empty key. queue: max lets up to 100 wait. GitHub accepts it: a nightly dispatched on this branch at 42a823b1f, run 36988266186, started its toolchain / build, and was cancelled at once having saved nothing.

Gates

gate head exit
cargo run -- --ci host a305253e9 0, 14:01:12Z to 14:04:16Z: "Host: 64 step(s), all green"; the build system 389 passed, 10 ignored; git status --porcelain --ignore-submodules=none empty after
cargo run -- --build-only a305253e9 0, 14:04:55Z to 14:05:10Z: no store built
cargo run -- --build-only 68dc21ce2 0, 12:28:56Z to 12:29:04Z: every store kept
cargo test --test toyos-build, the whole guest suite 68dc21ce2 0, 12:29:04Z to 12:29:36Z: "test result: ok. 21 passed, 21 total (29.8s)"
cargo run -- --ci host 68dc21ce2 0, 12:29:36Z to 12:32:50Z: "Host: 64 step(s), all green"; the build system 389 passed, 10 ignored
the same three 482d4873f, whose src/ and Cargo.lock are the head's 0, 0 and 0, 12:16:46Z to 12:27:39Z: freestanding 4043f2f3e5ab2053 and sysroot 8ee6b823bf2f0688 built after the merge, compiler 4eb88555ff0f85b1 kept; "21 passed, 21 total (82.7s)"; "Host: 64 step(s), all green"

Mutations. Of sdk_at_tip, at 68dc21ce2, each against a_landing_during_the_nightly_puts_nothing_up_and_is_no_failure, which is green unmutated (#671 (comment)):

mutation exit the red
m1 the base's logic put back: the tip read first and refused off it, then crates.io 101 a landing before the release read anything: "HEAD … is not main's tip"
m2 the two reads swapped, nothing else 101 a landing between the two reads: "crates.io holds no toyos-abi of this tree, main's tip…"
m3 what is owed refused whatever the tip 101 a landing before the release read anything: "crates.io holds no toyos-abi of this tree…", nightly 36985427800's own line

At 1a4f3abda (#671 (comment)):

mutation test exit
9e917f19b's code reverted, its test kept a_submodule_is_the_commit_its_gitlink_records_checked_out_or_not 101: "checking the submodule out moved the key"
the review's src/libc.rs patch cargo test --lib 0: the filed issue's evidence

What 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

  • Negative control. Who may write a release: no write grant moved; read off the five workflows at this head, nightly.yml's release holds the only contents: write, and publish.yml's id-token: write is main's. Run as a pull request's job, the merge queue's, main's push or a branch's dispatched nightly, release_as is 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 reverted 9e917f19b, red as CI's run 36913380100 was.
  • Independent oracle. The recorded failure for the release's decision: nightly 36985427800's log line is the refusal m3 reproduces, on the landing the test stages. GitHub itself for the release's methods, its digest and the agent's read on ring, and shasum for 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 its actions-group-concurrency text for queue: "max: Up to 100 jobs or workflow runs can be pending in the concurrency group."

A reader of main must not miss

  • The build system's own build needs a C compiler, for ring.
  • A nightly a landing overtakes publishes nothing, and is green.
  • guest / suite is not a required check until the ruleset names it, and the order above is what makes naming it safe.
  • Deleted with what it described: 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.md now sums two host entries beside the toolchain's layers where it summed them beside guest entries, and src/cicache.rs's LIMIT names no guest entry.
  • Filed: 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.
  • Renamed: issues/build/no-nightly-runner-has-had-its-cpuid-and-vulnerability-lines-captured.md is issues/build/no-kvm-runner-has-had-its-cpuid-and-vulnerability-lines-captured.md, its heading and exit corrected and its one citation, in toyos-cpuvuln/src/tests.rs, moved with it: no nightly job is given /dev/kvm, and the KVM guests are ci.yml's guest.

Unsure

  • The release path runs first on main's nightly: a 413 MB asset sent in one request, and its digest in 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.
  • The agent on ring has run on no Linux host. Both of its measurements are the development host's, macOS on arm64. publish.yml's --ci publish reads 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.
  • Whether a merge group's guest / suite reaches a conclusion before the check is required is unmeasured. While host is the one required check, a merge group merges when host concludes, 7:57 and 10:19 in runs 37014929723 and 37007753187. This pull request's own group is cold, a toolchain / build of 2:11:46 in run 36934214557, so its guest / suite has not started by then. A warm group's follows a toolchain / build of 2:15 to 2:38 and has itself taken between 10:20 and 23:17, so by every measurement here it too concludes after host. On main a merge group runs host alone, 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.
    • If they are cancelled, no merge group's guest / suite concludes until the check is required, and step 4's condition never comes. The naming then rests on main's toolchain save, step 3, and on one pull request run's guest / suite concluding success, not on a merge group's; and the queue's path first reaches a conclusion in the first merge group after the naming.
  • First exercised by main's nightly after this lands: release's if:, queue: max on main, and guest.yml called with kvm: false, the nightly's tcg lane. The branch's one dispatched nightly was cancelled with tcg skipped, so that lane has run in no Actions run.

🤖 Generated with Claude Code

https://claude.ai/code/session_013UDZQ6fSKw14e4w2TKTRfm

Japabu and others added 2 commits October 1, 2026 12:38
… 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
@Japabu
Japabu marked this pull request as ready for review October 1, 2026 12:44
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
@Japabu
Japabu marked this pull request as draft October 1, 2026 13:18
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
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Review, round 1, at 2a0e045c4.

CI. No run at 2a0e045c4: the PR is a draft, so run 36867733521 skipped host, toolchain and guest. At 09bda2f3c (run 36863809437): host success, toolchain success, guest failure, 4 passed and 17 failed. These are main's reds; nightly run 36843762360 has the same 17. 2a0e045c4 adds only two issue files on top of 09bda2f3c.

Net lines (git diff --shortstat origin/main...HEAD): 11 files, +272 −80, net +192.

  • Production: +146 −59, net +87 (ci.yml +101, nightly.yml −15, src/ci.rs +1).
  • Tests: +45 −4, net +41.
  • Prose: net +64.

The brief

  1. Cost. Runner minutes are free on this public repository (orchestrator.md:42). What the check costs is time to a verdict: 27 min 14 s, against host's 10 min 56 s and 12 min 33 s on Linux in main's last two merge groups (runs 36868449794 and 36862873592).
    • Where guest's 23 min 17 s goes: 779 s is 17 red tests waiting out their ceilings (the 16 virt_* 740 s, nested_nmi_is_loud 39 s). The rest of the suite, 346 s, is every build in it plus the four green boots. Then deps 192 s, and the driver, install and harness 65 s. Booting red dominates, not building.
    • Host cache: read by content, written by main's cold nightly alone, sealed and bounded, with its workflow rules in the review prompt #669 changes only the host cache. It files the guest cache as read by mtime, so every path crate is rebuilt under a fresh checkout. As it stands it cuts none of this. And tcg writes no guest entry while main's suite is red.
    • The check's real cost is unmeasured until its suite is green.
    • toolchain is not the clean answer (B1, B2, N1). Main's tag goes unpublished because only the nightly publishes it. The landing that moves the tag should publish it, from a tree that becomes main, once the tag hashes the build system that builds it.
  2. Coverage. Nothing is lost. ci.yml's guest and the nightly's tcg each run all 21 tests, the 16 virt_* under TCG in both (the runner is x86-64), as the dropped KVM lane did. There is no --weekly tier: 6a2129e deleted the tiers, and git grep -i weekly finds nothing on the branch or on main.
  3. Instructions. CLAUDE.md shrinks from 16077 to 16068 bytes. What the changed lines leave untrue or unsaid is B5.
  4. Controls. The four mutations delete the exact substrings the two tests grep for. They show that the greps fire, not that the claims hold. B4 names the mutation that matters, and B3 removes the need for the second test.
  5. Minimality. B3, N1 and every REMOVE.

Plan: not acceptable.

Land guest green and required at once:

BLOCKER

  • B1. .github/workflows/ci.yml:49-70 — toolchain gives every same-repo pull request's unreviewed build system contents: write, and publishes what it bootstraps under its tree's tag — why:

    • The tag hashes none of src/toolchain.rs, src/sysroot.rs, src/llvm.rs or src/libc.rs (issues/build/the-release-tag-hashes-none-of-the-build-system-that-builds-the-toolchain.md).
    • install checks no digest. Main's issues/build/the-toolchain-install-unpacks-an-asset-no-digest-vouches-for.md names the nightly's build as the only job holding the token.
    • So a branch that edits one of those files while main's tag is unpublished publishes the toolchain that main's guest and tcg then install and the SDK alias then names, whether or not the branch lands. Measured: main's tag was unpublished 22:16Z–12:44Z (this PR's body), and 16 of main's last 100 first-parent landings edited one of those files.
    • Its TOOLCHAIN names a refs/pull/N/merge commit (src/release.rs:355).
    • Every pull request now runs Go's gh (release::published), which Arrivals refuses; install already asks the same question with curl.
    • Fix: no pull_request run holds the write token or publishes.
  • B2. .github/workflows/ci.yml:13-15,49-52 — as a required gate, the bootstrap cannot report in time — why:

    • 20 of main's last 100 first-parent landings moved the trees the tag hashes.
    • Each such pull request bootstraps for 2.5–3 h on its own run, and cancel-in-progress: true kills that bootstrap at every push.
    • It bootstraps again in the merge queue whenever main moved those trees in the meantime. Ruleset 20589156 allows a check 180 minutes there (read today), so a required guest behind the bootstrap fails that merge group.
    • The PR body's "Unsure" names both problems and leaves them.
  • B3. .github/workflows/ci.yml:49-144 — toolchain and guest are copies of nightly.yml's build (55-75) and tcg (80-155) — why:

    • The copies include two shell steps of ToyOS's own, deps and "disk, QEMU and CMake". src/CLAUDE.md:17 calls logic in YAML a defect, and Arrivals refuses new shell.
    • the_guest_lanes_share_an_instrument_and_a_cache (src/ci.rs:962-983) holds only two fields of the copies, the digest and the path list. It does not hold deps, which installs QEMU and both firmwares, nor restore-keys.
    • Fix: one on: workflow_call workflow that both lanes call, with KVM and the cache save as inputs, is the one declaration. The test and the four cross-file comments then go.
  • B4. src/ci.rs:954-960 — the_required_checks_are_jobs_on_every_pull_request stays green under the patch below at ci.yml:76 — why:

    • The patch skips guest past a failed toolchain: the green-by-skip that the test's own doc names.
    • The four controls only delete the substrings it greps for.
    • The test must red on this patch. Holding the if: whole against host's condition also reds on dropping the pull-request arm.
    -    if: ${{ !cancelled() && (github.event_name == 'merge_group' || github.event.pull_request.draft == false) }}
    +    if: ${{ !cancelled() && needs.toolchain.result == 'success' && (github.event_name == 'merge_group' || github.event.pull_request.draft == false) }}
    
  • B5. CLAUDE.md:75, .claude/agents/orchestrator.md:35-36,71 — these retire every local guest run, the orchestrator's included, and say nothing in place of the guest mutation loop — why:

    • The PR body's "Unsure" admits it: "A guest mutation has nowhere to run".
    • reviewer.md wants a high-risk change's negative control red on a named commit, and implementer.md:74-76 runs every mutation a review names.
    • tests/CLAUDE.md:7 and :9 still instruct re-running a local suite and reproducing boot deaths with parallel local guests.
    • Fix: the same diff says how a guest mutation and a boot-death reproduction run now (for example, a mutation commit and its revert, each judged by its own guest run). Or it keeps the orchestrator's local runs, and CLAUDE.md says so.
  • B6. .github/workflows/ci.yml:72-144 — the branch lands guest red on main's tree (run 36863809437: 4 passed, 17 failed) as a check nothing requires — why:

    • It is an exit status nobody reads.
    • Every pull request's CI goes red, no branch meets orchestrator.md:20 or the review gate, and a new guest red lands unseen.
    • CLAUDE.md:95 says what a red test on main is owed.
    • Fix: land it green and required (Plan, above).

NOTE

  • N1. .github/workflows/ci.yml:60-66 — on a published tag (the case this run measured), toolchain spends 2 min 46 s cleaning disk and installing QEMU and CMake for a bootstrap that does not happen, then a 62 s lookup. This sits serially ahead of guest on every pull request.
  • N2. src/release.rs:126-127 — the refusal still says the nightly's build is what publishes, which is false once another job publishes. The branch found this compromise and left it only in the PR body's "Unsure". Record it in issues/ with an owner and an exit, or remove it.
  • N3. issues/kernel/the-nested-nmi-report-interleaves-with-another-cpus-console-line.md — Fatal paths write the console UART only under its registers, whose lock knows which CPU's fatal path holds it #675 (head 21e3fc86f) fixes this defect but cannot delete the file, because the file is not on main. Whichever PR lands second deletes it, or it lands open over a fixed defect.

REMOVE

  • src/ci.rs:5-12 — the rewritten tour of the three workflows. "so a merge is gated on all of them" is false while ruleset 20589156 requires host alone (read today).
  • src/ci.rs:951 — "host and guest are the required checks." False, for the same reason.
  • src/ci.rs:39-40 — the rewritten "(ci.yml, nightly)" in USAGE. It rots with every workflow edit.
  • .github/workflows/ci.yml:3-5 — the rewritten header. "Each step is cargo run -- --ci <job>" is false of deps and of "disk, QEMU and CMake".
  • .github/workflows/nightly.yml:3-5 — the rewritten header, which restates the jobs beneath it.
  • .github/qemu-version:6 — the rewritten "ci.yml and nightly.yml share".
  • tests/common/lane.rs:69-71 — the rewritten "read afterwards, as CI's artifact" clause.
  • issues/kernel/the-nested-nmi-report-interleaves-with-another-cpus-console-line.md:19 — "with byte-identical interleaving" is false. Run 36843762360 interleaved another record and ended "QEMU died before NESTED NMI" at 63 s, not with a 39 s timeout.
  • issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md:44 — "CI's four rustup installs": a count that other landings move.
  • issues/kernel/the-kernel-is-at-least-as-secure-as-linux-on-every-machine-toyos-supports.md:12 and issues/kernel/the-speculation-decision-does-not-model-an-affected-cpus-l1tf-line.md:28 — "the nightly's" KVM guests and runners. False once the nightly boots no KVM guest.

SEND BACK

Japabu and others added 3 commits October 1, 2026 17:03
…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
@Japabu Japabu changed the title The guest suite is every pull request's guest check, on its tree's toolchain The guest suite is every pull request's guest check, on a toolchain only main publishes and CI installs by its digest Oct 1, 2026
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Review, round 2, at 9a3934221.

CI. Run 36883368774 at 9a3934221 skipped host, toolchain and guest, because the PR is a draft. Nothing this branch adds has run on a runner. This review proceeds on the brief's word that the batch's run is the evidence.

Net lines (git diff --shortstat origin/main...HEAD): 22 files, +934 −405, net +529.

  • Production: +288 (release.rs +222, workflows +74, toolchain.rs +1, clang.rs/libcxx.rs/n2.rs −9, ci.rs 0).
  • Tests: +251 (release.rs +172, ci.rs +79).
  • Prose: −10.

The production growth buys provenance that S1 and S2 show it does not have.

Main moved. origin/main moved to 1a8cd4a53 during this review. The merge base is still a97ff80df. git merge-tree a97ff80df HEAD origin/main shows implementer.md and src/ci.rs changed in both, with no conflict marker.

Round 1

  • B1 — OPEN. The pull-request arm is closed: ci.yml and nightly.yml are read-only, and m3 reds the gate on a block-style grant. What B1 guarded is reachable again through the artifacts: a branch planting the toolchain that main's CI installs and main publishes. See S1 and S2.
  • B2 — OPEN. The body's own table keeps it: an input-moving PR's merge group "bootstraps and overruns the queue's 180-minute check timeout". That happens when main moved an input after the PR's last run, or when two such PRs are queued together.
    • It is not a rust-bump corner. Over the 100 first-parent landings ending at a97ff80df (2026-09-27T04:45Z to 2026-10-01T13:24Z, 104.6 h), this tag moved on 32, about one every 3.3 h.
    • Each such PR waits 2 h 19 min to 3 h 08 min of bootstrap before guest starts, on every push. Its remedy (merge main, push, bootstrap again) runs the same race.
    • On a required check that is a designed-in red, and the design answer belongs in this branch.
    • toolchain.yml restores none of the stores the build system keys apart (LLVM, compiler, sysroot). 17 of those 32 landings touched neither rust nor llvm.rs, clang.rs or compiler.rs, yet every bootstrap for them rebuilds LLVM and rustc from nothing.
  • B3 — CLOSED. guest.yml and toolchain.yml are each defined once, and ci.yml, nightly.yml and publish.yml call them. The shared-digest test and the cross-file comments are gone (read at 9a3934221).
  • B4 — CLOSED by m1 and m2 (exit 101, PR body). Its sibling inside guest.yml is a new BLOCKER below.
  • B5 — CLOSED. CLAUDE.md:75 and implementer.md:23-24 say the plain suite runs in CI and the orchestrator runs guest mutations. git diff origin/main...HEAD -- .claude/agents/orchestrator.md is empty.
  • B6 — OPEN. Closing it needs the batch's run to be green and guest / suite required at once. That run has not happened, and no run shows guest green.
  • N1, N2, N3 and every round-1 REMOVE are CLOSED (read at 9a3934221).

The brief

  1. Security.
    • Fork pull requests: a fork PR gets no write token and pushes no tag. is_mains refuses its head_repository, and its workflows run only under its own heads. It can flood the listing (NOTE).
    • Same-repo writers: a same-repo writer, or a same-repo PR's own job, can plant a build that every tree installs (S1, S2). Main's own release then publishes S1's build.
    • Write access: the write token is still any branch's for the asking. A same-repo PR's diff gets it (run 36863809437, Contents: write). publish.yml's workflow_dispatch: {} hands release its token on whatever ref it is dispatched on, and only that ref's own code stands between the token and a publish. The filed release-asset issue records this for the asset; S1 carries it into CI and into main's release.
    • The digest check: it holds a download to what the uploading run uploaded, and nothing more. Provenance is the whole defence, and none of the PR's three oracles covers is_mains or vouched.
  2. Inputs.
    • The tag hashes rust, toyos-abi/src, toyos/src, userland/libc/src, userland/libc/include, their three manifests and the 18 BUILDERS.
    • That is more than the compiler build reads, and the excess is a BLOCKER below. In one spot it is less, though no byte moves today (NOTE).
    • The 180-minute overrun is not acceptable as is: see B2.
  3. Above and below.
  4. Batch. The resolution is right. The AArch64 kernel is entered with the MMU off, and refuses an entry with it on #676 at 8d74557fa changed three files in both, with conflict markers in nightly.yml alone. Both of The AArch64 kernel is entered with the MMU off, and refuses an entry with it on #676's edits land in the one deps and the one container comment that both lanes now share in guest.yml. The host-tools issue and src/ci.rs merge clean. Two NOTEs below.

BLOCKER

  • S1. src/release.rs:210-216,222 — is_mains names main's publisher by path, event and head_branch == "main", and a tag named main carries that head_branch. choose then takes the newest such build ahead of every other, never asking whether its head is on main — why:
    • How it is planted: a writer pushes refs/tags/main at a commit whose publish.yml uploads <main's tag>.tar.zst. A same-repo PR's own job can do the same: it asks for contents: write and actions: write, creates the tag and dispatches publish.yml on it.
    • What follows: every PR, merge group and nightly installs that build, and main's toolchain finds it and never bootstraps. Main's release fetches it, put_up replaces main's asset with it, and the SDK alias moves.
    • Oracle: GitHub names a tag-pushed run's head_branch after the tag. BurntSushi/ripgrep run 29431117779 shows push, head_branch "15.2.0". Ruleset 20589156, this repository's only ruleset, targets branches, so nothing refuses refs/tags/main.
    • Negative control: a publish.yml/main/push build whose head is not on main is refused. a_tree_installs_mains_build_else_one_its_history_vouches_for (:896-897) asserts the opposite today: it chooses a mains build whose head nothing vouches for.
    • The install-digest issue this branch deletes has the exit "an asset whose SHA-256 is one that no job holding a write token can rewrite". That exit is not met.
  • S2. src/release.rs:189-206,226,262 — a build is vouched for by its run's head_sha alone, and the run itself is fetched only when its branch is main — why:
    • How it is planted: a pull_request run takes its workflows from the merge with its base. A writer opens a PR from a vouched commit (main's tip, or a queued PR's head) into a branch of their own. Their on: pull_request workflow then runs and uploads <tag>.tar.zst under that head_sha.
    • What follows: every tree with that tag and no main's build installs it. That covers an input-moving PR's guest, its merge group, and every PR in the 2–3 h after it lands. A nightly tcg on main in that window also saves the guest- cache that every PR restores.
    • Negative control: a build whose run is a pull_request or pull_request_target against a base other than main, with a vouched head, is refused. listed reads no event or base, so today nothing can refuse it.
  • src/release.rs:44-63 — BUILDERS hashes modules the toolchain build never reads, and every hashed file whole, mod tests included — why:
  • .github/workflows/guest.yml:17-18 — the required check is guest / suite, and the_guest_lanes_run_whatever_the_toolchain_concluded never reads that job's own condition — why: a skipped required check reads green. Patch: under suite:, add + if: inputs.save-cache. That skips the suite on every PR and merge group. The test stays green; it must red.
  • src/ci.rs:985-988 — only_mains_publisher_holds_a_write_token sees a grant only on a line ending : write or containing write-all — why: a flow mapping or a trailing comment grants the same token. Patch, in ci.yml's toolchain job: + permissions: { contents: write, actions: read }. The test stays green; it must red.
  • src/release.rs:853-862 — mains_builds_are_publish_yml_on_main_and_nothing_else refuses every fixture by a clause other than the path — why: delete run["path"] == PUBLISHER && from is_mains (:211) and the test stays green. A nightly.yml/main/workflow_dispatch fixture must red on that patch.
  • src/release.rs:429-457 — put_up has no test — why: the filed release-asset issue rests on its replacement ("publish.yml puts main's build back only on main's next push").
    • Patch :447-450 to Some(_) => return Ok(format!("{tag} already carries main's build")),: another writer's asset is then never replaced, and no test reds.
    • The decision is pure given the release's JSON, and a test of it must red on that patch.

NOTE

  • src/release.rs:258 — the listing reads one page: per_page=100, newest first, never the next. 100 newer artifacts with a tag's name, from any run, hide main's build, and every run then bootstraps for 2–3 h. A fork PR's run can upload them after one approval (policy all_external_contributors); a writer's runs need none.
  • .github/workflows/toolchain.yml:36, src/release.rs:298 — --ci bootstrap runs whatever --ci toolchain said and asks find again, so one question is answered twice. A build that vanishes between the two answers bootstraps unprovisioned. The upload also needs if-no-files-found: ignore, which uploads nothing, silently, when no file is there.
  • src/release.rs:711 — a crate:: name with no src/<name>.rs is dropped silently. Today that drops crate::ensure_submodule, crate::primary_checkout and crate::git_common_dir, so builder code in src/lib.rs or in a directory module never reaches the tag.
  • src/release.rs:214 — run["repository"]["full_name"] == repo is dead: every run that repos/{repo}/actions/runs/{id} answers with is repo's.
  • src/release.rs:419-422 — on every push to main, release_as downloads and hashes the whole build before put_up asks whether the release already carries that digest.
  • src/release.rs:412-424 — release_as has no at_tip check (src/ci.rs:791). Re-running an older push's release moves sdk-<version> back onto an older toolchain, though --ci publish refuses that same re-run.
  • .github/workflows/toolchain.yml:40 — actions/upload-artifact is pinned twice: v7.0.1 here and v4.6.2 at guest.yml:87.
  • Batch — Fatal paths write the console UART only under its registers, whose lock knows which CPU's fatal path holds it #675's head is now f9835df2f, not the 21e3fc86f the body measured. Legacy git merge-tree of 9a3934221 with f9835df2f shows no entry changed in both.
  • Batch — in issues/build/the-build-runs-host-tools-outside-rust-and-qemu.md:25, the ca-certificates row's "the nightly's containers" is wrong once guest.yml's container runs on every PR. The batch's resolution owns that row, as it owns the conflict beside it.

REMOVE

  • src/toolchain.rs:588-591 — rewritten, and "hashes every source and every module it is built from" is false either way.
  • src/ci.rs:978-982 — "which main alone triggers" is false: publish.yml:10 dispatches on any branch or tag.
  • .github/workflows/toolchain.yml:3-5 — a header that restates src/release.rs.
  • .github/workflows/publish.yml:39-40,50-52 — narration of what the jobs do.
  • src/release.rs:74,84,527 — doc lines corrected word for word instead of deleted.
  • .github/workflows/nightly.yml:11 — rewritten, and "an hour" is not the 2 h 19 min to 3 h 08 min the body measured.
  • issues/build/a-toolchain-releases-asset-is-whatever-its-last-writer-put-there.md:9-11 — describes CI's install, not the defect, and is false under S1 and S2.

SEND BACK

Japabu and others added 4 commits October 1, 2026 19:02
…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
@Japabu

Japabu commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

Round 3's mutation patches, each made against 0237a67ec and run as the body's "Mutations" says: git apply --check, git apply, cargo test --lib --no-run, the named test with --exact, git apply -R.

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 this

m5

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`: no

m7

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` actually

m8

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.

@Japabu

Japabu commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator Author

Round 3's size measurements: the scripts and what each printed. The Linux layers are carved from toyos-toolchain.tar.zst of toolchain-linux-x86_64-48dd24f826263d6c, extracted by zstd -dc | tar -x; driver-nodebug.so is its librustc_driver after llvm-objcopy --strip-debug. Every size is tar -cf - | zstd -3 -T0 | wc -c, as actions/cache v4.3.0's zstdmt stores an entry.

measure-asset.sh

#!/bin/sh
# Compressed size of each part of the Linux asset, as actions/cache compresses (zstd -3 --long=30), and as zstd -3.
cd "$1/x" || exit 1
m() {
  name=$1; shift
  long=$(tar -cf - "$@" 2>/dev/null | zstd -3 --long=30 -T0 -c | wc -c | tr -d ' ')
  plain=$(tar -cf - "$@" 2>/dev/null | zstd -3 -T0 -c | wc -c | tr -d ' ')
  raw=$(du -sk "$@" | awk '{s+=$1} END {print s}')
  echo "$name raw_KiB=$raw zstd3_long30_B=$long zstd3_B=$plain"
}
G=x86_64-unknown-linux-gnu/stage2
R=$G/lib/rustlib
m sysroot-whole $G
m hosted-rustc x86_64-unknown-toyos/stage2
m compiler-host-part $G/bin $G/lib/librustc_driver-37f9a7448f819635.so $R/x86_64-unknown-linux-gnu
m librustc_driver $G/lib/librustc_driver-37f9a7448f819635.so
m rustdoc $G/bin/rustdoc
m host-bin $R/x86_64-unknown-linux-gnu/bin
m host-lib $R/x86_64-unknown-linux-gnu/lib
m guest-all $R/x86_64-unknown-toyos $R/aarch64-unknown-toyos $R/x86_64-unknown-none $R/x86_64-unknown-uefi $R/aarch64-unknown-none-softfloat $R/aarch64-unknown-uefi
m freestanding-4 $R/x86_64-unknown-none/lib $R/x86_64-unknown-uefi/lib $R/aarch64-unknown-none-softfloat/lib $R/aarch64-unknown-uefi/lib
m userland-libs-2 $R/x86_64-unknown-toyos/lib $R/aarch64-unknown-toyos/lib
m c-sysroots-2 $R/x86_64-unknown-toyos/c $R/aarch64-unknown-toyos/c
m tools-clang-lld-ar $R/x86_64-unknown-linux-gnu/bin/clang $R/x86_64-unknown-linux-gnu/bin/rust-lld $R/x86_64-unknown-linux-gnu/bin/llvm-ar
m tools-other $R/x86_64-unknown-linux-gnu/bin/llc $R/x86_64-unknown-linux-gnu/bin/opt $R/x86_64-unknown-linux-gnu/bin/llvm-as $R/x86_64-unknown-linux-gnu/bin/llvm-cov $R/x86_64-unknown-linux-gnu/bin/llvm-dis $R/x86_64-unknown-linux-gnu/bin/llvm-link $R/x86_64-unknown-linux-gnu/bin/llvm-nm $R/x86_64-unknown-linux-gnu/bin/llvm-objcopy $R/x86_64-unknown-linux-gnu/bin/llvm-objdump $R/x86_64-unknown-linux-gnu/bin/llvm-profdata $R/x86_64-unknown-linux-gnu/bin/llvm-readobj $R/x86_64-unknown-linux-gnu/bin/llvm-size $R/x86_64-unknown-linux-gnu/bin/llvm-strip $R/x86_64-unknown-linux-gnu/bin/rust-objcopy
m clang-resource $R/x86_64-unknown-linux-gnu/lib/clang

measure-asset.out

sysroot-whole raw_KiB=2106772 zstd3_long30_B=512834180 zstd3_B=602893995
hosted-rustc raw_KiB=762980 zstd3_long30_B=148465345 zstd3_B=170164952
compiler-host-part raw_KiB=1317448 zstd3_long30_B=312623378 zstd3_B=387515558
librustc_driver raw_KiB=580552 zstd3_long30_B=135942412 zstd3_B=139191385
rustdoc raw_KiB=58604 zstd3_long30_B=13583076 zstd3_B=13738023
host-bin raw_KiB=514176 zstd3_long30_B=132467478 zstd3_B=190499861
host-lib raw_KiB=164096 zstd3_long30_B=43674208 zstd3_B=44146483
guest-all raw_KiB=789316 zstd3_long30_B=190598059 zstd3_B=215377065
freestanding-4 raw_KiB=427960 zstd3_long30_B=110774962 zstd3_B=119641746
userland-libs-2 raw_KiB=302692 zstd3_long30_B=81443017 zstd3_B=86268681
c-sysroots-2 raw_KiB=58664 zstd3_long30_B=6887882 zstd3_B=9520602
tools-clang-lld-ar raw_KiB=244804 zstd3_long30_B=77123276 zstd3_B=90612643
tools-other raw_KiB=267228 zstd3_long30_B=68648276 zstd3_B=99649817
clang-resource raw_KiB=15032 zstd3_long30_B=1140050 zstd3_B=1188600

carve.sh

#!/bin/sh
# Carve the Linux asset into the layers steps a-c leave, and measure each as
# actions/cache v4.3.0 stores it: tar, then zstdmt at its default level 3.
set -e
S=$1
X=$S/x/x86_64-unknown-linux-gnu/stage2
H=lib/rustlib/x86_64-unknown-linux-gnu
rm -rf $S/carve && mkdir -p $S/carve
m() { name=$1; dir=$2; raw=$(du -sk $dir | awk '{print $1}'); z=$(tar -cf - -C $dir . | zstd -3 -T0 -c | wc -c | tr -d ' '); echo "$name raw_KiB=$raw zstd3_B=$z"; }
# The compiler after a+b+c: rustc, its driver without debuginfo, and in the host's
# rustlib the linker, the C tools and the host std; no rustdoc, no other LLVM tool,
# no guest library, no hosted rustc.
C=$S/carve/compiler
mkdir -p $C/bin $C/lib $C/$H/bin
cp -c $X/bin/rustc $C/bin/
cp -c $S/driver-nodebug.so $C/lib/librustc_driver-37f9a7448f819635.so
for t in rust-lld clang llvm-ar; do cp -c $X/$H/bin/$t $C/$H/bin/; done
cp -a $X/$H/bin/ld.lld $C/$H/bin/
cp -Rc $X/$H/bin/gcc-ld $C/$H/bin/
cp -Rc $X/$H/lib $C/$H/
m compiler-abc $C
# The sysroot after a+c: that compiler, and the guest targets' libraries and C sysroots.
R=$S/carve/sysroot
cp -Rc $C $R
for t in x86_64-unknown-toyos aarch64-unknown-toyos x86_64-unknown-none x86_64-unknown-uefi aarch64-unknown-none-softfloat aarch64-unknown-uefi; do cp -Rc $X/lib/rustlib/$t $R/lib/rustlib/; done
cp $X/SOURCES $R/
m sysroot-ac $R
# The sysroot after a alone (no other LLVM tool), and after a+c's rustdoc but with debuginfo.
A=$S/carve/sysroot-a
cp -Rc $X $A
for t in llc opt llvm-as llvm-cov llvm-dis llvm-link llvm-nm llvm-objcopy llvm-objdump llvm-profdata llvm-readobj llvm-size llvm-strip rust-objcopy; do rm $A/$H/bin/$t; done
m sysroot-a $A
rm $A/bin/rustdoc
m sysroot-a-norustdoc $A

carve.out

compiler-abc raw_KiB=657580 zstd3_B=210009551
sysroot-ac raw_KiB=1446904 zstd3_B=425366106
sysroot-a raw_KiB=1839544 zstd3_B=503356248
sysroot-a-norustdoc raw_KiB=1780940 zstd3_B=489630985

carve2.sh

#!/bin/sh
set -e
S=$1
X=$S/x/x86_64-unknown-linux-gnu/stage2
H=lib/rustlib/x86_64-unknown-linux-gnu
m() { name=$1; dir=$2; raw=$(du -sk $dir | awk '{print $1}'); z=$(tar -cf - -C $dir . | zstd -3 -T0 -c | wc -c | tr -d ' '); echo "$name raw_KiB=$raw zstd3_B=$z"; }
# The compiler after a: its host part (rustc, rustdoc, the driver with debuginfo,
# the host's rustlib) without the LLVM tools nothing invokes.
C=$S/carve/compiler-a
rm -rf $C; mkdir -p $C/bin $C/lib $C/$H/bin
cp -c $X/bin/rustc $X/bin/rustdoc $C/bin/
cp -c $X/lib/librustc_driver-37f9a7448f819635.so $C/lib/
for t in rust-lld clang llvm-ar; do cp -c $X/$H/bin/$t $C/$H/bin/; done
cp -a $X/$H/bin/ld.lld $C/$H/bin/
cp -Rc $X/$H/bin/gcc-ld $C/$H/bin/
cp -Rc $X/$H/lib $C/$H/
m compiler-a-hostpart $C
rm $C/bin/rustdoc
m compiler-a-hostpart-norustdoc $C

carve2.out

compiler-a-hostpart raw_KiB=1050220 zstd3_B=287987378
compiler-a-hostpart-norustdoc raw_KiB=991616 zstd3_B=274241342

slim-llvm.sh

#!/bin/sh
# The dev host's LLVM store as step a keeps it, staged by clone, measured as
# actions/cache stores an entry (tar, zstd -3).
set -e
S=$1; D=$2
L=$S/carve/llvm-slim
rm -rf $L; mkdir -p $L/bin $L/include $L/lib/clang
for t in llvm-config lld llvm-ar; do cp -c $D/bin/$t $L/bin/; done
cp -c $D/bin/clang-22 $L/bin/clang
cp -Rc $D/include/llvm $D/include/llvm-c $L/include/
for f in $($D/bin/llvm-config --link-static --libfiles); do cp -c $f $L/lib/; done
v=$(ls $D/lib/clang); mkdir -p $L/lib/clang/$v; cp -Rc $D/lib/clang/$v/include $L/lib/clang/$v/
cp -Rc $D/src $L/
cp $D/SOURCE $L/
m() { name=$1; shift; raw=$(du -sk "$@" | awk '{s+=$1} END {print s}'); z=$(tar -cf - "$@" | zstd -3 -T0 -c | wc -c | tr -d ' '); echo "$name raw_KiB=$raw zstd3_B=$z"; }
cd $L
m slim-whole .
m slim-bin bin
m slim-include include
m slim-libs $(ls lib/*.a)
m slim-resource lib/clang
m slim-src src
cd $D
m full-whole .

slim-llvm.out

slim-whole raw_KiB=508248 zstd3_B=121952968
slim-bin raw_KiB=181628 zstd3_B=61741179
slim-include raw_KiB=40012 zstd3_B=6585202
slim-libs raw_KiB=130920 zstd3_B=36152132
slim-resource raw_KiB=15032 zstd3_B=1188260
slim-src raw_KiB=140652 zstd3_B=16282256
full-whole raw_KiB=2417516 zstd3_B=741348616

measure-new.sh

#!/bin/sh
# This host's stores as the verification build left them, measured as
# actions/cache v4.3.0 stores an entry: tar, then zstd at level 3.
B=~/dev/toyos/rust/build
m() { name=$1; dir=$2; raw=$(du -sk "$dir" | awk '{print $1}'); z=$(tar -cf - -C "$dir" . | zstd -3 -T0 -c | wc -c | tr -d ' '); echo "$name $dir raw_KiB=$raw zstd3_B=$z"; }
for k in "$@"; do
  case $k in
    llvm=*) m llvm $B/llvm/${k#llvm=} ;;
    compiler=*) m compiler $B/compilers/${k#compiler=} ;;
    freestanding=*) m freestanding $B/freestanding/${k#freestanding=} ;;
    sysroot=*) m sysroot $B/sysroots/${k#sysroot=} ;;
  esac
done

measure-llvm-new.out

llvm ~/dev/toyos/rust/build/llvm/c54c833acd75e98b raw_KiB=513464 zstd3_B=123783951

measure-compiler-new.out

compiler ~/dev/toyos/rust/build/compilers/a4e3d9b05e1747d8 raw_KiB=554128 zstd3_B=164485466

measure-fs-new.out

freestanding ~/dev/toyos/rust/build/freestanding/8d5c8b9068ca7480 raw_KiB=427996 zstd3_B=119575500
sysroot ~/dev/toyos/rust/build/sysroots/3b3ed0fb252fe96d raw_KiB=1343492 zstd3_B=379808173

rustc-libs.txt

libLLVMAArch64AsmParser.a
libLLVMAArch64CodeGen.a
libLLVMAArch64Desc.a
libLLVMAArch64Disassembler.a
libLLVMAArch64Info.a
libLLVMAArch64Utils.a
libLLVMAggressiveInstCombine.a
libLLVMAnalysis.a
libLLVMAsmParser.a
libLLVMAsmPrinter.a
libLLVMBinaryFormat.a
libLLVMBitReader.a
libLLVMBitWriter.a
libLLVMBitstreamReader.a
libLLVMCFGuard.a
libLLVMCGData.a
libLLVMCodeGen.a
libLLVMCodeGenTypes.a
libLLVMCore.a
libLLVMCoroutines.a
libLLVMCoverage.a
libLLVMDebugInfoBTF.a
libLLVMDebugInfoCodeView.a
libLLVMDebugInfoDWARF.a
libLLVMDebugInfoDWARFLowLevel.a
libLLVMDebugInfoGSYM.a
libLLVMDebugInfoMSF.a
libLLVMDebugInfoPDB.a
libLLVMDemangle.a
libLLVMExtensions.a
libLLVMFrontendAtomic.a
libLLVMFrontendDirective.a
libLLVMFrontendHLSL.a
libLLVMFrontendOffloading.a
libLLVMFrontendOpenMP.a
libLLVMGlobalISel.a
libLLVMHipStdPar.a
libLLVMIRPrinter.a
libLLVMIRReader.a
libLLVMInstCombine.a
libLLVMInstrumentation.a
libLLVMLTO.a
libLLVMLinker.a
libLLVMMC.a
libLLVMMCA.a
libLLVMMCDisassembler.a
libLLVMMCParser.a
libLLVMObjCARCOpts.a
libLLVMObject.a
libLLVMObjectYAML.a
libLLVMPasses.a
libLLVMPlugins.a
libLLVMProfileData.a
libLLVMRemarks.a
libLLVMSandboxIR.a
libLLVMScalarOpts.a
libLLVMSelectionDAG.a
libLLVMSupport.a
libLLVMSymbolize.a
libLLVMTarget.a
libLLVMTargetParser.a
libLLVMTextAPI.a
libLLVMTransformUtils.a
libLLVMVectorize.a
libLLVMX86AsmParser.a
libLLVMX86CodeGen.a
libLLVMX86Desc.a
libLLVMX86Disassembler.a
libLLVMX86Info.a
libLLVMX86TargetMCA.a
libLLVMipo.a

Japabu and others added 5 commits October 1, 2026 20:40
…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
@Japabu
Japabu marked this pull request as ready for review October 1, 2026 19:19
@Japabu Japabu changed the title The guest suite is every pull request's guest check, on a toolchain only main publishes and CI installs by its digest The guest suite is every pull request's guest check, on toolchain stores CI caches by the build system's own keys Oct 1, 2026
@Japabu
Japabu marked this pull request as ready for review October 2, 2026 09:15
@Japabu
Japabu marked this pull request as draft October 2, 2026 11:29
@Japabu

Japabu commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

Review, round 5, at 42a823b1f.

Read from the runs. Run 36988764929, pull_request, four attempts, each on merge 22f3ff1 (42a823b1f into 46af79d5d) and runner image ubuntu-24.04 20260927.320.1. The API's job times and the four saved logs agree with the body's table to the second. My logs: /Users/jan/.claude/jobs/2280e09e/tmp/scratchpad/orch/671-review-r5/.

Where the head stands. origin/main is c1c504835. git merge-tree of the two conflicts in Cargo.lock and nowhere else. Main's nightly 36985427800 concluded its build in failure at 11:34:55Z ("crates.io holds no toyos-abi of this tree, so no sdk alias can name it"), with guest and tcg skipped. No finding rests on it.

Net lines (git diff --shortstat origin/main...42a823b1f, merge base 46af79d5d): 42 files, +2715 −960.

  • Production: +1178 −717, net +461 (Rust +960 −591, workflows +208 −124, Cargo.toml +8, .github/qemu-version +2 −2).
  • Tests: +590 −132, net +458.
  • Cargo.lock: +801 −6.
  • Prose: +146 −105, net +41.

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

  • Round 4's, three rows never run — CLOSED. Attempts 2, 3 and 4 are the three rows, and attempt 1 is a fourth. Each [ci] this tree's toolchain: line reads as the body quotes it.
    • Attempt 1: LLVM and compiler hit, freestanding and sysroot missed, both built and saved. 10:53.
    • Attempt 2: four hits, nothing built, nothing saved. 2:38.
    • Attempt 3: sysroot missed, built and saved. 7:13.
    • Attempt 4: LLVM hit, three missed, three built and saved. 41:27.
    • Every guest / suite: its restore hit toolchain-sysroot-c882c693da324ad2 under fail-on-cache-miss: true, then "installed sysroot c882c693da324ad2 as toyos", 21 PASS lines, no FAIL, /dev/kvm opens.
  • B2 — OPEN, at the ruleset. No commit closes it, and it is the one BLOCKER open. gh api repos/ToyOSOrg/ToyOS/rulesets/20589156 at 11:40Z reads check_response_timeout_minutes 180 and one required check, host. Landing this head therefore ejects nothing; the hazard is the edit that names guest / suite.
    • The number is 240. The cold toolchain / build took 2:11:46, 2:09:01 of it --ci bootstrap. At the ×1.33 one runner label has shown, the job is 2:54:21, and 2:58:52 with the slowest measured compiler (0:41:53) in place of this run's. guest / suite follows it, measured between 10:20 and 23:17 and bounded by its own 60 minutes. 178:52 + 60:00 = 238:52.
    • Attempt 4 is a second sample of everything after the LLVM: --ci bootstrap took 38:54, against the cold run's 39:46.
    • Order: raise to 240, land, wait for main's publish.yml toolchain to save four layers, then name guest / suite. Main's scope holds no layer now (the cache list shows toolchain-* under refs/pull/671/merge only), so a check named before that save makes every merge group cold.
    • If the check is not named in the same sitting as the landing, "the guest check gates nothing" is a weakness to file, with that edit as its exit.
  • B6 — CLOSED again, on this merge: jobs 110783115080, 110790307698, 110797630760 and 110815764987, 21 of 21 each under KVM.
  • B1, S1, S2, write grants, curl, ruzstd, keys and RECIPE — CLOSED, unchanged. Every job of all four attempts logs Contents: read; nightly.yml:60-61 is the only contents: write.
  • Round 4's NOTEs and REMOVEs — CLOSED by the diff, the probe and the two filed issues. The probe left nothing, read now: release 401672568 and asset 605224651 answer 404, no draft, no probe tag.

The three things beyond the brief

  • The dispatched nightly, run 36988266186 — stands. It measured what the body claims of it: the parser takes queue: max (toolchain / build in progress at 09:10:40Z). It ran on the branch's own ref and groups, concluded cancelled at 09:12:11Z, saved no cache entry and ran no release. It does not show that a waiting job survives a third arrival; that rests on GitHub's text, and the body's "Unsure" says so.
  • 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 guest-cache issue deleted, the host-cache limit re-summed — stands. No workflow at this head restores or saves a guest- entry, and no file cites the slug at the head or on origin/main. The sums check: 2 × 1,994,138,951 + 918,708,556 = 4,906,986,458; five more sets make 9,500,529,238; the ratio floor is 1.76.
  • The opening of Caches in .claude/agents/reviewer.md:79-81 — stands. Main's sentence, "Each cache has one writer, a nightly.yml job", is false of a layer by design: a pull request that moves one saves it into its own scope or rebuilds it on every push. What the sentence guarded holds without it: an entry is immutable under a key computed from sources, only a run on main saves where another ref restores, and main's two callers share one concurrency group. Every host-cache clause is kept. The edit was not briefed, so it is the orchestrator's to ratify by landing it.

BLOCKER

None new.

NOTE

  • Cargo.toml:173, src/release.rs:90 — the build system's HTTP agent takes rustls-rustcrypto 0.0.2-alpha, a third manifest naming it — origin/main since The self-hosting track carries what the owner decided and what is to be built; the internet clients' TLS stage targets ring, moves the tree off rustls-rustcrypto and owns the T14's HTTPS row #679 records the owner's ruling of 2026-10-02 that it "does not come back", lists the two places that still name it, and exits on "no manifest names rustls-rustcrypto" (issues/design-debt/the-internet-clients-work-unchanged.md:34-45). Merged, this branch makes that list false and moves the exit away. Either release::agent takes ring, which puts cc into the build system's own build against the body's cargo tree -i cc line, or stage 3 names the root manifest beside doom's build script. That choice is the owner's.
  • .github/workflows/nightly.yml:75-82, PR body "Unsure" — guest.yml called with kvm: false has run in no Actions run: the branch's one nightly was cancelled with tcg skipped — the body names release's if: and queue: max as first exercised on main, and not the lane root CLAUDE.md now says the nightly runs.
  • PR body:75, "Landing adds a set to main's scope" — until main's first toolchain job has saved (cold, 2:11:46 measured), every ready pull request's run and every merge group builds all four layers, and each pull request's run saves a 918,708,556 B set into its own scope — a reader of main must not miss it.
  • issues/kernel/the-kernel-loads-no-cpu-microcode.md:53, issues/kernel/toyos-uses-what-modern-hardware-offers-for-speed.md:11 — "the nightly's" EPYC KVM guests — the nightly's one guest lane is TCG at this head, and the branch dropped the same words from two other issues.
  • The next head merges origin/main at c1c504835 or later — 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 moves the rust gitlink and the kernel, so the freestanding and sysroot keys move — its gates and a ci run are that head's, not this one's.

REMOVE

  • PR body:3 — "It answers the round-4 review (…)": review chronology in main's record.
  • PR body:98 — "src/release.rs reads git through sysroot::git_out …": the diff shows it.
  • PR body:99 — "SYSROOT_MANIFESTS holds main's toyos-elf/Cargo.toml …": the diff shows it.
  • PR body:103 — "The nightly's release is skipped off main, above.": a pointer to a paragraph already read.

SEND BACK

Japabu and others added 6 commits October 2, 2026 14:07
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
@Japabu

Japabu commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

Round 6 evidence, at 68dc21ce2. Each patch was checked with git apply --check, applied, built, run and reverted in one script; git status --porcelain printed nothing after the last. Logs: /Users/jan/.claude/jobs/2280e09e/tmp/scratchpad/orch/671-r6/.

1. The release's decision, mutated

cargo test --lib -- --exact release::tests::a_landing_during_the_nightly_puts_nothing_up_and_is_no_failure, unmutated: exit 0.

mutation of sdk_at_tip exit the test's red
m1 the base's logic put back: the tip read first and refused off it, then crates.io 101 a landing before the release read anything: Err("HEAD 0123… is not main's tip \"fedc…\"")
m2 the two reads swapped, nothing else 101 a landing between the release's two reads: Err("crates.io holds no toyos-abi of this tree, main's tip, so no sdk alias can name it")
m3 what is owed refused whatever the tip, as main's nightly 36985427800 ended 101 a landing before the release read anything: Err("crates.io holds no toyos-abi of this tree, so no sdk alias can name it")

m1-the-base-refuses-off-the-tip-then-what-is-owed.patch:

--- 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)),

m2-the-tip-is-read-before-crates-io.patch:

--- 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);

m3-what-is-owed-is-refused-whatever-the-tip.patch:

--- 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

p-agent-read.patch, a throwaway test, run once at 482d4873f, whose src/ and Cargo.lock are this head's: GH_TOKEN=… cargo test --lib -- --ignored --exact --nocapture release::tests::probe_one_read_of_a_release, exit 0.

--- 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";
PROBE 462 ms GET releases/tags/toolchain-linux-x86_64-sdk-0.26.0: id 400958651, tag_name "toolchain-linux-x86_64-sdk-0.26.0", assets 1
PROBE asset "TOOLCHAIN" digest "sha256:68f6a1ac1c1d58a959f9a19959a8849f0491d47e53bdaa8d1a534bb47092db3f" size 355
test release::tests::probe_one_read_of_a_release ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 399 filtered out; finished in 0.46s

The digest is the one gh api repos/ToyOSOrg/ToyOS/releases lists for that release's TOOLCHAIN.

3. cc in the build system's own build

cargo tree -i cc, at 7f2721ac2, before the move to ring, exit 0:

warning: nothing to print.

To find dependencies that require specific target platforms, try to use option `--target all` first, and then narrow your search scope accordingly.

At this head, exit 0:

cc v1.2.56
[build-dependencies]
└── ring v0.17.14
    ├── rustls v0.23.45
    │   └── ureq v3.4.2
    │       └── toyos-build v0.1.0 (/Users/jan/Dev/jan/toyos-guestci)
    └── rustls-webpki v0.103.15
        └── rustls v0.23.45 (*)

4. The keys a runner computes at this head

Round 5's p-ci-keys.patch, unchanged (#671 (comment)), CI_COMPILER=8e57eb89153a182c cargo test --lib -- --ignored --exact sysroot::tests::ci_keys --nocapture, exit 0:

CI-KEYS fork 6c7f996a4fe3f8d8f08d7d2c9c30054946645e4f compiler 8e57eb89153a182c freestanding 11c213f25b8c6d8c sysroot d0548e109d1e0ef8

The fork moved from 3f6050fc8 to 6c7f996a4 in library/std alone, so the compiler's key is the one the last run printed.

@Japabu Japabu changed the title The guest suite is every pull request's guest check, on toolchain stores CI caches by the build system's own keys 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 Oct 2, 2026
@Japabu
Japabu marked this pull request as ready for review October 2, 2026 12:36
@Japabu
Japabu marked this pull request as draft October 2, 2026 13:05
@Japabu

Japabu commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

Review, round 6, at 68dc21ce2.

Read from the run. Run 37007753187, attempt 1, pull_request, on merge 27b4428 (68dc21ce2 into c1c504835), runner image ubuntu-24.04 20260927.320.1. From the API's jobs and the saved log, not from the body. My logs: /Users/jan/.claude/jobs/2280e09e/tmp/scratchpad/orch/671-review-r6/.

job started → completed (UTC) took read
host (110839929948) 12:37:04 → 12:47:23 10:19 restored host-sealed-Linux-X64-36988155706; "Host: 65 step(s), all green"
toolchain / build (110839930089) 12:37:03 → 12:48:03 11:00 [ci] this tree's toolchain: llvm da88e203716ecb6d restored, compiler 8e57eb89153a182c restored, freestanding 11c213f25b8c6d8c built, sysroot d0548e109d1e0ef8 built; two saves, two skipped
guest / suite (110843582245) 12:48:06 → 13:04:37 16:31 restore hit toolchain-sysroot-d0548e109d1e0ef8; /dev/kvm opens; 21 PASS, no FAIL; "21 passed, 21 total (715.0s)"

The development host's logs, read in 671-r6/:

  • --build-only, the guest suite and --ci host at 68dc21ce2: exit 0, 0 and 0; "21 passed, 21 total (29.8s)"; "Host: 64 step(s), all green"; git status --porcelain empty after.
  • m0 exits 0; m1, m2 and m3 exit 101, each on the assertion the body names. m3's refusal is nightly 36985427800's own line.

Net lines (git diff --shortstat origin/main...68dc21ce2, merge base c1c504835): 44 files, +2225 −960.

  • Production: +1206 −728, net +478 (Rust +987 −602, workflows +208 −124, Cargo.toml +9, .github/qemu-version +2 −2).
  • Tests: +619 −124, net +495.
  • Cargo.lock: +252 −1.
  • Prose: +148 −107, net +41.
  • This round's own commits (7f2721ac2..68dc21ce2): production +47 −29, tests +36, Cargo.lock +7 −551, prose +3 −3. Accepted: the release's decision and its test are the ruling's, and the lockfile loses the RustCrypto tree.

Earlier BLOCKERs

  • B2 — OPEN, at the ruleset. No commit closes it, and it is the one BLOCKER open. gh api repos/ToyOSOrg/ToyOS/rulesets/20589156 at 13:27Z reads check_response_timeout_minutes 180 and one required check, host.
    • The body's four steps are the brief's order, and its 238:52 sums as round 5's did.
    • It closes when that read says 240, which the order puts before the landing.
    • Round 5's condition stands: steps 3 and 4 come at least one cold build (2:11:46) after step 2. If that is not one sitting, "the guest check gates nothing" is filed with step 4 as its exit.
  • B6 — CLOSED again, on merge 27b4428: job 110843582245, 21 of 21 under KVM.
  • Round 4's three rows — CLOSED in round 5. Run 37007753187 is the freestanding row again, at this head's keys.
  • B1, S1, S2, write grants, curl, ruzstd, keys and RECIPE — CLOSED, unchanged. git diff 42a823b1f..68dc21ce2 -- .github .claude CLAUDE.md is empty; nightly.yml:60-61 is the only contents: write.
  • Round 5's NOTEs and REMOVEs — CLOSED by the diff and the body. Its fourth named two lines, now fixed; four more of the same words remain (NOTE below).

The three things from outside the last review

  • ring — stands, held to main's record.
    • Cargo.toml:176 names neither provider. The root Cargo.lock holds ring 0.17.14 and no rustls-rustcrypto.
    • git grep at the head finds the alpha only where main's issue says it still is: userland/doom/Cargo.toml:21, userland/doom/build.rs:165, tests/toyos-rust-tests/Cargo.toml:28, and their two lockfiles. Main's list stays true and its exit moves no further away.
    • ureq 3.4.2's rustls feature is rustls-no-provider, _ring and rustls-webpki-roots, read in its manifest; RootCerts defaults to WebPki.
    • The cc arrival is declared in the ledger's Linux cc row, which the macOS row takes by reference, and nowhere else. The README already asks for a C compiler.
    • One sentence of main's issue: NOTE below.
  • The nightly race — the ruling is met, and the residue may land recorded. It is not recorded yet.
    • Met: sdk_at_tip yields on a landing before either read and between the two, and m1, the base's decision put back, reds the test.
    • The residue is not a landing during the nightly: HEAD is the tip, and what is missing is HEAD's own publish.
    • Main has it in the same form: its alias refused what crates.io owed.
    • Its outcome is a refusal by name with nothing put up, and a re-run of that one job recovers it.
    • It takes a publish that outlasts the decision: at least 2:38 of toolchain job plus the release job's checkout, restore and driver build, against 1:04 to 1:54 for main's six green publish runs of 2026-10-02 (run list, read now).
    • Closing it is a wait on the tip's publish, or a release run from the landing's own push: a design the ruling did not ask for.
    • Recorded means issues/. At this head it is under "Unsure" alone: NOTE below.
  • The Caches opening in .claude/agents/reviewer.md — not a finding, by the orchestrator's ratification.

BLOCKER

None new.

NOTE

  • PR body:161-162, src/release.rs:353-368 — two weaknesses of the release's decision are recorded only under "Unsure": a tip whose own crates are not up yet reds the nightly for no defect of the tree, and any landing between a nightly's creation and its release leaves no release and no alias, green — each is removed or filed in issues/ with an owner, evidence and an exit. Evidence the file takes: cron: '0 3 * * *' created its scheduled runs at 09:35:54Z (36843762360) and 09:09:27Z (36988155706), and main took seven landings between 08:39Z and 11:21Z on 2026-10-02; run 36988155706 waited behind a dispatched nightly until 11:45Z, four landings after its HEAD; publish waits up to five minutes a crate for the index (src/ci.rs:919-925); on main a landing that moved no SDK crate did not stop the nightly's release.
  • PR body:73 — "No run has been made on this head … a prediction until the run prints it" is false since run 37007753187 — the body is main's record, and takes that run's three jobs, its key line and its guest line.
  • PR body:51, :159 — the crates.io index read has no measurement in this body: its probe through the agent (26 lines for toyos-abi, nothing for an unpublished name) was at f1ccb0b3e on RustCrypto and has left the body; on ring it has not run, and the agent has run on no Linux host — publish.yml's --ci publish makes that read on every push to main (src/ci.rs:907), so this landing's own push is its first on ring unless the throwaway runs again from the development host. "Unsure" names it either way.
  • .github/workflows/toolchain.yml:55-71, .github/workflows/ci.yml:53-60, PR body:99-104, :160 — the merge queue's path has run in no Actions run: gh run list --event merge_group holds no pr-671 group, so the three github.event_name != 'merge_group' save guards, and guest / suite restoring under fail-on-cache-miss a sysroot only the group's own scope holds, are unmeasured — it is the path step 4 makes every landing wait on, and "First exercised" names the nightly's paths alone. The body names it, and step 4 follows one merge group's guest / suite concluded success.
  • issues/hardware/features-no-proving-machine-is-known-to-offer.md:12, :38, :40, issues/kernel/a-pure-function-decides-a-cpus-speculation-mitigations-as-linux-does.md:16 — "a nightly EPYC KVM guest", "a nightly EPYC guest", "each nightly EPYC guest's" — the nightly's one guest lane is TCG at this head, and the branch dropped the same words from four other issues.
  • issues/design-debt/the-internet-clients-work-unchanged.md:36-37 — "no build compiles it" — at this head every build of the build system compiles ring, for the host. The body's reading, "of the ToyOS target", is one the sentence does not say; the issue says it.

REMOVE

  • PR body:44 — "This branch deleted that step and kept the red: … after that check.": a head that never lands.
  • PR body:45 — ", which is what at_tip was there for": the same head.
  • PR body:52 — "The agent had installed rustls-rustcrypto 0.0.2-alpha, which main's … says does not come back;": the same.
  • PR body:84 — "B6 is closed by it" and "The two kernel issues this branch had filed for them never land.": a review's label, and files that never land.
  • PR body:116 — "Two kernel issues said the EPYC KVM guests were the nightly's; …": the diff shows it.

SEND BACK

Japabu and others added 3 commits October 2, 2026 15:38
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
@Japabu

Japabu commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

Round 7 evidence, at 68dc21ce2, whose tree outside issues/ is 281602b72's. Logs: /Users/jan/.claude/jobs/2280e09e/tmp/scratchpad/orch/671-r7/.

The crates.io index read through the agent on ring, from the development host (macOS, arm64). A throwaway test, checked with git apply --check, applied, built, run and reverted in one script; git status --porcelain --ignore-submodules=none printed nothing after it. It writes nothing: two GETs of index.crates.io.

cargo test --lib -- --ignored --exact --nocapture sdkversion::tests::probe_the_index_read
PROBE 786 ms index(toyos-abi): 28 lines, 10331 bytes, the minor after its newest 0.29.0+
PROBE 725 ms index(toyos-no-such-crate): 0 lines, 0 bytes
test sdkversion::tests::probe_the_index_read ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 399 filtered out; finished in 1.51s
index-read EXIT=0
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";

@Japabu
Japabu marked this pull request as ready for review October 2, 2026 13:43
@Japabu

Japabu commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

Review, round 7, at 281602b72.

Read from the tree and the API, not from the body. git diff 68dc21ce2..281602b72 is five files under issues/, +72 −7; the same diff with ':!issues' is empty. My logs: /Users/jan/.claude/jobs/2280e09e/tmp/scratchpad/orch/671-review-r7/.

Run 37014929723, attempt 1, pull_request, on merge f528c4bb2 (281602b72 into c1c504835), runner image ubuntu-24.04 20260927.320.1. Read at 13:56:48Z, in progress:

job started → completed (UTC) took read
host (110863352409) 13:43:51 → 13:51:48 7:57 restored host-sealed-Linux-X64-36988155706; "Host: 65 step(s), all green"; Contents: read
toolchain / build (110863352757) 13:43:51 → 13:46:06 2:15 four hits; [ci] this tree's toolchain: llvm da88e203716ecb6d restored, compiler 8e57eb89153a182c restored, freestanding 11c213f25b8c6d8c restored, sysroot d0548e109d1e0ef8 restored; Contents: read
guest / suite (110864228036) 13:46:09 → its restore under fail-on-cache-miss succeeded at 13:48:55; cargo run -- --ci guest in progress
  • The four keys are run 37007753187's: no store key moved.

The development host's log, read in 671-r7/: cargo run -- --ci host at 281602b72, exit 0, 13:38:30Z to 13:41:24Z, "Host: 64 step(s), all green", the build system "389 passed; 0 failed; 10 ignored", git status --porcelain --ignore-submodules=none empty after. Every FAILED in it is a model control's.

What this verdict rests on, and what it awaits.

  • Rests on: that host gate at the head; the guest suite at 68dc21ce2, exit 0 on the development host (671-r6/guest.exit, "21 passed, 21 total (29.8s)") and 21 of 21 under KVM in job 110843582245; and the head differing from 68dc21ce2 under issues/ alone. No guest build reads issues/: its readers under src/ are host-gate tests (src/build.rs:2810-2812, src/userlandhost.rs:271).
  • Awaits: job 110864228036. Any conclusion but success is a red at this head and a BLOCKER, and this verdict does not stand over it.

Net lines (git diff --shortstat origin/main...281602b72, merge base c1c504835): 49 files, +2297 −967.

  • Production: +1206 −728, net +478 (Rust +987 −602, workflows +208 −124, Cargo.toml +9, .github/qemu-version +2 −2).
  • Tests: +619 −124, net +495.
  • Cargo.lock: +252 −1.
  • Prose: +220 −114, net +106 (issues/ +208 −109, .claude/agents/reviewer.md +11 −4, CLAUDE.md +1 −1).
  • The per-file sums are the numstat's (Rust +1606 −726 in all); the split of Rust into production and tests is round 6's, and no Rust file has changed since.
  • This round's own commits: prose +72 −7, two files filed and seven lines reworded. Accepted: each is what round 6 named.

Earlier BLOCKERs

  • B2 — CLOSED. gh api repos/ToyOSOrg/ToyOS/rulesets/20589156 at 13:44:27Z reads check_response_timeout_minutes 240 (updated_at 13:32:49Z) and one required check, host.
    • Round 5's condition stands and is the orchestrator's: if guest / suite is not named in the sitting that lands this, "the guest check gates nothing" (PR body:119) is filed in issues/ with step 4 as its exit.
  • B6 — CLOSED at 68dc21ce2 by job 110843582245; this head's job is the one awaited above.
  • Round 4's three rows — CLOSED in round 5. Job 110863352757 is the "moves no layer" row again, at this head: four restored, nothing built, 2:15.
  • B1, S1, S2, write grants, curl, ruzstd, keys and RECIPE — CLOSED, unchanged. git diff 42a823b1f..281602b72 -- .github .claude CLAUDE.md is empty; nightly.yml:61 is the only contents: write; every uses: at the head is one of main's five actions at main's pins, or a local path that resolves.
  • Round 6's NOTEs — CLOSED, each by the diff or the body:
    • The two weaknesses are filed: issues/build/a-nightly-a-landing-overtakes-leaves-no-release-and-no-sdk-alias.md and issues/build/a-release-that-decides-before-its-tips-crates-are-up-reds-the-nightly.md, each with owner, evidence and an exit a request or a test can fail, and each within issues/README.md. Their figures check against the API: seven publish runs created 08:39:27Z to 11:20:48Z on 2026-10-02, the six green ones 1:04 to 1:54 long; ci::publish waits 60 × 5 s (src/ci.rs:919-924).
    • The index read on ring has its measurement: 671-r7/index-read.log, exit 0, 28 lines in 786 ms and none for an unpublished name in 725 ms.
    • The merge queue's path is named unmeasured, and step 4 waits on it. What that wait rests on: NOTE below.
    • "nightly EPYC" is gone from the four lines. One file of the same kind remains: NOTE below.
    • "no build for that target compiles it": only the root, userland and tests/toyos-rust-tests lockfiles name ring, and 671-r7/tree-ring-*.log print nothing for the last two.
    • "No run has been made" was made true of 68dc21ce2's run and is false again of this head's: NOTE below.
  • Round 6's REMOVEs — CLOSED: all five are gone from the body.
  • The Caches opening in .claude/agents/reviewer.md stands as rounds 5 and 6 left it; the file has not changed since 42a823b1f.

The two things the round left out of the tree

BLOCKER

None.

NOTE

  • PR body:75 — "No run has been made on 281602b72" — false since run 37014929723, created 13:43:47Z — the body is main's record, and takes that run's three jobs and its key line once guest / suite has concluded.
  • issues/build/no-nightly-runner-has-had-its-cpuid-and-vulnerability-lines-captured.md:7, :17 — the slug's "nightly runner" and the exit's "a nightly step … on the runner" name the nightly for the KVM runners — at this head no nightly job is given /dev/kvm (nightly.yml:80, kvm: false), and the KVM guests are ci.yml:58's. This branch moved them, and reworded the same words in six other issues. A slug is renamed in the commit that corrects its body, with every citation moved (issues/README.md:78-79); its one citation is toyos-cpuvuln/src/tests.rs:605.
  • PR body:116, :118, :173 — step 4 waits on "one merge group's guest / suite has concluded success", and this pull request's own group is named the path's first run — while the check is not required, a group merges when host concludes (7:57 and 10:19 in this pull request's last two runs), before toolchain / build (2:11:46 cold, body:120; 2:15 to 2:38 warm) and the suite after it can. Whether a merged group's run goes on to a conclusion is in no measurement: on main a merge group runs host alone, so none has had a job outstanding at its merge. If it is cancelled there, no group's guest / suite concludes until the check is required, and step 4 never comes. "Unsure" names it, and says what step 4 rests on in that case.

REMOVE

  • PR body:111 — "B2 and": a review's label.

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
@Japabu
Japabu enabled auto-merge October 2, 2026 14:07
@Japabu
Japabu added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit 8e59c8c Oct 2, 2026
3 checks passed
@Japabu
Japabu deleted the wt/toyos-guestci branch October 2, 2026 14:26
Japabu added a commit that referenced this pull request Oct 2, 2026
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
Japabu added a commit that referenced this pull request Oct 2, 2026
…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
Japabu added a commit that referenced this pull request Oct 2, 2026
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
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