94 lines
3.8 KiB
JSON
94 lines
3.8 KiB
JSON
|
|
{
|
||
|
|
"schema_version": "0.1",
|
||
|
|
"resource_id": "resource:platform:audit-storage",
|
||
|
|
"cost_attribution_key": "platform:audit-storage",
|
||
|
|
"effective_from": "2026-08-14",
|
||
|
|
"review": "quarterly, and before any contract or retention change",
|
||
|
|
"basis": "docs/forecast-actual-control.md error thresholds, plus the operating facts proven in RESOURCE-WP-0002-T05",
|
||
|
|
"thresholds": [
|
||
|
|
{
|
||
|
|
"id": "budget-variance-infrastructure",
|
||
|
|
"kind": "budget_variance",
|
||
|
|
"metric": "infrastructure_eur",
|
||
|
|
"comparison": "absolute_percentage_error",
|
||
|
|
"limit": 10,
|
||
|
|
"action": "investigate before accepting the period; separate usage error from rate, tax, or SKU change"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "budget-variance-labor",
|
||
|
|
"kind": "budget_variance",
|
||
|
|
"metric": "internal_labor_hours",
|
||
|
|
"comparison": "absolute_error",
|
||
|
|
"limit": 1,
|
||
|
|
"unit": "hours",
|
||
|
|
"action": "investigate; recurring operator time above forecast is the usual reason a cheap provider is not cheap"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "abnormal-growth-stored",
|
||
|
|
"kind": "abnormal_growth",
|
||
|
|
"metric": "stored_gb",
|
||
|
|
"comparison": "absolute_percentage_error",
|
||
|
|
"limit": 20,
|
||
|
|
"action": "check retention behaviour, incomplete multipart uploads, versioning, and base-backup frequency before assuming demand grew"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "abnormal-growth-wal",
|
||
|
|
"kind": "abnormal_growth",
|
||
|
|
"metric": "wal_gb",
|
||
|
|
"comparison": "absolute_percentage_error",
|
||
|
|
"limit": 20,
|
||
|
|
"action": "check for a write-amplifying change in platform-pg before re-forecasting"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "unplanned-egress",
|
||
|
|
"kind": "abnormal_growth",
|
||
|
|
"metric": "restore_egress_gb",
|
||
|
|
"comparison": "unplanned",
|
||
|
|
"limit": 0,
|
||
|
|
"action": "any egress not explained by a recorded restore drill is investigated as an access or exfiltration question, not only a cost question"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "stale-backup",
|
||
|
|
"kind": "stale_backup",
|
||
|
|
"metric": "backup_success_pct",
|
||
|
|
"comparison": "minimum",
|
||
|
|
"limit": 100,
|
||
|
|
"action": "a single failed scheduled backup is investigated; backup success is not averaged across a month"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "stale-archive",
|
||
|
|
"kind": "stale_backup",
|
||
|
|
"metric": "wal_archive_gap_minutes",
|
||
|
|
"comparison": "maximum",
|
||
|
|
"limit": 15,
|
||
|
|
"unit": "minutes",
|
||
|
|
"action": "three times the 5-minute archive_timeout; beyond this the 5-minute RPO requirement is no longer met",
|
||
|
|
"measured_baseline": "about 2 seconds after pg_switch_wal, observed 2026-08-14"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "restore-rto-regression",
|
||
|
|
"kind": "stale_backup",
|
||
|
|
"metric": "restore_rto_minutes",
|
||
|
|
"comparison": "maximum",
|
||
|
|
"limit": 3.24,
|
||
|
|
"unit": "minutes",
|
||
|
|
"action": "three times the measured 1.08-minute full-restore baseline; a regression is investigated before the next drill is accepted",
|
||
|
|
"measured_baseline": "65 seconds full restore and 65 seconds PITR, observed 2026-08-14 on 636 MB of PGDATA"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"id": "unused-commitment",
|
||
|
|
"kind": "unused_commitment",
|
||
|
|
"metric": "commitment_utilization",
|
||
|
|
"comparison": "minimum",
|
||
|
|
"limit": null,
|
||
|
|
"status": "not_applicable",
|
||
|
|
"action": "Scaleway Multi-AZ is usage-based with no commitment (commitment_ref is null), so there is no unused commitment to detect. This threshold activates only if a term or reserved commitment is ever taken."
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"known_gaps": [
|
||
|
|
"No euro budget ceiling exists for this resource. Scaleway has no hard spend stop and the founder's email alert is the accepted backstop; an authoritative ceiling belongs to fin-hub (FIN-WP-0004).",
|
||
|
|
"wal_archive_gap_minutes is not yet emitted by any monthly observation; it requires an archive-health metric from rapp-postgres.",
|
||
|
|
"restore_rto_minutes is populated only in periods that contain a drill; absence is not a pass."
|
||
|
|
]
|
||
|
|
}
|