Both demands were accepted. Adopting what landed. EVIDENCE BASIS IS NOW ITC-GOV CANON (0.4.0) tools/basis.py reads infospace/models/governance/evidence-basis.yaml instead of defining its own vocabulary — same discipline we already applied to the capability catalog. Two semantic changes came back that we did not have: - estimated and assumed are peers in tier "judgement". We had them separately ranked, which asserted a difference the canon does not. - derived belongs to no tier at all; asking for its tier before resolving it is now an error rather than a silent rank. Tier membership is read from tiers[].members, not bases[].tier: the latter labels invoiced/measured/quoted all as "evidenced" while the tier list splits them across "observed" and "quoted". tiers[] is authoritative; reported upstream. USES_PROVISIONS IS NOW CANON (0.5.0, CAP-R11) Dropped the proposed_extensions marker. Renamed relation "uses" to "may_use" per their migration note. tools/capability.py now enforces CAP-R11: relation must be depends_on or may_use, a provider must be named, and a depends_on entry MUST be declared between those capabilities in the catalog. data.backup gained catalog may_use: security.secrets from our restatement, so our entry now checks out. Also in 0.4.0: §10.3 changed so a joinable consumer record counts as promotion proof, met by our restatement; ITC-CAP is now 0.4.0 / canon 0.6.0, status draft. Record and tests updated to those versions. 196 tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
285 lines
11 KiB
JSON
285 lines
11 KiB
JSON
{
|
|
"schema_version": "0.1",
|
|
"record_scope": "operational",
|
|
"canon": {
|
|
"model": "ITC-CAP",
|
|
"model_version": "0.4.0",
|
|
"canon_version": "0.6.0",
|
|
"status": "draft",
|
|
"catalog": "info-tech-canon/infospace/models/capability/capabilities.yaml",
|
|
"evidence_basis_catalog": "info-tech-canon/infospace/models/governance/evidence-basis.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",
|
|
"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": "I",
|
|
"name": "intelligence",
|
|
"quantity": {
|
|
"value": null,
|
|
"unit": "token"
|
|
},
|
|
"period": "month",
|
|
"basis": "unknown",
|
|
"gap": "not yet metered (owner: resource-control)"
|
|
}
|
|
],
|
|
"uses_provisions": [
|
|
{
|
|
"capability": "data.object",
|
|
"provider": "resource:platform:audit-storage",
|
|
"relation": "depends_on",
|
|
"note": "data.backup depends_on data.object in the catalog; this names which provision satisfies it."
|
|
},
|
|
{
|
|
"capability": "security.secrets",
|
|
"provider": "OpenBao / external-secrets on reef-railiance",
|
|
"relation": "may_use",
|
|
"note": "ClusterSecretStore openbao-backup-object-storage; ExternalSecret synced to databases/platform-pg-backup-s3. Not a consumption row: no purchased platform capacity is bought here, another capability is used.",
|
|
"evidence_basis": "measured",
|
|
"observed_at": "2026-08-14"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"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."
|
|
]
|
|
}
|