Repository navigation
The metal suite targets a second bench: --metal-host, every machine's record in the host's store, the home read off the machine, and the stick read off the record - #852
Conversation
… under the bench's own account, and the stick read off the machine's record `cargo test --test toyos-build -- --metal --metal-host <user>@<machine>` hands toyos-metal its existing `--host` on every run it drives and in every line of a staged `request.txt`; without it the T14 is the target, as before. The value is checked by the parser toyos-metal uses (`metal::host_of`), so a malformed one is refused before an image is built. A user carrying `/`, and either half opening with `-`, which ssh reads as a flag, are now refused too: the user names the account's home. `--host` changed the account and left the log's mount point under the T14 account's home. The mount is now derived from the user, as the staged sudoers file already was; the `mount` field is gone, so the two cannot disagree. The stick's expected identity moves out of the `STICK` const into the per-machine record `tests/metal/<vendor>-<product>.toml`, as a `[stick]` table. The loop reads the machine's SMBIOS first, loads that machine's record, then checks the disk against the stick it names; a machine with no record is refused with the command that records one. `--install-sudoers`, the step a bench is set up with once, records the machine with the disk the target names as its stick (refusing one that is not removable) before it installs the rule, and on a machine with a record checks the disk against it; it never moves a record. The T14's record carries the values the const held. A record now exists before any run, so `metaltimings::judge` takes one rather than inventing an empty one, and the harness judges readbacks of a machine with no record red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…t the stick it is about to write `recorded_stick`'s record had no caller, and the `removable` helper existed only for the capture, which now checks the disk against the stick it is about to record: only the removable test can refuse there, and it does so before the file is written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
|
Mutations at 10865ce (negative controls): patches, script and logs — part 1 of 1 |
|
Staged metal run with a made-up bench: log, exit and request.txt — part 1 of 1 |
|
cargo run -- --build-only at f01efa9, EXIT=0 — part 1 of 1 |
|
cargo run -- --ci host at 10865ce, EXIT=0 — part 1 of 9 |
|
cargo run -- --ci host at 10865ce, EXIT=0 — part 2 of 9 |
|
cargo run -- --ci host at 10865ce, EXIT=0 — part 3 of 9 |
|
cargo run -- --ci host at 10865ce, EXIT=0 — part 4 of 9 |
|
cargo run -- --ci host at 10865ce, EXIT=0 — part 5 of 9 |
|
cargo run -- --ci host at 10865ce, EXIT=0 — part 6 of 9 |
|
cargo run -- --ci host at 10865ce, EXIT=0 — part 7 of 9 |
|
cargo run -- --ci host at 10865ce, EXIT=0 — part 8 of 9 |
|
cargo run -- --ci host at 10865ce, EXIT=0 — part 9 of 9 |
|
cargo test (guest suite) at 10865ce, EXIT=1: virt_claim_lpi red — part 1 of 2 |
|
cargo test (guest suite) at 10865ce, EXIT=1: virt_claim_lpi red — part 2 of 2 |
|
cargo test (guest suite) at f01efa9, EXIT=1: virt_claim_lpi red — part 1 of 3 |
|
cargo test (guest suite) at f01efa9, EXIT=1: virt_claim_lpi red — part 2 of 3 |
|
cargo test (guest suite) at f01efa9, EXIT=1: virt_claim_lpi red — part 3 of 3 |
|
Review of #852 at 10865ce (round 1) Net lines: 8 files, +406 −110. Production is about +200 −80 ( Gates checked: BLOCKER
NOTE
SEND BACK |
…s which disk it will write, and the home is the machine's own Owner's rulings on review round 1 of #852: - The records move to `metal/` under `keystore::host()`, one root for every machine and no fallback: `metaltimings::dir()` is read by the loop (`toyos-metal`) and by the judge (`judge_readbacks`) alike. The T14's record leaves `tests/metal/`; the orchestrator places it in the host's store. The judge no longer tells anyone to commit a record. - `--install-sudoers` asks nothing and prints the record, the node and the identity of the disk every later run wipes and writes (`Captured::said`). - The account's home is read off the machine (`printf %s "$HOME"`) rather than assumed to be `/home/<user>`: the second bench's is under `/var/home`. The mount point and the staged rule derive from it, and a home that is no normal absolute path is refused. The staged rule's path is now shell-quoted where it reaches the remote shell. - `host_of` no longer refuses a `/` in the user: the user names no path now. - Root CLAUDE.md: every metal bench is the orchestrator's alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
|
Mutations at c126cd9 (negative controls): patches, script and logs — part 1 of 1 |
|
Staged T14 boot at c126cd9, EXIT=2 (Staged) — part 1 of 1 |
|
cargo run -- --ci host at c126cd9, EXIT=0 — part 1 of 9 |
|
cargo run -- --ci host at c126cd9, EXIT=0 — part 2 of 9 |
|
cargo run -- --ci host at c126cd9, EXIT=0 — part 3 of 9 |
|
cargo run -- --ci host at c126cd9, EXIT=0 — part 4 of 9 |
|
cargo run -- --ci host at c126cd9, EXIT=0 — part 5 of 9 |
|
cargo run -- --ci host at c126cd9, EXIT=0 — part 6 of 9 |
|
cargo run -- --ci host at c126cd9, EXIT=0 — part 7 of 9 |
|
AMD bench boot through this PR's loop, at
The loop's machine, disk and sudo lines, masked: The capture, run earlier ( The whole loop and judge log, masked, follows in the next two comments. |
|
AMD bench log, part 1 of 2 (masked): |
|
AMD bench log, part 2 of 2 (masked): |
|
Review of #852 at fb03703 (round 3) Earlier BLOCKERs
Changes since c126cd9:
Net lines: Machine identifiers: none. I checked the body and comments 31–42 (the host log, the summary and both AMD log parts) for:
All of these are masked:
BLOCKERNone. NOTE
LAND AFTER NAMED CHANGES |
…lers, rows that name no hardware, and the DSDT refused for a read in memory-mapped I/O The AMD bench's boot at fb03703 (PR #852, issuecomment-6107030904, its log in -6107031099 and -6107031259) found three things off this branch's fence, each filed with an owner and an exit: - the kernel refuses both of the bench's live HDA controllers by name, so soundserver plays on the null sink and test_rs_hda_client_stall exits 101; - test_rs_pci_reclaim claims the T14's I219 and exits 1 on a bench without it: a metal row declares no hardware, so an unfiltered --metal-host run reds rows the bench cannot run; - acpiserver's DSDT load reads one byte of memory the firmware types EfiMemoryMappedIO, the kernel refuses it MemoryType, and no \_S5 is handed over: the policy for AML in memory-mapped I/O is owed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Main now carries the loader's relocation (#836), stat identity (#851), libc's realpath (#854), the kernel's directory identity (#855) and the second bench (#852). ALL_CONFIGS keeps consentcase and hostedclangcase; the host-tools issue takes main's os-release row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…5-9 as landed and what stage 5 still owes Citations of `src/<file>`, `bootloader/`, `.github/qemu-version` and `cargo run --example imgstat` name `build/`, `loader/`, `build/ci/qemu-version` and `cargo run --bin imgstat`. Left as written, because they record their time: three panic lines quoted verbatim, a measurement "as at 5620b73", and a reference to `src/flash.rs` at 094c154. `issues/the-tree-says-who-uses-each-thing.md`: - Stages 6 to 9 are landed with stage 4, in one pull request. - Stage 5's moves are landed; its exit is not met. `SYSROOT_SOURCES` cannot come from `sdk/` alone, since libc links `toyos-elf` in `lib/elf`, and `PUBLISHED` leaves out `sdk/filepicker`, which the filepicker ruling makes public. The stage names that as remaining, with an exit that can be read. - Stage 8 says what landed: `tests/metal/`, with no `tests/machines/t14/` and no descriptor, since a machine's records are in the host's store since #852. - The tree and its list of differences say where i219, pci-claim, the two `-api` crates, toyos-ssh, the metal loop and `tests/cavp` are, and that there is no `tests/judges/ssh/`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
MAX_CPUS = 8 sizes every per-CPU array and the roster refuses past it; the AMD bench's boot on PR #852 logged "SMP: roster full at 8 CPUs" and brought up 8 of its MADT's 16. No issue named the cap; this records it as a present weakness, held by the orchestrator through the design round in PR #865. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…d track's staged plan The audit read origin/main at 06788fc; every citation was re-read at 177e72a, where no kernel file it cites had moved. Eight findings it marked unfiled become issues: the 64 GiB physical-memory span, PCID held back for INVPCID on the AMD bench, idle by hlt with no MWAIT doorbell, the LAPIC count re-armed every pass, the T14's wake-storm cost against the AMD bench's, the FP save and two locked instructions on every syscall, a wake to a busy CPU no idle CPU can take, and the per-CPU state on shared lines. The 8-CPU cap is PR #865's to file. The speed track gains the AMD bench among its proving machines, the rule that a test machine is where a feature is measured and never what it is designed for, the scouts in flight and next, and the new issues in its order: instruments, then the measured rounds, then the rest. The T14 figures rest on its testcases boot at c126cd9, posted whole on PR #866; the AMD bench's on PR #852's log at fb03703. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
cargo test --test toyos-build -- --metalcan now target a second metal bench. The T14 stays the default. Every machine's record, the T14's included, now lives in the host's store outside every checkout, and nothing identifying a bench is committed.What changed, per decision
One suite flag, forwarded as
toyos-metal's existing--host.--metal-host <user>@<machine>(src/testargs.rs) belongs to--metalonly. It is refused without--metal, and refused beside--list, where it would be dropped in silence. The harness (tests/common/metal.rs,invocation) appends--host <value>to everytoyos-metalrun it drives and to every line of a stagedrequest.txt. Without the flag the words carry no--host, which means the T14. The suite checks the value when it parses its arguments, using the parsertoyos-metalitself uses (metal::host_of, whichArgs::parsenow calls too), so a malformed value is refused before any image is built. The value is a machine identifier: it lives only on the command line and never in the tree.host_ofrefuses a user or machine that starts with-, becausesshreads it as a flag. The old checks still apply:user_wordfor the sudoers user field, andWord::literalfor the machine. Round 1 also refused a/in the user, because the user then named the home. The home is now read off the machine (below), so that check went.The account's home is read off the machine, not assumed (owner's ruling 3). On the AMD bench the account's home was measured as
/var/home/<user>, not/home/<user>.Driver::reachasks the account's login shellprintf %s "$HOME"(Home::QUERY). It does this once per run, after the image is admitted and before the sudo probe, and once per--install-sudoers.Home::parserefuses anything that is not a normal absolute path a rule can name: not absolute,/alone, an empty,.or..component, whitespace, or a quote or glob character.<home>/toyos-log) and the staged rule (<home>/.toyos-metal.sudoers) both derive from that oneHome. TheTargetrenderings (words,sudoers,argv,remote) take it as an argument, so the rule and the argv cannot name different homes.cat >,visudo -c -f,install,rm -f). It is a machine's answer now, not a constant.Every machine's record lives in the host's store (owner's ruling 1).
metaltimings::dir()iskeystore::host().join("metal"), which is$HOME/.cache/toyos/metal/on this Mac. It is the one root, with no fallback. The loop (recorded_stick,record_machine) and the judge (judge_readbacks, called frommetal::runwith&metaltimings::dir()) both read it, and nothing reads a record under a checkout.tests/metal/, and the directory is gone.Machine::path()is nowMachine::file(), the bare file name under that directory.keystore's module header saysmetal/sits beside the keyed kinds.sweep_byreads onlyKeyed::store(…)directories, so no sweep walksmetal/, and nothing else in the tree removes~/.cache/toyos.keystore::host()as the home, so this PR does not reopen that. The record is not reproducible from its inputs the way the store's keyed products are, and deleting it re-baselines that machine.dir()points: it is one line a reader checks. The loop's record tests (src/metal.rs) and the judge's (tests/checks/metal.rs,recorded()) each plant a record in a scratch directory and read it from there.How the T14's record was placed in the host's store (done; the T14 boot at
c126cd9d5read it). The record at10865ce02(this branch's previous head, the parent of the head commit, and inmain's history once this lands) ismain's T14 record at192491965plus the[stick]table:If
main's T14 record gains rows before this lands, takemain's file instead and append the four lines[stick],sectors = 60062500,vendor = "SanDisk"andmodel = "Ultra". Then merge with the file deleted. If the record is missing, the boot is refused before any write (exit 2,Refusal::Unrecorded, naming the path under~/.cache/toyos/metal/).The stick's expected identity is in the per-machine record. It used to be
const STICK. It is now a[stick]table (sectors,vendor,model), a required field ofmetaltimings::Record.rungoes in this order:Machine::QUERY);recorded_stick).A machine with no record is refused with
Refusal::Unrecorded, which names the record's path and the command that writes it. A record that exists but does not read is refused withRefusal::Record. Neither refusal is about a boot, so the loop exits 2.The capture asks nothing and says which disk it will write (owner's ruling 2).
--install-sudoersreads the home, the SMBIOS and the disk the target names (--device, default/dev/sda), then:Both paths print one line (
Captured::said), for example:<dir>/acme-bench-2.toml records this machine now: the stick is /dev/sdb, 120176640 sectors, Kingston DataTraveler, removable; every run on this machine wipes and writes that disk. A host test asserts the whole line for both paths. There is no prompt: the owner ruled that a bench holds nothing of value. The record comes before the rule, so no rule is installed for a disk the record refuses.The AMD bench is recorded and has booted through the loop (both the orchestrator's; no other agent touched either machine). The capture,
toyos-metal --install-sudoers <password file> --host <user>@<amd bench>, wrote that machine's record under~/.cache/toyos/metal/with/dev/sdaas its stick and installed the rule with the mount under the home the machine named. The boot atfb03703a1then ran the whole loop on that firmware. Both outputs, masked, are in issuecomment-6107030904, the whole log in -6107031099 and -6107031259.The issues that cited
tests/metal/cite the record where it now lives (round 2's NOTE). RootCLAUDE.mdrequires the merge that deletes a document to delete its citations. Six issues named the deleted file or directory:a-boot-paint-at-subsystems-ready-stalled-4-ms-on-the-t14,mutual-kill-panicked-on-the-t14-with-stdio-slot-1-not-a-log-ringandthe-host-cannot-reach-the-t14-while-it-runs-toyosnow say "the T14's record";a-metal-run-asks-ubuntu-which-machine-it-is-and-the-boot-says-nothing's exit says every record undermetaltimings::dir();the-tree-says-who-uses-each-thingdropstests/metal/from thetoyos-metalpackage's sources.the-t14s-record-keeps-three-rows-of-a-boot-nothing-stagesgets new evidence, sincegit grepno longer reads the record:grep testcases-windowon the T14's record undermetaltimings::dir()finds the three rows, andgit grep testcases-windowfinds nothing but the issue. Its exit deletes the rows from that record. Each names the record by its kind, never by a machine string.git grep tests/metal/finds nothing.Root
CLAUDE.md(round 1's NOTE): "Every metal bench is the orchestrator's alone: no other agent runs--metalwithout--metal-readback, which touches no machine."metaltimings::judgetakes aRecord, not anOption. The loop boots no machine without a record, so the judge judges readbacks of an unrecorded machine red and writes nothing.Out of scope, per the brief: per-row hardware requirements, the TCO and hard-lockup gaps on AMD, and Wi-Fi.
Can the loop wipe or flash a disk on the dev host?
Structurally it cannot reach a local disk.
src/metal.rsspawns isssh, each withTarget::ssh_argv, whose last two words are<user>@<machine>and the remote command. There are five sites:ssh(),Driver::as_root,Driver::raw_log, and the two instage_and_install.wipefs,dd,efibootmgr,mount,reboot) runs assudo -non the far side of thatssh.--readback(it removes only the fixedREADBACK_FILESnames there), and writes the record under~/.cache/toyos/metal/. It opens no block device.cargo run --bin toyos-metal(tests/common/metal.rs,drive).Not structural: which machine the far side is. The bench is whatever
--hostnames, and nothing in the code tells a bench from the dev host. Ansshdestination that resolves to the dev host itself (localhost, or an alias) is reached like any bench./sys/class/block, so the identity read fails; there is no/usr/bin/efibootmgr;Node's grammar (/dev/sd<letter>,/dev/nvme<n>n<m>) names no macOS disk; andrequire_sudoneeds the installed rule.sshdrunning, a capture given that account's own password would record the host's own removable disk at--deviceas its stick and install the rule. The loop would then write that disk.What stands in the way is the password
--install-sudoersneeds and, now, the line naming the disk. A structural guard, such as refusing a far side whose identity equals the local machine's, is not in this PR.Gates
cargo run -- --ci host92aae8c3dcargo run -- --ci hostfb03703a1cargo run -- --ci host("79 step(s), all green")c126cd9d5blackbox_unclaimed_page(the orchestrator's)fb03703a11 passed, 0 failed, 1 boot(s), 61664-byte log read backblackbox_unclaimed_page(the orchestrator's)c126cd9d51 passed, 0 failed, 1 boot(s), 67069-byte log read backc126cd9d5cargo test --test toyos-build -- --metal --metal-readback <scratch>/t14-stage blackbox_unclaimed_pagec126cd9d5cargo test(whole guest suite)10865ce02virt_claim_lpi, below)cargo run -- --build-onlyf01efa9a6The
FAILEDlines inside the--ci hostlog are the suite's own negative controls (loom and model mutations it expects red); its exit and its last line are the verdict.Guest suite not re-run at
c126cd9d5. The diff from10865ce02tofb03703a1(beyond the merge oforigin/main) touches no guest-built file and nottests/toyos.rs. It changes onlysrc/metal.rs,src/metaltimings.rs,src/keystore.rs,src/testargs.rs, the metal harness and checks,CLAUDE.md, six issues, and the deleted record. At10865ce02the suite was red on one test,virt_claim_lpi; the other 58 passed. That red was seen with the host's load average between 49 and 98. This branch reaches nothing that test builds. Per rootCLAUDE.mdit is not re-run; it is a defect of its own, left to the orchestrator to file.AMD bench, the orchestrator's runs.
--install-sudoers), masked: thesaidline (<path> records this machine now: the stick is /dev/sda, 240328704 sectors, USB SanDisk 3.2Gen1, removable; every run on this machine wipes and writes that disk),installed /etc/sudoers.d/toyos-metal, and thesudo -nprobe — issuecomment-6107030904.cargo test --test toyos-build -- --metal --metal-host <user>@<amd bench> blackbox_unclaimed_pageatfb03703a1: EXIT=0,Boot: complete 1312 ms, a log of 61664 bytes, back in 56 s,PASS blackbox_unclaimed_page,1 passed, 0 failed, 1 boot(s), and the judge's first write to the bench's record,now records 3 number(s). Themachine … BIOSline, thedisk /dev/sda … — the stick <path> namesline and everyrun: sudo -n …line fromwipefsthroughefibootmgr --create-only --disk /dev/sda --part 1,--bootnext,reboot, the mount and the rawddare in issuecomment-6107030904; the whole loop and judge log, masked, in -6107031099 and -6107031259.issues/the-amd-bench-answers-on-two-hda-controllers-and-plays-on-the-null-sink.md(test_rs_hda_client_stallexit 101 on the null sink),issues/a-metal-row-names-no-hardware-and-a-bench-without-it-reds.md(test_rs_pci_reclaimexit 1 for the absent I219, so an unfiltered--metal-hostrun on that bench is red), andissues/acpiserver-refuses-the-amd-benchs-dsdt-for-a-read-in-memory-mapped-io.md(no\_S5handed over).Negative controls
Each mutation is a patch checked with
patch --dry-run, then applied, built and run;git checkout -- src/restores the tree, which the script checks is clean. Patches, script and logs are in the mutation comment. Mutation 1 (1-records-in-checkout) is dropped with the test it turned red. Each remaining mutation exited 101 on an assertion, not on a build error:2-home-uncheckedHome::parseadmits empty,.and..componentsmetal::tests::the_mount_and_the_staged_rule_are_under_the_home_the_machine_named3-staged-in-tmp/tmp4-capture-silentmetal::tests::a_capture_says_the_disk_it_recorded_and_every_run_will_write5-stick-uncheckedrecorded_stickloads the record and checks nothingmetal::tests::the_identity_is_the_recorded_stick_or_it_is_refused6-capture-uncheckedmetal::tests::a_machine_is_recorded_once_and_then_checked_against_its_recordRound 1's mutations 3 and 4 (
--hostnot forwarded,--metal-hostunchecked) guard code this round did not change. Their logs at10865ce02are in this comment.What the host tests cannot see:
Driver::reachtakes itsHomefrom the machine's answer;metal::runhands the judgemetaltimings::dir().Both are one call site, read rather than tested. Only the T14 and AMD boots exercise them.
Independent oracle: the real stick answering. Under
--metal-readbackthe staged T14 boot builds the image and touches no machine. The orchestrator ran itsrequest.txtline atc126cd9d5(comment): the home read, the mount under the home the machine named, and the record read from~/.cache/toyos/metal/admitting the real stick, judge exit 0.Unsure
--install-sudoersreads over ssh before it installs. A T14 reinstall now first checks the stick against the record in the host's store, and refuses if that record is missing or does not match. That is intended, but it is a new way for that action to refuse.Growth
git diff --shortstat origin/main...HEAD: 19 files, +702 −279, of which the three new issues are +126.src/metal.rs+198 −71,src/metaltimings.rs+52 −34,src/testargs.rs+23 −5,src/keystore.rs+2, the harnesstests/common/metal.rs+25 −11,tests/toyos.rs+1 −1,CLAUDE.md+1 −1. Six issues +13 −14. The T14 record leaves the tree: −66.src/metal.rs+145 −21,src/metaltimings.rs+12 −34,src/testargs.rs+24,tests/checks*+77 −19.The production growth is:
Homewith its parse;Capturedwith its line;Unrecorded,Record) andHome's;host_of;--metal-hostchecks.Deleted:
Expect,STICK, themountfield, the duplicated--hostsplit,judge's implicit record,metaltimings::DIR, the committed T14 record, and the test that read it.🤖 Generated with Claude Code
https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C