Implement FIN-WP-0001 ledger, evaluate, and evidence lane (T03–T05)
Add SQLite-backed cost ledger with import/summary CLI, cron-friendly evaluate command with federation emit, and dogfood evidence artefact generation from fixture CSVs.
This commit is contained in:
parent
d6f88cd70a
commit
277c2d05ca
12 changed files with 760 additions and 7 deletions
60
tests/test_ledger.py
Normal file
60
tests/test_ledger.py
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from fin_hub.services.evaluate import evaluate_runway
|
||||
from fin_hub.services.evidence import build_runway_report, seed_fixture_ledger, write_runway_evidence
|
||||
from fin_hub.services.ledger import import_csv, monthly_burn_series, monthly_summary, set_opening_balance
|
||||
|
||||
FIXTURES = Path(__file__).parent / "fixtures"
|
||||
|
||||
|
||||
def test_ledger_import_and_monthly_summary(tmp_path: Path):
|
||||
ledger = tmp_path / "ledger.db"
|
||||
set_opening_balance(ledger, 12000.0)
|
||||
|
||||
cloud = import_csv(FIXTURES / "cloud-costs.csv", "cloud", ledger_path=ledger)
|
||||
host = import_csv(FIXTURES / "hosteurope.csv", "hosteurope", ledger_path=ledger)
|
||||
|
||||
assert cloud.rows_imported == 3
|
||||
assert host.rows_imported == 2
|
||||
|
||||
rollups = monthly_summary(ledger_path=ledger)
|
||||
eur_totals = {rollup.period_month: rollup.total for rollup in rollups if rollup.currency == "EUR"}
|
||||
assert eur_totals["2026-06"] == pytest.approx(85.5 + 99.8)
|
||||
|
||||
burns = monthly_burn_series(ledger_path=ledger, currency="EUR")
|
||||
assert burns == [pytest.approx(185.3)]
|
||||
|
||||
|
||||
def test_ledger_import_skips_unchanged_file(tmp_path: Path):
|
||||
ledger = tmp_path / "ledger.db"
|
||||
first = import_csv(FIXTURES / "cloud-costs.csv", "cloud", ledger_path=ledger)
|
||||
second = import_csv(FIXTURES / "cloud-costs.csv", "cloud", ledger_path=ledger)
|
||||
assert first.rows_imported == 3
|
||||
assert second.skipped is True
|
||||
assert second.rows_imported == 0
|
||||
|
||||
|
||||
def test_evaluate_runway_from_ledger(tmp_path: Path):
|
||||
ledger = tmp_path / "ledger.db"
|
||||
seed_fixture_ledger(ledger_path=ledger, opening_balance=12000.0)
|
||||
report = evaluate_runway(ledger_path=ledger, alert_threshold_months=3.0)
|
||||
assert report["runway"]["current_balance"] == 12000.0
|
||||
assert report["runway"]["monthly_burn"] > 0
|
||||
|
||||
|
||||
def test_build_runway_report_and_write_evidence(tmp_path: Path):
|
||||
ledger = tmp_path / "ledger.db"
|
||||
seed_fixture_ledger(ledger_path=ledger, opening_balance=12000.0)
|
||||
text = build_runway_report(ledger_path=ledger)
|
||||
assert "Runway Dogfood Evidence" in text
|
||||
assert "2026-06" in text
|
||||
|
||||
output = write_runway_evidence(
|
||||
ledger_path=ledger,
|
||||
output_dir=tmp_path / "evidence",
|
||||
opening_balance=12000.0,
|
||||
)
|
||||
assert output.exists()
|
||||
assert "runway-dogfood-" in output.name
|
||||
Loading…
Add table
Add a link
Reference in a new issue