From 9537469b5615ad6b81b24be72a6318ac3148d1e2 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 23 Aug 2026 07:21:00 +0000 Subject: [PATCH 1/3] The fleet's hardware reconcile had verdicts and no reader: render expectation-versus-observation, and keep "never read" out of "confirmed" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The operator asked for live fleet info on the daily workspace. The capacity panel already shows committed slot widths; the HARDWARE those widths are derived from had no view at all. The inventory has been reconciling expectation against observation per host and producing typed verdicts the whole time -- gunbc.fleet_physical_inventory fleet_dimm_verdicts and fleet_processor_verdicts -- and nothing rendered them, so a disagreement between what the tree believes and what the machines report was reachable only by reading .dag source. THE COST OF THAT WAS ALREADY PAID. srv2's 64 GiB DIMM upgrade was modeled while the install failed training and was reverted, so the tree asserted a memory population the machine did not have and the slot widths computed from it were wrong on the one host that differed. The verdict existed and said so. Nobody could see it. THREE STANDINGS ARE NOT ENOUGH; THERE ARE FOUR, AND THE POINT IS THE ONES THAT ARE NOT REFUSALS. Confirmed and Refused are the obvious pair. UNREAD says no reading was taken, so there is nothing to disagree with. MISFILED says the observation was filed against a different host, so NEITHER machine has been assessed. Their remedies share nothing: go look at that host's DIMMs, go RUN a reading, go find out which machine was measured. Collapsing Unread into Confirmed asserts hardware nobody looked at; collapsing it into Refused sends the operator to inspect a machine that is fine. This is DESIGN's not-applicable-versus-malformed conflation on the axis where it currently costs the most. MEASURED, live, on the real fleet: 4 of 4 memory confirmed · 0 of 4 processor confirmed srv1..srv4 memory confirmed 8 sticks as expected srv1..srv4 processor unread no per-host processor reading exists... EVERY PROCESSOR ROW IN THE FLEET IS UNREAD. The part is modeled intent that every in-tree consumer agrees on, and no dmidecode receipt has ever been supplied for any host. A panel mapping "no contradiction found" to Confirmed would render four confirmations of a fact no instrument has measured, on the page the operator reads to decide what is true about their machines. THE DISCRIMINATING RED, measured rather than asserted. Installing exactly that collapse (ProcessorModelUnconfirmed => HardwareConfirmed) in a copy of the tree: FALSE every_processor_row_is_unread_and_none_is_confirmed true the_memory_axis_is_confirmed_on_every_host true the_four_verdict_shapes_map_to_four_distinct_standings true the_four_standings_do_not_share_a_wire_word true a_refusal_detail_carries_the_count_and_the_discrepancy_tally FALSE the_summary_reports_each_axis_separately_and_never_one_fraction Four of six pass the collapsed mapping. All eight witnesses return true on this branch. THE SUMMARY IS PER AXIS AND NEVER ONE FRACTION. Collapsed, it would read "4 of 8 confirmed" -- arithmetically true and useless. Memory is fully read; the processor axis has never been measured once. A solved problem beside an unstarted one, and averaging them hides both. Two live standings out of four means a mapping that collapsed the two UNOCCUPIED arms would pass everything the fleet can currently exercise, so those verdicts are authored in the witness rather than read from the roster. Same reason the mixed-population summary row is authored: the live rosters are all-confirmed and all-unread, and only a mixed input separates counting confirmations from counting members. The outstanding-contradictions line renders only when non-zero, and UNREAD deliberately does not count toward it -- nothing has been contradicted by a reading nobody took, and counting it would put the panel in a permanent alarm state the operator cannot clear by fixing anything. RUNG: the panel is a reader, and it inherits its subject's rung rather than adding one. The verdicts are the inventory's; this renders them without re-deriving them, so panel and reconcile cannot disagree -- the same reason the capacity panel reads the dispatch gate's own roster. Next-rung trigger for the processor axis is a dmidecode -t processor receipt per host, which is what turns four Unread rows into a real comparison; the panel is what makes their absence visible in the meantime. Column reservations derive from the longest label each column can wear (css_ch), following roadmap_component dispatch_reserved_width, so a new host or a longer standing word moves the reservation by derivation and there is no pixel to maintain. Local parse gate: 0 diagnostics. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012q31BK3okLA8vG4kdTWtBf --- dag/gunbc/fleet_hardware_standing_panel.dag | 262 ++++++++++++++++++ dag/gunbc/roadmap_page.dag | 5 +- dag/gunbc/roadmap_style.dag | 65 +++++ ...t_hardware_standing_panel_witness_test.dag | 135 +++++++++ 4 files changed, 465 insertions(+), 2 deletions(-) create mode 100644 dag/gunbc/fleet_hardware_standing_panel.dag create mode 100644 dag/test/claim/fleet_hardware_standing_panel_witness_test.dag diff --git a/dag/gunbc/fleet_hardware_standing_panel.dag b/dag/gunbc/fleet_hardware_standing_panel.dag new file mode 100644 index 00000000000..abe9fa99666 --- /dev/null +++ b/dag/gunbc/fleet_hardware_standing_panel.dag @@ -0,0 +1,262 @@ +module gunbc.fleet_hardware_standing_panel + +import std.types { String, NonEmptyStr, Bool, List, Int } +import std.markup { Fragment } +import gunbc.site.markup { txt, el_class } +import extdeps.languages.css.values { css_ch, css_length_wire } +import product.placement_supply { HostIdentity } +import product.installed_bom_reconcile { + DimmReconcileVerdict, ProcessorReconcileVerdict, + DimmPopulationConfirmed, DimmPopulationRefused, + DimmObservationHostMismatch, DimmPopulationUnconfirmed, + ProcessorModelConfirmed, ProcessorModelRefused, + ProcessorObservationHostMismatch, ProcessorModelUnconfirmed, + DimmCountMatches, DimmCountDiffers, +} +import gunbc.fleet_physical_inventory { fleet_dimm_verdicts, fleet_processor_verdicts } + +// WHAT THE FLEET IS BELIEVED TO CONTAIN, BESIDE WHAT WAS ACTUALLY READ OFF IT. +// +// The inventory already reconciles expectation against observation per host and produces a typed +// verdict; nothing rendered it, so the disagreement was reachable only by reading .dag source. That +// is the gap this closes: the operator can see committed slot widths on the capacity panel, but the +// hardware those widths are DERIVED FROM had no view at all. +// +// The concrete cost of that, already paid: srv2's 64 GiB DIMM upgrade was modeled while the install +// failed training and was reverted, so the tree asserted a memory population the machine did not +// have, and the slot widths computed from it were wrong on the one host that differed. The verdict +// existed the whole time and said so. Nobody could see it. +data fleet_hardware_standing_panel_note: String = "Daily-workspace panel over gunbc.fleet_physical_inventory's per-host reconcile verdicts. Renders expectation-versus-observation standing for memory and processor; reads the verdicts directly rather than re-deriving them." + +// THREE STANDINGS, NOT TWO, AND THE THIRD IS THE ONE THE PANEL EXISTS FOR. +// +// Confirmed and Refused are the obvious pair. Unconfirmed is separate and is NOT a soft refusal: it +// says no reading was taken, so there is nothing to disagree with. Collapsing it into Confirmed +// asserts hardware nobody looked at. Collapsing it into Refused reports a contradiction that did +// not happen and sends the operator to inspect a machine that is fine. +// +// Their REMEDIES are what makes the distinction load-bearing, and they share nothing: a refusal +// means go look at that host's DIMMs, an unconfirmed means go RUN a reading, and a host mismatch +// means the observation was filed against the wrong host and neither machine has been assessed. +// This is DESIGN's not-applicable-versus-malformed conflation, on the axis where it costs the most: +// every processor row in the fleet is Unconfirmed today, so a panel that collapsed the third state +// would render four confirmations of a fact no instrument has ever measured. +type HardwareStanding + = HardwareConfirmed + | HardwareRefused + | HardwareUnread + | HardwareMisfiled + +fn hardware_standing_label(standing: HardwareStanding) -> String { + match standing { + HardwareConfirmed => "confirmed" + HardwareRefused => "REFUSED" + HardwareUnread => "unread" + HardwareMisfiled => "MISFILED" + } +} + +fn hardware_standing_class(standing: HardwareStanding) -> String { + match standing { + HardwareConfirmed => "hardware-cell hardware-confirmed" + HardwareRefused => "hardware-cell hardware-refused" + HardwareUnread => "hardware-cell hardware-unread" + HardwareMisfiled => "hardware-cell hardware-misfiled" + } +} + +fn dimm_standing(verdict: DimmReconcileVerdict) -> HardwareStanding { + match verdict { + DimmPopulationConfirmed { host: _, stick_count: _ } => HardwareConfirmed + DimmPopulationRefused { host: _, discrepancies: _, count: _ } => HardwareRefused + DimmObservationHostMismatch { expectation_host: _, observation_host: _ } => HardwareMisfiled + DimmPopulationUnconfirmed { host: _, cause: _ } => HardwareUnread + } +} + +fn processor_standing(verdict: ProcessorReconcileVerdict) -> HardwareStanding { + match verdict { + ProcessorModelConfirmed { host: _, model_number: _ } => HardwareConfirmed + ProcessorModelRefused { host: _, expected: _, observed: _ } => HardwareRefused + ProcessorObservationHostMismatch { expectation_host: _, observation_host: _ } => HardwareMisfiled + ProcessorModelUnconfirmed { host: _, cause: _ } => HardwareUnread + } +} + +fn dimm_verdict_host(verdict: DimmReconcileVerdict) -> HostIdentity { + match verdict { + DimmPopulationConfirmed { host: h, stick_count: _ } => h + DimmPopulationRefused { host: h, discrepancies: _, count: _ } => h + DimmObservationHostMismatch { expectation_host: h, observation_host: _ } => h + DimmPopulationUnconfirmed { host: h, cause: _ } => h + } +} + +fn processor_verdict_host(verdict: ProcessorReconcileVerdict) -> HostIdentity { + match verdict { + ProcessorModelConfirmed { host: h, model_number: _ } => h + ProcessorModelRefused { host: h, expected: _, observed: _ } => h + ProcessorObservationHostMismatch { expectation_host: h, observation_host: _ } => h + ProcessorModelUnconfirmed { host: h, cause: _ } => h + } +} + +// THE DETAIL LINE CARRIES WHAT THE VERDICT FOUND, BECAUSE A STANDING WORD IS UNACTIONABLE. +// +// "REFUSED" tells an operator that something is wrong and nothing about where to go. The count +// mismatch and the discrepancy tally are the two independent axes the verdict already separates -- +// a population can hold the right count of the wrong part, or the wrong count of the right one -- +// so both are rendered rather than folded into one number. +fn dimm_detail(verdict: DimmReconcileVerdict) -> String { + match verdict { + DimmPopulationConfirmed { host: _, stick_count: n } => + join([to_string(n), " sticks as expected"], "") + DimmPopulationRefused { host: _, discrepancies: d, count: c } => + join([ + match c { + DimmCountMatches { count: n } => join([to_string(n), " sticks"], "") + DimmCountDiffers { expected: e, observed: o } => + join(["expected ", to_string(e), " sticks, read ", to_string(o)], "") + }, + " · ", to_string(d |> count), " slot discrepancies", + ], "") + DimmObservationHostMismatch { expectation_host: e, observation_host: o } => + join(["reading filed against ", o as String, ", expected ", e as String], "") + DimmPopulationUnconfirmed { host: _, cause: c } => c as String + } +} + +fn processor_detail(verdict: ProcessorReconcileVerdict) -> String { + match verdict { + ProcessorModelConfirmed { host: _, model_number: m } => m as String + ProcessorModelRefused { host: _, expected: e, observed: o } => + join(["expected ", e as String, ", read ", o as String], "") + ProcessorObservationHostMismatch { expectation_host: e, observation_host: o } => + join(["reading filed against ", o as String, ", expected ", e as String], "") + ProcessorModelUnconfirmed { host: _, cause: c } => c as String + } +} + +fn hardware_axis_cell(standing: HardwareStanding, detail: String) -> List { + [ + el_class("span", hardware_standing_class(standing: standing), [ + txt(hardware_standing_label(standing: standing)), + ]), + el_class("span", "hardware-detail", [txt(detail)]), + ] +} + +fn dimm_row(verdict: DimmReconcileVerdict) -> Fragment { + el_class("div", "hardware-row", concat( + [el_class("span", "hardware-subject", [txt(dimm_verdict_host(verdict: verdict) as String)]), + el_class("span", "hardware-axis", [txt("memory")])], + hardware_axis_cell( + standing: dimm_standing(verdict: verdict), + detail: dimm_detail(verdict: verdict), + ), + )) +} + +fn processor_row(verdict: ProcessorReconcileVerdict) -> Fragment { + el_class("div", "hardware-row", concat( + [el_class("span", "hardware-subject", [txt(processor_verdict_host(verdict: verdict) as String)]), + el_class("span", "hardware-axis", [txt("processor")])], + hardware_axis_cell( + standing: processor_standing(verdict: verdict), + detail: processor_detail(verdict: verdict), + ), + )) +} + +fn fleet_dimm_standings() -> List { + map(fleet_dimm_verdicts, v => dimm_standing(verdict: v)) +} + +fn fleet_processor_standings() -> List { + map(fleet_processor_verdicts, v => processor_standing(verdict: v)) +} + +fn standing_count(standings: List, wanted: HardwareStanding) -> Int { + filter(standings, s => s == wanted) |> count +} + +// THE SUMMARY REPORTS CONFIRMED OVER TOTAL PER AXIS, NEVER A SINGLE FLEET FRACTION. +// +// One number across both axes would today read "4 of 8 confirmed", which is arithmetically true and +// tells the operator nothing: the memory axis is fully read and the processor axis has never been +// measured once. Those are not two halves of one shortfall, they are a solved problem beside an +// unstarted one, and the remedies have nothing in common. +fn hardware_axis_summary(axis: String, standings: List) -> String { + join([ + to_string(standing_count(standings: standings, wanted: HardwareConfirmed)), + " of ", to_string(standings |> count), " ", axis, " confirmed", + ], "") +} + +fn fleet_hardware_summary_line() -> String { + join([ + hardware_axis_summary(axis: "memory", standings: fleet_dimm_standings()), + " · ", + hardware_axis_summary(axis: "processor", standings: fleet_processor_standings()), + ], "") +} + +// AN OUTSTANDING LINE APPEARS ONLY WHEN SOMETHING IS OUTSTANDING. +// +// A standing "0 refused" row is noise on every ordinary day and trains the reader to skip the line +// on the day it finally carries a number. Refused and misfiled are counted together here because +// both mean a host's declared hardware cannot be trusted right now; they stay separately labelled +// in the rows, where the differing remedy is actionable. +fn fleet_hardware_outstanding_line() -> String? { + let all = concat(fleet_dimm_standings(), fleet_processor_standings()) + let bad = standing_count(standings: all, wanted: HardwareRefused) + + standing_count(standings: all, wanted: HardwareMisfiled) + if bad > 0 { + Present { + value: join([to_string(bad), " host-axes contradict their declared hardware"], ""), + } + } else { + none + } +} + +fn fleet_hardware_outstanding_nodes() -> List { + match fleet_hardware_outstanding_line() { + Present { value: line } => [el_class("div", "hardware-outstanding", [txt(line)])] + Absent => [] + } +} + +data hardware_column_ch_gutter: Int = 2 + +fn hardware_longest_len(labels: List) -> Int { + fold(labels, init: 0, f: (acc, l) => + if string_length(s: l) > acc { string_length(s: l) } else { acc }) +} + +fn hardware_subject_reserved_width() -> String { + let labels = map(fleet_dimm_verdicts, v => dimm_verdict_host(verdict: v) as String) + let widest = hardware_longest_len(labels: labels) + hardware_column_ch_gutter + css_length_wire(l: css_ch(n: widest)) +} + +fn hardware_standing_reserved_width() -> String { + let all = [HardwareConfirmed, HardwareRefused, HardwareUnread, HardwareMisfiled] + let labels = map(all, s => hardware_standing_label(standing: s)) + let widest = hardware_longest_len(labels: labels) + hardware_column_ch_gutter + css_length_wire(l: css_ch(n: widest)) +} + +fn fleet_hardware_standing_panel() -> Fragment { + el_class("section", "fleet-hardware-standing", concat( + concat( + [el_class("h2", "hardware-heading", [txt("Fleet hardware standing")]), + el_class("div", "hardware-summary", [txt(fleet_hardware_summary_line())])], + fleet_hardware_outstanding_nodes(), + ), + concat( + map(fleet_dimm_verdicts, v => dimm_row(verdict: v)), + map(fleet_processor_verdicts, v => processor_row(verdict: v)), + ), + )) +} diff --git a/dag/gunbc/roadmap_page.dag b/dag/gunbc/roadmap_page.dag index 7815abfbe60..a92c911996b 100644 --- a/dag/gunbc/roadmap_page.dag +++ b/dag/gunbc/roadmap_page.dag @@ -13,6 +13,7 @@ import gunbc.roadmap_model { } import gunbc.roadmap_status { line_ticket } import gunbc.roadmap_document { RoadmapDocument, RoadmapSection } +import gunbc.fleet_hardware_standing_panel { fleet_hardware_standing_panel } import gunbc.roadmap_altitude { section_counts, section_counts_wire, statuses_all_routine, SectionCounts } import gunbc.roadmap_authority { roadmap_authority, authored_merged_prs, @@ -850,9 +851,9 @@ fn roadmap_daily_workspace_page_impl_for_accepted( ]), el("body", [ roadmap_header(page: "daily workspace"), - el_class("main", "daily-workspace", concat(main_prefix, concat(program_strip, concat( + el_class("main", "daily-workspace", concat(main_prefix, concat([fleet_hardware_standing_panel()], concat(program_strip, concat( workspace_observation_banner(observation: ws.observation), - [ workspace_markup(ws: ws) ])))), + [ workspace_markup(ws: ws)]))))), dispatch_client_script(), ]), ], diff --git a/dag/gunbc/roadmap_style.dag b/dag/gunbc/roadmap_style.dag index d72e10ecc92..46e7b30d15d 100644 --- a/dag/gunbc/roadmap_style.dag +++ b/dag/gunbc/roadmap_style.dag @@ -28,6 +28,9 @@ import gunbc.design.state_response { state_var_name, state_var_ref, state_rest_decl, state_paint_rules, RestBinding, StateClassBinding, } +import gunbc.fleet_hardware_standing_panel { + hardware_subject_reserved_width, hardware_standing_reserved_width, +} import gunbc.roadmap_component { dispatch_reserved_width, theme_toggle_class, theme_toggle_reserved_width, sound_toggle_class, sound_toggle_reserved_width, @@ -486,6 +489,68 @@ fn roadmap_instance_rules_head() -> List { decl(prop: FontStyle, value: "italic"), decl(prop: FontSize, value: scale_var(t: text_12)), ] }, + StaticRule { selector: ClassSelector { name: "fleet-hardware-standing" }, decls: [ + role_decl(prop: Background, r: SurfaceRole), + decl(prop: Border, value: scale_border(w: border_1, color_var: "var(--border)")), + decl(prop: BorderRadius, value: scale_var(t: radius_3)), + decl(prop: Padding, value: scale_pair(a: space_12, b: space_16)), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-heading" }, decls: [ + role_decl(prop: Color, r: TextRole), + decl(prop: FontSize, value: scale_var(t: text_13)), + decl(prop: FontWeight, value: "600"), + decl(prop: MarginBottom, value: scale_var(t: space_8)), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-summary" }, decls: [ + role_decl(prop: Color, r: TextRole), + decl(prop: FontSize, value: scale_var(t: text_13)), + decl(prop: FontFamily, value: scale_var(t: font_mono)), + decl(prop: MarginBottom, value: scale_var(t: space_8)), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-outstanding" }, decls: [ + role_decl(prop: Color, r: SalienceRole), + decl(prop: FontSize, value: scale_var(t: text_13)), + decl(prop: FontFamily, value: scale_var(t: font_mono)), + decl(prop: FontWeight, value: "600"), + decl(prop: MarginBottom, value: scale_var(t: space_8)), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-row" }, decls: [ + decl(prop: Display, value: "flex"), + decl(prop: AlignItems, value: "center"), + decl(prop: Gap, value: scale_var(t: space_12)), + decl(prop: FontSize, value: scale_var(t: text_12)), + decl(prop: FontFamily, value: scale_var(t: font_mono)), + decl(prop: Padding, value: scale_pair(a: space_1, b: space_4)), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-subject" }, decls: [ + role_decl(prop: Color, r: TextRole), + decl(prop: FontWeight, value: "600"), + decl(prop: MinWidth, value: hardware_subject_reserved_width()), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-axis" }, decls: [ + role_decl(prop: Color, r: TextDimRole), + decl(prop: MinWidth, value: hardware_subject_reserved_width()), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-cell" }, decls: [ + decl(prop: FontWeight, value: "600"), + decl(prop: MinWidth, value: hardware_standing_reserved_width()), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-confirmed" }, decls: [ + role_decl(prop: Color, r: TextDimRole), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-refused" }, decls: [ + role_decl(prop: Color, r: SalienceRole), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-misfiled" }, decls: [ + role_decl(prop: Color, r: SalienceRole), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-unread" }, decls: [ + role_decl(prop: Color, r: TextDimRole), + decl(prop: FontStyle, value: "italic"), + ] }, + StaticRule { selector: ClassSelector { name: "hardware-detail" }, decls: [ + role_decl(prop: Color, r: TextDimRole), + ] }, StaticRule { selector: ClassSelector { name: "daily-workspace" }, decls: [ decl(prop: Padding, value: scale_pair(a: space_16, b: space_24)), decl(prop: MaxWidth, value: scale_var(t: measure_page)), diff --git a/dag/test/claim/fleet_hardware_standing_panel_witness_test.dag b/dag/test/claim/fleet_hardware_standing_panel_witness_test.dag new file mode 100644 index 00000000000..f3d70399bb3 --- /dev/null +++ b/dag/test/claim/fleet_hardware_standing_panel_witness_test.dag @@ -0,0 +1,135 @@ +module test.claim.fleet_hardware_standing_panel_witness_test + +import std.types { Bool, String, NonEmptyStr, List, Int } +import product.placement_supply { HostIdentity } +import product.installed_bom_reconcile { + DimmReconcileVerdict, ProcessorReconcileVerdict, + DimmPopulationConfirmed, DimmPopulationRefused, + DimmObservationHostMismatch, DimmPopulationUnconfirmed, + ProcessorModelConfirmed, ProcessorModelUnconfirmed, + DimmCountMatches, DimmCountDiffers, +} +import gunbc.fleet_hardware_standing_panel { + HardwareStanding, HardwareConfirmed, HardwareRefused, HardwareUnread, HardwareMisfiled, + hardware_standing_label, dimm_standing, processor_standing, + dimm_detail, hardware_axis_summary, standing_count, + fleet_dimm_standings, fleet_processor_standings, + fleet_hardware_summary_line, fleet_hardware_outstanding_line, +} + +fn a_host() -> HostIdentity { "srv3" } +fn other_host() -> HostIdentity { "srv4" } + +// THE PROCESSOR AXIS IS UNREAD ON EVERY HOST, AND THE PANEL MUST SAY SO RATHER THAN CONFIRM IT. +// +// This is the load-bearing row in the file. The fleet's processor is modeled intent -- every +// in-tree consumer agrees on the part -- and no dmidecode receipt has ever been supplied for any +// host. A panel that mapped "no contradiction found" to Confirmed would render four confirmations +// of a fact no instrument has measured, on a page the operator reads to decide what is true about +// their machines. The distinction between "read and agreed" and "never read" is the entire reason +// HardwareStanding has a third value. +test fn every_processor_row_is_unread_and_none_is_confirmed() -> Bool { + let standings = fleet_processor_standings() + (standings |> count) == 4 + && standing_count(standings: standings, wanted: HardwareUnread) == 4 + && standing_count(standings: standings, wanted: HardwareConfirmed) == 0 +} + +// THE POSITIVE CONTROL ON THE SAME AXIS PAIR: memory IS read, and IS confirmed. +// +// Without this, the assertion above is satisfied by a panel that renders everything as unread -- +// which would be just as wrong, in the direction that makes a healthy fleet look unmeasured. The +// two axes disagreeing is what proves the mapping discriminates rather than answering a constant. +test fn the_memory_axis_is_confirmed_on_every_host() -> Bool { + let standings = fleet_dimm_standings() + (standings |> count) == 4 + && standing_count(standings: standings, wanted: HardwareConfirmed) == 4 + && standing_count(standings: standings, wanted: HardwareUnread) == 0 +} + +// EACH VERDICT VARIANT MAPS TO ITS OWN STANDING, PROVEN ON AUTHORED VERDICTS. +// +// The live tree currently exercises only two of the four standings, so a mapping that collapsed +// Refused into Misfiled would pass every assertion above. These verdicts are authored here rather +// than read from the fleet precisely so the two unoccupied arms are still discriminated. +test fn the_four_verdict_shapes_map_to_four_distinct_standings() -> Bool { + let confirmed = dimm_standing(verdict: DimmPopulationConfirmed { host: a_host(), stick_count: 8 }) + let refused = dimm_standing(verdict: DimmPopulationRefused { + host: a_host(), + discrepancies: [], + count: DimmCountDiffers { expected: 8, observed: 6 }, + }) + let misfiled = dimm_standing(verdict: DimmObservationHostMismatch { + expectation_host: a_host(), + observation_host: other_host(), + }) + let unread = dimm_standing(verdict: DimmPopulationUnconfirmed { + host: a_host(), + cause: "no reading taken" as NonEmptyStr, + }) + confirmed == HardwareConfirmed + && refused == HardwareRefused + && misfiled == HardwareMisfiled + && unread == HardwareUnread + && (confirmed != refused) && (refused != misfiled) && (misfiled != unread) +} + +// THE FOUR STANDINGS DO NOT SHARE A WIRE WORD. +// A label function collapsing two still renders a plausible row, and the collapse would surface +// only as an operator acting on the wrong remedy. +test fn the_four_standings_do_not_share_a_wire_word() -> Bool { + let all = [HardwareConfirmed, HardwareRefused, HardwareUnread, HardwareMisfiled] + let labels = map(all, s => hardware_standing_label(standing: s)) + (labels |> count) == 4 + && !any(labels, a => (filter(labels, b => b == a) |> count) > 1) +} + +// A REFUSAL NAMES BOTH INDEPENDENT AXES, BECAUSE EITHER CAN BE THE WHOLE STORY. +// +// A population can hold the right count of the wrong part or the wrong count of the right one. The +// verdict separates them, so the detail line must not fold them into one number -- an operator told +// only "3 discrepancies" does not know whether sticks are missing. +test fn a_refusal_detail_carries_the_count_and_the_discrepancy_tally() -> Bool { + let detail = dimm_detail(verdict: DimmPopulationRefused { + host: a_host(), + discrepancies: [], + count: DimmCountDiffers { expected: 8, observed: 6 }, + }) + string_contains(s: detail, pattern: "expected 8") + && string_contains(s: detail, pattern: "read 6") + && string_contains(s: detail, pattern: "discrepancies") +} + +// THE SUMMARY IS PER AXIS, AND A SINGLE FLEET FRACTION WOULD BE THE DEFECT. +// +// Collapsed today, the summary would read "4 of 8 confirmed" -- arithmetically true and useless. +// Memory is fully read; the processor axis has never been measured once. Those are a solved problem +// beside an unstarted one, and averaging them hides both. +test fn the_summary_reports_each_axis_separately_and_never_one_fraction() -> Bool { + let line = fleet_hardware_summary_line() + string_contains(s: line, pattern: "4 of 4 memory confirmed") + && string_contains(s: line, pattern: "0 of 4 processor confirmed") + && !string_contains(s: line, pattern: "of 8") +} + +// AN AXIS SUMMARY COUNTS CONFIRMATIONS, NOT ROWS. +// Authored rather than read from the fleet: the live rosters are all-confirmed and all-unread, so +// a mixed population is the only input that separates counting confirmations from counting members. +test fn an_axis_summary_counts_confirmations_not_members() -> Bool { + let mixed = [HardwareConfirmed, HardwareUnread, HardwareRefused, HardwareConfirmed] + let line = hardware_axis_summary(axis: "memory", standings: mixed) + string_contains(s: line, pattern: "2 of 4 memory confirmed") +} + +// THE OUTSTANDING LINE IS ABSENT WHEN NOTHING CONTRADICTS, AND THAT IS THE CURRENT FLEET STATE. +// +// Present-with-zero would be a standing row of noise that trains the reader to skip the line on the +// day it carries a number. Unread must NOT count toward it: nothing has been contradicted by a +// reading nobody took, and treating an unmeasured axis as a contradiction would put the panel in a +// permanent alarm state that the operator cannot clear by fixing anything. +test fn no_outstanding_line_while_nothing_contradicts_and_unread_does_not_count() -> Bool { + match fleet_hardware_outstanding_line() { + Present { value: _ } => false + Absent => standing_count(standings: fleet_processor_standings(), wanted: HardwareUnread) == 4 + } +} From 8cf2d4eb65bfd0479a31b6232fe628ea20e2b1da Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 23 Aug 2026 07:41:16 +0000 Subject: [PATCH 2/3] Style the panel on the existing refused-state vocabulary, and re-pin the CSS digest by execution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two things the panel commit owed, and one real defect that only the whole-page consumer could find. THE DEFECT: the first draft painted the refused and misfiled standings with role_decl(prop: Color, r: SalienceRole). That COMPILED CLEAN -- 0 diagnostics, every one of the eight panel witnesses green -- and then failed at evaluation with NoSuchVariable { name: "SalienceRole" }. SalienceRole is a TYPE in gunbc.design.salience, not one of the theme roles role_decl accepts (CanvasRole, SurfaceRole, BorderRole, TextRole, TextDimRole, FigureRole, FocusRole, BoundaryRole). A name that resolves as a type and is then used where a value is needed passes the parse gate and dies on the page. Nothing in the panel's own witnesses could have caught it, and that is the point worth recording rather than just fixing: every witness tested the panel's LOGIC, and the stylesheet is not reachable from any of them. It surfaced within seconds of serializing the actual daily workspace, which is the consumer. A green witness file is not evidence the page renders. THE FIX is not a new role. var(--band-loud) is the established refused-state vocabulary in this stylesheet -- the activity obligation row already paints [data-state="refused"] with it -- so the panel reuses it rather than minting a parallel one for the same meaning. Confirmed and unread stay dim, unread additionally italic, so the four standings are distinguishable by material and not by colour alone. RECEIPT, by serializing the real page rather than the panel function: 233,714 bytes, the .fleet-hardware-standing section present, the summary line rendering "4 of 4 memory confirmed · 0 of 4 processor confirmed", four unread cells, and all twelve .hardware-* rules emitted. The derived reservations land as 6ch and 11ch -- 11 being the width of "confirmed", the longest of the four standing words plus the gutter -- so they are computed, not typed. THE RE-PIN: roadmap_css_lift_parity_digest moves 25d65c956b7578ca -> 9f37abcc65255edf, DERIVED by running roadmap_css_derived_digest against this tree, never chosen. The accompanying note states what moved and why. The two neighbouring digests deliberately did NOT move, and that is scope evidence rather than an absence of checking: moodboard_css did not move because this adds no rule it covers, and moodboard_html did not move because it renders the thesis and principles rather than the stylesheet. A change that had leaked past the roadmap stylesheet would have moved them too. Both re-run green here alongside the re-pinned one. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012q31BK3okLA8vG4kdTWtBf --- dag/gunbc/roadmap_style.dag | 6 +++--- dag/test/claim/design_register_lift_parity_witness_test.dag | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dag/gunbc/roadmap_style.dag b/dag/gunbc/roadmap_style.dag index 46e7b30d15d..4f28d5f2855 100644 --- a/dag/gunbc/roadmap_style.dag +++ b/dag/gunbc/roadmap_style.dag @@ -508,7 +508,7 @@ fn roadmap_instance_rules_head() -> List { decl(prop: MarginBottom, value: scale_var(t: space_8)), ] }, StaticRule { selector: ClassSelector { name: "hardware-outstanding" }, decls: [ - role_decl(prop: Color, r: SalienceRole), + decl(prop: Color, value: "var(--band-loud)"), decl(prop: FontSize, value: scale_var(t: text_13)), decl(prop: FontFamily, value: scale_var(t: font_mono)), decl(prop: FontWeight, value: "600"), @@ -539,10 +539,10 @@ fn roadmap_instance_rules_head() -> List { role_decl(prop: Color, r: TextDimRole), ] }, StaticRule { selector: ClassSelector { name: "hardware-refused" }, decls: [ - role_decl(prop: Color, r: SalienceRole), + decl(prop: Color, value: "var(--band-loud)"), ] }, StaticRule { selector: ClassSelector { name: "hardware-misfiled" }, decls: [ - role_decl(prop: Color, r: SalienceRole), + decl(prop: Color, value: "var(--band-loud)"), ] }, StaticRule { selector: ClassSelector { name: "hardware-unread" }, decls: [ role_decl(prop: Color, r: TextDimRole), diff --git a/dag/test/claim/design_register_lift_parity_witness_test.dag b/dag/test/claim/design_register_lift_parity_witness_test.dag index 58665b89fe5..f39f2d082aa 100644 --- a/dag/test/claim/design_register_lift_parity_witness_test.dag +++ b/dag/test/claim/design_register_lift_parity_witness_test.dag @@ -64,7 +64,9 @@ data roadmap_css_repin_a2_hierarchy_note: String = "Re-pinned 2026-08-02 for the data lift_parity_merge_resolution_note: String = "MERGE RESOLUTION, RE-DERIVED NOT RECONCILED (S1 x A2-hierarchy, 2026-08-03). Both branches edited this row block and each moved a DIFFERENT digest: #7701 (A2 hierarchy closeout) moved roadmap_css because it changed the stylesheet, and S1 moved moodboard_thesis_themes because it revised register_thesis. Neither touched the other's surface, so the semantic union is the resolution and no value is a compromise between two claims. The union was nonetheless not TRUSTED: both digests were re-run by execution on the merged tree, because a digest pins emitted bytes and a merge is the one moment when the bytes belong to a tree neither side ever built — picking a side by reasoning about scope is exactly the copied-measurement-as-oracle failure this file's own repin notes disclaim ('derived by execution, never chosen'). The re-run is the oracle; the reasoning above only explains why the re-run was expected to agree." -data roadmap_css_lift_parity_digest: String = "25d65c956b7578ca" +data roadmap_css_repin_fleet_hardware_standing_note: String = "Re-pinned 2026-08-23 for the daily-workspace fleet hardware standing panel (operator request: live fleet info on the workspace): the roadmap bytes move intentionally — the .fleet-hardware-standing family lands (panel surface, .hardware-heading, .hardware-summary, .hardware-outstanding, .hardware-row, .hardware-subject, .hardware-axis, .hardware-cell and the four standing variants .hardware-confirmed / .hardware-refused / .hardware-misfiled / .hardware-unread, plus .hardware-detail), all role-routed and tokened. The two column reservations are NOT pixels: .hardware-subject/.hardware-axis and .hardware-cell take min-width from gunbc.fleet_hardware_standing_panel hardware_subject_reserved_width and hardware_standing_reserved_width, which derive the longest label each column can wear plus a gutter — emitted as 6ch and 11ch, the latter being the width of 'confirmed', the longest of the four standing words. The refused and misfiled variants reuse the EXISTING var(--band-loud) refused-state vocabulary rather than minting a role: an earlier revision of this change wrote role_decl(r: SalienceRole), which compiled clean and then failed evaluation with NoSuchVariable — SalienceRole is a type in gunbc.design.salience, not a theme role role_decl can take — and it was caught only by serializing the whole page, not by any panel-level witness. Behavioral receipts: test.claim.fleet_hardware_standing_panel_witness_test — every processor row is unread and none confirmed, the memory axis is confirmed on every host as the positive control, the four verdict shapes map to four distinct standings, the summary reports each axis separately and never one fraction, and no outstanding line renders while nothing contradicts. Derived by execution from this tree (roadmap_css_derived_digest run 2026-08-23); this digest only pins bytes, never chosen." + +data roadmap_css_lift_parity_digest: String = "9f37abcc65255edf" data moodboard_thesis_themes_lift_parity_digest: String = "98f0513aebb0dcb3" fn emission_content_digest(s: String) -> String { From e271024d3386266307f0bedaae0aad9e094c8fe7 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 23 Aug 2026 11:53:34 +0000 Subject: [PATCH 3/3] The axis column reserved the widest HOSTNAME for words that are not hostnames (review 55065) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `.hardware-axis` took `hardware_subject_reserved_width()` — copied from the column beside it — so a column carrying "memory" and "processor" was reserved to the width of the longest HOST LABEL. Two unrelated populations that happen to be adjacent, and the derivation read the wrong one. Emitted 6ch for a column whose longest word is nine characters. That it looked derived is what made it survive review twice, mine included: the call is a derivation, it just derives from the wrong population. A hardcoded `11ch` would have been more obviously wrong. FIXED BY GIVING THE AXIS WORDS AN AUTHORITY. `hardware_axis_labels()` is now the one list, read by both the rendered rows and the reservation, so a third axis widens the column by derivation rather than by someone noticing. Emits 11ch, and the rows still render "memory" / "processor" from that same list rather than from their own literals. THE WITNESS ASSERTS THE DISCRIMINATING FACT, NOT THE TAUTOLOGY. A row checking that the axis width is derived from the axis labels would be `measure() == measure()` — it would pass against the defect too, because the defect is also a derivation. What separates them is that the subject population CANNOT HOLD the axis one: host labels are four characters, "processor" is nine. So the row asserts the two reservations differ and that the axis words are longer than any host label, which is exactly the condition the copy-paste violates. Digest re-pinned 9f37abcc65255edf -> becaf5e24965215d, derived by executing `roadmap_css_derived_digest` against this tree, never chosen. `moodboard_css` deliberately did not move and re-runs green beside it, which is the scope evidence that this touched only the roadmap stylesheet. Local parse gate: 0 diagnostics. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012q31BK3okLA8vG4kdTWtBf --- dag/gunbc/fleet_hardware_standing_panel.dag | 19 ++++++++++++++-- dag/gunbc/roadmap_style.dag | 5 +++-- ...sign_register_lift_parity_witness_test.dag | 4 +++- ...t_hardware_standing_panel_witness_test.dag | 22 +++++++++++++++++++ 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/dag/gunbc/fleet_hardware_standing_panel.dag b/dag/gunbc/fleet_hardware_standing_panel.dag index abe9fa99666..80e2a0b2d50 100644 --- a/dag/gunbc/fleet_hardware_standing_panel.dag +++ b/dag/gunbc/fleet_hardware_standing_panel.dag @@ -149,7 +149,7 @@ fn hardware_axis_cell(standing: HardwareStanding, detail: String) -> List Fragment { el_class("div", "hardware-row", concat( [el_class("span", "hardware-subject", [txt(dimm_verdict_host(verdict: verdict) as String)]), - el_class("span", "hardware-axis", [txt("memory")])], + el_class("span", "hardware-axis", [txt(hardware_axis_labels().first())])], hardware_axis_cell( standing: dimm_standing(verdict: verdict), detail: dimm_detail(verdict: verdict), @@ -160,7 +160,7 @@ fn dimm_row(verdict: DimmReconcileVerdict) -> Fragment { fn processor_row(verdict: ProcessorReconcileVerdict) -> Fragment { el_class("div", "hardware-row", concat( [el_class("span", "hardware-subject", [txt(processor_verdict_host(verdict: verdict) as String)]), - el_class("span", "hardware-axis", [txt("processor")])], + el_class("span", "hardware-axis", [txt(hardware_axis_labels().skip(n: 1).first())])], hardware_axis_cell( standing: processor_standing(verdict: verdict), detail: processor_detail(verdict: verdict), @@ -234,6 +234,21 @@ fn hardware_longest_len(labels: List) -> Int { if string_length(s: l) > acc { string_length(s: l) } else { acc }) } +// THE AXIS COLUMN RESERVES THE WIDEST AXIS WORD, NOT THE WIDEST HOSTNAME (review 55065). +// +// It was taking hardware_subject_reserved_width -- copied from the column beside it -- so the +// column carrying "memory" and "processor" was reserved to the width of the longest HOST LABEL. +// The two are unrelated populations that happen to be adjacent, and the derivation was reading the +// wrong one; today that is merely wrong-looking, and it would silently truncate or over-reserve the +// moment either population moved. The axis words now come from one list that both the rows and the +// reservation read, so a third axis widens the column by derivation rather than by anyone noticing. +fn hardware_axis_labels() -> List { ["memory", "processor"] } + +fn hardware_axis_reserved_width() -> String { + let widest = hardware_longest_len(labels: hardware_axis_labels()) + hardware_column_ch_gutter + css_length_wire(l: css_ch(n: widest)) +} + fn hardware_subject_reserved_width() -> String { let labels = map(fleet_dimm_verdicts, v => dimm_verdict_host(verdict: v) as String) let widest = hardware_longest_len(labels: labels) + hardware_column_ch_gutter diff --git a/dag/gunbc/roadmap_style.dag b/dag/gunbc/roadmap_style.dag index 4f28d5f2855..5a2c2e3347f 100644 --- a/dag/gunbc/roadmap_style.dag +++ b/dag/gunbc/roadmap_style.dag @@ -29,7 +29,8 @@ import gunbc.design.state_response { RestBinding, StateClassBinding, } import gunbc.fleet_hardware_standing_panel { - hardware_subject_reserved_width, hardware_standing_reserved_width, + hardware_subject_reserved_width, hardware_axis_reserved_width, + hardware_standing_reserved_width, } import gunbc.roadmap_component { dispatch_reserved_width, theme_toggle_class, theme_toggle_reserved_width, @@ -529,7 +530,7 @@ fn roadmap_instance_rules_head() -> List { ] }, StaticRule { selector: ClassSelector { name: "hardware-axis" }, decls: [ role_decl(prop: Color, r: TextDimRole), - decl(prop: MinWidth, value: hardware_subject_reserved_width()), + decl(prop: MinWidth, value: hardware_axis_reserved_width()), ] }, StaticRule { selector: ClassSelector { name: "hardware-cell" }, decls: [ decl(prop: FontWeight, value: "600"), diff --git a/dag/test/claim/design_register_lift_parity_witness_test.dag b/dag/test/claim/design_register_lift_parity_witness_test.dag index f39f2d082aa..6abe4cd5b2c 100644 --- a/dag/test/claim/design_register_lift_parity_witness_test.dag +++ b/dag/test/claim/design_register_lift_parity_witness_test.dag @@ -64,9 +64,11 @@ data roadmap_css_repin_a2_hierarchy_note: String = "Re-pinned 2026-08-02 for the data lift_parity_merge_resolution_note: String = "MERGE RESOLUTION, RE-DERIVED NOT RECONCILED (S1 x A2-hierarchy, 2026-08-03). Both branches edited this row block and each moved a DIFFERENT digest: #7701 (A2 hierarchy closeout) moved roadmap_css because it changed the stylesheet, and S1 moved moodboard_thesis_themes because it revised register_thesis. Neither touched the other's surface, so the semantic union is the resolution and no value is a compromise between two claims. The union was nonetheless not TRUSTED: both digests were re-run by execution on the merged tree, because a digest pins emitted bytes and a merge is the one moment when the bytes belong to a tree neither side ever built — picking a side by reasoning about scope is exactly the copied-measurement-as-oracle failure this file's own repin notes disclaim ('derived by execution, never chosen'). The re-run is the oracle; the reasoning above only explains why the re-run was expected to agree." +data roadmap_css_repin_fleet_hardware_axis_width_note: String = "Re-pinned again 2026-08-23 for review 55065: .hardware-axis was taking hardware_subject_reserved_width — copied from the column beside it — so a column carrying the axis words memory and processor was reserved to the width of the longest HOST LABEL (6ch). It now takes hardware_axis_reserved_width, derived from a single hardware_axis_labels authority that the rendered rows read too, and emits 11ch. Behavioral receipt: each_column_reserves_its_own_population, which asserts the two reservations DIFFER and that the subject population cannot hold the axis one — the discriminating fact, since a witness merely re-deriving the axis width from the axis labels would be measure() == measure(). Derived by execution (roadmap_css_derived_digest run 2026-08-23), never chosen." + data roadmap_css_repin_fleet_hardware_standing_note: String = "Re-pinned 2026-08-23 for the daily-workspace fleet hardware standing panel (operator request: live fleet info on the workspace): the roadmap bytes move intentionally — the .fleet-hardware-standing family lands (panel surface, .hardware-heading, .hardware-summary, .hardware-outstanding, .hardware-row, .hardware-subject, .hardware-axis, .hardware-cell and the four standing variants .hardware-confirmed / .hardware-refused / .hardware-misfiled / .hardware-unread, plus .hardware-detail), all role-routed and tokened. The two column reservations are NOT pixels: .hardware-subject/.hardware-axis and .hardware-cell take min-width from gunbc.fleet_hardware_standing_panel hardware_subject_reserved_width and hardware_standing_reserved_width, which derive the longest label each column can wear plus a gutter — emitted as 6ch and 11ch, the latter being the width of 'confirmed', the longest of the four standing words. The refused and misfiled variants reuse the EXISTING var(--band-loud) refused-state vocabulary rather than minting a role: an earlier revision of this change wrote role_decl(r: SalienceRole), which compiled clean and then failed evaluation with NoSuchVariable — SalienceRole is a type in gunbc.design.salience, not a theme role role_decl can take — and it was caught only by serializing the whole page, not by any panel-level witness. Behavioral receipts: test.claim.fleet_hardware_standing_panel_witness_test — every processor row is unread and none confirmed, the memory axis is confirmed on every host as the positive control, the four verdict shapes map to four distinct standings, the summary reports each axis separately and never one fraction, and no outstanding line renders while nothing contradicts. Derived by execution from this tree (roadmap_css_derived_digest run 2026-08-23); this digest only pins bytes, never chosen." -data roadmap_css_lift_parity_digest: String = "9f37abcc65255edf" +data roadmap_css_lift_parity_digest: String = "becaf5e24965215d" data moodboard_thesis_themes_lift_parity_digest: String = "98f0513aebb0dcb3" fn emission_content_digest(s: String) -> String { diff --git a/dag/test/claim/fleet_hardware_standing_panel_witness_test.dag b/dag/test/claim/fleet_hardware_standing_panel_witness_test.dag index f3d70399bb3..7ebd0fc9a61 100644 --- a/dag/test/claim/fleet_hardware_standing_panel_witness_test.dag +++ b/dag/test/claim/fleet_hardware_standing_panel_witness_test.dag @@ -10,6 +10,8 @@ import product.installed_bom_reconcile { DimmCountMatches, DimmCountDiffers, } import gunbc.fleet_hardware_standing_panel { + hardware_axis_labels, hardware_axis_reserved_width, hardware_subject_reserved_width, + hardware_longest_len, dimm_verdict_host, HardwareStanding, HardwareConfirmed, HardwareRefused, HardwareUnread, HardwareMisfiled, hardware_standing_label, dimm_standing, processor_standing, dimm_detail, hardware_axis_summary, standing_count, @@ -133,3 +135,23 @@ test fn no_outstanding_line_while_nothing_contradicts_and_unread_does_not_count( Absent => standing_count(standings: fleet_processor_standings(), wanted: HardwareUnread) == 4 } } + + +// EACH COLUMN RESERVES ITS OWN POPULATION, WHICH IS THE DEFECT REVIEW 55065 CAUGHT. +// +// .hardware-axis took hardware_subject_reserved_width -- copied from the column beside it -- so a +// column carrying "memory" and "processor" was reserved to the width of the longest HOST LABEL. +// Two unrelated populations that happen to be adjacent, and the derivation read the wrong one. +// +// The discriminating fact is that the subject reservation is NOT wide enough for the axis words: +// host labels are four characters and "processor" is nine, so the copy-paste is observable rather +// than merely wrong-looking. A witness asserting only "the axis width is derived from the axis +// labels" would be measure() == measure(); this asserts the two reservations DIFFER and that the +// subject population genuinely cannot hold the axis one, which is what makes the swap detectable. +test fn each_column_reserves_its_own_population() -> Bool { + let longest_axis = hardware_longest_len(labels: hardware_axis_labels()) + let longest_host = hardware_longest_len(labels: map(fleet_dimm_verdicts, v => dimm_verdict_host(verdict: v) as String)) + longest_axis > longest_host + && hardware_axis_reserved_width() != hardware_subject_reserved_width() + && (hardware_axis_labels() |> count) == 2 +}