Skip to content

Commit 9b3617d

Browse files
hyperpolymathclaude
andcommitted
chore(governance): salvage net-new svc/k9 set only — drop superseded scaffold
main's 2026-06-12 checkpoint (5f109f5) + submodule removal (9c26f95) already supersede the bulk of this PR. Merging as-is would have regressed canonical work: main's FLAT contractiles (Bustfile/Mustfile at contractiles/ root vs this branch's nested bust//must/ variants), the 6a2 files, estate-standard bot_directives, and main's deletion of anchors/ANCHOR.a2ml. Rebuilt on current main with ONLY the genuinely net-new, structurally-canonical content: the .machine_readable/svc/k9/ validator set that main's own svc/README.adoc promises under ADR-001 but does not yet contain. This FIXES main's dangling ADR-001 reference. All MPL-2.0, additive, zero conflicts. Excluded as superseded/regressive: 6a2/*, bot_directives/*, nested contractiles, anchors (main-deleted), wiki/* (main canonical), 0-AI-MANIFEST. No LICENSE/SPDX. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 9c26f95 commit 9b3617d

4 files changed

Lines changed: 306 additions & 0 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// SPDX-License-Identifier: MPL-2.0
2+
= K9 Contractiles — nextgen-languages self-validation
3+
:toc: left
4+
:icons: font
5+
6+
== Why K9 lives here
7+
8+
Per **ADR-001 (2026-04-18)** (see `../README.adoc`), K9 self-validating
9+
components live under `.machine_readable/svc/k9/` rather than under
10+
`contractiles/`, so the contractile directory stays a pure six-verb set
11+
(intend, trust, must, bust, adjust, dust). The verb contractiles *declare*
12+
invariants; the K9 validators here *machine-check* them.
13+
14+
NOTE: `../../MUST.contractile` historically points its `enforcement` at
15+
`contractiles/k9/must-check.k9.ncl`. The canonical location is here
16+
(`svc/k9/must-check.k9.ncl`) per ADR-001; the stale path in MUST.contractile
17+
is a known doc gap (it lives outside this sweep's write-scope and is left as
18+
a TODO for a future MUST.contractile refresh).
19+
20+
== The Leash — three security levels
21+
22+
K9 components declare their trust requirements:
23+
24+
[horizontal]
25+
`'Kennel`:: Pure data, no execution (safest; no signature)
26+
`'Yard`:: Nickel evaluation with contracts (medium trust; signature recommended)
27+
`'Hunt`:: Full execution with Just recipes (signature *required*)
28+
29+
== Components in this directory
30+
31+
`must-check.k9.ncl`:: **Yard.** The runnable surface of the hard invariants
32+
declared in `../../MUST.contractile` and
33+
`../../contractiles/must/Mustfile.a2ml`. CI runs it on every PR
34+
(`quality.yml`); violations of `error`-severity checks block merge.
35+
36+
`methodology-guard.k9.ncl`:: **Yard.** Checks that agent work respects the
37+
methodology constraints in `../../agent_instructions/methodology.a2ml`
38+
(believe_me / assert_total ceilings, state-file template-placeholder
39+
rejection, coverage staleness).
40+
41+
`template-kennel.k9.ncl`:: **Kennel.** Starting point for new pure-data K9
42+
components.
43+
44+
== Validate / run
45+
46+
[source,bash]
47+
----
48+
# Typecheck a Yard/Kennel component (no I/O)
49+
nickel typecheck svc/k9/must-check.k9.ncl
50+
51+
# Evaluate a Yard component (validation, no side effects)
52+
nickel eval svc/k9/methodology-guard.k9.ncl
53+
54+
# Export Kennel data
55+
nickel export svc/k9/template-kennel.k9.ncl > out.json
56+
----
57+
58+
== Dependencies
59+
60+
* **Nickel** — configuration language and contract evaluator.
61+
* **k9-svc** (https://github.com/hyperpolymath/k9-svc) — the `must` shim,
62+
signing, and the full SPEC. IANA media type `application/vnd.k9+nickel`.
63+
64+
== Adding a K9 component
65+
66+
1. Pick the lowest sufficient leash (Kennel > Yard > Hunt).
67+
2. Document what it does in the `pedigree.metadata.description`.
68+
3. Put real contracts in Yard/Hunt components — a Yard file with no
69+
contracts is just a Kennel file in disguise.
70+
4. Sign Hunt components before committing; never run unsigned Hunt.
71+
5. Wire `error`-severity validators into `quality.yml`.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
#
4+
# K9 Validator: Methodology Guard (nextgen-languages)
5+
# Security Level: Yard (Nickel evaluation; no I/O)
6+
#
7+
# Checks that agent work respects the methodology constraints declared in
8+
# ../../agent_instructions/methodology.a2ml.
9+
#
10+
# Usage: k9 validate methodology-guard
11+
12+
let methodology_guard = {
13+
name = "methodology-guard",
14+
version = "1.0.0",
15+
description = "Validates that agent work respects declared methodology constraints",
16+
17+
source_of_truth = ".machine_readable/agent_instructions/methodology.a2ml",
18+
19+
checks = {
20+
believe_me_ceiling = {
21+
description = "believe_me count must not exceed the declared ceiling",
22+
severity = "error",
23+
pattern = "believe_me",
24+
ceiling_key = "methodology.divergent-invariants.believe-me-ceiling",
25+
default_ceiling = 0,
26+
note = "Hub-level scan; submodule trees enforce their own ceilings.",
27+
},
28+
29+
assert_total_ceiling = {
30+
description = "assert_total count must not exceed the declared ceiling",
31+
severity = "error",
32+
pattern = "assert_total",
33+
ceiling_key = "methodology.divergent-invariants.assert-total-ceiling",
34+
default_ceiling = 0,
35+
},
36+
37+
state_not_template = {
38+
description = "STATE.a2ml must not contain template placeholders",
39+
severity = "warning",
40+
file = ".machine_readable/6a2/STATE.a2ml",
41+
reject_patterns = ["{{PLACEHOLDER}}", "{{PROJECT}}", "rsr-template-repo"],
42+
reject_key = "methodology.state-validation.reject-if-contains",
43+
},
44+
45+
state_not_stale = {
46+
description = "STATE.a2ml last-updated should be within the staleness threshold",
47+
severity = "info",
48+
file = ".machine_readable/6a2/STATE.a2ml",
49+
staleness_key = "methodology.state-validation.staleness-threshold-days",
50+
default_staleness_days = 90,
51+
},
52+
53+
coverage_updated = {
54+
description = "coverage.a2ml should be refreshed within 30 days",
55+
severity = "info",
56+
file = ".machine_readable/agent_instructions/coverage.a2ml",
57+
staleness_days = 30,
58+
},
59+
60+
spike_required = {
61+
description = "Sessions must ship code, not only designs (methodology.spike-required)",
62+
severity = "info",
63+
key = "methodology.spike-required",
64+
expected = true,
65+
},
66+
},
67+
68+
# KNOWN GAP: methodology.a2ml still carries template defaults for
69+
# unique-strength, divergent-invariants.rules, and known-constraints.
70+
# Until those are filled, the divergent-mode checks fall back to defaults.
71+
open_gaps = [
72+
"methodology.unique-strength.description == {{PROJECT_UNIQUE_STRENGTH}}",
73+
"methodology.divergent-invariants.rules == []",
74+
"methodology.known-constraints.constraints == []",
75+
],
76+
}
77+
in methodology_guard
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
K9!
2+
# SPDX-License-Identifier: MPL-2.0
3+
# K9 Yard-level validator: MUST-check
4+
# Security Level: Yard (Nickel evaluation with contracts; no I/O)
5+
#
6+
# Runnable surface of the hard invariants declared in
7+
# ../../MUST.contractile and ../../contractiles/must/Mustfile.a2ml.
8+
# CI (quality.yml) runs this on every PR; `error`-severity failures block
9+
# merge. Keep the check IDs aligned with Mustfile.a2ml section names.
10+
11+
{
12+
pedigree = {
13+
schema_version = "1.0.0",
14+
component_type = "must-validator",
15+
security = {
16+
leash = 'Yard,
17+
trust_level = "validated-config",
18+
allow_network = false,
19+
allow_filesystem_write = false,
20+
allow_subprocess = false,
21+
},
22+
metadata = {
23+
name = "must-check",
24+
version = "1.0.0",
25+
description = "Machine-checks the nextgen-languages MUST invariants (hub-level hygiene; submodule trees are each repo's own concern).",
26+
author = "Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>",
27+
paired_files = [
28+
"../../MUST.contractile",
29+
"../../contractiles/must/Mustfile.a2ml",
30+
],
31+
},
32+
},
33+
34+
# Each check declares a severity and a shell predicate (exit 0 = pass).
35+
# A K9 'Yard runner evaluates these; it does not itself run the shell —
36+
# the predicate string is handed to the CI executor named in `run`.
37+
checks = {
38+
license_present = {
39+
description = "LICENSE file must exist",
40+
severity = 'error,
41+
predicate = "test -f LICENSE",
42+
},
43+
44+
ai_manifest_present = {
45+
description = "0-AI-MANIFEST.a2ml entry point must exist",
46+
severity = 'error,
47+
predicate = "test -f 0-AI-MANIFEST.a2ml",
48+
},
49+
50+
machine_readable_dir = {
51+
description = ".machine_readable/ directory preserved",
52+
severity = 'error,
53+
predicate = "test -d .machine_readable",
54+
},
55+
56+
no_root_scm_duplication = {
57+
description = "No STATE/META/ECOSYSTEM state file orphaned in repo root (canonical home is .machine_readable/6a2/)",
58+
severity = 'error,
59+
predicate = "! ls STATE.* META.* ECOSYSTEM.* 2>/dev/null | head -1 | grep -q .",
60+
},
61+
62+
six_a_two_complete = {
63+
description = "The 6a2 metadata set is complete (>= 6 .a2ml files)",
64+
severity = 'warning,
65+
predicate = "test $(ls .machine_readable/6a2/*.a2ml 2>/dev/null | wc -l) -ge 6",
66+
},
67+
68+
spdx_on_machine_readable = {
69+
description = "Every .a2ml under .machine_readable/ carries an SPDX header",
70+
severity = 'warning,
71+
predicate = "! grep -rL 'SPDX-License-Identifier' .machine_readable --include='*.a2ml' 2>/dev/null | head -1 | grep -q .",
72+
},
73+
74+
no_agpl = {
75+
description = "No AGPL references in dotfiles (estate policy is MPL-2.0)",
76+
severity = 'error,
77+
predicate = "! grep -rE 'AGPL-3[.]0' .gitignore .gitattributes .editorconfig 2>/dev/null | head -1 | grep -q .",
78+
},
79+
80+
actions_sha_pinned = {
81+
description = "Third-party GitHub Actions are SHA-pinned (reusable callers to hyperpolymath/standards excepted)",
82+
severity = 'warning,
83+
predicate = "! grep -rEn 'uses:[[:space:]]+[^#]+@(main|master|v[0-9]+)[[:space:]]*$' .github/workflows 2>/dev/null | grep -v 'hyperpolymath/standards' | head -1 | grep -q .",
84+
},
85+
86+
hypatia_waiver_registry = {
87+
description = "Hypatia accepted-findings registry exists (NEUROSYM.a2ml)",
88+
severity = 'warning,
89+
predicate = "grep -q '\\[accepted-findings\\]' .machine_readable/6a2/NEUROSYM.a2ml",
90+
},
91+
92+
kitchenspeak_postulate_axiom = {
93+
description = "KitchenSpeak Agda postulates remain annotated as trusted base (AXIOM marker)",
94+
severity = 'warning,
95+
predicate = "test ! -d kitchenspeak/proofs/agda || ! grep -rl 'postulate' kitchenspeak/proofs/agda --include='*.agda' 2>/dev/null | xargs -r grep -L 'AXIOM' 2>/dev/null | head -1 | grep -q .",
96+
},
97+
},
98+
99+
run = {
100+
executor = "ci:quality.yml",
101+
on_error_severity = "exit-nonzero", # error-severity failures block merge
102+
on_warning_severity = "report-only",
103+
report_format = "a2ml",
104+
},
105+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
K9!
2+
# SPDX-License-Identifier: MPL-2.0
3+
# K9 Kennel-level template: Pure data configuration
4+
# Security Level: Kennel (data-only, no execution)
5+
# No signature required — safe for any use.
6+
7+
{
8+
pedigree = {
9+
schema_version = "1.0.0",
10+
component_type = "TODO: describe component type (e.g., 'language-metadata', 'build-config')",
11+
security = {
12+
leash = 'Kennel,
13+
trust_level = "data-only",
14+
allow_network = false,
15+
allow_filesystem_write = false,
16+
allow_subprocess = false,
17+
},
18+
metadata = {
19+
name = "TODO: component-name",
20+
version = "1.0.0",
21+
description = "TODO: Brief description of what this component contains",
22+
author = "Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>",
23+
},
24+
},
25+
26+
# Pure data only. No contracts, no recipes — promote to template-yard
27+
# (Nickel contracts) or a Hunt component if you need validation/execution.
28+
config = {
29+
setting_1 = "value",
30+
setting_2 = 42,
31+
setting_3 = true,
32+
33+
nested = {
34+
key = "value",
35+
},
36+
37+
list = [
38+
"item1",
39+
"item2",
40+
],
41+
},
42+
43+
export = {
44+
format = "json", # or "yaml", "toml"
45+
destination = "output.json",
46+
},
47+
}
48+
49+
# Usage:
50+
# 1. Fill in TODO items above.
51+
# 2. Replace config = { ... } with your data.
52+
# 3. Validate: nickel typecheck your-file.k9.ncl
53+
# 4. Export: nickel export your-file.k9.ncl > output.json

0 commit comments

Comments
 (0)