// Headless guard for the run-context header builder (chart-viewer.js buildHeader). // Property protected: buildHeader maps an AURA_TRACES.meta object to header chips // WITHOUT a DOM — a run shows name/tap/broker/window/commit chips; a family adds a // members chip; absent meta yields []. Loads the real viewer module and drives the // exported pure buildHeader; mount() (browser-only) is never called. import { createRequire } from "node:module"; import { fileURLToPath } from "node:url"; import { dirname, join } from "node:path"; const require = createRequire(import.meta.url); const here = dirname(fileURLToPath(import.meta.url)); const fail = (msg) => { console.error("FAIL: " + msg); process.exit(1); }; const has = (chips, label, needle, msg) => { const c = chips.find((c) => c.label === label); if (!c) fail(msg + " (no '" + label + "' chip)"); if (needle != null && String(c.value).indexOf(needle) < 0) fail(msg + " (got " + c.value + ")"); }; // No `document` global -> chart-viewer.js's browser mount is skipped; require gives // only the pure export (mirrors chart_viewer_build.mjs stubbing window before require). global.window = {}; const { buildHeader } = require(join(here, "..", "assets", "chart-viewer.js")); // run meta -> name / tap / broker / window / commit chips; no members chip const run = { kind: "run", name: "eur-demo", commit: "abc1234def567", window: [1704067200000000000, 1735689600000000000], broker: "sim-optimal(pip_size=0.0001)", seed: 0, taps: ["equity", "exposure"], members: null, params: [["len", "20"]], }; const rc = buildHeader(run); has(rc, "run", "eur-demo", "run name chip"); has(rc, "tap", "equity", "tap chip"); has(rc, "broker", "sim-optimal", "broker chip"); has(rc, "window", "2024", "window chip (formatted day)"); has(rc, "commit", "abc1234", "commit chip (shortened)"); if (rc.find((c) => c.label === "members")) fail("a single run must not carry a members chip"); // family meta -> adds a members chip, name label is 'family', and renders its // SPANNING window. The window models a walk-forward family's full OOS coverage // (built Rust-side as (min member.from, max member.to)); the rendered chip must // show that full span's endpoints, not a single member's window. const fam = { kind: "family", name: "ger40-5y", commit: "deadbeef", window: [1577836800000000000, 1735689600000000000], // 2020-01-01 -> 2025-01-01 broker: "sim-optimal(pip_size=1)", seed: 0, taps: ["equity"], members: 4, params: [], }; const fc = buildHeader(fam); has(fc, "family", "ger40-5y", "family name chip"); has(fc, "members", "4", "family members chip"); has(fc, "window", "2020", "family window chip (span start)"); has(fc, "window", "2025", "family window chip (span end)"); // absent meta -> [] if (buildHeader(undefined).length !== 0) fail("absent meta must yield no chips"); console.log("OK — buildHeader run/family/empty chips."); process.exit(0);