# HTML Report Verify

> Visual + structural verification of HTML benchmark/validation reports using the Claude-in-Chrome extension. Opens the report in a browser, takes screenshots, checks key DOM elements, and produces a PASS/FAIL verdict. Generic by default; module-specific check lists extend the base set.

- Skill: `vamseeachanta/html-report-verify-2` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add vamseeachanta/html-report-verify-2`
- Raw SKILL.md: https://api.skillmd.com/api/skills/vamseeachanta/html-report-verify-2/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: vamseeachanta (https://skillmd.com/u/vamseeachanta)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/vamseeachanta/html-report-verify-2

---


# /html-report-verify — HTML Report Visual & Structural Verification

Opens an HTML report in Chrome (via local HTTP server for local files) and
performs layered verification: console errors → DOM structure → visual scan →
module-specific checks.

## Trigger

```
/html-report-verify <path-or-url> [--module <name>]
```

Examples:
```
/html-report-verify docs/modules/orcawave/L00_validation_wamit/3.2/benchmark/benchmark_report.html --module orcawave-qtf
/html-report-verify http://localhost:8974/3.1/benchmark/benchmark_report.html
```

## Verification Layers

### Layer 0 — Server Setup (local files only)
If a local path is given, start a Python HTTP server in the parent directory on
a free port (default `8974`). Use `uv run python -m http.server` so the uv
environment is active. For background tool launches, explicitly `cd` into the
intended server root inside the command (for example `cd /path/to/repo && python -m http.server 8974`) rather than relying only on the tool's `workdir`; a wrong server root produces misleading 404s even when the file exists. Kill the server after verification is complete.

For a user asking only for a clickable HTML review link, do the minimal hyperlink path instead of full visual QA: start or reuse a local server from the artifact's parent directory, move to the next free port if the default is occupied, verify the exact URL returns `200 OK` with `curl -I`/HEAD, then return a concise Markdown hyperlink plus artifact path and verification status. Do not present an unverified server-start URL as review-ready.

### Layer 1 — Page Load
- Navigate to URL via `mcp__claude-in-chrome__navigate`
- Take screenshot immediately
- Check `mcp__claude-in-chrome__read_console_messages` for JS errors (`onlyErrors: true`)
- FAIL if console shows uncaught errors or the page is blank

### Layer 2 — Generic DOM Structure Checks
Run via `mcp__claude-in-chrome__javascript_tool`:

For static local collateral where browser/MCP verification is unnecessary or unavailable, use Python stdlib `html.parser` for basic title/link/content checks instead of depending on BeautifulSoup; many worktree/agent environments do not have `bs4` installed.

| Check | Selector / Test | Pass Condition |
|-------|----------------|----------------|
| Title present | `document.title` | Non-empty string |
| H1/H2 headings | `querySelectorAll('h1,h2').length` | ≥ 1 |
| Navigation bar | `querySelector('.nav-bar, nav, [class*="nav"]')` | Not null |
| Plotly charts rendered | `querySelectorAll('.js-plotly-plot, .plotly-graph-div').length` | ≥ 1 |
| No broken images | `[...querySelectorAll('img')].every(i => i.complete && i.naturalWidth > 0)` | True |
| No empty script errors | Check console | Zero JS exceptions |

### Layer 3 — Visual Screenshot Scan
1. Screenshot top of page (executive summary / header)
2. Scroll to bottom (`window.scrollTo(0, document.body.scrollHeight)`)
3. Screenshot bottom of page (should show QTF / last section)
4. Confirm plots are visible (not grey/blank boxes)

### Layer 3b — Data Contract Cross-Check for Parameter-Sweep Reports
When a report visualizes generated sweep data (speed × heading × angle, cases × phases, benchmarks, etc.), do not stop at DOM rendering. Cross-check the rendered controls and embedded/chart data against the source artifact (`.csv`, `.json`, manifest, or generator summary):
- Enumerate dropdown options and selected defaults from the DOM.
- Verify sweep cardinality from source data (e.g., rows per current speed, heading/rudder ranges and step counts).
- Exercise at least one dropdown change and verify chart titles/data update.
- Confirm scope/provenance caveats are visible when the displayed quantity is a subset/model approximation rather than total physical load.
- Include any extra default case policy in the verdict (for example, a chart default speed outside the requested sweep list).

### Layer 3c — Multi-Artifact Engineering Report Bundle Checks
When a generator emits an HTML/PDF report plus CSV/JSON/provenance/manifest artifacts, verify the bundle before summarizing success:
- Parse the manifest and confirm every referenced artifact exists and has non-zero size.
- Cross-check generated CSV/JSON row counts and key extrema against the command output or generator summary.
- Verify HTML structure with browser tools when available; if browser verification is unavailable, use Python stdlib `html.parser` for title, headings, expected section labels, schematic captions, and provenance/caveat text.
- Verify PDF readability by extracting text/metadata when possible. If only file existence/size was checked, label PDF status as "existence-only" and do not claim content fidelity.
- For engineering force reports, confirm individual component forces, resultant forces, heading/rudder-angle convention schematics, and selected basecase/current magnitude are visible in the report.
- Treat non-blocking solver/license warnings as caveats, not failures, when the report path uses packaged/static input data and all artifacts are produced.

### Layer 4 — Module-Specific Checks

#### `--module orcawave-qtf`
| Check | Test | Pass Condition |
|-------|------|----------------|
| QTF section exists | `document.getElementById('qtf-analysis')` | Not null |
| QTF heading | `querySelector('#qtf-analysis h2')?.textContent` | Contains "QTF Analysis" |
| Figure cards | `querySelectorAll('#qtf-analysis .qtf-figure').length` | ≥ 1 |
| Figure titles (h3) | `querySelectorAll('#qtf-analysis h3').length` | Matches figure count |
| Reference images | `querySelectorAll('#qtf-analysis img[src^="data:image"]').length` | ≥ 1 (if screenshots available) |
| Plotly in QTF section | `querySelectorAll('#qtf-analysis .plotly-graph-div').length` | ≥ 1 |
| OrcaWave label | Text search for "OrcaWave Output" | Present |
| Reference label | Text search for "Reference (WAMIT paper)" | Present |

Scroll into `#qtf-analysis` and take a screenshot to capture side-by-side layout.

#### `--module benchmark-correlation`
| Check | Test | Pass Condition |
|-------|------|----------------|
| Consensus table | `querySelector('table')` | Not null |
| DOF sections | `querySelectorAll('[id^="dof-"]').length` | ≥ 1 |
| Correlation values | Text contains `r=` | ≥ 1 match |
| Pass/Fail badges | Elements with green/red color styling | Present |

### Layer 5 — Verdict
Produce a structured report:

```
HTML Report Verification — <filename>
======================================
URL          : http://localhost:8974/...
Module checks: orcawave-qtf

Layer 1 (Load)         : PASS
Layer 2 (DOM)          : PASS  [3 h2, 12 Plotly divs, 0 broken images]
Layer 3 (Visual)       : PASS  [screenshots attached]
Layer 4 (Module: QTF)  : PASS  [2 figures, 2 reference images]

OVERALL: ✅ PASS
```

If any layer fails, list the specific failing check and what was found vs expected.

## Implementation Notes

- See `references/parameter-sweep-report-review.md` for the data-contract + interaction checklist for generated engineering parameter-sweep chart reports.
- See `references/engineering-report-artifact-verification.md` for manifest/HTML/PDF/CSV/JSON verification when an engineering report generator emits a multi-artifact bundle.
- See `references/client-review-export-closeout.md` for locating an existing HTML report with tolerant spelling/condition-token search, producing PDF/DOCX client-review copies, verifying URLs/content, and closing out issue-scoped follow-up artifacts.
- Always call `mcp__claude-in-chrome__tabs_context_mcp` first to get a valid tab ID
- Use `mcp__claude-in-chrome__tabs_create_mcp` for a fresh tab (don't reuse report tab)
- After verification, kill the HTTP server: `pkill -f "http.server 8974"` (Linux/macOS) or `taskkill` (Windows)
- On Windows MINGW: use `uv run python -m http.server` (not `python3`)
- The Plotly CDN script in the QTF section may cause a duplicate Plotly load warning in console — this is expected, not a failure

## Extending for New Modules

Add a new `--module <name>` block to Layer 4. The module check function receives
the tab ID and runs additional `javascript_tool` calls + screenshots tailored to
that report's specific sections.

## Style Quality Checklist

When verifying, note (but do not fail on) these visual quality signals:
- [ ] Section headers have consistent hierarchy (H1 → H2 → H3)
- [ ] Color scheme is consistent (no clashing inline colors)
- [ ] Charts have explicit physical-scope labels in titles/axes (for example, "rudder-induced" vs total-load wording when the model is bounded)
- [ ] Charts have readable axis labels, units, legends/colorbars, and hover text with the governing parameters
- [ ] Default controls produce a screenshot-ready state and do not imply an extreme/off-nominal case unless that is intentional and documented
- [ ] Parameter-sweep reports include a visible selected-case or selected-speed summary panel/table when a single dropdown controls multiple charts
- [ ] Reference screenshots are labeled ("Reference (WAMIT paper)")
- [ ] Side-by-side comparison columns are balanced in width
- [ ] No content overflow or horizontal scroll at 1280px viewport

