facett-demo/src/errcode_tab.rs
//! **The `Errors` tab** — the facett **UI error-code** showcase.
//!
//! This is the visible proof of the `facet-<component>-<n>` scheme
//! ([`facett_core::errcode`]). It:
//!
//! 1. **Triggers a few example errors** and renders them so the CLEAR-PINK code
//! chips are visible on-screen (in a debug build; subdued in release).
//! 2. Shows the running build's **version + git hash** (the nordisk WHICH-build LAW).
//! 3. Renders the **error-code MATRIX slide** — the whole [`facett_core::errcode::REGISTRY`]
//! as a table (component → code → message → source link → Phase-2 consumer
//! reaction) — the same catalog that grows the reaction-test coverage in Phase 2.
//! 4. Shows a **source link per facet-component**.
//! 5. Demonstrates the **consumer mount-prefix** API
//! (`korp/cases:facet-map-2` vs `korp/analysis:facet-map-2`).
//!
//! Everything is folded into `state_json` so the robot-UI matrix keys off the CODE,
//! not a matched string. The tab itself reports [`Severity::Info`](facett_core::Severity)
//! — it displays error codes as a **catalog**, it is not itself in a failure state, so
//! it does not (and must not) trip the Robot-UI HARD GATE. It uses
//! [`FacetError::render_demo`](facett_core::errcode::FacetError::render_demo) (neutral
//! a11y atoms), never the live [`render`](facett_core::errcode::FacetError::render).
use facett::Facet;
use facett::core::FacetCaps;
use facett::core::errcode::{self, FacetError};
/// The stable tab title (the deck / discovery-contract key + the legend key).
pub const TITLE: &str = "Errors";
/// The error-code showcase tab.
pub struct ErrCodeTab {
title: &'static str,
/// The example errors triggered for the pink-code demonstration.
raised: Vec<FacetError>,
}
impl ErrCodeTab {
pub fn new(title: &'static str) -> Self {
// Trigger a couple of demo error sites so the pink codes are on-screen. These
// are the `demo` component's registered codes (facet-demo-1 / facet-demo-2).
let raised = vec![
facett::core::facet_err!(demo, 1, "example error: a triggered demo condition (showcase)"),
facett::core::facet_err!(demo, 2, "example note: a triggered demo degrade (showcase)"),
];
Self { title, raised }
}
/// The build stamp line (version + git hash).
fn version_line(&self) -> String {
crate::version_line()
}
}
impl Facet for ErrCodeTab {
fn title(&self) -> &str {
self.title
}
fn ui(&mut self, ui: &mut egui::Ui) {
egui::ScrollArea::vertical().auto_shrink([false, false]).show(ui, |ui| {
ui.heading("facett UI error codes");
ui.label("Every facett UI part carries a STABLE, UNIQUE code facet-<component>-<n> so tests + consumers react to the CODE, not a matched string.");
// The WHICH-build stamp (git hash) — also shown in the About popup.
ui.weak(self.version_line());
ui.separator();
// ── 1. Triggered examples: the pink code chips (visible in debug) ──────
ui.strong("Triggered examples (message + pink code):");
for e in &self.raised {
e.render_demo(ui);
}
ui.small(if cfg!(debug_assertions) {
"(debug build — codes render in CLEAR PINK next to the message)"
} else {
"(release build — codes subdued on-screen but present in state_json + logs)"
});
ui.separator();
// ── 2. Consumer mount-prefix demonstration ────────────────────────────
ui.strong("Consumer mount-prefix (Phase 2 — same facet, two mount points):");
if let Some(e) = self.raised.first() {
let cases = e.with_consumer_prefix("korp/cases");
let analysis = e.with_consumer_prefix("korp/analysis");
ui.monospace(cases.mounted_code());
ui.monospace(analysis.mounted_code());
}
ui.separator();
// ── 3. The error-code MATRIX slide (the whole registry) ───────────────
ui.strong(format!(
"Error-code MATRIX — {} codes across {} components:",
errcode::registry().len(),
errcode::components().len()
));
egui::Grid::new("errcode_matrix")
.striped(true)
.num_columns(7)
.spacing([14.0, 4.0])
.show(ui, |ui| {
ui.strong("component");
ui.strong("code");
ui.strong("message");
ui.strong("source");
ui.strong("status");
ui.strong("reaction (Phase 2)");
ui.strong("who reacts");
ui.end_row();
for e in errcode::registry() {
ui.label(e.component);
ui.label(
egui::RichText::new(e.code)
.monospace()
.color(errcode::code_color()),
);
ui.label(e.message);
ui.hyperlink_to(format!("{}/{}", e.crate_dir, e.src_file), e.source_url());
ui.label(if errcode::is_wired(e.code) { "wired" } else { "reserved" });
// The canonical consumer REACTION — the Phase-2 column.
ui.label(egui::RichText::new(e.reaction.token()).monospace())
.on_hover_text(e.reaction.describe());
ui.label(if e.consumer.is_empty() { "— (none today)" } else { e.consumer });
ui.end_row();
}
});
ui.separator();
// ── The Phase-2 REACTION MATRIX slide: one row per (code × mount) pair ──
let matrix = errcode::reaction_matrix();
ui.strong(format!(
"Reaction MATRIX (Phase 2) — {} (code × mount) pairs the consumer tests assert:",
matrix.len()
));
egui::Grid::new("errcode_reaction_matrix")
.striped(true)
.num_columns(4)
.spacing([14.0, 4.0])
.show(ui, |ui| {
ui.strong("mounted code");
ui.strong("base code");
ui.strong("mount");
ui.strong("expected reaction");
ui.end_row();
for (mounted, base, mount, reaction) in &matrix {
ui.label(
egui::RichText::new(mounted).monospace().color(errcode::code_color()),
);
ui.label(egui::RichText::new(*base).monospace());
ui.label(*mount);
ui.label(egui::RichText::new(reaction.token()).monospace())
.on_hover_text(reaction.describe());
ui.end_row();
}
});
});
}
fn state_json(&self) -> serde_json::Value {
// The whole catalog as data — a robot test keys off the CODE.
let matrix: Vec<serde_json::Value> = errcode::registry()
.iter()
.map(|e| {
serde_json::json!({
"component": e.component,
"n": e.n,
"code": e.code,
"message": e.message,
"source_url": e.source_url(),
"consumer": e.consumer,
// Phase 2: the canonical reaction + whether the code is raised today.
"reaction": e.reaction.token(),
"status": if errcode::is_wired(e.code) { "wired" } else { "reserved" },
})
})
.collect();
// The Phase-2 reaction MATRIX — one row per (code × mount) pair, the exact
// table the consumer reaction tests are generated from.
let reaction_matrix: Vec<serde_json::Value> = errcode::reaction_matrix()
.into_iter()
.map(|(mounted, base, mount, reaction)| {
serde_json::json!({
"mounted_code": mounted,
"code": base,
"mount": mount,
"reaction": reaction.token(),
})
})
.collect();
// The triggered examples (code + message + url) — proof the pink render ran.
let raised: Vec<serde_json::Value> = self.raised.iter().map(|e| e.to_json()).collect();
// The consumer-prefix demonstration.
let mount = self
.raised
.first()
.map(|e| {
serde_json::json!({
"base": e.code,
"cases": e.with_consumer_prefix("korp/cases").mounted_code(),
"analysis": e.with_consumer_prefix("korp/analysis").mounted_code(),
})
})
.unwrap_or(serde_json::Value::Null);
serde_json::json!({
"scheme": "facet-<component>-<n>",
"version": self.version_line(),
"git_hash": env!("FACETT_GIT_HASH"),
"code_count": errcode::registry().len(),
"component_count": errcode::components().len(),
"components": errcode::components(),
"raised": raised,
"mount_example": mount,
"matrix": matrix,
// Phase 2: the (code × mount) reaction matrix + the vocabulary.
"reaction_matrix": reaction_matrix,
"reaction_pairs": errcode::reaction_matrix().len(),
"wired_count": errcode::registry().iter().filter(|e| errcode::is_wired(e.code)).count(),
// The visible-pink flag (decision 4): on-screen pink only in debug.
"code_visible_onscreen": cfg!(debug_assertions),
})
}
fn caps(&self) -> FacetCaps {
FacetCaps::NONE.themeable().resizable()
}
fn kind(&self) -> &'static str {
"errors"
}
}
#[cfg(test)]
mod tests {
use super::*;
use facett::core::harness;
#[test]
fn errcode_tab_surfaces_codes_in_state_json() {
let mut tab = ErrCodeTab::new(TITLE);
// Renders headless without panic.
let r = harness::headless_render(&mut tab);
assert!(r.drew(), "the errcode tab drew");
let s = tab.state_json();
assert_eq!(s["scheme"], "facet-<component>-<n>");
// The build stamp / git hash is present.
assert!(s["git_hash"].as_str().is_some());
assert!(s["version"].as_str().unwrap().contains("facett-demo v"));
// The whole catalog is exposed as data.
assert!(s["code_count"].as_u64().unwrap() >= 20, "the matrix carries the whole registry");
assert_eq!(
s["matrix"].as_array().unwrap().len(),
errcode::registry().len(),
"one matrix row per registry code"
);
// The triggered examples surface their CODE (not just a string).
let raised = s["raised"].as_array().unwrap();
assert!(!raised.is_empty(), "example errors were triggered");
assert_eq!(raised[0]["code"], "facet-demo-1");
assert_eq!(raised[0]["severity"], "error");
// The consumer mount-prefix demonstration.
assert_eq!(s["mount_example"]["cases"], "korp/cases:facet-demo-1");
assert_eq!(s["mount_example"]["analysis"], "korp/analysis:facet-demo-1");
// The tab itself is NOT in a failure state (catalog display, Info floor).
assert_eq!(tab.severity(), facett::core::Severity::Info);
}
#[test]
fn every_matrix_message_avoids_the_robot_error_markers() {
// The matrix slide renders every canonical message as a label; none may
// contain a robot-UI ERROR_MARKER stem or the deck error-atom net goes RED.
const MARKERS: &[&str] = &["Failed to load", "is not served", "unavailable", "RPC: status:", "panicked"];
for e in errcode::registry() {
for m in MARKERS {
assert!(
!e.message.contains(m),
"registry message {:?} contains the reserved marker {:?}",
e.message,
m
);
}
}
}
}