Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-core/tests/webgl_free_law.rs

//! **LAW 4 for the facett workspace: modern backends only — no GL, anywhere.**
//!
//! Decision 0 (`1fca337`) dropped `Backends::GL` from the runtime mask and
//! Decision 0b (`39dcddc`) purged the `glow` dev-deps, but until 2026-08-22 every
//! SHIPPED binary still *compiled* wgpu-hal's GLES backend, `glow` (54k LOC,
//! 6.9 MB rlib) and `khronos-egl` — because the direct `wgpu` deps carried
//! wgpu's default features (which include `gles`) and every eframe host's `wgpu`
//! feature expanded to `egui-wgpu/default` → `wgpu/default` + `wgpu/webgl`.
//! GFX_V2 V2.8 measured it; the owner decided: flip it. The workspace now has ONE
//! `wgpu` feature list (`[workspace.dependencies]` in the root manifest —
//! default minus `gles`) and this file is the gate that keeps it flipped.
//!
//! | check | what it fails on |
//! |---|---|
//! | [`manifests_never_reopen_the_gl_door`] | a member manifest bypassing the one workspace `wgpu` list, or an `egui-wgpu` dep with default features |
//! | [`no_gl_reaches_a_shipped_binary`] | a **normal** dep edge to `glow` or `khronos-egl` |
//!
//! The DEV graph is out of scope on purpose, and that is a fact, not an
//! oversight: `egui_kittest`'s `wgpu` feature pins `gles` in its own dependency
//! table (a registry crate — unreachable from our manifests short of a fork), so
//! test builds still compile `glow`. Nothing we ship links it; the same
//! ships-only line the rayon law draws for the `dify` screenshot harness.
//!
//! Run: `cargo test -p facett-core --test webgl_free_law`

use facett_core::law;
use std::path::{Path, PathBuf};

fn root() -> PathBuf {
    law::workspace_root(Path::new(env!("CARGO_MANIFEST_DIR")))
}

/// The two crates that exist ONLY under the GL backend. `wgpu-hal`'s `gles`
/// module has no crate boundary of its own; these are its imports, and either
/// re-appearing on a normal edge means `gles` (or `webgl`) got re-enabled.
const GL_CRATES: [&str; 2] = ["glow", "khronos-egl"];

#[test]
fn manifests_never_reopen_the_gl_door() {
    let root = root();

    // (1) The one writer exists and is shaped right: the root manifest's
    // `[workspace.dependencies]` wgpu entry, default-features off, no GL feature.
    let ws = std::fs::read_to_string(root.join("Cargo.toml")).expect("workspace Cargo.toml");
    let wgpu_entry = ws
        .split("\nwgpu = {")
        .nth(1)
        .map(|rest| &rest[..rest.find('}').unwrap_or(rest.len())])
        .expect("the workspace manifest declares THE `wgpu` entry under [workspace.dependencies]");
    assert!(
        wgpu_entry.contains("default-features = false"),
        "the workspace `wgpu` entry lost `default-features = false` — wgpu's default \
         list includes `gles`, which is the GL backend LAW 4 forbids"
    );
    for banned in ["\"gles\"", "\"webgl\"", "\"angle\""] {
        assert!(
            !wgpu_entry.contains(banned),
            "the workspace `wgpu` feature list re-admits {banned} — LAW 4: no GL, anywhere"
        );
    }

    // (2) No member manifest bypasses the one writer with its own versioned
    // `wgpu` dep (that is how the default `gles` came back last time), and no
    // `egui-wgpu` dep runs with default features (its default list ends in
    // `wgpu/default` + `wgpu/webgl`).
    let manifests = law::workspace_manifests(&root);
    assert!(
        manifests.len() > 50,
        "the manifest scan only found {} Cargo.toml files under {} — it is not looking \
         at the workspace",
        manifests.len(),
        root.display(),
    );
    let mut hits: Vec<String> = Vec::new();
    for m in &manifests {
        if *m == root.join("Cargo.toml") {
            continue; // the one writer itself
        }
        let Ok(text) = std::fs::read_to_string(m) else { continue };
        for (i, line) in text.lines().enumerate() {
            let line = line.trim();
            if line.starts_with("wgpu =") && line.contains("version") {
                hits.push(format!(
                    "{}:{} declares its own versioned `wgpu` (use `workspace = true`): {line}",
                    m.display(),
                    i + 1
                ));
            }
            if line.starts_with("egui-wgpu =") && !line.contains("default-features = false") {
                hits.push(format!(
                    "{}:{} `egui-wgpu` with default features (re-enables `wgpu/default` + \
                     `wgpu/webgl`): {line}",
                    m.display(),
                    i + 1
                ));
            }
        }
    }
    assert!(
        hits.is_empty(),
        "LAW 4 violated by OUR OWN MANIFESTS ({} scanned):\n{}",
        manifests.len(),
        hits.join("\n"),
    );
}

