tenant-engine named the relation in TEN-DEC-2026-002: `tenant` is the target tenant record and always equals `resource.id`; the write API is cross-tenant by design and `tenant.guardrail.read` does not differ. v2 carried no tenant rule and a constant fixture tenant, so the deliberate scope and an omitted rule were indistinguishable. tenant-engine.write-api.mutate v3 (FLEX-DEC-2026-016): - allowed requires tenant_is_target; a mismatch or absent tenant is denied tenant_not_target (object.get, so an absent key names the right cause). - the cross-tenant scope is stated in the package and quantified by test_tenant_never_changes_effect over every action, three subjects and four tenants, with guards against passing by denying everything. - fixtures rotate tenant across four tenants; five cross-tenant allows and two tenant_not_target denies added (42 fixtures, 33 tests, all pass). - user-engine's tenant:platform exclusion is named as a fixed-record rule, not a subject/tenant relation, and tested separately. Closes FLEX-WP-0022 (T01, T02 done). Also records TEN-IN-0004 and SECRETS-IN-0002 on FLEX-WP-0020 and acknowledges the GH-DEC-2026-017 replies on FLEX-WP-0030-T04. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 63291@bnt-lap001 Assistant-Session: 8bd77868-ca68-4f49-bb1e-d539ecc0d703
398 lines
18 KiB
Markdown
398 lines
18 KiB
Markdown
---
|
||
id: FLEX-WP-0030
|
||
type: workplan
|
||
title: "The layer declaration pins a version it should not, and four security-relevant peers do not declare at all"
|
||
domain: infotech
|
||
repo: flex-auth
|
||
status: active
|
||
flavor: review
|
||
owner: claude
|
||
topic_slug: netkingdom
|
||
planning_priority: P1
|
||
planning_order: 300
|
||
related_workplans:
|
||
- FLEX-WP-0019
|
||
- FLEX-WP-0029
|
||
created: "2026-09-21"
|
||
updated: "2026-09-21"
|
||
state_hub_workstream_id: "abe60f5f-79cc-5857-b9e8-a46bed704279"
|
||
---
|
||
|
||
# FLEX-WP-0030 — Boundary declaration cleanup and estate boundaries review
|
||
|
||
`INTENT.md` declares `standard_version: "0.7"` in the frontmatter that §11
|
||
requires. That conflates two things the standard itself separates. The standard's
|
||
own frontmatter says it outright:
|
||
|
||
> `assented_by` records assent to a **BOUNDARY**, given at the version named.
|
||
> It is not assent to the current text.
|
||
|
||
A layer is a boundary. flex-auth is Engine / PDP whether the standard is at v0.6,
|
||
v0.7, v0.8 or v1.0 — the role does not change when the text is amended. Pinning a
|
||
version in the boundary declaration makes every standard revision look like it
|
||
invalidates the declaration, and generates exactly the churn seen this month:
|
||
v0.8 lands, the file still says `0.7`, and a reader cannot tell whether that is
|
||
staleness or a deliberate position.
|
||
|
||
**It is also decorative.** `internal/layer/conformance.go:40` parses
|
||
`standard_version` into `Declaration.StandardVersion` and `ValidateDeclaration`
|
||
never reads it. The field is enforced by nothing, in a file whose entire purpose
|
||
is being mechanically checkable.
|
||
|
||
## 1. Make the declaration version-agnostic
|
||
|
||
```task
|
||
id: FLEX-WP-0030-T01
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "016ab184-e814-591b-938b-24ff9ace5ede"
|
||
```
|
||
|
||
Owner: `flex-auth`.
|
||
|
||
- Drop `standard_version` from the `INTENT.md` frontmatter. §11 requires a
|
||
`layer:` key; it does not require a version, and flex-auth's own validator
|
||
does not check one.
|
||
- Replace versioned prose references (`security-layer-model_v0.7.md`) with the
|
||
unversioned standard path. `INTENT.md` is declared "aspirational and stable"
|
||
in its own words; a stable file should not carry a number that moves quarterly.
|
||
- Move version-scoped conformance state out of `INTENT.md` into a conformance
|
||
record that is *supposed* to move: which version was reviewed, the conformance
|
||
state, and each declared gap with owner, blocker and review date (§11's
|
||
four-state table).
|
||
- That split also satisfies §11's derived-artifact rule, which requires a
|
||
derived artifact to name what it derives from **and the version it was derived
|
||
at**. The boundary declaration is not derived; the conformance record is, and
|
||
it is the artifact that should carry the version.
|
||
- Keep `internal/layer` green, and decide whether `StandardVersion` stays as a
|
||
tolerated-but-unused field or is removed. Do not leave a parsed field that
|
||
nothing validates without saying which it is.
|
||
|
||
Gate: `INTENT.md` names no standard version; conformance state is version-stamped
|
||
somewhere that is maintained; `go test ./internal/layer/...` passes.
|
||
|
||
2026-09-21: done. `standard_version` removed; `conformance_record` added. The
|
||
test that pinned `0.7` was **inverted rather than deleted** — `internal/layer`
|
||
now rejects a version pin in the declaration and requires `conformance_record` to
|
||
name a file that exists on disk. `StandardVersion` is kept on the struct
|
||
deliberately, documented as must-stay-empty, so a reintroduced pin fails loudly
|
||
instead of being silently ignored. Version-scoped state is in
|
||
`docs/conformance/security-layer-conformance.md`. Full suite green.
|
||
|
||
## 2. Update SCOPE.md and assess the gaps
|
||
|
||
```task
|
||
id: FLEX-WP-0030-T02
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "224cd214-7226-5286-9794-a8a6d36c25e5"
|
||
```
|
||
|
||
Owner: `flex-auth`.
|
||
|
||
`SCOPE.md`'s Current State is accurate but drifting: it says §13.1's register has
|
||
**two rows** (it has five — `FLEX-WP-0029` owns that), and it states conformance
|
||
as "conforming with one declared gap" without naming where the gap list is
|
||
maintained.
|
||
|
||
Assess and state, per gap: what it is, who owns it, what unblocks it, and when it
|
||
is next reviewed. Known candidates:
|
||
|
||
| Candidate gap | State |
|
||
| --- | --- |
|
||
| Registry-snapshot digest in decision provenance | declared, `FLEX-WP-0019`, §9.7.2 conformance prerequisite |
|
||
| Emission guarantee not declared (see T04 / B3) | **unassessed** — may be a second declared gap |
|
||
| Stance-register review stale at five rows | `FLEX-WP-0029` |
|
||
|
||
Gate: every gap in `SCOPE.md` has an owner and a route; no gap is described only
|
||
as a sentence.
|
||
|
||
2026-09-21: done. Three gaps, each with owner and route. G2 (emission guarantee)
|
||
is newly assessed and recorded as a gap rather than as conformance, because the
|
||
flattering reading has been asserted by nobody but flex-auth. Register corrected
|
||
from two rows to five. All `v0.7` references removed from `SCOPE.md`.
|
||
|
||
## 3. Publish the boundaries review
|
||
|
||
```task
|
||
id: FLEX-WP-0030-T03
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "7d45a3d6-d4a7-556a-8607-58086f74a998"
|
||
```
|
||
|
||
Owner: `flex-auth`.
|
||
|
||
Review flex-auth's boundary against every security-relevant repository it names
|
||
or is named by, and publish findings as a derived artifact marked with the
|
||
version it was derived at. Five findings are already identified in T04; the
|
||
review is the durable form of them.
|
||
|
||
Cover at minimum: `gate-house` (doctrine), `key-cape` (identity claims in),
|
||
`ops-warden`, `secrets-engine`, `user-engine`, `tenant-engine`, `zone-engine`,
|
||
`approval-engine`, `audit-core`, `maturity-engine`, `kings-guard`, `ops-mason`.
|
||
|
||
Gate: the review states, for each counterpart, whether the boundary is agreed,
|
||
contested, or unstated — and does not record "unstated" as if it were "agreed".
|
||
|
||
2026-09-21: published at `docs/conformance/boundaries-review.md`, marked derived
|
||
and version-stamped. Twelve counterparts. Seven agreed, one agreed-in-substance
|
||
but undeclared (`gate-house`), one asserted from one side only (`key-cape`), one
|
||
held unilaterally and unconfirmed (`zone-engine`), two unclear (`tenant-engine`
|
||
on `CheckRequest.tenant`, `audit-core` on evidence source), one undeclared twice
|
||
over (`ops-mason`).
|
||
|
||
## 4. Raise the conflicting and unclear boundaries for resolution
|
||
|
||
```task
|
||
id: FLEX-WP-0030-T04
|
||
status: progress
|
||
priority: high
|
||
state_hub_task_id: "70786e6d-02f2-5a90-8640-247ba377d9a4"
|
||
```
|
||
|
||
Owner: `flex-auth` to raise; the named owner resolves each.
|
||
|
||
### B1 — nine of nine repositories disagree with themselves across the two §11 forms
|
||
|
||
**Corrected 2026-09-21.** The first version of this finding said the estate
|
||
spelled `layer:` three ways across repositories and named eight as non-conformant
|
||
on casing. That was wrong, from an ad-hoc shell survey that took the first
|
||
`^layer:` match per repository without recording which file it came from.
|
||
|
||
Re-run mechanically (`tools/survey_layer_declarations.go`, receipt at
|
||
`docs/evidence/2026-09-21-layer-declaration-survey.json`):
|
||
|
||
| Repositories carrying both §11 forms | 9 |
|
||
| --- | --- |
|
||
| Of those, forms that disagree | **9 of 9** |
|
||
| Shape | `INTENT.md`: `Engine` / `Staff`. `layer.yaml`: `engine` / `staff` |
|
||
| Only one form | `flex-auth` — no `layer.yaml`, which is why it cannot exhibit this |
|
||
|
||
The disagreement is **within** each repository, not across the estate, and it is
|
||
universal rather than careless: two generators, two conventions, no repository
|
||
mixing them. Nobody is inconsistent with anybody else.
|
||
|
||
§11 accepts *"a `layer:` key in the `INTENT.md` frontmatter, **or** an equivalent
|
||
declaration file"* and does not say which governs when both exist and disagree. A
|
||
conformance run reading `INTENT.md` and one reading `layer.yaml` reach different
|
||
answers for nine repositories, and both follow §11. That is the finding: not
|
||
casing, but an unruled precedence between two permitted forms.
|
||
|
||
Owner: `gate-house`. Two things would resolve it — which form governs, and
|
||
whether the §3 vocabulary is case-sensitive. If it is case-insensitive, the
|
||
casing half evaporates and flex-auth's validator is what changes; the precedence
|
||
half does not.
|
||
|
||
### B2 — four security-relevant repositories carry no layer declaration
|
||
|
||
`gate-house`, `key-cape`, `ops-mason`, and `net-kingdom` have no `layer:` key in
|
||
`INTENT.md` and no equivalent declaration file. §11 requires one of every
|
||
estate-authored repository in §4, and is explicit that a layer stated *about* a
|
||
repository by another repository is not a declaration.
|
||
|
||
Two matter directly to flex-auth:
|
||
|
||
- **`key-cape`** is the identity source whose verified claims flex-auth consumes
|
||
as normative input and never redefines. That boundary is load-bearing for
|
||
every decision flex-auth renders, and it is asserted only from flex-auth's
|
||
side.
|
||
- **`gate-house`** authors the obligation. A doctrine owner that has not
|
||
discharged its own §11 obligation is the standard's §9.1 defect pointed at
|
||
itself.
|
||
|
||
`ops-mason` is already marked non-conformant in §13.1 for publishing no stance
|
||
map; a missing layer declaration is the same gap one level up.
|
||
|
||
Owner: each named repository. flex-auth raises, does not grade.
|
||
|
||
### B3 — flex-auth declares no emission guarantee, and may owe one
|
||
|
||
§11 requires every repository catalogued in §4 **as a source of evidence** to
|
||
declare its emission guarantee — class, cadence, and detection surface — in its
|
||
machine-readable layer declaration, and says a source that declares none is not
|
||
conforming.
|
||
|
||
flex-auth produces the decision record, which §17 moved to flex-auth as its own
|
||
contract and calls "the one thing in the estate only `access-engine` produces".
|
||
flex-auth's frontmatter declares no emission guarantee.
|
||
|
||
The unclear boundary is whether flex-auth is a §4 *source of evidence* or merely
|
||
the producer of an artifact that `audit-core` is the source of. The answer
|
||
decides whether this is a second declared gap or nothing at all. flex-auth should
|
||
not answer it alone, and should not assume the flattering reading.
|
||
|
||
Owner: `gate-house` to rule; `audit-core` to confirm which side of the line it
|
||
holds.
|
||
|
||
### B4 — the declaration pins a version the standard says is not part of the boundary
|
||
|
||
Raised here as the general form of T01, because if flex-auth is right that a
|
||
layer declaration should not carry a standard version, the fix belongs in §11 and
|
||
not only in flex-auth's file. If §11 wants a version, it should say so and say
|
||
what it means when the standard moves.
|
||
|
||
Owner: `gate-house`.
|
||
|
||
### B5 — canon names a repository that does not resolve
|
||
|
||
v0.8 refers to the PDP as `access-engine` throughout (§4 catalog row, §13.1,
|
||
§17), while the repository, runtime, namespace, images, and API vocabulary all
|
||
remain `flex-auth` per `FLEX-DEC-2026-013`, and the rename has not landed —
|
||
`access-engine` raw returns 404, verified 2026-09-20 under `FLEX-WP-0020`.
|
||
|
||
Neither side is wrong: the rename is ruled and sequenced, and canon named the
|
||
end state. But a reader of v0.8 cannot resolve the repository it keeps naming,
|
||
and `reuse-surface` already probed the 404 independently. Worth one line in the
|
||
standard recording that the coordinate is pending rather than broken.
|
||
|
||
Owner: `gate-house` to note; `flex-auth` to ping when `FLEX-WP-0020` lands.
|
||
|
||
Gate: every finding above is sent to its named owner with what would resolve it.
|
||
An unanswered finding stays open and is not closed by silence.
|
||
|
||
2026-09-21: eleven messages sent. `gate-house` (all five findings), `key-cape`
|
||
(B2, one-sided identity boundary), `audit-core` (B3, evidence source),
|
||
`ops-mason` (B2), `net-kingdom` (B5 plus the vendored-vs-authored question),
|
||
`zone-engine` (membership/stance confirmation), `tenant-engine` (the live unclear
|
||
boundary, restated with its standing), and B1 as a heads-up to the five affected
|
||
engine repos — sent as an estate property, not as a finding against any of them,
|
||
since no repository could have discovered it from inside its own checker.
|
||
|
||
Task stays `progress`: every finding is open until its owner answers. None is
|
||
closed by silence.
|
||
|
||
2026-09-21 (later): **B1 was sent wrong and corrected the same day.** See T05.
|
||
Corrections went to `gate-house` and the five engine repositories that received
|
||
the original, plus `ops-warden`, `kings-guard` and `audit-core`, who are affected
|
||
by the corrected finding and had not been told of the first.
|
||
|
||
2026-09-21 (rulings): gate-house ruled B1, B3 and B4 (`GH-DEC-2026-017`,
|
||
`-018`, `-019`; amendments A9–A13). B1: `INTENT.md` governs, case folds. B3:
|
||
**against flex-auth** — a source of evidence, non-conforming on §11 today, and
|
||
`audit-core` confirmed independently (`AUDIT-IN-0005`). B4: ruled as asked. B5:
|
||
A13 notes it. B2: `gate-house` declared; `key-cape`, `ops-mason` and
|
||
`net-kingdom` have not answered. Task stays `progress` on B2 alone — not closed
|
||
by silence. Consequences are T06–T08.
|
||
|
||
2026-09-21 (acknowledgements): `kings-guard`'s reply to the B1 correction
|
||
(`4c328bf6`) predates `GH-DEC-2026-017`; it held its two forms rather than
|
||
guessing, recorded `KG-IN-0007`, and has since applied the ruling and closed
|
||
that intake (`kings-guard` `5120adf`, value unchanged, `standard_version`
|
||
removed). Its observation — that off-vocabulary values are a third class a
|
||
precedence ruling alone leaves untouched — is answered by the post-ruling
|
||
survey (`docs/evidence/2026-09-21-layer-declaration-survey-after-ghdec017.json`):
|
||
`off_vocab` is empty once `Taxonomy` is admitted. `approval-engine`,
|
||
`maturity-engine`, `zone-engine`, `secrets-engine` and `railiance-master` also
|
||
confirmed the ruling applied. None of these bears on B2.
|
||
|
||
## Out of scope
|
||
|
||
- Bumping flex-auth to declare v0.8. v0.8 is `status: proposed`; T01 removes the
|
||
version from the declaration entirely, which makes the question moot rather
|
||
than answering it.
|
||
- Grading any peer repository's conformance. flex-auth reports what it can
|
||
observe and names the owner; §9.3's two-owner split cuts here too.
|
||
- `FLEX-WP-0029`'s stance-register second edition. Adjacent, separately owned.
|
||
|
||
## 5. Make the survey reproducible
|
||
|
||
```task
|
||
id: FLEX-WP-0030-T05
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "a695c139-b831-55a2-b015-445742ee043c"
|
||
```
|
||
|
||
Owner: `flex-auth`.
|
||
|
||
B1 was found with a shell pipeline and published as a finding. The review it
|
||
appeared in had already argued that a mechanical check nobody can re-run is an
|
||
assertion — and §11's whole claim is mechanical checkability. Asserting B1
|
||
unmechanically was that defect committed by the repository reporting it.
|
||
|
||
`tools/survey_layer_declarations.go` reads **both** §11 forms for every
|
||
security-relevant counterpart, reports intra-repository disagreement, and writes
|
||
a JSON receipt. `internal/layer` carries four tests covering the disagreement
|
||
case, the refusal to fold case, a missing declaration, and the single-form shape
|
||
that must not be reported as disagreeing with itself.
|
||
|
||
It checks exactly one property — the `layer:` value against the §3 vocabulary as
|
||
written — and deliberately does **not** apply flex-auth's own declaration rules
|
||
(`pep_stance`, `tooling_contacts`, `conformance_record`) to any other repository.
|
||
Grading peers by the surveyor's house rules would be §11's own defect wearing a
|
||
tool for a hat.
|
||
|
||
Running it immediately falsified the finding it was built to reproduce, which is
|
||
the argument for building it.
|
||
|
||
Gate: B1 is reproducible by command, with a receipt, and the correction is
|
||
recorded rather than edited away.
|
||
|
||
2026-09-21: done. Receipt at
|
||
`docs/evidence/2026-09-21-layer-declaration-survey.json`.
|
||
|
||
## 6. Fix the validator: four tokens, case folded, scope stated
|
||
|
||
```task
|
||
id: FLEX-WP-0030-T06
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "23af18ea-93da-5bd2-9511-e4fce7475dc3"
|
||
```
|
||
|
||
Owner: `flex-auth`. Authority: `GH-DEC-2026-017` §2–§4, A9, A11.
|
||
|
||
The validator admitted `{Staff, Engine, Tooling}` — three tokens taken from §4's
|
||
catalog rows, omitting §3.1's Taxonomy. `railiance-master`'s `Taxonomy` was
|
||
conforming; the validator was the divergent artifact.
|
||
|
||
Gate: the four tokens are admitted; comparison folds ASCII case; §4's column
|
||
spelling is canonical; `INTENT.md` governs while form disagreements are still
|
||
reported; a run states its scope and reports non-catalogued declarers as
|
||
volunteers; the review records the correction rather than editing it away.
|
||
|
||
2026-09-21: done. `internal/layer` (`CanonicalLayer`, `Vocabulary`, `Scope`,
|
||
`CatalogScope`, `EstateScope`, `VolunteerDeclarations`), survey `--catalog-only`,
|
||
eight new or inverted tests. Also fixed a survey defect found on the way: peers
|
||
were decoded into flex-auth's struct, and `audit-core`'s `layer.yaml` silently
|
||
dropped out once field shapes diverged. Correction in
|
||
`docs/conformance/boundaries-review.md`; receipt re-run.
|
||
|
||
## 7. Publish the per-class emission inventory and register G2 as a dated gap
|
||
|
||
```task
|
||
id: FLEX-WP-0030-T07
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "55af504c-482d-5c1a-97e3-7034912308f5"
|
||
```
|
||
|
||
Owner: `flex-auth`. Authority: `GH-DEC-2026-018`.
|
||
|
||
Gate: G2 closes as a question with the ruling as its reason and reopens as a
|
||
gap with owner, blocker and review date; the classification is published per
|
||
event class by flex-auth, not inferred; `INTENT.md` states
|
||
`source_of_evidence` and names the declaration; the test suite asserts both.
|
||
|
||
2026-09-21: done. `cadence.yaml` classifies five decision classes. Rare
|
||
load-bearing (`deny`, `redact`, `not_applicable`, `audit_only`): heartbeat and
|
||
reconciliation, rate monitoring forbidden. Volume load-bearing (`allow`):
|
||
expected-rate **and** reconciliation, because rate cannot see a targeted subset
|
||
removed. G2 is dated 2026-10-19; delivery is `FLEX-WP-0031`.
|
||
|
||
## 8. Rule whether resource.system follows the repository or the runtime
|
||
|
||
```task
|
||
id: FLEX-WP-0030-T08
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "cbf8531e-1aa9-5bc4-9f63-ecbbcf987083"
|
||
```
|
||
|
||
Owner: `flex-auth` as PDP. Asked by `ops-warden` (`WARDEN-IN-0003`).
|
||
|
||
2026-09-21: done. `FLEX-DEC-2026-015`: it follows the runtime. It is policy
|
||
vocabulary, retained by `FLEX-DEC-2026-013`, and both places the PDP matches on
|
||
it fail closed on an unknown value. Any future flip is PDP-first,
|
||
consumer-second, and is not a repository-rename step.
|