from __future__ import annotations
# ── Dark G100 design tokens ──────────────────────────────────────────────────
_BG = "#161616"
_L1 = "#262626" # layer 01 — panels
_L2 = "#393939" # layer 02 — rows / hover
_L3 = "#525252" # layer 03 — borders
_T1 = "#f4f4f4" # text primary
_T2 = "#c6c6c6" # text secondary
_T3 = "#8d8d8d" # text helper / labels
_T4 = "#6f6f6f" # text disabled / placeholder
_BLUE = "#4589ff" # interactive (blue-40)
_BLUE_DIM = "#001d6c" # blue tint bg (blue-90)
_BLUE_LNK = "#78a9ff" # link / code (blue-30)
# status — dark
_ERR_BG = "#2d0709"; _ERR_BD = "#ff8389"; _ERR_FG = "#ff8389"
_WARN_BG = "#302200"; _WARN_BD = "#f1c21b"; _WARN_FG = "#f1c21b"
_OK_BG = "#071908"; _OK_BD = "#42be65"; _OK_FG = "#42be65"
_INFO_BG = _BLUE_DIM; _INFO_BD = _BLUE; _INFO_FG = _BLUE
_FONT = "'IBM Plex Sans', system-ui, -apple-system, sans-serif"
_MONO = "'IBM Plex Mono', 'SFMono-Regular', Consolas, monospace"
# ── SVG icons ────────────────────────────────────────────────────────────────
_SVG_ERROR = (
""
" "
)
_SVG_WARNING = (
""
" "
)
_SVG_CHECK = (
""
" "
)
_SVG_INFO = (
""
" "
)
_NOTIFICATION: dict[str, dict] = {
"approved": {"border": _OK_BD, "bg": _OK_BG, "color": _OK_FG, "icon": _SVG_CHECK, "label": "APPROVED"},
"needs_human_review": {"border": _WARN_BD, "bg": _WARN_BG, "color": _WARN_FG, "icon": _SVG_WARNING, "label": "NEEDS HUMAN REVIEW"},
"rejected": {"border": _ERR_BD, "bg": _ERR_BG, "color": _ERR_FG, "icon": _SVG_ERROR, "label": "REJECTED"},
"refused": {"border": _ERR_BD, "bg": _ERR_BG, "color": _ERR_FG, "icon": _SVG_ERROR, "label": "REFUSED"},
}
_DEFAULT_NOTIFICATION = {"border": _L3, "bg": _L1, "color": _T3, "icon": _SVG_INFO, "label": "UNKNOWN"}
def _notification_html(action: str, reason: str) -> str:
cfg = _NOTIFICATION.get(action, _DEFAULT_NOTIFICATION)
return (
f"
"
f"
{cfg['icon']} "
f"
"
f"
{cfg['label']}
"
f"
{reason}
"
f"
"
)
def _severity_pill(sev: str) -> str:
dark_colors = {
"CRITICAL": (_ERR_FG, _ERR_BG),
"HIGH": ("#ffb3b8", "#3b0d0e"),
"MEDIUM": (_WARN_FG, _WARN_BG),
"LOW": (_BLUE_LNK, "#001141"),
}
fg, bg = dark_colors.get(sev, (_T3, _L2))
return (
f"{sev} "
)
def render_findings_html(rule_ids: list[str], summary: dict) -> str:
failed = summary.get("failed", len(rule_ids))
crit = int(summary.get("CRITICAL", 0))
high = int(summary.get("HIGH", 0))
med = int(summary.get("MEDIUM", 0))
rows = "".join(
f"{rid} "
for rid in rule_ids
)
table = (
f""
) if rule_ids else f"No findings
"
pills = " ".join(filter(None, [
(_severity_pill("CRITICAL") + f" {crit} ") if crit else "",
(_severity_pill("HIGH") + f" {high} ") if high else "",
(_severity_pill("MEDIUM") + f" {med} ") if med else "",
]))
return (
f""
f"
"
f"{failed} "
f"failed checks "
f"
"
f"
{pills}
"
f"{table}
"
)
def _details_html(
parse_ok: bool,
changed_ratio: float,
resolved: list[str],
unresolved: list[str],
explanation: str,
risk_notes: list[str],
) -> str:
def _row(label: str, value: str) -> str:
return (
f""
f"{label} "
f"{value} "
f" "
)
def _pill_list(items: list[str], ok: bool) -> str:
if not items:
return f"— "
fg = _OK_FG if ok else _ERR_FG
bg = _OK_BG if ok else _ERR_BG
pills = "".join(
f"{r} "
for r in items
)
return f"{pills}
"
risks_html = ""
if risk_notes:
items = "".join(f"{n} " for n in risk_notes)
risks_html = (
f""
)
expl_html = ""
if explanation:
expl_html = (
f""
f"
Explanation
"
f"
{explanation}
"
f"
"
)
table = (
f""
f"{_row('Parse OK', 'Yes' if parse_ok else 'No')}"
f"{_row('Changed lines', f'{changed_ratio:.0%}')}"
f"{_row('Resolved', _pill_list(resolved, ok=True))}"
f"{_row('Unresolved', _pill_list(unresolved, ok=False))}"
f"
"
)
return (
f""
f"{table}{expl_html}{risks_html}"
f"
"
)
def render_result(data: dict) -> tuple[str, str, str, str, str, str]:
decision = data.get("decision") or {}
action = decision.get("action", "unknown")
reason = decision.get("reason", "")
original = data.get("original_file", "")
patch_obj = decision.get("patch") or {}
fixed = patch_obj.get("fixed_file") or data.get("fixed_file", "")
pre_rules: list[str] = data.get("pre_rule_ids") or []
post_rules: list[str] = data.get("post_rule_ids") or []
pre_summary: dict = data.get("pre_summary") or {}
post_summary:dict = data.get("post_summary") or {}
validation = decision.get("validation") or data.get("validation") or {}
resolved: list[str] = validation.get("targeted_resolved") or []
unresolved: list[str] = validation.get("targeted_unresolved") or []
parse_ok: bool = validation.get("parse_ok", False)
changed_ratio: float = validation.get("changed_lines_ratio", 0.0)
explanation = patch_obj.get("explanation") or reason
risk_notes: list[str] = patch_obj.get("risk_notes") or []
return (
original,
fixed,
_notification_html(action, reason),
render_findings_html(pre_rules, pre_summary),
render_findings_html(post_rules, post_summary),
_details_html(parse_ok, changed_ratio, resolved, unresolved, explanation, risk_notes),
)
def error_html(label: str, exc: Exception) -> str:
return _notification_html("rejected", f"{label}: {exc}")