resource-control/docs/forecast-actual-control.md
tegwick 2c2a6073ff 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

5.4 KiB
Raw Blame History

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:

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.