Repository navigation
feat(k9): vnd.k9.coordination subtype, coordination grammar v1.2.0, native signed-push - #1233
Conversation
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
K9 contract conformancerun https://github.com/hyperpolymath/standards/actions/runs/38475956439 K9 normative contract typecheckK9 contract self-testK9 conformance fixturesK9 corpus conformance (L2) |
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing: 24
✨ Finishing Touches: 💡 1
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. Comment |
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
K9 contract conformancerun https://github.com/hyperpolymath/standards/actions/runs/38476322882 K9 normative contract typecheckK9 contract self-testK9 conformance fixturesK9 corpus conformance (L2) |
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
K9 contract conformancerun https://github.com/hyperpolymath/standards/actions/runs/38476549165 K9 normative contract typecheckK9 contract self-testK9 conformance fixturesK9 corpus conformance (L2) |
|
|
❌ Failed to create Coding Agent finishing-touch task. Please try again. |
|
Add Carrot credits or activate Agent usage billing to use Autofix |
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
…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>
…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>
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>



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)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.k9extension.vnd.k9registration (Revision 4) and its form-ready copy:.k9.ncl;SPEC.adoc:metadata:match tells the two apart. Checked against every committed.k9and.k9.nclfile.mime.typescannot express.k9.ncl.2. Coordination grammar v1.2.0; the repo's own
coordination.k9conforms(Owner ruling: extend the grammar for what belongs, move the rest out.)
coordination-k9-grammar_v1.2.abnfadds two optional sections:build_commandsandinnervation(afferent / efferent / reflex). The change is additive, so every v1.1.1 file is still valid.coordination.k9now parses under v1.2.0. I checked this with an ABNF parser (apg-js), and the file correctly fails v1.1.---line.ports,verisimdb_portandcrg_grade. A2ML is retired, so neither fact went into a.a2mlfile:.verisimdb/config.toml.READINESS.mdunder the CRG spec, andjust crg-gradereads it from there. This repo has noREADINESS.mdyet, so thecoordination.k9header comment records the grade and where it belongs.a2ml/andlol/are gone;pmpl-license-onlyinvariant contradicts this repo's MPL-2.0 classification. Licence content is flag-only.consumersnow parses as a list instead of a string.3.
signed-pushwithoutAsana/push-signed-commitsThe Asana action is written in Python and has no licence file. It also uses the tag-pinned
setup-python@v2and runs an unpinnedpip install. It is replaced by.github/actions/signed-push/push-verified.sh, which uses bash,ghandjqto callcreateCommitOnBranch.scripts/tests/signed-push-test.shruns 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.asana/push-signed-commitsandactions/setup-python@v2records are not hand-edited out ofactions.lock. All lock gates pass with them present, and the next tool regeneration drops them.prune-stalestill 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
minimal.k9, the spec's new examples and the rootcoordination.k9pass v1.2. Negative controls fail.k9-validate.sh --self-testand thevalidate-k9hook pass.signed-push-test13/13,validate-sha-pins-test22/22 (with mikefarah yq),descriptile-policy-test11/11. The docstring scan shows 100% on the new code.validate-actions-lockandcheck-lock-sync. These also pass:check-workflow-duplicate-keys,check-standards-map,check-canon-lockstep.mainhere, 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-formatandscience-ci-security.🤖 Generated with Claude Code
https://claude.ai/code/session_01GqfpQtLuMczxtgG1U9PkLW
Generated by Claude Code