"""Markdown renderers: per-deck DECK_REPORT and per-company SCORECARD. Pure string builders over the scoring record shape (scoring.score_deck) and ledger deck records — no I/O here; jobs.py decides where the files land. """ from __future__ import annotations _CATEGORIES = "ABCDEFGH" _CATEGORY_TITLES = { "A": "Incentive Alignment & Skin in the Game", "B": "Inversion Discipline & Margin of Safety", "C": "Circle of Competence & Rational Learning", "D": "Capital Allocation Quality", "E": "Moat Durability & Competitive Reality", "F": "Psychological & Cultural Health", "G": "Simplicity, Clarity & Decision Velocity", "H": "Board Value-Add & Governance Quality", } def _fmt(x, digits: int = 1) -> str: if x is None: return "—" if isinstance(x, bool): return "yes" if x else "no" if isinstance(x, float): return f"{x:.{digits}f}" return str(x) def _num(x, unit: str = "") -> str: if x is None: return "—" s = f"{x:g}" if isinstance(x, (int, float)) else str(x) return f"{s}{unit}" if unit and unit in ("%",) else (f"{s} {unit}".strip() if unit else s) def _bucket_row(name: str, b: dict) -> str: if b.get("na"): return f"| {name} | — | — | {b.get('kpi_count', 0)} | NA — weight redistributed |" return (f"| {name} | {_fmt(b.get('weight'))} | {_fmt(b.get('score'))} " f"| {b.get('kpi_count', 0)} | |") def render_deck_report(record: dict, extraction: dict, adjudication_md: str | 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("") 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("") # --- quantitative buckets lines.append("## Quantitative (max 60)") lines.append("") lines.append("| Bucket | Weight | Score | KPIs | Note |") lines.append("|---|---|---|---|---|") lines.append(_bucket_row("Profitability KPIs", q.get("profitability", {}))) lines.append(_bucket_row("Other KPIs", q.get("other", {}))) lines.append(_bucket_row("Forecast integrity", q.get("forecast_integrity", {}))) lines.append("") kpi_results = record.get("kpi_results") or [] if kpi_results: lines.append("### KPI results") lines.append("") lines.append("| KPI | Actual | Target | Source | Credit |") lines.append("|---|---|---|---|---|") for r in kpi_results: name = r.get("name") or r.get("canonical_name") or "?" if r.get("matched_via") == "fuzzy": name += " (≈ matched via fuzzy)" src = r.get("target_source") or "—" credit = "—" if r.get("credit") is None else _fmt(r.get("credit"), 2) lines.append(f"| {name} | {_num(r.get('actual'), r.get('unit') or '')} " f"| {_num(r.get('target'), r.get('unit') or '')} | {src} | {credit} |") lines.append("") fresults = record.get("forecast_results") or [] if fresults: lines.append("### Forecast integrity (prior targets vs this period's actuals)") lines.append("") lines.append("| KPI | Prior target | Actual | Accuracy |") lines.append("|---|---|---|---|") for r in fresults: lines.append(f"| {r.get('canonical_name')} | {_num(r.get('target'))} " f"| {_num(r.get('actual'))} | {_fmt(r.get('accuracy'), 2)} |") lines.append("") # --- qualitative lines.append("## Qualitative (max 40)") lines.append("") lines.append("| Category | Median | Evidence quality | Adjusted | Points |") lines.append("|---|---|---|---|---|") cats = record.get("qual", {}).get("categories", {}) for cid in _CATEGORIES: c = cats.get(cid, {}) lines.append(f"| {cid}. {_CATEGORY_TITLES[cid]} | {_fmt(c.get('median'))} " f"| {_fmt(c.get('evidence_quality'), 2)} | {_fmt(c.get('adjusted'), 2)} " f"| {_fmt(c.get('points'), 2)} |") lines.append("") for cid in _CATEGORIES: c = cats.get(cid, {}) rats = c.get("rationales") or [] if not rats: continue best = max(rats, key=lambda r: sum(len(e.get("quote") or "") for e in r.get("evidence") or [])) lines.append(f"### {cid}. {_CATEGORY_TITLES[cid]}") lines.append("") lines.append(f"**{best.get('grader')}**: {best.get('rationale')}") for ev in best.get("evidence") or []: loc = f" — {ev.get('location')}" if ev.get("location") else "" lines.append(f"> \"{ev.get('quote')}\"{loc}") lines.append("") # --- red flags flags = record.get("penalties", {}).get("flags") or [] lines.append(f"## Red flags (penalty −{_fmt(record.get('penalties', {}).get('total'))})") lines.append("") if flags: lines.append("| Code | Severity | Points | Sources | Description |") lines.append("|---|---|---|---|---|") for f in flags: lines.append(f"| `{f.get('code')}` | {f.get('severity')} | {_fmt(f.get('points'))} " f"| {', '.join(f.get('sources') or [])} | {f.get('description')} |") else: lines.append("None raised.") lines.append("") # --- narrative narrative = record.get("narrative") or extraction.get("narrative") or {} if narrative.get("summary"): lines.append("## Narrative") lines.append("") lines.append(narrative["summary"]) lines.append("") asks = narrative.get("asks") or [] if asks: lines.append("### Asks") lines.append("") for a in asks: lines.append(f"- {a}") lines.append("") if adjudication_md: lines.append("## Panel adjudication") lines.append("") lines.append(adjudication_md.strip()) lines.append("") return "\n".join(lines).rstrip() + "\n" def _arrow(delta: float) -> str: if delta > 0: return "↑" if delta < 0: return "↓" return "→" def render_scorecard(company: dict, records: list[dict]) -> str: """Company SCORECARD.md across all live deck records (oldest first).""" name = company.get("name") or company.get("slug") or "?" lines: list[str] = [f"# Scorecard — {name}", ""] if not records: lines.append("No graded decks yet.") return "\n".join(lines) + "\n" latest = records[-1] prev = records[-2] if len(records) > 1 else None comp = latest.get("composite") or 0.0 if prev is not None: delta = round(comp - (prev.get("composite") or 0.0), 1) lines.append(f"## Latest composite: **{_fmt(comp)}** ({latest.get('period')}) " f"{_arrow(delta)} {'+' if delta > 0 else ''}{_fmt(delta)} vs {prev.get('period')}") else: lines.append(f"## Latest composite: **{_fmt(comp)}** ({latest.get('period')}) — first graded deck") lines.append("") # --- composite history lines.append("## Composite history") lines.append("") lines.append("| Period | Composite | Quant | Qual | Penalties |") lines.append("|---|---|---|---|---|") for r in records: lines.append(f"| {r.get('period') or '?'} | {_fmt(r.get('composite'))} " f"| {_fmt(r.get('quant', {}).get('score'))} " f"| {_fmt(r.get('qual', {}).get('score'))} " f"| −{_fmt(r.get('penalties', {}).get('total'))} |") lines.append("") # --- categories latest vs previous lines.append("## BDEF categories (latest vs previous)") lines.append("") lines.append("| Category | Latest | Previous | Δ |") lines.append("|---|---|---|---|") lcats = latest.get("qual", {}).get("categories", {}) pcats = (prev or {}).get("qual", {}).get("categories", {}) for cid in _CATEGORIES: lp = lcats.get(cid, {}).get("points") pp = pcats.get(cid, {}).get("points") if lp is not None and pp is not None: d = round(lp - pp, 2) dcol = f"{_arrow(d)} {'+' if d > 0 else ''}{_fmt(d, 2)}" else: dcol = "—" lines.append(f"| {cid}. {_CATEGORY_TITLES[cid]} | {_fmt(lp, 2)} | {_fmt(pp, 2)} | {dcol} |") lines.append("") # --- KPI hit-rate across records order: list[str] = [] per_kpi: dict[str, list] = {} for r in records: for k in r.get("kpi_results") or []: cn = k.get("canonical_name") or k.get("name") or "?" if cn not in per_kpi: per_kpi[cn] = [] order.append(cn) per_kpi[cn].append(k.get("credit")) lines.append("## KPI hit-rate") lines.append("") lines.append("| KPI | Attempts | Hits | Streak | Last credit |") lines.append("|---|---|---|---|---|") for cn in order: credits = [c for c in per_kpi[cn] if c is not None] if not credits: continue hits = sum(1 for c in credits if c >= 1) streak = 0 for c in reversed(credits): if c >= 1: streak += 1 else: break lines.append(f"| {cn} | {len(credits)} | {hits} | {streak} | {_fmt(credits[-1], 2)} |") lines.append("") # --- open flags on the latest deck flags = latest.get("penalties", {}).get("flags") or [] lines.append(f"## Open flags ({latest.get('period')})") lines.append("") if flags: lines.append("| Code | Severity | Points | Sources | Description |") lines.append("|---|---|---|---|---|") for f in flags: lines.append(f"| `{f.get('code')}` | {f.get('severity')} | {_fmt(f.get('points'))} " f"| {', '.join(f.get('sources') or [])} | {f.get('description')} |") else: lines.append("None.") lines.append("") # --- deck reports lines.append("## Deck reports") lines.append("") for r in records: lines.append(f"- {r.get('period') or '?'} — composite {_fmt(r.get('composite'))} — " f"decks/{r.get('deck_id')}.json / DECK_REPORT.md") return "\n".join(lines).rstrip() + "\n"