ops-warden/history/2026-08-29-layer-model-v06-review.md
tegwick 94f32bd160
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Review layer model v0.6; publish the PEP stance map §6.4 requires
All three v0.4 findings were acted on — §9.1 split into pending/declared-gap and
§5's scope rule adopted as recommended and credited, and §9.6 ruled via the
load-bearing/attributive distinction with ops-warden's `# audit must not block
signing` named as the estate's live example.

Checked the favourable ruling rather than accepting it. §9.6's test is "no
control branches on its presence": the only consumer of audit.jsonl is `warden
activity`, which displays. Nothing gates on a signing record, so the lane is
genuinely attributive. AuditTrail.md now records the ruling instead of the open
question, and states that the trade must be revisited if a control ever gates on
the trail.

CONFORMANCE ACTION. §6.4 obligation 3 requires a stance map "published rather
than held in code", and requires every PEP-shaped consumer to publish one so the
maps can be inventoried — naming ADR-0009 as the reference shape. ops-warden was
not doing it: the map lived in PolicyConfig.failure_modes, a dataclass default.
Not a code comment, but not published either.

pep-stance.yaml publishes it, and the test asserts the published map EQUALS the
shipped default. A published map that may drift from the code is worse than no
map, because it invites reliance it cannot support.

Two findings sent to gate-house, in history/2026-08-29-layer-model-v06-review.md:
§6.4 obligation 1 (no side effect without a decision record) contradicts
obligation 3 and §9.3, with ops-warden's blessed fail-open stance as the
instance; and §6.4 mandates a stance-map inventory in §13 that §13 does not
implement — where ops-warden is currently the only PEP to have published one.

402 tests pass, ruff clean.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4014535@bnt-lap001
Assistant-Session: d0036016-73e8-4da1-8e47-563e3ab39a3c
2026-08-29 10:20:49 +02:00

8.4 KiB
Raw Blame History

Security Layer Model v0.6 — ops-warden's review

Date: 2026-08-29 Reviewed: security-layer-model_v0.6.md (proposed), plus v0.5 and the companion Prior positions: ADR-0010 (v0.1 assent); history/2026-08-29-layer-model-v04-review.md Outcome: no objection; one conformance action taken, two findings, one accepted SHOULD.


Disposition of ops-warden's v0.4 findings

All three were acted on, two of them exactly as recommended.

Finding Outcome
§9.1 forces a false pending onto working capability Adopted — v0.5 split it into pending and declared-gap, credited to ops-warden
§5 scope undefined for uncatalogued infrastructure Adopted — "Tooling-layer system" now means a §4 Tooling row; the State Hub case is recorded, not policed
§9.6 atomicity lands on ops-warden's signing lane Ruled — the load-bearing / attributive distinction, with ops-warden's # audit must not block signing named as the estate's live example

The §9.6 ruling deserves a note, because it went in ops-warden's favour and that is a reason to check it rather than accept it. The test is "no control branches on its presence". Verified: the only consumer of audit.jsonl is warden activity (cli.py), which displays. Nothing gates on a signing record — not the agent read-boundary, not warden plan, not the scorecard. The lane is genuinely attributive and the trade is legitimate on the standard's own terms. The two obligations that attach — declare it, never claim completeness — were already met in wiki/AuditTrail.md, now updated to record the ruling rather than the open question. If a future ops-warden control ever gates on this trail, the trade has to be revisited before that ships, and that is recorded there.

layer.yaml is named in §11 as the estate's reference declaration form, including the "record non-Tooling clients so the check is total" property. Offered again to the repositories that have yet to declare.


Conformance action taken — the stance map was not published

§6.4 obligation 3 requires a declared unreachable-engine stance that is total, per zone, with no implicit default, "published rather than held in code comments" — and §6.4 requires every PEP-shaped consumer to publish its map so the maps can be inventoried. ADR-0009 is named as the reference shape.

ops-warden was not doing this. The map lived in PolicyConfig.failure_modes, a dataclass default in src/warden/config.py. That is not a code comment, but it is not published either — it is merely written down, and a consumer of the estate had no way to read ops-warden's stance without reading ops-warden's source.

Published as pep-stance.yaml, with the property that makes publishing worth anything: tests/test_layer_conformance.py asserts the published map is equal to the shipped default. A published map that may drift from the code is worse than no map, because it invites reliance it cannot support. The file also records the obligation-2 position (verdict never cached; input claims cached under their own freshness rules) and the obligation-4 bound (§9.6 attributive).


Finding 1 — §6.4 obligation 1 contradicts obligation 3, and ops-warden is the instance

1. No side effect without a decision record. A PEP MUST NOT perform the protected action unless it holds a decision from access-engine identifying the request it was rendered for.

3. A declared unreachable-engine stance (§9.3): total, per zone... ops-warden ADR-0009 is the reference shape.

These cannot both be absolute. ops-warden's declared stance — blessed by §9.3 as "the only thing left" when there is no engine to ask — is fail_open for z0z2 and unknown. Applying it means issuing a certificate without holding a decision, which obligation 1 forbids without qualification.

So the same section names ops-warden as the reference shape for obligation 3 while obligation 1 makes ops-warden's shipped behaviour a violation. §9.3 settled the substance; §6.4 restates it in a form that takes it back.

Recommendation. Bound obligation 1 by obligation 3:

A PEP MUST NOT perform the protected action unless it holds a decision from access-engine identifying the request it was rendered for, or its declared §9.3 stance for the applicable scope permits proceeding without one and the application of that stance is recorded in place of the decision.

This is not a weakening. It is stricter than today's text in the case that matters: it makes the recorded application of the stance mandatory, rather than leaving "no decision record" as a silent state. ops-warden already does this — ca.py writes policy_zone, policy_failure_mode and policy_decision_id (present only where a decision was rendered) into both the signatures log and audit.jsonl, per ADR-0009 rule 4: a fail-open signing result is metadata, not silence.

This is the same shape as the v0.4 §9.1 finding: a rule written for the clean case, correct there, producing a false result on the adjacent case the standard has already sanctioned elsewhere.


Finding 2 — §6.4 creates a register that §13 does not implement

§6.4: "Every PEP-shaped consumer MUST publish its stance map, and those maps MUST be inventoried — in maturity-engine once it exists, in §13 until then."

§13 contains no stance-map rows. It records declared contacts and unowned capabilities; there is no column, row, or section for a PEP stance. So the obligation names a register that does not exist yet, and the failure mode §6.4 itself warns about — "z0z2 and unknown fail open" becoming the estate's real policy without anyone having compiled it — is exactly what the missing register permits.

Recommendation. Either add a stance-map table to §13 with the same state/owner-status discipline the gap table has, or state that the inventory waits for maturity-engine and mark the obligation pending under §9.1's own logic — a requirement whose register does not exist is a capability catalogued without a surface. ops-warden's row is ready to paste:

PEP Protected action Scope Stance Published
ops-warden SSH certificate issuance security-zone open z0z2+unknown, closed z3/n-a ops-warden/pep-stance.yaml

The second half matters more than the first: ops-warden is currently the only PEP that has published one, so an inventory today would contain one row and that is itself the finding. ops-mason is named PEP-shaped in the same paragraph.


Accepted, not yet done — §9.6 emission cadence

§9.6: "A source SHOULD declare an expected emission cadence, and a drop below it SHOULD become a finding in its own right."

ops-warden declares none. This is a genuine SHOULD and the reasoning behind it is sound — it converts the suppression blind spot into something detectable without any Tooling contact, because the source publishes its own stream. It is not done here because a cadence asserted without evidence is worse than none: ops-warden's signing volume is operator-driven and bursty, and a fabricated baseline would generate findings that mean nothing. Deriving one from the existing trail is tractable and is recorded as ops-warden's to do, not gate-house's to chase.


On the pace

Six versions in two days, with four repositories' findings absorbed and credited, is the §12 loop working at a rate the estate has not seen before. Two cautions, offered as an interested consumer rather than as objections:

  1. §13 already says it should not be statute, and it is right. The register has grown every version. Moving it to maturity-engine is the stated plan; until that exists, each version of the standard is also a snapshot of a backlog, and the two have very different review intervals.
  2. The standard is proposed again at v0.6, and the four repositories that assented did so to v0.1. ops-warden's ADR-0010 assent covers the three boundary items, and nothing in v0.2v0.6 has disturbed them — the layer, the lane/rule demarcation, and doctrine-versus-runbook all stand. But the assented_by list carries assent forward across five revisions, and a reader could take it as assent to the current text. Worth distinguishing assented to the boundary from reviewed the current revision; ops-warden has now done both, and this note is the second.