Apply GH-DEC-2026-021: identity-value pins, prose citations not reached.
The playbook detector is the estate reference (021 §3). Add its one addition to the reference and the checker: any v?N.N in a standard: or companion: value is a pin. The prose-citation note moves from pending to not reached (021 §1, A12 r3), and intent_version is noted as a key that must not be flagged. VALIDATED_AGAINST keeps accepted v0.7 and adds GH-DEC-2026-021 at gate-house@39d9287. 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:
parent
0f9ada0b0d
commit
39791526a0
3 changed files with 61 additions and 21 deletions
|
|
@ -58,12 +58,13 @@ 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).
|
# What every run checks against, printed on every run (GH-DEC-2026-020 §4,
|
||||||
# The accepted text is v0.7 at net-kingdom@66dc491; the amendments that already
|
# GH-DEC-2026-021 §2). The accepted text is v0.7 at net-kingdom@66dc491; the
|
||||||
# govern through their decision records are named with it.
|
# decision records whose rulings this checker enforces beyond v0.7 are named with it.
|
||||||
VALIDATED_AGAINST = (
|
VALIDATED_AGAINST = (
|
||||||
"net-kingdom/canon/standards/security-layer-model_v0.7.md (net-kingdom@66dc491) "
|
"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)"
|
"as amended by GH-DEC-2026-017, GH-DEC-2026-020 and GH-DEC-2026-021 "
|
||||||
|
"(A9-A13, A12 r3; gate-house@39d9287)"
|
||||||
)
|
)
|
||||||
# What every run ranges over. pep-stance.yaml is deliberately outside it.
|
# What every run ranges over. pep-stance.yaml is deliberately outside it.
|
||||||
SCOPE = "INTENT.md frontmatter, layer.yaml, src/warden/**/*.py"
|
SCOPE = "INTENT.md frontmatter, layer.yaml, src/warden/**/*.py"
|
||||||
|
|
@ -72,12 +73,18 @@ SCOPE = "INTENT.md frontmatter, layer.yaml, src/warden/**/*.py"
|
||||||
# declaration. Keys: anything naming a standard/companion version. Values: a
|
# 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
|
# 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-named key. `schema_version` is the file's own schema, not reached.
|
||||||
|
# GH-DEC-2026-021 §1/§3 (A12 r3): a version is reached only as a pin. Any version
|
||||||
|
# token (`v?N.N`) in the value of an identity-bearing key (`standard:`,
|
||||||
|
# `companion:`) is a pin; a revision cited in other prose is provenance and is not
|
||||||
|
# reached. Keys such as `intent_version` name neither and are not flagged.
|
||||||
VERSION_KEY = re.compile(r"(standard|companion).*version|version.*(standard|companion)", re.I)
|
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)
|
VERSION_IN_VALUE = re.compile(r"[_\-.]v\d+(\.\d+)*(\.md)?\b|@v?\d+\.\d+", re.I)
|
||||||
NOT_REACHED_KEYS = {"schema_version"}
|
NOT_REACHED_KEYS = {"schema_version"}
|
||||||
|
IDENTITY_KEYS = {"standard", "companion"}
|
||||||
|
IDENTITY_VERSION = re.compile(r"\bv?\d+\.\d+", re.I)
|
||||||
|
|
||||||
|
|
||||||
def find_version_pins(node, where: str = "") -> list[str]:
|
def find_version_pins(node, where: str = "", identity: bool = False) -> list[str]:
|
||||||
"""Every place in a parsed declaration that carries a standard/companion version.
|
"""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
|
Walks every key and value (comments are gone after parsing, which is the
|
||||||
|
|
@ -92,12 +99,14 @@ def find_version_pins(node, where: str = "") -> list[str]:
|
||||||
if VERSION_KEY.search(str(k)):
|
if VERSION_KEY.search(str(k)):
|
||||||
pins.append(f"{here} (key names a standard/companion version)")
|
pins.append(f"{here} (key names a standard/companion version)")
|
||||||
continue
|
continue
|
||||||
pins.extend(find_version_pins(v, here))
|
pins.extend(find_version_pins(v, here, str(k).lower() in IDENTITY_KEYS))
|
||||||
elif isinstance(node, list):
|
elif isinstance(node, list):
|
||||||
for i, v in enumerate(node):
|
for i, v in enumerate(node):
|
||||||
pins.extend(find_version_pins(v, f"{where}[{i}]"))
|
pins.extend(find_version_pins(v, f"{where}[{i}]", identity))
|
||||||
elif isinstance(node, str) and VERSION_IN_VALUE.search(node):
|
elif isinstance(node, str) and VERSION_IN_VALUE.search(node):
|
||||||
pins.append(f"{where} = {node!r} (value carries a version)")
|
pins.append(f"{where} = {node!r} (value carries a version)")
|
||||||
|
elif isinstance(node, str) and identity and IDENTITY_VERSION.search(node):
|
||||||
|
pins.append(f"{where} = {node!r} (identity-bearing value carries a version)")
|
||||||
return pins
|
return pins
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,21 @@ class TestDeclaration:
|
||||||
assert checker.find_version_pins({"layer": "Staff", "companion_version": "0.2"})
|
assert checker.find_version_pins({"layer": "Staff", "companion_version": "0.2"})
|
||||||
assert checker.find_version_pins({"nested": {"standard_version": "0.7"}})
|
assert checker.find_version_pins({"nested": {"standard_version": "0.7"}})
|
||||||
|
|
||||||
|
def test_version_token_in_identity_value_is_a_pin(self):
|
||||||
|
"""GH-DEC-2026-021 §3: any `v?N.N` in a standard:/companion: value is a pin."""
|
||||||
|
checker = _checker()
|
||||||
|
pins = checker.find_version_pins({"standard": "security-layer-model v0.7"})
|
||||||
|
assert pins and pins[0].startswith("standard")
|
||||||
|
assert checker.find_version_pins({"companion": "SECURITY-COMPANION 0.2"})
|
||||||
|
assert checker.find_version_pins({"nested": {"standard": ["security-layer-model v0.8"]}})
|
||||||
|
|
||||||
|
def test_prose_citation_and_intent_version_are_not_reached(self):
|
||||||
|
"""GH-DEC-2026-021 §1 (A12 r3): prose provenance and `intent_version` pass."""
|
||||||
|
checker = _checker()
|
||||||
|
assert checker.find_version_pins(
|
||||||
|
{"layer": "Staff", "note": "Outside §5 by the v0.5 scope rule", "intent_version": "0.1.0"}
|
||||||
|
) == []
|
||||||
|
|
||||||
def test_schema_version_is_not_reached(self):
|
def test_schema_version_is_not_reached(self):
|
||||||
assert _checker().find_version_pins({"schema_version": "0.2", "layer": "Staff"}) == []
|
assert _checker().find_version_pins({"schema_version": "0.2", "layer": "Staff"}) == []
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,15 +122,16 @@ from this page.
|
||||||
(`tests/test_layer_conformance.py` has the reference set). Change declaration,
|
(`tests/test_layer_conformance.py` has the reference set). Change declaration,
|
||||||
checker and tests in the same commit, and re-spell no layer value.
|
checker and tests in the same commit, and re-spell no layer value.
|
||||||
|
|
||||||
### Reference detector and `VALIDATED_AGAINST` — practice, not a ruling
|
### Reference detector and `VALIDATED_AGAINST` — the estate reference (`GH-DEC-2026-021`)
|
||||||
|
|
||||||
The estate's checkers each wrote their own version detector in the 020 round, and
|
The estate's checkers each wrote their own version detector in the 020 round, and
|
||||||
they diverge: some flag any key *ending* in `version`, some any key *containing*
|
they diverge: some flag any key *ending* in `version`, some any key *containing*
|
||||||
it, one flags `vN.N` anywhere in prose while the others ignore prose. The
|
it, one flags `vN.N` anywhere in prose while the others ignore prose. The
|
||||||
checkers also disagree on what `VALIDATED_AGAINST` names. Neither point is
|
checkers also disagree on what `VALIDATED_AGAINST` names. `GH-DEC-2026-021` §3
|
||||||
ruled by `GH-DEC-2026-020`. What follows is the reference form to copy so the
|
rules that the detector below is the **estate reference** every checker's copy
|
||||||
copies stop diverging; it is steward's practice, and a gate-house ruling wins
|
converges on — when the copy is next edited, and no later than the commit that
|
||||||
over it.
|
re-points its `VALIDATED_AGAINST` after the v0.8 flip (`GH-WP-0004-T11`). Each
|
||||||
|
repository implements its own copy.
|
||||||
|
|
||||||
**One detector.** Copy this from ops-warden's checker as-is:
|
**One detector.** Copy this from ops-warden's checker as-is:
|
||||||
|
|
||||||
|
|
@ -138,35 +139,50 @@ over it.
|
||||||
VERSION_KEY = re.compile(r"(standard|companion).*version|version.*(standard|companion)", re.I)
|
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)
|
VERSION_IN_VALUE = re.compile(r"[_\-.]v\d+(\.\d+)*(\.md)?\b|@v?\d+\.\d+", re.I)
|
||||||
NOT_REACHED_KEYS = {"schema_version"}
|
NOT_REACHED_KEYS = {"schema_version"}
|
||||||
|
IDENTITY_KEYS = {"standard", "companion"}
|
||||||
|
IDENTITY_VERSION = re.compile(r"\bv?\d+\.\d+", re.I)
|
||||||
|
|
||||||
def find_version_pins(node, where=""): # walk every parsed key and value
|
def find_version_pins(node, where="", identity=False): # walk every parsed key and value
|
||||||
... # see scripts/check_layer_conformance.py
|
... # see scripts/check_layer_conformance.py
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Keys:** flag a key that names a *standard or companion* version
|
- **Keys:** flag a key that names a *standard or companion* version
|
||||||
(`standard_version`, `companion_version`, `standard_version_reviewed`) — not
|
(`standard_version`, `companion_version`, `standard_version_reviewed`) — not
|
||||||
every key containing `version`. `schema_version` is the file's own schema and
|
every key containing `version`. `schema_version` is the file's own schema and
|
||||||
is skipped (A12 r2).
|
is skipped (A12 r2). **Do not flag a key such as `intent_version`**: it names
|
||||||
|
neither the standard nor its companion. `informed-decision`'s declaring
|
||||||
|
frontmatter carries `intent_version: 0.1.0` (the version of its own
|
||||||
|
`INTENT.md`), and a detector that flags every key containing or ending in
|
||||||
|
`version` fails it wrongly (`GH-DEC-2026-021`, Context).
|
||||||
- **Values:** flag a version carried in a *file name or path* (`_v0.7`,
|
- **Values:** flag a version carried in a *file name or path* (`_v0.7`,
|
||||||
`-v0.8.md`, `@0.7`) — the `standard: …_v0.7.md` case §1 rules on.
|
`-v0.8.md`, `@0.7`) — the `standard: …_v0.7.md` case §1 rules on.
|
||||||
|
- **Identity-bearing values:** any version token (`v?N.N`) in the value of a
|
||||||
|
`standard:` or `companion:` key is a pin (`GH-DEC-2026-021` §3), so
|
||||||
|
`standard: security-layer-model v0.7` fails.
|
||||||
|
- **Deliberate over-reach:** the path pattern flags a versioned path of *any*
|
||||||
|
document in a declaration, wider than A12's "this standard or its companion".
|
||||||
|
`GH-DEC-2026-021` §3 accepts this; a repository that needs such a path raises
|
||||||
|
it, and it is not waived by allowlist.
|
||||||
- **Comments:** never read; the detector runs on parsed YAML, so they are gone.
|
- **Comments:** never read; the detector runs on parsed YAML, so they are gone.
|
||||||
- **Prose citations in a value** (e.g. a rationale string saying "the v0.5 scope
|
- **Prose citations in a value** (e.g. a rationale string saying "the v0.5 scope
|
||||||
rule"): **pending.** Whether A12 reaches them is an open question to
|
rule"): **not reached** (`GH-DEC-2026-021` §1, A12 r3). A revision cited in
|
||||||
gate-house. The reference detector deliberately does not flag a bare `vN.N`
|
prose is provenance, not a pin. The reference detector does not flag a bare
|
||||||
preceded by a space, so it neither enforces nor waives an answer that has not
|
`vN.N` outside a `standard:`/`companion:` value, and no allowlist is needed.
|
||||||
been given. Do not widen or narrow this in your copy until gate-house rules.
|
A12 r3 is out for assent; if it is rejected in favour of the literal reading,
|
||||||
|
the reference is widened to any `vN.N` in any value.
|
||||||
|
|
||||||
**Name the text in force.** While v0.8's acceptance flip is held
|
**Name the text in force.** While v0.8's acceptance flip is held
|
||||||
(`GH-DEC-2026-019`), `VALIDATED_AGAINST` names the **accepted** text —
|
(`GH-DEC-2026-019`), `VALIDATED_AGAINST` names the **accepted** text —
|
||||||
`security-layer-model_v0.7.md`, with a net-kingdom commit — plus the decision
|
`security-layer-model_v0.7.md`, with a net-kingdom commit — plus the decision
|
||||||
records whose amendments already govern (`GH-DEC-2026-017`, `GH-DEC-2026-020`),
|
records whose rulings the checker enforces beyond v0.7 (`GH-DEC-2026-017`,
|
||||||
with a gate-house commit. Naming the proposed v0.8 states a check against text
|
`GH-DEC-2026-020`, `GH-DEC-2026-021`), with a gate-house commit recommended
|
||||||
|
(`GH-DEC-2026-021` §2). Naming the proposed v0.8 states a check against text
|
||||||
that does not yet govern. Change it in the same commit that follows the flip.
|
that does not yet govern. Change it in the same commit that follows the flip.
|
||||||
ops-warden's constant is the example:
|
ops-warden's constant is the example:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
net-kingdom/canon/standards/security-layer-model_v0.7.md (net-kingdom@66dc491)
|
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)
|
as amended by GH-DEC-2026-017, GH-DEC-2026-020 and GH-DEC-2026-021 (A9-A13, A12 r3; gate-house@39d9287)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Citation.** Cite the ruling by the decision's body section: `GH-DEC-2026-017`
|
**Citation.** Cite the ruling by the decision's body section: `GH-DEC-2026-017`
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue