Skip to content

feat(k9): vnd.k9.coordination subtype, coordination grammar v1.2.0, native signed-push - #1233

Merged
hyperpolymath merged 5 commits into
mainfrom
claude/exciting-noether-dzrfrr
Oct 13, 2026
Merged

hyperpolymath merged 5 commits into
mainfrom
claude/exciting-noether-dzrfrr

Conversation

@hyperpolymath

@hyperpolymath hyperpolymath commented Oct 13, 2026 •

Copy link
Copy Markdown
Owner

Follow-up to #1232. This PR covers its three open items, each in its own commit, plus two fix-ups.

1. application/vnd.k9.coordination (owner ruling 2026-10-13: own subtype, not a parameter)

  • New registration draft: 2-protocols/k9-coordination/docs/iana/application-vnd.k9.coordination-registration.txt. The format is pure data, with a YAML-like body governed by its own ABNF, and uses the .k9 extension.
  • vnd.k9 registration (Revision 4) and its form-ready copy:
    • the open decision is settled;
    • the type claims only .k9.ncl;
    • it is ready to file alongside the companion type.
  • MIME recipes in SPEC.adoc:
    • The two types get separate freedesktop entries. Filename globs decide the type; for files with no extension, a nested metadata: match tells the two apart. Checked against every committed .k9 and .k9.ncl file.
    • A UTI is added for the new type.
    • A note says mime.types cannot express .k9.ncl.
  • The K9 contract spec and the coordination spec now name each dialect's media type.

2. Coordination grammar v1.2.0; the repo's own coordination.k9 conforms

(Owner ruling: extend the grammar for what belongs, move the rest out.)

  • New coordination-k9-grammar_v1.2.abnf adds two optional sections: build_commands and innervation (afferent / efferent / reflex). The change is additive, so every v1.1.1 file is still valid.
  • The v1.1 file stays, marked superseded, so existing links resolve. Every in-repo reference now points to v1.2.
  • The root coordination.k9 now parses under v1.2.0. I checked this with an ABNF parser (apg-js), and the file correctly fails v1.1.
    • Before this change, it failed at its --- line.
    • Moved out: ports, verisimdb_port and crg_grade. A2ML is retired, so neither fact went into a .a2ml file:
      • The VeriSimDB port is already set in .verisimdb/config.toml.
      • The CRG grade (B) belongs in a root READINESS.md under the CRG spec, and just crg-grade reads it from there. This repo has no READINESS.md yet, so the coordination.k9 header comment records the grade and where it belongs.
    • Stale facts corrected:
      • the languages now match the tree;
      • the protected entries for the deleted a2ml/ and lol/ are gone;
      • the banned-language lines follow the current policy.
  • Flagged, not changed: the pmpl-license-only invariant contradicts this repo's MPL-2.0 classification. Licence content is flag-only.
  • The generator's parser reads the new file. As a side effect, consumers now parses as a list instead of a string.

3. signed-push without Asana/push-signed-commits

The Asana action is written in Python and has no licence file. It also uses the tag-pinned setup-python@v2 and runs an unpinned pip install. It is replaced by .github/actions/signed-push/push-verified.sh, which uses bash, gh and jq to call createCommitOnBranch.

  • Same contract as before:
    • the remote branch must exist and must not have diverged;
    • commits are replayed oldest first with their messages, and each call names the head it expects;
    • the local branch is reset to the remote afterwards.
  • Stricter than before:
    • binary files are pushed intact;
    • merges, symlinks, submodules and mode changes are refused before anything is sent;
    • the pushed tree is compared with the local one.
  • Tests: scripts/tests/signed-push-test.sh runs 13 cases against a stub GitHub, with no shellcheck warnings. Writing it caught a real partial-push bug in my first draft, which is now fixed. A mutant that stops sending deletions fails 4 cases.
  • Lock entries left in place: the now-unused asana/push-signed-commits and actions/setup-python@v2 records are not hand-edited out of actions.lock. All lock gates pass with them present, and the next tool regeneration drops them.
  • Not changed: the regen job's composite guard (Lock repair chain drops composite-action edges, and --verify-local accepts the result #1122). prune-stale still cannot see refs that a workflow reaches through a local action, so action bumps here still need a hand-run regeneration. Relaxing the guard safely needs a live check of how GitHub validates locks for local composites.

Testing

  • ABNF: minimal.k9, the spec's new examples and the root coordination.k9 pass v1.2. Negative controls fail.
  • k9-validate.sh --self-test and the validate-k9 hook pass.
  • Script tests: signed-push-test 13/13, validate-sha-pins-test 22/22 (with mikefarah yq), descriptile-policy-test 11/11. The docstring scan shows 100% on the new code.
  • Lock gates pass: validate-actions-lock and check-lock-sync. These also pass: check-workflow-duplicate-keys, check-standards-map, check-canon-lockstep.
  • Full shell suite: 77 of 81 files pass locally. The other 4 fail identically on main here, because this sandbox lacks KYAML-capable yq, the JCS tool and Ruby. CI is the authority for those four: check-actions-lock-gate, check-ijson-jcs, kyaml-format and science-ci-security.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GqfpQtLuMczxtgG1U9PkLW


