Skip to content

Every shipping-kernel member rides testcases behind its rows' jobs, and the two debug timing rows ride shared-debug: 23 boots to 20 - #799

Merged
Japabu merged 6 commits into
mainfrom
wt/toyos-oneboot-b3b
Oct 9, 2026
Merged

Japabu merged 6 commits into
mainfrom
wt/toyos-oneboot-b3b

Conversation

@Japabu

@Japabu Japabu commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

Stage 3b of step B of the one-boot plan for the T14's metal rows: merge boots. Stage 1 was #785, stage 2 #789, stage 3a #794. Head 01fd3aedd, which holds main at 558283168 (#797, with #796 under it) by a merge with no conflict: in tests/toyos.rs main's two hunks are the nvme_disk_keeps_log_and_home machine test's row in MACHINE_TESTS and its arm and function after run_machine_test, guest tests both, neither in the METAL table nor near shared_metal; tests/common/qemu.rs moved on main alone, and this branch does not touch it. --metal --list is unchanged by it.

--metal --list before (965e62bb1): 61 registrations and 232 shared members over 23 boots. After: 61 and 232 over 20. shared, ccorpus and testcases-debug are gone; no test is.

The T14 read 2c7e1be1a: 266 passed, 1 failed. The red was this merge's own: see the first decision. This head is staged and owed a reading: see "The T14".

What changed, per decision

  • endowment_denied holds a link against toybox's policy table only where the link's target has a [programs] row. The red at 2c7e1be1a: "/system/bin/134_double_to_signed" is a link to something else: a second multicall binary needs its own policy table, not this one, after every earlier phase passed. The member walks /system/bin and asserted every link lands on /system/bin/toybox; the merged ROOT carries the C corpus, whose 137 cases are links to the comparator test_rs_ccheck, which reads argv[0] so the kernel records each run under the case's name. On shared's own ROOT there were none. The walk was too wide, and the corpus is not a second multicall binary in the sense the claim is about. What a link carries is its target's row: the supervisor's declared follows one link and matches a row by its whole path, and a target no row names is answered NotDeclared, which the caller spawns itself with what it holds; the build's unnamed_program says the same of every harness binary ("a harness binary has none, holding only what its spawner moved in"), and test-runner spawns every job directly in any case. A policy table limits what a row grants; a binary with no row is granted nothing by one. So the walk skips a link whose target the image's manifest names no row for, matched by the whole path as the supervisor matches it (its own parse of the manifest, as before), and a second binary that does have a row behind a link reds as before. The applets line counts the links it passed over. The corpus's shape is unchanged: one comparator under one link per case is what lets a stick say which case failed. Nothing of the endowment policy for C programs is decided here: the corpus's cases hold what test-runner gives every job, as on ccorpus' own boot.
  • shared and ccorpus ride testcases. Its list is the ten jobs its rows name, then the 85 discovered Rust binaries, then the 137 C cases, then the three bounds programs (LAST_MEMBERS), then reboot: 234 jobs, since fault_gates is a row's job and a member and runs once, among the rows'. c_corpus_metal gives the corpus's part of that boot and shared_metal puts the Rust members around it.
  • testcases-debug rides shared-debug. tlb_shootdown_waits and trace_record_cost name that boot, its kernel and its parameters, and their two jobs run before its seven members.
  • A member says what it adds to its list's bound (metal::Member), where a shared boot said one number for all of its members: one boot now carries Rust tests at 300 ms and C cases at 100.
  • A boot's last job ends its rows' jobs, and the members run behind it. This reverses what stage 3a built. acpi_hold gives up 54 000 ms after boot (UNTIL_MS); behind the members it would have started 51.8 to 52.5 s in by the readings before the merge. On the T14 at 2c7e1be1a, before them, it started 43 095 ms into the kernel's clock with 10.9 s left and exited 0. It also keeps the three bounds programs the last jobs of the boot. The compromise under it is filed, not fixed: issues/acpi-hold-gives-up-at-a-time-counted-from-boot-whatever-its-runner-was-given.md, owner the harness, exit the hold bounded from its own start or by the bound its runner was given; it now carries the T14's start too.
  • Two jobs of one boot the kernel records under one name are refused, in batches, for every boot. The C corpus checked its own cases; the merged list puts Rust members, C cases and rows' jobs under one log, so the check is the boot's now and the corpus's own is deleted.
  • The judge prints a shared boot's members' time summed between each member's own markers, against what they add to the bound, and says over how many: its members took <ms> ms of the <ms> ms they add to the list's bound, summed over the <n> of <all> with both markers, and a line <k> without a start and an end marker, the first <job> only where there is one. It is a line a reader reads and reds nothing; no host test holds it. On the T14: 9253 ms of the 40100 ms … summed over the 225 of 225.
  • The record rows of shared, ccorpus and testcases-debug are deleted from the machine's record under tests/metal/. The three testcases-window rows stay: issues/the-t14s-record-keeps-three-rows-of-a-boot-nothing-stages.md owns them and half its exit.
  • The allowance issue's exit is three parts, by the orchestrator's ruling on the round-1 review: (1) each allowance derived from the members' sum between their own markers by one stated factor, the judge redding a boot whose members' sum is past that share; (2) what a boot's rows' jobs are given derived the same way from what they take, the judge redding a boot whose rows' jobs end past their share; (3) testcases reading both inside, the pair from the kernel's own lines, the margin to the list bound beside them. None of it is built and the issue stays open. Its present numbers are now the T14's reading of the merged boot, beside the sum of the three boots it was.

What the merged boots arm

--metal --list and the staging's own lines at 01fd3aedd; the wait is metal::return_secs' arithmetic. The T14 read the same pairs off the kernel's own lines at 2c7e1be1a.

boot jobs --bound-ms= boot-deadline= hard-lockup bound toyos-metal waits
testcases 234 100 100 (main: 60 000) 200 200 (main: 120 000) 100 100 (main: 60 000) 501 s (main: 420)
shared-debug 9 (main: 7) 62 100, unchanged 124 200, unchanged 62 100, unchanged 425 s, unchanged

100 100 is 60 000 for the rows' jobs, 88 members at 300 and 137 at 100. No other boot's list, bound or deadline changes.

The merged list against its bound, as the T14 measured it

testcases at 2c7e1be1a, each part between its own markers, the kernel's clock counted from its Boot: complete (1135ms) line; beside it the sum of the three boots it was, three readings each (testcases at 9e70cd2e3, 473efea22, accbd79dd; shared and ccorpus at eff8b20ee, d6d008e88, 49e12f23b).

part merged, 2c7e1be1a its parts apart its share of the bound
the boot, to its first job 1 191 ms 1 190 to 1 196 ms
the rows' ten jobs 41 924 ms, ending 43 115 ms in 41 913 to 41 983 ms 60 000 ms
the 225 members 9 253 ms 8 735 to 9 298 ms 40 100 ms
the list's last record 52 352 ms 51 838 to 52 477 ms 100 100 ms

Read per part, as issues/a-shared-members-allowance-sets-the-kernels-deadline-at-several-times-the-work.md's exit reads: the members at about 4.3 times their work, the rows' jobs at about 1.4 times theirs (counters_metal alone 32.7 s), the last record 47.7 s inside its bound, read by nothing. No part of that exit is met and none is built: the issue stays open. Behind 42 s of rows' jobs the members took 9 253 ms, inside what they took alone.

The loader at 2c7e1be1a: ROOT read 9 301 ms, loader 13 069 ms, as the measured rate predicted (30.5 ms/MiB to read, 7.1 to hash, a ROOT partition of 305 MiB), under the firmware's 60 s. shared-debug: 176 ms of members over 7 of 7, its last record 1 754 ms of 62 100 ms.

Why each row can share its boot

Rows' jobs run first, so every row's own jobs see the machine testcases gave them at stage 1: the same config, the same prefix, one job at a time. What changes is what stands in the log, the page and the census behind them. By what each judge reads:

rows what the judge reads why 225 programs behind it cannot move it
blackbox_unclaimed_page, control_regs, ioapic_topology, klogd_hosted, smp_roster_and_tsc_trail, pmm_accounting, acpi_table_inventory, timer_calibration, pci_inventory, loader_watchdog_arms' control arm the loader's file and kernel records written before the first job a kernel record is the kernel's (Readback::kernel drops every program's line), and these are said at boot
wake_storm_cost, syscall_cost the job's exit record, and syscall_cost's own two lines the first and fifth jobs of the list; exit_code takes the lowest pid of a name, and a row's job is spawned before any member
audio_idle_suspend, hda_tone, hda_client_stall, shipped_client_departures job_window: the log from the job's spawn to its sessions' end, or to the next spawn each window closes before the hold. Two reads are boot-wide: no null sink, said at soundserver's start, and no repeated completion for free buffer. The second gains no stream: no member opens one on soundserver. cpal_drop_unreleased is its own stream server (its header: "No sound is played and soundserver is not involved"), and in the three shared readbacks soundserver says nothing after its start
counters counters_metal's own lines by their counters_metal <phase>: head; the idle second by stamp; no acpi: legacy mode again in the boot no member prints that head (none in six readings of the member boots); the idle second is inside the job, which ends before the first member starts; legacy mode returns only when the acpi claim's holder goes, and no member holds or kills it (none in six readings)
acpi_server_events, acpi_tables_loaded lines whose tag is acpiserver, and boot records a member's line carries the runner's tag. The last count line is read with rfind: a boot that passes the server's next interval prints a later one, also a count
claim_reuses_its_remapping_entry every hand-over and release of the I219, and every iommu: irte record whose source is it, counted: two and two no member claims a PCI function: pci_reclaim is on RUST_SKIP, and six readings of the member boots carry no handed over on slot
domain_ends_below_the_host_bridges every iommu: domain record of the boot a domain a member's boot made is held to the same windows; judged over the member boots' readbacks below
crash_report_reads_no_kernel_memory three refusals fault_gates stages, and no report line anywhere in the boot that carries a kernel address's contents members fault on purpose, and their reports are now read too: a leak in any of them is the defect. Judged over shared's readback below
irq_census_conservation the stop's census, off the page: every device delivery on cpu0, every shootdown IPI counted by its issuer the census is the whole boot's, members included, and the rule is conservation, not a count. Judged over the member boots' readbacks below
tlb_shootdown_waits (to shared-debug) its exit every wait it asserts is a floor (elapsed >= FLOOR_NANOS), which no load shortens. The eleven self-tests run at init and on the first syscall of the boot (task_probes, once), before any job
trace_record_cost (to shared-debug) its exit and one printed line a million records written by one syscall with interrupts closed; the number is printed and not recorded. On that boot each syscall pays one atomic swap in task_probes; the flood is one syscall

The boot-wide judges, run over the member boots a machine has already answered. The shared and ccorpus readbacks of #794's third reading, relabelled testcases and judged at 3055ab0d1 (--metal --metal-readback <dir> with thirteen row names):

readback exit
shared's 88 members 0 13 passed, irq_census_conservation (5 196 shootdowns, every delivery accounted for), domain_ends_below_the_host_bridges, acpi_tables_loaded and crash_report_reads_no_kernel_memory among them
ccorpus' 137 cases 1 12 passed; crash_report_reads_no_kernel_memory red for its premise, since fault_gates did not run on that boot

And the old readbacks under the new profile (boot:testcases boot:shared-debug over stage 1's testcases and #794's shared-debug): exit 1, every testcases row and every self-test row PASS, 224 members and the two moved rows red as never run, which is what those logs hold. shared-debug reads its members took 176 ms of the 2100 ms they add, the sum taken by hand above.

The numbers each boot measures are the boot's own (boot.testcases.complete_ms, panel_us, panel_max_us): the kernel's time to Boot: complete, before any job, and the panel's census, which painted 10 times on testcases, shared and ccorpus alike. No row riding these two boots records a number of its own.

No row kept a boot for sharing's sake. mkdir_cap and readdir_bound keep theirs until stage 3c.

The members that read machine-wide state

The red was a member reading something the merged ROOT changed. Each other member whose source reads state another program moves, by rg over tests/toyos-rust-tests/src/bin for directory walks, roster reads (SYS_SYSINFO entries), the memory header and the log:

member what it reads why the merged ROOT or population cannot move its verdict
std_fs /system/bin's listing asserts it non-empty and its own binary in it: more entries cannot red it
hierarchy_paths /'s listing against ROOT_ENTRIES / is the mount table, not ROOT's content; the corpus's expect/ and binaries land under /system
toybox_file_tools its scratch directory for .part names; /home for one name each keyed on names it wrote itself ("other tests write there in the same boot")
empty_dir_stat /tmp/empty_dir_stat_empty its own directory
readdir_bound, mkdir_cap /tmp's exact count; the VFS directory cap, left full the reason both ride boots of their own (testcases-readdir, testcases-mkdir), unchanged here
endowment_denied the roster in a 256-entry buffer, its own pid in it; ps's row count above zero members run one at a time, so the live set is the services and one member: ps counted 26 processes at 2c7e1be1a. Past 256 threads it would red "does not contain this process", loud and misnamed; nothing near that
kill_ends_every_wait the roster in 256 entries, one pid's state refuses past 256 by name
process_tree, abuse_thread_name the roster in 1 024 entries, filtered to names they spawned keyed on their own names and pids
audio_idle_suspend soundserver's threads in a 128-entry roster a rows' job: it runs before any member
allocator_stress the memory header: used above zero and below total a sum of the whole machine against itself
abuse_connect_flood the memory header before and after its own 32 connects, the growth under 32 MiB the window holds its own syscalls; ROOT is read into memory by the loader before the kernel starts, not in the window. It is the first member, as on main's shared
shm_release_reclaims, handle_lifetime per-kind object counts their own headers: "per kind, and not the machine's free memory"
inbox_log_post the log, until its own child's exit record keyed on its child's pid
file_mtime its own file on /log its own file

No other member walks a directory it did not make, counts processes or files, or reads a log line count. This is evidence for this list; a member a later landing adds is held to the same question by its own review.

The log

