From 03265b6e219bef40cf026c4003f99b8ca636ddb1 Mon Sep 17 00:00:00 2001 From: stxkxs <139715017+stxkxs@users.noreply.github.com> Date: Wed, 5 Aug 2026 16:55:25 -0700 Subject: [PATCH] fix(standards): the datastore claim asserts a path that is not wired MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `PLATFORM_TENANT_CONTRACT` stated as present-tense fact that the tenant-substrate module provisions a Platform CR's declared datastores. The module does provision them, and the operator does generate the scoped IAM — but nothing carries a Platform CR's `spec.datastores` into that module's `var.tenants` input, and that map is `{}` in development, staging and production. Verified against landing-zone main: all three live leaves declare `tenants = {}`, and no renderer exists anywhere. This is the one that matters most in this repo, because `FACTORY_PREAMBLE` puts it in front of every agent session fab runs. The factory was instructing every agent to declare datastores on the strength of a claim false in all three environments — an agent could reasonably build an app that assumes its database exists at deploy time. The instruction is unchanged and still correct: declare stores in spec.datastores, never hand-write a per-app landing-zone component. What is added is the state — declared is not provisioned yet, so do not build against one. Same correction lands in nanohype/standards/platform-tenant-contract.json, which this repo vendors, and in the three live leaves whose comment says the map is "rendered from the Platform CRs by the factory". --- src/standards.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/standards.ts b/src/standards.ts index 10f8a01..e5bc447 100644 --- a/src/standards.ts +++ b/src/standards.ts @@ -379,7 +379,7 @@ Optional, AI workloads only: ### Platform CR shape (minimum) -The Platform CR declares the tenant boundary AND its stateful substrate. The operator reconciles Namespace (with Pod Security Standards label), ResourceQuota, LimitRange, default-deny NetworkPolicy, ArgoCD AppProject, the operator-owned tenant-runtime ServiceAccount, and the per-Platform IAM role — with a datastore-access policy generated from spec.datastores and a capability-access policy generated from spec.identity.capabilities — plus the Pod Identity association binding tenant-runtime to it. The declared datastores themselves are provisioned by the generic tenant-substrate landing-zone module from that same declaration. +The Platform CR declares the tenant boundary AND its stateful substrate. The operator reconciles Namespace (with Pod Security Standards label), ResourceQuota, LimitRange, default-deny NetworkPolicy, ArgoCD AppProject, the operator-owned tenant-runtime ServiceAccount, and the per-Platform IAM role — with a datastore-access policy generated from spec.datastores and a capability-access policy generated from spec.identity.capabilities — plus the Pod Identity association binding tenant-runtime to it. The declared datastores themselves are provisioned by the generic tenant-substrate landing-zone module from that same declaration. NOT YET WIRED END TO END: nothing currently carries a Platform CR's spec.datastores into that module's var.tenants input, which is empty in development, staging and production. Declare the stores — it is correct and forward-compatible — but do not build an app that assumes its database, bucket or queue exists at deploy time. \`\`\`yaml apiVersion: platform.nanohype.dev/v1alpha1 @@ -412,7 +412,7 @@ spec: ### Datastore vocabulary -Declare stateful stores in spec.datastores; never hand-write a landing-zone component for them. Six kinds — relational (Aurora Serverless v2), keyValue (DynamoDB), objectStore (S3), queue (SQS), cache (ElastiCache), stream (MSK Serverless). Each entry carries at most the one typed config block matching its kind; omit it for the young/light defaults (keyValue requires its partitionKey; stream carries none). deletionPolicy defaults to Retain, so deleting the CR orphans the datastore intact. The tenant-substrate module provisions each store and the operator generates the scoped IAM to reach it — tenant count is unbounded because adding one is a declaration, not a new component. +Declare stateful stores in spec.datastores; never hand-write a landing-zone component for them. Six kinds — relational (Aurora Serverless v2), keyValue (DynamoDB), objectStore (S3), queue (SQS), cache (ElastiCache), stream (MSK Serverless). Each entry carries at most the one typed config block matching its kind; omit it for the young/light defaults (keyValue requires its partitionKey; stream carries none). deletionPolicy defaults to Retain, so deleting the CR orphans the datastore intact. The tenant-substrate module provisions each store and the operator generates the scoped IAM to reach it — tenant count is unbounded because adding one is a declaration, not a new component. The module and the IAM generation both exist; the step that renders a Platform CR's declaration into the module's var.tenants input does not, so no declared store is provisioned in any environment today. ### Capability vocabulary