resource-control/docs/evidence/RESOURCE-WP-0002-T07-control-loop-2026-08-14.md
tegwick 10b988fa1c feat(wp-0002): complete T07 — control loop on the live backup resource
The backup is procured and proven, so the loop runs on real evidence.

- data/actuals/2026-08.json: first real observation. database 0.6365 GB,
  stored 0.0066 GB over 8 objects, backup success 1/1, restore RTO 1.08 min.
  Five proxies null, each with a named owner in measurement_gaps.
- data/thresholds/platform-audit-storage.json + tools/thresholds.py: budget
  variance, abnormal growth, stale backup, unused commitment. Fail-closed —
  an unmeasured value is reported as unmeasured, never as within.
- financial_exchange.py gains a usage mode emitting technical_usage records to
  fin-hub, with measurement gaps carried through and no infrastructure amount:
  fin-hub owns the booked fact and a null is never sent as 0.00.
- observation schema 0.2 allows null cost and usage proxies; variance.py fails
  closed rather than reporting a 100% favourable variance on a missing amount.
- platform-audit-storage: ordered -> active, commissioned 2026-08-14, on
  operational fact rather than on the purchase.

The optimization case is now approved by the founder. That needed a schema
change: Host Europe never supplied written terms, so options gained
excluded/exclusion_reason. Previously an unevaluable alternative blocked its
case forever, leaving the record claiming no decision while the bucket was in
production. An excluded option keeps its unknowns and must say what would
bring it back.

August produces no variance and should not: the decision forecast starts at
2026-09, so August is a commissioning baseline. Threshold run is 2 within,
1 not applicable, 6 unmeasured, 0 breaches.

Also fixes a pre-existing test failure: reef-storage consumers_actual is now
rapp-postgres, which the assertion still expected to be empty.

136 tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 20:53:12 +02:00

5.8 KiB

RESOURCE-WP-0002-T07 — fin-hub feed and optimization loop — 2026-08-14

Result

The backup resource is live and proven, so the loop it exists to feed can now run on real evidence instead of a model. T07 closes the cycle: observation → thresholds → normalized fin-hub evidence → decided optimization case.

Artifact Purpose
data/actuals/2026-08.json First real monthly observation for platform:audit-storage
data/thresholds/platform-audit-storage.json Budget variance, abnormal growth, stale backup, and unused-commitment thresholds
tools/thresholds.py, make thresholds PERIOD=… Fail-closed threshold evaluation
tools/financial_exchange.py usage, make exchange-usage Normalized technical-usage evidence to fin-hub
data/optimization/platform-audit-storage-2026-08.json The A/B/C case, now approved and executed
data/resources/platform-audit-storage.json orderedactive, commissioned 2026-08-14

The first period is honest about being four hours long

The bucket was created 2026-08-14T16:21:56Z and the first backup completed at 18:14:21Z. The 2026-08 row therefore covers about four hours of operation, and says so. What is measured:

Proxy Value Source
database_gb 0.6365 PGDATA 636 485 632 B
stored_gb 0.0066 8 objects, 6 604 031 B in platform-pg/
backup_success_pct 100 1 of 1 completed backups
restore_rto_minutes 1.08 65 s full restore; PITR the same

Five proxies are null, each with a named owner in measurement_gaps: WAL is not separable from the base backup in the archive, restore egress bytes were not recorded, no request metric is exposed to the scoped key, no invoice exists, and no time record was kept for the procurement and drill work.

internal_labor_hours being null deserves a note: real operator hours were spent this period on procurement, credential custody, and two restore drills. Recording zero would have been false, and estimating would have been invention. It is null with the reason attached, and the next period starts a time record.

Why August produces no variance

make variance ACTUAL=data/actuals/2026-08.json returns no-forecast for the period. The decision forecast begins at 2026-09, because the resource was not expected to exist in August. This is the correct answer, not a defect: August is a commissioning baseline and 2026-09 is the first comparable month.

The threshold run reflects the same thing without pretending. Of nine thresholds: two within, one not_applicable, six unmeasured, zero breaches.

  • withinstale-backup (100%) and restore-rto-regression (1.08 min against a 3.24 min limit). These are the two things that were actually proven.
  • not_applicableunused-commitment. Scaleway Multi-AZ is usage-based with no commitment, so there is nothing to under-use. Distinguished from passing.
  • unmeasured — everything requiring an invoice, a request metric, a WAL split, or a forecast row.

unmeasured is deliberately not within. A threshold that silently passes on absent evidence is worse than no threshold: it reports safety it never checked.

Thresholds set

Budget variance at 10% on infrastructure and 1 hour on labour; abnormal growth at 20% on stored bytes and WAL; any egress not explained by a recorded drill; backup success below 100% on any single run, not averaged across a month; WAL archive gap above 15 minutes, three times the 5-minute archive_timeout beyond which the RPO requirement fails; restore RTO above 3.24 minutes, three times the measured baseline.

Two are declared rather than active. wal_archive_gap_minutes needs an archive health metric from rapp-postgres. No euro budget ceiling exists: Scaleway has no hard spend stop, the founder's email alert is the accepted backstop, and an authoritative ceiling belongs to fin-hub.

Feed to fin-hub

financial_exchange.py usage emits technical_usage records under the contract's resource-control-to-fin-hub direction: resource, service, workload, attribution key, period bounds, usage proxies, service evidence, and valued internal labour — with measurement_gaps carried through so fin-hub sees why a field is empty.

Infrastructure cost is absent by design. fin-hub owns the booked fact; an uninvoiced period has no amount to send, and a null is never normalized to 0.00.

The optimization case is now decided

opt:platform-audit-storage:2026-08 moved from blocked_on_evidence to approved, approver "founder (human financial authority)", 2026-08-14.

The schema gained excluded / exclusion_reason on an option, because the real decision exposed a modelling gap: Host Europe never supplied written terms, and the deciding authority chose to exclude it rather than delay recovery capability indefinitely. Before this, an unevaluable alternative blocked its case forever, which would have left the record claiming no decision had been made while the bucket was in production. An excluded option no longer blocks, keeps its recorded unknowns, and must state what would bring it back.

Hetzner remains a fully costed reject at €29.14/month dearer. The rationale records two accepted risks at decision time: no euro hard-stop at Scaleway, and the independent second copy required by the correlated-failure rule still outstanding as T06.

Boundary held

No booked cost was originated. The resource record moved to active on operational fact — production backup enabled, ContinuousArchivingSuccess, both restores verified — not on the purchase. Implementation of anything the case approves is delegated to railiance-platform and rapp-postgres.

Standing dependency

Total cost stays unknown until Scaleway invoices and fin-hub books it under FIN-WP-0004. The loop runs monthly regardless; 2026-09 is the first period that will produce real variance.