v0.1.9: per-company progress reviews + deck-quality guidance

progress.py reads the whole graded ledger and answers two questions the
per-deck scorecard can't: is the company actually progressing (composite/
BDEF-category/KPI trajectories, recurring vs resolved flags), and is the
material good enough to judge them by — a deterministic gap engine spots
what the decks are NOT showing (no profitability visibility, untargeted
KPIs, no forward guidance, broken forecast chain, silently dropped KPIs,
thin-evidence BDEF categories, no board asks) and renders each gap as a
concrete, paste-ready request for the next deck.

Served live from the ledger (no GPU) at /api/companies/{slug}/progress(.md),
written to /data/ledger/<slug>/PROGRESS.md + /data/reports/latest-progress.md
after each graded deck, and viewable/downloadable from the dashboard company
card ("View progress review"). 18 new tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jonathan Kirkwood
2026-07-31 20:50:41 -05:00
co-authored by Claude Fable 5
parent 506e6c79bd
commit 9b9c7e58c1
8 changed files with 792 additions and 14 deletions
+9 -2
View File
@@ -51,6 +51,7 @@ import extraction
import graders as gr_mod
import ledger as ledger_mod
import preflight
import progress as progress_mod
import scorecard
import scoring
import serving
@@ -605,14 +606,20 @@ class JobRunner:
with open(os.path.join(report_deck_dir, "ADJUDICATION.md"), "w") as f:
f.write(adjudication_md + "\n")
# Refresh the company scorecard + the /data/reports latest copy.
sc_md = scorecard.render_scorecard(led.get_company(slug_c), led.deck_records(slug_c))
# Refresh the company scorecard + progress review + /data/reports copies.
company_now = led.get_company(slug_c)
sc_md = scorecard.render_scorecard(company_now, all_recs)
sc_path = os.path.join(LEDGER_DIR, slug_c, "SCORECARD.md")
os.makedirs(os.path.dirname(sc_path), exist_ok=True)
with open(sc_path, "w") as f:
f.write(sc_md)
with open(os.path.join(REPORTS_DIR, "latest-scorecard.md"), "w") as f:
f.write(sc_md)
prog_md = progress_mod.render_progress_md(progress_mod.analyze(company_now, all_recs))
with open(os.path.join(LEDGER_DIR, slug_c, "PROGRESS.md"), "w") as f:
f.write(prog_md)
with open(os.path.join(REPORTS_DIR, "latest-progress.md"), "w") as f:
f.write(prog_md)
self.log(f"[runner] reports saved to {report_deck_dir}")
return {"period": period, "deck_id": deck_id, "composite": _composite(record),