feat: migrate live inventory to five-facet 0.3 and close WP-0006

All seven data/resources records now carry description, decision,
reef/secret refs, and potential vs actual consumers. Discovered
resources use decision.status: gap. Validators require live inventory
to be 0.3. WP-0006 T03 done; workplan finished.
This commit is contained in:
tegwick 2026-08-15 02:47:31 +02:00
parent 6e57a65360
commit dafc812daa
11 changed files with 165 additions and 11 deletions

View file

@ -1,10 +1,27 @@
{
"schema_version": "0.2",
"schema_version": "0.3",
"record_scope": "inventory",
"id": "resource:railiance:apps-pg",
"financial_entity_id": null,
"procuring_entity_id": "entity:railiance",
"entity_gap": "shared allocation; coulomb-social maps to entity:coulomb; vergabe-teilnahme has no financial entity",
"description": "Shared CloudNativePG cluster apps-pg on reef-railiance. Holds isolated consumer databases; not the platform-pg backup target.",
"decision": {
"status": "gap",
"chosen": "Live discovered cluster; no formal procurement decision in this repo",
"rejected": [],
"approved_by": null,
"approved_on": null,
"ref": "docs/evidence/RESOURCE-WP-0003-apps-pg-evidence-foldin-2026-08-14.md"
},
"operational_refs": [
"reef:railiance/declarations/reef.yaml"
],
"credential_handles": [],
"consumers": {
"potential": ["coulomb-social", "vergabe-teilnahme"],
"actual": ["coulomb-social", "vergabe-teilnahme"]
},
"resource_class": "database",
"status": "active",
"management_model": "self_managed",

View file

@ -1,9 +1,28 @@
{
"schema_version": "0.2", "record_scope": "inventory",
"schema_version": "0.3", "record_scope": "inventory",
"id": "resource:tenant:friendly:binky:rapp-qonto",
"financial_entity_id": "entity:binky",
"procuring_entity_id": "entity:railiance",
"entity_gap": null,
"description": "Binky Qonto assistant on reef-railiance (Knative plus dedicated egress). Railiance procures the runtime; Binky is the financial consumer.",
"decision": {
"status": "gap",
"chosen": "Live discovered tenant workload; no formal procurement decision in this repo",
"rejected": [],
"approved_by": null,
"approved_on": null,
"ref": "/home/worsch/rapp-qonto/docs/security-and-reliability-gates.md"
},
"operational_refs": [
"reef:railiance/declarations/reef.yaml"
],
"credential_handles": [
"secret:railiance-platform/tenants/binky/qonto-api"
],
"consumers": {
"potential": ["rapp-qonto"],
"actual": ["rapp-qonto"]
},
"resource_class": "self_managed_service",
"status": "active", "management_model": "shared_capacity",
"provider": {"name": "Railiance", "account_ref": null, "product_ref": "rail-knative", "provider_resource_id": "knative:rapp-qonto/rapp-qonto"},

View file

@ -1,9 +1,26 @@
{
"schema_version": "0.2", "record_scope": "inventory",
"schema_version": "0.3", "record_scope": "inventory",
"id": "resource:tenant:coulomb:coulomb-social",
"financial_entity_id": "entity:coulomb",
"procuring_entity_id": "entity:railiance",
"entity_gap": null,
"description": "Coulomb Social production deployment on reef-railiance. Railiance procures the runtime; Coulomb is the financial consumer.",
"decision": {
"status": "gap",
"chosen": "Live discovered tenant workload; no formal procurement decision in this repo",
"rejected": [],
"approved_by": null,
"approved_on": null,
"ref": "/home/worsch/coulomb-social/INTENT.md"
},
"operational_refs": [
"reef:railiance/declarations/reef.yaml"
],
"credential_handles": [],
"consumers": {
"potential": ["coulomb-social"],
"actual": ["coulomb-social"]
},
"resource_class": "self_managed_service",
"status": "active", "management_model": "shared_capacity",
"provider": {"name": "Railiance", "account_ref": null, "product_ref": "coulomb-social", "provider_resource_id": "kubernetes:coulomb-social/deployment/coulomb-social"},

View file

@ -1,9 +1,26 @@
{
"schema_version": "0.2", "record_scope": "inventory",
"schema_version": "0.3", "record_scope": "inventory",
"id": "resource:hosteurope:railiance01",
"financial_entity_id": null,
"procuring_entity_id": "entity:railiance",
"entity_gap": "no allocation driver; cost remains a Railiance residual",
"description": "Host Europe virtual server railiance01. Capacity substrate for reef-railiance. Product SKU and booked price are still unknown.",
"decision": {
"status": "gap",
"chosen": "Live discovered host; commercial product and contract not yet recorded",
"rejected": [],
"approved_by": null,
"approved_on": null,
"ref": "docs/evidence/RESOURCE-WP-0003-initial-portfolio-discovery-2026-08-11.md"
},
"operational_refs": [
"reef:railiance/declarations/reef.yaml"
],
"credential_handles": [],
"consumers": {
"potential": ["reef-railiance"],
"actual": ["reef-railiance"]
},
"resource_class": "compute_instance",
"status": "active", "management_model": "provider_managed",
"provider": {"name": "Host Europe", "account_ref": null, "product_ref": null, "provider_resource_id": null},

View file

@ -1,9 +1,26 @@
{
"schema_version": "0.2", "record_scope": "inventory",
"schema_version": "0.3", "record_scope": "inventory",
"id": "resource:railiance:forgejo",
"financial_entity_id": null,
"procuring_entity_id": "entity:railiance",
"entity_gap": "no allocation driver; cost remains a Railiance residual",
"description": "Shared Forgejo source and package forge on reef-railiance. Allocation across consuming orgs is not yet modeled.",
"decision": {
"status": "gap",
"chosen": "Live discovered platform service; forge source-of-truth decision lives in railiance-apps",
"rejected": [],
"approved_by": null,
"approved_on": null,
"ref": "/home/worsch/railiance-apps/docs/forge-source-of-truth-decision.md"
},
"operational_refs": [
"reef:railiance/declarations/reef.yaml"
],
"credential_handles": [],
"consumers": {
"potential": ["helix-forge", "coulomb-social", "railiance"],
"actual": ["helix-forge", "coulomb-social", "railiance"]
},
"resource_class": "shared_platform_service",
"status": "active", "management_model": "self_managed",
"provider": {"name": "Railiance", "account_ref": null, "product_ref": "forgejo-11.0.3", "provider_resource_id": "kubernetes:forgejo/deployment/forgejo-gitea"},

View file

@ -1,9 +1,39 @@
{
"schema_version": "0.2", "record_scope": "inventory",
"schema_version": "0.3", "record_scope": "inventory",
"id": "resource:railiance:reef-railiance:k3s",
"financial_entity_id": null,
"procuring_entity_id": "entity:railiance",
"entity_gap": "no allocation driver; cost remains a Railiance residual",
"description": "Single-node k3s runtime on railiance01. Cost and consumption view of reef-railiance; not a copy of IPs or kubeconfig.",
"decision": {
"status": "gap",
"chosen": "Live discovered cluster; no formal procurement decision in this repo",
"rejected": [],
"approved_by": null,
"approved_on": null,
"ref": "/home/worsch/railiance-cluster/docs/rail-kubernetes-substrate-profile.md"
},
"operational_refs": [
"reef:railiance/declarations/reef.yaml"
],
"credential_handles": [],
"consumers": {
"potential": [
"rapp-postgres",
"rapp-qonto",
"rapp-openbao",
"coulomb-social",
"helix-forge",
"railiance-platform"
],
"actual": [
"rapp-postgres",
"rapp-qonto",
"coulomb-social",
"helix-forge",
"railiance-platform"
]
},
"resource_class": "kubernetes_capacity",
"status": "active", "management_model": "self_managed",
"provider": {"name": "Railiance", "account_ref": null, "product_ref": "k3s", "provider_resource_id": "k3s://239.62.205.92.host.secureserver.net"},

View file

@ -104,7 +104,7 @@ Both `ref` and the parsed fields must agree when both are present.
## What a resource-control resource then holds
Five facets, all first-class in the forthcoming inventory v0.3:
Five facets, all first-class in inventory v0.3:
1. **Description** — purpose and class; why this resource exists.
2. **Decision** — chosen option, approver, date, rejected alternatives

View file

@ -30,7 +30,7 @@
"additionalProperties": false,
"required": ["status", "ref"],
"properties": {
"status": {"enum": ["recommended", "approved", "rejected"]},
"status": {"enum": ["recommended", "approved", "rejected", "gap"]},
"chosen": {"type": ["string", "null"]},
"rejected": {"type": "array", "items": {"type": "string"}},
"approved_by": {"type": ["string", "null"]},

View file

@ -75,9 +75,34 @@ class PortfolioTest(unittest.TestCase):
def test_v02_records_remain_valid(self):
v02 = [r for _, r in self.records() if r.get("schema_version") == "0.2"]
self.assertGreaterEqual(len(v02), 1)
self.assertTrue(all(r["record_scope"] == "example" for r in v02))
for record in v02:
validate_record(record)
def test_live_inventory_is_v03_with_consumers(self):
live = [
(path, record)
for path, record in self.records()
if record.get("record_scope") == "inventory"
]
self.assertGreaterEqual(len(live), 7)
for path, record in live:
with self.subTest(path=path):
self.assertEqual(record["schema_version"], "0.3")
for facet in (
"description",
"decision",
"operational_refs",
"credential_handles",
"consumers",
):
self.assertIn(facet, record)
consumers = record["consumers"]
self.assertIn("potential", consumers)
self.assertIn("actual", consumers)
self.assertTrue(consumers["potential"])
validate_record(record)
def test_unknown_commission_date_is_preserved(self):
record = deepcopy(next(r for _, r in self.records() if r["status"] == "active"))
record["lifecycle"]["commissioned_on"] = None

View file

@ -50,7 +50,12 @@ def main() -> int:
need |= v03
assert not need - resource.keys(), f"missing fields: {need - resource.keys()}"
validate_record(resource)
assert any(resource.get("schema_version") == "0.3" for resource in resources)
live = [resource for resource in resources if resource.get("record_scope") == "inventory"]
assert live and all(resource.get("schema_version") == "0.3" for resource in live)
assert all(
"potential" in resource.get("consumers", {}) and "actual" in resource.get("consumers", {})
for resource in live
)
operational_records = [load(str(path)) for path in Path("data/control-cycle").glob("*.json")]
control_records += operational_records
record_ids = {record["record_id"] for record in control_records}

View file

@ -4,7 +4,7 @@ type: workplan
title: "Resource object model and reef operational references"
domain: financials
repo: resource-control
status: active
status: finished
owner: grok
topic_slug: railiance
created: "2026-08-14"
@ -101,7 +101,7 @@ the repo does.
```task
id: RESOURCE-WP-0006-T03
status: todo
status: done
priority: high
state_hub_task_id: "da959cf1-cbd2-492c-95ff-b9ab78c16697"
```
@ -116,6 +116,13 @@ flows; attribute refs wait on `reef-storage`; credential handle =
Done when no live record relies on undifferentiated `workload_ids` as the
only consumer list.
Done 2026-08-15: all seven live inventory records are schema `0.3` with
the five facets. Discovered hosts and workloads use `decision.status:
gap` rather than a fake approval. Backup remains the only `approved`
decision. Consumers are first-class on every record; `workload_ids` is
no longer the only consumer list. Examples stay `0.2`. Formal
procurement write-ups for the six gap records are not this workplan.
## T04 — Wire WP-0002 to the convention
```task