Files
Aura/crates/aura-cli/tests/chart_viewer_header.mjs
T
Brummel 476342d7b1 feat(chart): decimate served pages + run-context header (visual World cut 2)
Hardens the families-comparison chart page (#107) so it is openable and legible on
real multi-year data. Two halves, both confined to the CLI render path (engine +
registry untouched, C14):

#108 — serve-time min-max decimation. A pure `decimate(ChartData, buckets)`
transform partitions the shared union-ts spine into <=~2000 buckets and emits each
series' per-bucket min+max (nulls preserved), bounding the served page to a few
thousand points regardless of the underlying M1 point count. Applied in emit_chart
on both the single-run and family paths; a no-op under budget (every existing
fixture). Full recorded data stays on disk; only the page is thinned. For a
walk-forward family the null-fill blow-up collapses for free (an all-null bucket
stays null). Deterministic (C1).

#102 — a run-context header. A `ChartMeta` (name/commit/window/broker/seed/taps,
+ member count for a family, + bound params for a single run) is built from the
RunManifest in build_chart_data / build_comparison_chart_data (which gain a `name`
arg), injected into window.AURA_TRACES.meta, and rendered by a new pure buildHeader
in chart-viewer.js (headless .mjs-guarded). The family window is the SPAN across
members (min from, max to), not the first member's window — the only reading that
labels a disjoint walk-forward family's true OOS coverage (it collapses to the
shared window for sweep/MC). Reuses the existing render_value for param display
(no new Scalar Display, keeping C7's tag-only param plane). The earlier
"manifest is NOT carried into the page" render pin is flipped to a positive one.

Verified: cargo test --workspace = 446 passed / 0 failed; cargo clippy --workspace
--all-targets -D warnings clean. New coverage: 5 decimate unit tests, single-run +
family meta wiring (incl. the span-window invariant), a buildHeader headless guard,
and two end-to-end cli_run tests pinning the served-page meta at the binary boundary.

closes #108
closes #102
2026-06-22 12:37:09 +02:00

59 lines
2.9 KiB
JavaScript

// 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);