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

nordisk/dwarves

dwarves-gui/tests/robot_jera_wire.rs

//! **ROBOT-UI: the 🧬 Jera tab reads the job ledger OVER THE WIRE, not off a path.**
//!
//! The rule is written one line above the answer in
//! `edda/crates/nornir-wire/proto/nornir.proto:981-983`:
//!
//! > the server holds the redb lock, **SO CLIENTS GO THROUGH HERE.**
//!
//! The tab used to open `jobs.redb` at a filesystem path derived from the UI's own
//! `$HOME`. This file is the red-before-green for moving it onto `Viz.Jobs`, and it also
//! **corrects the standing diagnosis of why the file road fails**, because getting that
//! wrong would have sent the next lane after the wrong bug.
//!
//! ## What was measured, and what the received diagnosis got wrong
//!
//! The received diagnosis was: *`jobs.redb` is held open by the running server, redb
//! takes an EXCLUSIVE lock, and `JobStore::open_read_only` is called "lock-tolerant"
//! but is not — that comment is a false claim in the code.*
//!
//! Measured here, in [`the_lock_is_not_what_breaks_the_file_road`], and reproduced on
//! t14s 2026-08-25:
//!
//! | probe | result |
//! |---|---|
//! | a second plain `JobStore::open` against a live writer | `Database already open. Cannot acquire lock.` |
//! | `JobStore::open_read_only` against the SAME live writer | **Ok** — it copies the file aside and opens the copy |
//! | `open_read_only` on a ledger the reader cannot WRITE | `I/O error: Permission denied (os error 13)` |
//!
//! So `open_read_only` **is** lock-tolerant and the comment is **true**. What breaks the
//! file road is ownership, not locking: `open` routes through `redb::Database::create`,
//! so a `-rw-r--r--` ledger owned by another user fails before jera's `is_lock_error` is
//! consulted and the snapshot fallback never runs. The installed forge runs as user
//! `dwarves`; a UI a human started does not. On top of that the snapshot that makes it
//! lock-tolerant is a whole-file byte copy paid on **every** read, at a 2 s cadence, and
//! the path the UI would derive is the forge's own ledger, not the served workspace's.
//!
//! ## The tests
//!
//! 1. [`the_lock_is_not_what_breaks_the_file_road`] — the three probes above, run.
//! 2. [`red_the_file_road_cannot_read_it_green_the_wire_can`] — THE red/green. One
//!    ledger, unreadable to this process the way the forge's is; the FILE road paints
//!    "could not READ" and zero jobs, the WIRE road paints the rows. Same tab type, same
//!    frame, one seam swapped.
//! 3. [`viz_jobs_really_travels_the_wire`] — a sentinel `job_id` no local read could
//!    synthesise comes back through the shipped pane, and the client stamps the selected
//!    workspace as the `nornir-workspace` header.
//! 4. [`a_forge_that_does_not_proxy_viz_is_a_NAMED_failure_never_zero_jobs`] — the state
//!    this repo is in until the forge grows the `Viz` proxy: `Unimplemented` must read
//!    as an outage, never as an idle forge.
//! 5. [`a_failed_refresh_keeps_the_previous_reading_and_names_the_failure`] — the two
//!    properties seven panes in this repo hold.
//! 6. [`a_read_in_flight_is_named_and_does_not_blank_the_previous_reading`].
//! 7. [`an_empty_answer_is_idle_over_the_wire_and_never_the_fixture`] — "no answer" and
//!    "no jobs" stay different values (`1aa8f0f`: a deleted workspace once PAINTED
//!    invented jobs).
//!
//! Each check emits a `nornir-testmatrix` `functional_status` cell under
//! `--features testmatrix` (reuse edda; never a hand-rolled ledger).

use std::sync::{Arc, Mutex};
use std::time::Duration;

use dwarves_gui::jera::{JeraTab, JobsRead, LedgerJobs, WireJobs};
use facett_core::Facet;
use nornir_warehouse_embed::testkit::{spawn_mock_viz, Code, MockViz};

#[allow(unused_variables)]
fn matrix(check: &str, ok: bool, detail: &str) {
    #[cfg(feature = "testmatrix")]
    nornir_testmatrix::functional_status("dwarves-gui", check, ok, detail);
}

