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

nordisk/facett

facett-demo/tests/roster_gate.rs

//! **THE WORKSPACE ROSTER GATE** — the by-construction fix for the blind spot that
//! left **14 workspace crates out of the gallery** (found 2026-08-20).
//!
//! ## The bug this guards
//! The demo's roster claims ("shows EVERY facett component") were gated against the
//! **umbrella `facett` crate's re-export list** — but a component crate that is not
//! re-exported by the umbrella (facett-cicd, facett-holger, facett-deploykey, …) was
//! invisible to every roster check: in the workspace, released, tested, and never on
//! screen. The umbrella was the wrong denominator.
//!
//! ## The gate
//! The denominator is now the **workspace itself**: parse the root `Cargo.toml`
//! members list, and every member crate named `facett-*` must be either
//!
//! 1. **credited by at least one LEGEND row** — via the same
//!    [`facett_demo::source_links`] extraction that drives each tab's on-screen
//!    `source:` hyperlink (one writer: a row that credits its crate both links it
//!    and satisfies this gate), or
//! 2. **named in [`EXCLUDED`]** with a documented reason (engines, support crates,
//!    and the deliberate non-tabs — each entry says WHY).
//!
//! A new workspace crate that nobody wires then fails this gate **by name**,
//! instead of shipping unseen. The companion tests prove the gate bites (a fake
//! member is rejected) and that the exclusion list cannot go stale (an EXCLUDED
//! crate that is credited, or that leaves the workspace, is RED too).

use std::collections::BTreeSet;

/// The documented exclusions: `facett-*` workspace members that are deliberately
/// NOT a gallery tab, each with the reason. Everything not in this list must be
/// credited by a LEGEND row.
///
/// Engines and support crates are NOT here when a LEGEND row already credits them
/// (facett-core, facett-arrow, facett-cfd, facett-osm, … are credited by the rows
/// of the tabs built on them — the credit is the honest "where it's used" pointer).
const EXCLUDED: &[(&str, &str)] = &[
    (
        "facett-confirm",
        "an ELM gate (Msg/Effect/update), NOT an `impl Facet` — it cannot be a deck \
         tab; the confirm/cancel UX it models is exercised in the `overlay` tab \
         through facett-app's Modal (see the crate-doc 'Not shown here' list)",
    ),
    (
        "facett-build-thing",
        "facett's own BUILD RECIPE (the pip/wheel variant rows the xtask door and the \
         forge read) — build declaration, not a UI component",
    ),
    (
        "facett-dbexplorer",
        "a LIVE-SOURCE explorer: its navigator expands by querying its connections \
         (Arrow batches on demand); the demo carries no database to point it at, and a \
         canned one would show a picture of a browser, not the browser (2026-09-29, \
         already unlisted on main 2450648)",
    ),
    (
        "facett-flowsim",
        "a flow-simulation OVERLAY that rides another component's DAG edges \
         (animated particles) — no standalone data surface to open a tab on; it \
         decorates a host graph the way pop_beauty decorates the population views",
    ),
    (
        "facett-map3d-flight",
        "the AAA planetary flight-sim ENGINE layer (floating origin, 6DOF rig, DEM \
         terrain) — driven by the standalone flight_demo / osm_fly_demo bins and \
         the native-only osm_fly flow, not a deck Facet",
    ),
    (
        "facett-ops",
        "the non-build release VERBS (`cargo ops deploy-pages` / publish-pip / …, lane X \
         2026-10-01) — tooling, not a UI component",
    ),
    (
        "facett-simview",
        "the population Simulate viewer over the bench's live /sim/api — it ships as \
         facet-wrapped's `sim` bundle group, and the demo has no sim server to point it \
         at (the population itself is in the `Sverige` and `Graphs` tabs)",
    ),
    (
        "facett-wasm-demo",
        "the wasm test-harness SUPPORT crate (a dev-dependency of the leaf crates' \
         wasm smoke tests), not a UI component",
    ),
];

/// Every workspace member, parsed from the root `Cargo.toml`'s `members = [...]`
/// list. A parse that finds nothing is a loud failure, never an empty (vacuously
/// green) roster — LAW 2.
fn workspace_members() -> Vec<String> {
    let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().join("Cargo.toml");
    let text = std::fs::read_to_string(&root)
        .unwrap_or_else(|e| panic!("read the workspace manifest {}: {e}", root.display()));
    let start = text.find("members = [").expect("the workspace manifest declares `members = [`");
    let rest = &text[start + "members = [".len()..];
    let end = rest.find(']').expect("the members list closes");
    let members: Vec<String> = rest[..end]
        .split('"')
        .skip(1)
        .step_by(2)
        .map(str::to_string)
        .collect();
    assert!(
        members.len() > 50,
        "parsed only {} workspace members — the parse is broken, not the workspace",
        members.len()
    );
    members
}

/// Every crate dir credited by at least one LEGEND row — derived through the SAME
/// [`facett_demo::source_links`] extraction that renders each tab's `source:`
/// hyperlink, so there is no second key→crate table to drift.
fn credited_dirs() -> BTreeSet<String> {
    let mut out = BTreeSet::new();
    for (key, _) in facett_demo::LEGEND {
        for (dir, _url) in facett_demo::source_links(key) {
            out.insert(dir);
        }
    }
    out
}

/// The gate's pure core: which `facett-*` members are neither credited nor
/// excluded. Split out so [`the_gate_bites_on_an_unwired_member`] can prove it red
/// against an injected fake without touching the real workspace.
fn unwired(members: &[String], credited: &BTreeSet<String>) -> Vec<String> {
    let excluded: BTreeSet<&str> = EXCLUDED.iter().map(|(c, _)| *c).collect();
    members
        .iter()
        .filter(|m| m.starts_with("facett-"))
        .filter(|m| !credited.contains(m.as_str()) && !excluded.contains(m.as_str()))
        .cloned()
        .collect()
}

/// **THE GATE**: every `facett-*` workspace member is credited by a LEGEND row or
/// documented in [`EXCLUDED`]. A new crate nobody wires fails here BY NAME.
#[test]
fn every_facett_workspace_member_is_wired_or_excluded() {
    let members = workspace_members();
    let credited = credited_dirs();
    let missing = unwired(&members, &credited);
    assert!(
        missing.is_empty(),
        "workspace crates in NO LEGEND row and NOT in the documented EXCLUDED list — \
         the gallery claims to show every component, so wire each as a tab (credit \
         its crate in the LEGEND description, `… — facett-xxx::Type`) or add it to \
         EXCLUDED in tests/roster_gate.rs with a reason: {missing:?}"
    );
}

/// **RED-PROOF** (LAW 2): the gate actually bites — an injected member that no
/// LEGEND row credits and no exclusion names is reported, by name.
#[test]
fn the_gate_bites_on_an_unwired_member() {
    let mut members = workspace_members();
    members.push("facett-unwired-widget".to_string());
    let missing = unwired(&members, &credited_dirs());
    assert_eq!(
        missing,
        vec!["facett-unwired-widget".to_string()],
        "the gate must name exactly the injected unwired crate"
    );
}

/// The exclusion list cannot go STALE: every `EXCLUDED` entry must (a) still be a
/// workspace member — an entry for a deleted crate is dead weight that would mask a
/// future name reuse — and (b) NOT be credited by any LEGEND row — a crate that got
/// wired keeps its exclusion only by mistake, and the stale reason would then
/// contradict the on-screen source link.
#[test]
fn the_exclusion_list_is_live_and_not_redundant() {
    let members: BTreeSet<String> = workspace_members().into_iter().collect();
    let credited = credited_dirs();
    for (crate_name, reason) in EXCLUDED {
        assert!(
            members.contains(*crate_name),
            "EXCLUDED names `{crate_name}` but it is no longer a workspace member — remove the entry (reason was: {reason})"
        );
        assert!(
            !credited.contains(*crate_name),
            "EXCLUDED names `{crate_name}` but a LEGEND row now credits it — it is wired, so remove the stale exclusion"
        );
    }
}