v0.2 records stay valid. v0.3 requires the five facets. Validators reject inline Scaleway endpoints and secret-looking strings. The backup record is the first 0.3 object. Reef views already met T02.
141 lines
7.8 KiB
Python
141 lines
7.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Dependency-free validation for resource-control JSON declarations."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
from entities import REQUIRED_ENTITY_IDS, load_register, load_terms, require_entity, validate_register, validate_terms
|
|
from optimization import validate_case
|
|
from portfolio import validate_record
|
|
from portfolio_report import build as build_portfolio_report
|
|
from settlement import close_fixture, close_live
|
|
|
|
|
|
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 set(schema["properties"]["schema_version"]["enum"]) == {"0.2", "0.3"}
|
|
required = set(schema["required"])
|
|
v03 = {"description", "decision", "operational_refs", "credential_handles", "consumers"}
|
|
for resource in resources:
|
|
need = set(required)
|
|
if resource.get("schema_version") == "0.3":
|
|
need |= v03
|
|
assert not need - resource.keys(), f"missing fields: {need - resource.keys()}"
|
|
validate_record(resource)
|
|
assert any(resource.get("schema_version") == "0.3" for resource in resources)
|
|
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)
|
|
assert {record["resource_class"] for record in control_records} >= {"storage", "cluster_compute", "shared_platform_service"}
|
|
for record in control_records:
|
|
assert record["schema_version"] in {"0.1", "0.2"}
|
|
assert record["resource_id"].startswith("resource:")
|
|
costs = record["costs"]
|
|
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
|
|
# 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"]
|
|
register_payload = load("data/entities/register.json")
|
|
terms_payload = load("data/terms/procurement-v0.1.json")
|
|
entities = validate_register(register_payload)
|
|
terms = validate_terms(terms_payload)
|
|
_, loaded_entities = load_register(Path("."))
|
|
assert loaded_entities.keys() == entities.keys()
|
|
assert list(entities) == list(REQUIRED_ENTITY_IDS) or set(entities) == set(REQUIRED_ENTITY_IDS)
|
|
assert terms["markup_rate"] == load_terms(Path("."))["markup_rate"]
|
|
try:
|
|
require_entity("entity:unknown")
|
|
raise AssertionError("unknown entity id must be rejected")
|
|
except ValueError as exc:
|
|
assert "unknown entity id" in str(exc)
|
|
entity_ids = {row["financial_entity_id"] for row in report["entities"]["entities"]}
|
|
assert entity_ids == set(REQUIRED_ENTITY_IDS)
|
|
assert report["entities"]["known_monthly_spend_eur"] is None
|
|
assert report["entities"]["unattributed_resources"]
|
|
live_statements = close_live(Path("."), "2026-08")
|
|
assert live_statements == []
|
|
fixture_dir = Path("examples/settlement")
|
|
ordinary = close_fixture(load(str(fixture_dir / "15.1-ordinary.json")), terms, entities)
|
|
assert len(ordinary) == 1
|
|
assert ordinary[0]["known_transfer_price_eur"] == "240.00"
|
|
planning = load("examples/planning/entity-forecast-transfer.json")
|
|
assert planning["transfer_price"] == "240.00"
|
|
assert planning["credit_headroom"] == "760.00"
|
|
assert planning["financial_entity_id"] == "entity:coulomb"
|
|
reef_view_schema = load("schemas/reef-view.schema.json")
|
|
assert reef_view_schema["$schema"].endswith("2020-12/schema")
|
|
inventory_ids = {resource["id"] for resource in resources if resource.get("record_scope") == "inventory"}
|
|
for path in Path("data/reefs").glob("*.json"):
|
|
view = load(str(path))
|
|
assert view["schema_version"] == "0.1"
|
|
assert view["declaration_ref"].startswith("reef:")
|
|
missing = [row["resource_id"] for row in view["resources"] if row["resource_id"] not in inventory_ids]
|
|
assert not missing, f"{path} cites unknown resources: {missing}"
|
|
if view["reef_id"] == "reef-railiance":
|
|
assert view["role"] == "compute_substrate"
|
|
assert any("reef-storage" in note for note in view.get("notes") or [])
|
|
if view["reef_id"] == "reef-storage":
|
|
assert view["role"] == "storage_substrate"
|
|
print("resource-control declarations: valid")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|