Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions issues/a-metal-failure-drops-every-row-its-boot-measured.md

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
status: open
kind: tooling
opened: 2026-10-09
---

# The licence step re-locks the std workspace against the registry on every run, so `host` reds without the network and judges whatever the registry serves that day

`licence::judge` (`src/licence.rs`) copies the fork's `library/Cargo.lock`
into `target/licence/` and runs `cargo metadata` over the std workspace with
`resolver.lockfile-path` pointing at the copy, with neither `--locked` nor
`--offline`. The copy is stale by design, since bootstrap re-locks it to this
tree's `toyos-abi` and `toyos` versions, so cargo resolves it again and asks
the registry each time. Two things follow. `cargo run -- --ci host` cannot
pass on a machine without the network, though nothing else in it needs one.
And the set of crates whose licences the step judges is not pinned by anything
in the tree: it moves with what the registry answers on the day of the run.

Evidence: during a network outage on the development machine, the `--ci host`
runs of two branches were each red in this one step, `the licences of what
ships`, 77 of 78 steps green, the step's `cargo metadata` failing to resolve
the registry's host name after its retries; both were green on the same heads
once the registry answered again. Neither branch touched anything the step
reads.

**Exit**: `the licences of what ships` passes with the network off, shown by a
check that runs it so, and what it resolves for the std workspace is a
function of the tree alone. Owner: the build system (`src/licence.rs`).
14 changes: 7 additions & 7 deletions src/metaltimings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 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,
//! 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,
//! 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.
//!
Expand Down Expand Up @@ -136,8 +136,8 @@ enum Unread {
Refused(String),
}

/// 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.
/// One number a run measured, and whether its owner passed: every reading is
/// judged, and only a passing owner's becomes a record.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Reading {
pub value: u64,
Expand Down Expand Up @@ -386,9 +386,9 @@ mod tests {
);
}

/// **A failed boot's numbers are judged and never become a baseline.**
/// **A failed owner's numbers are judged and never become a baseline.**
#[test]
fn a_failing_boots_reading_is_judged_and_not_recorded() {
fn a_failing_owners_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 };
Expand Down
12 changes: 6 additions & 6 deletions tests/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -872,8 +872,8 @@ mod checks {
}