Generated by Claude Code

Owner ruling, 2026-10-13: the k9-coordination dialect gets its own
subtype rather than a parameter of application/vnd.k9. File-type
detectors drop parameters, which would label coordination files as
Nickel components; a subtype survives that and lets each type state its
own encoding and security considerations.

- New registration draft for application/vnd.k9.coordination beside the
  coordination spec (pure data, YAML-like body under its own ABNF, .k9).
- vnd.k9 registration (Revision 4) and its form-ready copy: the open
  decision is settled, the type claims only .k9.ncl, and it is ready to
  file together with the companion type.
- SPEC.adoc MIME recipes: separate freedesktop entries (globs decide;
  a nested "metadata:" match tells extensionless files apart, verified
  against every committed .k9 and .k9.ncl file), a UTI for the new type,
  and a mime.types note that it cannot express .k9.ncl.
- K9-CONTRACT-SPEC and COORDINATION-K9-SPEC name the media type of each
  dialect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GqfpQtLuMczxtgG1U9PkLW
Owner ruling, 2026-10-13: extend the grammar for what belongs in a
coordination file, and move the rest out.

Grammar v1.2.0 (coordination-k9-grammar_v1.2.abnf), additive: every
v1.1.1 file is a v1.2.0 file.
- build_commands (between project and invariants): command + purpose.
- innervation (between architecture and do_not_create): afferent
  signals with their consumers, efferent signals with auto_fix, and
  reflex guards.
- Comments are ASCII as RFC 5234 requires (bar the SPDX copyright line).
The v1.1 file stays, marked superseded, so existing links resolve; the
spec, READMEs, CLAUDE.md, AGENTS/REGISTRY and the K9 contract now point
at v1.2.

Root coordination.k9 now parses under v1.2.0 (checked with an ABNF
parser; it fails v1.1, as it should). Previously it failed at its
`---` line.
- `---` removed; blank lines inside sections removed; repo and glob
  values unquoted; multi-word terminology and ecosystem names made
  tokens; build_commands restructured; innervation consumers are lists.
- Moved out: ports / project.verisimdb_port to ECOSYSTEM.a2ml [ports],
  project.crg_grade to STATE.a2ml [position].
- Stale facts corrected: languages now match the tree (AffineScript and
  Julia in; ReScript, Agda, Elixir out; none are present); protected
  entries for the deleted a2ml/ and lol/ dropped; the banned-language
  rule and the *.ts reason follow the current language policy.
- NOT changed: the pmpl-license-only invariant contradicts this repo's
  MPL-2.0 classification, but licence content is flag-only.

The generator's parser reads the new file (consumers now parse as a
list instead of a string).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GqfpQtLuMczxtgG1U9PkLW
…ed.sh

The signed-push composite action delegated its push to
Asana/push-signed-commits, which is Python (banned here), has no licence
file at the pinned commit, installs Python through the tag-pinned
actions/setup-python@v2 and runs an unpinned `pip install requests` at
run time. The same work is a short bash script over `gh api graphql`
createCommitOnBranch, the pattern scripts/regen-dependabot-locks.sh
already uses.

push-verified.sh keeps the contract (remote branch must exist and must
not have diverged; local commits replayed oldest first with their
messages; each call names the head it expects, so a concurrent push fails
closed; local branch reset to the remote afterwards) and is stricter:
- file contents are base64'd from the raw blob, so binary files survive
  (the Python action decoded them as UTF-8 text);
- merges, symlinks, submodules, executable additions and mode changes,
  none of which createCommitOnBranch can express, are refused before
  anything is sent, and the pushed tree is compared with the local one.

scripts/tests/signed-push-test.sh drives it against a local bare remote
through a stub gh that applies each mutation as GitHub would: 13 cases,
including a partial-push report and the five refusals. Writing it caught
a merge being detected only after earlier commits had been pushed; every
commit is now validated and prepared before the first call. A mutant
that stops sending deletions fails 4 of the cases.

The asana/push-signed-commits and actions/setup-python@v2 records stay in
actions.lock for now: nothing references them, every lock gate passes
with them present, and the file is regenerated by tooling, not by hand.
The next regeneration drops them.

The regen job's composite guard (#1122) is unchanged. prune-stale still
cannot see refs a workflow reaches through a local action, so this repo
still needs a hand-run regeneration after action bumps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GqfpQtLuMczxtgG1U9PkLW
@github-actions

Copy link
Copy Markdown
Contributor

K9 contract conformance

run https://github.com/hyperpolymath/standards/actions/runs/38475956439

K9 normative contract typecheck

k9_contract.ncl typechecks

K9 contract self-test

== the bash mirrors cannot drift from the normative contract ==
ok   leash_levels mirrors k9_contract.ncl
ok   core_capabilities mirrors k9_contract.ncl
ok   contract_version mirrors k9_contract.ncl
ok   schema_major mirrors k9_contract.ncl
== capability arithmetic (§8) ==
ok   capability_ok fs.read accepted
ok   capability_ok rollback.apply accepted
ok   capability_ok x-acme.gpu.alloc accepted
ok   capability_ok x-acme rejected
ok   capability_ok x-.gpu rejected
ok   capability_ok fs.delete rejected
ok   capability_ok  rejected
== the extractor ==
ok   extracts pedigree.security.leash
ok   extracts pedigree.component_type
ok   extracts pedigree.metadata.name
ok   pedigree leash is not reported as top-level leash
ok   required_capabilities for a quiet component
ok   required_capabilities follows allow_network
== the envelope strip keeps line numbers (§3.6) ==
ok   line 1 becomes a comment
ok   line count is preserved
ok   schema_version stays on line 5
== L3: signature presence is not verification (§10) ==
ok   no verifier -> K9-C001 is SKIPPED, never a pass
ok   the skip states presence does not authorise 'Hunt
ok   verifier accepts -> verdict 'Verified, no K9-C001 finding
ok   verifier refuses -> K9-C001 error, verdict 'Rejected
== the fixture runner's attribution cannot be fooled by a filename ==
ok   every extracted finding is well-formed rule+layer
ok   the rule that really fired is attributed
ok   a rule named only in the filename is NOT attributed
ok   K9-C001 is present as a skipped finding
ok   and that same finding is NOT extractable as a rejection
== the dialect discriminator agrees with the coordination grammar (§4.3) ==
ok   magic file opening '---' is coordination
ok   magic file opening 'metadata:' is coordination
ok   plain file opening '---' is unclaimed
ok   plain file opening 'metadata:' is unclaimed
== no Nickel reserved word is used as an identifier ==
ok   the contract and all 27 fixtures avoid Nickel's reserved words

self-test: all assertions passed

K9 conformance fixtures

== positive controls (must pass) ==
ok   extension-capability.k9.ncl
ok   extension-fields.k9.ncl
ok   hunt-fully-granted.k9.ncl
ok   kennel-data.k9.ncl
ok   library-base.ncl
ok   yard-typed-config.k9.ncl

== negative controls (must fail, by the named rule) ==
ok   L0-K9-E001-bad-magic.k9.ncl (rejected by K9-E001 at L0)
ok   L0-K9-E002-nul-byte.k9.ncl (rejected by K9-E002 at L0)
ok   L0-K9-E003-crlf.k9.ncl (rejected by K9-E003 at L0)
ok   L0-K9-E004-no-spdx.k9.ncl (rejected by K9-E004 at L0)
ok   L0-K9-E005-unclaimed-body.k9.ncl (rejected by K9-E005 at L0)
ok   L0-K9-S012-library-with-pedigree.ncl (rejected by K9-S012 at L0)
ok   L0-K9-S014-stray-leash.ncl (rejected by K9-S014 at L0)
ok   L1-K9-S001-no-pedigree.k9.ncl (rejected by K9-S001 at L1)
ok   L1-K9-S002-wrong-major.k9.ncl (rejected by K9-S002 at L1)
ok   L1-K9-S003-todo-component-type.k9.ncl (rejected by K9-S003 at L1)
ok   L1-K9-S004-unknown-leash.k9.ncl (rejected by K9-S004 at L1)
ok   L1-K9-S005-missing-name.k9.ncl (rejected by K9-S005 at L1)
ok   L1-K9-S006-unknown-capability.k9.ncl (rejected by K9-S006 at L1)
ok   L1-K9-S007-ungranted-flag.k9.ncl (rejected by K9-S007 at L1)
ok   L1-K9-S008-hunt-signature-not-required.k9.ncl (rejected by K9-S008 at L1)
ok   L1-K9-S009-hunt-no-signature-block.k9.ncl (rejected by K9-S009 at L1)
ok   L1-K9-S010-hunt-empty-side-effects.k9.ncl (rejected by K9-S010 at L1)
ok   L1-K9-S011-recipes-at-yard.k9.ncl (rejected by K9-S011 at L1)
ok   L1-K9-S013-dangling-import.k9.ncl (rejected by K9-S013 at L1)
ok   L2-K9-N001-two-segment-version.k9.ncl (rejected by K9-N001 at L2)
ok   L2-K9-N001-wrong-field-type.k9.ncl (rejected by K9-N001 at L2)

fixtures: 6 positive, 21 negative (0 needing nickel), 0 failure(s)

K9 corpus conformance (L2)

[validate-k9] 14 conforming, 0 grandfathered (layer all, contract v1.0.0)

@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 2be261c1-9fc7-4f49-bf5e-feb13a2a9f7a
📥 Commits

Reviewing files that changed from the base of the PR and between 4c101fb and 36c99f6.

