Repository navigation
fix(k9): validate K9 with the canonical validator; bring every K9 record to contract v1.0.0 #124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0cf8011
47894e8
d408483
ea156b4
9bda496
a661b77
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| #!/usr/bin/env bash | ||
| # SPDX-License-Identifier: MPL-2.0 | ||
| # Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk> | ||
| # | ||
| # validate-k9.sh — pre-push K9 check, through the canonical validator. | ||
| # | ||
| # One validator per family (hyperpolymath/standards, | ||
| # docs/CONTRACTILE-DESCRIPTILE-VALIDATION.adoc): the grep checks that used to | ||
| # live here were a second validator, and they accepted files that contract | ||
| # v1.0.0 (D173) rejects. This runs 1-formats/k9/tools/k9-validate.sh from a | ||
| # standards checkout over the tracked K9 files, strict, layers L0–L2 (L0–L1 | ||
| # when nickel is not installed), as the k9-conformance lane does in CI (.github/workflows/dogfood-gate.yml). The lane | ||
| # is the gate; this is the early warning. | ||
| # | ||
| # Environment variables: | ||
| # INPUT_PATH — Repository to check (default: .) | ||
| # STANDARDS_DIR — A hyperpolymath/standards checkout | ||
| # (default: ../standards beside the repository) | ||
| # | ||
| # Exit codes: | ||
| # 0 — Every tracked K9 file passes, or no validator is available (skipped | ||
| # with a notice: CI still runs the lane) | ||
| # 1 — A file failed | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| REPO="${INPUT_PATH:-.}" | ||
| STANDARDS_DIR="${STANDARDS_DIR:-$(cd "$REPO/.." && pwd)/standards}" | ||
| case "$STANDARDS_DIR" in | ||
| /*) ;; | ||
| *) STANDARDS_DIR="$PWD/$STANDARDS_DIR" ;; | ||
| esac | ||
| VALIDATOR="$STANDARDS_DIR/1-formats/k9/tools/k9-validate.sh" | ||
|
|
||
| if [ ! -f "$VALIDATOR" ]; then | ||
|
Check failure on line 35 in .github/hooks/validate-k9.sh
|
||
| echo "::notice::K9: no standards checkout at $STANDARDS_DIR (set STANDARDS_DIR to run the validator locally); the k9-conformance lane validates in CI" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # L2 is the Nickel evaluation against the contract; without nickel the | ||
| # validator reports those checks as SKIPPED and refuses to call that a pass, | ||
| # so stop at L1 here and say so. The lane checks L2 in CI either way. | ||
| LAYER=L2 | ||
| if ! command -v nickel >/dev/null 2>&1; then | ||
| echo "::notice::K9: nickel is not installed, so layer L2 (Nickel semantics) is left to the CI lane; checking L0–L1" | ||
| LAYER=L1 | ||
| fi | ||
|
|
||
| cd "$REPO" | ||
| mapfile -t files < <(git ls-files -- '*.k9.ncl' '*.k9' '*.k9.lock' | sort) | ||
| if [ "${#files[@]}" -eq 0 ]; then | ||
|
Check failure on line 51 in .github/hooks/validate-k9.sh
|
||
| echo "::notice::K9: no tracked K9 file" | ||
| exit 0 | ||
| fi | ||
|
|
||
| errors=0 | ||
| for f in "${files[@]}"; do | ||
| echo " Validating: $f" | ||
| if ! bash "$VALIDATOR" --strict --layer "$LAYER" "$f"; then | ||
| errors=$((errors + 1)) | ||
| fi | ||
| done | ||
|
|
||
| echo "K9: ${#files[@]} file(s), ${errors} failing (validator: $VALIDATOR)" | ||
| [ "$errors" -eq 0 ] || { echo "::error::K9 validation failed for ${errors} file(s)"; exit 1; } | ||
|
Check failure on line 65 in .github/hooks/validate-k9.sh
|
||
| echo "K9 validation passed." | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyone following this new copy command gets a file that cannot pass the canonical validator:
setup-repo.k9.ncl.incontains no placeholders to fill, still uses the Nickel 1.18 reserved field namerecipes.default, and its Hunt pedigree has neither an explicit capability grant nor the required signature and side-effect declarations. Because the new hook deliberately excludes.k9.ncl.in, CI does not expose this until a user copies it to.k9.ncl; either make the example a conforming component or add real render/sign substitutions that produce one.Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is real, but this PR didn't introduce it, so I'm not fixing it here. Before this PR the same file was
setup-repo.k9.ncl, and the canonical validator already rejected it. This PR renames it to.inand corrects the copy path. The renamed file also matches rsr-template-repo's ownsetup-repo.k9.ncl.in, which is where the fix belongs.The fix should land in rsr-template-repo first, then be copied here. It means turning the example into a conforming Hunt component: rename the reserved
recipes.defaultfield, and add the explicit capability grant, the side effects and the signature block. In this repo's copy it also means dropping the steps that write.a2mlfiles and fetch a PMPL licence. I'm leaving this thread open for the owner to schedule that follow-up.Generated by Claude Code