crates/knut-popviz/tests/law4_no_opengl_backend.rs
//! **LAW #4 — the shipped desktop GUI renders on WebGPU, never OpenGL.**
//!
//! The nordisk rule is "modern platforms only: WebGPU everywhere, no WebGL/glow". This
//! crate broke it *silently* and for a long time, in a way no compiler and no runtime
//! check could catch:
//!
//! * `Cargo.toml` listed `eframe = { features = ["glow", …] }` as a REAL (non-dev)
//! dependency behind `gui`;
//! * `main.rs` passes a bare `eframe::NativeOptions::default()`, and eframe resolves
//! `Renderer::default()` to **`Glow`** whenever its `glow` feature is enabled
//! (eframe 0.34.3, `epi.rs`).
//!
//! So the backend was chosen by a feature flag in a manifest, the source said nothing
//! about it, and `glow v0.17` was linked into the shipped binary twice — directly and
//! through `egui_glow`. Nothing in the tree stated which renderer shipped, so nothing
//! could disagree with it.
//!
//! This test is the missing statement. It reads the manifests — the things that actually
//! decide — and asserts no non-comment line in any of them so much as names `glow`, and
//! that every `eframe` declaration asks for `wgpu` explicitly.
//!
//! Manifest-reading is the point: an `eframe::Renderer` assertion would need a window, and
//! a dependency-*tree* assertion would trip over `wgpu-hal`'s internal GLES backend, which
//! is a legitimately different thing (`glow` reachable *under* `wgpu-hal` is not a
//! violation; `glow` reachable via `eframe`/`egui_glow` is). Sibling guards of the same
//! shape live in `korp/tests/`, `nornir/tests/` and `holger/server/ui/tests/`.
//!
//! # Two holes this file used to have, both measured on 2026-08-01
//!
//! The first version of this guard walked `crates/*/Cargo.toml` — one level — and checked
//! only the `eframe` line. Two mutations proved it blind while glow was genuinely present:
//!
//! 1. **Location.** `eframe = { features = ["glow"] }` appended to `xtask/Cargo.toml` —
//! outside `crates/` — and the guard reported `ok`. knut's root manifest, `xtask/`, the
//! vendored tree, and the workspace-`exclude`d `crates/knut-bifrost/wasm-guest` were all
//! unreachable by that walk, and the file's own doc claimed it "covers the WHOLE
//! workspace".
//! 2. **Vector.** `glow = "0.17"` plus `egui_glow` added straight to knut-popviz's
//! `[dependencies]`, and the guard reported `ok` in the same cargo run that printed
//! `Compiling glow v0.17.0` — glow linked, guard green. Checking one dependency's
//! feature list can only ever catch one of the ways glow gets in.
//!
//! Both are closed by construction rather than by two more special cases (LAW #5): ONE
//! tree walk that reaches every `Cargo.toml` in the repo, and ONE rule — **the substring
//! `glow` may not appear in any non-comment line of any manifest.** That is airtight
//! against every reintroduction vector at once: a feature (`features = ["glow"]`), a
//! direct dep (`glow = "0.17"`), a wrapper (`egui_glow`), a table header
//! (`[dependencies.glow]`), a forwarded feature (`gui = ["eframe/glow"]`) and a
//! target-gated duplicate of any of them. Comments are excluded, so the prose ABOUT glow
//! in knut's manifests can neither satisfy nor trip the guard.
//!
//! RED when someone re-adds `glow` anywhere, or drops `wgpu`, in any manifest in the repo.
use std::path::PathBuf;
/// The repo root — the directory whose `Cargo.toml` declares `[workspace]`.
///
/// `CARGO_MANIFEST_DIR` is set by cargo, so this works from any working directory, any
/// worktree and any workspace layout.
fn repo_root() -> PathBuf {
let mut root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
while !std::fs::read_to_string(root.join("Cargo.toml"))
.is_ok_and(|s| s.lines().any(|l| l.trim() == "[workspace]"))
{
assert!(
root.pop(),
"walked past the filesystem root without finding [workspace]"
);
}
root
}
/// Every `Cargo.toml` in the repo, as `(path relative to root, contents)`.
///
/// This walks the whole tree rather than the `[workspace] members` list, and that is
/// deliberate twice over. knut's root manifest **excludes**
/// `crates/knut-bifrost/wasm-guest` (a self-rooting wasm32 crate), so a members-driven
/// walk would skip a real crate; and the previous `crates/*` walk skipped the root
/// manifest and `xtask/` entirely, which is measured hole #1 above. Walking the tree means
/// the next manifest to declare a GUI stack is covered the moment it lands, by
/// construction, wherever it lands.
fn all_manifests() -> Vec<(String, String)> {
let root = repo_root();
let mut out = Vec::new();
let mut stack = vec![root.clone()];
while let Some(dir) = stack.pop() {
let Ok(entries) = std::fs::read_dir(&dir) else {
continue;
};
for e in entries.flatten() {
let p = e.path();
let name = e.file_name().to_string_lossy().into_owned();
if p.is_dir() {
// Skip build output, git internals and agent worktrees. A `target/` tree
// holds thousands of unrelated manifests, and a `.claude/worktrees/`
// checkout is a DIFFERENT commit of this same repo whose manifest must not
// be able to fail (or rescue) this guard. `vendor/` is NOT skipped: it is
// compiled into knut's binaries by path, so glow arriving there would be a
// real violation of the shipped tree.
if matches!(
name.as_str(),
"target" | ".git" | ".claude" | "node_modules"
) {
continue;
}
stack.push(p);
} else if name == "Cargo.toml" {
if let Ok(src) = std::fs::read_to_string(&p) {
let rel = p
.strip_prefix(&root)
.unwrap_or(&p)
.to_string_lossy()
.into_owned();
out.push((rel, src));
}
}
}
}
out.sort();
// Non-vacuity floor: if the walk finds nothing, every loop over it passes having
// inspected nothing — precisely the silent green this file exists to prevent. knut has
// 17 manifests today (15 workspace members + the excluded wasm-guest + the vendored
// spark tree).
assert!(
out.len() >= 15,
"found only {} Cargo.toml files under {} — the walk is broken, and a broken walk \
makes this guard pass while checking nothing. Found: {:?}",
out.len(),
root.display(),
out.iter().map(|(p, _)| p).collect::<Vec<_>>()
);
out
}
/// The non-comment lines of a manifest — the ones that actually configure cargo.
///
/// Comment-stripping is load-bearing in both directions: knut's manifests carry paragraphs
/// of prose about why glow is forbidden, and that prose must neither trip the guard nor be
/// mistakable for a dependency declaration.
fn effective_lines(src: &str) -> Vec<&str> {
src.lines()
.map(str::trim)
.filter(|l| !l.starts_with('#') && !l.is_empty())
.collect()
}
/// Every `eframe = { … }` dependency line in a manifest.
///
/// Returns every match, not the first: a manifest can grow a second, target-gated eframe
/// line (nornir's `nornir-viz-web` has exactly that shape — one for wasm32 and one for
/// native), and a `find()` would silently check only one of them.
fn eframe_lines(src: &str) -> Vec<String> {
effective_lines(src)
.into_iter()
.filter(|l| l.starts_with("eframe"))
.map(str::to_owned)
.collect()
}
/// Every non-comment line that names `glow` — a LAW #4 violation in any form.
fn glow_lines(src: &str) -> Vec<String> {
effective_lines(src)
.into_iter()
.filter(|l| l.contains("glow"))
.map(str::to_owned)
.collect()
}
#[test]
fn no_manifest_in_the_repo_names_glow_outside_a_comment() {
let manifests = all_manifests();
// Non-vacuity for measured hole #1: the walk must reach the three places the previous
// `crates/*` walk could not see. If it ever regresses to a one-level walk, these fail
// immediately and by name instead of the guard quietly narrowing.
for required in [
"Cargo.toml",
"xtask/Cargo.toml",
"crates/knut-bifrost/wasm-guest/Cargo.toml",
] {
assert!(
manifests.iter().any(|(p, _)| p == required),
"the walk did not reach {required} — that is measured hole #1 (a glow-featured \
eframe line appended to xtask/Cargo.toml passed this guard on 2026-08-01). \
Reached: {:?}",
manifests.iter().map(|(p, _)| p).collect::<Vec<_>>()
);
}
// Non-vacuity: count what was actually inspected. An empty or line-less read is shaped
// exactly like a clean tree.
let mut lines_scanned = 0usize;
let mut offenders: Vec<String> = Vec::new();
for (path, src) in &manifests {
lines_scanned += effective_lines(src).len();
for line in glow_lines(src) {
offenders.push(format!("{path}: {line}"));
}
}
assert!(
lines_scanned > 200,
"only {lines_scanned} non-comment manifest lines inspected across {} manifests — \
too few to be knut's real tree, and a guard that reads nothing passes",
manifests.len()
);
assert!(
offenders.is_empty(),
"LAW #4: no manifest in knut may name `glow` outside a comment — not as an eframe \
feature, not as a direct dependency, not as `egui_glow`, not in a \
`[dependencies.glow]` table and not behind a target gate. eframe resolves \
`Renderer::default()` to `Glow` whenever its `glow` feature is on, so one word in \
a manifest decides that the shipped desktop binary is OpenGL with nothing in the \
source saying so; and a direct `glow` edge links a whole second GL backend into \
the binary regardless of which renderer runs. ({lines_scanned} lines inspected.) \
Offending lines:\n {}",
offenders.join("\n ")
);
}
#[test]
fn every_eframe_declaration_asks_for_wgpu_explicitly() {
let mut checked: Vec<String> = Vec::new();
for (path, src) in all_manifests() {
for line in eframe_lines(&src) {
checked.push(path.clone());
assert!(
line.contains("\"wgpu\""),
"LAW #4: {path} must ASK for the WebGPU backend explicitly. Dropping both \
eframe backends is a `compile_error!` in eframe, so an eframe line naming \
neither cannot be right. Offending line:\n {line}"
);
// `default-features = false` is what keeps the choice explicit rather than
// inherited from whatever eframe's defaults happen to bring.
assert!(
line.contains("default-features = false"),
"{path}'s eframe dep must pin `default-features = false` so the renderer is \
the one this line names, not whatever eframe's defaults bring. Offending \
line:\n {line}"
);
}
}
// Non-vacuity: the two crates that declare eframe today are `knut-popviz` and
// `knut-pipelines`. If this list ever comes back empty or shrinks, the loop above
// proved nothing — which is the failure mode this whole file exists to make impossible.
assert!(
checked.len() >= 2,
"expected at least the two known eframe crates (knut-popviz, knut-pipelines); \
inspected {checked:?} — an empty or shrunken list means the detector stopped \
finding dependency lines, not that the violations were fixed"
);
}
/// **The guard is not blind: prove each detector fires on the shape it exists to catch.**
///
/// A manifest-reading test is exactly the kind that quietly stops working — a renamed key,
/// a reformatted table or an over-eager comment filter and it inspects nothing while still
/// reporting `ok`. Every constant below is a line that was really run against the real
/// guard on 2026-08-01, including the two shapes it passed.
#[test]
fn the_guard_itself_can_report_red() {
// ── The original violation, verbatim from knut-popviz's own history ───────────────
const BEFORE: &str = r#"eframe = { version = "0.34", default-features = false, features = ["glow", "wayland", "x11"], optional = true }"#;
const AFTER: &str = r#"eframe = { version = "0.34", default-features = false, features = ["default_fonts", "wgpu", "wayland", "x11"], optional = true }"#;
assert_eq!(
glow_lines(BEFORE).len(),
1,
"the detector must see glow in the pre-fix line"
);
assert!(
glow_lines(AFTER).is_empty(),
"the post-fix line must carry no glow"
);
assert!(
AFTER.contains("\"wgpu\""),
"the post-fix line must ask for wgpu"
);
// korp's shape is the HARDEST, and the reason the glow check and not the wgpu check is
// doing the work: korp's pre-fix line already asked for wgpu, so a wgpu-only guard
// reported korp green for two months while glow was linked.
const BOTH_BACKENDS: &str = r#"eframe = { version = "0.34", default-features = false, features = ["glow", "wgpu", "wayland", "x11"] }"#;
assert!(
BOTH_BACKENDS.contains("\"wgpu\"") && glow_lines(BOTH_BACKENDS).len() == 1,
"a line asking for BOTH backends is still a violation, and only the glow check \
catches it"
);
// `knut-pipelines`' pre-fix line — a DIFFERENT eframe major (0.28, pinned there by
// egui-snarl 0.4), so the detector is proven against both shapes it had to catch.
const PIPELINES_BEFORE: &str = r#"eframe = { version = "0.28", default-features = false, features = ["glow", "wayland", "x11"], optional = true }"#;
assert_eq!(
glow_lines(PIPELINES_BEFORE).len(),
1,
"must fire on the 0.28-line shape too"
);
assert_eq!(
eframe_lines(&format!("[dependencies]\n{PIPELINES_BEFORE}\n")),
vec![PIPELINES_BEFORE.to_owned()],
"the extractor must pull that line intact from a manifest body"
);
// ── Measured hole #2: the vectors the eframe-feature check could not see ──────────
// The first two passed the previous guard for real; `glow = "0.17"` did so in the same
// cargo run that printed `Compiling glow v0.17.0`.
for vector in [
r#"glow = "0.17""#,
r#"egui_glow = { version = "0.34", optional = true }"#,
r#"egui-glow = "0.34""#,
r#"[dependencies.glow]"#,
r#"gui = ["dep:eframe", "eframe/glow"]"#,
r#"egui = { version = "0.34", features = ["glow"] }"#,
r#"glow.workspace = true"#,
] {
assert_eq!(
glow_lines(vector).len(),
1,
"the glow detector must fire on `{vector}` — every one of these links glow \
while an eframe-feature-only guard reports ok"
);
// And prove it is NOT the eframe check catching them: that check is blind here.
assert!(
eframe_lines(vector).is_empty(),
"`{vector}` is not an eframe line, so only the glow rule can catch it"
);
}
// ── The comment filter must be doing real work in both directions ─────────────────
let commented =
"[dependencies]\n# eframe = { features = [\"glow\"] }\n# see glow\nserde = \"1\"\n";
assert!(
glow_lines(commented).is_empty(),
"the extractor must ignore comments — otherwise the prose explaining why glow is \
forbidden could itself trip the guard"
);
assert!(
eframe_lines(commented).is_empty(),
"a manifest whose only mention of eframe is a comment declares no eframe"
);
// …and the filter must not swallow real lines that merely sit under prose.
assert_eq!(
glow_lines("# LAW 4 forbids glow\nglow = \"0.17\"\n").len(),
1,
"stripping comments must not strip the declaration under them"
);
// ── And it is the LIVE tree being read, not only these constants ──────────────────
let manifests = all_manifests();
let popviz = manifests
.iter()
.find(|(p, _)| p == "crates/knut-popviz/Cargo.toml")
.expect("the walk must reach knut-popviz's own manifest");
let live = eframe_lines(&popviz.1);
assert_eq!(
live.len(),
1,
"knut-popviz declares exactly one eframe line: {live:?}"
);
assert!(
live[0].contains("\"wgpu\""),
"live manifest asks for wgpu: {}",
live[0]
);
assert!(
glow_lines(&popviz.1).is_empty(),
"live manifest names no glow outside a comment"
);
// The prose about glow really is present in that file, so the comment filter above is
// exercised against the live tree and not only against a constructed string.
assert!(
popviz
.1
.lines()
.filter(|l| l.trim().starts_with('#') && l.contains("glow"))
.count()
>= 3,
"knut-popviz's manifest documents why glow is forbidden; if that prose is gone, the \
comment filter is no longer exercised against a real file"
);
}