fix(ci): exclude k9 contracts from the Nickel gate - #985
Conversation
`*.k9.ncl` files are k9 contracts, not Nickel source: they open with a `K9!` sentinel on line 1, so `nickel typecheck` dies at 1:3 on the `!`. The gate globbed `*.ncl` and swallowed them, so it failed over files the repo has no way to fix. Measured in cicd-squabbler: 16 of 27 `.ncl` are k9 contracts, and 2 more import JSON generated at build time and correctly uncommitted — 18 of 27 could never pass. `detect` counted the same inflated glob, so `has_nickel` went true on repos holding no Nickel at all, installing a toolchain to fail. detect and the job now share ONE pathspec: a guard that counts a different set than its consumer checks is how this defect arose. Typecheck is skipped only where an `import` target is untracked in git, each skip disclosed by name with its reason. Comments are stripped before scanning, because `_base.ncl` documents its own usage in a `#` comment containing a literal import. Format is still checked over every genuine Nickel file, with no exemption. Narrowing cannot manufacture a pass: the job prints its denominators and refuses when zero files survive, or when every file was skipped. Verified with the workflow's own pinned nickel 1.18.0, the embedded step body extracted byte-identical to the tested script: - unmodified tree -> exit 1, 11 format errors, 2 named skips - formatted tree -> exit 0, 11 checked / 9 typechecked / 2 skipped - injected type error-> exit 1 - un-formatted file -> exit 1 - all files skipped -> exit 1 (refuses, does not pass) - k9-only tree -> has_nickel false; job refuses if reached Refs: #982, #976 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📜 Recent review details⏰ Context from checks skipped due to timeout. (22)
🔇 Additional comments (1)
📝 SummarySummary by CodeRabbit
WalkthroughThe CI workflow now separates k9 contracts from Nickel sources. It checks format for genuine Nickel files, skips typechecking only when imports are untracked, reports each skip, and fails when no file is typechecked. ChangesNickel CI validation
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix · Severity of issue fixed: Medium Sequence Diagram(s)sequenceDiagram
participant GitHubActions as GitHub Actions Nickel job
participant GitRepository as Git repository
participant NickelCLI as Nickel CLI
participant StepSummary as Step summary
GitHubActions->>GitRepository: List *.ncl excluding *.k9.ncl
GitHubActions->>NickelCLI: Check format for each genuine Nickel file
GitHubActions->>GitRepository: Resolve imported targets
GitHubActions->>NickelCLI: Typecheck files with tracked imports
GitHubActions->>StepSummary: Report validation counts and skip reasons
Suggested reviewers: Merge Risk: ⚪ Minimal · up to The Nickel gate’s documented filtering and skip behavior is implemented without an outstanding actionable issue. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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. A rabbit checks the Nickel trail Comment |
Formatting only — all 11 genuine Nickel files in this repo fail `nickel format --check`. This is the **repo's own** half of the Nickel red. The other half was a defect in the shared gate, fixed in hyperpolymath/standards#985: it globbed `*.ncl` and so also checked the 16 `*.k9.ncl` **k9 contracts**, which are a different format (`K9!` sentinel on line 1) and can never pass. With that gate fix alone this repo would still be red, on these 11 files, legitimately. ## Verification Run with the pipeline's **own pinned nickel 1.18.0** (sha256-verified from the workflow), not a local build — formatter output differs between releases. | control | result | |---|---| | `nickel pprint-ast` byte-identical before vs after | **11 / 11** | | SPDX + copyright headers unchanged | 11 / 11 | | total comment lines | 353 before, 353 after | | files touched outside `*.ncl` | 0 | | `nickel format --check` after | passes on all 11 | The AST comparison is the point: this is provably a cosmetic reformat, not a semantic change. ## Not an auto-fix No `--fix` runs in CI. The pipeline still uses `--check` only; this is a deliberate commit in a reviewable PR. ## Remaining Once standards#985 merges, this repo's caller needs re-pinning to that squash SHA. Until then the pipeline check here still runs the old gate and will stay red on the k9 contracts — that is expected and is not caused by this PR. The 2 files importing build-time JSON (`claude-md-data.json`, `clauses.json`) remain un-typecheckable standalone by design; standards#985 skips them and discloses each skip by name rather than pretending to check them. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
|
Formatting only — all 11 genuine Nickel files in the template fail `nickel format --check`. **This is where the defect originates.** Every repo seeded from this template inherits these files, so each one goes red on the ci-pipeline Nickel gate over boilerplate it did not write. `cicd-squabbler` is the measured case (hyperpolymath/cicd-squabbler#106) — it went 100% red on template files, never on its own source. Fixing the template stops the defect propagating to new seeds. The other half of that red was a defect in the shared gate itself, fixed in hyperpolymath/standards#985: it globbed `*.ncl`, so it also checked the 18 `*.k9.ncl` **k9 contracts** here — a different format (`K9!` sentinel on line 1) that can never pass `nickel typecheck`. Those 18 files are untouched by this PR. ## Verification Run with the pipeline's **own pinned nickel 1.18.0** (sha256-verified from the workflow), not a local build — formatter output differs between releases. | control | result | |---|---| | `nickel pprint-ast` byte-identical before vs after | **11 / 11** | | SPDX + copyright headers unchanged | 11 / 11 | | total comment lines | 356 before, 356 after | | files touched outside genuine `*.ncl` | 0 | | `nickel format --check` after | passes on all 11 | The AST comparison is the point: this is provably a cosmetic reformat, not a semantic change. ## Not an auto-fix No `--fix` runs in CI. The pipeline still uses `--check` only; this is a deliberate commit in a reviewable PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…3f65 (#56) ## What Re-pins this repository's `standards-pipeline.yml` caller from `2eb9bb19` to **`f95130bb`** — the squash merge of [hyperpolymath/standards#985][985]. ## Why `2eb9bb19` predates #985, which fixed the `ci-pipeline` detect gate. Every caller still on the old pin runs the **pre-fix** gate. The workflow is `pull_request`-triggered only, so the failure is latent: it does not manifest until the next PR is opened here. ## What moves Two lines, together: | Line | From | To | |---|---|---| | provenance comment | `@ 2eb9bb19 — ci-pipeline.yml blob d2583657.` | `@ f95130bb — ci-pipeline.yml blob 8bcdeaf2.` | | `uses:` ref | `...ci-pipeline.yml@2eb9bb19...` | `...ci-pipeline.yml@f95130bb...` | A SHA bump that leaves the blob comment behind is a **phantom pin** — it names a tree it can no longer be checked against — so both change or neither does. ## Why `f95130bb` and not current `main` `main` has since moved to `d1bd7f42` (#988, a changelog fix). `f95130bb` was chosen deliberately: - `ci-pipeline.yml` is **byte-identical at both** — blob `8bcdeaf2` either way. - `f95130bb` is the **reviewed** revision: the commit #985 was merged as. - Its only failing checks are `SonarCloud Code Analysis` and the mirror trio (`mirror-gitea`, `mirror-disroot`, `mirror-codeberg`) — all four are listed in standards' own `config/rulesets/gates.json` under `never_required_workflows`. Nothing ci-pipeline-related is red there. `ci-pipeline.yml` pins its own sub-reusables fully-qualified at `571cc734` rather than `./`, so this pin selects only which `ci-pipeline.yml` is read — not its dependencies. ## Verification - Pre-flight refused to edit unless the exact pre-fix SHA **and** the expected provenance-comment shape were both present. - Post-flight asserted exactly `2/2` changed lines, no residue of `2eb9bb19` or `d2583657`, and the new SHA present. - Commit is SSH-signed (`%G?` = `G`). [985]: hyperpolymath/standards#985 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…3f65 (#122) ## What Re-pins this repository's `standards-pipeline.yml` caller from `2eb9bb19` to **`f95130bb`** — the squash merge of [hyperpolymath/standards#985][985]. ## Why `2eb9bb19` predates #985, which fixed the `ci-pipeline` detect gate. Every caller still on the old pin runs the **pre-fix** gate. The workflow is `pull_request`-triggered only, so the failure is latent: it does not manifest until the next PR is opened here. ## What moves Two lines, together: | Line | From | To | |---|---|---| | provenance comment | `@ 2eb9bb19 — ci-pipeline.yml blob d2583657.` | `@ f95130bb — ci-pipeline.yml blob 8bcdeaf2.` | | `uses:` ref | `...ci-pipeline.yml@2eb9bb19...` | `...ci-pipeline.yml@f95130bb...` | A SHA bump that leaves the blob comment behind is a **phantom pin** — it names a tree it can no longer be checked against — so both change or neither does. ## Why `f95130bb` and not current `main` `main` has since moved to `d1bd7f42` (#988, a changelog fix). `f95130bb` was chosen deliberately: - `ci-pipeline.yml` is **byte-identical at both** — blob `8bcdeaf2` either way. - `f95130bb` is the **reviewed** revision: the commit #985 was merged as. - Its only failing checks are `SonarCloud Code Analysis` and the mirror trio (`mirror-gitea`, `mirror-disroot`, `mirror-codeberg`) — all four are listed in standards' own `config/rulesets/gates.json` under `never_required_workflows`. Nothing ci-pipeline-related is red there. `ci-pipeline.yml` pins its own sub-reusables fully-qualified at `571cc734` rather than `./`, so this pin selects only which `ci-pipeline.yml` is read — not its dependencies. ## Verification - Pre-flight refused to edit unless the exact pre-fix SHA **and** the expected provenance-comment shape were both present. - Post-flight asserted exactly `2/2` changed lines, no residue of `2eb9bb19` or `d2583657`, and the new SHA present. - Commit is SSH-signed (`%G?` = `G`). [985]: hyperpolymath/standards#985 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…3f65 (#22) ## What Re-pins this repository's `standards-pipeline.yml` caller from `2eb9bb19` to **`f95130bb`** — the squash merge of [hyperpolymath/standards#985][985]. ## Why `2eb9bb19` predates #985, which fixed the `ci-pipeline` detect gate. Every caller still on the old pin runs the **pre-fix** gate. The workflow is `pull_request`-triggered only, so the failure is latent: it does not manifest until the next PR is opened here. ## What moves Two lines, together: | Line | From | To | |---|---|---| | provenance comment | `@ 2eb9bb19 — ci-pipeline.yml blob d2583657.` | `@ f95130bb — ci-pipeline.yml blob 8bcdeaf2.` | | `uses:` ref | `...ci-pipeline.yml@2eb9bb19...` | `...ci-pipeline.yml@f95130bb...` | A SHA bump that leaves the blob comment behind is a **phantom pin** — it names a tree it can no longer be checked against — so both change or neither does. ## Why `f95130bb` and not current `main` `main` has since moved to `d1bd7f42` (#988, a changelog fix). `f95130bb` was chosen deliberately: - `ci-pipeline.yml` is **byte-identical at both** — blob `8bcdeaf2` either way. - `f95130bb` is the **reviewed** revision: the commit #985 was merged as. - Its only failing checks are `SonarCloud Code Analysis` and the mirror trio (`mirror-gitea`, `mirror-disroot`, `mirror-codeberg`) — all four are listed in standards' own `config/rulesets/gates.json` under `never_required_workflows`. Nothing ci-pipeline-related is red there. `ci-pipeline.yml` pins its own sub-reusables fully-qualified at `571cc734` rather than `./`, so this pin selects only which `ci-pipeline.yml` is read — not its dependencies. ## Verification - Pre-flight refused to edit unless the exact pre-fix SHA **and** the expected provenance-comment shape were both present. - Post-flight asserted exactly `2/2` changed lines, no residue of `2eb9bb19` or `d2583657`, and the new SHA present. - Commit is SSH-signed (`%G?` = `G`). [985]: hyperpolymath/standards#985 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…3f65 (#107) ## What Re-pins this repository's `standards-pipeline.yml` caller from `2eb9bb19` to **`f95130bb`** — the squash merge of [hyperpolymath/standards#985][985]. ## Why `2eb9bb19` predates #985, which fixed the `ci-pipeline` detect gate. Every caller still on the old pin runs the **pre-fix** gate. The workflow is `pull_request`-triggered only, so the failure is latent: it does not manifest until the next PR is opened here. ## What moves Two lines, together: | Line | From | To | |---|---|---| | provenance comment | `@ 2eb9bb19 — ci-pipeline.yml blob d2583657.` | `@ f95130bb — ci-pipeline.yml blob 8bcdeaf2.` | | `uses:` ref | `...ci-pipeline.yml@2eb9bb19...` | `...ci-pipeline.yml@f95130bb...` | A SHA bump that leaves the blob comment behind is a **phantom pin** — it names a tree it can no longer be checked against — so both change or neither does. ## Why `f95130bb` and not current `main` `main` has since moved to `d1bd7f42` (#988, a changelog fix). `f95130bb` was chosen deliberately: - `ci-pipeline.yml` is **byte-identical at both** — blob `8bcdeaf2` either way. - `f95130bb` is the **reviewed** revision: the commit #985 was merged as. - Its only failing checks are `SonarCloud Code Analysis` and the mirror trio (`mirror-gitea`, `mirror-disroot`, `mirror-codeberg`) — all four are listed in standards' own `config/rulesets/gates.json` under `never_required_workflows`. Nothing ci-pipeline-related is red there. `ci-pipeline.yml` pins its own sub-reusables fully-qualified at `571cc734` rather than `./`, so this pin selects only which `ci-pipeline.yml` is read — not its dependencies. ## Verification - Pre-flight refused to edit unless the exact pre-fix SHA **and** the expected provenance-comment shape were both present. - Post-flight asserted exactly `2/2` changed lines, no residue of `2eb9bb19` or `d2583657`, and the new SHA present. - Commit is SSH-signed (`%G?` = `G`). [985]: hyperpolymath/standards#985 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
## What Re-pins this repository's `standards-pipeline.yml` caller from `2eb9bb19` to **`f95130bb`** — the squash merge of [hyperpolymath/standards#985][985]. ## Why `2eb9bb19` predates #985, which fixed the `ci-pipeline` detect gate. Every caller still on the old pin runs the **pre-fix** gate. The workflow is `pull_request`-triggered only, so the failure is latent: it does not manifest until the next PR is opened here. ## What moves Two lines, together: | Line | From | To | |---|---|---| | provenance comment | `@ 2eb9bb19 — ci-pipeline.yml blob d2583657.` | `@ f95130bb — ci-pipeline.yml blob 8bcdeaf2.` | | `uses:` ref | `...ci-pipeline.yml@2eb9bb19...` | `...ci-pipeline.yml@f95130bb...` | A SHA bump that leaves the blob comment behind is a **phantom pin** — it names a tree it can no longer be checked against — so both change or neither does. ## Why `f95130bb` and not current `main` `main` has since moved to `d1bd7f42` (#988, a changelog fix). `f95130bb` was chosen deliberately: - `ci-pipeline.yml` is **byte-identical at both** — blob `8bcdeaf2` either way. - `f95130bb` is the **reviewed** revision: the commit #985 was merged as. - Its only failing checks are `SonarCloud Code Analysis` and the mirror trio (`mirror-gitea`, `mirror-disroot`, `mirror-codeberg`) — all four are listed in standards' own `config/rulesets/gates.json` under `never_required_workflows`. Nothing ci-pipeline-related is red there. `ci-pipeline.yml` pins its own sub-reusables fully-qualified at `571cc734` rather than `./`, so this pin selects only which `ci-pipeline.yml` is read — not its dependencies. ## Verification - Pre-flight refused to edit unless the exact pre-fix SHA **and** the expected provenance-comment shape were both present. - Post-flight asserted exactly `2/2` changed lines, no residue of `2eb9bb19` or `d2583657`, and the new SHA present. - Commit is SSH-signed (`%G?` = `G`). [985]: hyperpolymath/standards#985 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>



Closes #982. Cures the Nickel half of #976.
The defect
A suffix is not a format.
*.k9.nclfiles are k9 contracts, not Nickelsource — they open with a
K9!sentinel on line 1, sonickel typecheckdies at1:3on the!. The gate globbed*.ncland swallowed all of them.Measured in the one pilot repo that actually ran the pipeline (
cicd-squabbler):*.k9.ncl— a different format.nclimporting build-time JSON (correctly uncommitted).ncltotalThat repo went red entirely on boilerplate, never on its own source.
detectcounted the same inflated glob at line 132, sohas_nickelwent true onrepos holding no Nickel at all — installing a toolchain in order to fail.
The fix
detectand the job both use'*.ncl' ':!*.k9.ncl'. A guard that counts a different set than its consumerchecks is how this defect arose, so the cure is that they cannot diverge.
N_K9, printed in thedetection table, and explicitly excluded from the Total (the same shape as
the existing "detected but unsupported" disclosure).
importtarget is untracked in git, andevery skip is disclosed by name with its reason via
::noticeand in thestep summary. A skip is never a pass. Comments are stripped before scanning —
_base.ncldocuments its own usage in a#comment containing a literalimport "../_base.ncl", and matching that would have skipped a file thattypechecks perfectly well.
.ncl, with no exemption. Thisnarrows the file set; it does not weaken the check.
refuses when zero files survive, or when every file was skipped.
Still read-only:
--checkonly, no--fix, nonickel formatin CI.Verification — the mutants, not just the greens
Run with the workflow's own pinned nickel 1.18.0 (sha256-verified), and the
embedded step body extracted from this YAML and diffed byte-identical to the
script under test, so these results are about the artefact, not a paraphrase.
has_nickel=false; job refuses if reachedFormat-safety control for the follow-up commits:
nickel pprint-astisbyte-identical for 11/11 files before and after
nickel format, so thereformatting is provably semantics-preserving.
Consequence, stated plainly
Repos that were vacuously green because their only
.nclwere k9 contractswill now correctly report no Nickel. That is #976's intended cure, not a
regression.
This alone does not turn
cicd-squabblergreen: all 11 of its genuine.nclgenuinely fail
format --check. That is a real defect in that repo and is fixedin its own PR, together with the matching fix in
rsr-template-reposo futureseeded repos do not inherit it.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Ji1bq3TypfycfUPAR7hSxR