diff --git a/docs/estate-partition-2026-08-19.md b/docs/estate-partition-2026-08-19.md index 684932d..d46646f 100644 --- a/docs/estate-partition-2026-08-19.md +++ b/docs/estate-partition-2026-08-19.md @@ -212,9 +212,16 @@ still predict where danger concentrates. What they cannot do is name the entity policy applies to, because ops-warden's catalog contains no workloads. The missing join found in §4 is therefore not a tidy-up. **It is the model.** -Until something declares which workload consumes which lane, there is no subject -to attach a standard to — and `M0`–`M3` already grades workloads, which is the -side of the join that exists. + +> **Corrected 2026-08-20.** "No registry carries a join key" was too strong — it +> was concluded from ops-warden's catalog alone, the one place a *workload* +> declaration would not live. `rapp-*/declarations/rapp.yaml` declares +> `workload_identity` with `data_classification` and `criticality` for nine +> workloads, and ops-warden's `dataclass_floor` already maps classification to +> `M0`–`M3`. The chain exists and spans two repos. What is genuinely missing is +> an explicit `workload:` field on catalog entries — the key is currently only +> derivable by parsing `path_template`, whose convention is inconsistent. See +> `ZONE-WP-0001-T03`. ### Build stage diff --git a/workplans/ZONE-WP-0001-security-zone-model.md b/workplans/ZONE-WP-0001-security-zone-model.md index 05f3341..0d79012 100644 --- a/workplans/ZONE-WP-0001-security-zone-model.md +++ b/workplans/ZONE-WP-0001-security-zone-model.md @@ -332,6 +332,49 @@ anything declaring which workload consumes which lane. T03 cannot produce a usable stance model until that is answered, and the honest answer may be that it belongs to whatever declares workloads — not to this repo. +**Corrected 2026-08-20 — the workload side exists, and most of the join with +it.** T02 concluded no registry carries a join key. That was too strong; it was +derived from ops-warden's catalog alone, which is the one place a workload +declaration would *not* live. + +`rapp-*/declarations/rapp.yaml` is the workload declaration surface. **Nine** +rapps declare `workload_identity` (`name`, `principal`, `service_account`, +`tenant`) together with `data_classification`, `criticality` +(`low`/`medium`/`high`/`critical`), `readiness_state`, and `bound_reefs`. + +And the chain to maturity is already complete: ops-warden's +`registry/policy/security-posture.yaml` carries `dataclass_floor`, mapping +`synthetic→M0, internal→M1, confidential→M2, restricted→M3`. So +**workload → `data_classification` → minimum maturity** is a shared vocabulary +that spans two repos today, with nobody having built it for this purpose. That +is the operator's maturity-derived default, already half-implemented. + +`criticality` is the other half — it is exactly the "critical if the context is +critical" axis, declared per workload, and untouched by any control so far. + +Three defects in the join, which are now T03's actual work rather than a +blocking unknown: + +1. **The lane→workload key is derivable but fragile.** `path_template` encodes + `platform/workloads///` for most lanes — but the + convention is inconsistent: `platform/workloads/rapp-qonto/keycape-client` + has one level fewer, so parsing yields `keycape-client` as a "workload" when + it is a bundle. And the names do not agree: that path says `rapp-qonto` while + the rapp declares `workload_identity.name: qonto`. **Recommendation: add an + explicit `workload:` field to catalog entries.** Inferring identity by + parsing a path string is precisely the implicit coupling that breaks quietly. +2. **Vocabulary mismatch.** rapps declare `public`, which `dataclass_floor` does + not map. `rapp-policy-nexus` is `public` today, so the floor cannot grade it. + One of the two vocabularies must move; canon owns `DataClassification`. +3. **Coverage is partial.** Nine workloads are declared; ops-warden's catalog + yields ~17 distinct path identities. The unmatched remainder is the + interesting set — it is where a lane exists for something that is not a + declared workload at all. + +This reopens the ownership question favourably: zone-engine does **not** need to +build a workload registry. It needs to consume `rapp` declarations and ops-warden's +`dataclass_floor`, and to ask ops-warden for one explicit field. + **Build stage is a positional fact, not a concession.** The organization is in `build`; the default stance is permissive and zones tighten by *admission*, rather than by raising a global floor. That is what makes this model compatible