{esc(rec.get('title', '(untitled)'))}
{esc(rec.get('id', ''))}{esc(rec.get("body"))}
' if rec.get('body') else ''}Diagnostics
{pretty(diag)}
#!/usr/bin/env python3
"""Generate a deterministic BUG-REPORT.html from data/reports/*.json.
Every field is HTML-escaped; the page is self-contained (no external assets).
Output is stable for a given set of reports — no wall-clock timestamps.
"""
import glob
import html
import json
import os
import sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
REPORTS_DIR = os.path.join(ROOT, "data", "reports")
OUT_FILE = os.path.join(ROOT, "downloads", "bugs", "BUG-REPORT.html")
MAX_REPORTS = 200
def esc(value):
return html.escape("" if value is None else str(value), quote=True)
def load_reports():
rows = []
for path in sorted(glob.glob(os.path.join(REPORTS_DIR, "RPT-*.json"))):
try:
with open(path, encoding="utf-8") as fh:
rec = json.load(fh)
if isinstance(rec, dict) and rec.get("id"):
rows.append(rec)
except (OSError, ValueError):
continue
rows.sort(key=lambda r: (str(r.get("created_at", "")), str(r.get("id", ""))), reverse=True)
return rows[:MAX_REPORTS]
def pretty(value, limit=6000):
try:
text = json.dumps(value, indent=2, ensure_ascii=False)
except (TypeError, ValueError):
text = str(value)
if len(text) > limit:
text = text[:limit] + "\n… (truncated)"
return esc(text)
def render(rows):
total = len(rows)
latest = esc(rows[0].get("created_at", "—")) if rows else "—"
cards = []
for rec in rows:
diag = rec.get("diagnostics") if isinstance(rec.get("diagnostics"), dict) else {}
errors = diag.get("errors") if isinstance(diag.get("errors"), list) else []
cards.append(
f""" {esc(rec.get("body"))}{esc(rec.get('title', '(untitled)'))}
{esc(rec.get('id', ''))}
Diagnostics
{pretty(diag)}
No reports yet. Run bug <title> in newOS4.
Generated from data/reports/*.json — no manual edits.