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

nordisk/nornir

src/viz/bloodstream_tab.rs

//! 🩸 **Bloodstream tab** — the workspace rendered as a living *circulatory
//! system* (the "blodomlopp"), painted natively in egui over the pure
//! [`super::bloodstream::Organism`] model.
//!
//! Crates are **organs** seated at anatomical body positions (the busiest hub
//! beats at the **heart**); dependency edges are **arteries** with **blood
//! corpuscles** streaming along them, driven by an injected clock (FC-7). Click an
//! organ to **drill in**: its entire transitive crates.io dependency closure —
//! the deps-of-deps, excluding workspace members — is pulled live from a
//! `Cargo.lock` and blooms outward as **capillary** rings by recursion depth.
//!
//! The view is a [`facett_jobview::Facet`] (== `facett_core::Facet`) so the
//! robot-UI harness introspects it uniformly: [`Facet::state_json`] delegates to
//! the organism, so the drawn body — organs, vessels, flow phase, and the loaded
//! recursive external layer — is asserted as DATA (LAW #6), no screenshot needed.

use std::path::Path;

use egui::{Align2, Color32, CornerRadius, FontId, Pos2, Sense, Stroke, Vec2};
use facett_jobview::Facet; // == facett_core::Facet (both re-export the 0.1 trait)

use super::bloodstream::{Organism, member_edges, workspace_members};
use super::facett_theme::Theme;
use super::model::Timeline;

/// nornir's **own** committed lockfile, embedded at build time. The bloodstream's
/// default blood supply: when there is no live warehouse snapshot yet, the body is
/// built from — and every drill-down resolves against — nornir's real dependency
/// closure, so the view is never a demo and the recursion is always real data.
const NORNIR_LOCK: &str = include_str!("../../Cargo.lock");

/// How many recursion rings a drill-down pulls (bounds the deps-of-deps walk so a
/// single organ can't drag the whole crates.io universe in at once).
const DRILL_DEPTH: usize = 4;

/// 🩸 The Bloodstream tab pane — a native egui host around the pure [`Organism`].
pub struct BloodstreamView {
    title: String,
    organism: Organism,
    /// The `(source, crate_count, edge_count)` signature the current organism was
    /// built from — rebuild only when the underlying workspace data changes, so
    /// drill-down state survives across animation frames.
    built_sig: Option<(String, usize, usize)>,
    /// The `Cargo.lock` text drill-downs resolve against (nornir's own by default;
    /// a live local workspace overrides it with the selected repo's lock).
    lock_text: String,
    /// Human label of the current lock/data source (folded into `state_json`).
    lock_source: String,
    theme: Theme,
    /// **Pinned animation clock** (seconds; FC-7). `Some` ⇒ the blood phase is a
    /// pure function of this value (deterministic headless render); `None` ⇒ follow
    /// egui's ambient `input.time` (the live UX).
    clock_pinned: Option<f64>,
    /// Render tallies for the emit-doctrine marker (organs/capillaries painted).
    painted_organs: usize,
    painted_capillaries: usize,
}

impl Default for BloodstreamView {
    fn default() -> Self {
        Self {
            title: "🩸 Bloodstream".into(),
            organism: Organism::default(),
            built_sig: None,
            lock_text: NORNIR_LOCK.to_string(),
            lock_source: "nornir Cargo.lock (embedded)".into(),
            theme: Theme::default(),
            clock_pinned: None,
            painted_organs: 0,
            painted_capillaries: 0,
        }
    }
}

impl BloodstreamView {
    /// Discovery-contract ctor (the no-arg surface the test matrix enumerates).
    pub fn local() -> Self {
        Self::default()
    }

    /// Set the active facett palette (C8) — re-skins the body's organs/vessels.
    pub fn set_palette(&mut self, t: Theme) {
        self.theme = t;
    }

    /// **Pin the animation clock** (seconds; FC-7) so the blood flow is
    /// reproducible: identical organism + clock ⇒ identical frame + state dump.
    pub fn set_clock(&mut self, seconds: f64) {
        self.clock_pinned = Some(seconds);
        self.organism.set_clock(seconds);
    }

