Apply GH-DEC-2026-020: checker prints version and scope, A12 r2 by content.
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s

The layer conformance checker now prints VALIDATED_AGAINST and SCOPE on every
run, including the PASS line (kings-guard pattern), and enforces A12 r2 over
every key and value of INTENT.md frontmatter and layer.yaml: a versioned
standard: path and a companion_version are caught, schema_version and comments
are not reached, pep-stance.yaml is outside the run. Tests guard both returns.
The playbook carries the adopter change set and confirms the section 5
citation is canonical. WARDEN-WP-0034's open 4220413a note is closed.

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:17 +02:00
parent b9151e20da
commit c23918d6ec
4 changed files with 191 additions and 18 deletions

View file

@ -13,8 +13,19 @@ comparing (`GH-DEC-2026-017` §2, amendment A9): two spellings of a token do not
describe two boundaries, and a check that reports findings about capital letters describe two boundaries, and a check that reports findings about capital letters
buries the one real disagreement it exists to find. buries the one real disagreement it exists to find.
Neither form carries a `standard_version`, and their absence is enforced here Neither form carries a version of the standard or of its companion, in any key
and by tests (`GH-DEC-2026-017` §5, amendment A12). or value (`GH-DEC-2026-017` §5, amendment A12 as refined by A12 r2 /
`GH-DEC-2026-020` §1-§2). The rule reaches content, not a key name: a
`standard_version` key, a `companion_version` key, and a version-bearing path
such as `standard: .../security-layer-model_v0.7.md` are the same pin. Comments
and a file's own `schema_version` are not reached. Stance, claims and
evidence-classification maps (`pep-stance.yaml`) are NOT declarations and this
check does not read them (`GH-DEC-2026-020` §3).
The version belongs to the run (`GH-DEC-2026-020` §4): every run prints
VALIDATED_AGAINST and SCOPE below, including the PASS line, following
kings-guard's pattern. A retained copy of this output is a derived artifact
whose version is owed by whoever retains it.
Makes §11's second mechanical check real: Makes §11's second mechanical check real:
@ -47,6 +58,61 @@ DECL = ROOT / "layer.yaml"
VALID_SHAPES = {"5.1", "5.2", "5.3"} VALID_SHAPES = {"5.1", "5.2", "5.3"}
# What every run checks against, printed on every run (GH-DEC-2026-020 §4, A12 r2).
# The accepted text is v0.7 at net-kingdom@66dc491; the amendments that already
# govern through their decision records are named with it.
VALIDATED_AGAINST = (
"net-kingdom/canon/standards/security-layer-model_v0.7.md (net-kingdom@66dc491) "
"as amended by GH-DEC-2026-017 and GH-DEC-2026-020 (A9-A13, A12 r2; gate-house@d8c82a8)"
)
# What every run ranges over. pep-stance.yaml is deliberately outside it.
SCOPE = "INTENT.md frontmatter, layer.yaml, src/warden/**/*.py"
# A12 r2: a version of the standard or companion in any key or value of the
# declaration. Keys: anything naming a standard/companion version. Values: a
# versioned file name or path (`_v0.7`, `-v0.8.md`) or a bare version string on a
# version-named key. `schema_version` is the file's own schema, not reached.
VERSION_KEY = re.compile(r"(standard|companion).*version|version.*(standard|companion)", re.I)
VERSION_IN_VALUE = re.compile(r"[_\-.]v\d+(\.\d+)*(\.md)?\b|@v?\d+\.\d+", re.I)
NOT_REACHED_KEYS = {"schema_version"}
def find_version_pins(node, where: str = "") -> list[str]:
"""Every place in a parsed declaration that carries a standard/companion version.
Walks every key and value (comments are gone after parsing, which is the
A12 r2 exclusion). Returns human-readable locations; empty means clean.
"""
pins: list[str] = []
if isinstance(node, dict):
for k, v in node.items():
here = f"{where}.{k}" if where else str(k)
if str(k) in NOT_REACHED_KEYS:
continue
if VERSION_KEY.search(str(k)):
pins.append(f"{here} (key names a standard/companion version)")
continue
pins.extend(find_version_pins(v, here))
elif isinstance(node, list):
for i, v in enumerate(node):
pins.extend(find_version_pins(v, f"{where}[{i}]"))
elif isinstance(node, str) and VERSION_IN_VALUE.search(node):
pins.append(f"{where} = {node!r} (value carries a version)")
return pins
def _reject_version_pins(label: str, node) -> None:
pins = find_version_pins(node)
if pins:
print(
f"MALFORMED: {label} carries a standard/companion version — a layer "
"declaration MUST NOT, in any key or value (§11 as amended by A12 r2, "
"GH-DEC-2026-020 §1-§2):"
)
for p in pins:
print(f" {p}")
raise SystemExit(2)
# §3's vocabulary, closed, four tokens (GH-DEC-2026-017 §3, amendment A9). The # §3's vocabulary, closed, four tokens (GH-DEC-2026-017 §3, amendment A9). The
# canonical spellings are §4's catalog-column forms; comparison is ASCII # canonical spellings are §4's catalog-column forms; comparison is ASCII
# case-insensitive, so the fold is what is stored and `Taxonomy` is in the set — # case-insensitive, so the fold is what is stored and `Taxonomy` is in the set —
@ -80,12 +146,7 @@ def load_governing_layer() -> str:
if "layer" not in front: if "layer" not in front:
print("MALFORMED: INTENT.md frontmatter has no 'layer' key — §11's declaration") print("MALFORMED: INTENT.md frontmatter has no 'layer' key — §11's declaration")
raise SystemExit(2) raise SystemExit(2)
if "standard_version" in front: _reject_version_pins("INTENT.md frontmatter", front)
print(
"MALFORMED: INTENT.md frontmatter carries 'standard_version' — a layer "
"declaration MUST NOT carry a standard version (§11 as amended by A12)"
)
raise SystemExit(2)
layer = front["layer"] layer = front["layer"]
if _fold(layer) not in LAYER_VOCABULARY: if _fold(layer) not in LAYER_VOCABULARY:
print( print(
@ -139,12 +200,7 @@ def load_declaration() -> dict:
) )
raise SystemExit(2) raise SystemExit(2)
# A12: the version has no home in a declaration, governing or derived. # A12: the version has no home in a declaration, governing or derived.
if "standard_version" in decl: _reject_version_pins("layer.yaml", decl)
print(
"MALFORMED: layer.yaml carries 'standard_version' — a layer declaration "
"MUST NOT carry a standard version (§11 as amended by A12)"
)
raise SystemExit(2)
if _fold(decl["layer"]) not in LAYER_VOCABULARY: if _fold(decl["layer"]) not in LAYER_VOCABULARY:
print( print(
f"MALFORMED: layer.yaml declares layer {decl['layer']!r}, outside §3's " f"MALFORMED: layer.yaml declares layer {decl['layer']!r}, outside §3's "
@ -197,6 +253,10 @@ def main() -> int:
ap.add_argument("--report", action="store_true", help="also print the declaration and gap review dates") ap.add_argument("--report", action="store_true", help="also print the declaration and gap review dates")
args = ap.parse_args() args = ap.parse_args()
# Printed before anything can fail, so even a MALFORMED run states what it
# checked against and over what (GH-DEC-2026-020 §4).
print(f"validated against: {VALIDATED_AGAINST}")
print(f"scope: {SCOPE}")
governing = load_governing_layer() governing = load_governing_layer()
decl = load_declaration() decl = load_declaration()
declared = {c["module"].split("/")[-1] for c in decl["tooling_contacts"]} declared = {c["module"].split("/")[-1] for c in decl["tooling_contacts"]}
@ -258,9 +318,15 @@ def main() -> int:
print(f" {m}") print(f" {m}")
if ok and not args.report: if ok and not args.report:
print(f"PASS — {len(found)} module(s) with Tooling contact, all declared.") print(
f"PASS — {len(found)} module(s) with Tooling contact, all declared; "
f"validated against {VALIDATED_AGAINST}"
)
elif ok: elif ok:
print("\nPASS — every direct Tooling contact maps to a declared shape.") print(
"\nPASS — every direct Tooling contact maps to a declared shape; "
f"validated against {VALIDATED_AGAINST}"
)
return 0 if ok else 1 return 0 if ok else 1

View file

@ -32,6 +32,17 @@ def _intent_frontmatter() -> dict:
return yaml.safe_load("\n".join(lines[1:end])) return yaml.safe_load("\n".join(lines[1:end]))
def _checker():
import importlib.util
spec = importlib.util.spec_from_file_location(
"check_layer_conformance", ROOT / "scripts" / "check_layer_conformance.py"
)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def _fold(value: str) -> str: def _fold(value: str) -> str:
return str(value).strip().encode("ascii", "ignore").decode().lower() return str(value).strip().encode("ascii", "ignore").decode().lower()
@ -81,6 +92,51 @@ class TestDeclaration:
assert "standard_version" not in _decl() assert "standard_version" not in _decl()
assert "standard_version" not in _intent_frontmatter() assert "standard_version" not in _intent_frontmatter()
def test_no_version_anywhere_in_either_declaration(self):
"""A12 r2 / GH-DEC-2026-020 §1-§2: content, not a key name.
A versioned `standard:` path or a `companion_version` is the same pin as
`standard_version`, so the guard walks every key and value of both forms.
"""
checker = _checker()
assert checker.find_version_pins(_intent_frontmatter()) == []
assert checker.find_version_pins(_decl()) == []
assert not str(_intent_frontmatter()["standard"]).endswith(".md")
def test_checker_catches_a_versioned_standard_path(self):
checker = _checker()
pins = checker.find_version_pins(
{"layer": "Staff", "standard": "net-kingdom/canon/standards/security-layer-model_v0.7.md"}
)
assert pins and pins[0].startswith("standard")
def test_checker_catches_a_companion_version(self):
checker = _checker()
assert checker.find_version_pins({"layer": "Staff", "companion_version": "0.2"})
assert checker.find_version_pins({"nested": {"standard_version": "0.7"}})
def test_schema_version_is_not_reached(self):
assert _checker().find_version_pins({"schema_version": "0.2", "layer": "Staff"}) == []
def test_stance_map_is_outside_the_run(self):
"""GH-DEC-2026-020 §3: a stance map keeps its version; the run must not read it."""
stance = yaml.safe_load((ROOT / "pep-stance.yaml").read_text())
assert "standard_version" in stance, "pep-stance.yaml keeps its clause-scoped version"
assert "pep-stance" not in _checker().SCOPE
def test_every_run_states_version_and_scope(self):
"""GH-DEC-2026-020 §4: the version belongs to the run, printed every time."""
checker = _checker()
out = subprocess.run(
[sys.executable, str(ROOT / "scripts" / "check_layer_conformance.py")],
capture_output=True,
text=True,
).stdout
assert f"validated against: {checker.VALIDATED_AGAINST}" in out
assert f"scope: {checker.SCOPE}" in out
pass_line = next(ln for ln in out.splitlines() if ln.startswith("PASS"))
assert checker.VALIDATED_AGAINST in pass_line
def test_every_tooling_contact_maps_to_a_declared_shape(self): def test_every_tooling_contact_maps_to_a_declared_shape(self):
"""§11 mechanical check — the guard against a new undeclared client.""" """§11 mechanical check — the guard against a new undeclared client."""
result = subprocess.run( result = subprocess.run(

View file

@ -51,8 +51,10 @@ anyone else's files.
property that does not change when the standard is revised, and a version in property that does not change when the standard is revised, and a version in
the declaration makes every revision read as though it invalidated every the declaration makes every revision read as though it invalidated every
declaration. Keeping it "for information" was declined explicitly — a field declaration. Keeping it "for information" was declined explicitly — a field
that is present will be branched on. Version-scoped state belongs in the that is present will be branched on. Version-scoped state belongs to the
derived conformance record. If your checker lists `standard_version` as a conformance *run* (see the 2026-09-21 `GH-DEC-2026-020` section below; the
"derived conformance record" this line used to name was a defect in §5 and
nobody is required to emit one). If your checker lists `standard_version` as a
required key, or prints it in a report line, it will now **reject a conforming required key, or prints it in a report line, it will now **reject a conforming
declaration** — fix the checker in the same commit. declaration** — fix the checker in the same commit.
2. **Add `derived: true` and `derived_from: INTENT.md`.** The sidecar is a derived 2. **Add `derived: true` and `derived_from: INTENT.md`.** The sidecar is a derived
@ -82,6 +84,49 @@ ops-warden's applied instance of this change set is commit-local: `INTENT.md`,
`layer.yaml`, `scripts/check_layer_conformance.py`, `tests/test_layer_conformance.py`. `layer.yaml`, `scripts/check_layer_conformance.py`, `tests/test_layer_conformance.py`.
Read those four together rather than the sidecar alone. Read those four together rather than the sidecar alone.
## Reach and run-version change set — 2026-09-21 (`GH-DEC-2026-020`, A12 r2)
**If you copied ops-warden's checker before this change, it enforces A12 by key
name only, and prints no version.** Both are now defects. `GH-DEC-2026-020`
refines A12 as A12 r2; verify it in `gate-house` `decisions/decisions.md` and
`docs/amendments/v0.8-section-11-declaration-amendments.md` (§ "A12 r2"), not
from this page.
1. **A version anywhere in the declaration counts.** The declaration is every key
and value of your `INTENT.md` frontmatter and of your derived sidecar. No key
or value carries a version of the standard **or of its companion**, including
a version-bearing path: `standard: .../security-layer-model_v0.7.md` becomes
`standard: .../security-layer-model` (`GH-DEC-2026-020` §1). A de-versioned
path was a required change, not a voluntary one.
2. **`companion_version` counts** and comes out of the declaration (§2).
3. **Not reached:** comments, and a file's own `schema_version`. Keeping or
removing them is equally fine; do not edit them just to tidy.
4. **Not a declaration, not checked:** stance maps (`pep-stance.yaml`), claims
maps, evidence classifications. Their version is what makes them re-readable
when clause text changes; keep it. Your checker **MUST NOT** apply A12 to
them (§3).
5. **The version belongs to the run.** A re-runnable checker is sufficient —
not "for now" — if **every** run prints the standard version or commit it
checks against and the scope it ranged over, including the PASS line (§4).
No repository must emit a durable conformance record; whoever retains a run's
output owes that copy's version. The pattern is kings-guard's: a
`VALIDATED_AGAINST` constant in the checker, printed on every run.
6. **Widen your checker from key name to content.** ops-warden's
`scripts/check_layer_conformance.py` now carries `VALIDATED_AGAINST`, `SCOPE`
and `find_version_pins()`, which walks every parsed key and value, skips
`schema_version`, and flags any key naming a standard/companion version and
any value carrying a versioned file name or path. It prints version and scope
before loading anything, so even a MALFORMED run states them. Copy that, set
`VALIDATED_AGAINST` to what *your* run checks against, and add tests that fail
if a versioned `standard:` path or a `companion_version` comes back
(`tests/test_layer_conformance.py` has the reference set). Change declaration,
checker and tests in the same commit, and re-spell no layer value.
**Citation.** Cite the ruling by the decision's body section: `GH-DEC-2026-017`
§5, statute A12 (now A12 r2). This page's "§5" is canonical
(`GH-DEC-2026-020`); the decision's `rationale:` part numbers are a summary and
are not cited.
## Ownership boundary ## Ownership boundary
`gate-house` owns what the model requires. Each repository owns the truth of its `gate-house` owns what the model requires. Each repository owns the truth of its

View file

@ -292,6 +292,12 @@ says version-scoped state belongs in the derived conformance record, which
checker that emits nothing durable, not an emitted record. Whether §11 expects an checker that emits nothing durable, not an emitted record. Whether §11 expects an
emitted artifact or a re-runnable check discharges it is asked of gate-house in emitted artifact or a re-runnable check discharges it is asked of gate-house in
message `4220413a` and unanswered. Nothing applied above depends on the answer. message `4220413a` and unanswered. Nothing applied above depends on the answer.
**Closed 2026-09-21 by `GH-DEC-2026-020` §4 (gate-house@104f3fc):** §5 was wrong
that the record exists; a re-runnable checker is sufficient if every run prints
the version it checks against and its scope. Applied: the checker now prints
`VALIDATED_AGAINST` and `SCOPE` on every run and enforces A12 r2 by content, not
key name (versioned `standard:` path, `companion_version`); `pep-stance.yaml`
untouched per §3; the playbook carries the adopter change set.
**Ruled the same day, and still `wait` — deliberately.** `GH-DEC-2026-017` **Ruled the same day, and still `wait` — deliberately.** `GH-DEC-2026-017`
(message `3715e247`) landed hours later: `INTENT.md` governs, the sidecar is a (message `3715e247`) landed hours later: `INTENT.md` governs, the sidecar is a