fix(dogfood-gate): repair the manifest defects the revived gate exposed#55
Merged
Conversation
The Dogfood Gate could not parse before #53, so it never ran. Now that it parses, it runs — and it immediately reported 2 A2ML errors and 4 K9 errors on main. All six are addressed here. Each fix was verified by running the actual validator locally, not by reading its source. A2ML (2 errors -> 0) * docs/governance/TSDM.a2ml was not defective. The workflow pinned a2ml-validate-action at 6bff6ec, which is PR #26 ("recognise s-expression identity/version fields"). The colon/brace-block identity form -- `id: "tsdm-standard"` -- was only recognised from PR #41 onward, and the validator's own comment names this exact file as the motivating case. The pin predated the fix for the file it was failing on. Bumped to current main (5468b7f). Running the newer validator locally drops the error count from 2 to 1, confirming the diagnosis before the bump was made. * docs/governance/MAINTENANCE-CHECKLIST.a2ml genuinely lacked an identity field. It is not named *AI-MANIFEST*, is not under .machine_readable/, and carries no @-directives, so none of the validator's four exemptions apply. Added `name` to its [metadata] block. K9 (4 errors -> 0) Both files were genuinely defective; the current validator reports the same 4 errors as the pinned one, so unlike the A2ML case this is not pin staleness. * container/deploy.k9.ncl and .machine_readable/self-validating/methodology-guard.k9.ncl were both missing the mandatory `K9!` magic number on line 1. * container/deploy.k9.ncl had `pedigree = component_pedigree,` where the canonical template (rsr-julia-library-template-repo) has `pedigree = component_pedigree & { name = "..." },`. Without the merge the pedigree carries no name. Matched to the template. * methodology-guard.k9.ncl had no pedigree block at all. Added one. Note on `K9!` and Nickel: the magic number is not valid Nickel syntax, so `nickel typecheck` fails on every .k9.ncl in the estate that carries it, including the canonical template and every currently-passing file. k9-svc evidently strips the line before parsing. This means the `nickel typecheck container/deploy.k9.ncl` usage line in these files' own headers cannot succeed as written. That is pre-existing and estate-wide, not introduced here, and is left alone. Both files were checked with the magic line stripped, and both typecheck clean -- which caught a real error in the first draft of this change, where the new pedigree block had been placed at top level in a file whose body is `let ... in ...`. Verified: K9 0 errors, A2ML 0 errors (121 files), actionlint 0, aspect 4/4, e2e 4/4, smoke 20/20.
|
hyperpolymath
marked this pull request as ready for review
July 21, 2026 15:05
hyperpolymath
added a commit
that referenced
this pull request
Jul 21, 2026
…andards pins (#56) Both failing Governance jobs are root-caused and fixed. Follows #53, #54, #55. ## `Workflow security linter` ``` ERROR: .github/workflows/pages.yml missing SPDX header ``` `pages.yml` arrived in #51 and begins directly at `name:`. Every other workflow already carries the header; this was the only one. > **Recording a correction against myself.** Earlier in this programme I audited all workflows, reported that every one had both an SPDX header *and* a top-level `permissions:` block, and marked the SPDX hypothesis **disproved**. That audit was wrong — it must have run against a tree without `pages.yml`. The real cause is exactly the one first suspected. A "disproved" hypothesis is only as good as the test that disproved it. ## `Check Workflow Staleness` ``` governance-reusable.yml pin d7c22711e830 is 63 commit(s) / 24d behind standards HEAD — outside the recency window (>50 commits AND >14d). Refresh toward f9dca6ded2ca ``` Three callers were pinned at `d7c22711e830`: | Workflow | From | To | |---|---|---| | `governance-reusable.yml` | `d7c22711e830…` | `f9dca6ded2cad8ab54044c1cb0489b558ae2682b` | | `hypatia-scan-reusable.yml` | `d7c22711e830…` | `f9dca6ded2cad8ab54044c1cb0489b558ae2682b` | | `scorecard-reusable.yml` | `d7c22711e830…` | `f9dca6ded2cad8ab54044c1cb0489b558ae2682b` | Full 40-char SHAs — the gate's message quotes the abbreviated form, which would weaken the pin. ### Deliberately not touched - **`mirror-reusable.yml`** (`d135b05`) and **`secret-scanner-reusable.yml`** (`c65436e`) — neither was flagged by the staleness gate, and the secret-scanner pin in particular **should not be moved independently of the gitleaks allowlist work**, since re-pinning consumers ahead of the config work reintroduces false positives. - **`scorecard-enforcer.yml`** — the gate asks for its removal, but **this repo doesn't have that file**. That clause is generic advice in the reusable's message, not a finding against krl. ## Note on bumping toward standards HEAD The newer `governance-reusable` has *more* real checks than the pinned one (its previously-dead docs and Guix/Nix jobs were made real, warn-first until 2026-08-21). So this bump may surface new warnings. That is the gate working, and warn-first means it should not turn the build red. ## Verified `actionlint` **0 errors** · all **18** workflows carry an SPDX header
hyperpolymath
added a commit
that referenced
this pull request
Jul 21, 2026
#55 and #56 were merged **before their final commits landed**, so three fixes verified on those branches are not on `main`. One is a **regression `main` did not have before #56** — please treat this as the follow-up that finishes them. ## 1. Hypatia is `startup_failure` on main — regression from #56 #56 refreshed `hypatia-scan-reusable.yml` to standards HEAD. The newer reusable declares `security-events: **write**` (it uploads SARIF); the caller still grants `security-events: **read**`. A called workflow **cannot escalate beyond its caller's grant**, so GitHub rejects the run at parse time — zero jobs, no log. Confirmed by a clean A/B on the tangle branch, which carries the identical change: | tangle commit | pin | caller perm | Hypatia | |---|---|---|---| | `558f631` | old | `read` | **success** | | `2369299` | new | `read` | **startup_failure** | | `d090ff2` | new | `write` | **success** | > **Worth knowing for future sweeps:** `gh pr checks` does **not** list `startup_failure` among its `fail` rows. A PR can read *"0 fail"* while a workflow never started. Use `gh run list --json conclusion` to see it. This is how the regression slipped past my own green check. ## 2. Dogfood Gate still fails — `k9-validate-action` pin `container/deploy.k9.ncl` uses the canonical single-line pedigree form: ```nickel pedigree = component_pedigree & { name = "krl-deploy" }, ``` The pinned validator (`2d96f43`) cannot parse it — single-line support was added upstream *after* that pin. Exactly the same stale-pin trap as the `a2ml-validate-action` bump in #55, where the file was correct and the validator was too old to see it. Bumped to `08958c9`. ## 3. Governance still fails — unpinned actions in `pages.yml` #56 fixed the SPDX half of the Workflow security linter, which then reported its **next** rule: ``` ERROR: Found unpinned actions: ``` `pages.yml` used floating tags where every other workflow pins by SHA: | Action | From | To | |---|---|---| | `actions/checkout` | `@v4` | `de0fac2e…` `# v6.0.2` | | `actions/upload-pages-artifact` | `@v3` | `56afc609…` `# v3` | | `actions/deploy-pages` | `@v4` | `d6db9016…` `# v4` | Same major versions — pinning only, not behaviour. ## Verified on this branch | Check | Result | |---|---| | K9 validator | **0 errors** | | A2ML validator | **0 errors** (121 files) | | `actionlint` | **0 errors** | | SPDX headers | all 18 workflows | | Unpinned third-party actions | **0** | ## Two reds will remain, and neither is fixable in-repo - **GitHub Pages deploy** — Pages is **not enabled**: `/repos/hyperpolymath/krl/pages` returns `404`, surfacing as `HttpError: Not Found`. The build itself passes and certifies a11y. **Owner action** (also true of `hyperpolymath/tangle`). - **Instant Sync** — deliberately frozen. Opened ready-for-review rather than draft, since it repairs a live regression on `main`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Follows #53 and #54.
The Dogfood Gate could not parse before #53, so it never ran. Now that it parses, it runs — and immediately reported 2 A2ML errors and 4 K9 errors on
main. That's the gate working as intended; this PR clears what it found.Each fix was verified by running the actual validator locally, not by reading its source.
A2ML: 2 errors → 0
docs/governance/TSDM.a2mlwas not defective — the pin was staleThis is the SHA-pinning-defeats-upstream-fixes pattern, caught red-handed:
6bff6ec— PR #26, "recognise s-expression identity/version fields"6c47174— PR #41, "recognise colon/brace-block identity"TSDM.a2ml declares
id: "tsdm-standard", the colon/brace-block form. The validator's own source comment names this exact file as the motivating case — so the fix existed upstream, and the pin predated it.Confirmed before changing anything: running the newer validator locally drops the count 2 → 1. Bumped to current main (
5468b7f).docs/governance/MAINTENANCE-CHECKLIST.a2mlgenuinely lacked identityThe validator exempts four categories —
*AI-MANIFEST*files,.machine_readable/(structural identity), contractile@directiveshape, and named typed manifests. None applies here, and the file has noname/project/agent-id. Addednameto its[metadata]block.K9: 4 errors → 0
Unlike the A2ML case, these are genuine file defects — the current validator reports the same 4 errors as the pinned one, so pin staleness is ruled out.
container/deploy.k9.ncland.machine_readable/self-validating/methodology-guard.k9.nclwere missing the mandatoryK9!magic number on line 1.deploy.k9.nclhadpedigree = component_pedigree,where the canonical template (rsr-julia-library-template-repo) haspedigree = component_pedigree & { name = "…" },. Without the merge the pedigree carries no name. Matched to the template.methodology-guard.k9.nclhad no pedigree block at all. Added one.K9!and Nickel contradict each other, estate-wideWorth recording, and not changed here:
The magic number is not valid Nickel, so
nickel typecheckfails on every.k9.nclin the estate that carries it — including the canonical template and every currently-passing file.k9-svcevidently strips the line before parsing. The consequence is that thenickel typecheck container/deploy.k9.nclusage line in these files' own headers can never succeed as written.Pre-existing and estate-wide, so left alone. But I used it as a check: both files were typechecked with the magic line stripped, and that caught a real error in my first draft, where the new pedigree block sat at top level in a file whose body is
let … in …— invalid Nickel. Moved inside the record; the validator matches at any indent.Verified
actionlinttests/aspect_tests.shtests/e2e.shtests/smoke/grammar_smoke.sh