#[test]
fn no_gl_reaches_a_shipped_binary() {
    let root = root();

    for krate in GL_CRATES {
        // LIVENESS FIRST — same command, same parser, one flag wider. glow IS in
        // this workspace's dev graph (egui_kittest's `wgpu` feature pins `gles`),
        // so a `None` here means cargo, the command or the parser stopped working
        // and the clean verdict below would be worth nothing.
        let live = law::dep_tree(&root, krate, "normal,dev,build", &[])
            .expect("cargo tree -e normal,dev,build");
        assert!(
            !law::tree_found_nothing(&live),
            "`cargo tree -e normal,dev,build -i {krate}` no longer reaches this workspace \
             at all. Either egui_kittest stopped pinning `gles` (check, then update this \
             guard's liveness arm) or the tree walk stopped reading cargo's output — until \
             that is resolved, the clean answer below is not evidence of anything.",
        );

        // THE VERDICT: no normal edge. This is the exact command the flip was
        // proven with, and the red proof is re-adding wgpu's default features to
        // the workspace entry (captured in GFX_V2 V2.8).
        let shipped = law::dep_tree(&root, krate, "normal", &[]).expect("cargo tree -e normal");
        assert!(
            law::tree_found_nothing(&shipped),
            "LAW 4 violated on a SHIPPED edge: `{krate}` is reachable through NORMAL \
             dependencies, so the GL backend links into what we ship. Chain:\n{}\n\
             Reproduce with `cargo tree -e normal -i {krate} --target all`.",
            law::tree_chain_to_first_party(&shipped, &root)
                .map(|c| c.join(" -> "))
                .unwrap_or_else(|| shipped.lines().take(12).collect::<Vec<_>>().join("\n")),
        );
    }
}

/// **The SOURCE may not branch on the GL backend either** — the third leg of LAW 4,
/// added 2026-08-24.
///
/// The two checks above hold the *dependency* line: no `glow`, no `khronos-egl`, no
/// `wgpu/gles` on a shipped edge. They cannot see the other half of the residue, which is
/// what GFX_V2 §V2.9b actually found:
///
/// > `facett-core/src/render/gpu/adapter_wgpu.rs:163-168` holds an **unreachable**
/// > WebGL2-limits branch (`Backends::GL` never appears in `preferred_backends()`).
///
/// That branch compiled, cost nothing at runtime, and could never fire — and it was still
/// worth removing, because dead code describing a lane the product does not have is a
/// documentation defect with a compiler behind it. A reader finds live-looking WebGL2
/// handling in the adapter policy and concludes there is a GL path to maintain; the next
/// one "fixes" it, and now there is.
///
/// So the shape this fails on is a source line that TESTS FOR or ASKS FOR the GL backend:
/// `wgpu::Backend::Gl`, `Backends::GL`, `downlevel_webgl2_defaults`. Comments are stripped
/// first, deliberately — every one of these names appears in prose across the workspace
/// explaining why GL is gone, and a law that could not be explained in a comment would be
/// obeyed by deleting the explanation.
#[test]
fn no_source_branches_on_the_gl_backend() {
    // The tokens that mean "this code expects a GL adapter to be possible" — SPLIT so
    // they never appear whole in this file. The alternative was to exempt this file from
    // its own scan, and an exempted file is exactly the hole the next real violation hides
    // in: `webgl_free_law.rs` is a plausible place for somebody to park a GL helper.
    // Assembled at runtime, the guard scans itself like every other file and still passes.
    let gl_code_tokens: [String; 4] = [
        format!("Backend{}Gl", "::"),
        format!("Backends{}GL", "::"),
        format!("Backends{}GL_", "::"),
        format!("downlevel{}webgl2", "_"),
    ];

    fn rs_files(dir: &Path, out: &mut Vec<PathBuf>) {
        let Ok(entries) = std::fs::read_dir(dir) else { return };
        for e in entries.flatten() {
            let p = e.path();
            if p.is_dir() {
                if p.file_name().is_some_and(|n| n == "target" || n == ".git") {
                    continue;
                }
                rs_files(&p, out);
            } else if p.extension().is_some_and(|x| x == "rs") {
                out.push(p);
            }
        }
    }

    let root = root();
    let mut files = Vec::new();
    for dir in facett_core::law::source_roots(&root) {
        rs_files(&dir, &mut files);
    }

    // LIVENESS FIRST, and not as decoration: this file's own prose below contains every
    // token in the list, so a scan that read nothing would report a clean workspace, and a
    // scan whose comment-stripping broke would report this file. Both are checked.
    assert!(
        files.len() > 100,
        "the source scan read only {} .rs files under {} — it is not looking at the \
         workspace, so its clean verdict is worth nothing",
        files.len(),
        root.display()
    );

    let mut hits: Vec<String> = Vec::new();
    for file in &files {
        let Ok(text) = std::fs::read_to_string(file) else { continue };
        for (i, raw) in text.lines().enumerate() {
            let code = raw.split("//").next().unwrap_or("");
            for tok in &gl_code_tokens {
                if code.contains(tok.as_str()) {
                    hits.push(format!(
                        "{}:{}: {}",
                        file.strip_prefix(&root).unwrap_or(file).display(),
                        i + 1,
                        raw.trim()
                    ));
                }
            }
        }
    }
    assert!(
        hits.is_empty(),
        "LAW 4: {} source line(s) branch on or request the GL backend, which \
         `preferred_backends()` can never produce (PRIMARY on native, BROWSER_WEBGPU on \
         wasm) and which this workspace no longer compiles at all. Delete the branch — an \
         unreachable GL path reads as a lane somebody has to maintain:\n  {}",
        hits.len(),
        hits.join("\n  ")
    );
}