    /// Feed the live workspace: rebuild the organism from the timeline's crates +
    /// dep edges when they change, else keep the current (drill-down-preserving)
    /// body. Falls back to nornir's own embedded lockfile so the body is always
    /// real, never blank. `workspace_root/<repo>/Cargo.lock` (or the root lock)
    /// becomes the drill-down source when a local checkout is present.
    fn rebuild_if_needed(&mut self, tl: Option<&Timeline>, workspace_root: &Path) {
        // Prefer live snapshot data (crates = lanes, edges = latest snapshot).
        let live = tl.and_then(|t| {
            let crates: Vec<String> = t.lanes.iter().map(|l| l.repo.clone()).collect();
            if crates.is_empty() {
                return None;
            }
            let edges = t
                .latest_snapshot
                .as_ref()
                .map(|s| s.edges.clone())
                .unwrap_or_default();
            Some((crates, edges))
        });

        let (source, crates, edges, lock) = match live {
            Some((crates, edges)) => {
                // A local checkout's lockfile makes the drill-down that workspace's
                // real closure; otherwise resolve against nornir's own embedded lock.
                let (lock, lock_src) = local_lock(&crates, workspace_root).unwrap_or_else(|| {
                    (
                        NORNIR_LOCK.to_string(),
                        "nornir Cargo.lock (embedded)".into(),
                    )
                });
                (format!("live:{lock_src}"), crates, edges, lock)
            }
            None => {
                // No live snapshot yet — build the body from nornir's OWN workspace
                // members + their intra-workspace edges, resolved from the embedded
                // lock. Real crates, real arteries, real drill-down. Not a demo.
                (
                    "nornir Cargo.lock (embedded)".to_string(),
                    workspace_members(NORNIR_LOCK),
                    member_edges(NORNIR_LOCK),
                    NORNIR_LOCK.to_string(),
                )
            }
        };

        let sig = (source.clone(), crates.len(), edges.len());
        if self.built_sig.as_ref() == Some(&sig) {
            return;
        }
        self.built_sig = Some(sig);
        self.lock_text = lock;
        self.lock_source = source;
        self.organism = Organism::build(&crates, &edges);
    }

    /// Toggle a crate's drill-down (its recursive external closure), the
    /// robot-addressable equivalent of clicking the organ. Ensures a body exists
    /// first so a headless driver can expand without a prior paint. Returns the
    /// number of external deps now attached.
    fn expand(&mut self, crate_name: &str) -> usize {
        if self.organism.organs.is_empty() {
            self.rebuild_if_needed(None, Path::new(""));
        }
        self.organism.selected = Some(crate_name.to_string());
        self.organism
            .toggle_expand(crate_name, &self.lock_text, DRILL_DEPTH)
    }

    /// **R6 robot-drive** — apply a `bloodstream.<action>` control-channel button.
    /// `expand:<crate>` drills into (or collapses) that organ; `collapse_all`
    /// drops every drill-down. Returns `Err` for an unknown action.
    pub(crate) fn click_for_drive(&mut self, action: &str) -> Result<(), String> {
        if let Some(krate) = action.strip_prefix("expand:") {
            let n = self.expand(krate);
            if self.organism.organ(krate).is_none() {
                return Err(format!("no organ named `{krate}`"));
            }
            let _ = n;
            Ok(())
        } else if action == "collapse_all" {
            for o in &mut self.organism.organs {
                o.expanded = false;
                o.external.clear();
            }
            Ok(())
        } else {
            Err(format!("unknown bloodstream action {action:?}"))
        }
    }

