resource-control/tools/validate.py

94 lines
5 KiB
Python
Raw Normal View History

#!/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)
2026-08-14 09:36:57 +02:00
operational_records = [load(str(path)) for path in Path("data/control-cycle").glob("*.json")]
control_records += operational_records
record_ids = {record["record_id"] for record in control_records}
assert len(record_ids) == len(control_records)
2026-08-14 09:36:57 +02:00
assert {record["resource_class"] for record in control_records} >= {"storage", "cluster_compute", "shared_platform_service"}
for record in control_records:
2026-08-14 09:36:57 +02:00
assert record["schema_version"] in {"0.1", "0.2"}
assert record["resource_id"].startswith("resource:")
costs = record["costs"]
2026-08-14 09:36:57 +02:00
components = [costs["infrastructure"], costs["internal_labor"], costs["external_labor"]]
if any(component is None for component in components):
# An unknown component makes the total unknown; it is never the sum
# of the parts that happen to be known.
assert record["schema_version"] == "0.2", "null costs require schema 0.2"
assert costs["total"] is None
else:
assert costs["total"] == round(sum(components), 2)
if record["record_type"] == "actual":
assert record["forecast_ref"] in record_ids
2026-08-14 09:36:57 +02:00
# Operational records assert real facts and must cite the authoritative
# repository evidence they came from.
for record in operational_records:
assert record["evidence"], f"{record['record_id']} cites no evidence"
assert record["uncertainty"]["notes"], f"{record['record_id']} states no uncertainty"
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())