Operator direction. The T02 analysis concluded "a zone is a property of the lane", which mistook the corpus for the subject — ops-warden's catalog is a credential surface with no workloads in it, so lane properties were the only thing available to partition. Partitioning what is available is not the same as finding what policy applies to. Three roles: the repo providing the software SUGGESTS a posture for running it; the workload and its responsible party DECLARE the scrutiny applied, and are the policy subject; the zone REQUIRES a standard for admission. A workload is not labelled with a zone, it qualifies to run in one. This is canon's existing mechanism, not a new one. Decision 8.2 already splits authority this way and joins tier minima by machine, precisely so a checkable constraint does not depend on someone remembering a signature; Decision 5.6 already ruled stance behaves as a tier minimum under it. It also dissolves the grade-versus-acceptance question raised for T03 — they are the two sides of that join. Consequence: the four bands survive as membership inputs, demoted from conclusions, and the missing lane-to-workload join is not a tidy-up. It is the model. M0-M3 already grades workloads, which is the side of the join that exists. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
225 lines
12 KiB
Markdown
225 lines
12 KiB
Markdown
# Estate partition — ZONE-WP-0001-T02
|
||
|
||
**Date:** 2026-08-19 · **Corpus:** ops-warden `registry/routing/catalog.yaml`
|
||
(27 entries), `inventory.yaml` (4 actors), `registry/policy/security-posture.yaml`
|
||
(3 env postures, 4 maturity levels).
|
||
|
||
The test set by T02: *the model must partition what exists without a residue of
|
||
unexplained exceptions, and the exceptions found are the most informative
|
||
output.* This is the raw result, before any model is fitted to it.
|
||
|
||
---
|
||
|
||
## 1. What the data actually says
|
||
|
||
Cross-tabulating the three declared fields that could plausibly drive
|
||
membership — `delegation.mode`, `risk`, `exec_capable` — fills **9 of 27
|
||
possible cells**. The estate clusters hard.
|
||
|
||
| delegation | risk | exec_capable | n | character |
|
||
| --- | --- | --- | --- | --- |
|
||
| `permanent` | ungraded | — | 1 | The one lane ops-warden decides (`ssh-cert-host-access`) |
|
||
| `native` | ungraded | — | 7 | Pure pointers: route to an owner, nothing executes |
|
||
| `native` | ungraded | `false`/`true` | 2 | Owner-fronted exec (`whynot-design-npm-publish`, `audit-core-senders`) |
|
||
| `native` | high | `false` | 1 | `database-dynamic-credentials` — owner-fronted, dangerous |
|
||
| `interim` | ungraded | `true` | 4 | **ops-warden proxying, ungraded** |
|
||
| `interim` | standard | `false` | 2 | Interim, graded, not proxyable |
|
||
| `interim` | high | `false` | 2 | Interim, dangerous, routed only |
|
||
| `interim` | high | `true` | 8 | **ops-warden proxying a high-risk credential for an absent owner** |
|
||
|
||
The three fields are **not independent**, and that is the finding. Danger
|
||
concentrates in `interim`: 10 of the 11 high-risk lanes are interim, and 8 of
|
||
those are `exec_capable`. `permanent` and `native` are almost entirely benign.
|
||
|
||
**Delegation mode is doing most of the discriminating work.** It was introduced
|
||
by WP-0030 to answer a governance question — *should ops-warden own this?* — and
|
||
it turns out to predict operational danger better than the field named `risk`.
|
||
|
||
## 2. The bands that exist
|
||
|
||
Four, derived rather than invented. Every one of the 27 lanes lands in exactly
|
||
one.
|
||
|
||
| Band | n | Defining property | What it means for a control |
|
||
| --- | --- | --- | --- |
|
||
| **Decided** | 1 | `warden_executes: true` — ops-warden is the decision point | The only place a pre-sign gate can bite at all |
|
||
| **Fronted** | 10 | `delegation.mode` is `native` — the owner has a front door | Stance is the *owner's*; ops-warden holds nothing |
|
||
| **Covered** | 12 | `interim` and `exec_capable: true` — ops-warden proxies a value it does not own | The band that actually needs rigidity, and the band a refactor most needs relaxed |
|
||
| **Signposted** | 4 | `interim`, not `exec_capable` — routed, nothing flows | Advisory at most; there is no value to leak |
|
||
|
||
The interesting boundary is **Covered vs Fronted**, and it is not a risk
|
||
judgement — it is a statement about *whether the owning component exists yet*.
|
||
That is why it moves over time and why bands must be re-derived, not assigned
|
||
once.
|
||
|
||
## 3. The existing controls already imply bands — and they disagree
|
||
|
||
Before any zone model, ops-warden's three controls each cut the estate
|
||
differently:
|
||
|
||
| Control | Lanes touched | Selector |
|
||
| --- | --- | --- |
|
||
| flex-auth pre-sign gate | **1** | `warden_executes` |
|
||
| fetch policy gate | **13** | `exec_capable` |
|
||
| agent read-boundary (`ADR-0004`) | **11** | `risk == "high"` |
|
||
| `warden plan` escalation | 27 | all |
|
||
|
||
Only **8 lanes** are in both the fetch gate and the read-boundary. The controls
|
||
were built independently and their scopes were never reconciled. A zone model
|
||
that assigns one zone per lane and expects all controls to agree with it will
|
||
misfit immediately — which answers a question T03 was going to have to ask:
|
||
**stance is per control per zone, never per zone alone.**
|
||
|
||
## 4. The residue — and it is the most valuable output
|
||
|
||
**14 of 27 lanes carry no `risk` value at all.**
|
||
|
||
This is not a modelling inconvenience. `is_high_risk` is `risk == "high"`
|
||
(`routing/models.py:123`), so an ungraded lane never triggers the agent
|
||
read-boundary. Five of the fourteen are `exec_capable: true`, meaning
|
||
`warden access --fetch` can stream a real value for them to an agent session:
|
||
`openbao-api-key`, `whynot-design-npm-publish`, `key-cape-oidc-login`,
|
||
`issue-core-ingestion-api-key`, `reuse-surface-hub-write-token`.
|
||
|
||
`ADR-0004` reads as a categorical rule. The implementation is an opt-in list,
|
||
and absence fails open.
|
||
|
||
**Routed to `risk-nexus` as `RISK-F-0003`.** It is a defect in a shipped
|
||
control, not a known gap being worked — the distinction ops-warden's own
|
||
finding-routing rule draws. Severity is risk-nexus's to set.
|
||
|
||
For this task it also means: **a zone model cannot be derived from `risk` as it
|
||
stands.** Half the corpus is unlabelled on that field, and grading it is real
|
||
judgement, not backfill.
|
||
|
||
Two further gaps, less severe but structural:
|
||
|
||
- `warden_role` and `has_rotation` are **derived at load, not declared** — they
|
||
are absent from every raw entry despite appearing in `warden route --json`. A
|
||
membership compiler must read the model, not the file.
|
||
- The posture registry (`env_postures`, `M0`–`M3`) and the catalog share **no
|
||
join key**. No lane references a workload or an environment. They are
|
||
currently disjoint vocabularies.
|
||
|
||
## 5. Answers to T02's questions
|
||
|
||
### Is a zone a property of the actor, the lane, the workload, or the moment?
|
||
|
||
> **Corrected 2026-08-19 by operator direction, after this analysis was
|
||
> written.** The answer below ("the lane") mistook the corpus for the subject.
|
||
> **Security policy is always about the actual workload.** ops-warden's catalog
|
||
> is a credential surface, not a workload inventory, so lane properties were the
|
||
> only thing available to partition — and partitioning what is available is not
|
||
> the same as finding the policy subject. The bands in §2 stand as an accurate
|
||
> description of ops-warden's credential surface and remain useful membership
|
||
> *inputs*; they are not zones. See §7.
|
||
|
||
**The lane**, on the evidence available in this corpus. Every field that discriminates —
|
||
`delegation.mode`, `exec_capable`, `risk` — is a lane property. The actor
|
||
inventory holds 4 actors mapping to a single lane and cannot carry a partition.
|
||
No lane references a workload.
|
||
|
||
With two qualifications the data forces:
|
||
|
||
- **The caller is a modifier, not the zone.** The read-boundary keys on
|
||
`WARDEN_AGENT_ID` — a property of *who is asking*, orthogonal to the lane. A
|
||
zone says what the lane requires; the caller decides which requirement
|
||
applies. Collapsing them would make one lane need two zones.
|
||
- **The moment is a different object, confirmed.** Nothing in the corpus
|
||
represents it. `delegation.blocked_on` carries a free-text claim with a
|
||
`reviewed` date and no expiry — precisely the "expiry by intention" shape
|
||
`ZONE-WP-0001-T04` must not reproduce. A time-boxed relaxation is an
|
||
**exception against a zone**, never a zone.
|
||
|
||
### Do zones compose with, or fold in, environment posture and `M0`–`M3`?
|
||
|
||
**Compose — and the composition cannot be built yet.** They are per-workload;
|
||
zones as derived here are per-lane; and there is **no join key between them in
|
||
any registry today**. Folding them in would require inventing a lane→workload
|
||
mapping that does not exist, which is fabrication under §6.
|
||
|
||
The honest sequence: zones stand alone on lane properties now, and a join is
|
||
proposed only when something actually declares it. (`organization_posture` was
|
||
already ruled out of the declaration entirely by net-kingdom — it is an input.)
|
||
|
||
### Reefs
|
||
|
||
Struck by net-kingdom. Per `tenancy-posture` Decision 8.4.1, substrate location
|
||
is never by itself evidence for a level. The unreconciled pair is reef ↔ `P`/`V`
|
||
and it is canon's, tracked as `NK-WP-0027`.
|
||
|
||
## 6. What this hands to T03 and T04
|
||
|
||
- Four bands, each lane in exactly one, derived from declared fields.
|
||
- **Stance must be per control per zone** — the existing controls demonstrably
|
||
disagree about scope.
|
||
- **`Covered` is the band the model exists for**: 12 lanes where ops-warden
|
||
proxies what it does not own, holding the highest concentration of high-risk
|
||
`exec_capable` lanes, and the band a deep refactor most needs relaxed.
|
||
- **`risk` is not usable as a membership input until the 14 ungraded lanes are
|
||
graded** (`RISK-F-0003`). `delegation.mode` is usable today and is a better
|
||
predictor.
|
||
- Membership must be computed from the loaded model, not read from raw YAML.
|
||
|
||
|
||
---
|
||
|
||
## 7. Correction — the subject is the workload, and a zone is an admission standard
|
||
|
||
Operator direction, 2026-08-19, after §1–§6 were written:
|
||
|
||
> *Security policy is always about the actual workload. The repository providing
|
||
> the software may suggest security policy for running workloads in different
|
||
> situations, but the workload — and whoever is responsible for it — defines the
|
||
> level of scrutiny. Some zones may well define standards that have to be met in
|
||
> order to run as a workload in that zone.*
|
||
|
||
This reverses the direction the analysis above assumed. It had zones as a
|
||
**classification derived from** properties. They are **bands with admission
|
||
standards**: a workload does not get labelled with a zone, it *qualifies* to run
|
||
in one.
|
||
|
||
### Three roles, not one
|
||
|
||
| Role | Who | Authority |
|
||
| --- | --- | --- |
|
||
| **Suggests** | The repository providing the software | Recommends a posture for running its software in given situations. A recommendation, never a determination — it does not know where its software will run |
|
||
| **Declares** | The workload and its responsible party | Sets the level of scrutiny actually applied. **This is the policy subject.** |
|
||
| **Requires** | The zone | Defines the standard a workload must meet to be admitted. A floor, not a label |
|
||
|
||
### This is canon's existing mechanism, not a new one
|
||
|
||
`tenancy-posture_v0.1` **Decision 8.2 — split authority, machine-reconciled**
|
||
already partitions authority this way: the package repo owns substrate numbers
|
||
and enforcement, *"the consuming repo owns its workload requirements"*, and a
|
||
tier minimum is owned separately and **joined by machine** at definition and
|
||
whenever either side changes — because *"a machine-checkable constraint must not
|
||
depend on somebody remembering to collect a signature."*
|
||
|
||
And Decision 5.6, ruling on this very standard, already said stance *"behaves
|
||
like a tier minimum under Decision 8.2 — asserted elsewhere, joined by machine."*
|
||
|
||
So the zone model does not need a new prescription mechanism. It needs to **be**
|
||
a tier minimum: the zone asserts a floor, the workload asserts its posture, and
|
||
the join is mechanical. That also resolves the grade-versus-acceptance split
|
||
raised for T03 — they are simply the two sides of the join.
|
||
|
||
### What this does to the bands in §2
|
||
|
||
They survive as *inputs*, demoted from conclusions. `Decided` / `Fronted` /
|
||
`Covered` / `Signposted` accurately describe ops-warden's credential surface and
|
||
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.
|
||
|
||
### Build stage
|
||
|
||
The organization is in `build`. The default stance is therefore permissive, and
|
||
that is a positional fact rather than a concession: `ADR-0006` deferred a global
|
||
gate for exactly this reason. Zones tighten by **admission to a zone**, not by
|
||
raising a global floor — which is what makes the model compatible with deep
|
||
refactoring instead of hostile to it.
|