    /// Draw the pane: header + the organic body. Feeds the live timeline in, scoped
    /// to the stable `Bloodstream` pane id so the AccessKit `id_salt` matches the
    /// surfaces registry.
    pub fn draw(&mut self, ui: &mut egui::Ui, tl: Option<&Timeline>, workspace_root: &Path) {
        self.rebuild_if_needed(tl, workspace_root);
        ui.push_id("Bloodstream", |ui| {
            ui.horizontal(|ui| {
                ui.heading("🩸 Bloodstream");
                ui.label(
                    egui::RichText::new(
                        "the workspace as a circulatory system — crates are organs, deps are arteries, the call-chain is the blood. Click an organ to drill into its crates.io closure.",
                    )
                    .weak(),
                );
            });
            ui.label(
                egui::RichText::new(format!(
                    "{} organ(s) · {} vessel(s) · {} capillaries drilled · source: {}",
                    self.organism.organs.len(),
                    self.organism.vessels.len(),
                    self.organism.external_count(),
                    self.lock_source,
                ))
                .weak(),
            );
            ui.separator();
            self.render_body(ui);
        });
    }

    /// The native circulatory-system painter.
    fn render_body(&mut self, ui: &mut egui::Ui) {
        // Animate: pinned clock (deterministic) or ambient time (live).
        let seconds = self.clock_pinned.unwrap_or_else(|| ui.input(|i| i.time));
        self.organism.set_clock(seconds);
        let phase = self.organism.flow_phase;

        let canvas = ui.available_size();
        let (rect, resp) = ui.allocate_exact_size(canvas, Sense::click_and_drag());
        let painter = ui.painter_at(rect);
        let th = self.theme;
        painter.rect_filled(rect, CornerRadius::ZERO, th.bg);

        // Body → screen. Body coords are x∈[-1,1] (L→R), y∈[-1,1] (bottom→top).
        let center = rect.center();
        let scale = 0.44 * rect.width().min(rect.height());
        let to_screen = |x: f32, y: f32| Pos2::new(center.x + x * scale, center.y - y * scale);

        self.paint_silhouette(&painter, to_screen, th);

        // ── organ screen positions (crate → pos + radius) ─────────────────────
        let max_deg = self
            .organism
            .organs
            .iter()
            .map(|o| o.in_degree)
            .max()
            .unwrap_or(0)
            .max(1);
        let mut org_pos: std::collections::HashMap<&str, (Pos2, f32)> =
            std::collections::HashMap::new();
        for o in &self.organism.organs {
            let base = 0.020 * scale;
            let r = base + 0.028 * scale * (o.in_degree as f32 / max_deg as f32);
            org_pos.insert(o.crate_name.as_str(), (to_screen(o.x, o.y), r));
        }

        // ── vessels (arteries) + streaming blood corpuscles ───────────────────
        for (vi, v) in self.organism.vessels.iter().enumerate() {
            let (Some(&(a, _)), Some(&(b, _))) =
                (org_pos.get(v.from.as_str()), org_pos.get(v.to.as_str()))
            else {
                continue;
            };
            // A curved artery: quadratic bezier bowed perpendicular to the chord.
            let mid = Pos2::new((a.x + b.x) / 2.0, (a.y + b.y) / 2.0);
            let dir = (b - a).normalized();
            let normal = Vec2::new(-dir.y, dir.x);
            let bow = ((vi % 2) as f32 * 2.0 - 1.0) * (a - b).length() * 0.14;
            let ctrl = mid + normal * bow;
            let pts = sample_quadratic(a, ctrl, b, 20);
            // Vessel wall: translucent, deep venous blue-red.
            let wall = Color32::from_rgba_unmultiplied(150, 40, 55, 70);
            for w in pts.windows(2) {
                painter.line_segment([w[0], w[1]], Stroke::new(2.2_f32, wall));
            }
            // Corpuscles: bright arterial cells marching along the curve.
            let selected_edge = self.organism.selected.as_deref() == Some(v.from.as_str())
                || self.organism.selected.as_deref() == Some(v.to.as_str());
            let cells = 4;
            for c in 0..cells {
                let t =
                    ((phase + c as f32 / cells as f32 + vi as f32 * 0.05) % 1.0).clamp(0.0, 1.0);
                let p = quadratic_at(a, ctrl, b, t);
                let cell = if selected_edge {
                    Color32::from_rgb(255, 90, 90)
                } else {
                    Color32::from_rgb(210, 45, 55)
                };
                painter.circle_filled(p, if selected_edge { 3.2 } else { 2.3 }, cell);
            }
        }

        // ── capillaries (drilled external closure) as concentric rings ─────────
        let mut painted_caps = 0usize;
        for o in &self.organism.organs {
            if !o.expanded || o.external.is_empty() {
                continue;
            }
            let (heart, _) = org_pos[o.crate_name.as_str()];
            let max_d = o.max_depth().max(1);
            // group externals by depth so each ring is spread evenly.
            let mut by_depth: std::collections::BTreeMap<usize, Vec<&str>> = Default::default();
            for e in &o.external {
                by_depth.entry(e.depth).or_default().push(e.name.as_str());
            }
            for (depth, names) in &by_depth {
                let ring = 0.05 * scale + 0.055 * scale * (*depth as f32);
                let n = names.len().max(1);
                for (i, name) in names.iter().enumerate() {
                    let ang = (i as f32 / n as f32) * std::f32::consts::TAU
                        + *depth as f32 * 0.6
                        + phase * 0.5;
                    let p = Pos2::new(heart.x + ring * ang.cos(), heart.y + ring * ang.sin());
                    // hairline from the organ, fading with depth.
                    let fade = 120 - (*depth as i32 * 22).min(90);
                    painter.line_segment(
                        [heart, p],
                        Stroke::new(
                            0.7_f32,
                            Color32::from_rgba_unmultiplied(200, 120, 130, fade as u8),
                        ),
                    );
                    // capillary node: cooler + smaller the deeper it is.
                    let g = 60 + (*depth as i32 * 30).min(150);
                    let cap =
                        Color32::from_rgb(220u8.saturating_sub((*depth as u8) * 20), g as u8, 160);
                    let cr = (3.2 - *depth as f32 * 0.4).max(1.2);
                    painter.circle_filled(p, cr, cap);
                    painted_caps += 1;
                    // label only the shallow ring to avoid clutter.
                    if *depth <= 1 && n <= 24 {
                        painter.text(
                            p + Vec2::new(5.0, -2.0),
                            Align2::LEFT_CENTER,
                            name,
                            FontId::proportional(9.0),
                            th.text_dim,
                        );
                    }
                }
                let _ = max_d;
            }
        }

        // ── organs on top ─────────────────────────────────────────────────────
        let mut painted_organs = 0usize;
        for o in &self.organism.organs {
            let (p, r) = org_pos[o.crate_name.as_str()];
            let selected = self.organism.selected.as_deref() == Some(o.crate_name.as_str());
            // Systolic pulse: organs breathe with the blood phase.
            let pulse = 1.0 + 0.10 * (phase * std::f32::consts::TAU + o.x + o.y).sin();
            let rr = r * pulse;
            // Halo (glow) for the heart / selected / expanded organs.
            if selected || o.expanded || o.organ == "heart" {
                painter.circle_filled(
                    p,
                    rr * 2.1,
                    Color32::from_rgba_unmultiplied(200, 40, 60, 40),
                );
            }
            let fill = if o.organ == "heart" {
                Color32::from_rgb(200, 40, 55)
            } else if o.expanded {
                Color32::from_rgb(180, 70, 90)
            } else {
                th.node_fill
            };
            painter.circle_filled(p, rr, fill);
            let stroke_col = if selected {
                th.accent
            } else {
                Color32::from_rgb(210, 90, 100)
            };
            painter.circle_stroke(
                p,
                rr,
                Stroke::new(if selected { 2.4_f32 } else { 1.4_f32 }, stroke_col),
            );
            // Label: crate name + organ role.
            painter.text(
                p + Vec2::new(0.0, rr + 2.0),
                Align2::CENTER_TOP,
                &o.crate_name,
                FontId::proportional(11.0),
                th.text,
            );
            painter.text(
                p + Vec2::new(0.0, -rr - 11.0),
                Align2::CENTER_BOTTOM,
                &o.organ,
                FontId::proportional(8.5),
                th.text_dim,
            );
            painted_organs += 1;
        }

        // ── click → drill into the nearest organ ──────────────────────────────
        if resp.clicked() {
            if let Some(pos) = resp.interact_pointer_pos() {
                let mut best: Option<(&str, f32)> = None;
                for o in &self.organism.organs {
                    let (p, r) = org_pos[o.crate_name.as_str()];
                    let d = p.distance(pos);
                    if d <= r + 6.0 && best.map(|(_, bd)| d < bd).unwrap_or(true) {
                        best = Some((o.crate_name.as_str(), d));
                    }
                }
                if let Some((name, _)) = best {
                    let name = name.to_string();
                    self.expand(&name);
                }
            }
        }

        self.painted_organs = painted_organs;
        self.painted_capillaries = painted_caps;

        // Keep the blood flowing (live mode); pinned-clock renders stay still.
        if self.clock_pinned.is_none() {
            ui.ctx().request_repaint();
        }

        // EMIT-DOCTRINE (§selftest): the body is a pixel/render stage whose
        // non-blankness can't be read from a return value — implant the marker so
        // the coverage audit sees this NEW surface actually paint real organs.
        #[cfg(feature = "testmatrix")]
        crate::selftest::emit(
            "viz/bloodstream (egui draw)",
            "bloodstream_rendered_non_blank",
            painted_organs > 0,
            &format!(
                "painted {painted_organs} organ(s) + {painted_caps} capillary node(s) on a {:.0}x{:.0}px body",
                rect.width(),
                rect.height()
            ),
        );
    }

    /// Faint anatomical silhouette (torso + head + four limbs) so the organs read
    /// as seated in a body, not a bare graph.
    fn paint_silhouette(
        &self,
        painter: &egui::Painter,
        to_screen: impl Fn(f32, f32) -> Pos2,
        th: Theme,
    ) {
        let wall = Color32::from_rgba_unmultiplied(
            th.panel_stroke.r(),
            th.panel_stroke.g(),
            th.panel_stroke.b(),
            40,
        );
        let limb = Stroke::new(10.0_f32, wall);
        // Torso: shoulders → hips (a bowed capsule via two side lines).
        let torso = [
            to_screen(-0.34, 0.55),
            to_screen(0.34, 0.55),
            to_screen(0.24, -0.55),
            to_screen(-0.24, -0.55),
        ];
        for w in [
            [torso[0], torso[1]],
            [torso[1], torso[2]],
            [torso[2], torso[3]],
            [torso[3], torso[0]],
        ] {
            painter.line_segment(w, Stroke::new(6.0_f32, wall));
        }
        // Head.
        painter.circle_stroke(
            to_screen(0.0, 0.82),
            0.10 * (to_screen(1.0, 0.0).x - to_screen(0.0, 0.0).x)
                .abs()
                .max(1.0)
                + 14.0,
            Stroke::new(6.0_f32, wall),
        );
        // Neck.
        painter.line_segment(
            [to_screen(0.0, 0.72), to_screen(0.0, 0.56)],
            Stroke::new(8.0_f32, wall),
        );
        // Arms.
        painter.line_segment([to_screen(-0.34, 0.55), to_screen(-0.64, 0.09)], limb);
        painter.line_segment([to_screen(0.34, 0.55), to_screen(0.64, 0.09)], limb);
        // Legs.
        painter.line_segment([to_screen(-0.24, -0.55), to_screen(-0.30, -0.94)], limb);
        painter.line_segment([to_screen(0.24, -0.55), to_screen(0.30, -0.94)], limb);
    }
}

