{# Plotly ships with the report (report_suite.write_report_assets), not from a CDN: an air-gapped lab rendered a plot-less report with no error at all. Pinned to the version the CDN tag used to name — plotly.js v2.35.0. ONE copy per suite, at the reports root — hence ``../``; a copy per test dir cost 1.25 MB × N. Moving a single test's report dir elsewhere means bringing ``plotly.min.js`` along beside it. #} {# === SERVER-RENDERED METRIC TREE ========================================== The tree is a read-only view of what the CLI already decided: every pill, score, criterion and detail pair below comes from the evaluated tree view. No form controls — editing a spec is the authoring tool's job, not the report's. #} {% macro status_pill(passed) %}{% if passed is sameas true %}PASS{% elif passed is sameas false %}FAIL{% else %}—{% endif %}{% endmacro %} {% macro advisory_chip(count, vidx=None) %}{% if count == 1 %}1 advisory{% else %}{{ count }} advisory{% endif %}{% endmacro %} {% macro node(n) %} {%- set combinator_help = { 'and': 'All children must pass.', 'or': 'At least one child must pass.', 'warn': 'Single-child wrapper; never fails its parent (advisory-only scoring).', 'k-of-n': 'At least k of N children must pass.', 'weighted': 'Weighted sum of child scores passes a threshold.'} -%} {%- if n.kind == 'leaf' -%}
{{ status_pill(n.passed) }}{{ n.metric }} · {{ n.label or n.variable }}{% if n.against and n.against != 'primary' %} [against={{ n.against }}]{% endif %}{% if n.window and (n.window.get('start') is not none or n.window.get('end') is not none) %} [window{% if n.window.get('start') is not none %} start={{ n.window.get('start') }}{% endif %}{% if n.window.get('end') is not none %} end={{ n.window.get('end') }}{% endif %}]{% endif %}{% if n.score_display %}{{ n.score_display }}{% endif %}
{%- if n.criterion %}
{{ n.criterion }}
{% endif %} {%- if n.error %}
{{ n.error }}
{% endif %} {%- if n.details %}
{% for pair in n.details %}
{{ pair[0] }}
{{ pair[1] }}
{% endfor %}
{% endif %}
{%- else -%}
{{ status_pill(n.passed) }}{{ n.combinator }}[{{ (n.children or []) | length }}]{% if n.get('k') is not none or n.get('threshold') is not none or n.get('weights') %}{% if n.get('k') is not none %}k={{ n.get('k') }}{% endif %}{% if n.get('weights') %} weights={{ n.get('weights') | join(', ') }}{% endif %}{% if n.get('threshold') is not none %} threshold={{ n.get('threshold') }}{% endif %}{% endif %}
{% for child in n.children or [] %}{{ node(child) }}{% endfor %}
{%- endif -%} {% endmacro %} {# === DECIMATION DISCLOSURE === Server-rendered from the figures' ``full_samples`` stamps: a trace whose stamp exceeds the samples it carries was thinned to fit the page. The sidecar holds the full-resolution INPUT trajectories (actual, reference, overlays) — derived traces such as bands, error series and spectra are not in it, so the banner promises only the inputs. #} {% if decimated %}
{{ decimated | length }} trace{{ '' if decimated | length == 1 else 's' }} decimated to fit this page — the full-resolution input trajectories are in comparison_data.json: {% for d in decimated %}{{ d.variable }} {{ d.trace }} {{ d.full }}→{{ d.embedded }}{% if not loop.last %}, {% endif %}{% endfor %}
{% endif %}

{{ model_id }}

{% if run_metadata %}
{{ run_metadata.label }}{% if run_metadata.tool_version and run_metadata.tool_version != run_metadata.label %} ({{ run_metadata.tool_version }}){% endif %}{% if run_metadata.msl %} · MSL {{ run_metadata.msl }}{% endif %}{% if run_metadata.os %} · {{ run_metadata.os }}{% endif %}{% if run_metadata.dstf_version %} · DSTF {{ run_metadata.dstf_version }}{% endif %}{% if run_metadata.generated_str %} · {{ run_metadata.generated_str }}{% endif %}
{% endif %} {% if last_run_str %}
Last run: {{ last_run_str }}
{% endif %} {# === SUMMARY === #}
{# A refused test FIRST: it has no scored variable, so the branches below read it as a test with no baseline — whether or not it has one. -#} {% if refused %} Not scored: {{ refused }} {% elif is_simulate_only %} Simulate-only: simulation succeeded {% elif nobaseline_trajectories %} {{ nobaseline_trajectories | length }} variables (no baseline) {% elif sim_failed %} Simulation failed {% else %} {% if tree_summary %}{{ tree_summary.n_pass }} / {{ tree_summary.n_total }} leaves passed{% if tree_summary.root_passed is not sameas true and tree_summary.root_passed is not sameas false %} · root verdict pending — run dstf run to evaluate{% endif %}{% if tree_summary.n_advisory_failed %}{{ advisory_chip(tree_summary.n_advisory_failed) }}{% endif %}{% else %}{% endif %} {% endif %}
{# === KEY STATS === #} {% if key_stats %}
{% for s in key_stats %}
{{ s.label }}
{{ s.current or "\u2014" }}
{% if s.reference %}
ref: {{ s.reference }}
{% endif %}
{% endfor %}
{% endif %} {# === STRUCTURAL WARNINGS === #} {% if warnings %}

Structural Warnings ({{ warnings | length }})

{# A statement about this run is a sentence; only a change from the baseline has a Reference and a Current to put in columns. #} {% for w in warnings if not w.is_change %}

{{ w.text }}

{% endfor %} {% set changes = warnings | selectattr('is_change') | list %} {% if changes %} {% for w in changes %} {% endfor %}
FieldReferenceCurrent
{{ w.field }}{{ w.reference }}{{ w.current }}
{% endif %}
{% endif %} {# === REFERENCE INFO (moved up, after summary) === #} {% if ref_info %}
Reference Info {% for row in ref_info %}{% endfor %}
FieldValue
{{ row.label }}{% if row.link %}{{ row.value }}{% else %}{{ row.value }}{% endif %}
{% endif %} {# === ARTIFACT LINKS === #} {% if artifacts %} {% if sim_failed %}

Simulation Artifacts

{% for a in artifacts %}{{ a.label }}{% if not loop.last %} · {% endif %}{% endfor %}

{% else %}
Simulation Artifacts

{% for a in artifacts %}{{ a.label }}{% if not loop.last %} · {% endif %}{% endfor %}

{% endif %} {% endif %} {# === SIM PARAMS (collapsible, moved up) === #} {% if sim_params %}
Simulation Parameters {% for row in sim_params %} {% endfor %}
ParameterCurrentReference
{{ row.label }}{{ row.current }}{{ row.reference }}
{% endif %} {# === OVERLAYS SUMMARY — A2 / idea #50 === #} {% if overlay_rows %}
Overlays ({{ overlay_rows | length }}) — companion + soft_check {% for ov in overlay_rows %} {% endfor %}
NameRoleStatusVariablesNote
{{ ov.name }} {{ ov.role }}{% if ov.kind %} ({{ ov.kind }}){% endif %} {{ ov.status }} {% if ov.variables %}{{ ov.variables | join(", ") }}{% else %}—{% endif %} {{ ov.note }}{% for warning in ov.warnings %}
{{ warning }}
{% endfor %}

Toggle per-variable visibility with the Overlays: checkboxes above each plot. Companions are visual-only; soft_checks are warn-wrapped scorable baselines.

{% endif %} {# === STATISTICS (collapsible, moved up) === #} {% if statistics_sections %}
Statistics ({{ statistics_sections | length }} sections) {% for section in statistics_sections %}

{{ section.title }}

{% for row in section.rows %} {% endfor %}
MetricCurrentReference
{{ row.label }}{{ row.current }}{{ row.reference }}
{% endfor %}
{% endif %} {# === DIAGNOSTIC PLOTS (moved up, above variables) === #} {% if diag_trajectories %}
Diagnostics ({{ diag_trajectories | length }} variables) {% for traj in diag_trajectories %}

INFO {{ traj.name }}

{% endfor %}
{% endif %} {# === METRIC TREE (Stage 3 — full unfiltered SpecNodeView mount) === #} {% if tree_view %}
Metric Tree — every leaf + combinator, as the CLI scored it
{{ node(tree_view) }}
{% endif %} {# === PLOT SECTIONS — one per plot, derived from the criteria tree === One per scored variable or array family, in the order the tree first names it, then the watch plots; nothing scored is one per tracked variable. Each lists the criteria on its subject in tree order, each led by its ancestors' kinds, and its context series (drawn grey; a context series may be scored on a plot of its own). A family's badges name their members, as the tool's pills do. The error select shows when the subject is ONE scored variable the result carries, the overlay picker when that one variable has overlays. #} {% if plot_sections %} {% for plot in plot_sections %}

{%- for v in plot.variables -%} {% if not plot.single %}{{ v.text or v.name }} {% endif %}{{ 'PASS' if v.passed else 'FAIL' }}{% if v.n_advisory_failed %}{{ advisory_chip(v.n_advisory_failed, v.vidx) }}{% endif %} {%- endfor %} {{ plot.title }}{% if plot.names %}{{ plot.names }}{% endif %}

{% if plot.errors %}
{% endif %} {% if plot.overlays %}
Overlays: {% for ov in plot.overlays %} {% endfor %}
{% endif %} {% if plot.context %}
Context: {{ plot.context | join(", ") }}
{% endif %} {% if plot.missing %}
Not in this result: {{ plot.missing | join(", ") }}
{% endif %} {#- A subject the result lacks entirely draws no chart: an empty one said nothing the note does not. #} {% if plot.subject %}
{% endif %} {% if plot.criteria %}
{%- for row in plot.criteria %}
{% if row.crumbs %}{{ row.crumbs }}{% endif %}{{ node(row.leaf) }}
{%- endfor %}
{% elif plot.watch %}
No criteria yet.
{% endif %}
{% endfor %} {% endif %}