/// A jera `JobRecord` as `Viz.Jobs` serializes it. `nornir::jobs` is a re-export of
/// `jera::jobs`, so this is the SAME type the file road decodes — not a twin.
fn record(job_id: &str, kind: &str, status: &str) -> serde_json::Value {
    serde_json::json!({
        "job_id": job_id,
        "kind": kind,
        "target": "dwarves@a1b2c3d4",
        "workspace": "nordisk",
        "status": status,
        "ts_start_micros": 1_700_000_000_000_000i64,
        "ts_end_micros": null,
        "elapsed_ms": null,
        "detail_json": "",
        "result_ref": "",
    })
}

/// Render a `JeraTab` headless and return whether the given text is on screen.
fn painted(tab: &mut JeraTab, needle: &str) -> bool {
    use nornir_robotui::egui_kittest::kittest::Queryable;
    let cell = std::cell::RefCell::new(tab);
    let mut h = nornir_robotui::egui_kittest::Harness::builder()
        .with_size(egui::vec2(1400.0, 900.0))
        .build_ui(|ui| Facet::ui(*cell.borrow_mut(), ui));
    h.step();
    h.step();
    // `query_all_*`, not `query_*`: a job KIND legitimately appears twice on this surface
    // (once in its row, once in the reused JobList's kind filter), and the single-node
    // query PANICS on two matches — which would turn a correctly-rendered job into a test
    // failure.
    let hit = h.query_all_by_label_contains(needle).next().is_some();
    hit
}

/// Write a real jera ledger at `root` carrying one finished job, then close it.
fn seed_ledger(root: &std::path::Path) {
    let store = jera::jobs::JobStore::open(root).expect("open ledger");
    store
        .start(
            "lens",
            "change_risk @nordisk",
            "nordisk",
            serde_json::json!({}),
        )
        .finish(serde_json::json!({ "rows": 1 }), "");
    drop(store);
}

/// **1 — THE LOCK IS NOT WHAT BREAKS THE FILE ROAD.**
///
/// Run the three probes the received diagnosis rested on. This test exists because the
/// diagnosis named the wrong mechanism *and* condemned a true comment: acting on it would
/// have deleted `read_ledger_jobs`' accurate `lock-tolerant` doc line and left the real
/// failure — file ownership — undiagnosed for the next lane.
///
/// RED-when-broken in BOTH directions: if `open_read_only` ever stops snapshotting past a
/// live writer, probe (b) goes red; if it ever starts coping with a read-only file, probe
/// (c) does, and the wire's justification changes.
#[test]
fn the_lock_is_not_what_breaks_the_file_road() {
    use jera::jobs::{JobSelector, JobStore};

    // (a) A second PLAIN open against a live writer really is refused by redb.
    let d = tempfile::tempdir().unwrap();
    seed_ledger(d.path());
    let _writer = JobStore::open(d.path()).expect("the live writer");
    let plain = JobStore::open(d.path());
    let locked = plain
        .as_ref()
        .err()
        .map(|e| format!("{e:#}"))
        .unwrap_or_default();
    let a_ok = plain.is_err() && locked.contains("Cannot acquire lock");
    assert!(
        a_ok,
        "a second plain open must be refused by redb's exclusive lock: {locked}"
    );

    // (b) …and `open_read_only` COPES with exactly that, by snapshotting the file aside.
    //     This is the claim the received diagnosis said was false. It is true.
    let ro = JobStore::open_read_only(d.path());
    let b_ok = ro
        .as_ref()
        .ok()
        .map(|s| s.list(&JobSelector::All).map(|v| v.len()).unwrap_or(0))
        == Some(1);
    assert!(
        b_ok,
        "`open_read_only` IS lock-tolerant — it read past a live exclusive writer: {:?}",
        ro.err().map(|e| format!("{e:#}"))
    );
    drop(_writer);

    // (c) What it does NOT cope with is a ledger this process may read but not WRITE —
    //     the shape the installed forge leaves behind (`-rw-r--r--`, owner `dwarves`).
    let d2 = tempfile::tempdir().unwrap();
    seed_ledger(d2.path());
    let p = d2.path().join("jobs.redb");
    let mut perms = std::fs::metadata(&p).unwrap().permissions();
    std::os::unix::fs::PermissionsExt::set_mode(&mut perms, 0o444);
    std::fs::set_permissions(&p, perms).unwrap();
    let denied = JobStore::open_read_only(d2.path())
        .err()
        .map(|e| format!("{e:#}"))
        .unwrap_or_default();
    let c_ok = denied.contains("Permission denied");
    assert!(
        c_ok,
        "the file road's real failure is OWNERSHIP, not the lock — expected a permission \
         error from `Database::create`, got: {denied:?}"
    );

    let ok = a_ok && b_ok && c_ok;
    matrix(
        "jera_file_road_fails_on_ownership_not_the_lock",
        ok,
        "measured: a 2nd plain JobStore::open is refused by redb's exclusive lock, but \
         open_read_only READS PAST IT by snapshotting the file aside (so its `lock-tolerant` \
         doc line is TRUE); what it cannot do is open a ledger it may read but not write \
         (Permission denied os error 13) — which is exactly the -rw-r--r-- the forge, \
         running as user `dwarves`, leaves for a UI that does not",
    );
}

/// **2 — RED: the FILE road cannot read it. GREEN: the WIRE can.**
///
/// One ledger, in the state the forge's actually is (readable bytes, not writable by this
/// reader). The FILE-road tab paints its honest "could not READ" and zero jobs; the
/// WIRE-road tab, against a server serving that ledger's rows, paints the rows. Same tab
/// type, same rendered surface, one seam swapped — which is the whole change.
#[test]
fn red_the_file_road_cannot_read_it_green_the_wire_can() {
    let d = tempfile::tempdir().unwrap();
    seed_ledger(d.path());
    let p = d.path().join("jobs.redb");
    let mut perms = std::fs::metadata(&p).unwrap().permissions();
    std::os::unix::fs::PermissionsExt::set_mode(&mut perms, 0o444);
    std::fs::set_permissions(&p, perms).unwrap();

    // ── RED ── the road the tab used to take.
    let mut file_tab = JeraTab::live(d.path().to_path_buf());
    let red = file_tab.state_json();
    let red_ok = red["source"] == "unreadable" && red["job_count"] == 0;
    assert!(
        red_ok,
        "the FILE road must fail on this ledger — that is the bug being fixed: {red}"
    );
    // …and it fails LOUDLY, never as a blank list.
    assert!(
        painted(&mut file_tab, "could not READ"),
        "a file road that cannot read must SAY so: {}",
        red["source_headline"]
    );
    // Never the fixture. `1aa8f0f`: an unreadable/absent ledger once painted invented jobs.
    assert!(
        !painted(&mut file_tab, "cargo-build"),
        "no fixture job on a failed read"
    );

    // ── GREEN ── the same ledger's rows, served by the server that holds it.
    let srv = spawn_mock_viz(MockViz {
        jobs: serde_json::json!([record("j-1", "lens", "done")]).to_string(),
        ..Default::default()
    });
    let mut wire_tab = JeraTab::wire(&srv.endpoint, "", "nordisk");
    wire_tab.refresh();
    let green = wire_tab.state_json();
    let green_ok = green["source"] == "ledger" && green["job_count"] == 1;
    assert!(
        green_ok,
        "the WIRE road reads the same ledger the file road could not: {green}"
    );
    assert_eq!(
        green["error"],
        serde_json::Value::Null,
        "a good read clears the failure"
    );

    let ok = red_ok && green_ok;
    matrix(
        "jera_tab_reads_the_ledger_over_viz_jobs",
        ok,
        "red/green on ONE ledger in the state the installed forge leaves it (readable, not \
         writable by the UI's user): JeraTab::live (the file road) lands `unreadable`/0 jobs \
         and paints `could not READ`, while JeraTab::wire over /nornir.v1.Viz/Jobs lands \
         `ledger`/1 job — same pane, same surface, the read seam swapped",
    );
}

/// **3 — `Viz.Jobs` really travels the wire, and carries the selected workspace.**
///
/// The sentinel `job_id` is a value no ledger on this box holds, so seeing it in the
/// pane's rendered job tree proves the row crossed the socket. The header assertion is
/// the other half: the server picks the workspace off `nornir-workspace`, so a client
/// that forgot to stamp it would silently read whatever the server defaults to.
#[test]
fn viz_jobs_really_travels_the_wire() {
    let seen: Arc<Mutex<Vec<String>>> = Arc::default();
    let srv = spawn_mock_viz(MockViz {
        jobs: serde_json::json!([
            record("j-42", "over-wire-release", "failed"),
            record("j-43", "over-wire-bench", "running"),
        ])
        .to_string(),
        seen_workspaces: Arc::clone(&seen),
        ..Default::default()
    });

    let mut tab = JeraTab::wire(&srv.endpoint, "", "nordisk");
    tab.refresh();
    let s = tab.state_json();
    let count_ok = s["job_count"] == 2;
    // The sentinel is on the RENDERED surface, not merely in a field.
    let painted_ok = painted(&mut tab, "over-wire-release");
    // And the honest per-status roll-up the shared JeraCentral derives came from the wire.
    let status_ok = s["failed"] == 1 && s["running"] == 1;
    let ws_ok =
        seen.lock().unwrap().iter().all(|w| w == "nordisk") && !seen.lock().unwrap().is_empty();

    assert!(
        count_ok && painted_ok,
        "the server's rows reach the pane's tree: {s}"
    );
    assert!(
        status_ok,
        "the wire rows keep their status through the SAME JobRecord mapper: {s}"
    );
    assert!(
        ws_ok,
        "the client stamps the selected workspace: {:?}",
        seen.lock().unwrap()
    );

    let ok = count_ok && painted_ok && status_ok && ws_ok;
    matrix(
        "jera_viz_jobs_crosses_the_socket",
        ok,
        "a sentinel job_id no local ledger holds is rendered by the shipped pane, its \
         failed/running roll-up survives the SAME jera JobRecord -> JobEntry mapper the \
         file road uses, and every call carried `nornir-workspace: nordisk`",
    );
}

/// **4 — a forge that does not proxy `Viz` yet is a NAMED failure, never zero jobs.**
///
/// This is the state of `main` at the time of writing: the dwarves forge proxies
/// Warehouse / Workspaces / Mímir / Telemetry / Bench / Funnel and not `Viz`, so its gRPC
/// router answers `Unimplemented` on `/nornir.v1.Viz/Jobs`. That must reach the operator
/// as an outage with a name. If it read as "0 jobs · the forge is idle" the missing proxy
/// would be invisible — the precise shape of the bug `1aa8f0f` cost a workspace to find.
#[test]
#[allow(non_snake_case)]
fn a_forge_that_does_not_proxy_viz_is_a_NAMED_failure_never_zero_jobs() {
    let srv = spawn_mock_viz(MockViz {
        refuse: Some((Code::Unimplemented, "unknown service nornir.v1.Viz".into())),
        ..Default::default()
    });
    let mut tab = JeraTab::wire(&srv.endpoint, "", "nordisk");
    tab.refresh();
    let s = tab.state_json();

    let named = s["error"].as_str().unwrap_or_default().to_string();
    let named_ok = named.contains("transport cannot carry it") || named.contains("Unimplemented");
    let not_idle_ok = s["source"] != "idle";
    assert!(
        named_ok,
        "an unproxied verb must be NAMED, got error={named:?} state={s}"
    );
    assert!(not_idle_ok, "…and must never read as an idle forge: {s}");
    assert!(
        painted(&mut tab, "FAILED"),
        "the outage is on the rendered surface"
    );

    // A dead endpoint is the other named outage, and a different one.
    drop(srv);
    let mut dead = JeraTab::wire("http://127.0.0.1:1", "", "nordisk");
    dead.refresh();
    let ds = dead.state_json();
    let dead_ok = ds["error"]
        .as_str()
        .unwrap_or_default()
        .contains("unreachable")
        && ds["source"] != "idle";
    assert!(
        dead_ok,
        "a dead forge is `unreachable`, not an idle one: {ds}"
    );

    let ok = named_ok && not_idle_ok && dead_ok;
    matrix(
        "jera_outage_is_named_never_idle",
        ok,
        "Unimplemented (the forge's router before it proxies nornir.v1.Viz) and a dead \
         socket each surface as their own named outage in `error` with source != idle — \
         an unreachable server and an empty ledger never draw the same",
    );
}

