Refine SCOPE, add INTENT, fix the GOAL invariant flex-auth rejected

GOAL.md still carried the first-draft invariant — "nothing this repo builds sits
synchronously in a decision path" — after flex-auth's review had rejected it as
a latency guarantee wearing an authority guarantee's clothes. Under that wording
zone-engine could compile enforced: false for a lane, flip warden sign from deny
to allow with no flex-auth policy change, and be literally compliant. Replaced:
identity and membership here, effect in a flex-auth policy package. Compiled-not-
queried is demoted to a consequence of that, which is what it always was.

SCOPE now records what the two reviews settled rather than what was proposed:
separate standard (canon Decision 5.6), membership declared in tenancy.yaml's
reserved zones: key, stance out of scope for controls flex-auth decides, the
fail-open axis modelled PEP-side because a PDP structurally cannot express it,
organization_posture an input rather than a declaration field, and reefs not
ours. Plus the two inherited constraints: the dead trust_zone field already
sitting where membership would go, and flex-auth's lack of a reload path.

INTENT.md states the argument, including what would falsify the repo — the
exception lifecycle not needing a runtime is called out as a legitimate outcome
that should archive this repo rather than keep it for its own sake.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-19 22:20:13 +02:00
parent 468e0d3321
commit 38a186d308
3 changed files with 236 additions and 47 deletions

18
GOAL.md
View file

@ -17,9 +17,21 @@ expires on its own.
## Invariants
- **`flex-auth` remains the only policy decision point.** Zone membership
reaches it by compilation into the registry it already consumes. Nothing this
repo builds sits synchronously in a decision path.
- **`flex-auth` remains the only policy decision point.** zone-engine is
authority over zone **identity and membership**; the **effect** of a zone on
any decision flex-auth renders is expressed in a flex-auth policy package.
The first draft of this invariant said "nothing this repo builds sits
synchronously in a decision path". flex-auth rejected that on review: it is a
*latency* guarantee, not an authority one. Compiled data that determines an
outcome is still deciding — it just decided earlier. Under the old wording
zone-engine could compile `enforced: false` for a lane, flip `warden sign`
from deny to allow with no flex-auth policy change, and be literally
compliant. Membership is ours; stance is theirs.
- **Compiled, not queried.** Membership reaches flex-auth by compilation into
the registry it already loads. This is a *consequence* of the invariant
above, not the invariant itself — flex-auth is `service_class:
latency-critical` and loads its registry once at process start.
- **A zone that can be quietly widened is not a boundary.** Every change of
stance is observable, and every exception has an enforced expiry.
- **Accuracy, not altitude** (`tenancy-posture_v0.1` §6). A repo declaring a

127
INTENT.md Normal file
View file

