Three things. 1. CANON RESTATEMENT (info-tech-canon's ask after accepting our demand) data/capability/platform-audit-storage.json restates the backup case against ITC-CAP 0.2.0: requirement with profile, targets and the failure-domain constraint that decided the procurement; two provisions (data.object and data.backup); all four data.backup evidence hooks satisfied and measured; and consumption in native units — GB, hours, tokens — with unknown never zero. tools/capability.py reads their capabilities.yaml directly rather than copying it, so drift in either repo fails here. The requirement asks D5, the provision is D4, and the review reports below_requirement rather than inflating maturity. 2. EVIDENCE BASIS (tools/basis.py, docs/evidence-basis.md) Every value declares how it was obtained on an ordered scale: invoiced, measured, quoted, derived, projected, estimated, assumed, unknown. A derived value resolves to the weakest basis among its inputs, so precise arithmetic cannot launder weak assumptions. First application is a finding about our own biggest decision: the Scaleway vs Hetzner comparison, EUR 29.14/month stated to the cent, grades "indicative" — 1 of 4 load-bearing values evidenced, weakest "assumed". The direction is robust; the magnitude is a model output. The cheapest fix is recording real operator hours, not better arithmetic. 3. CONSUMPTION-MODE SIGNAL (railiance-platform RAILIANCE-WP-0017) settlement.py gains a consumption-mode command projecting statements into the signal they consume; make consumption-mode PERIOD=YYYY-MM publishes data/consumption-mode/current.json. Currently an empty list: no live charges for 2026-09, so no entity is restricted. Publishing the empty list makes that an assertion rather than an absence, which their contract distinguishes. The validator fails if the published signal is stale. 185 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
217 lines
9.8 KiB
JSON
217 lines
9.8 KiB
JSON
{
|
|
"schema_version": "0.1",
|
|
"record_scope": "operational",
|
|
"canon": {
|
|
"model": "ITC-CAP",
|
|
"model_version": "0.2.0",
|
|
"canon_version": "0.3.0",
|
|
"catalog": "info-tech-canon/infospace/models/capability/capabilities.yaml"
|
|
},
|
|
"record_id": "capability-case:platform-audit-storage:2026-08",
|
|
"created_at": "2026-08-15T00:00:00Z",
|
|
"subject": "PostgreSQL backup for rapp-postgres/platform-pg, restated in canon terms",
|
|
"note": "Real provisioned resource. Every value carries an evidence basis; a derived value is only as strong as its weakest input.",
|
|
|
|
"requires": [
|
|
{
|
|
"consumer": "rapp-postgres/platform-pg",
|
|
"capability": "data.backup",
|
|
"profile": "database",
|
|
"minimum_maturity": "D5",
|
|
"targets": {
|
|
"rpo": { "value": 5, "unit": "minutes" },
|
|
"rto": { "value": 60, "unit": "minutes" },
|
|
"retention": { "value": 30, "unit": "days" }
|
|
},
|
|
"constraints": [
|
|
{
|
|
"dimension": "geographical_separation",
|
|
"predicate": "not_in",
|
|
"of": [
|
|
{ "kind": "host", "id": "railiance01" },
|
|
{ "kind": "provider", "id": "host-europe" }
|
|
]
|
|
}
|
|
],
|
|
"requirement_note": "The constraint is the one that decided the procurement: the backup must not share a failure domain with the host it protects. Before ITC-CAP 0.2.0 this lived only in prose."
|
|
}
|
|
],
|
|
|
|
"provisions": [
|
|
{
|
|
"provider": "resource:platform:audit-storage",
|
|
"capability": "data.object",
|
|
"environment": "production",
|
|
"maturity": "D4",
|
|
"implements": "Scaleway Standard Multi-AZ object storage, nl-ams",
|
|
"resource_ref": "data/resources/platform-audit-storage.json",
|
|
"maturity_rationale": "Approved for production dependency and in production use since 2026-08-14. Not D5: object-integrity testing is inherited from the backup restore drill rather than measured on this provision.",
|
|
"consumes": [
|
|
{
|
|
"class": "S",
|
|
"name": "stored objects",
|
|
"quantity": { "value": 0.0066, "unit": "GB" },
|
|
"period": "month",
|
|
"basis": "measured",
|
|
"evidence": "docs/evidence/RESOURCE-WP-0002-T05-restore-2026-08-14.json#archive",
|
|
"observed_at": "2026-08-14",
|
|
"measurement_note": "8 objects, 6 604 031 B in prefix platform-pg/, four hours after commissioning"
|
|
},
|
|
{
|
|
"class": "N",
|
|
"name": "restore egress",
|
|
"quantity": { "value": null, "unit": "GB" },
|
|
"period": "month",
|
|
"basis": "unknown",
|
|
"gap": "two scratch restores read from the bucket but bytes transferred were not recorded (owner: resource-control, add to the next drill)"
|
|
},
|
|
{
|
|
"class": "P",
|
|
"name": "object-store service",
|
|
"quantity": { "value": 1, "unit": "unit" },
|
|
"period": "month",
|
|
"supply": "external",
|
|
"basis": "quoted",
|
|
"evidence": "data/providers/object-storage.json#scaleway-standard-multi-az",
|
|
"measurement_note": "Published list price; no account quote and no invoice yet"
|
|
},
|
|
{
|
|
"class": "H",
|
|
"name": "object-store operation",
|
|
"quantity": { "value": 1.0, "unit": "hour" },
|
|
"period": "month",
|
|
"supply": "internal",
|
|
"basis": "assumed",
|
|
"evidence": "data/providers/object-storage.json#scaleway-standard-multi-az.operator_hours_per_month",
|
|
"measurement_note": "A planning allowance chosen at model time, not an observed or recorded figure"
|
|
},
|
|
{
|
|
"class": "I",
|
|
"name": "intelligence",
|
|
"quantity": { "value": null, "unit": "token" },
|
|
"period": "month",
|
|
"basis": "unknown",
|
|
"gap": "resource-control does not yet meter token consumption against a provision (owner: resource-control)"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"provider": "rapp-postgres/platform-pg CNPG barmanObjectStore",
|
|
"capability": "data.backup",
|
|
"profile": "database",
|
|
"environment": "production",
|
|
"maturity": "D4",
|
|
"implements": "CloudNativePG 1.25 / Barman, PostgreSQL 16.10",
|
|
"depends_on_provision": "resource:platform:audit-storage provides data.object",
|
|
"maturity_rationale": "D4 and not D5. The requirement asks for D5 (reliability measured and actively controlled). Thresholds are declared in data/thresholds/platform-audit-storage.json, but the evidence behind them is one backup, one full restore, one PITR, and about four hours of operation. wal_archive_gap_minutes is declared and not yet emitted. Reliability is therefore claimed and not yet substantiated. The requirement is not met; the gap is stated rather than the maturity inflated.",
|
|
"evidence": [
|
|
{
|
|
"hook": "successful_backup",
|
|
"basis": "measured",
|
|
"value": "platform-pg-daily-20260814181421 completed in 48 s, method barmanObjectStore, verified",
|
|
"observed_at": "2026-08-14",
|
|
"ref": "docs/evidence/RESOURCE-WP-0002-T05-restore-2026-08-14.json#first_backup"
|
|
},
|
|
{
|
|
"hook": "successful_restore_test",
|
|
"basis": "measured",
|
|
"value": "full restore to scratch cluster in 65 s; audit_core.events 30 = 30; PITR to a corrected target in 65 s with keep marker present and destroy absent",
|
|
"observed_at": "2026-08-14",
|
|
"ref": "docs/evidence/RESOURCE-WP-0002-T05-restore-2026-08-14.json#full_restore,pitr"
|
|
},
|
|
{
|
|
"hook": "measured_rpo",
|
|
"basis": "measured",
|
|
"value": "WAL segment archived about 2 s after pg_switch_wal, against a 5-minute archive_timeout",
|
|
"observed_at": "2026-08-14",
|
|
"ref": "docs/evidence/RESOURCE-WP-0002-T05-restore-2026-08-14.json#rpo_notes",
|
|
"caveat": "A single observation, not a distribution. The target is met on the evidence available."
|
|
},
|
|
{
|
|
"hook": "measured_rto",
|
|
"basis": "measured",
|
|
"value": "65 s full-restore RTO, 65 s PITR RTO, on 636 MB of PGDATA",
|
|
"observed_at": "2026-08-14",
|
|
"ref": "docs/evidence/RESOURCE-WP-0002-T05-restore-2026-08-14.json"
|
|
}
|
|
],
|
|
"consumes": [
|
|
{
|
|
"class": "H",
|
|
"name": "backup operation",
|
|
"quantity": { "value": null, "unit": "hour" },
|
|
"period": "month",
|
|
"supply": "internal",
|
|
"basis": "unknown",
|
|
"gap": "real operator time was spent on procurement, credential custody, and two restore drills in this period, but no time record was kept (owner: resource-control)"
|
|
},
|
|
{
|
|
"class": "P",
|
|
"name": "credential custody",
|
|
"quantity": { "value": 1, "unit": "unit" },
|
|
"period": "month",
|
|
"supply": "internal",
|
|
"basis": "measured",
|
|
"evidence": "OpenBao ClusterSecretStore openbao-backup-object-storage, ExternalSecret synced to databases/platform-pg-backup-s3",
|
|
"observed_at": "2026-08-14",
|
|
"measurement_note": "security.secrets is a separate capability; this row records only that this provision consumes it"
|
|
},
|
|
{
|
|
"class": "I",
|
|
"name": "intelligence",
|
|
"quantity": { "value": null, "unit": "token" },
|
|
"period": "month",
|
|
"basis": "unknown",
|
|
"gap": "not yet metered (owner: resource-control)"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
|
|
"modelled_alternatives": {
|
|
"note": "The provider comparison that produced the decision, graded by evidence basis. The euro figures look precise and are not evidenced: they are derived from quoted list prices, projected demand, and an assumed labour rate.",
|
|
"review_period": "2026-08",
|
|
"values": [
|
|
{
|
|
"name": "scaleway.infrastructure_eur_month",
|
|
"value": 7.35,
|
|
"basis": "derived",
|
|
"derived_from": [
|
|
{ "name": "scaleway.storage_eur_per_gb_month", "value": 0.01606, "basis": "quoted", "evidence": "data/providers/object-storage.json#scaleway-standard-multi-az" },
|
|
{ "name": "stored_gb.month12", "value": 457.968, "basis": "projected", "evidence": "data/demand/platform-audit-storage.json base scenario, month 12" }
|
|
]
|
|
},
|
|
{
|
|
"name": "scaleway.labour_eur_month",
|
|
"value": 60.0,
|
|
"basis": "derived",
|
|
"derived_from": [
|
|
{ "name": "scaleway.operator_hours_per_month", "value": 1.0, "basis": "assumed", "evidence": "data/providers/object-storage.json#scaleway-standard-multi-az" },
|
|
{ "name": "operator_hourly_eur", "value": 60, "basis": "assumed", "evidence": "data/demand/platform-audit-storage.json scenarios[*].operator_hourly_eur" }
|
|
]
|
|
},
|
|
{
|
|
"name": "hetzner.infrastructure_eur_month",
|
|
"value": 6.49,
|
|
"basis": "quoted",
|
|
"evidence": "data/providers/object-storage.json#hetzner-object-storage monthly_minimum_eur"
|
|
},
|
|
{
|
|
"name": "hetzner.labour_eur_month",
|
|
"value": 90.0,
|
|
"basis": "derived",
|
|
"derived_from": [
|
|
{ "name": "hetzner.operator_hours_per_month", "value": 1.5, "basis": "assumed", "evidence": "data/providers/object-storage.json#hetzner-object-storage" },
|
|
{ "name": "operator_hourly_eur", "value": 60, "basis": "assumed", "evidence": "data/demand/platform-audit-storage.json scenarios[*].operator_hourly_eur" }
|
|
]
|
|
}
|
|
]
|
|
},
|
|
|
|
"open_items": [
|
|
"The requirement asks for data.backup at D5; the provision is D4. Closing it needs a drill cadence, an emitted wal_archive_gap_minutes, and more than one backup.",
|
|
"Class I consumption is unknown on both provisions. resource-control does not meter tokens against a provision yet.",
|
|
"Class H on the data.backup provision is unknown: effort was spent and not recorded. A time record starts in 2026-09.",
|
|
"No invoiced basis exists anywhere in this record. The first booked Scaleway cost from fin-hub (FIN-WP-0004) would be the first."
|
|
]
|
|
}
|