feat(portfolio): complete RESOURCE-WP-0003 T06 optimization cases and T07 reporting
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>
2026-08-14 09:28:44 +02:00
|
|
|
|
# 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
|
|
|
|
|
|
```
|
|
|
|
|
|
|
feat(portfolio): fold in RAILIANCE-WP-0016 apps-pg evidence
First delegated evidence from RESOURCE-WP-0003-T04 to land. railiance-platform
delivered apps-pg capacity, utilization, consumers, and the apps-pg-dbbytes-v1
allocation driver, and correctly delivered no EUR.
- data/resources/apps-pg.json: real capacity; allocation unattributed -> shared
under apps-pg-dbbytes-v1; second consumer vergabe-teilnahme registered
- data/control-cycle/apps-pg-2026-09-base.json: first operational control-cycle
record in the repository
- examples/control-cycle/apps-pg-*.json retired; the invented fixture collided
with the real record's identifier
- data/portfolio-coverage-2026-08-14.json: gap marked delivered with three
residual unknowns still open
The real evidence exposed a design gap in the T05 schema: v0.1 required a number
for every cost field, so recording genuine usage without a booked cost meant
inventing one. Schema 0.2 permits null costs, null unattributed_eur, a technical
unattributed_share, and null measurements. Null is unknown, never zero; an
unknown component makes the total null rather than the sum of the known parts;
and the comparator classifies unknown amounts as data_quality instead of
computing a variance. Existing 0.1 records are not rewritten.
apps-pg is now measured (idle at 5.8% of volume) and attributed, and remains
unpriced: delivered technical evidence does not create a booked cost.
86 tests pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 09:36:57 +02:00
|
|
|
|
The examples cover storage and `reef-railiance` cluster compute. Their numbers
|
|
|
|
|
|
are illustrative contract fixtures, not booked facts. Operational records
|
|
|
|
|
|
replace them once the owner workplans publish observations — the illustrative
|
|
|
|
|
|
`apps-pg` pair was retired on 2026-08-14 when `RAILIANCE-WP-0016` delivered the
|
|
|
|
|
|
real one to `data/control-cycle/apps-pg-2026-09-base.json`.
|
|
|
|
|
|
|
|
|
|
|
|
Illustrative fixtures live in `examples/control-cycle/`; operational records
|
|
|
|
|
|
live in `data/control-cycle/` and must cite the authoritative repository
|
|
|
|
|
|
evidence they came from and state their uncertainty. The validator enforces
|
|
|
|
|
|
both.
|
|
|
|
|
|
|
|
|
|
|
|
### Schema 0.2 — unknown is not zero
|
|
|
|
|
|
|
|
|
|
|
|
Real evidence arrives incomplete. `RAILIANCE-WP-0016` supplied apps-pg
|
|
|
|
|
|
capacity, utilization, consumers, and an allocation driver, and correctly
|
|
|
|
|
|
supplied no EUR: the host bill belongs to `resource:hosteurope:railiance01`,
|
|
|
|
|
|
whose price is still unknown. Schema 0.1 could not express that — every cost
|
|
|
|
|
|
field required a number, so the only way to record real usage was to invent a
|
|
|
|
|
|
cost.
|
|
|
|
|
|
|
|
|
|
|
|
Schema 0.2 permits `null` for each cost component, for `unattributed_eur`, and
|
|
|
|
|
|
for any measurement value, and adds `unattributed_share` so a shared-cost
|
|
|
|
|
|
residual can be recorded from technical evidence before any EUR exists. The
|
|
|
|
|
|
rules:
|
|
|
|
|
|
|
|
|
|
|
|
- `null` means unknown or unbounded, never zero;
|
|
|
|
|
|
- if any cost component is unknown, `total` is `null` — never the sum of the
|
|
|
|
|
|
parts that happen to be known;
|
|
|
|
|
|
- the comparator returns `status: "unknown"` for that component and classifies
|
|
|
|
|
|
it `data_quality`, overriding any explicit attribution, because a missing
|
|
|
|
|
|
amount is an evidence gap rather than a price or labour movement;
|
|
|
|
|
|
- known components still compute their variance alongside unknown ones.
|
|
|
|
|
|
|
|
|
|
|
|
Existing 0.1 records stay valid and are never rewritten. Immutability applies
|
|
|
|
|
|
to the record, not to the schema, so `schema_version` accepts both.
|
feat(portfolio): complete RESOURCE-WP-0003 T06 optimization cases and T07 reporting
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>
2026-08-14 09:28:44 +02:00
|
|
|
|
|
|
|
|
|
|
## 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.
|