The T14's testcases log at 2c7e1be1a: 8 123 829 bytes, whole (no part missing), where the sum of the boots it was predicted 8 095 744 to 8 130 458. Eight parts at logkeeper's 1 MiB a part; a fresh volume keeps sixteen before retire deletes one of this boot's own continuations; a part that is missing reds the whole boot by name (bootlog::lost_parts, #785), unchanged.

The T14

At 2c7e1be1a (the orchestrator's reading; worktree clean before and after, each image's sha256 checked in the command that flashed it): three boots, each toyos-metal exit 0; judged with --metal --metal-readback <dir> boot:testcases boot:shared-debug: exit 1, 266 passed, 1 failed, test_rs_endowment_denied exit 101 as above. Everything else as the request asked: the armed pairs 200 200 / 100 100 and 124 200 / 62 100 from the kernel's own lines; acpi_hold at the end of the rows' jobs, exit 0; the bounds programs last; no bound fired; each loader pass after the reset DONE; the members' line over 225 of 225. That reading is this change's negative control: the walk as it stood, on a ROOT with the corpus's links, red.

At 01fd3aedd: staged with cargo test --test toyos-build -- --metal --metal-readback <dir> boot:testcases boot:shared-debug, exit 2, which is "staged"; no machine touched. The images of 2c7e1be1a were gone already (the runner deletes each after its boot).

boot sha256 bytes
testcases d99c1440e52def650a5f9600cd75fe4283322db709d40f95fb12f181358003cd 429 916 160
shared-debug 82c1d8aee120d02b9acee3af3245ec2f12d4d33abd81b664c1467cdd5299e43c 136 314 880
testcases-watchdog c296fb0c0b9b37e2617a1b371c442a78598c011436a320510cd5b818783f1ed4 119 537 664

The hashes stand in request.txt as shasum -a 256 lines, and shasum -a 256 -c over them answers OK for the three. The request names round 2's fourteen with this head's expected numbers, then: PASS test_rs_endowment_denied with its line applets: 15 links behind /system/bin/toybox, 14 declared over-grants and no undeclared one; 137 links to a binary no row names and the lines after it; and 267 passed. Sent back by any FAIL or a count other than 267, an applets line with other numbers, a bound or a WEDGED, a missing part, the hold at or past 54 000 ms, another order, or a members' line over fewer than 225.

A mutation boot, optional, staged beside it: m4-a-second-binary-with-a-row-behind-a-link (the patch is in the round-3 comment) adds bin/zz_second_multicall -> /system/bin/symbolize to tests/testcases/system.toml, symbolize having a row. Staged from a never-pushed commit of it on 01fd3aedd with --metal --metal-readback <dir> endowment_denied 134_double_to_signed, exit 2, the tree restored to 01fd3aedd and clean after; one image of 134 217 728 bytes, sha256 b6787c435359a87d68264f014fef286583667a9a73d8e93c8f91752b6db74d71, its config carrying both the C case's link to test_rs_ccheck and the mutation's. Expected: exit 1, test_rs_endowment_denied red naming /system/bin/zz_second_multicall: a second binary with a row behind a link still reds. No machine has run it, and only a machine can: see below.

Where the tree differs from the design's text

Gates, at 01fd3aedd

Logs are kept beside the orchestrator's scratch as r3-*.

command exit
cargo run -- --clippy 0, 24 invocations clean
cargo test --test toyos-checks 0, 39 passed
cargo test -p toyos-build --lib 0
cargo test --test toyos-build -- --metal --list 0, 61 registrations and 232 members over 20 boots
cargo run -- --ci host 0, 78 steps green
cargo run -- --build-only 0
cargo test --test toyos-build -- test_rs_endowment_denied 1, No test matches filter "test_rs_endowment_denied"
cargo test --test toyos-build -- --metal --metal-readback <dir> boot:testcases boot:shared-debug 2, "staged": three images
the same with endowment_denied 134_double_to_signed, under m4 2, "staged": one image

Host load when the gates started: 18.65 / 29.42 / 32.46.

No guest runs endowment_denied, so the T14 is its only oracle. The guest suite's names are MACHINE_TESTS and SCREEN_TESTS; the discovered Rust binaries and the C corpus are shared members, run only by --metal and the interactive --debug, and the filter above is refused for that reason. No QEMU boot carries a ROOT with the corpus's links either: the guest stages C cases as test_c_<case> and no comparator. The rest of the change is reached only through --metal and toyos-checks; guest / suite is a required check and runs at the landing head.

High-risk checks

The harness's batching decides what the kernel's deadline is armed with and which program's exit a verdict is read from; endowment_denied is a security claim about endowments.

  • Negative controls: round 2's three mutations of tests/common/metal.rs, each red (101) in metal_rows_run_before_members_under_a_bound_the_members_widen at tests/checks/metal.rs 479, 480 and 499 (the round-2 comment); metal.rs has not changed since. For endowment_denied: the T14's reading of 2c7e1be1a, the walk before the change on a ROOT with the corpus's links, red; and m4, staged, owed a machine.
  • Independent oracle: the T14, owed at this head. The supervisor's declared and the build's unnamed_program are the rule the narrowed walk follows, read, not run.

The host check, and what it sees that reading cannot

rows_run_before_members_under_a_bound_the_members_widen is changed, not added: the last job's place in a list rows and members share, a bound summed over members of two allowances, and the refusal of two jobs under one recorded name. No guest test is added or cut; endowment_denied's walk is narrowed, its claim kept. No dependency is added. No program is changed.

Size

git diff --shortstat origin/main...01fd3aedd: 9 files, +266 −151. issues/: 4 files, +97 −25, one new. tests/checks/: +29 −18. The harness and the record: +128 −106 as before. endowment_denied.rs: +12 −2.

Unsure of

  • Whether the 266 that passed at 2c7e1be1a pass again: one reading of a boot of its kind.
  • The order read_dir lists /system/bin in. On m4's boot the walk reds on the mutation's link whichever it meets first; that it passes over the C case's link there holds only if it meets that one first. The main boot's 137 is what shows the pass-over.
  • endowment_denied's roster read takes 256 entries and asserts its own pid among them without first refusing a larger roster by name, as kill_ends_every_wait does. Not this change's, and far from reached (26 processes).

🤖 Generated with Claude Code

https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C

…nd the two debug timing rows ride shared-debug: 23 boots to 20

Stage 3b of step B of the one-boot plan for the T14's metal rows.

`shared` and `ccorpus` are no boots of their own: the 85 discovered Rust
binaries, the 137 C cases and the three bounds programs are `testcases`'
members, in that order, behind the ten jobs its rows name. `testcases-debug`
is gone: `tlb_shootdown_waits` and `trace_record_cost` name `shared-debug`,
whose kernel is the one they need, and run before its seven members.

A shared boot's members each say what they add to the list's bound
(`metal::Member`), since one boot now carries Rust tests at 300 ms and C cases
at 100. `testcases` is told `--bound-ms=100100` and armed with
`boot-deadline=200200`; `shared-debug` keeps 62100 and 124200.