@ -0,0 +1,127 @@
# INTENT
> Why `zone-engine` exists and where it is going.
> What is true today is `SCOPE.md`. Checkable gates and the retirement
> condition are `GOAL.md`. This file is the argument, not the checklist.
---
## 1. The sentence this repo exists to make sayable
> *"This control is enforced **there**, advisory **here**, and relaxed **in this
> band until Friday** — and all three of those are written down, reviewable, and
> expire on their own."*
NetKingdom cannot say that today. It can say how exposed a workload is
(environment posture), how ready it is (`M0``M3`), and what state the
organization is in (`organization_posture`). Every one of those **describes**.
None of them **decides**. So every enforcement control in the estate has been a
boolean over a whole repo.
## 2. Where that bit
ops-warden built a pre-sign authorization gate, flex-auth enforced its side, and
the gate verified clean. Then it was deliberately not switched on.
`policy.enabled` is one boolean over the entire repo. With `fail_closed: true`
it makes flex-auth a hard dependency of *every* `warden sign` — including the
SSH certificates the ops-bridge tunnels depend on, one of which carries the
policy call itself. Turning it on would have been correct for a settled
production lane and wrong for an estate in the middle of decommissioning one
host and moving a service off it.
That is not a story about a flag. **Security that stops the work stops being
security and becomes an outage with good intentions** — and the reason it would
have was structural: there was nowhere to say *where* it applies. The decision
is ops-warden's `ADR-0006`; this repo is what it defers to.
## 3. What a zone has to be, to be worth having
A classification that changes nothing is a label. A zone earns its keep only if
it decides something, so the model must carry:
- **Membership** — what puts a lane, actor or workload in a zone, derived from
posture already declared rather than a fourth hand-maintained list.
- **Stance per control** — enforced, advisory, or exempt.
- **Failure mode** — what happens when the control cannot run. This is where
the bite is; `fail_closed` is what turns a dead tunnel into an outage.
- **Exceptions that expire without anyone remembering them.**
The last is the reason this is a repo rather than a document. A standing
classification needs no engine — canon plus a declaration file covers it, which
is exactly how tenancy posture works. **A relaxation with an expiry is state**,
and state wants an owner, an audit trail, and something other than good
intentions enforcing the deadline.
## 4. The line this repo must not cross
`flex-auth` is the policy decision point. It stays the only one.
zone-engine is authority over zone **identity and membership**. The **effect**
of a zone on a decision flex-auth renders belongs in a flex-auth policy package,
because flex-auth's decision envelope stamps `matched_policy_version` and
`policy_package` — and registry content appears nowhere in that provenance. Put
stance in the registry and two decisions with the same policy version and the
same request can differ, with nothing in the audit trail explaining why.
That boundary was drawn by flex-auth on review, against a first draft of ours
that got it wrong in an instructive way: the original invariant forbade sitting
*synchronously* in a decision path, which is a latency guarantee wearing an
authority guarantee's clothes. Compiled data that determines an outcome is still
deciding; it just decided earlier.
**Held to, in one line: membership is ours, stance is theirs, and the decision
point is neither.**
## 5. What success looks like from outside
Someone who has never read this repo should be able to:
- open a service's `tenancy.yaml`, read its `zones:` key, and know which
controls bite it;
- ask "why was this relaxed?" and get a justification, an author and an expiry,
not a shrug;
- watch a relaxation lapse **without a human remembering it**;
- and find the rule published in NetKingdom canon rather than in this repo's
prose.
If a reader has to come here to understand their own posture, the model has
failed at being a standard and has succeeded only at being a service.
## 6. What would make this repo wrong
Stated up front, because a repo created on a recommendation should say what
would falsify it:
- **The exception lifecycle turns out not to need a runtime.** If reviewed
declarations in git, with expiry evaluated at decision time, are sufficient,
then the honest outcome is a canon standard and no engine — and this repo
should be archived rather than kept for the sake of existing. `GOAL.md` gate 5
and `ZONE-WP-0001-T04` both hold that door open deliberately.
- **The zones do not partition the real estate.** If the model needs a residue
of special cases to cover today's 27 routing lanes and actor inventory, it is
describing an aspiration, not a structure.
- **Nobody but the author declares one.** Two repos declaring and a third
reading is the minimum evidence of a model rather than a preference.
- **It becomes a second decision point.** The failure would not announce itself;
it would arrive as a small convenience — a stance compiled into membership
"just for now".
## 7. What this repo deliberately will not become
Not a PDP. Not network segmentation — "zone" is overloaded and the routing sense
is someone else's word. Not a placement model: reefs answer *where a thing runs*
and are `repo-manager`'s, and the fact that `reef-railiance` caps availability
for everything bound to it is a canon composition problem (`NK-WP-0027`), not
ours. Not an owner of anyone's controls — the controls stay with the repos that
enforce them; this model only says where they bite.
## 8. Direction
Model first, from the real estate. Canon standard drafted here and published by
`net-kingdom`, in the family of `tenancy-posture_v0.1`. Membership declared in
the `zones:` key that canon has already reserved. Two consumers before it is
called adopted, the first being ops-warden retiring `policy.enabled`.
A runtime only if `ZONE-WP-0001-T04` proves the exception lifecycle needs one —
and the cheaper answer is a legitimate result, not a disappointment.

138
SCOPE.md
View file

@ -1,15 +1,16 @@
# SCOPE
> What this repository is about, when it is relevant, and when it is not.
> Direction lives in `GOAL.md`.
> The argument for its existence is `INTENT.md`; the checkable gates and the
> retirement condition are `GOAL.md`.
---
## One-liner
Authority for security zones — the bands of enforcement rigidity that scope
*where* a control is enforced, and the lifecycle of time-boxed exceptions that
relax them during deep refactors without leaving a permanent hole.
*where* a control bites, and the lifecycle of time-boxed exceptions that relax
them during deep refactors without leaving a permanent hole.
---
@ -22,80 +23,129 @@ dependency of every `warden sign` — including the SSH certificates the
ops-bridge tunnels depend on, one of which carries the policy call itself.
Across an estate under continuous deep refactor, uniform enforcement hardens
exactly the access needed to perform the refactor. That is not security; it is
an outage with good intentions. The flip was deferred under ops-warden's
`ADR-0006`*enforcement is zone-scoped, never a global flag* — and this repo
is what that ADR defers to.
exactly the access needed to perform the refactor. The flip was deferred under
ops-warden's `ADR-0006`*enforcement is zone-scoped, never a global flag*
and this repo is what that ADR defers to.
---
## In scope
- **Zone identity and membership.** What zones exist, and what puts a lane,
actor, or workload in one. Derived from declared posture where possible
rather than a fourth hand-maintained list.
- **Enforcement stance per control per zone** — enforced / advisory / exempt,
and the failure mode (fail-closed or fail-open) that goes with it. The failure
mode is the part with teeth.
- **Time-boxed exception lifecycle** — a relaxation with an expiry that is
enforced by something rather than intended, plus the record of who widened
what, when, and until when.
- **The declaration format** repos use to state their zones, following
`tenancy.yaml` and its rule: *accuracy, not altitude*.
- **Drafting the canon standard** for the model, offered to `net-kingdom` for
publication the way `tenant-engine` and `user-engine` have boundary contracts
in canon.
actor or workload in one — derived from posture already declared rather than
a fourth hand-maintained list.
- **Time-boxed exception lifecycle.** A relaxation with an expiry enforced by
something rather than intended, plus the record of who widened what, when,
and until when. **This is the task that decides whether this repo needs a
runtime at all.**
- **The membership declaration**, carried in each repo's `tenancy.yaml` under
the reserved top-level `zones:` key, with `tenancy-posture_v0.1` §6 carried
over verbatim: *accuracy, not altitude*.
- **Drafting the canon standard**, offered to `net-kingdom` for publication in
the family of `tenancy-posture_v0.1` and the `*-engine` boundary contracts.
- **Naming stance vocabulary**`enforced` / `advisory` / `exempt` — as
something owners express, not as something this repo evaluates.
## Out of scope
- **Authorization decisions.** `flex-auth` is the PDP and stays the only one.
A second decision point is the split-brain this repo must not create.
- **Network segmentation.** "Zone" is overloaded; this is about enforcement
rigidity, not routing or NetworkPolicy. The two must not be conflated.
- **Substrate placement.** Reefs (`reef-railiance`, `reef-storage`) answer
*where does it run*; a zone answers *how rigidly is it governed*. Correlated,
not the same axis — and per repo-manager's rule, topology is not readiness.
- **Identity, secrets, tenancy.** `key-cape`, OpenBao / `secrets-engine`,
- **Stance for controls flex-auth decides.** Settled on review: for the
pre-sign gate, stance lives in a flex-auth **policy package**, not in
compiled membership. flex-auth's decision envelope stamps
`matched_policy_version` and `policy_package`, and registry content appears
nowhere in that provenance — stance in the registry would let two decisions
with the same policy version and the same request differ, with nothing in the
audit trail explaining why. **Membership is ours; stance is theirs.**
- **The fail-open / fail-closed axis.** Also settled on review: a PDP returns
an effect. Fail-open describes what a *policy enforcement point* does when
the PDP is unreachable — no decision is rendered, so no compiled data and no
policy rule can reach it. The failure-mode axis is modelled PEP-side, by the
repo that owns the control.
- **`organization_posture`.** Ruled out of the declaration by canon: a
fleet-wide, time-varying scalar describing the estate is not a property of a
declaring service, and a per-repo copy of a global goes stale in as many
places as there are repos. It is an **input** to stance selection, read by
the model, never absorbed into it.
- **Network segmentation.** "Zone" is overloaded; the routing sense is someone
else's word.
- **Substrate placement.** Reefs are `repo-manager`'s. That
`reef-railiance` is single-node and therefore *caps availability* for
everything bound to it is a canon composition defect (`NK-WP-0027`), not a
zone problem — and zone-engine is explicitly not blocked on it.
- **Identity, secrets, tenancy**`key-cape`, OpenBao / `secrets-engine`,
`tenant-engine`.
- **Implementing any specific control.** Owners keep their own controls; this
repo says where they bite.
- **Implementing anyone's controls.** Owners keep them; this model says where
they bite.
- **Publishing canon.** `net-kingdom` owns canon; `policy-nexus` publishes.
---
## Settled by review (2026-08-19)
`ZONE-WP-0001` was reviewed by both affected owners before any modelling began.
Their answers are binding on this repo and are recorded in the workplan.
| Question | Answer | Ruled by |
| --- | --- | --- |
| A new standard, or a seventh axis of `tenancy-posture_v0.1`? | **Separate standard.** The six axes are ladders where higher is stronger and desirable; enforcement stance is not monotone — `ADR-0006` *is* the finding that the top rung is wrong for the SSH lane. And an accurately declared `exempt` as an axis would be conformant *and* exempt: a conformance rule handing out its own exemption. | net-kingdom, Decision 5.6 |
| Then where is membership declared? | **`tenancy.yaml`, reserved top-level `zones:` key.** One declaration surface, one review cadence, one validator; two standards, because they have different owners and different conformance semantics. | net-kingdom, Decision 5.6 |
| Does membership need a flex-auth schema change? | **No.** Resource `metadata` / `labels` / `attributes` are already flattened into the Rego input, so a compiler emitting a zone field is readable today. | flex-auth |
| Is "never synchronously in a decision path" the right invariant? | **No** — that is a latency guarantee, not an authority one. Replaced: identity and membership here, effect in a flex-auth policy package. | flex-auth |
| Are reefs ours to reconcile? | **No**, and the attempt surfaced a canon defect instead (`NK-WP-0027`). | net-kingdom |
### Two constraints inherited from that review
- **`trust_zone` already exists inside the PDP, and is dead.**
`ops-warden/scripts/build_flex_auth_registry.py` hardcodes
`"trust_zone": "platform"` on every ssh-cert resource; it reaches the Rego
input and **no policy rule reads it**. This repo's own warning about "zone"
being overloaded named network segmentation as the hazard; the live collision
is a dormant, plausibly-named field sitting exactly where membership would go.
The compiler must resolve it — reuse or rename, deliberately.
- **flex-auth has no reload path.** Registry and policy are loaded once at
process start from a digest-pinned image. An exception compiled as inert
registry data therefore expires only when a human redeploys — expiry by
*intention*, which is precisely what the exception lifecycle must not be. An
exception carrying `not_after`, evaluated against decision time in policy,
does expire on its own: granting costs a redeploy, lapsing is automatic.
---
## Relationship to what already exists
| Mechanism | Owner | Relationship |
| --- | --- | --- |
| `tenancy-posture_v0.1` (six axes, per-repo `tenancy.yaml`) | net-kingdom canon | **Structural model to follow** — graduated levels, declared conformance, review dates, "accuracy not altitude". Its §14 stance is *structure, not tooling*, which is why this repo starts as a model and not an API |
| Environment posture + workload maturity `M0``M3` | ops-warden (WP-0015) | Inputs a zone may derive membership from |
| `organization_posture: build` | ops-warden (WP-0029) | Candidate to fold in rather than run alongside |
| Reefs / `bound_reefs` | repo-manager | Correlated substrate axis; must be reconciled, not duplicated |
| Compiled registry snapshot | flex-auth | **How zone membership reaches the PDP.** flex-auth is latency-critical; compilation, not runtime lookup |
| `tenancy-posture_v0.1` | net-kingdom canon | Sibling standard and **carrier file**. Structural model: graduated levels, per-repo declaration with evidence and review dates, accuracy over altitude |
| Environment posture + workload maturity `M0``M3` | ops-warden (WP-0015) | Candidate membership inputs |
| `organization_posture: build` | ops-warden (WP-0029) | An **input** to stance selection. Explicitly not part of the declaration |
| Reefs / `bound_reefs` | repo-manager | Separate axis. Their interaction with availability is `NK-WP-0027`, not ours |
| Compiled registry snapshot | flex-auth | How membership reaches the PDP — no schema change needed, one name collision to resolve |
| Policy package | flex-auth | Where **stance** lives for controls flex-auth decides |
| `warden plan` verdicts + `reasons` | ops-warden (WP-0029) | Existing verdict machinery to extend, not parallel |
---
## Current state (2026-08-19)
Seeded. No model, no schema, no runtime. `ZONE-WP-0001` derives the model from
the real estate and drafts the canon standard; a runtime is earned only if the
exception lifecycle proves to need one.
Seeded and reviewed. **No model, no schema, no runtime** — deliberately: an
engine that ships a wire format before it has partitioned the real estate
defines the model by accident.
Deliberately empty of schema — an empty engine that ships a schema first ends up
defining the model by accident.
`ZONE-WP-0001` carries the work. T01 is answered by both owners; T02T07 are
open. Whether a runtime is warranted is an *output* of T04, and the "no runtime"
answer is a legitimate result that would retire this repo rather than embarrass
it (`GOAL.md` gate 5).
---
## Relevant when
- A control is about to be enabled and the question "enforced *where*?" has no
answer
- A control is about to be enabled and "enforced *where*?" has no answer
- A deep refactor needs relaxed rigidity in a band of the estate, with an expiry
- A repo needs to declare which zone its lanes sit in
- A repo is filling in the `zones:` key of its `tenancy.yaml`
## Not relevant when
- Asking whether a specific request is allowed (`flex-auth`)
- Placing a workload on a substrate (`repo-manager` reefs)
- Asking whether a specific request is allowed → `flex-auth`
- Placing a workload on a substrate → `repo-manager` reefs
- Anything about network reachability