From 8a48cb05df7ef072fd9bf7a11d91c596f694d234 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 21 Sep 2026 07:37:53 +0200 Subject: [PATCH] Apply GH-DEC-2026-017: INTENT.md governs, layer.yaml is derived, no version Verified against gate-house's committed ruling (decisions/decisions.md, GH-DEC-2026-017) and amendments A9-A13, then ops-warden's reference change set (a70f559, wiki/playbooks/netkingdom-layer-declaration.md). They agree. layer.yaml: standard_version removed; derived: true and derived_from: INTENT.md added; declared_by kept. INTENT.md frontmatter never carried standard_version, but its standard: value was a version-pinned path; it is de-versioned as the reference instance did. No layer value is re-spelled: INTENT.md still says Engine and layer.yaml still says engine. The checker changes in the same commit because it listed standard_version as a required key: removing the field alone would have made a conforming declaration exit 2 MALFORMED. It now reads INTENT.md as the governing form, requires the derived marking, rejects a returning standard_version in either form, checks 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 rather than resolving it by precedence. Tests assert the fold, not per-file spelling, and cover fold agreement, a real disagreement, the closed vocabulary and a returning version. Full suite 430 passed. role:, pep-stance.yaml and schema_version are untouched (not ruled). Still open: where the removed version lives in a derived conformance record; asked of gate-house by ops-warden (4220413a), followed rather than chosen here. Closes the SECRETS-WP-0008 note that waited on the reference form. Co-Authored-By: Claude Opus 5 Assistant: claude-code Assistant-Model: opus Assistant-Process: 63291@bnt-lap001 Assistant-Session: 8bd77868-ca68-4f49-bb1e-d539ecc0d703 --- INTENT.md | 11 ++- layer.yaml | 12 ++- scripts/check_layer_conformance.py | 89 +++++++++++++++--- tests/test_layer_conformance.py | 93 +++++++++++++++++-- ...-0008-layer-model-lifecycle-conformance.md | 43 ++++++++- 5 files changed, 226 insertions(+), 22 deletions(-) diff --git a/INTENT.md b/INTENT.md index 73fb754..62a3db9 100644 --- a/INTENT.md +++ b/INTENT.md @@ -1,9 +1,16 @@ --- +# THE layer declaration (§11, GH-DEC-2026-017 §1). `layer.yaml` is derived from +# this frontmatter and must agree with it; it does not govern. Comparison of the +# §3 vocabulary is ASCII case-insensitive, so `Engine` here and `engine` there +# are the same value and neither is re-spelled (GH-DEC-2026-017 §2). layer: Engine role: Lifecycle -standard: net-kingdom/canon/standards/security-layer-model_v0.7.md +# No standard version here or in the sidecar (GH-DEC-2026-017 §5 / A12): the +# declared layer is a standing property that does not change when the standard +# is revised. Version-scoped state belongs in the derived conformance record. +standard: net-kingdom/canon/standards/security-layer-model companion: net-kingdom/SECURITY-COMPANION.md -declaration: layer.yaml +declaration: layer.yaml # derived form; this frontmatter governs pep_stance: pep-stance.yaml declared_at: "2026-08-29" --- diff --git a/layer.yaml b/layer.yaml index 16ae2d4..2ba81d3 100644 --- a/layer.yaml +++ b/layer.yaml @@ -1,8 +1,15 @@ # secrets-engine — NetKingdom security layer declaration # -# Framework: net-kingdom/canon/standards/security-layer-model_v0.7.md +# Framework: net-kingdom/canon/standards/security-layer-model # Companion: net-kingdom/SECURITY-COMPANION.md # Voice: INTENT.md (this repository's own declaration, §11) +# +# DERIVED ARTIFACT (§11, GH-DEC-2026-017 §1 / A11). INTENT.md's frontmatter +# `layer:` key is the declaration and governs; this file derives from it and +# must agree with it. `engine` here and `Engine` there are one token: §3's +# vocabulary is closed and compared ASCII case-insensitively (GH-DEC-2026-017 +# §2 / A9), so nothing is re-spelled. No standard version is carried here +# (GH-DEC-2026-017 §5 / A12). # Validate: python3 scripts/check_layer_conformance.py # # §11 requires a machine-readable form because prose cannot distinguish a @@ -16,7 +23,8 @@ schema_version: "0.1" framework: netkingdom-security-layer-model -standard_version: "0.7" +derived: true +derived_from: INTENT.md repository: secrets-engine layer: engine role: lifecycle diff --git a/scripts/check_layer_conformance.py b/scripts/check_layer_conformance.py index 55722b6..94624c4 100644 --- a/scripts/check_layer_conformance.py +++ b/scripts/check_layer_conformance.py @@ -4,10 +4,21 @@ Read-only. This is the Engine/Lifecycle adaptation of the ops-warden reference checker. §5 Staff shapes do not apply to the owned OpenBao contact. +Two declaration forms are read. Per GH-DEC-2026-017 §1 (amendment A11) +INTENT.md's frontmatter `layer:` key governs; layer.yaml is a derived artifact +that must be marked derived, must name INTENT.md, and must agree with it. The +sidecar is still read, because a disagreement between the two is a finding in +its own right, reported rather than resolved away by precedence. + +Layer values are compared against §3's closed four-token vocabulary after an +ASCII case-fold (GH-DEC-2026-017 §2-§3, amendment A9). Nothing is re-spelled: +`Engine` and `engine` are one token. Neither form carries a standard version +(GH-DEC-2026-017 §5, amendment A12), and its return is rejected. + Mechanical checks: -- a machine-readable declaration exists and says Engine / Lifecycle -- INTENT.md frontmatter matches that declaration +- INTENT.md frontmatter carries the governing `layer:` (Engine) and role +- layer.yaml is marked derived from INTENT.md and agrees with it after folding - no authorization decision surface is exposed - the PEP stance map is published at the path named in the declaration - every OpenBao subprocess adapter lives in a module listed as owned tooling @@ -35,6 +46,34 @@ DECISION_SURFACE = re.compile( r"""\b(evaluate_policy|check_permission|render_decision|pdp_decide)\b""" ) +# §3's vocabulary: closed, four tokens, compared case-insensitively +# (GH-DEC-2026-017 §3, amendment A9). Taxonomy is in it. +LAYER_VOCABULARY = {"taxonomy", "tooling", "engine", "staff"} +EXPECTED_LAYER = "engine" + + +def _fold(value: object) -> str: + """ASCII case-fold, per §3 as amended: two spellings of a token are one token.""" + return str(value).strip().encode("ascii", "ignore").decode().lower() + + +def _no_standard_version(where: str, data: dict) -> None: + if "standard_version" in data: + print( + f"MALFORMED: {where} carries 'standard_version' — a layer declaration " + "MUST NOT carry a standard version (§11 as amended by A12)" + ) + raise SystemExit(2) + + +def _in_vocabulary(where: str, layer: object) -> None: + if _fold(layer) not in LAYER_VOCABULARY: + print( + f"MALFORMED: {where} declares layer {layer!r}, outside §3's closed " + f"vocabulary {sorted(LAYER_VOCABULARY)} (case-insensitive)" + ) + raise SystemExit(2) + def load_declaration() -> dict: if not DECL.exists(): @@ -45,7 +84,8 @@ def load_declaration() -> dict: "layer", "role", "repository", - "standard_version", + "derived", + "derived_from", "owned_tooling", "decision_surfaces_exposed", "pep_shaped", @@ -54,9 +94,18 @@ def load_declaration() -> dict: if key not in decl: print(f"MALFORMED: layer.yaml has no {key!r}") raise SystemExit(2) - if decl["layer"] != "engine": - print(f"MALFORMED: declared layer is {decl['layer']!r}, expected 'engine'") + # §11 derived-artifact rule (GH-DEC-2026-017 §1): marked, naming its source. + if decl["derived"] is not True: + print("MALFORMED: layer.yaml must be marked 'derived: true' (§11, GH-DEC-2026-017 §1)") raise SystemExit(2) + if decl["derived_from"] != "INTENT.md": + print( + f"MALFORMED: layer.yaml derives from {decl['derived_from']!r}; §11 names " + "INTENT.md as the governing declaration" + ) + raise SystemExit(2) + _no_standard_version("layer.yaml", decl) + _in_vocabulary("layer.yaml", decl["layer"]) if decl["role"] != "lifecycle": print(f"MALFORMED: declared role is {decl['role']!r}, expected 'lifecycle'") raise SystemExit(2) @@ -75,7 +124,13 @@ def intent_frontmatter() -> dict: if end < 0: print("MALFORMED: INTENT.md frontmatter is unclosed") raise SystemExit(2) - return yaml.safe_load(text[3:end]) or {} + front = yaml.safe_load(text[3:end]) or {} + if "layer" not in front: + print("MALFORMED: INTENT.md frontmatter has no 'layer' key — §11's declaration") + raise SystemExit(2) + _no_standard_version("INTENT.md frontmatter", front) + _in_vocabulary("INTENT.md frontmatter", front["layer"]) + return front def owned_modules(decl: dict) -> set[str]: @@ -118,13 +173,24 @@ def main() -> int: ap.add_argument("--report", action="store_true") args = ap.parse_args() - decl = load_declaration() front = intent_frontmatter() + decl = load_declaration() ok = True - if str(front.get("layer", "")).lower() != "engine": + governing = front["layer"] + if _fold(governing) != EXPECTED_LAYER: ok = False - print("FINDING: INTENT.md frontmatter layer is not Engine") + print(f"FINDING: INTENT.md frontmatter layer is {governing!r}, not Engine") + # §11 as amended (A11): a post-fold disagreement between the two forms is a + # finding in its own right, reported rather than resolved by precedence. + if _fold(decl["layer"]) != _fold(governing): + ok = False + print( + "FINDING: DECLARATION DISAGREEMENT (§11) — " + f"INTENT.md (governs) layer: {governing!r}; " + f"layer.yaml (derived) layer: {decl['layer']!r}. " + "Case is already folded; this is a disagreement about a layer." + ) if str(front.get("role", "")).lower() != "lifecycle": ok = False print("FINDING: INTENT.md frontmatter role is not Lifecycle") @@ -161,9 +227,10 @@ def main() -> int: if args.report: print( - f"{decl['repository']} — layer: {decl['layer']} " - f"role: {decl['role']} (model v{decl['standard_version']})" + f"{decl['repository']} — layer: {governing} role: {front.get('role')} " + "(declared in INTENT.md; §11 governing form)" ) + print(f"layer.yaml: derived from {decl['derived_from']}, layer: {decl['layer']}") print(f"declared by {decl['declared_by']}") print(f"pep stance: {decl['pep_stance']}") print(f"owned OpenBao modules: {sorted(owned)}") diff --git a/tests/test_layer_conformance.py b/tests/test_layer_conformance.py index 2cf97a9..26478b1 100644 --- a/tests/test_layer_conformance.py +++ b/tests/test_layer_conformance.py @@ -6,6 +6,7 @@ from the code is worse than none. """ from __future__ import annotations +import importlib.util import subprocess import sys from pathlib import Path @@ -38,28 +39,108 @@ def _stance() -> dict: return yaml.safe_load(STANCE.read_text(encoding="utf-8")) +def _front() -> dict: + text = INTENT.read_text(encoding="utf-8") + assert text.startswith("---"), "companion §2 requires INTENT.md frontmatter" + end = text.find("\n---", 3) + return yaml.safe_load(text[3:end]) + + +def _fold(value: object) -> str: + """§3 as amended (A9): comparison is ASCII case-insensitive.""" + return str(value).strip().encode("ascii", "ignore").decode().lower() + + +def _checker(): + spec = importlib.util.spec_from_file_location("check_layer_conformance", SCRIPT) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + def test_declares_engine_lifecycle_in_its_own_voice(): assert DECL.exists(), "no layer.yaml — §11 requires a machine-readable declaration" data = _decl() assert data["repository"] == "secrets-engine" - assert data["layer"] == "engine" + # Fold, never equality: the ruling declined to order a re-spelling. + assert _fold(data["layer"]) == "engine" assert data["role"] == "lifecycle" assert data["declared_by"] == "INTENT.md" + assert data["derived"] is True + assert data["derived_from"] == "INTENT.md" assert data["decision_surfaces_exposed"] == "none" assert data["pep_shaped"] is True def test_intent_frontmatter_matches_declaration(): - text = INTENT.read_text(encoding="utf-8") - assert text.startswith("---"), "companion §2 requires INTENT.md frontmatter" - end = text.find("\n---", 3) - front = yaml.safe_load(text[3:end]) - assert front["layer"] == "Engine" + front = _front() + assert _fold(front["layer"]) == "engine" + assert _fold(_decl()["layer"]) == _fold(front["layer"]), ( + "INTENT.md governs and layer.yaml must agree after folding (GH-DEC-2026-017 §1-§2)" + ) assert front["role"] == "Lifecycle" assert front["declaration"] == "layer.yaml" assert front["pep_stance"] == "pep-stance.yaml" +def test_no_standard_version_in_either_form(): + """GH-DEC-2026-017 §5 / A12: a layer declaration carries no standard version.""" + assert "standard_version" not in _decl() + assert "standard_version" not in _front() + assert not str(_front().get("standard", "")).endswith(".md") + + +def _run_checker(tmp_path, monkeypatch, intent_layer: str, sidecar_layer: str) -> int: + checker = _checker() + front = _front() + front["layer"] = intent_layer + intent = tmp_path / "INTENT.md" + intent.write_text("---\n" + yaml.safe_dump(front) + "---\n\n# INTENT\n", encoding="utf-8") + decl = _decl() + decl["layer"] = sidecar_layer + sidecar = tmp_path / "layer.yaml" + sidecar.write_text(yaml.safe_dump(decl), encoding="utf-8") + monkeypatch.setattr(checker, "INTENT", intent) + monkeypatch.setattr(checker, "DECL", sidecar) + monkeypatch.setattr(sys, "argv", ["check_layer_conformance.py"]) + try: + return checker.main() + except SystemExit as exc: + return int(exc.code) + + +def test_checker_folds_case_between_forms(tmp_path, monkeypatch): + assert _run_checker(tmp_path, monkeypatch, "ENGINE", "engine") == 0 + assert _run_checker(tmp_path, monkeypatch, "Engine", "Engine") == 0 + + +def test_checker_reports_a_real_disagreement(tmp_path, monkeypatch, capsys): + """A post-fold disagreement is a finding, not resolved by precedence.""" + assert _run_checker(tmp_path, monkeypatch, "Engine", "staff") == 1 + assert "DECLARATION DISAGREEMENT" in capsys.readouterr().out + + +def test_checker_vocabulary_is_closed_at_four_tokens(tmp_path, monkeypatch, capsys): + checker = _checker() + assert checker.LAYER_VOCABULARY == {"taxonomy", "tooling", "engine", "staff"} + # Taxonomy is in the vocabulary: a finding (wrong layer for this repo), not MALFORMED. + assert _run_checker(tmp_path, monkeypatch, "Taxonomy", "taxonomy") == 1 + assert _run_checker(tmp_path, monkeypatch, "surface", "surface") == 2 + assert "outside §3's closed vocabulary" in capsys.readouterr().out + + +def test_checker_rejects_a_returning_standard_version(tmp_path, monkeypatch): + checker = _checker() + decl = _decl() + decl["standard_version"] = "0.8" + sidecar = tmp_path / "layer.yaml" + sidecar.write_text(yaml.safe_dump(decl), encoding="utf-8") + monkeypatch.setattr(checker, "DECL", sidecar) + with pytest.raises(SystemExit) as raised: + checker.load_declaration() + assert raised.value.code == 2 + + def test_checker_passes_on_the_real_tree(): result = subprocess.run( [sys.executable, str(SCRIPT)], diff --git a/workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md b/workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md index f0c30e6..87a0544 100644 --- a/workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md +++ b/workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md @@ -9,7 +9,7 @@ flavor: implementation owner: grok topic_slug: custodian created: "2026-08-29" -updated: "2026-09-09" +updated: "2026-09-21" state_hub_workstream_id: "9c9e5164-b2f5-5ea2-a557-5368d65e9fe0" --- @@ -416,6 +416,47 @@ 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