📒 Files selected for processing: 24
  • .claude/CLAUDE.md
  • .github/actions/signed-push/README.md
  • .github/actions/signed-push/action.yml
  • .github/actions/signed-push/push-verified.sh
  • .machine_readable/descriptiles/ECOSYSTEM.a2ml
  • .machine_readable/descriptiles/STATE.a2ml
  • .meta/REQUIRED-FILES.adoc
  • 1-formats/k9/IANA-MEDIA-TYPE-APPLICATION.adoc
  • 1-formats/k9/SPEC.adoc
  • 1-formats/k9/docs/iana/application-vnd.k9-registration.txt
  • 1-formats/k9/spec/K9-CONTRACT-SPEC.adoc
  • 1-formats/k9/spec/contract/k9_contract.ncl
  • 1-formats/k9/tools/k9-validate.sh
  • 2-protocols/k9-coordination/README.adoc
  • 2-protocols/k9-coordination/docs/iana/application-vnd.k9.coordination-registration.txt
  • 2-protocols/k9-coordination/examples/minimal.k9
  • 2-protocols/k9-coordination/spec/COORDINATION-K9-SPEC.adoc
  • 2-protocols/k9-coordination/spec/abnf/coordination-k9-grammar_v1.1.abnf
  • 2-protocols/k9-coordination/spec/abnf/coordination-k9-grammar_v1.2.abnf
  • AGENTS.adoc
  • README.adoc
  • REGISTRY.adoc
  • coordination.k9
  • scripts/tests/signed-push-test.sh
 _____________________________________________________________
< Please stop using global state like it's a communal fridge. >
 -------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • 🔴 Error committing to branch - (🔄 Check to retry)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@hyperpolymath
hyperpolymath marked this pull request as ready for review October 13, 2026 22:12
Clears the shellcheck warnings CodeFactor raised on the new suite:
SC2164 (cd without a fallback inside the fixture subshells) and SC2181
(the second-run assertion read $? instead of testing run directly).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GqfpQtLuMczxtgG1U9PkLW
@github-actions

Copy link
Copy Markdown
Contributor

K9 contract conformance

run https://github.com/hyperpolymath/standards/actions/runs/38476322882

K9 normative contract typecheck

k9_contract.ncl typechecks

K9 contract self-test

== the bash mirrors cannot drift from the normative contract ==
ok   leash_levels mirrors k9_contract.ncl
ok   core_capabilities mirrors k9_contract.ncl
ok   contract_version mirrors k9_contract.ncl
ok   schema_major mirrors k9_contract.ncl
== capability arithmetic (§8) ==
ok   capability_ok fs.read accepted
ok   capability_ok rollback.apply accepted
ok   capability_ok x-acme.gpu.alloc accepted
ok   capability_ok x-acme rejected
ok   capability_ok x-.gpu rejected
ok   capability_ok fs.delete rejected
ok   capability_ok  rejected
== the extractor ==
ok   extracts pedigree.security.leash
ok   extracts pedigree.component_type
ok   extracts pedigree.metadata.name
ok   pedigree leash is not reported as top-level leash
ok   required_capabilities for a quiet component
ok   required_capabilities follows allow_network
== the envelope strip keeps line numbers (§3.6) ==
ok   line 1 becomes a comment
ok   line count is preserved
ok   schema_version stays on line 5
== L3: signature presence is not verification (§10) ==
ok   no verifier -> K9-C001 is SKIPPED, never a pass
ok   the skip states presence does not authorise 'Hunt
ok   verifier accepts -> verdict 'Verified, no K9-C001 finding
ok   verifier refuses -> K9-C001 error, verdict 'Rejected
== the fixture runner's attribution cannot be fooled by a filename ==
ok   every extracted finding is well-formed rule+layer
ok   the rule that really fired is attributed
ok   a rule named only in the filename is NOT attributed
ok   K9-C001 is present as a skipped finding
ok   and that same finding is NOT extractable as a rejection
== the dialect discriminator agrees with the coordination grammar (§4.3) ==
ok   magic file opening '---' is coordination
ok   magic file opening 'metadata:' is coordination
ok   plain file opening '---' is unclaimed
ok   plain file opening 'metadata:' is unclaimed
== no Nickel reserved word is used as an identifier ==
ok   the contract and all 27 fixtures avoid Nickel's reserved words

self-test: all assertions passed

K9 conformance fixtures

== positive controls (must pass) ==
ok   extension-capability.k9.ncl
ok   extension-fields.k9.ncl
ok   hunt-fully-granted.k9.ncl
ok   kennel-data.k9.ncl
ok   library-base.ncl
ok   yard-typed-config.k9.ncl