/// **5 — a failed refresh keeps the PREVIOUS reading and NAMES the failure.**
///
/// The two properties seven panes in this repo already hold. A refresh that fails must
/// not blank a good job list: the operator loses real information and gains a picture
/// indistinguishable from a quiet forge.
#[test]
fn a_failed_refresh_keeps_the_previous_reading_and_names_the_failure() {
    // A source that answers once, then fails forever — the shape of a server going away
    // under a pane that already has a reading.
    struct FlakySource {
        calls: Mutex<usize>,
    }
    impl dwarves_gui::jera::JeraJobSource for FlakySource {
        fn read(&self, _limit: usize, _kind: &str) -> JobsRead {
            let mut n = self.calls.lock().unwrap();
            *n += 1;
            if *n == 1 {
                JobsRead::Rows(
                    dwarves_embed::entries_from_records_json(&[record(
                        "j-first",
                        "first-good-read",
                        "done",
                    )])
                    .unwrap(),
                )
            } else {
                JobsRead::Failed("nornir-server unreachable: connect refused".into())
            }
        }
        fn describe(&self) -> String {
            "flaky test source".into()
        }
    }

    let mut tab = JeraTab::with_source(Arc::new(FlakySource {
        calls: Mutex::new(0),
    }));
    let first = tab.state_json();
    assert_eq!(first["job_count"], 1, "the good reading landed: {first}");

    tab.refresh(); // …and now it fails.
    let after = tab.state_json();
    let kept_ok = after["job_count"] == 1;
    let named_ok = after["error"]
        .as_str()
        .unwrap_or_default()
        .contains("unreachable");
    let stale_ok = after["stale"] == true;
    assert!(
        kept_ok,
        "a failed refresh must NOT blank the previous reading: {after}"
    );
    assert!(named_ok, "…and must name the failure: {after}");
    assert!(
        stale_ok,
        "…and must mark what is on screen as stale: {after}"
    );
    assert!(
        painted(&mut tab, "PREVIOUS reading"),
        "the surface says the rows are stale"
    );
    assert!(
        painted(&mut tab, "first-good-read"),
        "…and the rows are still there"
    );

    let ok = kept_ok && named_ok && stale_ok;
    matrix(
        "jera_failed_refresh_keeps_the_reading",
        ok,
        "a source that answers once then fails leaves the pane with its 1 job still \
         rendered, `error` naming the outage, `stale=true`, and the surface saying the \
         list is the PREVIOUS reading — never a blank",
    );
}

/// **6 — a read IN FLIGHT is named, and does not blank the previous reading.**
///
/// The delay lives on the far side of a REAL socket (the mock holds its reply), so what
/// the frame is waiting on is what it waits on in production.
#[test]
fn a_read_in_flight_is_named_and_does_not_blank_the_previous_reading() {
    let srv = spawn_mock_viz(MockViz {
        jobs: serde_json::json!([record("j-slow", "populate", "done")]).to_string(),
        reply_delay: Duration::from_millis(400),
        ..Default::default()
    });
    let mut tab = JeraTab::wire(&srv.endpoint, "", "nordisk");
    tab.refresh(); // land a first reading (blocking).
    assert_eq!(tab.state_json()["job_count"], 1);

    tab.start(); // a second read, NOT waited on.
    let mid = tab.state_json();
    let pending_ok = mid["pending"] == true;
    let kept_ok = mid["job_count"] == 1;
    assert!(pending_ok, "a read in flight must SAY so: {mid}");
    assert!(
        kept_ok,
        "…and the previous reading stays on screen while it travels: {mid}"
    );
    assert!(
        painted(&mut tab, "previous reading"),
        "the surface names the in-flight read"
    );

    tab.wait();
    let done = tab.state_json();
    assert_eq!(done["pending"], false, "…and it lands: {done}");

    let ok = pending_ok && kept_ok;
    matrix(
        "jera_in_flight_read_is_named",
        ok,
        "with the mock Viz holding its reply 400 ms on the far side of a real socket, the \
         pane reports pending=true and keeps its 1 previous job rendered — `still reading` \
         is a third state, never `read nothing`",
    );
}

