feat(e2e): render direct/recorder/debug/tcplogger/stress sections in the unified report
Extends report_build.py with build_by_kind() (per-scenario-kind pass/fail rollup) and a ported build_stress()/stress_headline()/stress_plots() (scaling curves per stress axis), wires both into the headline KPIs, regression tracking, and report_data.json. E2E_Report.typ renders the four new per-kind tables plus a Stress Tests section (per-axis case tables + scaling plots, gracefully degrading to placeholders when a kind/stress data is absent). run_e2e.sh now passes --stress-results so the report actually receives real stress data instead of silently omitting it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -323,6 +323,79 @@ MARTe2 processes, plus sustained client throughput (recorded samples ÷ duration
|
||||
#v(6pt)
|
||||
]
|
||||
|
||||
// ── per-kind sections (direct/recorder/debug/tcplogger) ─────────────────────
|
||||
// Raw scenario records here come straight from results.json (not e2e.scenarios'
|
||||
// reshaping), so they only carry id/kind/status/known_issue/metrics — no
|
||||
// waveform-fidelity breakdown (already covered, where applicable, in the
|
||||
// Scenarios section above for chain-kind scenarios; these kinds run through
|
||||
// dedicated non-chain harnesses in run_e2e.sh).
|
||||
#let kind_table(title, block) = {
|
||||
[= #title]
|
||||
[#block.n_pass/#block.n_total passed.]
|
||||
v(4pt)
|
||||
if block.n_total == 0 {
|
||||
text(fill: neutral)[_No scenarios of this kind in this run._]
|
||||
} else {
|
||||
table(
|
||||
columns: (1.4fr, 0.8fr, 2fr),
|
||||
align: (left, center, left),
|
||||
stroke: 0.4pt + rgb("#d0d7de"),
|
||||
inset: 5pt,
|
||||
table.header([*Scenario*], [*Status*], [*Known issue*]),
|
||||
..block.scenarios.map(s => (
|
||||
[#s.id],
|
||||
status_badge(s.status),
|
||||
if s.at("known_issue", default: none) != none {
|
||||
text(size: 8pt, fill: rgb("#7d4e00"))[#s.known_issue]
|
||||
} else { text(fill: neutral)[—] },
|
||||
)).flatten()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#kind_table("Direct Round-Trip (UDPStreamer ↔ UDPStreamerClient)", data.direct)
|
||||
#kind_table("Recorder (BinaryRecorder disk output)", data.recorder)
|
||||
#kind_table("Debug Service E2E", data.debug)
|
||||
#kind_table("TCPLogger E2E", data.tcplogger)
|
||||
|
||||
// ── stress tests ─────────────────────────────────────────────────────────────
|
||||
= Stress Tests
|
||||
#if data.stress == none [
|
||||
_Not run this session._
|
||||
] else [
|
||||
#align(center, status_badge(data.stress.overall) + h(8pt) + text(size: 11pt)[
|
||||
#hl.at("stress_pass", default: 0) passed ·
|
||||
#hl.at("stress_fail", default: 0) failed
|
||||
])
|
||||
#v(4pt)
|
||||
#for (axis, cases) in data.stress.by_axis [
|
||||
== Axis: #raw(axis)
|
||||
#table(
|
||||
columns: (0.8fr, 0.8fr, 1fr, 1fr, 1fr, 1fr),
|
||||
align: (right, center, right, right, right, right),
|
||||
stroke: 0.4pt + rgb("#d0d7de"),
|
||||
inset: 4pt,
|
||||
table.header([*Level*], [*Status*], [*Hub RSS (MB)*], [*MARTe RSS (MB)*],
|
||||
[*Zoom p50 (ms)*], [*Zoom p95 (ms)*]),
|
||||
..cases.map(c => (
|
||||
[#c.at("level", default: "n/a")],
|
||||
status_badge(c.at("status", default: "?")),
|
||||
fnum(c.at("hub_rss_mb", default: none), digits: 1),
|
||||
fnum(c.at("marte_rss_mb", default: none), digits: 1),
|
||||
fnum(c.at("zoom_p50_ms", default: none), digits: 1),
|
||||
fnum(c.at("zoom_p95_ms", default: none), digits: 1),
|
||||
)).flatten()
|
||||
)
|
||||
]
|
||||
#if data.stress_plots.len() > 0 [
|
||||
#v(4pt)
|
||||
== Scaling curves
|
||||
#grid(columns: 2, gutter: 8pt,
|
||||
..data.stress_plots.map(p => image(p, width: 100%))
|
||||
)
|
||||
]
|
||||
]
|
||||
|
||||
// ── trend plots ──────────────────────────────────────────────────────────────
|
||||
#if data.trend_plots.len() > 0 [
|
||||
= Trends over runs
|
||||
|
||||
Reference in New Issue
Block a user