Repository navigation
A number the T14 measured is recorded off its owner's verdict alone: one red row or member no longer drops what its boot measured, and a boot whose clocks disagree fails its rows' numbers - #789
Conversation
Stage 2 of step B of the one-boot plan for the T14's metal rows. `judge_readbacks` put boot labels in `failed`, and `Readback::measured` recorded a number with no test attached, so one red row or shared member riding a boot kept every number that boot measured out of the machine's record. With most of the profile about to ride one boot, one red would have kept the whole boot's numbers out. Now each number has an owner. What `judge_readbacks` reads off every boot (`boot.<label>.*`) is the boot's and stands or falls with the boot's own checks. What a row's judge measured is the row's and stands or falls with that judge: after each judge returns, the numbers its readbacks gained are taken (`Readback::taken`) and entered under its verdict (`own`). A failing shared member reds the run and moves no number. The `failed` set is gone; the two-boots check is `own`'s, and now also refuses two rows that measure one name on one boot. A row's number is not moved by its boot's own checks either: a row the harness prints PASS is a row whose measurement it took. Closes issues/a-metal-failure-drops-every-row-its-boot-measured.md: its exit, "each number is recorded against its owner, and only that owner fails", is `a_number_fails_with_its_owner_alone` and `a_failing_shared_member_fails_itself_alone` in tests/checks/metal.rs. Nothing else in the tree cited it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Round 1 mutations at
m0-whole-change-reverted.patchdiff --git a/src/metaltimings.rs b/src/metaltimings.rs
index e22a7cf53..de930057a 100644
--- a/src/metaltimings.rs
+++ b/src/metaltimings.rs
@@ -4,9 +4,9 @@
//! One file per machine under [`DIR`], named for its SMBIOS vendor and product,
//! written by a run and committed by whoever ran it. A run on a machine with no
//! record is recorded and not judged; a name the record lacks is added and not
-//! judged, and only where its owner passed, the boot or the row that measured
-//! it; a recorded value is never moved by a run, so a slow run cannot become
-//! the baseline the next is judged by. A run under a BIOS other than the record's is judged against it,
+//! judged, and only off a boot with no failure of its own; a recorded value is
+//! never moved by a run, so a slow run cannot become the baseline the next is
+//! judged by. A run under a BIOS other than the record's is judged against it,
//! fails naming both, and records nothing. Deleting a row is how a number is
//! re-recorded, and deleting the file is how a machine is, firmware and all.
//!
@@ -136,8 +136,8 @@ enum Unread {
Refused(String),
}
-/// One number a run measured, and whether its owner passed: every reading is
-/// judged, and only a passing owner's becomes a record.
+/// One number a run measured, and whether the boot that measured it passed:
+/// every reading is judged, and only a passing boot's becomes a record.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Reading {
pub value: u64,
@@ -386,9 +386,9 @@ mod tests {
);
}
- /// **A failed owner's numbers are judged and never become a baseline.**
+ /// **A failed boot's numbers are judged and never become a baseline.**
#[test]
- fn a_failing_owners_reading_is_judged_and_not_recorded() {
+ fn a_failing_boots_reading_is_judged_and_not_recorded() {
let machine = t14(BIOS);
let record = recorded(&machine, &[("boot.a.complete_ms", 1000)]);
let failed = |value| Reading { value, passed: false };
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7a382de67..21190c3bc 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -235,8 +235,7 @@ pub struct Readback {
pub stick_secs: u64,
/// The machine the loop read before the flash.
pub machine: Result<Machine, String>,
- /// What was measured on this boot and no owner has taken yet
- /// ([`Self::taken`]).
+ /// What this boot's judges measured, for the machine's record to judge.
numbers: RefCell<BTreeMap<String, u64>>,
}
@@ -463,11 +462,9 @@ impl Readback {
})
}
- /// One number measured on this boot. It is its measurer's, the row whose
- /// judge called this or the boot itself for what [`judge_readbacks`] reads
- /// off every boot, and is judged against this machine's record once every
- /// judge has spoken. A second value under one name is refused: which of
- /// the two a record kept would be nobody's reading.
+ /// One number this boot measured, judged by [`run`] against this machine's
+ /// record once every judge has spoken. A second value under one name is
+ /// refused: which of the two a record kept would be nobody's reading.
pub fn measured(&self, name: &str, value: u64) -> Result<(), String> {
match self.numbers.borrow_mut().entry(name.to_string()) {
Entry::Vacant(slot) => {
@@ -482,11 +479,6 @@ impl Readback {
}
}
- /// What was measured on this boot since this was last asked.
- fn taken(&self) -> BTreeMap<String, u64> {
- std::mem::take(&mut self.numbers.borrow_mut())
- }
-
/// The job ran and the kernel recorded it exiting cleanly.
pub fn job_passed(&self, binary: &str) -> Result<(), String> {
match self.exit_code(binary)? {
@@ -1013,41 +1005,10 @@ pub fn run(
}
}
-/// What `backs` measured since they were last asked becomes one owner's: judged
-/// against the record whatever the owner's verdict, and a new row of it only
-/// where the owner `passed`. A name a second owner measures is judged on the
-/// first reading and recorded off neither; answers whether one was.
-fn own(
- measured: &mut BTreeMap<String, Reading>,
- owner: &str,
- passed: bool,
- backs: &[&Readback],
-) -> bool {
- let mut twice = false;
- for (name, value) in backs.iter().flat_map(|back| back.taken()) {
- match measured.entry(name) {
- Entry::Vacant(slot) => {
- slot.insert(Reading { value, passed });
- }
- Entry::Occupied(mut first) => {
- eprintln!(" FAIL {} is measured twice, and {owner} is the second", first.key());
- first.get_mut().passed = false;
- twice = true;
- }
- }
- }
- twice
-}
-
/// Every verdict a run's readbacks carry, and this machine's record judged by
-/// them: one function of the readbacks, whether the loop wrote them a moment
-/// ago or a run long past did. Answers whether anything was red.
-///
-/// **A number is its owner's, and fails with its owner alone.** What a boot
-/// reads off itself is the boot's, and stands or falls with the boot's own
-/// checks; what a row's judge measured is the row's, and stands or falls with
-/// that judge. Neither is moved by another row or a shared member riding the
-/// same boot.
+/// them and added to off the boots that passed: one function of the readbacks,
+/// whether the loop wrote them a moment ago or a run long past did. Answers
+/// whether anything was red.
pub fn judge_readbacks(
root: &Path,
readbacks: &BTreeMap<String, Result<Readback, String>>,
@@ -1055,13 +1016,15 @@ pub fn judge_readbacks(
shared: &[SharedBoot],
) -> bool {
let mut red = false;
- let mut measured: BTreeMap<String, Reading> = BTreeMap::new();
+ // **A boot with any failure of its own adds no row**, whether the loop,
+ // the boot's own checks, or a test or member riding it failed.
+ let mut failed: BTreeSet<&str> = BTreeSet::new();
eprintln!("\n[metal] the boots");
for (label, back) in readbacks {
let back = match back {
Err(why) => {
eprintln!(" FAIL {label}: {why}");
- red = true;
+ failed.insert(label);
continue;
}
Ok(back) => back,
@@ -1109,9 +1072,9 @@ pub fn judge_readbacks(
for why in &findings {
eprintln!(" FAIL {why}");
}
- let whole = findings.is_empty();
- let twice = own(&mut measured, &format!("the boot {label}"), whole, &[back]);
- red |= twice || !whole;
+ if !findings.is_empty() {
+ failed.insert(label);
+ }
}
eprintln!("\n[metal] the tests");
@@ -1130,15 +1093,16 @@ pub fn judge_readbacks(
Some(why) => Err(why),
None => judge(&owed),
};
- match &verdict {
+ match verdict {
Ok(()) => {
eprintln!(" PASS {name}");
passed += 1;
}
- Err(why) => eprintln!(" FAIL {name}: {why}"),
+ Err(why) => {
+ eprintln!(" FAIL {name}: {why}");
+ failed.extend(arms.iter().map(|arm| arm.boot));
+ }
}
- let twice = own(&mut measured, name, verdict.is_ok(), &owed);
- red |= twice || verdict.is_err();
}
let mut members = 0usize;
for boot in shared {
@@ -1160,7 +1124,7 @@ pub fn judge_readbacks(
// bury the four that matter.
Err(why) => {
eprintln!(" FAIL {job}: {}", why.lines().next().unwrap_or(&why));
- red = true;
+ failed.insert(&boot.boot);
}
}
}
@@ -1171,8 +1135,27 @@ pub fn judge_readbacks(
}
}
}
+ red |= !failed.is_empty();
eprintln!("\n[metal] the timings");
+ let mut measured: BTreeMap<String, Reading> = BTreeMap::new();
+ for (label, back) in readbacks {
+ let Ok(back) = back else { continue };
+ let passed = !failed.contains(label.as_str());
+ for (name, &value) in back.numbers.borrow().iter() {
+ match measured.entry(name.clone()) {
+ Entry::Vacant(slot) => {
+ slot.insert(Reading { value, passed });
+ }
+ // Judged on the first, and recorded off neither.
+ Entry::Occupied(mut first) => {
+ eprintln!(" FAIL {name} is measured by two boots, and {label} is the second");
+ first.get_mut().passed = false;
+ red = true;
+ }
+ }
+ }
+ }
let machine = one_machine(readbacks);
let record =
machine.as_ref().map_err(Clone::clone).and_then(|machine| Record::load(root, machine));
@@ -1195,7 +1178,7 @@ pub fn judge_readbacks(
);
}
eprintln!(
- " {} number(s) on {} {}, BIOS {}; {} past its record, {} whose owner failed",
+ " {} number(s) on {} {}, BIOS {}; {} past its record, {} off a boot that failed",
measured.len(),
machine.vendor,
machine.product,m1-a-red-rows-number-is-recorded.patchdiff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7a382de67..a4353407f 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1137,7 +1137,7 @@ pub fn judge_readbacks(
}
Err(why) => eprintln!(" FAIL {name}: {why}"),
}
- let twice = own(&mut measured, name, verdict.is_ok(), &owed);
+ let twice = own(&mut measured, name, true, &owed);
red |= twice || verdict.is_err();
}
let mut members = 0usize;m2-a-red-boots-number-is-recorded.patchdiff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7a382de67..2c19b75f0 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1110,7 +1110,7 @@ pub fn judge_readbacks(
eprintln!(" FAIL {why}");
}
let whole = findings.is_empty();
- let twice = own(&mut measured, &format!("the boot {label}"), whole, &[back]);
+ let twice = own(&mut measured, &format!("the boot {label}"), true, &[back]);
red |= twice || !whole;
}
m3-a-red-boot-fails-its-rows-numbers.patchdiff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7a382de67..6af2b5162 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1056,6 +1056,7 @@ pub fn judge_readbacks(
) -> bool {
let mut red = false;
let mut measured: BTreeMap<String, Reading> = BTreeMap::new();
+ let mut unwhole: BTreeSet<&str> = BTreeSet::new();
eprintln!("\n[metal] the boots");
for (label, back) in readbacks {
let back = match back {
@@ -1110,6 +1111,9 @@ pub fn judge_readbacks(
eprintln!(" FAIL {why}");
}
let whole = findings.is_empty();
+ if !whole {
+ unwhole.insert(label);
+ }
let twice = own(&mut measured, &format!("the boot {label}"), whole, &[back]);
red |= twice || !whole;
}
@@ -1137,7 +1141,8 @@ pub fn judge_readbacks(
}
Err(why) => eprintln!(" FAIL {name}: {why}"),
}
- let twice = own(&mut measured, name, verdict.is_ok(), &owed);
+ let on_whole = arms.iter().all(|arm| !unwhole.contains(arm.boot));
+ let twice = own(&mut measured, name, verdict.is_ok() && on_whole, &owed);
red |= twice || verdict.is_err();
}
let mut members = 0usize;m4-a-red-member-is-not-red.patchdiff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7a382de67..13e1ca3d2 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1160,7 +1160,6 @@ pub fn judge_readbacks(
// bury the four that matter.
Err(why) => {
eprintln!(" FAIL {job}: {}", why.lines().next().unwrap_or(&why));
- red = true;
}
}
}m5-a-name-measured-twice-is-recorded.patchdiff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7a382de67..c3cb5b837 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1029,9 +1029,8 @@ fn own(
Entry::Vacant(slot) => {
slot.insert(Reading { value, passed });
}
- Entry::Occupied(mut first) => {
+ Entry::Occupied(first) => {
eprintln!(" FAIL {} is measured twice, and {owner} is the second", first.key());
- first.get_mut().passed = false;
twice = true;
}
}m6-a-name-measured-twice-is-not-red.patchdiff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7a382de67..112b1c6af 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1023,7 +1023,7 @@ fn own(
passed: bool,
backs: &[&Readback],
) -> bool {
- let mut twice = false;
+ let twice = false;
for (name, value) in backs.iter().flat_map(|back| back.taken()) {
match measured.entry(name) {
Entry::Vacant(slot) => {
@@ -1032,7 +1032,6 @@ fn own(
Entry::Occupied(mut first) => {
eprintln!(" FAIL {} is measured twice, and {owner} is the second", first.key());
first.get_mut().passed = false;
- twice = true;
}
}
}m7-taken-takes-nothing.patchdiff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7a382de67..15d778629 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -484,7 +484,7 @@ impl Readback {
/// What was measured on this boot since this was last asked.
fn taken(&self) -> BTreeMap<String, u64> {
- std::mem::take(&mut self.numbers.borrow_mut())
+ self.numbers.borrow().clone()
}
/// The job ran and the kernel recorded it exiting cleanly.m8-a-red-row-is-not-red.patchdiff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 7a382de67..e9aea23cb 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1138,7 +1138,7 @@ pub fn judge_readbacks(
Err(why) => eprintln!(" FAIL {name}: {why}"),
}
let twice = own(&mut measured, name, verdict.is_ok(), &owed);
- red |= twice || verdict.is_err();
+ red |= twice;
}
let mut members = 0usize;
for boot in shared { |
|
Review, round 1, of Net lines, BLOCKER
NOTE
What the brief asked to be saidPer kind of boot-level red, may a passing row's number stand, and where the head draws the line. The head draws one line: no finding of the boot's own touches a row's number; only a refused readback does, by judging no row.
Verdicts unchanged. With the clock stamps and build times stripped, Mutations. All nine logs end exit 101 at the checks the table names, none a build error. Claims with no mutation: the second BLOCKER's. A boot's own red reddening the run with no rider is held by The issue. Deleted; its exit is met for a red row and a red member, and exceeded for a boot's own red as the first BLOCKER says. Its rule is the doc comment of Machinery. Evidence. Landing. The pull request is a draft, so SEND BACK |
…owner of a name is no PASS Round 1 of #789's review. A row's number is recorded where its judge passed and every boot it rode has one clock. Every number a row measures is a difference of the clock `one_clock` compares, a disagreement may be another rate, and the record never moves a recorded value, so a scaled duration would have stood as the baseline. No other finding of a boot's own touches a row's number: each is read off one line that is present. The check plants a boot whose supervisor line precedes the spawn it reports, with a passing row on it. A row that is the second to measure a name is no longer printed PASS nor counted as passed: `own` runs before the verdict is printed. `metal_name_two_owners_measured_is_refused` gains the arm where the first of the two owners fails: the name is still recorded off neither. Filed, not fixed: the licence step re-locks the std workspace against the registry on every run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Round 2, answering the round-1 review. Head BLOCKERs
NOTEs
Mutations at
|
| patch | exit | checks red |
|---|---|---|
m0-whole-change-reverted |
101 | metal_number_fails_with_its_owner_alone, metal_failing_shared_member_fails_itself_alone, metal_name_two_owners_measured_is_refused |
m1-a-red-rows-number-is-recorded |
101 | metal_number_fails_with_its_owner_alone |
m2-a-red-boots-number-is-recorded |
101 | metal_number_fails_with_its_owner_alone, metal_cleared_page_owes_no_panel |
m3-a-late-deadline-fails-its-rows-numbers |
101 | metal_number_fails_with_its_owner_alone |
m4-a-red-member-is-not-red |
101 | metal_failing_shared_member_fails_itself_alone |
m5-a-name-measured-twice-is-recorded |
101 | metal_name_two_owners_measured_is_refused |
m6-a-name-measured-twice-is-not-red |
101 | metal_name_two_owners_measured_is_refused |
m7-taken-takes-nothing |
101 | metal_name_two_owners_measured_is_refused, metal_reading_past_its_record_fails_and_moves_nothing, metal_run_under_another_bios_fails_and_records_nothing, metal_number_fails_with_its_owner_alone |
m8-a-red-row-is-not-red |
101 | metal_number_fails_with_its_owner_alone |
m9-a-row-number-stands-on-a-boot-whose-clocks-disagree |
101 | metal_number_fails_with_its_owner_alone |
m10-a-failing-owners-reading-is-not-entered |
101 | metal_name_two_owners_measured_is_refused |
m0-whole-change-reverted.patch
diff --git a/src/metaltimings.rs b/src/metaltimings.rs
index e22a7cf53..de930057a 100644
--- a/src/metaltimings.rs
+++ b/src/metaltimings.rs
@@ -4,9 +4,9 @@
//! One file per machine under [`DIR`], named for its SMBIOS vendor and product,
//! written by a run and committed by whoever ran it. A run on a machine with no
//! record is recorded and not judged; a name the record lacks is added and not
-//! judged, and only where its owner passed, the boot or the row that measured
-//! it; a recorded value is never moved by a run, so a slow run cannot become
-//! the baseline the next is judged by. A run under a BIOS other than the record's is judged against it,
+//! judged, and only off a boot with no failure of its own; a recorded value is
+//! never moved by a run, so a slow run cannot become the baseline the next is
+//! judged by. A run under a BIOS other than the record's is judged against it,
//! fails naming both, and records nothing. Deleting a row is how a number is
//! re-recorded, and deleting the file is how a machine is, firmware and all.
//!
@@ -136,8 +136,8 @@ enum Unread {
Refused(String),
}
-/// One number a run measured, and whether its owner passed: every reading is
-/// judged, and only a passing owner's becomes a record.
+/// One number a run measured, and whether the boot that measured it passed:
+/// every reading is judged, and only a passing boot's becomes a record.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Reading {
pub value: u64,
@@ -386,9 +386,9 @@ mod tests {
);
}
- /// **A failed owner's numbers are judged and never become a baseline.**
+ /// **A failed boot's numbers are judged and never become a baseline.**
#[test]
- fn a_failing_owners_reading_is_judged_and_not_recorded() {
+ fn a_failing_boots_reading_is_judged_and_not_recorded() {
let machine = t14(BIOS);
let record = recorded(&machine, &[("boot.a.complete_ms", 1000)]);
let failed = |value| Reading { value, passed: false };
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..21190c3bc 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -235,8 +235,7 @@ pub struct Readback {
pub stick_secs: u64,
/// The machine the loop read before the flash.
pub machine: Result<Machine, String>,
- /// What was measured on this boot and no owner has taken yet
- /// ([`Self::taken`]).
+ /// What this boot's judges measured, for the machine's record to judge.
numbers: RefCell<BTreeMap<String, u64>>,
}
@@ -463,11 +462,9 @@ impl Readback {
})
}
- /// One number measured on this boot. It is its measurer's, the row whose
- /// judge called this or the boot itself for what [`judge_readbacks`] reads
- /// off every boot, and is judged against this machine's record once every
- /// judge has spoken. A second value under one name is refused: which of
- /// the two a record kept would be nobody's reading.
+ /// One number this boot measured, judged by [`run`] against this machine's
+ /// record once every judge has spoken. A second value under one name is
+ /// refused: which of the two a record kept would be nobody's reading.
pub fn measured(&self, name: &str, value: u64) -> Result<(), String> {
match self.numbers.borrow_mut().entry(name.to_string()) {
Entry::Vacant(slot) => {
@@ -482,11 +479,6 @@ impl Readback {
}
}
- /// What was measured on this boot since this was last asked.
- fn taken(&self) -> BTreeMap<String, u64> {
- std::mem::take(&mut self.numbers.borrow_mut())
- }
-
/// The job ran and the kernel recorded it exiting cleanly.
pub fn job_passed(&self, binary: &str) -> Result<(), String> {
match self.exit_code(binary)? {
@@ -1013,42 +1005,10 @@ pub fn run(
}
}
-/// What `backs` measured since they were last asked becomes one owner's: judged
-/// against the record whatever the owner's verdict, and a new row of it only
-/// where the owner `passed`. A name a second owner measures is judged on the
-/// first reading and recorded off neither; answers whether one was.
-fn own(
- measured: &mut BTreeMap<String, Reading>,
- owner: &str,
- passed: bool,
- backs: &[&Readback],
-) -> bool {
- let mut twice = false;
- for (name, value) in backs.iter().flat_map(|back| back.taken()) {
- match measured.entry(name) {
- Entry::Vacant(slot) => {
- slot.insert(Reading { value, passed });
- }
- Entry::Occupied(mut first) => {
- eprintln!(" FAIL {} is measured twice, and {owner} is the second", first.key());
- first.get_mut().passed = false;
- twice = true;
- }
- }
- }
- twice
-}
-
/// Every verdict a run's readbacks carry, and this machine's record judged by
-/// them: one function of the readbacks, whether the loop wrote them a moment
-/// ago or a run long past did. Answers whether anything was red.
-///
-/// **A number is its owner's, and fails with its owner alone.** What a boot
-/// reads off itself is the boot's, and stands or falls with the boot's own
-/// checks; what a row's judge measured is the row's, and stands or falls with
-/// that judge, and with the clocks of every boot it rode agreeing
-/// ([`Readback::one_clock`]). Neither is moved by another row or a shared
-/// member riding the same boot.
+/// them and added to off the boots that passed: one function of the readbacks,
+/// whether the loop wrote them a moment ago or a run long past did. Answers
+/// whether anything was red.
pub fn judge_readbacks(
root: &Path,
readbacks: &BTreeMap<String, Result<Readback, String>>,
@@ -1056,13 +1016,15 @@ pub fn judge_readbacks(
shared: &[SharedBoot],
) -> bool {
let mut red = false;
- let mut measured: BTreeMap<String, Reading> = BTreeMap::new();
+ // **A boot with any failure of its own adds no row**, whether the loop,
+ // the boot's own checks, or a test or member riding it failed.
+ let mut failed: BTreeSet<&str> = BTreeSet::new();
eprintln!("\n[metal] the boots");
for (label, back) in readbacks {
let back = match back {
Err(why) => {
eprintln!(" FAIL {label}: {why}");
- red = true;
+ failed.insert(label);
continue;
}
Ok(back) => back,
@@ -1110,9 +1072,9 @@ pub fn judge_readbacks(
for why in &findings {
eprintln!(" FAIL {why}");
}
- let whole = findings.is_empty();
- let twice = own(&mut measured, &format!("the boot {label}"), whole, &[back]);
- red |= twice || !whole;
+ if !findings.is_empty() {
+ failed.insert(label);
+ }
}
eprintln!("\n[metal] the tests");
@@ -1131,22 +1093,16 @@ pub fn judge_readbacks(
Some(why) => Err(why),
None => judge(&owed),
};
- // A clock at another rate scales every duration a row measures. No
- // other finding of a boot's own touches a row's number while each is
- // read off one line that is present: one summed or maximised over the
- // log would fall with a log that is not whole too.
- let clocked = owed.iter().all(|back| back.one_clock().is_ok());
- let twice = own(&mut measured, name, verdict.is_ok() && clocked, &owed);
- match &verdict {
- // `own` said so, by name.
- Ok(()) if twice => {}
+ match verdict {
Ok(()) => {
eprintln!(" PASS {name}");
passed += 1;
}
- Err(why) => eprintln!(" FAIL {name}: {why}"),
+ Err(why) => {
+ eprintln!(" FAIL {name}: {why}");
+ failed.extend(arms.iter().map(|arm| arm.boot));
+ }
}
- red |= twice || verdict.is_err();
}
let mut members = 0usize;
for boot in shared {
@@ -1168,7 +1124,7 @@ pub fn judge_readbacks(
// bury the four that matter.
Err(why) => {
eprintln!(" FAIL {job}: {}", why.lines().next().unwrap_or(&why));
- red = true;
+ failed.insert(&boot.boot);
}
}
}
@@ -1179,8 +1135,27 @@ pub fn judge_readbacks(
}
}
}
+ red |= !failed.is_empty();
eprintln!("\n[metal] the timings");
+ let mut measured: BTreeMap<String, Reading> = BTreeMap::new();
+ for (label, back) in readbacks {
+ let Ok(back) = back else { continue };
+ let passed = !failed.contains(label.as_str());
+ for (name, &value) in back.numbers.borrow().iter() {
+ match measured.entry(name.clone()) {
+ Entry::Vacant(slot) => {
+ slot.insert(Reading { value, passed });
+ }
+ // Judged on the first, and recorded off neither.
+ Entry::Occupied(mut first) => {
+ eprintln!(" FAIL {name} is measured by two boots, and {label} is the second");
+ first.get_mut().passed = false;
+ red = true;
+ }
+ }
+ }
+ }
let machine = one_machine(readbacks);
let record =
machine.as_ref().map_err(Clone::clone).and_then(|machine| Record::load(root, machine));
@@ -1203,7 +1178,7 @@ pub fn judge_readbacks(
);
}
eprintln!(
- " {} number(s) on {} {}, BIOS {}; {} past its record, {} whose owner failed",
+ " {} number(s) on {} {}, BIOS {}; {} past its record, {} off a boot that failed",
measured.len(),
machine.vendor,
machine.product,m1-a-red-rows-number-is-recorded.patch
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..43bf08b70 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1136,7 +1136,7 @@ pub fn judge_readbacks(
// read off one line that is present: one summed or maximised over the
// log would fall with a log that is not whole too.
let clocked = owed.iter().all(|back| back.one_clock().is_ok());
- let twice = own(&mut measured, name, verdict.is_ok() && clocked, &owed);
+ let twice = own(&mut measured, name, clocked, &owed);
match &verdict {
// `own` said so, by name.
Ok(()) if twice => {}m2-a-red-boots-number-is-recorded.patch
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..6a1be59c5 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1111,7 +1111,7 @@ pub fn judge_readbacks(
eprintln!(" FAIL {why}");
}
let whole = findings.is_empty();
- let twice = own(&mut measured, &format!("the boot {label}"), whole, &[back]);
+ let twice = own(&mut measured, &format!("the boot {label}"), true, &[back]);
red |= twice || !whole;
}
m3-a-late-deadline-fails-its-rows-numbers.patch
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..ce6b0d843 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1135,7 +1135,7 @@ pub fn judge_readbacks(
// other finding of a boot's own touches a row's number while each is
// read off one line that is present: one summed or maximised over the
// log would fall with a log that is not whole too.
- let clocked = owed.iter().all(|back| back.one_clock().is_ok());
+ let clocked = owed.iter().all(|back| back.one_clock().is_ok() && back.deadline_on_time().is_ok());
let twice = own(&mut measured, name, verdict.is_ok() && clocked, &owed);
match &verdict {
// `own` said so, by name.m4-a-red-member-is-not-red.patch
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..5eabfcffc 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1168,7 +1168,6 @@ pub fn judge_readbacks(
// bury the four that matter.
Err(why) => {
eprintln!(" FAIL {job}: {}", why.lines().next().unwrap_or(&why));
- red = true;
}
}
}m5-a-name-measured-twice-is-recorded.patch
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..6d18eb1ce 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1029,9 +1029,8 @@ fn own(
Entry::Vacant(slot) => {
slot.insert(Reading { value, passed });
}
- Entry::Occupied(mut first) => {
+ Entry::Occupied(first) => {
eprintln!(" FAIL {} is measured twice, and {owner} is the second", first.key());
- first.get_mut().passed = false;
twice = true;
}
}m6-a-name-measured-twice-is-not-red.patch
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..4bcead8c4 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1023,7 +1023,7 @@ fn own(
passed: bool,
backs: &[&Readback],
) -> bool {
- let mut twice = false;
+ let twice = false;
for (name, value) in backs.iter().flat_map(|back| back.taken()) {
match measured.entry(name) {
Entry::Vacant(slot) => {
@@ -1032,7 +1032,6 @@ fn own(
Entry::Occupied(mut first) => {
eprintln!(" FAIL {} is measured twice, and {owner} is the second", first.key());
first.get_mut().passed = false;
- twice = true;
}
}
}m7-taken-takes-nothing.patch
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..c8be471de 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -484,7 +484,7 @@ impl Readback {
/// What was measured on this boot since this was last asked.
fn taken(&self) -> BTreeMap<String, u64> {
- std::mem::take(&mut self.numbers.borrow_mut())
+ self.numbers.borrow().clone()
}
/// The job ran and the kernel recorded it exiting cleanly.m8-a-red-row-is-not-red.patch
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..aa0ff267e 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1146,7 +1146,7 @@ pub fn judge_readbacks(
}
Err(why) => eprintln!(" FAIL {name}: {why}"),
}
- red |= twice || verdict.is_err();
+ red |= twice;
}
let mut members = 0usize;
for boot in shared {m9-a-row-number-stands-on-a-boot-whose-clocks-disagree.patch
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..bad0d6f22 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1135,7 +1135,7 @@ pub fn judge_readbacks(
// other finding of a boot's own touches a row's number while each is
// read off one line that is present: one summed or maximised over the
// log would fall with a log that is not whole too.
- let clocked = owed.iter().all(|back| back.one_clock().is_ok());
+ let clocked = true;
let twice = own(&mut measured, name, verdict.is_ok() && clocked, &owed);
match &verdict {
// `own` said so, by name.m10-a-failing-owners-reading-is-not-entered.patch
diff --git a/tests/common/metal.rs b/tests/common/metal.rs
index 0c440f498..075d286e3 100644
--- a/tests/common/metal.rs
+++ b/tests/common/metal.rs
@@ -1026,9 +1026,10 @@ fn own(
let mut twice = false;
for (name, value) in backs.iter().flat_map(|back| back.taken()) {
match measured.entry(name) {
- Entry::Vacant(slot) => {
+ Entry::Vacant(slot) if passed => {
slot.insert(Reading { value, passed });
}
+ Entry::Vacant(_) => {}
Entry::Occupied(mut first) => {
eprintln!(" FAIL {} is measured twice, and {owner} is the second", first.key());
first.get_mut().passed = false;|
Review, round 2, of Net lines, Round 1's BLOCKERs
These are the readings round 1 asked for, with the third pair beyond it. The script restores the tree after each arm, Round 1's NOTEs
BLOCKERNone. NOTENone. Evidence at
|
|
CI at |
…s verdict (#789), into the listener's option Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
…atagram-senders stage Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
…nd the two debug timing rows ride shared-debug: 23 boots to 20 (#799) 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 - The design counts 24 boots to 21. `main` is at 23 (#794 was 25 to 23), so this stage is 23 to 20. - The design puts a boot's registered jobs first "in today's order" and names no last job. Stage 3a built the last job behind the members; this stage puts it back among the rows', on the measurement above. - The design's merged boot arms "about 198 s"; the tree's formula gives 200 200 ms. - Nothing of stage 4b is built or prepared. ## 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...01fd3ae`: 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.com/claude-code) https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
Stage 2 of step B of the one-boot plan for the T14's metal rows. Head
71afd05ef, which carriesmainat9cf2c4e5c. Harness only: no kernel, no userland program, no change to which rows a boot runs.The owner wants as many tests on the T14 as possible in as few boots as possible, and a metal failure must never silently drop what its boot measured. This lands before stage 3 puts most of the profile's verdicts on one boot's label.
What changed, per decision
judge_readbackskept a set of failed boot labels: one red row or shared member riding a boot put the label in it, and every number that boot measured was then kept out of the machine's record. The set is gone. What the harness reads off every boot (boot.<label>.complete_ms,panel_us,panel_max_us) is the boot's, and is recorded where the boot's own checks pass. What a row's judge measured is the row's, and is recorded where that judge passed. A failing shared member reds the run and moves no number.Readback::measured, whose signature is unchanged, so no registration changed. After the boot's own checks, and after each row's judge returns, the harness takes what the readbacks gained (Readback::taken) and enters it under that owner's verdict (own). No field names an owner: the owner is whoever was being judged when the number was measured.one_clock) fails every row-measured number of that boot: every such number is a duration on the clock that check compares, a disagreement may be another rate, and the record never moves a recorded value, so a scaled number would stand as the baseline. It is one clause in the row'sowncall: the judge passed and every boot the row rode hasone_clock()Ok. No set, no second pass. Every other boot-level red the harness has (noBoot: completeor no census, the log not whole, the stop giving up, a late deadline or lockup) leaves a passing row's number standing, because each is read off one line that is present; the comment at the site says what would change that: a number summed or maximised over the log.takendrains a readback, two rows on one boot take the same path throughown, which is read from the code and not exercised by a check.ownruns before the verdict is printed, itsFAIL <name> is measured twice, and <row> is the secondis the row's line, and the row is counted among the failed. Nothing checks the printed count; it is read from the code.src/metaltimings.rschanges in its header and one doc comment, and one test is renamed.N whose owner failedwhere it readN off a boot that failed. A passing row's number on a boot whose clocks disagree is counted in thatN; the boot's ownFAILline above says why.Boots, as the harness prints them:
[metal] 64 registration(s) and 229 shared member(s) over 25 boot(s)at the head (r2-list), as at the base in round 1.Where the landed tree differs from the design
LOADEDcut to 2 s. As landed (A T14 boot whose log is missing parts reds by name, and the two ACPI rows ride testcases again: 26 boots to 25 #785)LOADEDstays 20 s and the count is 25.issues/carries a line for this stage, and stage 1 added none, so none is edited.Issues
issues/a-metal-failure-drops-every-row-its-boot-measured.mdis closed: deleted. Its exit, "each number is recorded against its owner, and only that owner fails", is what the two rewritten checks hold. Its rule is the doc comment ofjudge_readbacks. Nothing else in the tree cited it, by path or by slug.issues/the-licence-step-re-locks-std-against-the-registry-on-every-run.mdis filed,kind: tooling, as a record of the review's off-branch finding. Nothing here fixes it.Gates at
71afd05ef, each by its own exit code (logs namedr2-<step>)checkscargo test --locked --test toyos-checks(38 passed)libcargo test --locked --lib(340 passed, 15 ignored)listcargo test --locked --test toyos-build -- --metal --list: 25 bootsclippycargo run -- --clippy(24 invocations)build-onlycargo run -- --build-onlyhostcargo run -- --ci host(Host: 78 step(s), all green)No guest test is reached: the change is in the judge of readbacks, which no QEMU test calls. None was run.
High-risk checks
The harness's verdict path is the change.
The row half of the rule over a real readback, base against head. Every row-measured number lives on
latencycase. The newest recorded T14 readback of that boot (a full-profile run of 7 October, another branch's) is one the current harness reads. It was copied; no recorded readback was changed in place. The T14's record had its sixlatencycaserows removed (boot.latencycase.*,tlb.latencycase.p50_ns,.p99_ns,latency.p99_us) before each arm and was restored after it. Each arm is--metal --metal-readback <copy> boot:latencycase; the base arm is the same withm0applied (tests/common/metal.rsandsrc/metaltimings.rsas onmain).0 whose owner failed0 off a boot that failedtlb: benchline'smin=made 0tlb_shootdown_cost);0 whose owner failedboot.latencycase.*andlatency.p99_us; notlb.*4 off a boot that failedFAILfor its clocks;6 whose owner failed6 off a boot that failedLogs
r2-lat-<asis|benchfail|skew>-<head|base>.log, each with the record's diff beside it. The three record diffs that regain nothing are byte-identical to the removal patch. In the second armtlb_shootdown_costfails before it measures, so that arm shows the boot and the row beside the red one keeping their numbers; a red row's own measured number staying out is the host check's (m1). The third arm is beyond what the review asked: it is the first BLOCKER's rule on the same real readback.The earlier control, round 1 at
7cc209f13: atestcasesreadback withhda_tonemade red, head against base; the head re-records the threeboot.testcases.*rows and the base none (r1-redrow-*).Independent oracle. The readbacks are the T14's own. Every red in them is planted: no recorded readback with a red row and an unrecorded number was at hand.
Mutations at
71afd05ef(patches in the round-2 comment; each applied as a checked patch, run withcargo test --locked --test toyos-checks -- metal_, reversed, tree clean after; each a test failure, exit 101):m0-whole-change-revertedmetal_number_fails_with_its_owner_alone,metal_failing_shared_member_fails_itself_alone,metal_name_two_owners_measured_is_refusedm1-a-red-rows-number-is-recordedmetal_number_fails_with_its_owner_alonem2-a-red-boots-number-is-recordedmetal_cleared_page_owes_no_panelm3-a-late-deadline-fails-its-rows-numbersmetal_number_fails_with_its_owner_alonem4-a-red-member-is-not-redmetal_failing_shared_member_fails_itself_alonem5-a-name-measured-twice-is-recordedmetal_name_two_owners_measured_is_refusedm6-a-name-measured-twice-is-not-redm7-taken-takes-nothingm8-a-red-row-is-not-redmetal_number_fails_with_its_owner_alonem9-a-row-number-stands-on-a-boot-whose-clocks-disagreemetal_number_fails_with_its_owner_alonem10-a-failing-owners-reading-is-not-enteredmetal_name_two_owners_measured_is_refusedTiers and growth
No new test and no new gate: three existing host checks are rewritten to the new rule and renamed; one gains a row beside the failing one, a boot whose clocks disagree with a passing row on it, and a run where the row's failure is the only one; one gains the arm where the first of two owners fails. They see what reading cannot: which names reach the record file when owners fail in combination.
git diff --numstat origin/main...HEAD: the harness andsrc/metaltimings.rs+72 −47, the checks +81 −29, the closed issue −23, the filed one +28.Unsure of
one_clockis evaluated twice per boot a row rides, once among the boot's own checks and once per row in the clause; it is a pure function of the readback's two texts.🤖 Generated with Claude Code
https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A