From d846eba65c442fa0749cfa09ee662d845fa98d67 Mon Sep 17 00:00:00 2001 From: tegwick Date: Mon, 21 Sep 2026 07:35:01 +0200 Subject: [PATCH] Apply GH-DEC-2026-017: INTENT.md governs, layer.yaml is derived, no version Remove standard_version from layer.yaml and the INTENT.md frontmatter (A12), mark layer.yaml derived: true / derived_from: INTENT.md (A11), and change the conformance checker and its tests in the same commit so the conforming declaration does not fail as malformed. The checker now requires the INTENT.md layer: key, rejects standard_version in either form, checks the layer against the closed four-token vocabulary (A9), and reports a layer/role disagreement between the two forms after an ASCII case-fold. Nothing is re-spelled: INTENT.md keeps Engine/PIP and layer.yaml keeps engine/pip. pep-stance.yaml and pip-claims.yaml keep their standard_version; neither is a layer declaration. 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 | 1 - layer.yaml | 7 +++- scripts/check_layer_conformance.py | 64 +++++++++++++++++++++++++----- tests/test_layer_conformance.py | 46 +++++++++++++++++++-- 4 files changed, 103 insertions(+), 15 deletions(-) diff --git a/INTENT.md b/INTENT.md index b4fc91e..3424cf4 100644 --- a/INTENT.md +++ b/INTENT.md @@ -4,7 +4,6 @@ updated: "2026-08-29" layer: Engine role: PIP standard: netkingdom-security-layer-model -standard_version: "0.7" companion: net-kingdom/SECURITY-COMPANION.md --- diff --git a/layer.yaml b/layer.yaml index f45e91c..b721977 100644 --- a/layer.yaml +++ b/layer.yaml @@ -5,6 +5,10 @@ # Assent: decisions/decisions.md TEN-DEC-2026-001 # Validate: python3 scripts/check_layer_conformance.py # +# Derived artifact (§11, GH-DEC-2026-017 §1): INTENT.md frontmatter governs; +# this file is its machine-readable form and must agree with it once case is +# folded. No standard version is carried here (GH-DEC-2026-017, A12). +# # Engine / PIP. Same authoritative tenant state yields the same result. We # supply tenant-as-an-entity facts as claims; we do not render a decision. # Writes are PEP-shaped (pep-stance.yaml). Catalogued Tooling (§4) is @@ -12,8 +16,9 @@ schema_version: "0.1" framework: netkingdom-security-layer-model -standard_version: "0.7" repository: tenant-engine +derived: true +derived_from: INTENT.md layer: engine role: pip declared_by: decisions/decisions.md#TEN-DEC-2026-001 diff --git a/scripts/check_layer_conformance.py b/scripts/check_layer_conformance.py index fa60f94..0e24089 100644 --- a/scripts/check_layer_conformance.py +++ b/scripts/check_layer_conformance.py @@ -3,7 +3,11 @@ Read-only. Makes two mechanical checks: -1. INTENT.md frontmatter and layer.yaml agree on layer and role. +1. INTENT.md frontmatter declares the layer and governs; layer.yaml is a + derived artifact (derived: true, derived_from: INTENT.md) that must agree + with it after ASCII case-folding. The layer is one of §3's closed four + tokens (Taxonomy, Tooling, Engine, Staff). Neither form carries a + standard_version (GH-DEC-2026-017 §1-§5, v0.8 amendments A9, A11, A12). 2. No catalogued Tooling client (OpenBao, key-cape) appears in src/ unless it maps to a declared §5.1 / §5.2 / §5.3 entry. @@ -45,6 +49,15 @@ TOOLING_IMPORTS = { TOOLING_ARGV = re.compile(r"""\[\s*(?:["']bao["']|bao_bin\b|bao_binary\b)\s*,""") OPENBAO_ADDR = re.compile(r"\b(?:VAULT_ADDR|BAO_ADDR|X-Vault-Token)\b") +# §3 as amended (A9): closed, four tokens, compared after an ASCII case-fold. +LAYER_VOCABULARY = {"taxonomy", "tooling", "engine", "staff"} + + +def _fold(value: object) -> str: + """ASCII case-fold only; two spellings of a token are one token.""" + return str(value).translate(str.maketrans("ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyz")) + def load_declaration() -> dict: if not DECL.exists(): @@ -55,14 +68,26 @@ def load_declaration() -> dict: except yaml.YAMLError as exc: print(f"FAIL: {DECL.name} is not parseable: {exc}", file=sys.stderr) raise SystemExit(2) from exc - for key in ("layer", "role", "repository", "standard_version", "tooling_contacts"): + for key in ("layer", "role", "repository", "derived", "derived_from", "tooling_contacts"): if key not in data: print(f"FAIL: {DECL.name} missing required key '{key}'", file=sys.stderr) raise SystemExit(2) - if str(data["layer"]).lower() != "engine": + if data["derived"] is not True or data["derived_from"] != "INTENT.md": + print(f"FAIL: {DECL.name} must be marked derived: true, derived_from: INTENT.md " + "(§11, GH-DEC-2026-017 §1)", file=sys.stderr) + raise SystemExit(2) + if "standard_version" in data: + print(f"FAIL: {DECL.name} carries standard_version; a layer declaration " + "must not (GH-DEC-2026-017, A12)", file=sys.stderr) + raise SystemExit(2) + if _fold(data["layer"]) not in LAYER_VOCABULARY: + print(f"FAIL: {DECL.name} layer {data['layer']!r} is outside the closed " + f"vocabulary {sorted(LAYER_VOCABULARY)}", file=sys.stderr) + raise SystemExit(2) + if _fold(data["layer"]) != "engine": print(f"FAIL: declared layer is {data['layer']!r}, expected engine", file=sys.stderr) raise SystemExit(2) - if str(data["role"]).lower() != "pip": + if _fold(data["role"]) != "pip": print(f"FAIL: declared role is {data['role']!r}, expected pip", file=sys.stderr) raise SystemExit(2) if data["repository"] != "tenant-engine": @@ -78,10 +103,21 @@ def intent_frontmatter() -> dict: raise SystemExit(2) block = text.split("---", 2)[1] data = yaml.safe_load(block) or {} - if str(data.get("layer", "")).lower() != "engine": + if "layer" not in data: + print("FAIL: INTENT.md frontmatter has no layer: key (§11)", file=sys.stderr) + raise SystemExit(2) + if "standard_version" in data: + print("FAIL: INTENT.md frontmatter carries standard_version; a layer " + "declaration must not (GH-DEC-2026-017, A12)", file=sys.stderr) + raise SystemExit(2) + if _fold(data["layer"]) not in LAYER_VOCABULARY: + print(f"FAIL: INTENT.md layer {data['layer']!r} is outside the closed " + f"vocabulary {sorted(LAYER_VOCABULARY)}", file=sys.stderr) + raise SystemExit(2) + if _fold(data["layer"]) != "engine": print(f"FAIL: INTENT.md layer is {data.get('layer')!r}, expected Engine", file=sys.stderr) raise SystemExit(2) - if str(data.get("role", "")).lower() != "pip": + if _fold(data.get("role", "")) != "pip": print(f"FAIL: INTENT.md role is {data.get('role')!r}, expected PIP", file=sys.stderr) raise SystemExit(2) return data @@ -119,12 +155,22 @@ def main() -> int: args = parser.parse_args() decl = load_declaration() - intent_frontmatter() + intent = intent_frontmatter() + + # A11: a disagreement between the governing and derived forms is a finding + # in its own right, reported rather than resolved by precedence. Case is + # folded first (A9), so what survives is a real disagreement. + for key in ("layer", "role"): + if _fold(decl[key]) != _fold(intent.get(key, "")): + print(f"FAIL: {key} disagrees after case-fold — INTENT.md (governing): " + f"{intent.get(key)!r}, layer.yaml (derived): {decl[key]!r}", + file=sys.stderr) + return 2 hits = scan() if args.report: - print(f"tenant-engine — layer {decl['layer']}, role {decl['role']}, " - f"standard v{decl['standard_version']}") + print(f"tenant-engine — layer {intent['layer']}, role {intent['role']} " + f"(INTENT.md governs; layer.yaml derived from {decl['derived_from']})") print(f" tooling contacts declared: {len(decl.get('tooling_contacts') or [])}") print(f" non-tooling clients: {len(decl.get('non_tooling_clients') or [])}") diff --git a/tests/test_layer_conformance.py b/tests/test_layer_conformance.py index 534b59f..c23c92a 100644 --- a/tests/test_layer_conformance.py +++ b/tests/test_layer_conformance.py @@ -24,7 +24,8 @@ def test_layer_yaml_declares_engine_pip(): assert data["repository"] == "tenant-engine" assert data["layer"] == "engine" assert data["role"] == "pip" - assert data["standard_version"] == "0.7" + assert data["derived"] is True + assert data["derived_from"] == "INTENT.md" assert data["tooling_contacts"] == [] assert data["pep_stance"] == "pep-stance.yaml" assert data["pip_claims"] == "pip-claims.yaml" @@ -35,11 +36,48 @@ def test_layer_yaml_declares_engine_pip(): assert "state-hub-work-records" in ids +def _intent() -> dict: + return yaml.safe_load((ROOT / "INTENT.md").read_text().split("---", 2)[1]) + + +def _fold(value: object) -> str: + return str(value).translate(str.maketrans("ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyz")) + + def test_intent_frontmatter_agrees_with_layer_yaml(): - intent = yaml.safe_load((ROOT / "INTENT.md").read_text().split("---", 2)[1]) + """A11/A9: the derived form agrees with the governing one after a case-fold. + + A fold, not an equality: INTENT.md says Engine and layer.yaml says engine, + and neither is re-spelled. A real divergence still fails. + """ + intent = _intent() decl = yaml.safe_load((ROOT / "layer.yaml").read_text()) - assert str(intent["layer"]).lower() == str(decl["layer"]).lower() - assert str(intent["role"]).lower() == str(decl["role"]).lower() + assert _fold(intent["layer"]) == _fold(decl["layer"]) + assert _fold(intent["role"]) == _fold(decl["role"]) + assert _fold(intent["layer"]) in {"taxonomy", "tooling", "engine", "staff"} + + +def test_no_declaration_carries_a_standard_version(): + """GH-DEC-2026-017 / A12: neither form carries a standard version.""" + assert "standard_version" not in yaml.safe_load((ROOT / "layer.yaml").read_text()) + assert "standard_version" not in _intent() + + +def test_checker_rejects_a_divergence_that_survives_the_fold(tmp_path, monkeypatch): + spec = importlib.util.spec_from_file_location("check_layer_conformance", SCRIPT) + module = importlib.util.module_from_spec(spec) + assert spec.loader is not None + spec.loader.exec_module(module) + fake = tmp_path / "INTENT.md" + fake.write_text("---\nlayer: Staff\nrole: PIP\n---\n") + monkeypatch.setattr(module, "INTENT", fake) + try: + module.intent_frontmatter() + except SystemExit as exc: + assert exc.code == 2 + else: # pragma: no cover + raise AssertionError("a Staff INTENT.md must not pass as Engine") def test_checker_passes_on_the_real_tree():