/// **7 — an EMPTY answer is `idle` over the wire, and never the fixture.**
///
/// `1aa8f0f`: `read_ledger_jobs` returned `Ok(Vec::new())` for BOTH an absent and an
/// empty ledger, `jera.rs:118` fell through to `fixture_zoned_jobs()`, and a **deleted
/// workspace painted invented jobs** — a green build, a running bench, a failed release
/// that did not exist. Over the wire the client is not entitled to claim `absent` (only
/// the server knows whether the workspace exists), so the three answers are: rows, an
/// empty ledger, and a NAMED failure for "no such workspace". None of them is a fixture.
#[test]
fn an_empty_answer_is_idle_over_the_wire_and_never_the_fixture() {
    let srv = spawn_mock_viz(MockViz::default()); // serves `[]`
    let mut tab = JeraTab::wire(&srv.endpoint, "", "nordisk");
    tab.refresh();
    let s = tab.state_json();
    let idle_ok = s["source"] == "idle" && s["job_count"] == 0 && s["ledger_absent"] == false;
    assert!(
        idle_ok,
        "`[]` from a server that answered IS an idle ledger: {s}"
    );
    assert!(painted(&mut tab, "idle"), "…and it says idle");
    let no_fixture_ok = !painted(&mut tab, "cargo-build") && !painted(&mut tab, "#1042");
    assert!(
        no_fixture_ok,
        "an empty ledger must NEVER render the demo fixture"
    );

    // "no such workspace" is a NAMED failure, not an empty list — the state a wiped
    // registry (`serving 0 workspace(s)`) actually produces.
    let gone = spawn_mock_viz(MockViz {
        refuse: Some((Code::NotFound, "workspace `nordisk` is not served".into())),
        ..Default::default()
    });
    let mut gone_tab = JeraTab::wire(&gone.endpoint, "", "nordisk");
    gone_tab.refresh();
    let gs = gone_tab.state_json();
    let gone_ok = gs["source"] != "idle"
        && gs["error"]
            .as_str()
            .unwrap_or_default()
            .contains("not_served");
    assert!(
        gone_ok,
        "an unserved workspace is a named failure, not zero jobs: {gs}"
    );

    let ok = idle_ok && no_fixture_ok && gone_ok;
    matrix(
        "jera_empty_and_absent_stay_different_values",
        ok,
        "over Viz.Jobs: `[]` lands `idle`/0 with the demo fixture nowhere on the surface, \
         while an unserved workspace lands a named `not_served` failure with source != idle \
         — `no answer` and `no jobs` remain different values after the move to gRPC",
    );
}

/// The FILE road survives as an explicit escape hatch and still answers its own three
/// states — kept so moving the shipped tab to the wire did not quietly delete a capability.
#[test]
fn the_file_road_still_answers_absent_idle_and_rows() {
    let d = tempfile::tempdir().unwrap();
    let root = d.path().to_path_buf();

    let absent = JeraTab::with_source(Arc::new(LedgerJobs { root: root.clone() }));
    assert_eq!(
        absent.state_json()["source"],
        "absent",
        "no jobs.redb ⇒ absent"
    );

    drop(jera::jobs::JobStore::open(&root).unwrap());
    let idle = JeraTab::with_source(Arc::new(LedgerJobs { root: root.clone() }));
    assert_eq!(
        idle.state_json()["source"],
        "idle",
        "an empty ledger ⇒ idle"
    );

    seed_ledger(&root);
    let rows = JeraTab::with_source(Arc::new(LedgerJobs { root: root.clone() }));
    assert_eq!(
        rows.state_json()["source"],
        "ledger",
        "a populated ledger ⇒ ledger"
    );
    assert_eq!(rows.state_json()["job_count"], 1);
}

