HTML Dashboards - Metrics Leaders Will Actually Open
Static, linkable files beat unread TSV piles
Engineering metrics that only live in TSV and _raw.json do not change staff meetings. Analysts open them; directors do not. On a delivery program I lead, the pipeline already produced honest person and PR rollups - and the numbers still sat unread until someone pasted a screenshot into Slack.
Here's what this piece covers: the leadership problem of unread analyst artifacts, what commit 8c5b196 (2026-06-30) shipped, the HTML + cache path I still use, the named pattern, and three habits before you fund another BI project.
Part of the Field Notes: agentic delivery series - visibility only works when leaders can open the artifact without a project.
1. The leadership problem
Month-end review needs narrative and drill-down in one place. Notebooks and TSV piles create a notebook graveyard - analysis only the author can re-run.
Wrong: "We need a BI tool."
Right: "8c5b196: one self-contained HTML dashboard from the same pipeline - opened in exec prep because it is a file, not a project."
Leaders will open a Chrome link. They will not open Jupyter, a SharePoint permission maze, or a folder of _raw.json.
2. What the git history shows
On 2026-06-30, commit 8c5b196 - some major changes - landed the presentation layer:
| Artifact | What landed |
|---|---|
export/html.py |
+761 lines - self-contained HTML with inline CSS/JS |
cache/data_store.py |
Local data/ snapshot cache (schema version, window, timezone) |
pipeline/retry_skipped.py |
Recover skipped PRs without a full re-fetch |
docs/architecture.md |
Cache-first run --html path documented |
Same metrics as TSV/Excel; different audience. Analysts keep tabular exports. Leaders get a file they can email, drop in SharePoint, or open offline.
A tiny shape for the export boundary:
def export_html_report(
results: list[ReportResult],
output_path: str | Path,
*,
bucket_granularity: str = "weekly",
) -> Path:
payload = build_report_payload(results, bucket_granularity=bucket_granularity)
target = Path(output_path).expanduser()
target.write_text(render_html(payload), encoding="utf-8")
return target3. What I built
Self-contained HTML - no server, no login. Overview, person views, sortable tables, weekly/monthly buckets via --bucket. One panel is enough for staff prep: who moved, who reviewed, where cycle time spiked.
data/ snapshot cache - matching repo + date window + timezone loads without hitting GitHub. Misses fetch once, then render fast for re-opens during the same review week.
retry_skipped - partial pipeline failures stop being an all-or-nothing re-run. Recovery is a path, not a war story.
The anti-pattern this replaces is shipping metrics only the pipeline author trusts. HTML is the presentation layer; TSV remains the audit trail when someone challenges a number.
What broke: the first commit also checked in bytecode under __pycache__/ - cleaned later (127196d). Large HTML files are an acceptable trade for an exec audience; do not optimize file size before someone opens them.
4. Named pattern: HTML leaders will open
HTML leaders will open - static, linkable, no login friction; same pipeline as TSV, different audience.
| Layer | Who uses it | Decision it supports |
|---|---|---|
| HTML dashboard | EM, directors | "What changed this window?" |
| TSV / Excel | Analysts, deep dive | Column-level audit |
data/ cache |
Whoever regenerates | Fast re-render without API burn |
| Run log | When challenged | Provenance of the number |
What broke: presentation without a run log turns into "trust me." HTML is not a BI replacement - it is the monthly review surface that precedes deeper burn-down work (visibility before burn-down).
5. What I'd do as a lead
Three habits - steal one this month:
- Standardize on one HTML template for monthly reviews. Same panels every time; stop inventing a new slide deck from raw exports.
- Pair the dashboard with the run log when numbers are challenged. Presentation and provenance travel together.
- Do not replace person-summary TSV with HTML. HTML is the layer leaders open; TSV is how you defend a cell.
Further reading
- Field notes: agentic delivery - series intro
- Next: Specifications as execution contracts
- github-analysis anchor: commit
8c5b196· 2026-06-30 ·docs/architecture.md