mirror of
https://github.com/magnus919/agent-skills.git
synced 2026-09-12 20:16:29 +03:00
* fix(calculator): honest burn-multiple and runway labels, surface model assumptions - Burn Multiple now reports Graham's metric (net burn / net new ARR); the net burn / MRR ratio is reported separately as Burn to Revenue. The qualifier (efficient/healthy/warning/critical) is derived from the real burn multiple, so DEAD verdicts no longer print 'efficient'. - ALIVE verdicts no longer print a misleading 'Runway: 120 months' (projection cap); output now shows 'Projected cash-out' with 'none within the 10-year projection' when the company never runs out. - Model assumptions (fixed/variable burn split, variable burn ratio, growth decay, projection cap, safety buffer) are now surfaced in the human report and in JSON model_assumptions. - SKILL.md: fix dead paulgraham.com/default.html source URL to aord.html; update output-field docs and examples to real model output. - Add regression tests (tests/integration/test_default_alive.py). Fixes #272 Fixes #273 * docs(calculator): add When Not to Use boundary (validator requirement)
69 lines
2.4 KiB
Python
69 lines
2.4 KiB
Python
"""Regression tests for yc-default-alive-calculator output labeling.
|
|
|
|
Covers issues #272 (Burn Multiple mislabel) and #273 (runway display and
|
|
unsurfaced model assumptions): the canonical Burn Multiple is Graham's
|
|
net burn / net new ARR, the MRR ratio has an honest name, ALIVE verdicts
|
|
no longer print a misleading projection-cap runway, and model assumptions
|
|
are surfaced in the output.
|
|
"""
|
|
|
|
import importlib.util
|
|
from pathlib import Path
|
|
|
|
SCRIPT = Path(__file__).resolve().parents[2] / "yc-default-alive-calculator" / "scripts" / "default-alive.py"
|
|
|
|
_spec = importlib.util.spec_from_file_location("default_alive", SCRIPT)
|
|
assert _spec is not None and _spec.loader is not None
|
|
MOD = importlib.util.module_from_spec(_spec)
|
|
_spec.loader.exec_module(MOD)
|
|
|
|
|
|
def calc(revenue, burn, cash, growth):
|
|
return MOD.project_trajectory(
|
|
monthly_revenue=revenue,
|
|
monthly_burn=burn,
|
|
cash_on_hand=cash,
|
|
monthly_growth_pct=growth,
|
|
growth_decay_pct=0.5,
|
|
)
|
|
|
|
|
|
def test_lean_saas_alive_diagnostics():
|
|
d = calc(12000, 18000, 220000, 7)
|
|
diag = d["diagnostics"]
|
|
assert d["verdict"] == "ALIVE"
|
|
assert diag["burn_multiple"] == 0.6 # Graham: net burn / net new ARR
|
|
assert diag["burn_to_revenue_ratio"] == 0.5 # net burn / MRR
|
|
assert diag["projected_cashout_month"] is None
|
|
assert "none within the 10-year projection" in d["explanation"]
|
|
assert "Runway:" not in d["explanation"]
|
|
|
|
|
|
def test_dead_verdict_labels_are_honest():
|
|
d = calc(12000, 26000, 220000, 3)
|
|
diag = d["diagnostics"]
|
|
assert d["verdict"] == "DEAD"
|
|
assert diag["burn_multiple"] == 3.24
|
|
assert diag["burn_to_revenue_ratio"] == 1.17
|
|
assert diag["projected_cashout_month"] == 18
|
|
assert "critical" in d["explanation"]
|
|
assert "efficient" not in d["explanation"]
|
|
assert "net burn / net new ARR" in d["explanation"]
|
|
|
|
|
|
def test_model_assumptions_surfaced():
|
|
d = calc(12000, 26000, 220000, 3)
|
|
a = d["model_assumptions"]
|
|
assert a["fixed_burn_pct"] == 70.0
|
|
assert a["variable_burn_ratio"] == 0.65
|
|
assert a["growth_decay_pct"] == 0.5
|
|
assert a["projection_cap_months"] == 120
|
|
assert a["safety_buffer_months"] == 3
|
|
|
|
|
|
def test_pre_revenue_has_no_burn_multiple():
|
|
d = calc(0, 80000, 400000, 0)
|
|
assert d["verdict"] == "DEAD"
|
|
assert d["diagnostics"]["burn_multiple"] is None
|
|
assert d["diagnostics"]["burn_to_revenue_ratio"] is None
|