Skip to content

fix(dogfood-gate): repair the manifest defects the revived gate exposed#55

Merged
hyperpolymath merged 1 commit into
mainfrom
fix/dogfood-gate-manifests
Jul 21, 2026
Merged

fix(dogfood-gate): repair the manifest defects the revived gate exposed#55
hyperpolymath merged 1 commit into
mainfrom
fix/dogfood-gate-manifests

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

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.a2ml was not defective — the pin was stale

This is the SHA-pinning-defeats-upstream-fixes pattern, caught red-handed:

Pinned 6bff6ec — PR #26, "recognise s-expression identity/version fields"
Fix needed 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.a2ml genuinely lacked identity

The validator exempts four categories — *AI-MANIFEST* files, .machine_readable/ (structural identity), contractile @directive shape, and named typed manifests. None applies here, and the file has no name/project/agent-id. Added name to 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.

  • Both container/deploy.k9.ncl and .machine_readable/self-validating/methodology-guard.k9.ncl were missing the mandatory K9! magic number on line 1.
  • 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.

This is template rot with a measurable blast radius: container/deploy.k9.ncl is missing the K9! line in 6 repos (lucidscript, pandoc-k9, pseudoscript, squeakwell, stateful-artefacts, systemet) while the newer template has it.

⚠️ K9! and Nickel contradict each other, estate-wide

Worth recording, and not changed here:

$ nickel typecheck container/deploy.k9.ncl
error: unexpected token
1 │ K9!
  │   ^

The magic number is not valid Nickel, 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. The consequence is that the nickel typecheck container/deploy.k9.ncl usage 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

Check Result
K9 validator 0 errors (8 files)
A2ML validator 0 errors (121 files)
actionlint 0 errors
tests/aspect_tests.sh 4/4
tests/e2e.sh 4/4
tests/smoke/grammar_smoke.sh 20/20

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.
@sonarqubecloud

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath marked this pull request as ready for review July 21, 2026 15:05
@hyperpolymath
hyperpolymath merged commit 10e8662 into main Jul 21, 2026
31 of 34 checks passed
@hyperpolymath
hyperpolymath deleted the fix/dogfood-gate-manifests branch 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`.
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.

1 participant