impl Facet for BloodstreamView {
    fn title(&self) -> &str {
        &self.title
    }

    fn ui(&mut self, ui: &mut egui::Ui) {
        // Standalone (FacetDeck) render over the current organism — the app's own
        // tab dispatch uses `draw` to feed live data first.
        if self.organism.organs.is_empty() {
            self.rebuild_if_needed(None, Path::new(""));
        }
        self.render_body(ui);
    }

    fn state_json(&self) -> serde_json::Value {
        let mut v = self.organism.state_json();
        if let Some(obj) = v.as_object_mut() {
            obj.insert(
                "lock_source".into(),
                serde_json::Value::from(self.lock_source.clone()),
            );
            obj.insert(
                "painted_organs".into(),
                serde_json::Value::from(self.painted_organs),
            );
            obj.insert(
                "painted_capillaries".into(),
                serde_json::Value::from(self.painted_capillaries),
            );
            obj.insert("drill_depth".into(), serde_json::Value::from(DRILL_DEPTH));
        }
        v
    }

    fn selection_json(&self) -> serde_json::Value {
        match &self.organism.selected {
            Some(s) => serde_json::Value::from(s.clone()),
            None => serde_json::Value::Null,
        }
    }
}

/// Sample a quadratic bezier `a→ctrl→b` into `n` line points.
fn sample_quadratic(a: Pos2, ctrl: Pos2, b: Pos2, n: usize) -> Vec<Pos2> {
    (0..=n)
        .map(|i| quadratic_at(a, ctrl, b, i as f32 / n as f32))
        .collect()
}

