From e5af1ba2706cbde2175adbad3104c7f4044500c8 Mon Sep 17 00:00:00 2001 From: tegwick Date: Wed, 19 Aug 2026 23:08:53 +0200 Subject: [PATCH] ZONE-WP-0001-T02: partition the estate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four bands, derived rather than invented, each of the 27 catalog lanes in exactly one: Decided (1), Fronted (10), Covered (12), Signposted (4). The finding is that delegation.mode — introduced by ops-warden WP-0030 to answer a governance question — predicts operational danger better than the field named risk. Ten of eleven high-risk lanes are interim, eight of those exec_capable. Two results that constrain T03 and T04. The three existing controls each cut the estate differently (1, 13 and 11 lanes) with only 8 in the overlap, so stance is per control per zone and never per zone alone. And the posture registry shares no join key with the catalog, so environment posture and M0-M3 compose in principle but cannot be joined today without inventing a mapping — fabrication under §6. The residue is the most valuable output: 14 of 27 lanes carry no risk value, and is_high_risk is risk == "high", so the agent read-boundary never fires for them. Five are exec_capable. Routed to risk-nexus as RISK-F-0003. Co-Authored-By: Claude Opus 5 --- docs/estate-partition-2026-08-19.md | 153 ++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 docs/estate-partition-2026-08-19.md diff --git a/docs/estate-partition-2026-08-19.md b/docs/estate-partition-2026-08-19.md new file mode 100644 index 0000000..8892f2d --- /dev/null +++ b/docs/estate-partition-2026-08-19.md @@ -0,0 +1,153 @@ +# 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? + +**The lane**, on the evidence. 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.