== negative controls (must fail, by the named rule) ==
ok   L0-K9-E001-bad-magic.k9.ncl (rejected by K9-E001 at L0)
ok   L0-K9-E002-nul-byte.k9.ncl (rejected by K9-E002 at L0)
ok   L0-K9-E003-crlf.k9.ncl (rejected by K9-E003 at L0)
ok   L0-K9-E004-no-spdx.k9.ncl (rejected by K9-E004 at L0)
ok   L0-K9-E005-unclaimed-body.k9.ncl (rejected by K9-E005 at L0)
ok   L0-K9-S012-library-with-pedigree.ncl (rejected by K9-S012 at L0)
ok   L0-K9-S014-stray-leash.ncl (rejected by K9-S014 at L0)
ok   L1-K9-S001-no-pedigree.k9.ncl (rejected by K9-S001 at L1)
ok   L1-K9-S002-wrong-major.k9.ncl (rejected by K9-S002 at L1)
ok   L1-K9-S003-todo-component-type.k9.ncl (rejected by K9-S003 at L1)
ok   L1-K9-S004-unknown-leash.k9.ncl (rejected by K9-S004 at L1)
ok   L1-K9-S005-missing-name.k9.ncl (rejected by K9-S005 at L1)
ok   L1-K9-S006-unknown-capability.k9.ncl (rejected by K9-S006 at L1)
ok   L1-K9-S007-ungranted-flag.k9.ncl (rejected by K9-S007 at L1)
ok   L1-K9-S008-hunt-signature-not-required.k9.ncl (rejected by K9-S008 at L1)
ok   L1-K9-S009-hunt-no-signature-block.k9.ncl (rejected by K9-S009 at L1)
ok   L1-K9-S010-hunt-empty-side-effects.k9.ncl (rejected by K9-S010 at L1)
ok   L1-K9-S011-recipes-at-yard.k9.ncl (rejected by K9-S011 at L1)
ok   L1-K9-S013-dangling-import.k9.ncl (rejected by K9-S013 at L1)
ok   L2-K9-N001-two-segment-version.k9.ncl (rejected by K9-N001 at L2)
ok   L2-K9-N001-wrong-field-type.k9.ncl (rejected by K9-N001 at L2)

fixtures: 6 positive, 21 negative (0 needing nickel), 0 failure(s)

K9 corpus conformance (L2)

[validate-k9] 14 conforming, 0 grandfathered (layer all, contract v1.0.0)

A2ML is retired (CLAUDE.md, Machine-Readable Artefacts: never add a fact
to a .a2ml file), so the two facts moved out of coordination.k9 in
1cc0fc0 should not have gone into STATE.a2ml and ECOSYSTEM.a2ml. Both
files are back to their main content.

- The VeriSimDB port already has an authoritative home:
  .verisimdb/config.toml (port = 8097). The ECOSYSTEM.a2ml copy was a
  duplicate.
- The CRG grade (B, self-declared) belongs in a root READINESS.md per
  component-readiness-grades/COMPONENT-READINESS-GRADES.adoc, which
  `just crg-grade` reads. The repo has no READINESS.md, so the header
  comment in coordination.k9 records the grade and where it belongs.

coordination.k9 still parses under grammar v1.2.0; descriptile-policy
and validate-k9 pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GqfpQtLuMczxtgG1U9PkLW
@github-actions

Copy link
Copy Markdown
Contributor

K9 contract conformance

run https://github.com/hyperpolymath/standards/actions/runs/38476549165

K9 normative contract typecheck

k9_contract.ncl typechecks

K9 contract self-test

== the bash mirrors cannot drift from the normative contract ==
ok   leash_levels mirrors k9_contract.ncl
ok   core_capabilities mirrors k9_contract.ncl
ok   contract_version mirrors k9_contract.ncl
ok   schema_major mirrors k9_contract.ncl
== capability arithmetic (§8) ==
ok   capability_ok fs.read accepted
ok   capability_ok rollback.apply accepted
ok   capability_ok x-acme.gpu.alloc accepted
ok   capability_ok x-acme rejected
ok   capability_ok x-.gpu rejected
ok   capability_ok fs.delete rejected
ok   capability_ok  rejected
== the extractor ==
ok   extracts pedigree.security.leash
ok   extracts pedigree.component_type
ok   extracts pedigree.metadata.name
ok   pedigree leash is not reported as top-level leash
ok   required_capabilities for a quiet component
ok   required_capabilities follows allow_network
== the envelope strip keeps line numbers (§3.6) ==
ok   line 1 becomes a comment
ok   line count is preserved
ok   schema_version stays on line 5
== L3: signature presence is not verification (§10) ==
ok   no verifier -> K9-C001 is SKIPPED, never a pass
ok   the skip states presence does not authorise 'Hunt
ok   verifier accepts -> verdict 'Verified, no K9-C001 finding
ok   verifier refuses -> K9-C001 error, verdict 'Rejected
== the fixture runner's attribution cannot be fooled by a filename ==
ok   every extracted finding is well-formed rule+layer
ok   the rule that really fired is attributed
ok   a rule named only in the filename is NOT attributed
ok   K9-C001 is present as a skipped finding
ok   and that same finding is NOT extractable as a rejection
== the dialect discriminator agrees with the coordination grammar (§4.3) ==
ok   magic file opening '---' is coordination
ok   magic file opening 'metadata:' is coordination
ok   plain file opening '---' is unclaimed
ok   plain file opening 'metadata:' is unclaimed
== no Nickel reserved word is used as an identifier ==
ok   the contract and all 27 fixtures avoid Nickel's reserved words

