Skip to content

feat(engine): trace report generation — Markdown + HTML#47

Merged
sepehr-safari merged 1 commit into
mainfrom
feat/report-generation
Jul 11, 2026
Merged

feat(engine): trace report generation — Markdown + HTML#47
sepehr-safari merged 1 commit into
mainfrom
feat/report-generation

Conversation

@sepehr-safari

Copy link
Copy Markdown
Member

What

feat(engine): Markdown + HTML trace report generation (S4 #41), plus the
session summarizer it consumes.

Closes #41.

Changes

  • src/ocpp/report.ziggenerateMarkdownReport / generateHtmlReport over
    an AnalysisResult, mirroring the toolkit's reporter/{markdown,html}.ts: the
    same six sections (header, session overview, timeline summary, failures,
    suggested next steps, event appendix). Self-contained HTML (inline CSS ported
    from the toolkit — no external assets). Includes an epoch-ms → ISO-8601-UTC
    formatter (std.time.epoch); the engine only had ISO → epoch before.
  • src/ocpp/summarizer.zig + types.SessionSummary — ADR-0003 parity
    with core/summarizer.ts: per-session event count, duration, Call action
    sequence, and the count of failures touching the session. The diff (feat(engine): semantic trace diff #43) reuses it.
  • Wired both into ocpp.zig (exports + test discovery); CURRENT_STATE updated.

Hardening beyond the toolkit (untrusted input)

  • Escaping on both paths. The toolkit escapes only its HTML report; here every
    trace-derived value is escaped on HTML and Markdown, so a hostile payload can't
    inject markup (HTML) or break a table/line (Markdown). Enum wire strings
    (direction/type/severity/status/code) are the only unescaped output.
  • Bounded lists. A trusted-ingestion trace can hold millions of events; each
    rendered list is capped (appendix 1000, sessions/failures 500) with a truncation
    note. The header still reports true totals.

Tests

98/98 headless tests pass (native test -Dplatform=null); native check --strict
clean; zig fmt clean. New coverage: both formats over the clean and failed-auth
fixtures, exact epoch→ISO formatting, HTML self-containment (no external asset
refs), hostile content escaped on both paths, list-section bounds, and the
empty-analysis placeholders.

Scope notes

Add src/ocpp/report.zig: render an AnalysisResult as a Markdown report and a
self-contained HTML report, mirroring the toolkit's reporter (the same six
sections — header, session overview, timeline summary, failures, suggested next
steps, event appendix). Add src/ocpp/summarizer.zig (ADR-0003 parity) and a
SessionSummary type to derive the per-session projections the report consumes.

Harden the untrusted-input path beyond the toolkit: every trace-derived value is
escaped on BOTH outputs (HTML entities for HTML; table/line-structural chars for
Markdown, which the toolkit's Markdown reporter does not escape), and every list
section is bounded so a dataset-scale trace (ADR-0007) can't produce an unbounded
document. The header still reports the true totals.

Includes an epoch-ms to ISO-8601-UTC formatter (std.time.epoch); the engine had
only ISO-to-epoch before. Pure and headless — no file I/O in the module; the
caller owns the allocator.

Closes #41.
@sepehr-safari sepehr-safari merged commit 76284cf into main Jul 11, 2026
3 checks passed
@sepehr-safari sepehr-safari deleted the feat/report-generation branch July 11, 2026 20:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(engine): trace report generation — Markdown + HTML

1 participant