#[test]
fn metal_boot_with_a_failure_of_its_own_adds_no_row() {
metal_checks::a_boot_with_a_failure_of_its_own_adds_no_row();
fn metal_number_fails_with_its_owner_alone() {
metal_checks::a_number_fails_with_its_owner_alone();
}

#[test]
Expand All @@ -882,8 +882,8 @@ mod checks {
}

#[test]
fn metal_name_two_boots_measured_is_refused() {
metal_checks::a_name_two_boots_measured_is_refused();
fn metal_name_two_owners_measured_is_refused() {
metal_checks::a_name_two_owners_measured_is_refused();
}

#[test]
Expand All @@ -897,8 +897,8 @@ mod checks {
}

#[test]
fn metal_failing_shared_member_fails_its_boot() {
metal_checks::a_failing_shared_member_fails_its_boot();
fn metal_failing_shared_member_fails_itself_alone() {
metal_checks::a_failing_shared_member_fails_itself_alone();
}

#[test]
Expand Down
98 changes: 75 additions & 23 deletions tests/checks/metal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,50 +167,93 @@ fn unqualified(b: &[&Readback]) -> Result<(), String> {
b[0].measured("latency.p99_us", 16)
}

fn unqualified_and_fail(b: &[&Readback]) -> Result<(), String> {
unqualified(b)?;
Err("a planted failure".to_string())
}

static PASSING: Metal =
Metal { arms: &[metal::once("passing", "tests/jobcase", &[], &[])], judge: span };
static FAILING: Metal = Metal {
arms: &[metal::once("failing", "tests/jobcase", &[], &[])],
judge: span_and_fail,
};
static BESIDE: Metal = Metal {
arms: &[metal::once("failing", "tests/jobcase", &[], &[])],
judge: |b| b[0].measured("beside.failing.us", 9),
};
static REFUSED: Metal =
Metal { arms: &[metal::once("refused", "tests/jobcase", &[], &[])], judge: span };
static LATE: Metal =
Metal { arms: &[metal::once("late", "tests/jobcase", &[], &[])], judge: span };
static SKEWED: Metal =
Metal { arms: &[metal::once("skewed", "tests/jobcase", &[], &[])], judge: span };
static ONE: Metal =
Metal { arms: &[metal::once("one", "tests/jobcase", &[], &[])], judge: unqualified };
static ONE_FAILS: Metal = Metal {
arms: &[metal::once("one", "tests/jobcase", &[], &[])],
judge: unqualified_and_fail,
};
static TWO: Metal =
Metal { arms: &[metal::once("two", "tests/jobcase", &[], &[])], judge: unqualified };

/// **The record is one function of the readbacks.** A boot the loop refused, a
/// boot a riding test failed and a boot whose own check failed are each
/// judged, and none adds a row; the one boot with no failure of its own is
/// recorded whole.
pub fn a_boot_with_a_failure_of_its_own_adds_no_row() {
/// **A number is recorded off its owner's verdict and nobody else's.** A row
/// that fails keeps its own number out of the record, and neither its boot's
/// numbers nor those of the row beside it on that boot; a boot whose own check
/// fails keeps its own out, and not those of the row that passed on it, unless
/// the check is of its clocks, which every duration on it was read by; a boot
/// the loop refused measured nothing.
pub fn a_number_fails_with_its_owner_alone() {
let dir = toyos_tmpdir::TempDir::new("metal-readbacks");
let root = toyos_tmpdir::TempDir::new("metal-records");
plant(&dir, "passing", PANEL, BOOTED, None);
plant(&dir, "failing", PANEL, BOOTED, None);
plant(&dir, "refused", PANEL, BOOTED, Some(&Refusal::HungWithoutARecord));
plant(&dir, "late", &expired_at(120_160), &armed(), None);
let readbacks = read(&dir, &["passing", "failing", "refused", "late"]);
// The supervisor's line 10 ms before the spawn it reports.
plant(&dir, "skewed", PANEL, BOOTED, None);
let at = metal::at(&dir, "skewed").join(READBACK_KERNEL);
let kernel = fs::read_to_string(&at).expect("a planted log");
fs::write(&at, kernel.replacen("0.050 supervisor]", "0.040 supervisor]", 1)).expect("a planted log");
let readbacks = read(&dir, &["passing", "failing", "refused", "late", "skewed"]);
assert!(readbacks["skewed"].as_ref().expect("a readback").one_clock().is_err());
let why = readbacks["refused"].as_ref().err().expect("the loop's refusal, read back");
assert!(why.contains("never reported: no panic"), "{why}");

let tests = [("passes", &PASSING), ("fails", &FAILING), ("refused", &REFUSED), ("late", &LATE)];
let tests = [
("passes", &PASSING),
("fails", &FAILING),
("beside", &BESIDE),
("refused", &REFUSED),
("late", &LATE),
("skewed", &SKEWED),
];
let runs: Vec<&(&str, &'static Metal)> = tests.iter().collect();
assert!(metal::judge_readbacks(&root, &readbacks, &runs, &[]), "three failed boots judged green");
assert!(metal::judge_readbacks(&root, &readbacks, &runs, &[]), "four failures judged green");
let record = Record::load(&root, &t14()).expect("a readable record").expect("a record");
let names: Vec<&str> = record.measured.keys().map(String::as_str).collect();
assert_eq!(
names,
[
"beside.failing.us",
"boot.failing.complete_ms",
"boot.failing.panel_max_us",
"boot.failing.panel_us",
"boot.passing.complete_ms",
"boot.passing.panel_max_us",
"boot.passing.panel_us",
"span.late.us",
"span.passing.us"
]
);
// The row's own failure is red with nothing else beside it.
let alone = [("fails", &FAILING)];
let runs: Vec<&(&str, &'static Metal)> = alone.iter().collect();
let root = toyos_tmpdir::TempDir::new("metal-records");
assert!(
metal::judge_readbacks(&root, &read(&dir, &["failing"]), &runs, &[]),
"a failing row judged green"
);
}

static HOLED: Metal =
Expand Down Expand Up @@ -250,20 +293,22 @@ pub fn a_boot_that_lost_parts_of_its_log_judges_no_row() {
assert!(!record.measured.keys().any(|name| name.contains("holed")), "{:?}", record.measured);
}

/// Two boots under one name are judged on the first reading and recorded off
/// neither.
pub fn a_name_two_boots_measured_is_refused() {
/// Two rows under one name are judged on the first reading and recorded off
/// neither, whether the first of them passed or failed.
pub fn a_name_two_owners_measured_is_refused() {
let dir = toyos_tmpdir::TempDir::new("metal-readbacks");
let root = toyos_tmpdir::TempDir::new("metal-records");
plant(&dir, "one", PANEL, BOOTED, None);
plant(&dir, "two", PANEL, BOOTED, None);
let readbacks = read(&dir, &["one", "two"]);
let tests = [("one", &ONE), ("two", &TWO)];
let runs: Vec<&(&str, &'static Metal)> = tests.iter().collect();
assert!(metal::judge_readbacks(&root, &readbacks, &runs, &[]), "one name twice judged green");
let record = Record::load(&root, &t14()).expect("a readable record").expect("a record");
assert!(!record.measured.contains_key("latency.p99_us"), "{:?}", record.measured);
assert_eq!(record.measured.len(), 6, "{:?}", record.measured);
for first in [&ONE, &ONE_FAILS] {
let root = toyos_tmpdir::TempDir::new("metal-records");
let tests = [("one", first), ("two", &TWO)];
let runs: Vec<&(&str, &'static Metal)> = tests.iter().collect();
assert!(metal::judge_readbacks(&root, &readbacks, &runs, &[]), "one name twice judged green");
let record = Record::load(&root, &t14()).expect("a readable record").expect("a record");
assert!(!record.measured.contains_key("latency.p99_us"), "{:?}", record.measured);
assert_eq!(record.measured.len(), 6, "{:?}", record.measured);
}
}

/// `passing`'s four rows under `bios`: its planted readings, with `complete_ms`
Expand Down Expand Up @@ -325,10 +370,10 @@ pub fn a_run_under_another_bios_fails_and_records_nothing() {
assert_eq!(judged_against(&lacking(&bios)), (false, committed(&bios, 1165)));
}

/// **A failing shared member fails its boot**: the run is red, and that boot
/// adds no row while the shared boot whose members all passed is recorded
/// whole.
pub fn a_failing_shared_member_fails_its_boot() {
/// **A failing shared member fails itself alone**: the run is red, and the
/// boot it rode records its own numbers as the boot whose members all passed
/// does.
pub fn a_failing_shared_member_fails_itself_alone() {
let dir = toyos_tmpdir::TempDir::new("metal-readbacks");
let root = toyos_tmpdir::TempDir::new("metal-records");
let jobs = ["test_rs_std_tls", "test_rs_fs_large_file"];
Expand Down Expand Up @@ -360,7 +405,14 @@ pub fn a_failing_shared_member_fails_its_boot() {
let names: Vec<&str> = record.measured.keys().map(String::as_str).collect();
assert_eq!(
names,
["boot.passing.complete_ms", "boot.passing.panel_max_us", "boot.passing.panel_us"]
[
"boot.failing.complete_ms",
"boot.failing.panel_max_us",
"boot.failing.panel_us",
"boot.passing.complete_ms",
"boot.passing.panel_max_us",
"boot.passing.panel_us"
]
);
}

Expand Down
Loading
Loading