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:
tegwick 2026-08-14 09:28:44 +02:00
parent 54dd45c926
commit 2c2a6073ff
63 changed files with 4662 additions and 69 deletions

83
tools/control_cycle.py Normal file
View file

@ -0,0 +1,83 @@
#!/usr/bin/env python3
"""Compare a generic immutable resource forecast with an actual observation."""
from __future__ import annotations
import json
import sys
from pathlib import Path
COST_FIELDS = ("infrastructure", "internal_labor", "external_labor", "total")
ATTRIBUTIONS = {"demand", "provider_price", "allocation", "labor", "model", "data_quality"}
def delta(forecast: float, actual: float) -> dict:
error = actual - forecast
return {
"forecast": forecast,
"actual": actual,
"error": round(error, 4),
"absolute_percentage_error": None if forecast == 0 else round(abs(error) / forecast * 100, 2),
}
def compare(forecast: dict, actual: dict) -> dict:
if forecast["record_type"] != "forecast" or actual["record_type"] != "actual":
raise ValueError("expected forecast and actual records")
for field in ("resource_id", "resource_class", "period"):
if forecast[field] != actual[field]:
raise ValueError(f"{field} mismatch")
if actual.get("forecast_ref") != forecast["record_id"]:
raise ValueError("actual forecast_ref must identify the immutable forecast")
attribution = actual.get("variance_attribution", {})
unknown = set(attribution.values()) - ATTRIBUTIONS
if unknown:
raise ValueError(f"unknown variance attribution: {sorted(unknown)}")
proxies = {}
all_proxies = sorted(set(forecast["usage_proxies"]) | set(actual["usage_proxies"]))
for name in all_proxies:
planned = forecast["usage_proxies"].get(name)
observed = actual["usage_proxies"].get(name)
if planned is None or observed is None:
proxies[name] = {"status": "missing", "category": "data_quality"}
elif planned["unit"] != observed["unit"]:
proxies[name] = {"status": "unit-mismatch", "category": "data_quality"}
else:
proxies[name] = {**delta(planned["value"], observed["value"]), "unit": planned["unit"], "category": attribution.get(name, "demand")}
costs = {}
for name in COST_FIELDS:
default_category = "labor" if "labor" in name else "provider_price"
costs[name] = {**delta(forecast["costs"][name], actual["costs"][name]), "currency": "EUR", "category": attribution.get(f"costs.{name}", default_category)}
if forecast["allocation"] != actual["allocation"]:
costs["allocation_method"] = {"status": "changed", "category": attribution.get("allocation", "allocation")}
return {
"forecast_ref": forecast["record_id"],
"actual_ref": actual["record_id"],
"resource_id": forecast["resource_id"],
"resource_class": forecast["resource_class"],
"period": forecast["period"],
"usage_proxies": proxies,
"costs": costs,
}
def main() -> int:
if len(sys.argv) != 3:
print(f"usage: {sys.argv[0]} FORECAST.json ACTUAL.json", file=sys.stderr)
return 2
try:
result = compare(json.loads(Path(sys.argv[1]).read_text()), json.loads(Path(sys.argv[2]).read_text()))
except (KeyError, ValueError) as exc:
print(f"control-cycle error: {exc}", file=sys.stderr)
return 1
print(json.dumps(result, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())

99
tools/cost_model.py Normal file
View file

@ -0,0 +1,99 @@
#!/usr/bin/env python3
"""Calculate comparable 12-month object-storage forecasts from JSON evidence."""
from __future__ import annotations
import json
import sys
from pathlib import Path
def quote_provider(provider: dict, scenario: dict, stored_gb: float, restore_gb: float) -> dict:
excess_storage = max(0, stored_gb - provider["included_storage_gb"])
excess_egress = max(0, restore_gb - provider["included_egress_gb"])
missing = []
if excess_storage and provider["storage_eur_per_gb_month"] is None:
missing.append("storage_eur_per_gb_month")
if excess_egress and provider["egress_eur_per_gb"] is None:
missing.append("egress_eur_per_gb")
for field in ("monthly_minimum_eur", "operations_eur_per_month", "support_eur_per_month"):
if provider[field] is None:
missing.append(field)
infrastructure = None
labor_hours = max(scenario["operator_hours_per_month"], provider["operator_hours_per_month"])
labor = labor_hours * scenario["operator_hourly_eur"]
recurring = None
exit_cost = None
if not missing:
usage = excess_storage * (provider["storage_eur_per_gb_month"] or 0)
usage += excess_egress * (provider["egress_eur_per_gb"] or 0)
usage += scenario.get("write_requests_per_month", 0) / 1000 * provider.get("write_eur_per_1000", 0)
usage += scenario.get("read_requests_per_month", 0) / 1000 * provider.get("read_eur_per_1000", 0)
service = max(provider["monthly_minimum_eur"], usage)
infrastructure = service + provider["operations_eur_per_month"] + provider["support_eur_per_month"]
recurring = infrastructure + labor
exit_excess = max(0, stored_gb - provider["included_egress_gb"])
if exit_excess and provider["egress_eur_per_gb"] is None:
missing.append("egress_eur_per_gb_for_exit")
else:
exit_cost = exit_excess * (provider["egress_eur_per_gb"] or 0) + 4 * scenario["operator_hourly_eur"]
setup_internal_hours = provider.get("setup_operator_hours", 0)
setup_internal = setup_internal_hours * scenario["operator_hourly_eur"]
setup_external = provider.get("setup_external_eur", None if "garage" in provider["id"] else 0)
return {
"monthly_infrastructure_eur": None if infrastructure is None else round(infrastructure, 2),
"monthly_internal_labor_hours": labor_hours,
"monthly_internal_labor_eur": round(labor, 2),
"recurring_total_eur": None if recurring is None else round(recurring, 2),
"setup_internal_labor_hours": setup_internal_hours,
"setup_internal_labor_eur": round(setup_internal, 2),
"setup_external_services_eur": setup_external,
"setup_known_total_eur": None if setup_external is None else round(setup_internal + setup_external, 2),
"exit_cost_eur": None if exit_cost is None else round(exit_cost, 2),
"missing_price_fields": sorted(set(missing)),
}
def forecast(demand: dict, catalog: dict) -> dict:
result = {"currency": demand["currency"], "months": 12, "scenarios": {}, "comparison_320gb": []}
retention = demand["retention_days"]
backups_per_day = demand["base_backups_per_day"]
for scenario_name, scenario in demand["scenarios"].items():
rows = []
db_gb = scenario["initial_database_gb"]
for month in range(1, 13):
stored_gb = db_gb * retention * backups_per_day + scenario["wal_gb_per_day"] * retention
restore_gb = scenario["restore_egress_gb"]
for provider in catalog["providers"]:
rows.append({
"month": month, "provider_id": provider["id"],
"database_gb": round(db_gb, 3), "stored_gb": round(stored_gb, 3),
"restore_egress_gb": restore_gb,
**quote_provider(provider, scenario, stored_gb, restore_gb),
})
db_gb *= 1 + scenario["monthly_database_growth_pct"] / 100
result["scenarios"][scenario_name] = rows
normalized = demand["scenarios"]["base"]
for provider in catalog["providers"]:
result["comparison_320gb"].append({
"provider_id": provider["id"], "stored_gb": 320,
"restore_egress_gb": normalized["restore_egress_gb"],
**quote_provider(provider, normalized, 320, normalized["restore_egress_gb"]),
})
return result
def main() -> int:
if len(sys.argv) != 3:
print(f"usage: {sys.argv[0]} DEMAND.json PROVIDERS.json", file=sys.stderr)
return 2
demand = json.loads(Path(sys.argv[1]).read_text())
catalog = json.loads(Path(sys.argv[2]).read_text())
print(json.dumps(forecast(demand, catalog), indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())

144
tools/financial_exchange.py Normal file
View file

@ -0,0 +1,144 @@
#!/usr/bin/env python3
"""Produce planning evidence and consume fin-hub booked-cost projections."""
from __future__ import annotations
import json
import sys
from calendar import monthrange
from datetime import date
from decimal import Decimal, ROUND_HALF_EVEN
from pathlib import Path
CENT = Decimal("0.01")
def money(value: object) -> Decimal:
return Decimal(str(value)).quantize(CENT, rounding=ROUND_HALF_EVEN)
def money_text(value: object) -> str:
return format(money(value), ".2f")
def forecast_records(payload: dict, *, resource_id: str, source_ref: str) -> list[dict]:
if payload.get("schema_version") != "0.1" or payload.get("record_type") != "forecast":
raise ValueError("expected a resource-control forecast v0.1")
if not resource_id.startswith("resource:"):
raise ValueError("resource_id must use the resource: namespace")
created_at = payload["created_at"]
version = f"{payload['provider_id']}:{created_at}"
records = []
for row in payload["rows"]:
infrastructure = money(row["infrastructure_eur"])
labor = money(row["internal_labor_eur"])
if money(row["total_eur"]) != infrastructure + labor:
raise ValueError("total_eur does not match infrastructure plus internal labor")
year, month = (int(part) for part in row["period"].split("-"))
period_start = date(year, month, 1)
period_end = date(year, month, monthrange(year, month)[1])
records.append({
"schema_version": "0.1",
"record_type": "forecast",
"record_id": f"forecast:{payload['provider_id']}:{payload['cost_attribution_key']}:{row['period']}:{created_at}",
"revision_of": payload.get("forecast_ref"),
"resource_id": resource_id,
"service_id": payload["provider_id"],
"workload_id": payload["workload"],
"tenant_id": None,
"environment": "production",
"cost_attribution_key": payload["cost_attribution_key"],
"period_start": period_start.isoformat(),
"period_end": period_end.isoformat(),
"currency": "EUR",
"source_evidence": [source_ref, *row.get("evidence", [])],
"created_at": created_at,
"scenario": payload.get("scenario") or "base",
"forecast_version": version,
"costs": {
"infrastructure": money_text(infrastructure),
"internal_labor": money_text(labor),
"external_services": "0.00",
"setup": "0.00",
"other": "0.00"
},
"uncertainty": None,
"assumptions": [
f"database_gb={row['database_gb']}",
f"stored_gb={row['stored_gb']}",
f"wal_gb={row['wal_gb']}",
f"restore_egress_gb={row['restore_egress_gb']}",
f"write_requests={row['write_requests']}",
f"read_requests={row['read_requests']}",
f"internal_labor_hours={row['internal_labor_hours']}"
]
})
return records
def validate_booked_cost(record: dict) -> dict:
required = {
"schema_version", "record_type", "financial_fact_id", "adjustment_kind",
"source_document_id", "source_line_id", "content_fingerprint", "provider",
"accounting_period", "currency", "gross_amount", "adjustment_amount",
"effective_amount", "source_evidence_ref", "recorded_at"
}
missing = required - record.keys()
if missing:
raise ValueError(f"booked-cost evidence missing {sorted(missing)}")
if record["schema_version"] != "0.1" or record["record_type"] != "booked_cost":
raise ValueError("unsupported booked-cost schema")
if len(record["currency"]) != 3 or record["currency"] != record["currency"].upper():
raise ValueError("currency must be an uppercase three-letter code")
if money(record["effective_amount"]) != money(record["gross_amount"]) + money(record["adjustment_amount"]):
raise ValueError("effective_amount must equal gross plus adjustment")
if record.get("tax_status") == "unknown" and record.get("tax_amount") is not None:
raise ValueError("unknown tax must not have a tax amount")
return record
def reconcile(forecasts: list[dict], booked_costs: list[dict]) -> list[dict]:
planned = {
(record["period_start"][:7], record["currency"], record.get("cost_attribution_key")):
money(record["costs"]["infrastructure"])
for record in forecasts if record["record_type"] == "forecast"
}
observed: dict[tuple[str, str, str | None], Decimal] = {}
fact_ids: dict[tuple[str, str, str | None], list[str]] = {}
for raw in booked_costs:
record = validate_booked_cost(raw)
key = (record["accounting_period"], record["currency"], record.get("cost_attribution_key"))
observed[key] = observed.get(key, Decimal("0")) + money(record["effective_amount"])
fact_ids.setdefault(key, []).append(record["financial_fact_id"])
rows = []
for key in sorted(set(planned) | set(observed), key=lambda item: (item[0], item[1], item[2] or "")):
forecast = planned.get(key)
actual = observed.get(key)
rows.append({
"period": key[0], "currency": key[1], "cost_attribution_key": key[2],
"forecast_infrastructure": None if forecast is None else money_text(forecast),
"booked_effective": None if actual is None else money_text(actual),
"variance": None if forecast is None or actual is None else money_text(actual - forecast),
"financial_fact_ids": fact_ids.get(key, []),
"status": "reconciled" if forecast is not None and actual is not None else "missing-booked-cost" if forecast is not None else "missing-forecast"
})
return rows
def main() -> int:
if len(sys.argv) < 3 or sys.argv[1] not in {"forecast", "reconcile"}:
print(f"usage: {sys.argv[0]} forecast FORECAST.json [RESOURCE_ID] | reconcile FORECAST_EVIDENCE.json BOOKED_COST.json", file=sys.stderr)
return 2
if sys.argv[1] == "forecast":
payload = json.loads(Path(sys.argv[2]).read_text())
resource_id = sys.argv[3] if len(sys.argv) > 3 else "resource:platform_audit_storage"
print(json.dumps(forecast_records(payload, resource_id=resource_id, source_ref=sys.argv[2]), indent=2))
return 0
forecasts = json.loads(Path(sys.argv[2]).read_text())
booked = json.loads(Path(sys.argv[3]).read_text())
print(json.dumps(reconcile(forecasts, booked), indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())

209
tools/optimization.py Normal file
View file

@ -0,0 +1,209 @@
#!/usr/bin/env python3
"""Evaluate resource optimization cases.
The evaluator is fail-closed: any decision field that is unknown makes the
affected comparison unknown rather than optimistic. A case only reaches a
recommendation when every field the decision template requires is present for
the baseline and for the alternative being compared.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
CASE_TYPES = {
"rightsizing", "consolidation", "commitment", "renewal",
"migration", "retirement", "provider_switch",
}
DECISION_STATES = {
"blocked_on_evidence", "proposed", "approved", "rejected", "superseded",
}
COST_FIELDS = (
"recurring_infrastructure_eur_month",
"recurring_internal_labor_eur_month",
"recurring_external_labor_eur_month",
)
# Fields the decision template requires before any recommendation is made.
REQUIRED_FOR_DECISION = COST_FIELDS + ("one_time_eur", "exit_path")
# A saving below this monthly threshold is not material enough to act on.
MATERIALITY_EUR_MONTH = 5.0
def recurring_total(option: dict) -> float | None:
"""Monthly recurring cost, or None when any component is unknown."""
values = [option[field] for field in COST_FIELDS]
if any(value is None for value in values):
return None
return round(sum(values), 2)
def missing_fields(option: dict) -> list[str]:
missing = [field for field in REQUIRED_FOR_DECISION if option[field] is None]
if not option["utilization"]:
missing.append("utilization")
if not option["service_constraints"]:
missing.append("service_constraints")
return sorted(missing)
def utilization_ratios(option: dict) -> dict:
"""Used-over-provisioned per metric; None where either side is unknown."""
ratios = {}
for metric, pair in option["utilization"].items():
provisioned = pair["provisioned"]["value"]
used = pair["used"]["value"]
if provisioned in (None, 0) or used is None:
ratios[metric] = None
else:
ratios[metric] = round(used / provisioned, 4)
return ratios
def compare_option(baseline: dict, alternative: dict) -> dict:
"""Compare one alternative against the baseline on the decision fields."""
blocking = sorted(set(
[f"baseline.{field}" for field in missing_fields(baseline)]
+ [f"{alternative['option_id']}.{field}" for field in missing_fields(alternative)]
+ [f"baseline.unknown:{item}" for item in baseline["unknowns"]]
+ [f"{alternative['option_id']}.unknown:{item}" for item in alternative["unknowns"]]
))
base_recurring = recurring_total(baseline)
alt_recurring = recurring_total(alternative)
monthly_delta = None
monthly_saving = None
if base_recurring is not None and alt_recurring is not None:
monthly_delta = round(alt_recurring - base_recurring, 2)
monthly_saving = round(-monthly_delta, 2)
one_time = alternative["one_time_eur"]
payback_months = None
payback_note = None
if monthly_saving is None or one_time is None:
payback_note = "unknown: incomplete cost evidence"
elif monthly_saving <= 0:
payback_note = "never: the alternative does not reduce recurring cost"
elif one_time == 0:
payback_months = 0.0
payback_note = "immediate: no one-time cost"
else:
payback_months = round(one_time / monthly_saving, 1)
# Failure domains the alternative removes, and ones it newly introduces.
base_domains = set(baseline["failure_domains"])
alt_domains = set(alternative["failure_domains"])
if blocking:
verdict = "blocked_on_evidence"
elif monthly_saving is not None and monthly_saving > MATERIALITY_EUR_MONTH:
verdict = "recommend"
elif monthly_delta is not None and abs(monthly_delta) <= MATERIALITY_EUR_MONTH:
verdict = "no_material_change"
else:
verdict = "reject"
return {
"option_id": alternative["option_id"],
"label": alternative["label"],
"verdict": verdict,
"baseline_recurring_eur_month": base_recurring,
"alternative_recurring_eur_month": alt_recurring,
"monthly_delta_eur": monthly_delta,
"monthly_saving_eur": monthly_saving,
"one_time_eur": one_time,
"payback_months": payback_months,
"payback_note": payback_note,
"baseline_utilization": utilization_ratios(baseline),
"alternative_utilization": utilization_ratios(alternative),
"uncertainty": alternative["uncertainty"]["level"],
"failure_domains_removed": sorted(base_domains - alt_domains),
"failure_domains_added": sorted(alt_domains - base_domains),
"exit_path_known": alternative["exit_path"] is not None,
"blocking_evidence": blocking,
}
def validate_case(case: dict) -> None:
if case["schema_version"] != "0.1":
raise ValueError("unsupported optimization-case schema version")
if case["record_scope"] not in {"operational", "illustrative"}:
raise ValueError("record_scope must be operational or illustrative")
if case["case_type"] not in CASE_TYPES:
raise ValueError(f"unknown case_type {case['case_type']}")
if not case["case_id"].startswith("opt:"):
raise ValueError("case_id must start with 'opt:'")
if not case["resource_ids"]:
raise ValueError("a case must name at least one resource")
if any(not rid.startswith("resource:") for rid in case["resource_ids"]):
raise ValueError("resource_ids must be portfolio resource identifiers")
if not case["evidence"]:
raise ValueError("a case must cite evidence")
decision = case["decision"]
if decision["state"] not in DECISION_STATES:
raise ValueError(f"unknown decision state {decision['state']}")
option_ids = [case["baseline"]["option_id"]] + [a["option_id"] for a in case["alternatives"]]
if len(set(option_ids)) != len(option_ids):
raise ValueError("option identifiers must be unique within a case")
report = evaluate(case)
blocked = any(r["verdict"] == "blocked_on_evidence" for r in report["comparisons"])
# A case cannot be approved while its own evidence is incomplete, and an
# approval must name the authority that gave it.
if decision["state"] in {"approved", "rejected"}:
if decision["approver"] is None or decision["approved_on"] is None:
raise ValueError("a decided case must record approver and approved_on")
if decision["state"] == "approved":
if blocked:
raise ValueError("cannot approve a case with blocking evidence gaps")
if decision["recommended_option_id"] not in option_ids:
raise ValueError("approved case must recommend a known option")
if decision["state"] == "blocked_on_evidence" and not blocked:
raise ValueError("case is marked blocked but every decision field is known")
if decision["state"] == "proposed" and blocked:
raise ValueError("case has blocking evidence gaps and cannot be proposed")
def evaluate(case: dict) -> dict:
baseline = case["baseline"]
comparisons = [compare_option(baseline, alt) for alt in case["alternatives"]]
recommended = [c for c in comparisons if c["verdict"] == "recommend"]
recommended.sort(key=lambda c: (c["payback_months"] is None, c["payback_months"]))
return {
"case_id": case["case_id"],
"case_type": case["case_type"],
"record_scope": case["record_scope"],
"review_period": case["review_period"],
"baseline": {
"option_id": baseline["option_id"],
"label": baseline["label"],
"recurring_eur_month": recurring_total(baseline),
"utilization": utilization_ratios(baseline),
},
"comparisons": comparisons,
"best_option_id": recommended[0]["option_id"] if recommended else None,
"decision_state": case["decision"]["state"],
}
def main() -> int:
paths = sys.argv[1:] or sorted(str(p) for p in Path("data/optimization").glob("*.json"))
if not paths:
print("no optimization cases found", file=sys.stderr)
return 2
reports = []
for path in paths:
case = json.loads(Path(path).read_text())
validate_case(case)
reports.append(evaluate(case))
print(json.dumps(reports, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())

97
tools/portfolio.py Normal file
View file

@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""Semantic validation for managed-infrastructure portfolio records."""
from __future__ import annotations
import json
import re
import sys
from datetime import date
from pathlib import Path
RESOURCE_ID = re.compile(r"^resource:[a-z0-9][a-z0-9:_-]+$")
STATUSES = {
"proposed", "ordered", "commissioning", "active", "suspended",
"retiring", "retired", "rejected",
}
TRANSITIONS = {
"proposed": {"ordered", "rejected"},
"ordered": {"commissioning", "rejected"},
"commissioning": {"active", "rejected"},
"active": {"suspended", "retiring"},
"suspended": {"active", "retiring"},
"retiring": {"retired", "active"},
"retired": set(),
"rejected": {"proposed"},
}
def _day(value: str | None) -> date | None:
return date.fromisoformat(value) if value else None
def validate_transition(current: str, target: str) -> None:
if current not in STATUSES or target not in STATUSES:
raise ValueError("unknown lifecycle status")
if target not in TRANSITIONS[current]:
raise ValueError(f"invalid lifecycle transition {current} -> {target}")
def validate_record(record: dict) -> None:
if record.get("schema_version") != "0.2":
raise ValueError("portfolio records must use schema_version 0.2")
if not RESOURCE_ID.fullmatch(record.get("id", "")):
raise ValueError("invalid resource id")
if record.get("status") not in STATUSES:
raise ValueError("unknown lifecycle status")
if record.get("record_scope") not in {"inventory", "example"}:
raise ValueError("record_scope must be inventory or example")
allocation = record["ownership"]["allocation"]
if allocation["mode"] == "unattributed":
if allocation["cost_attribution_key"] is not None:
raise ValueError("unattributed resources cannot have an attribution key")
elif not allocation["cost_attribution_key"]:
raise ValueError("dedicated/shared resources require an attribution key")
if allocation["mode"] == "shared" and (
not allocation["driver"] or not allocation["method_version"]
):
raise ValueError("shared resources require a driver and method version")
dimensions = [(item["metric"], item["kind"]) for item in record["capacity"]]
if len(dimensions) != len(set(dimensions)):
raise ValueError("capacity metric/kind pairs must be unique")
if any(rel["resource_id"] == record["id"] for rel in record["relationships"]):
raise ValueError("a resource cannot relate to itself")
lifecycle = record["lifecycle"]
proposed = _day(lifecycle["proposed_on"])
ordered = _day(lifecycle["ordered_on"])
commissioned = _day(lifecycle["commissioned_on"])
retired = _day(lifecycle["retired_on"])
dated = [value for value in (proposed, ordered, commissioned, retired) if value]
if dated != sorted(dated):
raise ValueError("lifecycle dates are out of order")
if record["status"] == "retired" and retired is None:
raise ValueError("retired resources require retired_on")
# Discovery must preserve unknown commercial and commissioning dates as
# null instead of manufacturing precision. Date ordering is enforced when
# the authoritative repositories or provider evidence supply the values.
if record["record_scope"] == "example" and not any(
item["kind"] == "example" for item in record["evidence"]
):
raise ValueError("examples require explicit example evidence")
def main() -> int:
if len(sys.argv) < 2:
print(f"usage: {sys.argv[0]} RECORD.json ...", file=sys.stderr)
return 2
for name in sys.argv[1:]:
validate_record(json.loads(Path(name).read_text()))
print(f"portfolio records valid: {len(sys.argv) - 1}")
return 0
if __name__ == "__main__":
raise SystemExit(main())

292
tools/portfolio_report.py Normal file
View file

@ -0,0 +1,292 @@
#!/usr/bin/env python3
"""Portfolio view: coverage, lifecycle, capacity, cost, renewals, risk, and openings.
The report never fills a gap with a guess. Every section separates what is known
from what is unknown, names the owner of each unknown, and reports unattributed
cost as its own figure rather than spreading it across resources.
"""
from __future__ import annotations
import json
import sys
from datetime import date
from pathlib import Path
from optimization import evaluate, validate_case
from portfolio import validate_record
# How far ahead a contract date counts as "approaching".
RENEWAL_HORIZON_DAYS = 90
# Utilization at or below this fraction is flagged as idle capacity.
IDLE_THRESHOLD = 0.35
# Utilization at or above this fraction is flagged as saturated.
SATURATED_THRESHOLD = 0.85
USAGE_PAIRS = {
"cpu": "cpu_usage",
"memory": "memory_usage",
"root_filesystem": "root_filesystem_used",
}
def _load_all(pattern: Path) -> list[dict]:
return [json.loads(path.read_text()) for path in sorted(pattern.parent.glob(pattern.name))]
def load_portfolio(root: Path) -> dict:
resources = _load_all(root / "data" / "resources" / "*.json")
for resource in resources:
validate_record(resource)
coverage_files = sorted((root / "data").glob("portfolio-coverage-*.json"))
coverage = json.loads(coverage_files[-1].read_text()) if coverage_files else None
cases = _load_all(root / "data" / "optimization" / "*.json")
for case in cases:
validate_case(case)
return {"resources": resources, "coverage": coverage, "cases": cases}
def coverage_section(coverage: dict | None) -> dict:
if coverage is None:
return {"observed_at": None, "groups": [], "unresolved_gaps": [], "note": "no coverage observation recorded"}
return {
"observed_at": coverage["observed_at"],
"inventory_records": coverage["inventory_records"],
"groups": [
{"group": group["group"], "status": group["status"], "resources": len(group["resource_ids"])}
for group in coverage["coverage"]
],
"unresolved_gaps": [
{"owner": gap["owner"], "gap": gap["gap"], "delegated_workplan": gap["delegated_workplan"]}
for gap in coverage["owned_gaps"]
],
}
def lifecycle_section(resources: list[dict]) -> dict:
counts: dict[str, int] = {}
for resource in resources:
counts[resource["status"]] = counts.get(resource["status"], 0) + 1
unowned = [r["id"] for r in resources if not r["ownership"]["owner"]]
return {"by_status": dict(sorted(counts.items())), "without_owner": unowned}
def _capacity_index(resource: dict) -> dict:
return {entry["metric"]: entry for entry in resource["capacity"]}
def utilization_section(resources: list[dict]) -> dict:
measured, unmeasured = [], []
for resource in resources:
metrics = _capacity_index(resource)
rows = []
for metric, usage_metric in USAGE_PAIRS.items():
if metric not in metrics or usage_metric not in metrics:
continue
provisioned = metrics[metric]["value"]
used = metrics[usage_metric]["value"]
if not provisioned:
continue
ratio = round(used / provisioned, 4)
rows.append({
"metric": metric,
"provisioned": provisioned,
"used": used,
"unit": metrics[metric]["unit"],
"ratio": ratio,
"observed_at": metrics[metric].get("observed_at"),
"signal": (
"idle" if ratio <= IDLE_THRESHOLD
else "saturated" if ratio >= SATURATED_THRESHOLD
else "normal"
),
})
if rows:
measured.append({"resource_id": resource["id"], "metrics": rows})
else:
unmeasured.append({
"resource_id": resource["id"],
"owner": resource["ownership"]["owner"],
"reason": "no paired provisioned and observed capacity metric",
})
return {
"measured": measured,
"unmeasured": unmeasured,
"idle": sorted({
row["resource_id"] for row in measured
for metric in row["metrics"] if metric["signal"] == "idle"
}),
"saturated": sorted({
row["resource_id"] for row in measured
for metric in row["metrics"] if metric["signal"] == "saturated"
}),
}
def cost_section(resources: list[dict]) -> dict:
priced, unpriced, unattributed = [], [], []
for resource in resources:
entry = {
"resource_id": resource["id"],
"owner": resource["ownership"]["owner"],
"billing_model": resource["cost"]["billing_model"],
}
if resource["cost"]["price_evidence"]:
priced.append({**entry, "price_evidence": resource["cost"]["price_evidence"]})
else:
unpriced.append(entry)
if resource["ownership"]["allocation"]["mode"] == "unattributed":
unattributed.append(entry)
return {
"priced": priced,
"unpriced": unpriced,
"unattributed_allocation": unattributed,
# Deliberately not a number: no booked cost has reached this repository,
# so any portfolio spend total would be invented rather than measured.
"known_monthly_spend_eur": None,
"spend_note": (
f"{len(priced)} of {len(resources)} resources carry price evidence and none carries a booked "
"cost from fin-hub, so total portfolio spend is not computable and is reported as unknown "
"rather than as zero."
),
}
def renewals_section(resources: list[dict], today: date) -> dict:
approaching, undated = [], []
for resource in resources:
lifecycle = resource["lifecycle"]
dates = {k: lifecycle[k] for k in ("renews_on", "cancel_by") if lifecycle[k]}
if not dates:
if resource["status"] in {"active", "ordered", "commissioning"}:
undated.append({
"resource_id": resource["id"],
"owner": resource["ownership"]["owner"],
"risk": "no renewal or cancellation date recorded; the cancellation window cannot be respected",
})
continue
for field, value in dates.items():
days = (date.fromisoformat(value) - today).days
if days <= RENEWAL_HORIZON_DAYS:
approaching.append({
"resource_id": resource["id"],
"field": field,
"date": value,
"days_remaining": days,
})
approaching.sort(key=lambda row: row["days_remaining"])
return {"horizon_days": RENEWAL_HORIZON_DAYS, "approaching": approaching, "undated": undated}
def risk_section(resources: list[dict], utilization: dict, cost: dict) -> list[dict]:
risks = []
domains: dict[str, list[str]] = {}
for resource in resources:
for domain in resource["location"]["failure_domains"]:
domains.setdefault(domain, []).append(resource["id"])
for domain, members in sorted(domains.items()):
if len(members) > 2:
risks.append({
"kind": "concentrated_failure_domain",
"detail": f"{len(members)} resources share {domain}",
"resource_ids": sorted(members),
})
if cost["unpriced"]:
risks.append({
"kind": "unpriced_resources",
"detail": f"{len(cost['unpriced'])} resources have no price evidence, so spend cannot be measured",
"resource_ids": sorted(row["resource_id"] for row in cost["unpriced"]),
})
if cost["unattributed_allocation"]:
risks.append({
"kind": "unattributed_cost",
"detail": f"{len(cost['unattributed_allocation'])} resources have no allocation method, so their cost reaches no consumer",
"resource_ids": sorted(row["resource_id"] for row in cost["unattributed_allocation"]),
})
if utilization["idle"]:
risks.append({
"kind": "idle_capacity",
"detail": f"utilization at or below {IDLE_THRESHOLD:.0%} of provisioned capacity",
"resource_ids": utilization["idle"],
})
if utilization["saturated"]:
risks.append({
"kind": "saturated_capacity",
"detail": f"utilization at or above {SATURATED_THRESHOLD:.0%} of provisioned capacity",
"resource_ids": utilization["saturated"],
})
return risks
def optimization_section(cases: list[dict]) -> dict:
open_cases, blocked_on = [], []
for case in cases:
report = evaluate(case)
open_cases.append({
"case_id": report["case_id"],
"case_type": report["case_type"],
"state": report["decision_state"],
"best_option_id": report["best_option_id"],
"verdicts": {c["option_id"]: c["verdict"] for c in report["comparisons"]},
})
for comparison in report["comparisons"]:
for item in comparison["blocking_evidence"]:
if ".unknown:" in item:
blocked_on.append({"case_id": report["case_id"], "missing": item.split(".unknown:", 1)[1]})
return {
"cases": open_cases,
"undecided": [c["case_id"] for c in open_cases if c["state"] in {"blocked_on_evidence", "proposed"}],
"blocked_on_evidence": blocked_on,
}
def next_actions(report: dict) -> list[str]:
"""The smallest set of evidence that would unblock the most decisions."""
actions = []
for gap in report["coverage"]["unresolved_gaps"]:
actions.append(f"{gap['owner']}: deliver {gap['delegated_workplan']}{gap['gap']}")
if report["cost"]["unpriced"]:
actions.append(
"resource-control: no portfolio spend figure exists until at least one booked cost arrives "
"from fin-hub under the exchange contract"
)
for row in report["renewals"]["undated"]:
actions.append(f"{row['owner']}: record renewal and cancellation dates for {row['resource_id']}")
return actions
def build(root: Path, today: date | None = None) -> dict:
today = today or date.today()
data = load_portfolio(root)
resources = data["resources"]
utilization = utilization_section(resources)
cost = cost_section(resources)
report = {
"schema_version": "0.1",
"generated_on": today.isoformat(),
"resource_count": len(resources),
"coverage": coverage_section(data["coverage"]),
"lifecycle": lifecycle_section(resources),
"utilization": utilization,
"cost": cost,
"renewals": renewals_section(resources, today),
"optimization": optimization_section(data["cases"]),
}
report["risks"] = risk_section(resources, utilization, cost)
report["next_actions"] = next_actions(report)
return report
def main() -> int:
root = Path(sys.argv[1]) if len(sys.argv) > 1 else Path.cwd()
print(json.dumps(build(root), indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())

79
tools/validate.py Normal file
View file

@ -0,0 +1,79 @@
#!/usr/bin/env python3
"""Dependency-free validation for resource-control JSON declarations."""
import json
from pathlib import Path
from optimization import validate_case
from portfolio import validate_record
from portfolio_report import build as build_portfolio_report
def load(path: str) -> dict:
return json.loads(Path(path).read_text())
def main() -> int:
demand = load("data/demand/platform-audit-storage.json")
providers = load("data/providers/object-storage.json")
schema = load("schemas/resource-inventory.schema.json")
observation_schema = load("schemas/monthly-resource-observation.schema.json")
planning_schema = load("schemas/planning-evidence.schema.json")
control_schema = load("schemas/resource-control-cycle.schema.json")
forecasts = [load(str(path)) for path in Path("data/forecasts").glob("*.json")]
resource_paths = list(Path("data/resources").glob("*.json"))
resource_paths += list(Path("examples/portfolio").glob("*.json"))
resources = [load(str(path)) for path in resource_paths]
control_records = [load(str(path)) for path in Path("examples/control-cycle").glob("*.json")]
assert demand["schema_version"] == providers["schema_version"] == "0.1"
assert demand["retention_days"] >= 30
assert set(demand["scenarios"]) == {"low", "base", "high"}
assert len({p["id"] for p in providers["providers"]}) == len(providers["providers"])
assert {"Host Europe", "Scaleway", "Hetzner", "AWS", "Microsoft Azure", "Google Cloud", "STACKIT"} <= {p["provider"] for p in providers["providers"]}
assert schema["$schema"].endswith("2020-12/schema")
assert observation_schema["$schema"].endswith("2020-12/schema")
assert planning_schema["$schema"].endswith("2020-12/schema")
assert control_schema["$schema"].endswith("2020-12/schema")
assert len(planning_schema["oneOf"]) == 5
for forecast in forecasts:
assert forecast["record_type"] == "forecast"
assert len({row["period"] for row in forecast["rows"]}) == len(forecast["rows"])
assert all(row["total_eur"] == round(row["infrastructure_eur"] + row["internal_labor_eur"], 2) for row in forecast["rows"])
assert schema["properties"]["schema_version"]["const"] == "0.2"
required = set(schema["required"])
for resource in resources:
assert not required - resource.keys(), f"missing fields: {required - resource.keys()}"
validate_record(resource)
record_ids = {record["record_id"] for record in control_records}
assert len(record_ids) == len(control_records)
assert {record["resource_class"] for record in control_records} == {"storage", "cluster_compute", "shared_platform_service"}
for record in control_records:
assert record["schema_version"] == "0.1"
assert record["resource_id"].startswith("resource:")
costs = record["costs"]
assert costs["total"] == round(costs["infrastructure"] + costs["internal_labor"] + costs["external_labor"], 2)
if record["record_type"] == "actual":
assert record["forecast_ref"] in record_ids
case_schema = load("schemas/optimization-case.schema.json")
assert case_schema["$schema"].endswith("2020-12/schema")
assert case_schema["properties"]["schema_version"]["const"] == "0.1"
cases = [load(str(path)) for path in Path("data/optimization").glob("*.json")]
assert len({case["case_id"] for case in cases}) == len(cases)
for case in cases:
assert not set(case_schema["required"]) - case.keys()
validate_case(case)
# The optimization process must be validated on the backup case and on at
# least one non-storage portfolio candidate (RESOURCE-WP-0003-T06).
case_resources = {rid for case in cases for rid in case["resource_ids"]}
assert "resource:platform:audit-storage" in case_resources
assert case_resources - {"resource:platform:audit-storage"}
report = build_portfolio_report(Path("."))
assert report["resource_count"] == len(resource_paths) - len(list(Path("examples/portfolio").glob("*.json")))
assert report["cost"]["known_monthly_spend_eur"] is None
assert report["next_actions"]
print("resource-control declarations: valid")
return 0
if __name__ == "__main__":
raise SystemExit(main())

55
tools/variance.py Normal file
View file

@ -0,0 +1,55 @@
#!/usr/bin/env python3
"""Compare monthly resource actuals with the immutable decision forecast."""
from __future__ import annotations
import json
import sys
from pathlib import Path
METRICS = (
"database_gb", "stored_gb", "wal_gb", "restore_egress_gb",
"write_requests", "read_requests", "infrastructure_eur",
"internal_labor_hours", "internal_labor_eur", "total_eur",
)
def compare(forecast: dict, actual: dict) -> dict:
expected = {row["period"]: row for row in forecast["rows"]}
rows = []
for observed in actual["rows"]:
period = observed["period"]
if period not in expected:
rows.append({"period": period, "status": "no-forecast", "metrics": {}})
continue
metrics = {}
for metric in METRICS:
planned = expected[period][metric]
measured = observed[metric]
error = measured - planned
metrics[metric] = {
"forecast": planned,
"actual": measured,
"error": round(error, 4),
"absolute_percentage_error": None if planned == 0 else round(abs(error) / planned * 100, 2),
}
rows.append({"period": period, "status": "compared", "metrics": metrics})
return {
"forecast_created_at": forecast["created_at"],
"provider_id": actual["provider_id"],
"rows": rows,
}
def main() -> int:
if len(sys.argv) != 3:
print(f"usage: {sys.argv[0]} FORECAST.json ACTUAL.json", file=sys.stderr)
return 2
forecast = json.loads(Path(sys.argv[1]).read_text())
actual = json.loads(Path(sys.argv[2]).read_text())
print(json.dumps(compare(forecast, actual), indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())