T06: optimization-case schema, fail-closed evaluator, cadence and decision template. Every option including the baseline must present all ten decision fields; one unknown blocks the comparison. Validated on the storage case (Hetzner computes and loses to Scaleway by EUR 29.14/month on operator labour; Host Europe blocks on four named gaps) and on the non-storage reef-railiance k3s rightsizing case (low utilization is real, but nothing is costable while the railiance01 price is unknown). T07: portfolio report over coverage, lifecycle, utilization, cost, renewals, risks, open cases, and next actions, derived only from committed evidence. Portfolio spend is reported null rather than as a partial sum, unattributed cost is a named list rather than a spread, and unmeasurable resources are reported rather than dropped. RESOURCE-WP-0003 is finished; both cases remain blocked_on_evidence against live delegated records in other repositories. RESOURCE-WP-0002 is untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
123 lines
5.4 KiB
Markdown
123 lines
5.4 KiB
Markdown
# Forecast-to-actual resource control
|
||
|
||
## Why the €2.89, €5.14, €62.89, and €65.14 figures differ
|
||
|
||
They describe two volumes and two cost scopes:
|
||
|
||
| Figure | Stored volume | Scope | Calculation |
|
||
| --- | ---: | --- | --- |
|
||
| €2.89 | 180 GB | infrastructure only | 180 × €0.01606 |
|
||
| €62.89 | 180 GB | infrastructure + internal labor | €2.89 + 1 h × €60 |
|
||
| €5.14 | 320 GB | infrastructure only | 320 × €0.01606 |
|
||
| €65.14 | 320 GB | infrastructure + internal labor | €5.14 + 1 h × €60 |
|
||
|
||
The older €62.89 estimate was not “storage without elastic cost”; it already
|
||
included the €60 monthly operator allowance. The normalized table introduced a
|
||
different stored volume and showed infrastructure separately. Future reports
|
||
must always label both `stored_gb` and cost scope.
|
||
|
||
## Control records
|
||
|
||
A forecast is a timestamped, immutable record of what was believed at decision
|
||
time. The initial base forecast is
|
||
`data/forecasts/platform-audit-storage-scaleway-base-2026-08.json`. Do not edit
|
||
it after actual evidence exists. If assumptions change, create a new forecast
|
||
with a new creation date and retain the prior one so forecast accuracy remains
|
||
auditable.
|
||
|
||
After every billing month, record a technical `usage_observation` under
|
||
`data/actuals/`. Authoritative booked financial facts come from fin-hub and
|
||
are joined by reference; resource-control does not originate a second booked
|
||
actual.
|
||
The required cost and usage proxies are:
|
||
|
||
- database size and provider stored bytes;
|
||
- WAL volume;
|
||
- write and read requests;
|
||
- restore-test egress;
|
||
- infrastructure invoice cost;
|
||
- internal operations hours and valued labor cost;
|
||
- total attributable cost;
|
||
- backup success, maximum observed RPO, and restore RTO when measured.
|
||
|
||
Provider stored bytes are intentionally distinct from logical database size.
|
||
They expose base-backup retention, WAL, compression, versioning, incomplete
|
||
multipart uploads, and lifecycle behavior. Invoice cost is distinct from the
|
||
provider's usage estimator and must reconcile to non-secret billing evidence.
|
||
|
||
## Error calculation and review
|
||
|
||
`make variance ACTUAL=data/actuals/YYYY-MM.json` reports signed error and
|
||
absolute percentage error for each numeric proxy. Initially review rather than
|
||
automatically rewrite assumptions:
|
||
|
||
- investigate infrastructure cost error above 10%;
|
||
- investigate stored-byte or WAL error above 20%;
|
||
- investigate any unplanned egress or request-class charge;
|
||
- investigate labor error above 1 hour or 25%;
|
||
- investigate every backup failure, RPO breach, or restore-RTO regression.
|
||
|
||
After three comparable months, calculate mean absolute percentage error by
|
||
proxy and recalibrate the next forecast. Avoid MAPE where the forecast is zero;
|
||
use absolute error and explain the new activity instead. Separate forecast
|
||
error from price variance: a bill can differ because usage was wrong, the rate
|
||
changed, tax/discount treatment differed, or an unmodeled SKU appeared.
|
||
|
||
Quarterly provider comparison should use the latest actual trailing three
|
||
months, the next 12-month forecast, one monthly restore, an exit event, and
|
||
observed—not aspirational—operator labor.
|
||
|
||
## General portfolio control record
|
||
|
||
The storage-specific v0.1 observation remains valid for the backup procurement
|
||
case. New portfolio controls use
|
||
`schemas/resource-control-cycle.schema.json`, whose resource-specific
|
||
`usage_proxies` allow the same comparison mechanism to cover storage, VMs or
|
||
cluster compute, shared platform services, managed services, and future
|
||
resource types without pretending they share the same utilization unit.
|
||
|
||
Each record separates:
|
||
|
||
- provisioned and used capacity, with a fixed, elastic, or hybrid model;
|
||
- infrastructure, internal labor, and external labor cost;
|
||
- booked financial facts, referenced rather than copied from fin-hub;
|
||
- allocation method, driver, version, and unattributed residual;
|
||
- service constraints and their units;
|
||
- low/base/high forecast scenario or observed actual;
|
||
- evidence and uncertainty.
|
||
|
||
Forecast records are append-only. A changed forecast receives a new
|
||
`record_id`, creation time, and `revision_of` reference. Actuals must name the
|
||
exact original `forecast_ref`; a later revision must never replace the
|
||
decision-time baseline when measuring forecast error.
|
||
|
||
Run a generic comparison with:
|
||
|
||
```sh
|
||
make control-cycle FORECAST=examples/control-cycle/storage-forecast.json \
|
||
ACTUAL=examples/control-cycle/storage-actual.json
|
||
```
|
||
|
||
The examples cover storage, `reef-railiance` cluster compute, and the shared
|
||
`apps-pg` service. Their numbers are illustrative contract fixtures, not booked
|
||
facts. Operational records replace their evidence references after the owner
|
||
workplans publish observations.
|
||
|
||
## Variance attribution
|
||
|
||
Every material variance is assigned to one of six controlled categories:
|
||
|
||
- `demand`: the amount of consumed service differed;
|
||
- `provider_price`: rate, discount, tax, currency, or billed SKU differed;
|
||
- `allocation`: a shared-cost driver or attribution changed;
|
||
- `labor`: internal or external effort differed;
|
||
- `model`: a formula, assumption, capacity behavior, or omitted component was
|
||
wrong;
|
||
- `data_quality`: evidence is missing, late, inconsistent, or uses a different
|
||
unit.
|
||
|
||
The comparator defaults usage differences to demand, infrastructure cost to
|
||
provider price, and labor fields to labor, while preserving explicit
|
||
attribution supplied with the actual. Missing proxies and unit mismatches fail
|
||
closed as data-quality errors. Attribution explains an error; it does not
|
||
rewrite the forecast.
|