feat: join audit-storage usage without inventing a booked Scaleway fact
Ingest resource-control's August technical usage, omit nulls, and reconcile forecast + usage + booked facts. Commissioning month reports missing_booked_fact instead of 0.00. T05 still waits on the first invoice.
This commit is contained in:
parent
75356ea19e
commit
ac0949afd0
7 changed files with 426 additions and 1 deletions
33
tests/fixtures/platform-audit-storage-usage-2026-08.json
vendored
Normal file
33
tests/fixtures/platform-audit-storage-usage-2026-08.json
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"schema_version": "0.2",
|
||||
"record_type": "usage_observation",
|
||||
"workload": "rapp-postgres/platform-pg",
|
||||
"cost_attribution_key": "platform:audit-storage",
|
||||
"provider_id": "scaleway-standard-multi-az",
|
||||
"created_at": "2026-08-14T18:24:00Z",
|
||||
"scenario": "observed",
|
||||
"forecast_ref": "data/forecasts/platform-audit-storage-scaleway-base-2026-08.json",
|
||||
"rows": [
|
||||
{
|
||||
"period": "2026-08",
|
||||
"database_gb": 0.6365,
|
||||
"stored_gb": 0.0066,
|
||||
"wal_gb": null,
|
||||
"restore_egress_gb": null,
|
||||
"write_requests": null,
|
||||
"read_requests": null,
|
||||
"infrastructure_eur": null,
|
||||
"internal_labor_hours": null,
|
||||
"internal_labor_eur": null,
|
||||
"total_eur": null,
|
||||
"backup_success_pct": 100,
|
||||
"restore_rto_minutes": 1.08,
|
||||
"measurement_gaps": [
|
||||
"infrastructure_eur: no invoice for a resource commissioned 2026-08-14 (owner: fin-hub, FIN-WP-0004)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"evidence": [
|
||||
"resource-control:data/actuals/2026-08.json"
|
||||
]
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import json
|
||||
from datetime import date, datetime, timezone
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
|
|
@ -17,6 +18,8 @@ from fin_hub.services.exchange import (
|
|||
financial_constraint_projection,
|
||||
ingest_planning_evidence,
|
||||
ingest_resource_forecast,
|
||||
ingest_resource_usage,
|
||||
reconcile_resource_period,
|
||||
)
|
||||
from fin_hub.services.ledger import import_csv
|
||||
|
||||
|
|
@ -341,3 +344,72 @@ def test_exchange_health_exposes_rejection_stale_forecast_and_unattributed_cost(
|
|||
"stale_forecast",
|
||||
"unattributed_booked_cost",
|
||||
}
|
||||
|
||||
|
||||
FIXTURES = Path(__file__).parent / "fixtures"
|
||||
AUDIT_STORAGE = "resource:platform:audit-storage"
|
||||
|
||||
|
||||
def test_audit_storage_usage_omits_nulls_and_does_not_invent_zero_spend(tmp_path: Path):
|
||||
ledger = tmp_path / "ledger.db"
|
||||
payload = json.loads(
|
||||
(FIXTURES / "platform-audit-storage-usage-2026-08.json").read_text()
|
||||
)
|
||||
records = ingest_resource_usage(
|
||||
payload,
|
||||
resource_id=AUDIT_STORAGE,
|
||||
source_evidence_ref="resource-control:data/actuals/2026-08.json",
|
||||
ledger_path=ledger,
|
||||
)
|
||||
assert len(records) == 1
|
||||
names = {measure.name: measure for measure in records[0].measures}
|
||||
assert set(names) == {
|
||||
"database_gb",
|
||||
"stored_gb",
|
||||
"backup_success_pct",
|
||||
"restore_rto_minutes",
|
||||
}
|
||||
assert "infrastructure_eur" not in names
|
||||
assert names["stored_gb"].value == Decimal("0.0066")
|
||||
assert any("gap:infrastructure_eur" in item for item in records[0].source_evidence)
|
||||
|
||||
forecast = {
|
||||
"schema_version": "0.1",
|
||||
"record_type": "forecast",
|
||||
"workload": "platform-pg",
|
||||
"cost_attribution_key": "platform:audit-storage",
|
||||
"provider_id": "scaleway-standard-multi-az",
|
||||
"created_at": "2026-08-10T17:10:00Z",
|
||||
"scenario": "base",
|
||||
"forecast_ref": None,
|
||||
"rows": [
|
||||
{
|
||||
"period": "2026-09",
|
||||
"database_gb": 5,
|
||||
"stored_gb": 180,
|
||||
"wal_gb": 30,
|
||||
"restore_egress_gb": 5,
|
||||
"write_requests": 2500,
|
||||
"read_requests": 1000,
|
||||
"infrastructure_eur": 2.89,
|
||||
"internal_labor_hours": 1,
|
||||
"internal_labor_eur": 60,
|
||||
"total_eur": 62.89,
|
||||
}
|
||||
],
|
||||
}
|
||||
ingest_resource_forecast(
|
||||
forecast,
|
||||
resource_id=AUDIT_STORAGE,
|
||||
source_evidence_ref="resource-control:data/forecasts/platform-audit-storage",
|
||||
ledger_path=ledger,
|
||||
)
|
||||
august = reconcile_resource_period(
|
||||
resource_id=AUDIT_STORAGE, period="2026-08", ledger_path=ledger
|
||||
)
|
||||
assert august.usage_record_ids
|
||||
assert august.missing_booked_fact is True
|
||||
assert august.booked_effective_amount is None
|
||||
assert august.invented_zero is False
|
||||
health = exchange_health(ledger_path=ledger)
|
||||
assert "usage_without_booked_fact" in {issue.code for issue in health.issues}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue