Apply GH-DEC-2026-020: the checker states its version and scope, and reads content

scripts/check_layer_conformance.py now prints, on every run (success and
failure), the standard text it checks against (VALIDATED_AGAINST:
security-layer-model_v0.8.md @ net-kingdom f9e1611 with gate-house A9, A11,
A12 r2 @ 104f3fc) and its scope. A12 detection widens from the key name
standard_version to any *_version key (companion_version included), a
versioned standard/companion path, or a bare vN.N token in any key or value
of INTENT.md frontmatter or layer.yaml. schema_version and comments are not
reached; pep-stance.yaml and pip-claims.yaml are not read for A12 and keep
their version fields (GH-DEC-2026-020 §3).

The widened check found one value the key-name check could not: the
state-hub-work-records note in layer.yaml cited "the v0.7 scope rule". It is
reworded to "the standard's scope rule"; no layer or role value changes.

Tests fail if a versioned standard: path, a companion_version or a bare
version token returns, and if a run stops stating its version and scope.

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
This commit is contained in:
tegwick 2026-09-21 09:38:22 +02:00
parent 00e203c447
commit 8322f0587e
3 changed files with 155 additions and 12 deletions

View file

@ -85,5 +85,5 @@ non_tooling_clients:
operation: "HTTP to the Custodian State Hub for work records"
write: true
note: >-
Outside §5 by the v0.7 scope rule. Recorded, not policed. Carries no
Outside §5 by the standard's scope rule. Recorded, not policed. Carries no
tenant-fact authority and no secret payload.

View file

@ -7,7 +7,8 @@ Read-only. Makes two mechanical checks:
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).
version of the standard or its companion in any key or value
(GH-DEC-2026-017 §1-§5, GH-DEC-2026-020, amendments A9, A11, A12 r2).
2. No catalogued Tooling client (OpenBao, key-cape) appears in src/
unless it maps to a declared §5.1 / §5.2 / §5.3 entry.
@ -15,6 +16,17 @@ PostgreSQL / SQLite / httpx-to-flex-auth / httpx-to-audit-core are not
Tooling contacts. They are listed in layer.yaml non_tooling_clients so
the inventory is total.
A12 r2 reaches content, not a key name: a `*_version` key (standard_version,
companion_version, ...), a versioned `security-layer-model_v0.7.md` or
companion path, and a bare `v0.7` token all count. `schema_version` and YAML
comments are not reached. Stance, claims and classification maps
(pep-stance.yaml, pip-claims.yaml) are not declarations; this check does not
read them for A12 and must not (A12 r2, GH-DEC-2026-020 §3).
Every run prints the standard text it checks against (VALIDATED_AGAINST) and
the scope it ranged over, on success and on failure (GH-DEC-2026-020 §4).
There is no emitted conformance record; the version lives in the run.
Exit 0 clean, 1 undeclared contact, 2 declaration malformed.
"""
from __future__ import annotations
@ -36,6 +48,28 @@ SRC = ROOT / "src" / "tenant_engine"
DECL = ROOT / "layer.yaml"
INTENT = ROOT / "INTENT.md"
# The standard text this checker was built and validated against
# (GH-DEC-2026-020 §4, A12 r2: the version belongs to the run). Bump it when
# the checker is re-validated against a newer accepted text.
VALIDATED_AGAINST = ("net-kingdom/canon/standards/security-layer-model_v0.8.md "
"@ net-kingdom f9e1611, with gate-house "
"docs/amendments/v0.8-section-11-declaration-amendments.md "
"A9, A11, A12 r2 @ gate-house 104f3fc")
SCOPE = ("declaration = INTENT.md frontmatter + layer.yaml (every key and value); "
"tooling scan = src/tenant_engine/**/*.py; "
"not reached: pep-stance.yaml, pip-claims.yaml, comments, schema_version")
# A12 r2: what reads as a version of this standard or its companion.
_VERSION_KEY = re.compile(r"(?:^|_)version$", re.IGNORECASE)
_EXEMPT_KEYS = {"schema_version"} # the declaration file's own schema, not reached
_VERSIONED_PATH = re.compile(
r"(?:security-layer-model|security[-_]companion|companion)[^\s]*?[_-]v?\d+(?:\.\d+)+",
re.IGNORECASE)
# A bare version token (v0.7). A declaration names no other versioned text, so
# a bare token reads as this standard's. File-name suffixes of other
# standards (…_v0.1.md) are preceded by '_' and are not matched here.
_BARE_VERSION = re.compile(r"(?<![\w.])v\d+(?:\.\d+)+\b", re.IGNORECASE)
# Catalogued Tooling in statute §4 today: key-cape and OpenBao.
# Import roots that would constitute a direct client of those.
TOOLING_IMPORTS = {
@ -59,6 +93,44 @@ def _fold(value: object) -> str:
"abcdefghijklmnopqrstuvwxyz"))
def version_findings(data: object, where: str) -> list[str]:
"""Every key or value of a parsed declaration that carries a version (A12 r2)."""
found: list[str] = []
def walk(node: object, path: str) -> None:
if isinstance(node, dict):
for key, value in node.items():
sub = f"{path}.{key}" if path else str(key)
if str(key) in _EXEMPT_KEYS:
continue
if _VERSION_KEY.search(str(key)):
found.append(f"{where}: key '{sub}' is a version key")
continue
if isinstance(key, str):
walk(key, sub + " (key)")
walk(value, sub)
elif isinstance(node, list):
for i, item in enumerate(node):
walk(item, f"{path}[{i}]")
elif isinstance(node, str):
if _VERSIONED_PATH.search(node) or _BARE_VERSION.search(node):
found.append(f"{where}: '{path}' carries a version: {node.strip()[:80]!r}")
walk(data, "")
return found
def _reject_versions(data: object, where: str) -> None:
findings = version_findings(data, where)
if findings:
print("FAIL: a layer declaration must not carry a version of the standard "
"or its companion, in any key or value (A12 r2, GH-DEC-2026-020)",
file=sys.stderr)
for line in findings:
print(f" {line}", file=sys.stderr)
raise SystemExit(2)
def load_declaration() -> dict:
if not DECL.exists():
print(f"FAIL: no declaration at {DECL.relative_to(ROOT)} (§11)", file=sys.stderr)
@ -76,10 +148,7 @@ def load_declaration() -> dict:
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)
_reject_versions(data, DECL.name)
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)
@ -106,10 +175,7 @@ def intent_frontmatter() -> dict:
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)
_reject_versions(data, "INTENT.md frontmatter")
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)
@ -154,6 +220,10 @@ def main() -> int:
parser.add_argument("--report", action="store_true")
args = parser.parse_args()
# GH-DEC-2026-020 §4: every run states what it checked against and its scope.
print(f"checking against: {VALIDATED_AGAINST}")
print(f"scope: {SCOPE}")
decl = load_declaration()
intent = intent_frontmatter()
@ -187,7 +257,8 @@ def main() -> int:
if not args.report:
print(f"OK: Engine/PIP declaration matches INTENT.md; no Tooling client in "
f"{SRC.relative_to(ROOT)}")
f"{SRC.relative_to(ROOT)}; no version in the declaration; "
f"validated against {VALIDATED_AGAINST}")
return 0

View file

@ -58,10 +58,82 @@ def test_intent_frontmatter_agrees_with_layer_yaml():
assert _fold(intent["layer"]) in {"taxonomy", "tooling", "engine", "staff"}
def _checker():
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)
return module
def test_no_declaration_carries_a_standard_version():
"""GH-DEC-2026-017 / A12: neither form carries a standard version."""
"""A12 r2 / GH-DEC-2026-020: no version in any key or value of either form."""
checker = _checker()
assert "standard_version" not in yaml.safe_load((ROOT / "layer.yaml").read_text())
assert "standard_version" not in _intent()
assert checker.version_findings(yaml.safe_load((ROOT / "layer.yaml").read_text()),
"layer.yaml") == []
assert checker.version_findings(_intent(), "INTENT.md") == []
def test_versioned_standard_path_or_companion_version_fails():
"""GH-DEC-2026-020 §1-§2: the pin is caught under any name, not only standard_version."""
checker = _checker()
base = {"layer": "Engine", "role": "PIP"}
bad = [
{**base, "standard": "net-kingdom/canon/standards/security-layer-model_v0.7.md"},
{**base, "companion_version": "0.2"},
{**base, "companion": "net-kingdom/SECURITY-COMPANION.md v0.2"},
{**base, "standard_version": "0.8"},
{**base, "notes": [{"note": "Outside §5 by the v0.7 scope rule."}]},
]
for data in bad:
assert checker.version_findings(data, "x"), data
def test_schema_version_comments_and_section_numbers_are_not_reached():
checker = _checker()
data = yaml.safe_load(
"# Framework: net-kingdom/canon/standards/security-layer-model_v0.7.md\n"
"schema_version: '0.1'\nstandard: netkingdom-security-layer-model\n"
"declared_shapes: {'5.1': [], '5.2': []}\ndeclared_at: '2026-08-29'\n"
"ref: net-kingdom/canon/standards/tenant-engine-boundary-contract_v0.1.md\n")
assert checker.version_findings(data, "x") == []
def test_checker_does_not_apply_a12_to_stance_or_claims_maps():
"""A12 r2 / GH-DEC-2026-020 §3: those files keep their version and are not read for it."""
for name in ("pep-stance.yaml", "pip-claims.yaml"):
assert "standard_version" in yaml.safe_load((ROOT / name).read_text())
assert _run().returncode == 0
def test_every_run_states_version_and_scope(tmp_path):
"""GH-DEC-2026-020 §4: the version lives in the run, on success and on failure."""
checker = _checker()
ok = _run()
assert ok.stdout.count(checker.VALIDATED_AGAINST) >= 2 # header and OK line
assert "scope:" in ok.stdout
report = _run("--report")
assert checker.VALIDATED_AGAINST in report.stdout and "scope:" in report.stdout
def test_a_failing_run_still_states_version_and_scope(tmp_path, monkeypatch, capsys):
checker = _checker()
fake = tmp_path / "INTENT.md"
fake.write_text("---\nlayer: Engine\nrole: PIP\n"
"standard: net-kingdom/canon/standards/security-layer-model_v0.7.md\n---\n")
monkeypatch.setattr(checker, "INTENT", fake)
monkeypatch.setattr(sys, "argv", ["check_layer_conformance.py"])
try:
checker.main()
except SystemExit as exc:
assert exc.code == 2
else: # pragma: no cover
raise AssertionError("a versioned standard: path must fail")
out = capsys.readouterr()
assert checker.VALIDATED_AGAINST in out.out and "scope:" in out.out
assert "carries a version" in out.err
def test_checker_rejects_a_divergence_that_survives_the_fold(tmp_path, monkeypatch):