/// The shipped wire pane names its endpoint as the FORGE it was handed, and never
/// nornir's `:7878`. The suite-host-embedded-auth LAW, asserted at this pane's own seam —
/// `tests/robot_host_only.rs` folds `whence` in with every other pane and re-proves it
/// across the whole shell.
#[test]
fn the_wire_pane_dials_the_forge_and_holds_no_nornir_address() {
    let tab = JeraTab::wire("http://dwarves-host.example:7900", "", "nordisk");
    let whence = tab.state_json()["whence"]
        .as_str()
        .unwrap_or_default()
        .to_string();
    assert!(
        whence.contains(":7900"),
        "the pane names the forge: {whence}"
    );
    assert!(
        !whence.contains("7878"),
        "the UI holds no nornir address: {whence}"
    );
    // The type carries no second endpoint to hold one in, either.
    let w = WireJobs {
        endpoint: "http://dwarves-host.example:7900".into(),
        token: String::new(),
        workspace: "nordisk".into(),
    };
    assert!(!format!("{}", w.endpoint).contains("7878"));
}

/// **A JOB CLASS MUST NOT BE PUSHED OUT OF VIEW BY A NOISIER ONE** (`jerakind-1`).
///
/// # The measurement this is built on
///
/// Taken off the LIVE dwarves forge 2026-08-27 (`nornir jobs --server` against oden's
/// embedded nornir, workspace `nordisk`), comparing the server's own default 200-row window
/// with what a kind-scoped read of the same ledger returns:
///
/// ```text
///   kind                 in the MIXED window     kind-scoped read
///   snapshot_member                      57            200+
///   scip_member                          47            200+
///   knowledge_member                     38            200+
///   lens                                 26            200+
///   feed                                  6              84      (7.1 %)
///   workspace_populate                    0               1      (invisible)
/// ```
///
/// A populate emits one job per workspace member per phase, so the three per-member kinds
/// are **142 of the 200** — 71 % of the window — and a class that ran once is not in it at
/// all. The crowding happens in the SERVER'S truncate, so no client-side filter recovers
/// it: those rows never arrived.
///
/// # What is asserted, and why it is the source and not the field
///
/// The fixture RECORDS every `kind` it was asked for, and its answer depends on that kind
/// the way the real ledger does: 200 mixed rows with zero `workspace_populate` for `""`,
/// and the one populate row for `"workspace_populate"`. So this cannot pass by the pane
/// storing a string — the read has to carry it.
///
/// **THE RED.** Before `JeraJobSource::read` took a kind, `WireJobs` passed a literal `""`
/// to `Viz.Jobs` and the pane had no kind of its own: the first assertion below (`asked`
/// contains `"workspace_populate"`) failed with `asked = [""]`, and the count stayed at 0
/// after the drive. The capability had been on the RPC since it was written — the server's
/// `JobSelector::Kind` arm — and the pane dropped it on the floor.
#[test]
fn a_quiet_job_class_is_reachable_because_the_kind_rides_the_read() {
    /// The live census above, as a source. `asked` is the whole point: it is the evidence
    /// that the kind reached the read rather than a field.
    struct CensusJobs {
        asked: Mutex<Vec<String>>,
    }
    impl dwarves_gui::jera::JeraJobSource for CensusJobs {
        fn read(&self, limit: usize, kind: &str) -> JobsRead {
            self.asked.lock().unwrap().push(kind.to_string());
            // The mixed window, in the live proportions, truncated exactly as the server
            // truncates: the quiet class is not in it.
            let mixed: Vec<(&str, usize)> = vec![
                ("snapshot_member", 57),
                ("scip_member", 47),
                ("knowledge_member", 38),
                ("lens", 26),
                ("feed", 6),
                ("security_member", 5),
                ("knowledge_scan", 4),
                ("deepscan", 3),
                ("snapshot", 3),
                ("index_build", 3),
                ("scip_ingest", 2),
                ("security_scan", 2),
                ("workspace_republish", 2),
                ("arch_generate", 2),
            ];
            let mut rows: Vec<serde_json::Value> = Vec::new();
            let mut n = 0usize;
            if kind.is_empty() {
                for (k, count) in mixed {
                    for i in 0..count {
                        rows.push(record(&format!("{k}-{i}"), k, "done"));
                        n += 1;
                    }
                }
            } else if kind == "workspace_populate" {
                // The one row the mixed window never carried.
                rows.push(record("populate-0", "workspace_populate", "done"));
                n = 1;
            } else {
                // Any other class: the scoped read returns its whole history, which is what
                // makes the window a window and not a lens.
                for i in 0..200 {
                    rows.push(record(&format!("{kind}-{i}"), kind, "done"));
                }
                n = 200;
            }
            rows.truncate(limit.max(1));
            let _ = n;
            JobsRead::Rows(dwarves_embed::entries_from_records_json(&rows).unwrap())
        }
        fn describe(&self) -> String {
            "the 2026-08-27 live census, as a fixture".to_string()
        }
    }

    let src = Arc::new(CensusJobs {
        asked: Mutex::new(Vec::new()),
    });
    let mut tab = JeraTab::with_source(src.clone());

    // ── FORE: the mixed window. Not one populate row, and the pane's own oracle says the
    // read asked for every kind.
    let s = tab.state_json();
    assert_eq!(
        s["server_kind"], "",
        "the pane opens on every kind, as it always has"
    );
    let seen: Vec<String> = s["kinds_seen"]
        .as_array()
        .expect("kinds_seen is published")
        .iter()
        .map(|v| v.as_str().unwrap_or_default().to_string())
        .collect();
    assert!(
        seen.contains(&"snapshot_member".to_string()),
        "the picker learns the noisy classes from the mixed window: {seen:?}"
    );
    assert!(
        !seen.contains(&"workspace_populate".to_string()),
        "…and CANNOT learn the quiet one, which is exactly why the pane needs a typed \
         entry beside the picker: {seen:?}"
    );
    let before = s["job_count"].as_u64().unwrap_or(0);
    // The pane asks for `DEFAULT_LEDGER_LIMIT` (100) and the fixture's mixed window holds
    // 200, so the window comes back FULL — which is the condition under which a quiet class
    // is squeezed out, and the reason the assertion is `==` the limit rather than "some".
    assert_eq!(
        before,
        u64::try_from(dwarves_embed::DEFAULT_LEDGER_LIMIT).expect("limit fits"),
        "the mixed window must come back FULL, or nothing was being crowded out"
    );

    // ── THE DRIVE, through the robot seam the shell drives, not through the field.
    tab.update_json(&serde_json::json!({ "server_kind": "workspace_populate" }).to_string());

    // ── EFTER: the kind reached the READ, and the row that was invisible is on screen.
    let asked = src.asked.lock().unwrap().clone();
    assert!(
        asked.iter().any(|k| k == "workspace_populate"),
        "the read was never asked for the class — the kind is being stored and not sent. \
         Asked so far: {asked:?}"
    );
    let s = tab.state_json();
    assert_eq!(
        s["server_kind"], "workspace_populate",
        "the pane names its window"
    );
    assert_eq!(
        s["job_count"], 1,
        "the one populate row must be on screen. It is 0 of 200 in the mixed window, so a \
         client-side filter over what arrived could never have found it."
    );
    assert_eq!(
        s["source"], "ledger",
        "a scoped read that found rows is a live ledger"
    );

    // ── BACK TO EVERY KIND — a window you cannot leave is a mode, not a filter.
    tab.update_json(&serde_json::json!({ "server_kind": serde_json::Value::Null }).to_string());
    let s = tab.state_json();
    assert_eq!(
        s["server_kind"], "",
        "null puts the window back to every kind"
    );
    assert_eq!(
        s["job_count"].as_u64().unwrap_or(0),
        u64::try_from(dwarves_embed::DEFAULT_LEDGER_LIMIT).expect("limit fits"),
        "…and the full mixed window comes back"
    );

    // ── NON-VACUITY: the fixture must actually DISTINGUISH the two reads, or every
    // assertion above is a statement about one answer.
    assert!(
        src.asked.lock().unwrap().iter().any(|k| k.is_empty()),
        "the fixture was never asked for the mixed window — the FORE half is untested"
    );

    matrix(
        "jera kind window rides the read",
        true,
        "workspace_populate: 0 of 200 in the mixed window, 1 row through a kind-scoped read; \
         the kind reaches JeraJobSource::read and not just a field",
    );
}