Skip to content

refactor: separate Behavior Diff report rendering - #6

Merged
kentwelcome merged 19 commits into
mainfrom
feature/report-rendering-structure
Sep 4, 2026
Merged

refactor: separate Behavior Diff report rendering#6
kentwelcome merged 19 commits into
mainfrom
feature/report-rendering-structure

Conversation

@kentwelcome

Copy link
Copy Markdown
Contributor

Summary

  • add an immutable, versioned ReportData structure and internal report-data.json
  • split loading, shared copy, Markdown, HTML, and CSS behind the existing import-safe render.py command
  • freeze captured and self-reported output bytes and expand deterministic schema, renderer, stdout, fallback, and compile checks

Test plan

  • docker run --rm -v "$PWD:/mnt" -w /mnt mvdan/shfmt:v3.14.0 -d -i 2 -ci .
  • uvx ruff@0.16.5 format --check --diff .
  • bash tests/hooks-test.sh
  • python3 plugin/skills/behavior-diff/scripts/decisions.py --check
  • bash tests/live-report-contract.sh
  • bash tests/release-workflow-test.sh
  • inspect the captured HTML fixture at desktop and mobile widths
  • independent review: APPROVE

Notes

  • the six existing ShellCheck findings are unchanged from origin/main; this branch adds none

Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Signed-off-by: Kent Huang <kent@infuseai.io>
Copilot AI lite review requested due to automatic review settings September 4, 2026 06:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A few small robustness gaps (notably result.kind validation and clearer renderer failures) can still lead to KeyError crashes or misleading warnings in edge-case inputs.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Refactors Behavior Diff report generation into a layered, import-safe pipeline with a versioned internal ReportData schema and frozen byte-for-byte fixtures, while keeping the existing render.py CLI and report outputs stable.

Changes:

  • Introduces immutable, versioned ReportData + report-data.json, and splits loading/shared copy/Markdown/HTML/CSS into reporting/.
  • Makes render.py a thin orchestrator that renders all outputs in memory, then writes report-data.json, report.md, report-artifact.html, and report.html.
  • Expands deterministic contracts: schema round-trips, import-safety, stdout stability, CSS token checks, and byte-for-byte fixtures for captured + self-reported runs.
File summaries
File Description
tests/report-schema-test.py Adds schema round-trip + renderer determinism + import-safety checks.
tests/live-report-contract.sh Extends contract test to validate stdout, fixtures, and report-data.json invariants; adds fixture update mode and usage checks.
tests/fixtures/report-rendering/self-reported/report.md Golden Markdown fixture for self-reported mode.
tests/fixtures/report-rendering/self-reported/report.html Golden full HTML fixture for self-reported mode.
tests/fixtures/report-rendering/self-reported/report-artifact.html Golden HTML artifact fixture for self-reported mode.
tests/fixtures/report-rendering/captured/report.md Golden Markdown fixture for captured mode.
tests/fixtures/report-rendering/captured/report.html Golden full HTML fixture for captured mode.
tests/fixtures/report-rendering/captured/report-artifact.html Golden HTML artifact fixture for captured mode.
plugin/skills/behavior-diff/scripts/reporting/init.py Marks reporting/ as a private package.
plugin/skills/behavior-diff/scripts/reporting/schema.py Defines immutable report schema + deterministic (de)serialization.
plugin/skills/behavior-diff/scripts/reporting/content.py Centralizes shared, format-neutral report copy and headings.
plugin/skills/behavior-diff/scripts/reporting/load.py Loads persisted run evidence into ReportData (flow, decisions, diff, counts).
plugin/skills/behavior-diff/scripts/reporting/render_markdown.py Pure Markdown renderer from ReportData.
plugin/skills/behavior-diff/scripts/reporting/render_html.py Pure HTML renderer (artifact + document) from ReportData + CSS.
plugin/skills/behavior-diff/scripts/reporting/report.css Moves CSS into a source file with __RESULT_BG__ substitution token.
plugin/skills/behavior-diff/scripts/render.py Replaces monolithic renderer with orchestration + writes + stable stdout.
plans/2026-09-04-report-rendering-structure.md Design doc for the refactor and invariants/acceptance criteria.
plans/2026-09-04-report-rendering-structure-implementation.md Implementation plan and sequencing for the refactor.
CODING_GUIDELINES.md Updates py_compile guidance to include reporting/*.py.
.github/workflows/ci.yml Updates CI py_compile step to include reporting/*.py.
Review details
  • Files reviewed: 19/20 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +193 to +196
diff_heading=names["diff"],
decision_heading=names["decision"],
decision_blurb=decision_blurb(self_reported, before_total),
flow_heading=names["flow"],

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 57759dd. build_content() now enables the one-trial caution only when both before_total == 1 and after_total == 1 (content.py:195-197). The regression test covers (1, 2), (2, 1), and (1, 1).

Comment on lines +16 to +20
def _resolve_css(css: str, result_kind: str) -> str:
if css.count("__RESULT_BG__") != 1:
raise ValueError("report.css must contain __RESULT_BG__ exactly once")
return css.replace("__RESULT_BG__", _RESULT_BACKGROUNDS[result_kind])

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 57759dd. _resolve_css() keeps the CSS-token check first, then rejects an unsupported result kind with ValueError: unsupported report result kind: <kind> (render_html.py:16-21). Tests cover the new error and token-validation precedence.

Comment on lines +226 to +231
def _result(value, path):
value = _expect_dict(value, path)
return ResultData(
text=_expect_str(_field(value, "text", path), path + ".text"),
kind=_expect_str(_field(value, "kind", path), path + ".kind"),
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 57759dd. Schema-v1 loading now restricts result.kind to good, bad, or neutral and raises the path-aware ValueError at schema.py:227-235. Tests cover both an unsupported string and a non-string value.

- require both variants for the one-trial caution
- validate result kinds at schema and renderer boundaries
- cover asymmetric counts and error precedence

Signed-off-by: Kent Huang <kent@infuseai.io>
@kentwelcome
kentwelcome merged commit 1ef3904 into main Sep 4, 2026
2 checks passed
@kentwelcome
kentwelcome deleted the feature/report-rendering-structure branch September 4, 2026 07:05
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.

2 participants