A boot's last job ends its rows' jobs and no longer the whole list. Stage 3a
put it behind the members, with no boot that had both. `acpi_hold` gives up
54 s after boot, and by the readings on record the rows' jobs end 43.2 s in
and the members take 8.7 to 9.3 s more: behind them the hold would start with
under two seconds left, and past that time it panics before it reads a line
that has been in the log for twenty seconds. Before them it starts where
stage 1 measured it, and the three bounds programs stay the last jobs of the
boot, which is the only place a machine has run them.

Two jobs of one boot the kernel records under one name are refused in
`batches`, for every boot; the C corpus's own check of its cases is that one
now.

The judge prints a shared boot's members' time summed between each one's own
markers, against what they add to the bound: the time from `Boot: complete`
to the last record now holds the rows' jobs too.

The record rows of `shared`, `ccorpus` and `testcases-debug` are deleted. The
allowance issue carries the merged list summed from the boots it was: 51.8 to
52.5 s of a 100.1 s bound, past half by the rows' jobs.

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

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Mutations at 3055ab0d1

Each a checked patch against 3055ab0d1 (git apply --check), applied, built and run, reported by exit code, reversed, tree clean after. cargo test --test toyos-checks metal_ and cargo test --test toyos-build -- --metal --list.

patch toyos-checks metal_ what went red --metal --list
m1-the-last-job-lands-behind-the-members 101 metal_rows_run_before_members_under_a_bound_the_members_widen: ["tone", "cost", "late", "m1", "c1", "m2", "hold"] 0
m2-every-member-adds-what-the-first-does 101 the same check: bounds (62580, 125160), want (61980, 123960); the list arms testcases with 127 500 and 255 000 ms 0
m3-two-jobs-under-one-recorded-name-are-batched 101 the same check: two jobs the kernel records under one name were batched 0

The list stays green under each: it prints what it batches and judges nothing.

m1-the-last-job-lands-behind-the-members

diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index b3ed98370..58210b26f 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -634,12 +634,6 @@ pub fn batches(
             }
         }
     }
-    for batch in out.values_mut() {
-        if let Some(last) = batch.last {
-            batch.jobs.retain(|job| job != last);
-            batch.jobs.push(last.to_string());
-        }
-    }
     let mut ridden: BTreeSet<&str> = BTreeSet::new();
     for boot in shared {
         if !ridden.insert(&boot.boot) {
@@ -652,6 +646,12 @@ pub fn batches(
         batch.files.extend(boot.files.iter().cloned());
         batch.links.extend(boot.links.iter().cloned());
     }
+    for batch in out.values_mut() {
+        if let Some(last) = batch.last {
+            batch.jobs.retain(|job| job != last);
+            batch.jobs.push(last.to_string());
+        }
+    }
     for (label, batch) in &out {
         let mut recorded: BTreeMap<String, &str> = BTreeMap::new();
         for job in &batch.jobs {

m2-every-member-adds-what-the-first-does

diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index b3ed98370..365a2f7ee 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -123,7 +123,7 @@ pub struct Member {
 impl SharedBoot {
     /// What the members add to their boot's list bound.
     fn members_ms(&self) -> u64 {
-        self.members.iter().map(|member| member.adds_ms).sum()
+        self.members.len() as u64 * self.members.first().map_or(0, |member| member.adds_ms)
     }
 
     /// This boot with the members `named` and none else, or `None` where that

m3-two-jobs-under-one-recorded-name-are-batched

diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index b3ed98370..b7a961915 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -655,7 +655,7 @@ pub fn batches(
     for (label, batch) in &out {
         let mut recorded: BTreeMap<String, &str> = BTreeMap::new();
         for job in &batch.jobs {
-            if let Some(other) = recorded.insert(bootlog::recorded_name(job), job) {
+            if let Some(other) = recorded.insert(job.clone(), job) {
                 return Err(format!(
                     "the boot {label:?} runs {other} and {job}, and the kernel records both as {:?}: one \
                      boot's log cannot tell their verdicts apart",

@Japabu

Japabu commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator Author

Review, round 1, at 3055ab0d1

Read: git log origin/main..3055ab0d1 (one commit), git diff origin/main...3055ab0d1, the six changed files whole, the gate, mutation and judge logs of this round, and the nine readbacks on record (testcases at three heads, shared, ccorpus and shared-debug at three). Nothing was built or booted.

Net lines: 6 files, +177 −131. Harness (tests/common/metal.rs, tests/toyos.rs) +120 −97; the machine's record −9; host checks +29 −18; issues/ +28 −7. The harness grows by 23 lines for Member, the name refusal for every boot and the members' sum; accepted, the corpus's own check is deleted for it.

BLOCKER

  • PR body, "The T14" — no machine has run this head — the change targets hardware and its claim (225 members pass behind 42 s of rows' jobs in one kernel lifetime, under 100 100 / 200 200 ms) has no reading. The relabelled readbacks are no substitute: see "What the reading must show".

NOTE

  • tests/common/metal.rs:1209-1216 — the members' line sums only the members that have both markers (filter_map) and divides by the members that passed — a member cut or killed inside its run, the one that took longest, drops out of the sum in silence, and the line still reads "over the N that ran". The line names how many members it summed. It has run over seven Rust members and fault_gates, never over a C case's markers and never over a boot with rows and members; the first reading is checked against a hand sum of all 225. Untested is acceptable while it is a line a reader reads; the commit that makes it a red brings its host test.
  • tests/toyos-rust-tests/src/bin/acpi_hold.rs:18, tests/toyos.rs:923-930 — UNTIL_MS is "the runner's bound less a tenth" of JOB_BOUND_MS, counted from boot, and this head gives the hold's boot a runner bound of 100 100 ms — the branch found the compromise and ordered the list around it without recording it. File it: owner the harness; evidence the hold starting 43 161 ms in with 10.8 s left (the reading of accbd79dd), and a rows' job that adds 10.8 s redding acpi_server_events with "did not show … within 0ns" over a line 20 s old; exit the hold bounded from its own start, or by the bound its runner was given.
  • issues/a-shared-members-allowance-sets-the-kernels-deadline-at-several-times-the-work.md:106-118 — the exit's second line reads one sum against half of one bound, and the sum hides two opposite errors: members at 4.3 times their work (8.7 to 9.3 s of 40.1 s), rows' jobs at 1.4 times theirs (43.2 s of 60 s). Rewrite it per part, in this branch, with the T14's numbers. Read per part the issue is still not met, and that is the true state: the rows' share is tighter than the whole. A stated margin (47.6 s) is no exit by itself: nothing reads it. Proposed: (1) each allowance derived from the members' sum between their own markers by one stated factor, the judge redding a boot whose members' sum is past that share; (2) what a boot's rows' jobs are given derived the same way from what they take, where today it is one constant for a boot of no job and a boot of ten, one of them 32.7 s, and the judge redding a boot whose rows' jobs end past their share; (3) testcases reading both inside, the pair from the kernel's own lines, the margin to the list bound stated beside them. The 60 s base is on main since A T14 boot whose log is missing parts reds by name, and the two ACPI rows ride testcases again: 26 boots to 25 #785 and is not this branch's defect; (2) is what gives it an exit.
  • Prose, PR body and request item 9 — cpal_drop_unreleased opens no stream on soundserver: the binary is its own stream server (its module header: "No sound is played and soundserver is not involved"), and in the three shared readbacks soundserver says nothing after its start. The "unsure of" entry, the table's hda_client_stall row and item 9 are false of the tree. No member reaches soundserver; the boot-wide repeated completion read gains no stream.
  • Prose, PR body "Unsure of" — the ROOT read is not "about 3 s": the three images on record read at 30.5 ms/MiB (829 ms for 27 MiB, 2 262 for 74, 7 518 for 247) and hash at 7.1. The staged image's ROOT partition is 305 MiB: about 9.3 s of read and 13 s of loader, under the firmware's 60 s.
  • Prose, the allowance issue :62-67, :96-99 — the price table and the late-expiry sentence still give shared and ccorpus as boots --metal --list prints. issues/a-t14-boot-that-outlogs-its-retention-loses-its-middle-and-the-rows-whose-lines-sat-there.md:83 says test_rs_acpi_hold is testcases' last job.

What was asked, and what reading gives

  • The order. Right. last was never "sees everything before it": acpi_hold's header says it holds the boot open for one event, and TESTCASES_HELD says a row's job behind it would wait that out. Members behind it only lengthen the boot it holds. The stronger reason is not the 54 s: with the hold tenth, the rows' part of the list is main's testcases list job for job, the only one a machine has measured. A metal boot's list bound and deadline follow from who rides it, at 300 and 100 ms a member: shared-2 and the three bounds rows ride shared, 25 boots to 23 #794's body left the choice to this stage. m1 holds it; a_boots_last_job_is_behind_every_other holds the rows' side unchanged; LAST_MEMBERS stay last by one chain, which the list prints. Nothing else in the tree assumes the old order.
  • Tests. One function, three assertions at three lines (479, 480, 499), three mutations red at three different ones. Order, the per-member sum and the name refusal are each held. No mutation is owed.
  • Row by row. No row's own job reads past its own end: the ten jobs are spawned first, job_window closes on each session's end, counters_metal's four reads and its idle second are inside the job, and no row on either boot records a number. No row's job names a member's binary, so no child takes a member's lowest pid. Boot-wide absences over the members' text, counted in all nine readbacks: repeated completion 0, legacy mode again 0, handed over on slot 0 outside testcases' own 2, a counters_metal <phase>: head 0, the null sink 0. pmm_accounting is a sum, so the 305 MiB withheld passes it.
  • The relabelled readbacks. Evidence that each boot-wide judge at this head accepts the members' records alone. Not covered: the same judges over rows and members in one census; crash_report's scan over the C cases (it stopped at fault_gates' missing exit before scanning); counters, hda_client_stall, claim_reuses_its_remapping_entry, acpi_server_events and loader_watchdog_arms, which had no job to judge and stand on the counts above; any member's behaviour after 21 000 spawns, four sessions and 7.5 MB of log; the loader and the PMM under a 305 MiB ROOT.
  • The log. 8 parts of 16 on a fresh volume by the sum, 0.27 MiB short of a ninth. retire deletes this boot's own continuations only past sixteen.
  • shared-debug. The eleven self-tests log before any job and their judges take the first line; tlb_shootdown_waits disarms before it exits and asserts floors.
  • The guest suite. Agreed: Member, batches, jobs_ms and shared_metal are reached from the --metal branch of main and from toyos-checks only.

What the reading must show

At the head that lands, each image's sha256 checked in the command that flashes it. The request's nine, and:

  1. acpi_hold starts under 54 000 ms of the kernel's clock and exits 0; its start and what is left of the 54 000 ms are stated (43.2 s and 10.8 s expected).
  2. its members took … over the 225 that ran, equal to a hand sum of the 225 marker pairs; the sum beside the 8 735 to 9 298 ms the members took alone, and any member that takes more behind the rows than it did alone named.
  3. The loader's line: ROOT read near 9.3 s and the loader near 13 s; ROOT: read into memory at present.
  4. No soundserver line after the second session of null_sink_client_exits ends but its suspend.
  5. boot.testcases.panel_us from 10 paints; complete_ms near 1 152 to 1 196.

Sent back by: any FAIL or a count other than 267; a bound or a WEDGED; a missing part; the hold at or past 54 000 ms; a list order other than item 4's; a members' line over fewer than 225. A last record past 50 050 ms sends nothing back: it is predicted, and the issue stays open on it.

Landing

host: cargo run -- --ci host exit 0 with its log at the landing head; this head's is in the body (78 steps, exit 0). guest / suite: green at that head; no guest test is reached, and the check is required. Any commit after 3055ab0d1, an issue file included, moves all three images' bytes, so the notes are fixed first and the T14 is read once, at that head. The BLOCKER is closed by a round 2 over that reading and the delta, not by the reading alone: it is the first boot of its kind.

SEND BACK

Japabu and others added 2 commits October 9, 2026 13:58
…markers; the hold's boot-relative give-up is filed; the allowance issue's exit reads per part

The judge's line for a shared boot's members summed only the members with a
start and an end marker and then said "over the N that ran", N being the
members that passed: one cut inside its run, the longest of them, left the
sum in silence. The line now reads "summed over the N of M with both
markers", and a second line, "K without a start and an end marker, the first
<job>", is printed where K is not zero. The mean is gone with the count it
was divided by. It stays a line a reader reads.

`acpi_hold`'s `UNTIL_MS` is 54 000 ms from boot while its runner is given
100 100 ms: the round-1 review found that this branch ordered the list
around it and recorded nothing. It is filed, owner the harness, not fixed.

The allowance issue's exit read one sum against half of one bound, which hid
two opposite errors: members at about 4.3 times their work, rows' jobs at
about 1.4 times theirs. By the orchestrator's ruling it is three parts now:
the members' share, the rows' jobs' share, and `testcases` reading both
inside. None is built and the issue stays open. Its price table and its
late-expiry sentence named `shared` and `ccorpus`, which are no boots any
more, and the retention issue called the hold `testcases`' last job.

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

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Mutations at 2c7e1be1a (round 2)

Run again because tests/common/metal.rs changed under them. Each is round 1's patch, checked against 2c7e1be1a (git apply --check), applied, built and run, reported by exit code, reversed, tree clean after. The diffs below are git diff with the patch applied at this head. cargo test --test toyos-checks metal_ and cargo test --test toyos-build -- --metal --list.

patch toyos-checks metal_ what went red --metal --list
m1-the-last-job-lands-behind-the-members 101 metal_rows_run_before_members_under_a_bound_the_members_widen at tests/checks/metal.rs:479: ["tone", "cost", "late", "m1", "c1", "m2", "hold"] 0
m2-every-member-adds-what-the-first-does 101 the same check at :480: bounds (62580, 125160), want (61980, 123960) 0
m3-two-jobs-under-one-recorded-name-are-batched 101 the same check at :499: two jobs the kernel records under one name were batched 0

The list stays green under each: it prints what it batches and judges nothing.

m1-the-last-job-lands-behind-the-members

diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7810ecabe..85becb29b 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -634,12 +634,6 @@ pub fn batches(
             }
         }
     }
-    for batch in out.values_mut() {
-        if let Some(last) = batch.last {
-            batch.jobs.retain(|job| job != last);
-            batch.jobs.push(last.to_string());
-        }
-    }
     let mut ridden: BTreeSet<&str> = BTreeSet::new();
     for boot in shared {
         if !ridden.insert(&boot.boot) {
@@ -652,6 +646,12 @@ pub fn batches(
         batch.files.extend(boot.files.iter().cloned());
         batch.links.extend(boot.links.iter().cloned());
     }
+    for batch in out.values_mut() {
+        if let Some(last) = batch.last {
+            batch.jobs.retain(|job| job != last);
+            batch.jobs.push(last.to_string());
+        }
+    }
     for (label, batch) in &out {
         let mut recorded: BTreeMap<String, &str> = BTreeMap::new();
         for job in &batch.jobs {

m2-every-member-adds-what-the-first-does

diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7810ecabe..57c152833 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -123,7 +123,7 @@ pub struct Member {
 impl SharedBoot {
     /// What the members add to their boot's list bound.
     fn members_ms(&self) -> u64 {
-        self.members.iter().map(|member| member.adds_ms).sum()
+        self.members.len() as u64 * self.members.first().map_or(0, |member| member.adds_ms)
     }
 
     /// This boot with the members `named` and none else, or `None` where that

m3-two-jobs-under-one-recorded-name-are-batched

diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7810ecabe..109ac6100 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -655,7 +655,7 @@ pub fn batches(
     for (label, batch) in &out {
         let mut recorded: BTreeMap<String, &str> = BTreeMap::new();
         for job in &batch.jobs {
-            if let Some(other) = recorded.insert(bootlog::recorded_name(job), job) {
+            if let Some(other) = recorded.insert(job.clone(), job) {
                 return Err(format!(
                     "the boot {label:?} runs {other} and {job}, and the kernel records both as {:?}: one \
                      boot's log cannot tell their verdicts apart",

@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Answer to the round-1 review, at 2c7e1be1a

2c7e1be1a holds main at 1621281ae (#793), merged with no conflict: main's one hunk in tests/toyos.rs is boot_netcase's second wait, far from this branch's; tests/common/metal.rs and tests/common/qemu.rs did not move on main. #797 is not on main.

BLOCKER

  • The T14 reading: open, and the orchestrator's. Three boots are staged at 2c7e1be1a (exit 2, "staged"), the three of 3055ab0d1 deleted unrun. Each image's sha256 stands in request.txt as a shasum -a 256 line, and shasum -a 256 -c over the file answers OK for the three. The request carries your items 10 to 14 and your send-back list.

NOTE

  1. The members' line (tests/common/metal.rs). It names how many it summed, out of how many: its members took <ms> ms of the <ms> ms they add to the list's bound, summed over the <n> of <all> with both markers. A member not in the sum, one with a start marker and no end marker included, is counted on a second line printed only where there is one: <k> without a start and an end marker, the first <job>. The mean went with the count it was divided by, the members that passed. Read once over a real log: A metal boot's list bound and deadline follow from who rides it, at 300 and 100 ms a member: shared-2 and the three bounds rows ride shared, 25 boots to 23 #794's third shared readback relabelled testcases with the one ===TEST_END test_rs_allocator_stress line removed gives 6667 ms … summed over the 87 of 225 with both markers and 138 without a start and an end marker, the first test_rs_allocator_stress (the 137 C cases that boot never ran, and the one cut); shared-debug untouched gives 176 ms … the 7 of 7. It stays a line a reader reads, with no host test. The second line does not tell a member cut inside its run from one that never started: both lack the pair, and the first named is the earliest in the list.
  2. The hold's give-up: filed as issues/acpi-hold-gives-up-at-a-time-counted-from-boot-whatever-its-runner-was-given.md, kind: tooling, owner the harness, with your evidence (43 161 ms in with 10.8 s left at accbd79dd; a rows' job adding 10.8 s reds acpi_server_events with within 0ns over a line 20 s old) and your exit. Not fixed here, by the orchestrator's decision.
  3. The allowance issue's exit: rewritten as three parts, by the orchestrator's ruling, as you proposed them. The present numbers stand per part in the issue: members at about 4.3 times their work (8 735 to 9 298 ms of 40 100), rows' jobs at about 1.4 times theirs (ending 43 103 to 43 173 ms into 60 000), the margin of 47.6 s read by nothing. None of (1) or (2) is built; the issue stays open.
  4. cpal_drop_unreleased: corrected in the body's "unsure of" (entry removed), in the table's hda_client_stall row, and in the request's item 9: no member opens a stream on soundserver, and the boot-wide read gains none.
  5. The ROOT read: the body gives the measured rate, 30.5 ms/MiB to read and 7.1 to hash, so about 9.3 s of read and 13 s of loader for a ROOT of 305 MiB, and says it is an estimate from that rate; item 12 reads it off the kernel's line.
  6. The issues' prose: the price table has testcases (100.1 s, 200.2 s, 501 s) where it had ccorpus and shared; the late-expiry sentence reads 333 059 ms on testcases, the machine held 80.2 s longer; the retention issue says the hold is the last of the rows' jobs with the members behind it, and cites the new issue for its give-up.

Gates at 2c7e1be1a

cargo run -- --clippy 0; cargo test --test toyos-checks 0 (39 passed); cargo test -p toyos-build --lib 0; --metal --list 0 (61 and 232 over 20 boots); cargo run -- --ci host 0 (78 steps); cargo run -- --build-only 0; the staging 2. The three mutations again, each 101 at the same three lines, tree clean after: the comment above. The guest suite was not run: nothing a guest test reaches changed.

@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

The T14 at 2c7e1be1a: one member red (the orchestrator's reading; worktree clean before and after, each image's sha256 checked against the request in the command that flashed it). Three boots, each toyos-metal exit 0; judged with --metal --metal-readback <dir> boot:testcases boot:shared-debug: exit 1, 266 passed, 1 failed, 3 boots.

The red: FAIL test_rs_endowment_denied, exit 101 on the merged testcases boot. Its own lines: every earlier phase passes (names, keep_all, capability, power, roster, ps: 26 processes with the bit), then

panicked at src/bin/endowment_denied.rs:543:9:
assertion `left == right` failed: "/system/bin/134_double_to_signed" is a link to something else: a second multicall binary needs its own policy table, not this one

So the member walks /system/bin, and on the merged ROOT it meets the C corpus's cases, which are links to a binary that is not the one its policy table is for. On shared's own ROOT there were none. A failure made by the merge itself, which no relabelled readback could show.

Everything else as the request asked:

boot armed, the kernel's own lines members between their own markers the list's last record
testcases 200200 ms / 100100 ms 9253 ms of 40100 ms, summed over 225 of 225 52352 ms of 100100 ms
shared-debug 124200 ms / 62100 ms 176 ms of 2100 ms, 7 of 7 1754 ms of 62100 ms
  • acpi_hold ran at the end of the rows' jobs and exited 0; the three bounds programs are the boot's last jobs.
  • The loader: ROOT read 9301 ms, loader 13069 ms, as predicted from the measured rate (about 9.3 s and 13 s).
  • The testcases kernel log is 8,123,829 bytes and whole (no row refused for a missing part); no bound fired on any of the three; each loader pass after the reset reads DONE.
  • The members took 9253 ms behind the rows' jobs against 8735 to 9298 ms alone.

Not landable at this head: a red row is a defect. A round follows for the member.

Japabu and others added 2 commits October 9, 2026 14:39
…target has a row

The T14 read the merged testcases boot at 2c7e1be red on this member:
"/system/bin/134_double_to_signed" is a link to something else. The C
corpus's cases ride that boot now, each a link to the comparator
test_rs_ccheck, and the walk asserted every link in /system/bin lands on
toybox.

What a link carries is its target's row: the supervisor's `declared`
follows one link and matches a row by its whole path, and a target no row
names is answered undeclared, which the caller spawns itself with what it
holds (the build's `unnamed_program` says the same of every harness
binary). A link to test_rs_ccheck therefore buys no authority a policy
table could limit, and a second multicall binary that does carry a row
still reds the assertion. The walk now skips a link whose target the
manifest names no row for, matched by the whole path as the supervisor
matches it, and the line counts those links.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…Me (#797), into the one-boot merge

No conflict. In tests/toyos.rs main's two hunks are the
`nvme_disk_keeps_log_and_home` machine test's row in MACHINE_TESTS and its
arm and function after `run_machine_test`, both guest tests and neither in
the METAL table or near `shared_metal`. tests/common/qemu.rs moved on main
only; this branch does not touch it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…, and the hold issue its start there

At 2c7e1be: the first job 1 191 ms after the kernel's zero, the rows'
ten jobs 41 924 ms, ending 43 115 ms in, the 225 members 9 253 ms of the
40 100 ms they add, the last record 52 352 ms of 100 100. acpi_hold started
43 095 ms in, 10.9 s before its give-up. Stamps from that boot's
kernel.log, the zero being the `Boot: complete (1135ms)` line's stamp less
1 135 ms.

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

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Round 3, at 01fd3aedd: the T14's red, and its fix

The red. On the merged testcases boot at 2c7e1be1a, test_rs_endowment_denied passed every phase up to its last and then exited 101: "/system/bin/134_double_to_signed" is a link to something else: a second multicall binary needs its own policy table, not this one. Its last phase walks /system/bin and asserted every link lands on /system/bin/toybox, whose one manifest row it holds against a per-applet policy table. The merge put the C corpus on that ROOT, and each of its 137 cases is a link to the comparator test_rs_ccheck, which reads argv[0] so the kernel records each run under the case's name. shared's own ROOT had no such link.

The fix (02b1322bc): the walk holds a link against the table only where the link's target has a [programs] row in the image's manifest, matched by its whole path; the others are counted on the applets line and passed over. A second binary with a row behind a link still reds the same assertion.

Why this is the owner's fix, and not the corpus's shape. The test's claim is about authority a row grants: "a row's granularity is the binary", so every applet behind one binary holds that row's union. A link carries its target's row only where there is one: the supervisor's declared follows one link and matches a row by its whole path, a target no row names is answered NotDeclared, and the caller spawns it itself with what it holds. The build's unnamed_program states the same of every harness binary: "a harness binary has none, holding only what its spawner moved in". test-runner spawns every job directly in any case. A link to test_rs_ccheck therefore buys nothing a policy table could limit; a link to a binary with a row does, and that is still red. The corpus keeps one comparator under one link per case, which is what lets a stick say which case failed. The endowment policy for C programs is not touched: the cases hold what test-runner gives every job, as on ccorpus' own boot.

What reaches it. No guest: the shared members run only under --metal (cargo test --test toyos-build -- test_rs_endowment_denied exits 1, No test matches filter), and no QEMU ROOT carries the corpus's links. The T14 is its only oracle. The reading of 2c7e1be1a is the negative control (the walk before the change, red on a ROOT with those links). Staged and owed: the three boots at 01fd3aedd, and one optional mutation boot:

m4-a-second-binary-with-a-row-behind-a-link

Checked against 01fd3aedd (git apply --check exit 0), applied, committed (never pushed), staged with --metal --metal-readback <dir> endowment_denied 134_double_to_signed (exit 2, "staged", one image, sha256 b6787c435359a87d68264f014fef286583667a9a73d8e93c8f91752b6db74d71), then git reset --hard 01fd3aedd, tree clean after. Its config carries bin/134_double_to_signed -> /system/bin/test_rs_ccheck and the mutation's link. Expected on the machine: exit 1, test_rs_endowment_denied red naming /system/bin/zz_second_multicall. Not run: a machine is the only place it runs.

diff --git a/tests/testcases/system.toml b/tests/testcases/system.toml
index ae1061bf4..69a975b54 100644
--- a/tests/testcases/system.toml
+++ b/tests/testcases/system.toml
@@ -79,6 +79,8 @@ receives = ["soundserver"]
 # `toyos-rust-tests` drains the same sink perfectly, so a suite that ran only
 # that one certified a path no user takes.
 "bin/tone" = "/system/bin/toybox"
+# m4: a second binary with a row, reached through a link.
+"bin/zz_second_multicall" = "/system/bin/symbolize"
 
 # The block service: the NVMe controller this machine's DATA is on, driven
 # from userland through its claim. Started again when it ends; the claim goes

The other members. Every member whose source reads state another program moves (a directory walk, the roster, the memory header, the log) is listed in the body's "The members that read machine-wide state" with why the merged ROOT and population cannot move it. None does but readdir_bound and mkdir_cap, which ride boots of their own for that reason.

Also this round: main merged at 558283168 (#796, #797), no conflict, its tests/toyos.rs hunks a guest machine test's and nowhere near the metal table, tests/common/qemu.rs main's alone. The allowance issue reads the T14's numbers for the merged boot; the hold issue its start there (43 095 ms, 10.9 s left).

Gates at 01fd3aedd: clippy 0 (24 clean); toyos-checks 0 (39); toyos-build --lib 0; --metal --list 0 (61 and 232 over 20 boots); --ci host 0 (78 steps); --build-only 0; the staging 2.

@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Review, round 2, at 01fd3aedd

Read from git objects only: git diff 3055ab0d1 01fd3aedd less the two merges of main (22fd38a32, f6cc20477), the fix 02b1322bc whole, endowment_denied.rs whole at this head, the supervisor's declared, resolve and its NotDeclared arm (userland/supervisor/src/main.rs:1530-1725), the build's unnamed_program and build_root (src/build.rs:720-856), the issues' diff, the body, the three comments since round 1, both staged requests, the m4 image's derived config, and the gates' summary and head file (r3-gates.summary, r3-gates.head = 01fd3aedd). The per-gate r3-*.log files and both staging directories were gone from the orchestrator's scratch before I could read them. Nothing was built or booted.

Net lines: git diff --shortstat origin/main...01fd3aedd 9 files, +266 −151. No production code. Harness and record +128 −106; host checks +29 −18; endowment_denied.rs +12 −2; issues/ +97 −25, one new file. The fix's 10 net lines are accepted: the walk's rule plus a count the reading checks.

Round 1's BLOCKER

  • The T14 reading at the landing head: OPEN. 2c7e1be1a was read: 266 passed, 1 failed. That makes it the negative control for the walk as it stood. 01fd3aedd is staged but nobody has read it yet. No reading is on the pull request and the readback directory has none. See "What the reading must show".

The fix of the red (02b1322bc)

  1. No over-grant: true. declared (main.rs:1678) answers a row only where the launch path itself is a row's whole path, or where its one link lands on a row's whole path. A link to /system/bin/test_rs_ccheck matches neither, so resolve gives NotDeclared. That arm (:1565) sends MSG_NOT_DECLARED with the session's HOME and nothing else, and std then spawns the program with what the caller holds. Launched through such a link, a program holds exactly what its spawner moves in. That equals launching test_rs_ccheck directly, and the test header's first paragraph already says the same of every harness binary.

  2. A row-less multicall binary is safe by construction, not by luck. unnamed_program (src/build.rs:829) inventories every bin/ name in the image, link targets included (:744-750). It refuses any name that is neither a [programs] row nor bin/test_rs_* / bin/test_c_*, and refuses even those where nothing in [boot] start could spawn them. So a link in /system/bin that lands on a row-less binary lands on a harness binary or on supervisor. Either way that binary holds only what its spawner gives it, and no single row's union exists to limit. The sentence "a second multicall binary needs its own policy table" is about a row's union, so it does depend on the row.

  3. The criterion is the supervisor's rule, not a path exemption. Rows are keyed by the whole path from the test's own parse of the rendered manifest (manifest_rows), the same equality declared's program.path == p makes. No name or path is special-cased. Over-skipping would show:

    • All of toybox's links share one target. Skipping that target empties applets and reds at the is_empty assert, or rows.get(MULTICALL) panics.
    • Any other over-skip changes the 137 / 15 the reading checks exactly.

    The walk mirrors only declared's second half: a link standing at a row's own path is matched first by the supervisor. The build cannot make that case, because a row's binary is written at that same bin/<name>. So nothing is owed.

  4. m4 has not been read. Its patch is right for its purpose: the derived config carries [programs.symbolize] and bin/zz_second_multicall -> /system/bin/symbolize beside bin/134_double_to_signed -> /system/bin/test_rs_ccheck. A reader can see from the five changed lines that a rowed target other than toybox still reaches the unchanged assert_eq!, so I owe no mutation here and m4 stays optional. If it is read, the result binds: anything other than exit 1 with FAIL test_rs_endowment_denied naming /system/bin/zz_second_multicall is a BLOCKER.

The claim is kept. The 137 links were never applets of any row, and every link that buys a row is still held to toybox or reds.

BLOCKER

  • PR body, "The T14": no reading at 01fd3aedd. The change's claim (267 pass, the walk passes over 137 links and holds 15) can only be read on the machine.

NOTE

  • PR body, "The members that read machine-wide state": the table is not quite complete.

    • The endowment_denied row lists only the roster, and leaves out the /system/bin walk that went red.
    • hierarchy_paths also asserts /media lists nothing (hierarchy_paths.rs:94-99), which is not a directory it made. It stays empty because /media is a mount point, not ROOT's content.

    Prose only. A sample (std_fs, hierarchy_paths, shm_release_reclaims, query_modules_size, soundserver_log_stall, ccheck) found no other member that reads state the merged ROOT moves, and no verdict changes.

Round 1's NOTEs are closed as answered:

  • The members' line (tests/common/metal.rs:1208-1224) names the summed and the first unpaired member.
  • The hold's compromise is filed with an owner, evidence and an exit.
  • The allowance issue's exit is three parts with the T14's numbers.
  • The prose on cpal_drop_unreleased, the ROOT read and the price table is corrected.

What the reading must show

At 01fd3aedd, each image's sha256 checked in the command that flashes it (d99c1440… testcases, 82c1d8ae… shared-debug, c296fb0c… testcases-watchdog), the request's sixteen items as written. In particular:

  • 267 passed, 0 failed.
  • PASS test_rs_endowment_denied, with applets: 15 links behind /system/bin/toybox, 14 declared over-grants and no undeclared one; 137 links to a binary no row names, followed by its four ended the caller lines.
  • The supervisor's build line naming 01fd3aedd.
  • The members' line over 225 of 225, with no unpaired line.
  • acpi_hold starting under 54 000 ms.
  • No bound fired and no part missing.

Sent back by anything in the request's send-back list.

Landing

  • host: cargo run -- --ci host exit 0 at the landing head, with its log. This head's exit 0 stands in r3-gates.summary. On GitHub both checks read skipping while the PR is a draft, so it has to be marked ready, and a skip is not a pass.

  • guest / suite: green at the landing head. No guest test is reached, but the check is required.

  • Landing without another review round: the orchestrator may land on reading host, guest / suite and the T14 reading, with no round 3, if:

    • the landing head is 01fd3aedd;
    • every one of the sixteen items reads as the request states;
    • m4, if booted, reds as stated.

    The first boot of this kind has already been read (2c7e1be1a), and the delta since is the 12-line walk, whose exact output item 15 states. Any other result, or any commit after 01fd3aedd (a merge of main included, since it moves every image's bytes), goes to a round 3 over a new reading.

SEND BACK

@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

The T14 at 01fd3aedd (the orchestrator's reading). The images staged by the fix round were lost with the orchestrator's scratch directory before they ran, so they were staged again at this head (--metal --metal-readback <dir> boot:testcases boot:shared-debug, exit 2, staged) and booted: worktree clean before and after, each image's sha256 checked in the command that flashed it, each toyos-metal exit 0. Judged: exit 0, 267 passed, 0 failed, 3 boots.

  • The supervisor's build line names 01fd3aedd…, clean.
  • PASS test_rs_endowment_denied: applets: 15 links behind /system/bin/toybox, 14 declared over-grants and no undeclared one; 137 links to a binary no row names, then its ended the caller lines.
  • testcases: its members took 9325 ms of the 40100 ms they add to the list's bound, summed over the 225 of 225 with both markers; its last record came 52414 ms into a list bound of 100100 ms.
  • shared-debug: members 167 ms of 2100 ms, 7 of 7; last record 1745 ms of 62100 ms.
  • acpi_hold began at 65.6 s of the log's stamps, which start before the kernel (the previous reading put the same start at about 43 s of the kernel's clock); its rows passed.
  • No list ran past its bound on any of the three boots; each loader's next pass reads DONE; no row refused for a missing part.

The optional m4 boot was not run (its image was lost with the directory); round 2 judged it optional. Marked ready; it lands on host and guest / suite at this head.

@Japabu
Japabu marked this pull request as ready for review October 9, 2026 13:10
@Japabu

Japabu commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

CI at 01fd3aedd, read from each job's own log (the orchestrator). host: [ci] Host: 79 step(s), all green. guest / suite: test result: ok. 38 passed, 38 total, [ci] Guest: 5 step(s), all green, no FAIL line. With the T14 reading at this head above (267 passed, 0 failed). git merge-tree against main at 558283168 exits 0 with no conflict.

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