/// Point on the quadratic bezier `a→ctrl→b` at parameter `t∈[0,1]`.
fn quadratic_at(a: Pos2, ctrl: Pos2, b: Pos2, t: f32) -> Pos2 {
    let u = 1.0 - t;
    let x = u * u * a.x + 2.0 * u * t * ctrl.x + t * t * b.x;
    let y = u * u * a.y + 2.0 * u * t * ctrl.y + t * t * b.y;
    Pos2::new(x, y)
}

/// Find a local checkout's `Cargo.lock` for the live workspace: try
/// `workspace_root/<repo>/Cargo.lock` for each repo, then the root lock. Returns
/// `(lock_text, source_label)` or `None` when no local checkout is present
/// (remote workspace) — the caller then resolves against the embedded lock.
fn local_lock(crates: &[String], workspace_root: &Path) -> Option<(String, String)> {
    if workspace_root.as_os_str().is_empty() {
        return None;
    }
    for repo in crates {
        let p = workspace_root.join(repo).join("Cargo.lock");
        if let Ok(text) = std::fs::read_to_string(&p) {
            return Some((text, format!("{}/Cargo.lock", repo)));
        }
    }
    let root = workspace_root.join("Cargo.lock");
    std::fs::read_to_string(&root)
        .ok()
        .map(|t| (t, "workspace Cargo.lock".into()))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn defaults_to_nornir_own_body_and_drills_recursively() {
        let mut v = BloodstreamView::local();
        // No live data ⇒ built from nornir's OWN embedded lock: real organs.
        v.rebuild_if_needed(None, Path::new(""));
        assert!(
            v.organism.organs.len() >= 3,
            "nornir's workspace members seat as organs"
        );
        assert!(v.organism.from_data, "real data, not a demo");

        // Drill into nornir itself → its recursive crates.io closure appears.
        let n = v.expand("nornir");
        assert!(
            n > 5,
            "drilling nornir pulled a large external closure: {n}"
        );
        let depth = v.organism.organ("nornir").unwrap().max_depth();
        assert!(
            depth >= 2,
            "the closure is genuinely recursive (deps-of-deps): depth={depth}"
        );

        // state_json carries the recursive external layer as DATA.
        let j = v.state_json();
        assert!(j["external_count"].as_u64().unwrap() >= 5);
        assert_eq!(
            j["lock_source"],
            serde_json::json!("nornir Cargo.lock (embedded)")
        );
    }

    #[test]
    fn expand_unknown_organ_errors() {
        let mut v = BloodstreamView::local();
        v.rebuild_if_needed(None, Path::new(""));
        assert!(v.click_for_drive("expand:definitely-not-a-crate").is_err());
        assert!(v.click_for_drive("expand:nornir").is_ok());
        assert!(v.click_for_drive("collapse_all").is_ok());
        assert_eq!(
            v.organism.external_count(),
            0,
            "collapse_all cleared the drill-downs"
        );
    }
}