self-test: all assertions passed

K9 conformance fixtures

== positive controls (must pass) ==
ok   extension-capability.k9.ncl
ok   extension-fields.k9.ncl
ok   hunt-fully-granted.k9.ncl
ok   kennel-data.k9.ncl
ok   library-base.ncl
ok   yard-typed-config.k9.ncl

== negative controls (must fail, by the named rule) ==
ok   L0-K9-E001-bad-magic.k9.ncl (rejected by K9-E001 at L0)
ok   L0-K9-E002-nul-byte.k9.ncl (rejected by K9-E002 at L0)
ok   L0-K9-E003-crlf.k9.ncl (rejected by K9-E003 at L0)
ok   L0-K9-E004-no-spdx.k9.ncl (rejected by K9-E004 at L0)
ok   L0-K9-E005-unclaimed-body.k9.ncl (rejected by K9-E005 at L0)
ok   L0-K9-S012-library-with-pedigree.ncl (rejected by K9-S012 at L0)
ok   L0-K9-S014-stray-leash.ncl (rejected by K9-S014 at L0)
ok   L1-K9-S001-no-pedigree.k9.ncl (rejected by K9-S001 at L1)
ok   L1-K9-S002-wrong-major.k9.ncl (rejected by K9-S002 at L1)
ok   L1-K9-S003-todo-component-type.k9.ncl (rejected by K9-S003 at L1)
ok   L1-K9-S004-unknown-leash.k9.ncl (rejected by K9-S004 at L1)
ok   L1-K9-S005-missing-name.k9.ncl (rejected by K9-S005 at L1)
ok   L1-K9-S006-unknown-capability.k9.ncl (rejected by K9-S006 at L1)
ok   L1-K9-S007-ungranted-flag.k9.ncl (rejected by K9-S007 at L1)
ok   L1-K9-S008-hunt-signature-not-required.k9.ncl (rejected by K9-S008 at L1)
ok   L1-K9-S009-hunt-no-signature-block.k9.ncl (rejected by K9-S009 at L1)
ok   L1-K9-S010-hunt-empty-side-effects.k9.ncl (rejected by K9-S010 at L1)
ok   L1-K9-S011-recipes-at-yard.k9.ncl (rejected by K9-S011 at L1)
ok   L1-K9-S013-dangling-import.k9.ncl (rejected by K9-S013 at L1)
ok   L2-K9-N001-two-segment-version.k9.ncl (rejected by K9-N001 at L2)
ok   L2-K9-N001-wrong-field-type.k9.ncl (rejected by K9-N001 at L2)

fixtures: 6 positive, 21 negative (0 needing nickel), 0 failure(s)

K9 corpus conformance (L2)

[validate-k9] 14 conforming, 0 grandfathered (layer all, contract v1.0.0)

@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath merged commit 0b1898e into main Oct 13, 2026
65 checks passed
@hyperpolymath
hyperpolymath deleted the claude/exciting-noether-dzrfrr branch October 13, 2026 22:19
@coderabbitai

coderabbitai Bot commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

❌ Failed to create Coding Agent finishing-touch task. Please try again.

@coderabbitai

coderabbitai Bot commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Add Carrot credits or activate Agent usage billing to use Autofix

