Align INTENT and SCOPE to security layer model v0.7; plan conformance work
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

The standard was accepted at v0.7 on 2026-08-29. Four of flex-auth's review
findings are in the accepted text: 9.3's two-owner split, 6.4.2 scoped to the
decision's own binding with our canonical request digest as its mechanical test,
9.7.2 split by role, and 17 moving the decision-record schema to access-engine.

INTENT.md
- Machine-readable layer declaration in frontmatter (layer: Engine, role: PDP),
  which section 11 requires and we did not have. audit-core noted our
  declaration was legible only by following the decision trail.
- PDP failure semantics stated: our outage is consumer residue, not input
  degradation; fail-open is not expressible by a PDP at all.
- Four owned obligations added: the decision-record schema as our contract, the
  request digest as the published replay test, a lifetime on every allow, and
  visibility deadlines per input class.
- A Layer Conformance section stating the state honestly: conforming with one
  declared gap, no Tooling client, not PEP-shaped.
- Vocabulary correction: earlier text dropped "control plane" as Staff
  vocabulary. Section 8 binds it to the Engine layer, which is why kings-guard
  was asked to release it. The term is ours; we prefer "decision engine" for
  precision, not boundary.

SCOPE.md
- Layer and role in the one-liner; the four obligations In Scope; five
  boundaries established in review but never written down Out of Scope.
- Three capability blocks marked planned for workplans completed in May are now
  current; two blocks added.
- Superseded ADR-0006 citation corrected to ADR-0009, which retires the global
  flag outright rather than deferring it.

history/2026-08-29-layer-model-v0.7-alignment-review.md checks each obligation
against the code and finds six gaps. FLEX-WP-0019 closes them, with T02 before
T04 because a visibility deadline for registry-borne facts is unfalsifiable
until provenance can identify the snapshot a decision read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012sgN4GH5ZYT8pJVkCR6dcP

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014348@bnt-lap001
Assistant-Session: a993abda-65a0-4ea8-8ccd-0fcd78c92ac0
This commit is contained in:
tegwick 2026-08-29 14:43:49 +02:00
parent 5753b47ccb
commit 0e2efa8fcf
6 changed files with 492 additions and 64 deletions

View file

@ -2,9 +2,9 @@
"schema": "repo_manager.index.v1", "schema": "repo_manager.index.v1",
"slug": "flex-auth", "slug": "flex-auth",
"repo_root": "/home/worsch/flex-auth", "repo_root": "/home/worsch/flex-auth",
"head_sha": "54aae6b6b365407c102c511e30c392b459423be2", "head_sha": "5753b47ccb72f96689df9ec5eeb7be100f6817cd",
"observed_at": "2026-08-29T00:42:15.556704Z", "observed_at": "2026-08-29T08:19:42.754823Z",
"source_fingerprint": "3cadc015fd19f01f7381a51c7d7b0aa461f875bfe59253be427e9d5d8f373795", "source_fingerprint": "2d3773fc38408c64d1a9a4efc7335ed792f361cdf6464f04389615c9b443fa53",
"source_files": [ "source_files": [
".repo-classification.yaml", ".repo-classification.yaml",
"INTENT.md", "INTENT.md",
@ -1071,7 +1071,7 @@
"status": "resolved", "status": "resolved",
"title": "Review of security layer model v0.4: assent with findings, one rule contested", "title": "Review of security layer model v0.4: assent with findings, one rule contested",
"source_path": "decisions/decisions.md", "source_path": "decisions/decisions.md",
"uuid": null, "uuid": "2e96321d-c7bf-4127-9c30-f3def32e5bee",
"parent_id": null, "parent_id": null,
"extra": { "extra": {
"record": { "record": {
@ -1101,7 +1101,47 @@
"updated": "2026-08-29T00:42:13.009799Z", "updated": "2026-08-29T00:42:13.009799Z",
"rationale": "Assent to security-layer-model v0.4, with one rule contested and two capability assignments not accepted as assented. Section 9.3 conflicts with shipped assented behavior: it rules engine-unreachability fallback into the engine, where it cannot live, and collides with ops-warden ADR-0009's per-zone consumer PEP map. Section 13 names access-engine as intended owner of containment (accept as proposed owner only, pending per 9.2) and of authentication/assurance evidence (declined as stated; the identity layer and audit-core own that). Three consistency defects: frontmatter status proposed contradicts section 14 'accepted'; the adoption count reads seven of fifteen with remaining eight against sixteen estate-authored repositories and nine listed; section 14 says three repositories above a table of four. FLEX-IN-0002 answered: the approval boundary unblocks T03 design, T05 additionally needs the approval claim bound to the NewDecisionBinding request digest and a named owner and ordering for single consumption; the maturity claim route is practical as a request claim but not as registry content until the self-declared provenance digest gap closes.", "rationale": "Assent to security-layer-model v0.4, with one rule contested and two capability assignments not accepted as assented. Section 9.3 conflicts with shipped assented behavior: it rules engine-unreachability fallback into the engine, where it cannot live, and collides with ops-warden ADR-0009's per-zone consumer PEP map. Section 13 names access-engine as intended owner of containment (accept as proposed owner only, pending per 9.2) and of authentication/assurance evidence (declined as stated; the identity layer and audit-core own that). Three consistency defects: frontmatter status proposed contradicts section 14 'accepted'; the adoption count reads seven of fifteen with remaining eight against sixteen estate-authored repositories and nine listed; section 14 says three repositories above a table of four. FLEX-IN-0002 answered: the approval boundary unblocks T03 design, T05 additionally needs the approval claim bound to the NewDecisionBinding request digest and a named owner and ordering for single consumption; the maturity claim route is practical as a request claim but not as registry content until the self-declared provenance digest gap closes.",
"decided_by": "flex-auth (reviewing side)", "decided_by": "flex-auth (reviewing side)",
"decided_at": "2026-08-29T00:42:13.009799Z" "decided_at": "2026-08-29T00:42:13.009799Z",
"state_hub_decision_id": "2e96321d-c7bf-4127-9c30-f3def32e5bee"
}
}
},
{
"kind": "decision",
"id": "FLEX-DEC-2026-003",
"status": "resolved",
"title": "Review of security layer model v0.6 and companion v0.1: assent, two answers, five findings",
"source_path": "decisions/decisions.md",
"uuid": null,
"parent_id": null,
"extra": {
"record": {
"id": "FLEX-DEC-2026-003",
"kind": "decision",
"title": "Review of security layer model v0.6 and companion v0.1: assent, two answers, five findings",
"status": "resolved",
"origin": "cross-repo",
"origin_ref": "net-kingdom security-layer-model_v0.6 + companion_v0.1",
"standard": "net-kingdom/canon/standards/security-layer-model_v0.6.md",
"owner": "flex-auth",
"affects": [
"flex-auth",
"gate-house",
"net-kingdom",
"info-tech-canon",
"ops-warden",
"approval-engine"
],
"requested_dispositions": [
"assent",
"revise",
"reject"
],
"created": "2026-08-29T08:18:39.602701Z",
"updated": "2026-08-29T08:19:41.832549Z",
"rationale": "Assent to v0.6 and companion v0.1, with two answers and five findings, none blocking. Q1: section 6.4.2 is right but collides with 9.7.1's session-bound allow, needs the request digest as its mechanical replay test, and should rule explicitly on deny-caching. Q2: the visibility deadline does land on a PDP and harder than at a PEP, but must be per input class rather than one number, and it makes flex-auth's registry-provenance gap load-bearing rather than untidy. Findings: 6.4's stance-map register does not exist in section 13 and neither document says where a map is published; the companion omits it too, which is the sufficiency gap gate-house asked for; section 17 puts the decision-record schema in Taxonomy when it is the PDP's output artifact, inverting the section 2 rule flex-auth used to decline authentication evidence; sections 17-19 are H1 outside the hierarchy; section 19 grades the document it lives in and will age.",
"decided_by": "flex-auth (reviewing side)",
"decided_at": "2026-08-29T08:19:41.832549Z"
} }
} }
}, },
@ -1147,7 +1187,7 @@
"status": "closed", "status": "closed",
"title": "Review requested: security layer model v0.3 (approval-engine, maturity-engine)", "title": "Review requested: security layer model v0.3 (approval-engine, maturity-engine)",
"source_path": "intakes/intakes.md", "source_path": "intakes/intakes.md",
"uuid": null, "uuid": "01a04afa-307b-7e9e-b210-261badabcec7",
"parent_id": null, "parent_id": null,
"extra": { "extra": {
"record": { "record": {
@ -1171,7 +1211,8 @@
} }
], ],
"closed_at": "2026-08-29T00:42:14.888434Z", "closed_at": "2026-08-29T00:42:14.888434Z",
"outcome": "assented with findings \u2014 see FLEX-DEC-2026-002" "outcome": "assented with findings \u2014 see FLEX-DEC-2026-002",
"state_hub_intake_id": "01a04afa-307b-7e9e-b210-261badabcec7"
} }
} }
} }
@ -1179,17 +1220,17 @@
"events": [ "events": [
{ {
"type": "repo.command.applied", "type": "repo.command.applied",
"command": "repo.work.close_intake", "command": "repo.work.resolve_decision",
"operation": "close", "operation": "resolve",
"correlation_id": "1e832e3c-4e51-4dfd-919d-40593c18b2ab", "correlation_id": "fe430c1e-83bb-4dba-b6fc-337baa1a0059",
"kind": "intake", "kind": "decision",
"id": "FLEX-IN-0002", "id": "FLEX-DEC-2026-003",
"git_sha": "54aae6b6b365407c102c511e30c392b459423be2", "git_sha": "5753b47ccb72f96689df9ec5eeb7be100f6817cd",
"files_touched": [ "files_touched": [
"intakes/intakes.md" "decisions/decisions.md"
], ],
"source": "repo-manager", "source": "repo-manager",
"emitted_at": "2026-08-29T00:42:15.556791Z" "emitted_at": "2026-08-29T08:19:42.754925Z"
} }
] ]
} }

135
INTENT.md
View file

@ -1,45 +1,53 @@
---
# NetKingdom security layer declaration (security-layer-model_v0.7 §11).
# Machine-readable because §11 requires it: prose cannot distinguish a
# declaration from a transcribed review. Reference form: ops-warden layer.yaml.
layer: Engine
role: PDP
framework: netkingdom-security-layer-model
standard_version: "0.7"
declared_by: decisions/decisions.md FLEX-DEC-2026-001, FLEX-DEC-2026-002, FLEX-DEC-2026-003
declared_at: "2026-08-29"
pep_stance: null # not PEP-shaped: flex-auth renders decisions, it causes no protected side effect
tooling_contacts: [] # §5 binds Staff; flex-auth holds no Tooling client
---
# Flex-Auth Intent # Flex-Auth Intent
> **NetKingdom layering review — 2026-08-28.** This repository's role was reviewed > **Layer declaration.** flex-auth is **Engine / PDP** under the NetKingdom
> against the NetKingdom IT-security layer model: **Taxonomy → Tooling → Engines → > Security Layer Model (`net-kingdom/canon/standards/security-layer-model_v0.7.md`,
> Staff**, layered by determinism and by the kind of artifact each layer produces. > accepted 2026-08-29). It is **the only policy decision point in NetKingdom**
> Findings and the argument behind them: > (§6): no other repository, in any layer, renders or caches an authorization
> `gate-house/history/2026-08-28-security-layer-model-and-gate-house-recut.md`. > decision. The frontmatter above is the machine-readable form §11 requires; this
> The model is `net-kingdom/canon/standards/security-layer-model_v0.1.md` (proposed), > paragraph is the declaration in flex-auth's own voice.
> ratified by `gate-house/decisions/decisions.md` GH-DEC-2026-001.
> >
> The layer rule that binds every repository: **Staff never touches tooling > The layer rule that binds every repository: **Staff never touches Tooling
> directly. It acts only through engine APIs.** > directly. It acts only through Engine APIs.** flex-auth is one of those APIs.
> >
> **This repository is Engine — and the only policy decision point in NetKingdom.** > **What PDP means here, and what it does not.** As the estate's only PDP,
> Reframed on 2026-08-28 per `gate-house/decisions/decisions.md` GH-DEC-2026-001: > flex-auth's outage is *consumer residue*, not input degradation (§9.3): when
> "control plane" dropped as Staff vocabulary, the layer and the exclusive > flex-auth is unreachable there is no evaluator in the path, so what happens
> decision-point role stated, policy authoring separated from policy evaluation, > next is the consumer's declared stance and never flex-auth's to express.
> gate-house's authority context adopted as input claims, and the access > Fail-open is not expressible by a PDP at all. When flex-auth is reachable but
> lane/rule demarcation recorded. > cannot reach its own inputs, the fallback is flex-auth's, deterministic, and
> fails to reduced authority. The PIP engines — user, tenant, zone, approval,
> maturity — supply facts flex-auth consumes as claims; `audit-core` records;
> `secrets-engine` holds credential lifecycle downstream of a decision.
> >
> *Reframe applied. **Assent given on 2026-08-28** — `decisions/decisions.md` > flex-auth reached this position by review rather than assertion, and holds
> FLEX-DEC-2026-001, answering intake `FLEX-IN-0001`: flex-auth assents to the Engine > three records: `FLEX-DEC-2026-001` (Engine framing, the `access-engine` name,
> framing, to `access-engine` as the ruled name, and to the authoring/evaluation > the authoring/evaluation split), `FLEX-DEC-2026-002` (§9.3 contested and
> split. One item remains: the rename itself, a separate governed migration — it > upheld), and `FLEX-DEC-2026-003` (v0.6 review; §6.4.2, §9.7.2 and §17 as
> touches `FLEX-WP` prefix ownership, State Hub identifiers, ops-warden's routing > adopted in v0.7).
> tables, zone-engine's binding boundary text, and secrets-engine integrations — >
> and is not authorized by GH-DEC-2026-001. flex-auth adds two conditions on it > *One item remains open: the ruled rename to `access-engine`. It is a separate
> (FLEX-DEC-2026-001 item 2): repository identity and runtime identity rename in > governed migration — it touches `FLEX-WP` prefix ownership, State Hub
> identifiers, ops-warden's routing tables, zone-engine's boundary text, and
> secrets-engine integrations — and carries two conditions from
> `FLEX-DEC-2026-001`: repository identity and runtime identity rename in
> separate revertible steps, repository first, because the enforcing ops-warden > separate revertible steps, repository first, because the enforcing ops-warden
> pin binds tokens to the protected-system name; and `FLEX-WP` prefix ownership > pin binds tokens to the protected-system name; and `FLEX-WP` prefix ownership
> stays with the repository.* > stays with the repository.*
>
> **Known non-conformance — registry provenance.** Standard §6 holds that
> compiled data determining an outcome is still deciding, and that provenance
> must stay reconstructable from the decision. `DecisionProvenance` carries the
> evaluator, mode, policy package, policy version, and directory ETag, but no
> digest of the registry snapshot. A decision that turned on registry content
> cannot be replayed from its own provenance. flex-auth accepts this as its own
> gap rather than claiming conformance; until it is closed, outcome-determining
> content belongs in the versioned policy package, not the registry — for
> zone-engine's zone stance, for gate-house's authority ceilings, and for
> everyone else on the same terms.
> This file captures **why this repository exists**, the **direction it is > This file captures **why this repository exists**, the **direction it is
> moving toward**, and the **kind of system it is meant to become**. > moving toward**, and the **kind of system it is meant to become**.
@ -53,14 +61,24 @@ for organizations that want to grow from simple access rules into
enterprise-grade authorization without giving up clear ownership, local enterprise-grade authorization without giving up clear ownership, local
development ergonomics, or inspectable policy decisions. development ergonomics, or inspectable policy decisions.
It is an **Engine** in the NetKingdom security layer model It is an **Engine**, role **PDP**, in the NetKingdom security layer model
(`net-kingdom/canon/standards/security-layer-model_v0.1.md`): a deterministic (`net-kingdom/canon/standards/security-layer-model_v0.7.md`): a deterministic
API for a modeled concept, where the same authoritative input state yields the API for a modeled concept, where the same authoritative input state yields the
same result. It is deliberately not described as a control plane — that is same result.
Staff-layer vocabulary, and flex-auth is not Staff.
Within NetKingdom it is **the only policy decision point** (standard §6). No Within NetKingdom it is **the only policy decision point** (standard §6). No
other repository, in any layer, may render or cache an authorization decision. other repository, in any layer, may render or cache an authorization decision.
Engine typing (§3.3) makes the corollary explicit: a new engine is a PIP unless
the standard is amended, so *"we need an engine for X"* can never become *"X now
decides"*.
A note on vocabulary, corrected here. Earlier versions of this file dropped
"control plane" on the grounds that it was Staff-layer vocabulary. That reason
was wrong on the standard's own terms — §8 binds **control plane to the Engine
layer**, which is why kings-guard was asked to release it. The term is
flex-auth's to use. This file prefers **decision engine** anyway, because it
names what flex-auth does rather than where it sits, but the preference is
style, not a boundary.
It is the **authorization layer** in the path from verified identity to It is the **authorization layer** in the path from verified identity to
protected resources: protected resources:
@ -118,6 +136,19 @@ authenticated; flex-auth decides what that actor is allowed to do.
- Relationship facts and inherited access. - Relationship facts and inherited access.
- PDP adapter coordination. - PDP adapter coordination.
- Decision logging, explanations, and audit export. - Decision logging, explanations, and audit export.
- **The decision-record schema**, published as flex-auth's own contract
(§17). A decision record is the PDP's output artifact — the one thing in the
estate only flex-auth produces — so §2 keeps its schema here rather than in
Taxonomy. flex-auth argued this against its own interest and took the work on.
- **The canonical request digest** over normalized subject, action, resource,
and context. It is the mechanical test for §6.4.2: a consumer may replay a
verdict iff the digest matches and the decision's lifetime holds.
- **A stated lifetime on every allow** (§9.7.1) — a TTL, or a binding to a
session or obligation that ends. An allow with no stated end is a standing
grant.
- **A revocation visibility deadline per input class** (§9.7.2) — approval-claim
freshness, registry snapshot cadence, policy package activation, directory
ETag. A single number at a PDP is either a fiction or the worst case.
### Gate House Owns the Doctrine the Decision Serves ### Gate House Owns the Doctrine the Decision Serves
@ -237,12 +268,12 @@ adopting their models as its own:
- a local directory plus policy-evaluation engine for self-contained - a local directory plus policy-evaluation engine for self-contained
delegated setups delegated setups
Flex-auth remains the stable control plane even when the backend changes. Flex-auth remains the stable decision point even when the backend changes.
## Consumer Patterns ## Consumer Patterns
Two consumer shapes drive flex-auth, and the first one to ship deliberately Two consumer shapes drive flex-auth, and the first one to ship deliberately
is not a document pipeline — proving the control plane stays generic. is not a document pipeline — proving the decision engine stays generic.
**First shipped consumer — an action gate (ops-warden SSH signing).** A **First shipped consumer — an action gate (ops-warden SSH signing).** A
protected system asks flex-auth a single "may this actor perform this action protected system asks flex-auth a single "may this actor perform this action
@ -273,6 +304,30 @@ Together these shape flex-auth around real authorization needs — both
point-in-time action gates and result-filtering pipelines — without making the point-in-time action gates and result-filtering pipelines — without making the
policy service consumer-specific. policy service consumer-specific.
## Layer Conformance
flex-auth's conformance state under §11 is **conforming with one declared gap**.
It holds no Tooling client, so the §5 shapes do not apply to it, and it is not
PEP-shaped, so it owes no stance map under §6.4.
**The declared gap — registry-snapshot digest in decision provenance (§13).**
`DecisionProvenance` carries the evaluator, mode, policy package, policy version,
directory ETag, and decision time, but no digest of the registry snapshot that
supplied resource, subject, and relationship facts. A decision that turned on
registry content cannot be replayed from its own provenance.
v0.7 §9.7.2 promotes this from housekeeping to a **conformance prerequisite**,
on flex-auth's own argument: a stated visibility deadline for a fact carried by
a registry snapshot is unfalsifiable while provenance holds no snapshot digest,
because nobody can determine afterwards which snapshot a decision read. The
deadline and the digest are one gap seen from two sides.
Until it closes, one rule holds and flex-auth applies it to everyone equally,
including itself: **outcome-determining content belongs in the versioned policy
package, not in registry content** — for zone stance, for gate-house's authority
ceilings, for maturity levels, and for flex-auth's own facts. Registry content
carries membership and identity; the policy package carries effect.
## Non-Goals ## Non-Goals
- Flex-auth is not an identity provider. - Flex-auth is not an identity provider.

View file

@ -2,8 +2,10 @@
## One-liner ## One-liner
flex-auth is a policy-as-code authorization registry and control plane for flex-auth is a policy-as-code authorization registry and decision engine for
NetKingdom-aligned systems. NetKingdom-aligned systems. Under the NetKingdom Security Layer Model
(`security-layer-model_v0.7`, accepted 2026-08-29) it is **Engine / PDP** — the
estate's only policy decision point.
## Core Idea ## Core Idea
@ -33,6 +35,14 @@ can be coordinated behind a stable flex-auth API.
- Markitect as the first concrete protected-system consumer. - Markitect as the first concrete protected-system consumer.
- Delegated PDP and directory adapter boundaries after the standalone core is - Delegated PDP and directory adapter boundaries after the standalone core is
stable. stable.
- The **decision-record schema**, published as flex-auth's own contract
(`security-layer-model_v0.7` §17).
- The **canonical request digest** as the published replay test for consumers
(§6.4.2).
- **Decision lifetimes** on every allow, and **revocation visibility deadlines
stated per input class** (§9.7).
- **Registry-snapshot provenance**, so a decision that turned on registry
content is replayable from its own record (§6.1, §9.7.2).
## Out of Scope ## Out of Scope
@ -46,6 +56,18 @@ can be coordinated behind a stable flex-auth API.
model. model.
- Forcing a single PDP backend or directory provider. - Forcing a single PDP backend or directory provider.
- Hiding policy behavior behind opaque administrative toggles. - Hiding policy behavior behind opaque administrative toggles.
- Expressing fail-open. When flex-auth is unreachable there is no evaluator in
the path; the residue is the consumer's declared stance (§9.3).
- Owning enforcement. A PEP's obligations under §6.4 are the consumer's,
including its published stance map.
- Owning the approval object, its storage, or its lifecycle — that is
`approval-engine`'s (§9.4). flex-auth validates approvals as input claims and
never mutates them.
- Owning evidence of authentication or assurance. flex-auth consumes assurance
claims and never redefines them; it owns evidence of the decision
(`FLEX-DEC-2026-002`, recorded as declined in §13).
- Authoring security doctrine. gate-house owns invariants, authority ceilings,
operating modes, and the authority context flex-auth consumes as claims.
## Relevant When ## Relevant When
@ -105,13 +127,19 @@ ops-warden adopted a calling identity (`WARDEN-WP-0031`): anonymous `/v1/check`
is 401, a token bound to another protected system is 403. is 401, a token bound to another protected system is 403.
Production `policy.enabled` is **deliberately off, and is not coming back as a Production `policy.enabled` is **deliberately off, and is not coming back as a
boolean.** ops-warden's `ADR-0006` (2026-08-19) defers it permanently: boolean.** ops-warden's `ADR-0009` (2026-08-22, superseding `ADR-0006`) settles it:
`policy.enabled` is one repo-wide flag, and with `fail_closed: true` it makes `policy.enabled` is one repo-wide flag, and with `fail_closed: true` it makes
flex-auth a hard dependency of every `warden sign` — including the SSH 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 certificates the ops-bridge tunnels depend on, one of which carries the policy
call itself. Enforcement is being rescoped to *security zones* (`zone-engine` call itself. `ADR-0009` retires `policy.enabled` and the global `policy.fail_closed`
`ZONE-WP-0001`, consumer side `WARDEN-WP-0032`). flex-auth reviewed that model as outright and replaces them with a total per-zone stance map in the consumer PEP
the PDP on 2026-08-19 and holds one boundary: zone **membership** compiles into (`ops-warden/pep-stance.yaml`): open for `z0`-`z2` and `unknown`, closed for
`z3-critical`. That map is the reference shape for `security-layer-model_v0.7`
§6.4 obligation 3, and it is the estate's only published one — §13.1's register
has one row, which the standard records as itself the finding.
flex-auth reviewed the zone model as the PDP on 2026-08-19 and holds one
boundary: zone **membership** compiles into
the registry snapshot flex-auth already consumes (no schema change needed), while the registry snapshot flex-auth already consumes (no schema change needed), while
per-zone **stance** belongs in the versioned policy package, because registry per-zone **stance** belongs in the versioned policy package, because registry
content is absent from decision provenance. **Fail-open is not expressible by a content is absent from decision provenance. **Fail-open is not expressible by a
@ -119,6 +147,16 @@ PDP at all** and stays a consumer-side setting. The enforcing pins stay
enforcing regardless — an enforcing pin with no enforcing consumer still turns enforcing regardless — an enforcing pin with no enforcing consumer still turns
the anonymous path into a 401 rather than a decision. the anonymous path into a 401 rather than a decision.
**Layer position (2026-08-29).** The NetKingdom Security Layer Model was
accepted at v0.7. flex-auth is **Engine / PDP**, declared machine-readably in
`INTENT.md` frontmatter per §11. Four of flex-auth's review findings were adopted
into the standard: §9.3's two-owner split for degraded mode, §6.4.2 scoped to the
decision's own binding with the canonical request digest as its mechanical test
and negative caching ruled explicitly, §9.7.2 split by role, and §17 moving the
decision-record schema to flex-auth. Conformance state is **conforming with one
declared gap** — the registry-snapshot digest in decision provenance, which §9.7.2
promotes to a conformance prerequisite. `FLEX-WP-0019` carries the work.
State Hub integration is present through: State Hub integration is present through:
- `.custodian-brief.md` - `.custodian-brief.md`
@ -212,20 +250,34 @@ description: Repo intent, boundaries, research, workplan map, and State Hub agen
```capability ```capability
type: workplan type: workplan
title: Standalone policy core plan title: Standalone policy core plan
status: planned status: current
description: Workplan for schemas, local registry, policy packages, check APIs, list/explain, decision log, CLI/service skeleton, tests, and examples. description: Workplan for schemas, local registry, policy packages, check APIs, list/explain, decision log, CLI/service skeleton, tests, and examples.
``` ```
```capability ```capability
type: workplan type: workplan
title: Markitect consumer integration plan title: Markitect consumer integration plan
status: planned status: current
description: Workplan for Markitect resource namespace, manifest import, action vocabulary, check fixtures, contract tests, and integration flow. description: Workplan for Markitect resource namespace, manifest import, action vocabulary, check fixtures, contract tests, and integration flow.
``` ```
```capability ```capability
type: workplan type: workplan
title: Delegated adapter plan title: Delegated adapter plan
status: planned status: current
description: Workplan for Topaz evaluation, relationship PDP adapters, rule PDP adapters, Keycloak AuthZ path, directory resolvers, and operations docs. description: Workplan for Topaz evaluation, relationship PDP adapters, rule PDP adapters, Keycloak AuthZ path, directory resolvers, and operations docs.
``` ```
```capability
type: contract
title: Decision-record contract
status: current
description: Published decision-record schema, canonical request digest as the replay test for consumers, and decision provenance — flex-auth's own contract under security-layer-model v0.7 section 17.
```
```capability
type: orientation
title: Layer declaration
status: current
description: Machine-readable Engine/PDP declaration in INTENT.md frontmatter with conformance state and the one declared gap, per security-layer-model v0.7 section 11.
```

View file

@ -111,3 +111,4 @@
| intake | FLEX-IN-0002 | closed | — | intakes/intakes.md | | intake | FLEX-IN-0002 | closed | — | intakes/intakes.md |
| decision | FLEX-DEC-2026-001 | resolved | — | decisions/decisions.md | | decision | FLEX-DEC-2026-001 | resolved | — | decisions/decisions.md |
| decision | FLEX-DEC-2026-002 | resolved | — | decisions/decisions.md | | decision | FLEX-DEC-2026-002 | resolved | — | decisions/decisions.md |
| decision | FLEX-DEC-2026-003 | resolved | — | decisions/decisions.md |

View file

@ -0,0 +1,136 @@
---
id: flex-auth-2026-08-29-layer-model-alignment
type: history
title: "Layer model v0.7 alignment: INTENT, SCOPE, and the gap between them"
domain: infotech
repo: flex-auth
owner: flex-auth
created: "2026-08-29"
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
records: decisions/decisions.md FLEX-DEC-2026-001, FLEX-DEC-2026-002, FLEX-DEC-2026-003
workplan: workplans/FLEX-WP-0019-layer-model-conformance.md
---
# Layer model v0.7 alignment review
The NetKingdom Security Layer Model was accepted at **v0.7** on 2026-08-29.
`INTENT.md` and `SCOPE.md` were aligned to it in the same session. This document
records what changed, then asks the question the alignment exists to answer:
**where does the stated scope now outrun the implementation, and what has to be
built to close it.**
## 1. How flex-auth arrived at v0.7
flex-auth reviewed three versions and holds three records. Four of its findings
became text in the accepted standard:
| Finding | Adopted as |
| --- | --- |
| §9.3 collapsed two failures with different owners | §9.3 rewritten: input degradation is the engine's, engine-unreachability is necessarily the consumer's |
| §6.4.2 forbade the session-bound allow §9.7.1 permits | §6.4.2 scoped to the decision's own binding and lifetime, with flex-auth's canonical request digest as the mechanical test, and negative caching ruled permitted where the refusal is recorded |
| A PDP's visibility deadline is per input class, not one number | §9.7.2 split by role |
| The decision-record schema is the PDP's output, not Taxonomy's | §17 moves it to `access-engine` |
The last of those was argued **against flex-auth's own interest** — it takes work
on rather than off — and the standard says so, because that is what makes the
§2 ownership rule credible when flex-auth also uses it to decline work.
Two of flex-auth's positions were recorded rather than adopted: containment
surface ownership stays **proposed** (§13, pending under §9.2), and
authentication/assurance evidence is recorded as **declined**.
## 2. What changed in INTENT.md
1. **A machine-readable layer declaration** in frontmatter — `layer: Engine`,
`role: PDP` — which §11 requires and flex-auth did not have. `audit-core`
named this precisely: flex-auth's declaration was "legible as one only by
following its decision trail." Prose cannot distinguish a declaration from a
transcribed review.
2. **The PDP role stated with its failure semantics**: flex-auth's outage is
consumer residue, not input degradation. Fail-open is not expressible by a
PDP at all.
3. **Four obligations added to what flex-auth owns**: the decision-record
schema as its own contract, the canonical request digest as the published
replay test, a lifetime on every allow, and revocation visibility deadlines
per input class.
4. **A `Layer Conformance` section** stating the conformance state honestly:
conforming with one declared gap, no Tooling client, not PEP-shaped.
5. **A vocabulary correction.** Earlier versions dropped "control plane" as
Staff vocabulary. That reason was wrong on the standard's own terms — §8
binds control plane to the **Engine layer**, which is why kings-guard was
asked to release it. The term is flex-auth's to use. This file prefers
"decision engine" as a matter of precision, not boundary.
## 3. What changed in SCOPE.md
The one-liner now states the layer and role. In Scope gained the four v0.7
obligations. Out of Scope gained five boundaries flex-auth had established in
review but never written down: fail-open, enforcement, the approval object,
authentication evidence, and doctrine authoring. Three capability blocks were
still marked `planned` for workplans completed in May and are now `current`, and
two capability blocks were added. A superseded citation of ops-warden `ADR-0006`
was corrected to `ADR-0009`, which retires the global flag outright rather than
deferring it.
## 4. Scope versus implementation — the gap
This is the operative section. Each row is checked against the code, not
against the documents.
| # | Obligation | Standard | Implementation today | Gap |
| --- | --- | --- | --- | --- |
| G1 | Machine-readable layer declaration | §11 | `INTENT.md` frontmatter, added in this session | **closed**, needs a conformance test |
| G2 | Registry-snapshot digest in decision provenance | §6.1, §9.7.2, §13 | `DecisionProvenance` carries evaluator, mode, policy package, policy version, directory ETag, decision time — **no snapshot digest** | **open — conformance prerequisite** |
| G3 | Every allow carries an explicit lifetime | §9.7.1 | `DecisionEnvelope` has **no lifetime field**. `ActionAuthorizationValidity` has `not_before`/`expires_at`, but that is the durable approval object, not the decision | **open** |
| G4 | Revocation visibility deadline per input class | §9.7.2 | Not stated anywhere — no document, no field | **open** |
| G5 | Decision-record schema published as flex-auth's contract | §17 | `schemas/decision_envelope.schema.json` exists and describes `binding` and `provenance` via `$defs`. It carries no lifetime, no policy-package **digest** (name and version only), and no input-claim digests | **partial** |
| G6 | Canonical request digest as the §6.4.2 replay test | §6.4.2 | `NewDecisionBinding` computes it over normalized subject, action, resource, context; it is in every binding and regression-tested | **closed in code, unpublished as consumer guidance** |
| G7 | Doctrine reaches the decision as claim or versioned rule | §6.2 | Context claims and versioned policy packages both exist | **closed** |
| G8 | Approvals consumed as input claims, never mutated | §9.4 | flex-auth mutates no approval. `FLEX-WP-0017` T03/T05 wait on `approval-engine` | **closed on flex-auth's side; blocked externally** |
### Why G2 is the one that matters most
G2 and G4 are the same gap seen from two sides, and the standard now says so in
flex-auth's own words. A stated visibility deadline for a fact carried by a
registry snapshot is **unfalsifiable** while provenance holds no snapshot
digest, because nobody can determine afterwards which snapshot a decision read.
Publishing G4 without closing G2 would be publishing a number nobody can check.
G2 is also cheap. `registry.Snapshot` is already a deterministic,
JSON-serializable struct with a test asserting that determinism
(`TestStoreLoadsAndSavesDeterministicSnapshot`), and `pkg/api/canonical.go`
already carries the canonical-JSON-plus-SHA-256 pattern that
`NewDecisionBinding` uses. The work is to reuse that pattern over the snapshot
and thread the result into `DecisionProvenance`, including through the delegated
adapters, which already share the canonical binding constructor.
### Why G3 is larger than it looks
Adding a lifetime field is trivial. Deciding **what the lifetime is** is not: a
TTL, a session binding, or an obligation binding, per §9.7.1. flex-auth has no
session concept, so the honest first step is a policy-package-declared TTL with
an explicit default, and a deny for any allow that would otherwise have no
stated end. That is a policy-surface change and needs fixtures, not just a
struct field.
### A capability flex-auth claimed and cannot yet exercise
flex-auth told gate-house it is the repository positioned to notice when the
aggregate of consumer stances diverges from what the policy packages say. §13.1
now exists as the register, and it has **one row**`ops-warden`, with
`ops-mason` catalogued PEP-shaped and unpublished. The claim is sound and the
data is not there yet. This is not a flex-auth gap to close alone, but flex-auth
should be able to read the register once it is populated, and should say so
rather than let the claim sit unexercised.
## 5. What this does not change
flex-auth's boundaries are unchanged by v0.7. It still does not author doctrine,
own approvals, own enforcement, or own authentication evidence. The rename to
`access-engine` remains a separate governed migration under the two conditions
in `FLEX-DEC-2026-001`, and nothing in the alignment starts it.
## 6. Outcome
`FLEX-WP-0019` carries G1's test, G2, G3, G4, G5, and G6. G7 needs nothing.
G8 stays with `FLEX-WP-0017`, blocked on `approval-engine`.

View file

@ -0,0 +1,143 @@
---
id: FLEX-WP-0019
type: workplan
title: "Layer model v0.7 conformance: provenance, lifetimes, deadlines, and the decision contract"
domain: infotech
repo: flex-auth
status: ready
owner: codex
topic_slug: netkingdom
planning_priority: P1
planning_order: 119
created: "2026-08-29"
updated: "2026-08-29"
---
# FLEX-WP-0019 - Layer model v0.7 conformance
The NetKingdom Security Layer Model was accepted at v0.7 on 2026-08-29 and
`INTENT.md`/`SCOPE.md` were aligned to it. The alignment review
(`history/2026-08-29-layer-model-v0.7-alignment-review.md`) identified six gaps
between what flex-auth now states and what it implements. This workplan closes
them.
Two are conformance obligations rather than features: the registry-snapshot
digest (§9.7.2 promotes it from housekeeping to a prerequisite, on flex-auth's
own argument) and the per-input-class visibility deadlines that depend on it.
Ordering is load-bearing. **T02 precedes T04** — publishing a visibility
deadline for registry-borne facts before provenance can identify the snapshot
would publish a number nobody can check.
## Assert the layer declaration mechanically
```task
id: FLEX-WP-0019-T01
status: todo
priority: medium
```
`INTENT.md` frontmatter carries `layer: Engine`, `role: PDP` per §11. Add a
conformance check and test asserting the declaration parses, states a layer in
the §3 vocabulary, states a role because the layer is Engine, and that no
Tooling client exists in the tree — the Engine-side analogue of ops-warden's
`scripts/check_layer_conformance.py`, which is offered estate-wide as a
reference form.
Closes G1's remaining half. Wire it into `make test`.
## Add the registry-snapshot digest to decision provenance
```task
id: FLEX-WP-0019-T02
status: todo
priority: high
```
`DecisionProvenance` carries no digest of the registry snapshot that supplied
resource, subject, and relationship facts, so a decision that turned on registry
content cannot be replayed from its own record (§6.1). This is flex-auth's one
declared gap in §13 and a conformance prerequisite under §9.7.2.
Reuse the canonical-JSON plus SHA-256 pattern already in `pkg/api/canonical.go`
over `registry.Snapshot`, which is already deterministic and has a test asserting
it (`TestStoreLoadsAndSavesDeterministicSnapshot`). Thread the digest into
`DecisionProvenance`, through the standalone engine and through every delegated
adapter that shares the canonical constructor, and into
`schemas/decision_envelope.schema.json`. Add regression coverage that a changed
snapshot changes the digest and that two decisions over the same snapshot agree.
## Give every allow an explicit lifetime
```task
id: FLEX-WP-0019-T03
status: todo
priority: high
```
§9.7.1 requires every allow to carry an explicit lifetime — a TTL, or a binding
to a session or obligation that ends. `DecisionEnvelope` has no lifetime field;
`ActionAuthorizationValidity` has one but belongs to the durable approval object,
not the decision.
The struct field is trivial; the semantics are not. flex-auth has no session
concept, so the first honest shape is a **policy-package-declared TTL with an
explicit default**, and a deny for any allow that would otherwise have no stated
end. That is a policy-surface change: it needs package schema support, fixtures
covering declared TTL, defaulted TTL, and the no-stated-end deny, and it must
appear in the decision record and the published schema.
## State revocation visibility deadlines per input class
```task
id: FLEX-WP-0019-T04
status: todo
priority: high
```
§9.7.2 requires a PDP to state a deadline **per input class**, because a decision
is a join over sources with unrelated refresh behaviour. Enumerate the classes
flex-auth actually joins — approval-claim freshness, registry snapshot cadence,
policy package activation, directory ETag — and state a deadline for each, with
the mechanism that bounds it rather than an aspiration.
Depends on **T02**: the registry deadline is unfalsifiable until provenance can
identify the snapshot a decision read. Publish as
`docs/decision-input-freshness.md` and reference it from `INTENT.md`.
## Publish the decision-record schema as flex-auth's contract
```task
id: FLEX-WP-0019-T05
status: todo
priority: medium
```
§17 moves the decision-record schema from Taxonomy to `access-engine`, on
flex-auth's own argument that a decision record is the PDP's output artifact.
`schemas/decision_envelope.schema.json` exists and describes `binding` and
`provenance`, but carries no lifetime (T03), no snapshot digest (T02), no
policy-package **digest** — name and version only — and no input-claim digests.
Complete it, version it as a published contract rather than an internal shape,
and document it in `docs/` as the artifact consumers may rely on. Taxonomy holds
only the shared field vocabulary the claim schema references; this schema is
flex-auth's.
## Publish the request digest as the replay test
```task
id: FLEX-WP-0019-T06
status: todo
priority: medium
```
§6.4.2 makes replay permitted **iff the canonical request digest matches and the
decision's lifetime holds**, and names flex-auth's digest as the mechanical test.
The digest is computed and regression-tested but is documented nowhere a consumer
would look.
Publish what it is computed over, what normalization applies, its stability
guarantees across versions, and worked examples of a permitted retry and a
refused replay. Consumers cannot honour §6.4.2 against an undocumented digest,
and negative caching under §6.4.2 needs the same guidance.