Correct T02's "no join key": the workload side exists in rapp declarations

T02 concluded no registry carries a lane-to-workload join key. 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 declares workload_identity with
data_classification, criticality, readiness_state and bound_reefs for nine
workloads. ops-warden's dataclass_floor already maps synthetic/internal/
confidential/restricted to M0-M3. So workload -> classification -> minimum
maturity is a shared vocabulary spanning two repos already, and it is the
operator's maturity-derived default half-implemented by accident. criticality
is the other half and no control reads it yet.

Three real defects replace the blocking unknown: the lane-to-workload key is
only derivable by parsing path_template, whose convention is inconsistent
(rapp-qonto/keycape-client parses a bundle as a workload) and whose names
disagree with workload_identity.name; rapps declare "public" which
dataclass_floor does not map; and nine declared workloads do not cover ~17
catalog path identities.

Consequence for ownership: zone-engine does not need to build a workload
registry. It consumes rapp declarations plus dataclass_floor, and asks
ops-warden for one explicit field.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-20 07:17:04 +02:00
parent e55a3afa44
commit 26e3490c9b
2 changed files with 53 additions and 3 deletions

View file

@ -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

View file

@ -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/<domain>/<workload>/<bundle>` 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