hyperpolymath pushed a commit that referenced this pull request Oct 13, 2026
The README is prose documentation, which LICENCE-POLICY Rule 1 puts
under CC-BY-SA-4.0. It was given MPL-2.0 in error when it was added in
#1233. Owner-approved change to this one file (2026-10-13).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GqfpQtLuMczxtgG1U9PkLW
hyperpolymath added a commit that referenced this pull request Oct 13, 2026
…e; signed-push README licence (#1235)

Follow-up to #1233. The repo that defines CRG had no machine-readable
grade declaration, so `just crg-grade` would have printed X for it. In
fact the recipe never ran at all; see below.

## `READINESS.md` (new)
- Holds the `**Current Grade:** C` line that the CRG spec asks for
(COMPONENT-READINESS-GRADES.adoc, "Machine-Readable Grade Declaration").
- **Why C (owner ruling 2026-10-13):** C is the latest assessment,
`0-canon/CRG-SELF-ASSESSMENT.adoc` (2026-04-09). That document also
lists the gaps to Grade B.
- `component-readiness-grades/SELF-ASSESSMENT.adoc` records an earlier B
(2026-04-04). `READINESS.md` notes it and says the later assessment
governs. That document is not edited here.
- Licensed CC-BY-SA-4.0 as prose documentation, per LICENCE-POLICY Rule
1.

## `just crg-grade` / `just crg-badge` fixed
- **The bug:** both recipes used Make's `$$` escape, which `just` does
not have. `sh` therefore received `grade=<pid>(grep …)` and failed with
`Syntax error: "(" unexpected`.
- **The fix:** the seven `$$` in those two recipes become `$`. Nothing
else in the Justfile changes.
- **Checked with just 1.21:**
  - `crg-grade` prints `C`;
  - `crg-badge` prints the yellow CRG C shields.io badge;
  - without `READINESS.md`, both fall back to `X`.

## `signed-push` README licence (owner-approved)
`.github/actions/signed-push/README.md` was added in #1233 with an
MPL-2.0 header. It is prose documentation, so LICENCE-POLICY Rule 1 puts
it under CC-BY-SA-4.0. The owner approved changing this one file. Only
the SPDX line changes.

## Not changed (flagged)
- The B assessment in `component-readiness-grades/SELF-ASSESSMENT.adoc`
stays as it is.
- So does the header comment in `coordination.k9`, which still says the
grade is B and that this repo has no `READINESS.md` yet. It is now
stale.
- The CRG spec says these recipes come from `rsr-template-repo`'s
Justfile. If that file has the same `$$`, it has the same bug. It is a
different repository, so it is not fixed here.

## Testing
- `just --list` parses the Justfile, and the two recipes were run as
described above.
- Shell suite: 77 of 81 test files pass. The other 4 fail identically on
`main` in this sandbox, which lacks the tools they need: KYAML-capable
yq, the JCS tool and Ruby. The 4 are `check-actions-lock-gate`,
`check-ijson-jcs`, `kyaml-format` and `science-ci-security`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01GqfpQtLuMczxtgG1U9PkLW

---
_Generated by [Claude
Code](https://claude.ai/code/session_01GqfpQtLuMczxtgG1U9PkLW)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request Oct 13, 2026
…1238)

## Summary

[#1233](#1233) already
did the first half of this job. In
`.github/actions/signed-push/action.yml`, the "Push local commits as
Verified" step now runs `push-verified.sh`, a bash script beside the
action. It uses `gh` and `jq`, the App installation token from
`steps.app-token`, and `createCommitOnBranch` with `expectedHeadOid`, so
if the remote head moves the push fails closed. The inputs did not
change: `app-id`, `private-key`, `branch`. The action has no outputs. It
never had any.

#1233 left the lock records in place on purpose. This PR removes them.
Nothing references either one any more:

| Record removed from `dependencies:` | Why it was safe to remove |
|---|---|
| `asana/push-signed-commits@d615ca88…` (ref `v1.3`) | No `uses:`
anywhere names it, and neither does any `workflows:` list. |
| `actions/setup-python@v2` | Its only reference was the Asana record's
nested `uses:`. It was also the only key in the lock that is not a SHA.
|

The diff deletes 12 lines and changes nothing else.

### How the records were removed
The repo's lock tooling cannot do this:
- `prune-stale.sh` only edits the `workflows:` section.
- `close-lock.sh` only adds records.
- `gh actions-lock` regeneration is fenced off for this repo because of
the composite action (#1122).

So I removed the two `dependencies:` blocks with a gawk filter that only
touches that section. Afterwards `prune-stale.sh` was a no-op, and
`close-lock.sh` found 0 dangling refs and left the file alone.

## Testing
All lock gates were run before and after the deletion, with the pinned
tool versions:

| Gate | Result |
|---|---|
| `scripts/check-lock-sync.sh` | in sync |
| `.githooks/validate-actions-lock.sh` | 25 refs found among 27 lock
keys (was 28) |
| `scripts/check-actions-lock-gate.sh` (gh-actions-lock v0.1.6, the
version CI pins) | "Immutable direct and transitive lockfile coverage
verified" |
| `scripts/prune-stale.sh` | no-op |
| `scripts/close-lock.sh` | 0 dangling refs |
| `scripts/lock-selfcheck.sh HEAD` | SELF-CONSISTENT |

Script tests that touch this action or the lock all pass:

| Test | Result |
|---|---|
| `validate-sha-pins-test` | 22/22 |
| `signed-push-test` | 13/13 |
| `check-actions-lock-gate-test` | 23/23 |
| `validate-actions-lock-test` | 5/5 |
| `check-lock-sync-test` | 10/10 |
| `prune-stale-test` | 15/15 |
| `close-lock-test` | 9/9 |
| `lock-selfcheck-test` | 5/5 |
| `regen-dependabot-locks-test` | 34/34 |
| `update-actions-lock-test` | 15/15 |
| `kyaml-format-test` | 17/17 |

The full `run-shell-test-suite.sh` passed 79 of 81 files. The other two
fail the same way on `main` in this container because tools are missing:
- `check-ijson-jcs-test` needs the `ijson-jcs` binary.
- `science-ci-security-test` needs `ssh-keygen`.

Neither test reads `actions.lock`.

The pre-commit hook passed in full (gitleaks included), and the
commit-msg hook passed.

`signed-push-smoke.yml` was **not** run. It is dispatch-only and needs
`APP_ID`/`APP_PRIVATE_KEY`, which `config/README.adoc` says this repo
does not hold yet.

## Follow-up, not done here (outside this PR's scope)
- **`.hypatia-baseline.json`** has an `invalid_actions_lock`
acknowledgement (`**actions.lock`, tracking #963, expires 2026-12-22)
for exactly this defect. Its exit condition was "we replace the action",
and that is now met. Removing the entry would shrink the ledger, which
the ratchet allows. I left it because I could not run Hypatia here to
confirm that nothing else in the lock triggers the rule.
- **The composite guard in `regen-dependabot-locks.sh` (#1122)** is
unchanged. The action's only third-party dependency is now
`actions/create-github-app-token`, and other workflows also use it
directly. So a regeneration should no longer have to restore records by
hand. Relaxing the guard still needs the live check #1233 described.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_014h2gFLLQibfB5N5hFz9ZCD

---
_Generated by [Claude
Code](https://claude.ai/code/session_014h2gFLLQibfB5N5hFz9ZCD)_

Co-authored-by: Claude <noreply@anthropic.com>
hyperpolymath added a commit that referenced this pull request Oct 14, 2026
Closes #963.

## Summary

Removes the `.hypatia-baseline.json` acknowledgement for
`invalid_actions_lock`. The entry had:
- `rule_module: ["workflow_audit", "workflow_hardening"]`
- `file_pattern: "**actions.lock"`
- tracking issue #963
- `expires_at: 2026-12-22`

It acknowledged `asana/push-signed-commits@d615…`, which declared the
floating transitive `actions/setup-python@v2`. One of its listed exit
criteria was "we replace the action", and that is now met:
- #1233 replaced the Asana action in `.github/actions/signed-push/` with
`push-verified.sh`.
- #1238 deleted both the `asana/push-signed-commits` and the
`actions/setup-python@v2` records from `actions.lock`.

While the entry stood, `**actions.lock` would have muted **any** new
`invalid_actions_lock` finding in the repo until 2026-12-22.

## Evidence the rule no longer fires on `main`

These are from the Hypatia scan on `main` at `7d2041a` ([run
38484072239](https://github.com/hyperpolymath/standards/actions/runs/38484072239),
scanner pinned at `51ab6496`):
- The scan reported 59 findings: critical=2, high=2, medium=34, warn=21.
- `findings_kept` is `[]`.
- None of the 59 suppressed findings has type `invalid_actions_lock`.
The two highs are WH013 and `ncl_k9_missing_pedigree`.
- No finding names `actions.lock`, asana or setup-python anywhere in the
log.

The ack was matching nothing. Both lock checks from the task print
nothing on this branch:
- the non-SHA key grep;
- the non-SHA nested `uses:` grep.

## Changes

| File | Change |
|---|---|
| `.hypatia-baseline.json` | One entry deleted, 12 lines. jq confirms
the result equals the original with only that entry removed. No other
entry changes. |
| `scripts/tests/apply-baseline-test.sh` | The "SHIPPED ledger" section
asserted that the real baseline holds **exactly one** such ack and
suppresses both emission paths, so it would go red on this removal. It
is inverted: it now asserts the ledger holds **no**
`invalid_actions_lock` ack and that both emission paths **reach the
gate** (`workflow_audit`/`actions.lock` and
`workflow_hardening`/`.github/workflows/actions.lock`). The
fixture-based tests for list-valued `rule_module` are unchanged. |

`docs/HYPATIA-BASELINE-FORMAT.adoc`, the schema description and the
comment in `apply-baseline.sh` still use `invalid_actions_lock` as their
example of one defect emitted by two modules. That describes how the
scanner behaves, not a live ack, so they are left as they are.

## Testing

| Check | Result |
|---|---|
| `bash scripts/tests/exemption-ratchet-test.sh` | 14 passed, 0 failed |
| `bash scripts/tests/apply-baseline-test.sh` | 32 passed, 0 failed |
| `bash scripts/tests/hypatia-blocking-gate-test.sh` | exit 0 |
| `scripts/check-exemption-ratchet.sh origin/main` | `SHRANK
.hypatia-baseline.json: 189 -> 188`. OK, and no `Ratchet-exception:` was
needed. |
| `apply-baseline.sh` on `[]` in blocking mode | schema-valid, exit 0 |
| `apply-baseline.sh` with both `invalid_actions_lock` emissions in
blocking mode | kept=2, suppressed=0, **exit 1**. A recurrence now
blocks. |
| `.githooks/pre-commit` and `commit-msg` | passed. Included gitleaks
8.28.0, validate-actions-lock and validate-sha-pins, using
checksum-verified gitleaks and mikefarah yq v4.47.1. |

The Hypatia scanner itself was **not** run locally, because the
container has no Elixir. This PR's own `scan / Hypatia Neurosymbolic
Analysis` run is the live confirmation.

Licence headers are untouched.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01TbbnKqskQA5mj5gfMniPzi

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants