railiance-platform e82bb289 recorded against SECRETS-WP-0006-T05 (explicit wait on T04 serving; CCR-2026-0003 is provenance only). 29cccf8a recorded against SECRETS-WP-0008-T06, including the open tenant:coulomb vs tenant:platform question for the service JWT, left for an owner session. railiance-clock's review request opened as SECRETS-IN-0003. The intelligence-radar messages are superseded by SECRETS-WP-0010-T03 (done 2026-09-16) and answered by pointer. 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
488 lines
24 KiB
Markdown
488 lines
24 KiB
Markdown
---
|
||
id: SECRETS-WP-0008
|
||
type: workplan
|
||
title: "Evolve the Lifecycle engine to the accepted security layer model"
|
||
domain: infotech
|
||
repo: secrets-engine
|
||
status: active
|
||
flavor: implementation
|
||
owner: grok
|
||
topic_slug: custodian
|
||
created: "2026-08-29"
|
||
updated: "2026-09-21"
|
||
state_hub_workstream_id: "9c9e5164-b2f5-5ea2-a557-5368d65e9fe0"
|
||
---
|
||
|
||
# SECRETS-WP-0008 - Evolve the Lifecycle engine to the accepted security layer model
|
||
|
||
## Goal
|
||
|
||
Close the gaps between the 2026-08-29 layer declaration (Engine / Lifecycle)
|
||
and the obligations the accepted NetKingdom Security Layer Model v0.7 places on
|
||
a PEP-shaped Lifecycle engine.
|
||
|
||
Source review: `history/2026-08-29-layer-model-scope-intent-review.md`.
|
||
Declaration surface already landed this session: `INTENT.md` frontmatter,
|
||
`layer.yaml`, `pep-stance.yaml`, and `tests/test_layer_conformance.py`.
|
||
|
||
This workplan does **not** restart CLI hardening owned by `SECRETS-WP-0007`.
|
||
It adds the layer-model remainder: stance binding, decision-record consumption,
|
||
`audit-core` evidence, and the two proposed engine surfaces.
|
||
|
||
## Non-goals
|
||
|
||
- Taking ops-warden's SSH access lane or becoming a credential broker.
|
||
- Rendering or caching authorization decisions.
|
||
- Observation in production or automatic containment (companion §10: both are
|
||
at zero estate-wide).
|
||
- Service mode, runtime tenancy, or a second custody backend.
|
||
- Reopening live production on State Hub status or local fixtures.
|
||
|
||
## Coordination
|
||
|
||
- `SECRETS-WP-0007-T04` owns the consumer validator and the fail-closed
|
||
production gate until a durable ActionAuthorization object is served.
|
||
- `SECRETS-WP-0007-T05` owns delivery-session self-revocation and the KeyCape
|
||
scaffold; this workplan owns the layer-model "no standing credential" bar.
|
||
- railiance-platform owns production OpenBao and the JWT role.
|
||
- `access-engine` / State Hub own serving the decision record.
|
||
- `audit-core` owns evidence custody.
|
||
- ops-warden owns the SSH Staff PEP and must assent any SSH-CA API contract.
|
||
- kings-guard owns secret-abuse posture and must assent the evidence surface.
|
||
- gate-house owns statute §13.1 inventory of PEP stance maps.
|
||
|
||
## Tasks
|
||
|
||
## Publish stance application as shipped behaviour
|
||
|
||
```task
|
||
id: SECRETS-WP-0008-T01
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "945735c6-2d3d-5f72-baf0-692e6b210889"
|
||
```
|
||
|
||
Completed 2026-08-29. `_require_lane_approval` loads `pep-stance.yaml`.
|
||
`SHIPPED_STANCE` is pinned equal to the published map. Fail-closed production
|
||
evidence records `stance_stage`, `stance_failure_mode`, and omits
|
||
`stance_decision_id` unless a decision was rendered.
|
||
|
||
`pep-stance.yaml` is published and tests pin `prod: fail_closed` to
|
||
`_require_lane_approval`. The gate is still hardcoded, and a refusal is
|
||
recorded as a `DecisionError` rather than named stance fields.
|
||
|
||
Load the published map as the source of shipped defaults. When the
|
||
unreachable-engine residue is applied, record at least stage, failure mode, and
|
||
decision id present only where a decision was rendered. Keep the three-factor
|
||
unsafe-demo exception out of the stance table. Assert map equality in
|
||
`tests/test_layer_conformance.py` the way ops-warden's stance test does.
|
||
|
||
Acceptance:
|
||
|
||
- `_require_lane_approval` (or its successor) reads `pep-stance.yaml`.
|
||
- Changing the YAML without changing the code fails the test, and the reverse.
|
||
- Fail-closed production evidence includes named stance fields, never a secret.
|
||
- Build/test remain fail-open *relative to access-engine* and still require
|
||
the existing lane-approval check; that residue stays documented as a gap
|
||
until T02.
|
||
|
||
## Consume access-engine decision records
|
||
|
||
```task
|
||
id: SECRETS-WP-0008-T02
|
||
status: wait
|
||
priority: high
|
||
state_hub_task_id: "3eb9cff8-1441-5437-9e92-a2b655c82d04"
|
||
```
|
||
|
||
Progress 2026-09-02. Gate House notice `632bdad9` (`GH-DEC-2026-003`): this
|
||
engine is the PEP for FLEX-WP-0017-T05 / OpenBao writes. The shared consume
|
||
function now lives in `src/secrets_engine/approval_consume.py` and every live
|
||
privileged production handler reaches it through `_require_lane_approval`
|
||
before `OpenBaoClient.resolve`. Conflict, unavailability, or a missing
|
||
binding fail closed with no OpenBao call. Production still also fail-closes
|
||
on the unpublished durable ActionAuthorization / consume-binding serving
|
||
path, so this task remains `wait`.
|
||
|
||
Correction 2026-09-06. See `SECRETS-WP-0007-T04` for the full note. Summary: the
|
||
consume-before-OpenBao gate was real, but the PIP claim + validate join was a
|
||
`return None` stub and `validate_action_authorization` had no production caller,
|
||
so this task's "blocked on the durable serving path" framing hid an unimplemented
|
||
local seam. The join is now implemented and tested; the remaining blocker is
|
||
genuinely external (approval-engine claim endpoint and access-engine Check, both
|
||
unreachable as of 2026-09-06).
|
||
|
||
Progress 2026-09-07. **Step 2 is no longer blocked and is proved against a real
|
||
decision.** The 2026-09-06 note above says "approval-engine claim endpoint and
|
||
access-engine Check, both unreachable"; the second half of that is now out of
|
||
date and is corrected here rather than left to read as current.
|
||
|
||
`access-engine` Check is reachable through the owner-documented access path
|
||
(loopback `kubectl port-forward` to the named pod plus a bounded `TokenRequest`
|
||
token; `docs/pdp-access-path.md`). A real CheckRequest for
|
||
`glas-claude-agent-dev-anthropic` returned `decision:0f9c98f14545c42d`, `allow`,
|
||
`catalog_lane_policy_matched`, under package `secrets-engine.catalog-lane.lifecycle`
|
||
v2 with `binding.tenant: tenant:platform`.
|
||
|
||
Two defects surfaced only because the request was real, both now fixed:
|
||
|
||
- Our CheckRequest carried no `tenant`, which v2 treats as a `wrong_tenant`
|
||
denial rather than an omission (`80eafaf`).
|
||
- `validate_decision_envelope` required byte-equality between the binding and
|
||
our unenriched request, which no real decision can satisfy because the
|
||
evaluator normalizes and enriches from its registry before hashing. Corrected
|
||
to the published consumer rule in `10baad9`.
|
||
|
||
So the acceptance line "wrong digest, expired lifetime, superseded status, or
|
||
missing record fail closed before OpenBao" is now exercised against a genuine
|
||
envelope: the unrefreshed live decision is refused on lifetime, and a restated
|
||
`resource.attributes.stage`, a foreign `subject.tenant`, or an unexpected
|
||
enrichment field are each refused.
|
||
|
||
**What remains is step 1 only.** approval-engine must serve the claim endpoint;
|
||
`APPROVAL-WP-0002-T03` is still `wait` with no deployed base URL, so
|
||
`resolve_consume_binding` returns `None` and production stays fail-closed. That
|
||
is one external dependency rather than the two this task previously named.
|
||
|
||
Also recorded, and not a blocker for this task: flex-auth's response channel is
|
||
unauthenticated (`FLEX-DEC-2026-010`). Fail-closed protects against a PDP that is
|
||
absent, not one that lies. Until `FLEX-WP-0024` ships detached signatures, the
|
||
enforced loopback address shape is what stands in for responder authenticity.
|
||
|
||
Blocked on the durable ActionAuthorization serving path owned with
|
||
`SECRETS-WP-0007-T04` / State Hub / `access-engine`.
|
||
|
||
Once that object is served, a protected side effect holds a decision record
|
||
identifying the request it was rendered for. Replay is permitted iff the
|
||
canonical request digest matches and the lifetime holds. Do not cache the
|
||
verdict. Do not treat State Hub status, a local fixture, or catalog admission
|
||
as the decision.
|
||
|
||
Acceptance:
|
||
|
||
- Every live privileged production handler passes one shared consume function.
|
||
- Wrong digest, expired lifetime, superseded status, or missing record fail
|
||
closed before OpenBao.
|
||
- Evidence carries the decision id; a fail-closed residue still records the
|
||
stance instead.
|
||
- Local fixtures cannot authorize steady-state production.
|
||
|
||
### 2026-09-09 published replay-identity contract received
|
||
|
||
Owner message `83db7e47-ba93-4d3e-ac15-2bcb2bb16a34` supplies
|
||
FLEX-DEC-2026-012, flex-auth source `0bc624b`, and updated
|
||
`docs/request-enrichment.md`, `docs/canonical-request-digest.md` and replay
|
||
examples. This supersedes the earlier "only external dependency" reading.
|
||
T02 is progress: the next work is an executable local consumer correction,
|
||
with no new owner interpretation or approval needed.
|
||
|
||
Implement `binding.submitted_request_digest` comparison against the exact
|
||
submitted CheckRequest. Stop treating enriched `request_digest` or the consumer's
|
||
chosen list of benign enrichment fields as the replay identity. Preserve policy
|
||
pin, lifetime and deny checks. Refresh the owner's replay fixtures without
|
||
changing their existing request_digest/approval_binding_digest pins.
|
||
|
||
For the approval join, carry the validated approval claim to the PDP and compare
|
||
its recorded pdp_digest to the evaluator's approval_binding_digest. Do not
|
||
recompute either side from unenriched material. Prove changed request, wrong
|
||
claim/digest, absent new binding field and registry-overridden caller attributes
|
||
are handled under the published contract before any live native lane activates.
|
||
|
||
The separate approval identity exchange is implemented in SECRETS-WP-0009-T03
|
||
and passes 350 tests plus a real KeyCape/Approval Engine component exercise.
|
||
That exercise uses a PDP double and does not prove this newer replay contract.
|
||
The current source has not yet implemented the changes in this return; live
|
||
PDP rollout/adoption evidence remains explicit too. No synthetic fixture or Hub
|
||
decision substitutes for a runtime allow and consume.
|
||
|
||
### 2026-09-09 replay consumer implementation and real component acceptance
|
||
|
||
The returned correction is implemented. The PEP now checks the exact submitted
|
||
request digest including the full carried approval, permits registry-owned
|
||
attribute replacement, joins the evaluator-origin approval digests and rechecks
|
||
claim freshness after Check. The consume CAS uses the validated evaluator's
|
||
request_digest and decision id; an observation alone is not a consume binding.
|
||
|
||
334 regression tests pass. The disposable KeyCape + actual Approval Engine +
|
||
compiled Flex Auth exercise passes 13 checks, including real dual-control denial
|
||
then claim/check/consume, registry override, changed submitted request, wrong
|
||
action, consumed claim and same/different CAS digest. Independent producer
|
||
inputs replace response-reconstructed replay fixtures; existing digest pins
|
||
remain unchanged. Receipt: docs/evidence/2026-09-09-replay-contract-exercise.json.
|
||
No OpenBao side effect, live credential read or model request occurred.
|
||
|
||
T02 is wait for the live return: deployed PDP contract adoption and the admitted
|
||
Approval Engine claim/consume path (APPROVAL-WP-0002-T03 and RPF-WP-0035-T06 /
|
||
AUDIT-WP-0009-T09). SECRETS-WP-0009-T03 owns native delivery acceptance. The old
|
||
live decision lacks submitted_request_digest and is explicitly refused; its
|
||
historical evidence was not rewritten. Local conformance does not close the
|
||
remaining live task. This supersedes earlier additive-only and claim-free
|
||
transitive correspondence descriptions above.
|
||
|
||
## Emit evidence under the §9.6 bound
|
||
|
||
```task
|
||
id: SECRETS-WP-0008-T03
|
||
status: done
|
||
priority: high
|
||
state_hub_task_id: "0b54cedf-9335-5fa0-bdcb-1efa9a9cd98d"
|
||
```
|
||
|
||
Completed 2026-08-29. `evidence-classification.yaml` is the declaration.
|
||
Load-bearing records are queued in `evidence_dir/outbox/` before JSONL.
|
||
`secrets-engine evidence heartbeat` emits a positive claim. Drain never sits
|
||
on a mutation path and an audit-core outage leaves the queue in place.
|
||
|
||
Classify each privileged action as load-bearing or attributive. Today's trail
|
||
is attributive local JSONL plus best-effort State Hub notes; completeness is
|
||
already not claimed and must stay that way until the destination is
|
||
`audit-core`.
|
||
|
||
Load-bearing classes (at least live destroy, production revoke/suspend of a
|
||
control, and dual-control provision once those are enabled) require atomic
|
||
emission via a **local** outbox and a declared cadence or heartbeat. Do not
|
||
place a synchronous `audit-core` dependency inside the state-change
|
||
transaction. Attributive classes may keep the current non-blocking trade if
|
||
that trade stays declared.
|
||
|
||
Acceptance:
|
||
|
||
- A machine-readable classification exists next to the declaration.
|
||
- No control in this repository branches on presence or absence of a local
|
||
evidence record.
|
||
- Load-bearing emission is queued locally; an `audit-core` outage does not
|
||
block a revocation.
|
||
- Documentation uses the sound claim: the archive proves records it holds were
|
||
not altered or truncated after arrival.
|
||
|
||
## Accept the SSH-CA signing engine surface
|
||
|
||
```task
|
||
id: SECRETS-WP-0008-T04
|
||
status: done
|
||
priority: medium
|
||
state_hub_task_id: "581aeee3-3d99-5034-992b-7d42e6542a19"
|
||
```
|
||
|
||
Completed 2026-08-29. Contract published at `docs/ssh-ca-signing-contract.md`.
|
||
No OpenBao SSH-CA write was added. `layer.yaml` owner_status remains proposed.
|
||
|
||
ops-warden's `ssh-ca-signing-write` gap names this engine as intended owner.
|
||
Accept the **engine API**, decline the Staff lane. Publish a contract
|
||
ops-warden can call after an `access-engine` decision: sign a short-lived
|
||
certificate for an `adm`/`agt`/`atm` actor under the caller's request, present
|
||
no additional authority, reconstruct as the caller's action.
|
||
|
||
Do not implement a replacement client until ops-warden assents the contract.
|
||
Do not unpark the standalone `warden-sign` AppRole as break-glass.
|
||
|
||
Acceptance:
|
||
|
||
- A non-secret contract document in `docs/` states request, decision binding,
|
||
lifetime, evidence, and non-responsibilities.
|
||
- ops-warden has a recorded chance to assent or contest.
|
||
- No OpenBao SSH-CA write is added to this CLI ahead of that assent.
|
||
- `layer.yaml` owner_status remains `proposed` until the surface ships.
|
||
|
||
## Accept the secret-use evidence surface
|
||
|
||
```task
|
||
id: SECRETS-WP-0008-T05
|
||
status: done
|
||
priority: medium
|
||
state_hub_task_id: "3100d28c-9494-5b21-9d5a-af583cd8aa55"
|
||
```
|
||
|
||
Completed 2026-08-29. Contract published at
|
||
`docs/secret-use-evidence-contract.md`. `layer.yaml` owner_status remains
|
||
proposed. `route`/`audit` are still not this surface.
|
||
|
||
**2026-09-02:** kings-guard assented in its own voice (message
|
||
`75ebd2cc-a166-4676-94aa-deef2791c0c9`). It will not consume the surface as
|
||
an observation input until the surface ships and publishes its cadence
|
||
declaration. No Tooling contact will be opened to fill that wait.
|
||
|
||
**2026-09-02 later:** shipped `secrets-engine secret-use snapshot`. Cadence is
|
||
the declared 1d heartbeat on the snapshot envelope. `owner_status` stays
|
||
`proposed` until kings-guard admits the snapshot as an observation input.
|
||
`route`/`audit` remain distinct operator summaries.
|
||
|
||
kings-guard's secret-abuse posture is fixture-driven because no engine exposes
|
||
lease, revocation, mount, rotation, and delivery-session metadata. `route` and
|
||
`audit` are operator summaries over local JSONL and are not that surface.
|
||
|
||
Publish a read-only engine contract of non-secret metadata, bounded by §9.6:
|
||
it cannot prove omission at source. Coordinate destination with `audit-core`.
|
||
Do not give kings-guard a vault client, and do not return values.
|
||
|
||
Acceptance:
|
||
|
||
- Contract lists fields, freshness, and the evidence bound.
|
||
- kings-guard has a recorded chance to assent or contest.
|
||
- No secret material, token, or accessor is in the surface.
|
||
- `layer.yaml` owner_status remains `proposed` until the surface ships.
|
||
|
||
## No standing engine credential
|
||
|
||
```task
|
||
id: SECRETS-WP-0008-T06
|
||
status: wait
|
||
priority: medium
|
||
state_hub_task_id: "d7bc8bdc-a0f8-5058-a640-374ef9859148"
|
||
```
|
||
|
||
Progress 2026-09-02. Named engine auth is shipped: `service-jwt`, `bootstrap`,
|
||
and `env` are exclusive providers. `--auth service-jwt` exchanges the KeyCape
|
||
service JWT and logs in through `OpenBaoClient.login_jwt` (JSON file, never
|
||
argv), then self-revokes. A JWT selection refuses `--bootstrap-token-file` and
|
||
does not read `BAO_TOKEN` on failure. `--bootstrap-token-file` is a named
|
||
break-glass provider with `auth_break_glass` evidence.
|
||
|
||
The platform-owned OpenBao JWT mount/role is still unpublished, so auto keeps
|
||
bootstrap/env and this task remains `wait`.
|
||
|
||
Inbox triage 2026-09-21. railiance-platform `29cccf8a` (2026-09-09): status,
|
||
not a contract. Their side is RPF-WP-0035-T02 (design
|
||
`docs/credential-lane-designs/secrets-engine-service-jwt.md`), still `wait`.
|
||
Designed: role/audience `secrets-engine-openbao`, subject
|
||
`service:secrets-engine`, token policy `secrets-engine-login-self`, five-minute
|
||
budget, login-only. KeyCape issuer `https://kc.coulomb.social` and its JWKS are
|
||
now confirmed live, so the remaining blocker is this registration's issued
|
||
claims, consumer readiness, an approved source and attended apply authority.
|
||
**Open question for secrets-engine, not answered in the triage session:** the
|
||
JWT design says `tenant:coulomb`, while the approval chain resolved to
|
||
`tenant:platform` (decision `5ed3fb35`) and approval-engine compares tenant by
|
||
exact string. Which tenant the OpenBao service identity carries is a design
|
||
decision for an owner session; platform will correct its design before the
|
||
role exists once told. A service login grants no lane mutation authority. Companion §7 / statute §3.4: an
|
||
agent holds no long-lived credential of its own. Authority is per task,
|
||
time-bounded, and attributable to the principal it acts for.
|
||
|
||
Bootstrap token files remain break-glass, heavily evidenced, never an implicit
|
||
fallback from service identity.
|
||
|
||
Acceptance:
|
||
|
||
- Steady-state CLI/API auth is the reviewed service identity, not
|
||
`--bootstrap-token-file`.
|
||
- Bootstrap is a named break-glass provider with distinct evidence.
|
||
- No fallback from JWT/service-auth failure into bootstrap or AppRole.
|
||
- Issued delivery sessions continue to self-revoke as in WP-0007-T05.
|
||
|
||
### 2026-09-21 GH-DEC-2026-017 — section 11 layer declaration ruled
|
||
|
||
Read from `gate-house/decisions/decisions.md`, not from message text.
|
||
`secrets-engine` is a named affected repository and carries both permitted
|
||
forms, so all four parts apply here. State Hub decision id
|
||
`82dd0fea-fabb-4940-92d5-d6e2ea9985f5`.
|
||
|
||
What the ruling settles for this repository:
|
||
|
||
1. **`INTENT.md` governs.** Our declaration is the `layer: Engine` key in
|
||
`INTENT.md` frontmatter. `layer.yaml` is a **derived artifact**: it must be
|
||
marked as derived, must name `INTENT.md` as what it derives from, and must
|
||
agree with it. Our `layer.yaml` already carries `declared_by: INTENT.md` and
|
||
a `Voice: INTENT.md (this repository's own declaration, §11)` header comment,
|
||
so we are among the repositories already treating the sidecar as derived in
|
||
substance. What is missing is the explicit derived marking the ruling now
|
||
requires as a field rather than a comment.
|
||
2. **The §3 vocabulary is case-insensitive and comparison must ASCII case-fold.**
|
||
Our `INTENT.md` says `Engine` and our `layer.yaml` says `engine`. Under §2 of
|
||
the ruling that is **conforming**, it was never a disagreement about a layer,
|
||
and **nothing here is re-spelled**. flex-auth withdrew the casing finding
|
||
itself (message `962bf395`) and its validator is the thing that changes. We
|
||
do not touch either file's spelling, and we do not "align" them.
|
||
3. **The vocabulary is closed with four tokens** — `Taxonomy`, `Tooling`,
|
||
`Engine`, `Staff`. `Engine` is in it; no action.
|
||
4. **`standard_version` comes out of the declaration.** Our `layer.yaml` carries
|
||
`standard_version: "0.7"`. A declaration asserts a standing property and must
|
||
not carry a standard version; version-scoped state belongs in the derived
|
||
conformance record, which must name what it derives from and the version or
|
||
commit it was derived at.
|
||
|
||
**Deliberately not done in this session.** The ruling states that
|
||
`standard_version` is not one repository's habit but **ops-warden's reference
|
||
form**, which this repository copied along with seven others, and that ops-warden
|
||
is asked to make the change there rather than each adopter deciding independently.
|
||
ops-warden is updating that reference form in a parallel session. Inventing our
|
||
own sidecar shape ahead of it would produce exactly the divergence the ruling
|
||
exists to close, so we record the requirement and wait for the reference form.
|
||
|
||
What `secrets-engine` will need, once the reference form lands:
|
||
|
||
- Adopt the reference form's derived-artifact marking in `layer.yaml`, keeping
|
||
`declared_by: INTENT.md` or whatever field the reference form names for it.
|
||
- Remove `standard_version: "0.7"` from `layer.yaml`.
|
||
- Move the version the conformance run was derived at into our derived
|
||
conformance record, per the reference form's field for it. Our conformance
|
||
checker is `scripts/check_layer_conformance.py`; it reads `layer.yaml` today
|
||
and will need to read `INTENT.md` as the governing form, read the sidecar as
|
||
well, and **report a disagreement between them as a finding** rather than
|
||
resolve it by precedence. A casing-only difference is not such a disagreement.
|
||
- Keep `framework:`, `layer:`, `role:` and the substantive §3/§5/§6/§9.6
|
||
content unchanged. `role:` is explicitly not ruled and stays as it is.
|
||
- The `Framework:` header comment in `layer.yaml` cites
|
||
`security-layer-model_v0.7.md` while the ruling is issued against `v0.8`.
|
||
That is a citation in a comment, not a declaration version, so it is out of
|
||
scope for part 4 — but it should be refreshed in the same commit so the two
|
||
are not confused for each other.
|
||
|
||
No task is opened here by hand. This is a note against the workplan that already
|
||
owns `layer.yaml` / `pep-stance.yaml` / INTENT frontmatter staying in one voice;
|
||
the work lands under that exit criterion when ops-warden's form is published.
|
||
|
||
### 2026-09-21 GH-DEC-2026-017 applied — reference form published, note closed
|
||
|
||
ops-warden published the reference form (commit `a70f559`,
|
||
`wiki/playbooks/netkingdom-layer-declaration.md` "Reference-form change set").
|
||
Re-read against the ruling in `gate-house/decisions/decisions.md` and
|
||
amendments A9–A13 before editing; the ruling and the playbook agree.
|
||
|
||
Applied in one commit, field and checker together:
|
||
|
||
- `layer.yaml`: `standard_version: "0.7"` removed; `derived: true` and
|
||
`derived_from: INTENT.md` added (`declared_by: INTENT.md` kept, as the note
|
||
above required). Header comment marks the file derived and drops the version
|
||
from the framework citation.
|
||
- `INTENT.md` frontmatter: never carried `standard_version`, but its
|
||
`standard:` value was a version-pinned path (`..._v0.7.md`). De-versioned to
|
||
`net-kingdom/canon/standards/security-layer-model`, as the reference instance
|
||
did, because a pinned path in the governing form is a standard version by
|
||
another name. The field is kept; only the pin is gone.
|
||
- **No layer value re-spelled.** INTENT says `Engine`, layer.yaml says
|
||
`engine`; both unchanged.
|
||
- `scripts/check_layer_conformance.py`: `standard_version` was a required key,
|
||
so removing the field alone would have exited 2 MALFORMED. It now reads
|
||
INTENT.md as the governing form, requires the derived marking, rejects a
|
||
returning `standard_version` in either form, validates both layer values
|
||
against the closed four-token vocabulary (Taxonomy included) after an ASCII
|
||
fold, and reports a post-fold disagreement between the forms as a finding.
|
||
- `tests/test_layer_conformance.py`: per-file equality on the layer spelling
|
||
replaced by fold assertions; new tests for fold agreement, a real
|
||
disagreement (finding, exit 1), the closed vocabulary (`surface` exit 2,
|
||
`Taxonomy` admitted), and a returning `standard_version` (exit 2).
|
||
Full suite: 430 passed.
|
||
|
||
`role:` untouched (not ruled). `pep-stance.yaml` untouched (a stance map, not
|
||
a declaration). `schema_version` left at `0.1` — ops-warden bumped its own, but
|
||
the ruling does not call for it.
|
||
|
||
**Still open, not ours to answer:** where the removed version lives. A12 says
|
||
the derived conformance record already MUST carry it; our checker, like
|
||
ops-warden's, is re-runnable and emits nothing durable. ops-warden asked
|
||
gate-house (message `4220413a`); we follow that answer rather than choose.
|
||
|
||
## Exit criteria
|
||
|
||
- The published PEP stance is the shipped default and stance application is
|
||
recorded by name.
|
||
- Production live side effects require an access-engine decision record, or
|
||
remain fail-closed with a recorded stance.
|
||
- Evidence classification and destination match §9.6; completeness is not
|
||
claimed.
|
||
- SSH-CA and secret-use surfaces are either contracted with the declaring
|
||
repositories or explicitly declined in this repository's own voice.
|
||
- Bootstrap is not the steady-state engine credential.
|
||
- `layer.yaml` / `pep-stance.yaml` / INTENT frontmatter stay in one voice.
|
||
- No raw secret values in Git, State Hub, chat, prompts, workplans, evidence,
|
||
or argv.
|