feat(portfolio): complete RESOURCE-WP-0003 T06 optimization cases and T07 reporting
T06: optimization-case schema, fail-closed evaluator, cadence and decision template. Every option including the baseline must present all ten decision fields; one unknown blocks the comparison. Validated on the storage case (Hetzner computes and loses to Scaleway by EUR 29.14/month on operator labour; Host Europe blocks on four named gaps) and on the non-storage reef-railiance k3s rightsizing case (low utilization is real, but nothing is costable while the railiance01 price is unknown). T07: portfolio report over coverage, lifecycle, utilization, cost, renewals, risks, open cases, and next actions, derived only from committed evidence. Portfolio spend is reported null rather than as a partial sum, unattributed cost is a named list rather than a spread, and unmeasurable resources are reported rather than dropped. RESOURCE-WP-0003 is finished; both cases remain blocked_on_evidence against live delegated records in other repositories. RESOURCE-WP-0002 is untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
54dd45c926
commit
2c2a6073ff
63 changed files with 4662 additions and 69 deletions
62
tests/test_cost_model.py
Normal file
62
tests/test_cost_model.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import json
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parents[1] / "tools"))
|
||||
from cost_model import forecast
|
||||
|
||||
|
||||
class CostModelTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
root = Path(__file__).parents[1]
|
||||
self.demand = json.loads((root / "data/demand/platform-audit-storage.json").read_text())
|
||||
self.providers = json.loads((root / "data/providers/object-storage.json").read_text())
|
||||
|
||||
def test_all_scenarios_and_providers_are_projected_for_12_months(self):
|
||||
result = forecast(self.demand, self.providers)
|
||||
for rows in result["scenarios"].values():
|
||||
self.assertEqual(12 * len(self.providers["providers"]), len(rows))
|
||||
|
||||
def test_unknown_prices_never_become_zero(self):
|
||||
result = forecast(self.demand, self.providers)
|
||||
host_europe = [r for r in result["scenarios"]["base"] if r["provider_id"] == "host-europe-cloud-storage"]
|
||||
self.assertTrue(all(r["recurring_total_eur"] is None for r in host_europe))
|
||||
self.assertTrue(all(r["missing_price_fields"] for r in host_europe))
|
||||
|
||||
def test_storage_grows_month_over_month(self):
|
||||
result = forecast(self.demand, self.providers)
|
||||
rows = [r for r in result["scenarios"]["high"] if r["provider_id"] == "scaleway-standard-multi-az"]
|
||||
self.assertGreater(rows[-1]["stored_gb"], rows[0]["stored_gb"])
|
||||
|
||||
def test_fixed_capacity_self_hosted_option_fails_closed_when_full(self):
|
||||
result = forecast(self.demand, self.providers)
|
||||
rows = [r for r in result["scenarios"]["base"] if r["provider_id"] == "hetzner-garage-3"]
|
||||
self.assertIsNotNone(rows[0]["recurring_total_eur"])
|
||||
self.assertIsNone(rows[-1]["recurring_total_eur"])
|
||||
|
||||
def test_managed_cloud_comparators_calculate(self):
|
||||
result = forecast(self.demand, self.providers)
|
||||
ids = {"aws-s3-standard", "azure-blob-hot-zrs", "gcp-cloud-storage-standard", "stackit-object-storage"}
|
||||
rows = [r for r in result["scenarios"]["base"] if r["month"] == 1 and r["provider_id"] in ids]
|
||||
self.assertEqual(ids, {r["provider_id"] for r in rows})
|
||||
self.assertTrue(all(r["recurring_total_eur"] is not None for r in rows))
|
||||
|
||||
def test_recurring_total_is_infrastructure_plus_labor(self):
|
||||
result = forecast(self.demand, self.providers)
|
||||
row = next(r for r in result["comparison_320gb"] if r["provider_id"] == "stackit-object-storage")
|
||||
self.assertAlmostEqual(row["recurring_total_eur"], row["monthly_infrastructure_eur"] + row["monthly_internal_labor_eur"])
|
||||
|
||||
def test_normalized_comparison_uses_320gb_for_every_provider(self):
|
||||
result = forecast(self.demand, self.providers)
|
||||
self.assertEqual(len(self.providers["providers"]), len(result["comparison_320gb"]))
|
||||
self.assertTrue(all(r["stored_gb"] == 320 for r in result["comparison_320gb"]))
|
||||
|
||||
def test_garage_external_setup_services_are_unquoted(self):
|
||||
result = forecast(self.demand, self.providers)
|
||||
rows = [r for r in result["comparison_320gb"] if "garage" in r["provider_id"]]
|
||||
self.assertTrue(all(r["setup_external_services_eur"] is None for r in rows))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue