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>
117 lines
5.8 KiB
Markdown
117 lines
5.8 KiB
Markdown
# 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` | `ordered` → `active`, 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.
|
|
|
|
- `within` — `stale-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_applicable` — `unused-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.
|