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>
This commit is contained in:
tegwick 2026-08-14 09:36:57 +02:00
parent b64b5683df
commit 17de8b831e
16 changed files with 908 additions and 71 deletions

View file

@ -0,0 +1,90 @@
# RESOURCE-WP-0003 apps-pg evidence fold-in — 2026-08-14
## Result
`railiance-platform` finished `RAILIANCE-WP-0016` and published the apps-pg
evidence that `RESOURCE-WP-0003-T04` delegated. This is the first delegated
evidence to land, and folding it in exercised the whole loop end to end:
delegation, delivery, ingestion, allocation, control record, and report.
Source, captured 2026-08-14T00:04:19Z, refreshed with `make apps-pg-evidence`:
- `/home/worsch/railiance-platform/docs/evidence/RAILIANCE-WP-0016-apps-pg-observation.json`
- `/home/worsch/railiance-platform/docs/evidence/RAILIANCE-WP-0016-apps-pg-resource-evidence.md`
## What changed here
| Artifact | Change |
|---|---|
| `data/resources/apps-pg.json` | Real capacity and utilization; allocation moved from `unattributed` to `shared` under `apps-pg-dbbytes-v1`; second consumer `vergabe-teilnahme` registered; evidence repointed at the platform interface |
| `data/control-cycle/apps-pg-2026-09-base.json` | **New.** First operational control-cycle record in the repository |
| `examples/control-cycle/apps-pg-{forecast,actual}.json` | **Retired.** The invented fixture collided with the real record's identifier — the clearest possible signal it had been superseded |
| `schemas/resource-control-cycle.schema.json` | Widened to 0.2: nullable costs, nullable `unattributed_eur`, new `unattributed_share`, nullable measurement values |
| `tools/control_cycle.py` | Unknown amounts return `status: "unknown"` and classify as `data_quality` instead of computing a variance |
| `data/portfolio-coverage-2026-08-14.json` | **New.** Supersedes the 2026-08-11 observation; the railiance-platform gap is `delivered` with three residual unknowns |
| `tools/portfolio_report.py` | Delivered gaps stay visible with their residuals; `storage`/`storage_used` added to the measurable pairs |
## The schema gap the real evidence exposed
railiance-platform delivered technical facts and, correctly, no EUR — the host
bill belongs to `resource:hosteurope:railiance01`, whose price is unknown, and
they wrote plainly: "resource-control may convert hours at its own labor rate.
Do not treat these hours as booked cost."
Schema 0.1 could not represent that. Every cost field required a number, so the
only way to record real usage was to invent a cost — precisely what this
repository refuses to do everywhere else. That is a genuine design gap, found
by real evidence rather than by review.
Schema 0.2 permits `null` for cost components, `unattributed_eur`, and
measurement values, and adds `unattributed_share` so a residual can be recorded
from technical evidence alone. `null` means unknown, never zero; if any
component is unknown the total is `null` rather than the sum of the known
parts; and the comparator classifies an unknown amount as `data_quality`,
overriding any explicit attribution, because a missing amount is an evidence
gap and not a price movement.
Existing 0.1 records were not rewritten. `schema_version` accepts both:
immutability applies to the record, not to the schema.
## The first operational record
`forecast:apps-pg:2026-09:base:v1` carries what is known and refuses the rest:
| Field | Value | Basis |
|---|---|---|
| `consumer_database_gb` | 0.0155 GiB | `pg_database_size` of the two declared consumer databases |
| `pgdata_gb` | 0.5766 GiB | `du -sb` on PGDATA |
| storage used / provisioned | 0.5766 of 10 GiB | PVC `apps-pg-1`, `local-path` |
| `internal_labor` | EUR 30.00 | 0.5 declared operator-hours at the EUR 60/hour rate already used in `data/demand/platform-audit-storage.json` |
| `infrastructure` | **null** | Share of railiance01; price unknown (`RAIL-HO-WP-0008`) |
| `total` | **null** | One component unknown; not the sum of the known parts |
| `unattributed_share` | 0.948 | WAL and engine catalogs under `platform:apps-pg-overhead` |
| `rpo_minutes`, `rto_minutes` | **null** | No ScheduledBackup, no restore drill, not an Option A target |
Uncertainty is `high` and stated in eight notes, including the one that matters
most for allocation: `vergabe_db` has never recorded a transaction, so its
0.4614 byte share reflects a reserved empty database rather than realised
demand. The method is recorded as delivered; whether it survives contact with a
second month is a question for the quarterly calibration.
## Effect on the portfolio report
- apps-pg leaves `utilization.unmeasured` and enters `utilization.idle` at
5.8 percent of its volume — a third idle resource alongside railiance01 and
the k3s cluster.
- apps-pg leaves `cost.unattributed_allocation`, which drops from four
resources to three.
- apps-pg remains in `cost.unpriced`, and `known_monthly_spend_eur` remains
`null`. Delivered technical evidence does not create a booked cost.
- The railiance-platform gap moves to `delivered_gaps` and still generates
three next actions from its residual unknowns.
## Boundary held
No booked cost was originated here. The labour figure is a conversion of
declared hours at a rate this repository already publishes, recorded as an
estimate with its basis, not as a ledger fact. Recovery risk was recorded, not
resolved: apps-pg has RPO unbounded and RTO undefined on single-host local-path
storage, which stays railiance-platform's to close and is gated on the same
object-store decision as `RESOURCE-WP-0002`.