diff --git a/data/resources/apps-pg.json b/data/resources/apps-pg.json index 7f94f9b..f9a2eca 100644 --- a/data/resources/apps-pg.json +++ b/data/resources/apps-pg.json @@ -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", diff --git a/data/resources/binky-rapp-qonto.json b/data/resources/binky-rapp-qonto.json index 3b34b8a..cbca9b8 100644 --- a/data/resources/binky-rapp-qonto.json +++ b/data/resources/binky-rapp-qonto.json @@ -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"}, diff --git a/data/resources/coulomb-social-production.json b/data/resources/coulomb-social-production.json index 49b0271..c8fc3d6 100644 --- a/data/resources/coulomb-social-production.json +++ b/data/resources/coulomb-social-production.json @@ -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"}, diff --git a/data/resources/hosteurope-railiance01.json b/data/resources/hosteurope-railiance01.json index 5b57d9b..cfed39b 100644 --- a/data/resources/hosteurope-railiance01.json +++ b/data/resources/hosteurope-railiance01.json @@ -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}, diff --git a/data/resources/railiance-forgejo.json b/data/resources/railiance-forgejo.json index 5e28f3a..5c209d6 100644 --- a/data/resources/railiance-forgejo.json +++ b/data/resources/railiance-forgejo.json @@ -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"}, diff --git a/data/resources/reef-railiance-k3s.json b/data/resources/reef-railiance-k3s.json index 8b1ea8c..d1fe492 100644 --- a/data/resources/reef-railiance-k3s.json +++ b/data/resources/reef-railiance-k3s.json @@ -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"}, diff --git a/docs/operational-reference-convention.md b/docs/operational-reference-convention.md index c6f8017..4cba332 100644 --- a/docs/operational-reference-convention.md +++ b/docs/operational-reference-convention.md @@ -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 diff --git a/schemas/resource-inventory.schema.json b/schemas/resource-inventory.schema.json index c9a7f11..421f443 100644 --- a/schemas/resource-inventory.schema.json +++ b/schemas/resource-inventory.schema.json @@ -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"]}, diff --git a/tests/test_portfolio.py b/tests/test_portfolio.py index 877033a..5e8f94a 100644 --- a/tests/test_portfolio.py +++ b/tests/test_portfolio.py @@ -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 diff --git a/tools/validate.py b/tools/validate.py index f5e2df0..30d5330 100644 --- a/tools/validate.py +++ b/tools/validate.py @@ -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} diff --git a/workplans/RESOURCE-WP-0006-resource-object-and-reef-refs.md b/workplans/RESOURCE-WP-0006-resource-object-and-reef-refs.md index 82df55f..352f78f 100644 --- a/workplans/RESOURCE-WP-0006-resource-object-and-reef-refs.md +++ b/workplans/RESOURCE-WP-0006-resource-object-and-reef-refs.md @@ -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