v0.1.6: human-friendly reports
- Dashboard renders deck reports and scorecards as formatted pages (self-contained markdown renderer inlined in index.html — headings, styled tables, evidence blockquotes; no CDN, air-gap friendly) - At-a-glance strip on every deck report: composite with delta vs the prior deck, quant/qual/penalty mix, KPI hit/miss chips, BDEF best/weakest category, red-flag count - Generated DECK_REPORT.md now leads with a concise "At a glance" summary table (scorecard.py); jobs.py passes the previous deck record so the delta appears in the file too; dashboard hides the duplicate section since the strip covers it - .gitignore: .venv/ Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
6bf0786993
commit
32d5d7f373
@@ -42,19 +42,68 @@ def _bucket_row(name: str, b: dict) -> str:
|
||||
f"| {b.get('kpi_count', 0)} | |")
|
||||
|
||||
|
||||
def render_deck_report(record: dict, extraction: dict, adjudication_md: str | None = None) -> str:
|
||||
def _glance_lines(record: dict, prev_record: dict | None) -> list[str]:
|
||||
"""Concise 'At a glance' table: the whole deck in five rows."""
|
||||
lines = ["## At a glance", "", "| | |", "|---|---|"]
|
||||
|
||||
comp = f"**{_fmt(record.get('composite'))} / 100**"
|
||||
if prev_record is not None and prev_record.get("composite") is not None \
|
||||
and record.get("composite") is not None:
|
||||
d = round(record["composite"] - prev_record["composite"], 1)
|
||||
comp += (f" ({_arrow(d)} {'+' if d > 0 else ''}{_fmt(d)}"
|
||||
f" vs {prev_record.get('period') or 'previous deck'})")
|
||||
elif prev_record is None:
|
||||
comp += " (first graded deck)"
|
||||
lines.append(f"| Composite | {comp} |")
|
||||
lines.append(f"| Score mix | quant {_fmt(record.get('quant', {}).get('score'))}"
|
||||
f" + qual {_fmt(record.get('qual', {}).get('score'))}"
|
||||
f" − penalties {_fmt(record.get('penalties', {}).get('total'))} |")
|
||||
|
||||
kpis = [k for k in (record.get("kpi_results") or [])
|
||||
if isinstance(k.get("credit"), (int, float))]
|
||||
if kpis:
|
||||
missed = [k.get("name") or k.get("canonical_name") or "?"
|
||||
for k in kpis if k["credit"] < 0.999]
|
||||
hit_txt = f"{len(kpis) - len(missed)} of {len(kpis)} hit"
|
||||
if missed:
|
||||
hit_txt += f" — missed: {', '.join(missed)}"
|
||||
lines.append(f"| KPIs vs target | {hit_txt} |")
|
||||
else:
|
||||
lines.append("| KPIs vs target | none targeted |")
|
||||
|
||||
scored = [(cid, c["adjusted"]) for cid in _CATEGORIES
|
||||
if (c := record.get("qual", {}).get("categories", {}).get(cid, {}))
|
||||
.get("adjusted") is not None]
|
||||
if scored:
|
||||
best = max(scored, key=lambda x: x[1])
|
||||
worst = min(scored, key=lambda x: x[1])
|
||||
lines.append(f"| BDEF best / weakest | {best[0]} · {_CATEGORY_TITLES[best[0]]}"
|
||||
f" ({_fmt(best[1])}) / {worst[0]} · {_CATEGORY_TITLES[worst[0]]}"
|
||||
f" ({_fmt(worst[1])}) |")
|
||||
|
||||
flags = record.get("penalties", {}).get("flags") or []
|
||||
if flags:
|
||||
worst_flag = max(flags, key=lambda f: f.get("points") or 0)
|
||||
lines.append(f"| Red flags | {len(flags)} "
|
||||
f"(−{_fmt(record.get('penalties', {}).get('total'))} pts;"
|
||||
f" worst: `{worst_flag.get('code')}`) |")
|
||||
else:
|
||||
lines.append("| Red flags | none |")
|
||||
lines.append("")
|
||||
return lines
|
||||
|
||||
|
||||
def render_deck_report(record: dict, extraction: dict, adjudication_md: str | None = None,
|
||||
prev_record: dict | None = None) -> str:
|
||||
"""One deck's full markdown report."""
|
||||
lines: list[str] = []
|
||||
company = record.get("company") or "?"
|
||||
period = record.get("period") or "unknown period"
|
||||
lines.append(f"# Deck report — {company} · {period}")
|
||||
lines.append("")
|
||||
lines.append(f"## Composite: **{_fmt(record.get('composite'))} / 100**")
|
||||
lines.append("")
|
||||
lines.extend(_glance_lines(record, prev_record))
|
||||
q = record.get("quant", {})
|
||||
lines.append(f"Quant {_fmt(q.get('score'))} · Qual {_fmt(record.get('qual', {}).get('score'))}"
|
||||
f" · Penalties −{_fmt(record.get('penalties', {}).get('total'))}"
|
||||
f" · graded {record.get('graded_at') or '?'} (job {record.get('job_id') or '?'})")
|
||||
lines.append(f"Graded {record.get('graded_at') or '?'} (job {record.get('job_id') or '?'})")
|
||||
lines.append("")
|
||||
|
||||
# --- quantitative buckets
|
||||
|
||||
Reference in New Issue
Block a user