fix(ci): four workflows are parse-dead on main — re-fix + guard against recurrence - #69
Conversation
…recurring #68 ("repoint codeql-action at a SHA that exists") re-ran the sweep that appends `actions: read` after every `permissions:` line, undoing the fix landed in #64. Four workflows are parse-dead on main RIGHT NOW: zig.yml e2e.yml container-build.yml install-smoke.yml i.e. the Zig FFI gate, the Julia test suite, the container build and the install smoke test. All four declare permissions in the scalar form, so the appended key is invalid YAML: permissions: read-all actions: read # mapping values are not allowed here Actions rejects a malformed workflow at PARSE time — zero jobs, NO check run. Not a red X, an absence. The only visible tell is `gh run list` printing the workflow's PATH instead of its NAME, which is exactly how this was spotted. Same cause both times: the sweep matches `permissions:` as TEXT, not as a YAML node, so it cannot tell the scalar form from the mapping form. The insertion is redundant anyway — `read-all` already grants every read scope, `actions: read` included. Fixing it a second time without a guard would just queue up a third. So this also adds `.githooks/validate-workflow-yaml.sh`, wired as the first job of the dogfood gate: parse every workflow, fail on any that does not parse OR that declares no jobs (a workflow can be valid YAML and still be inert). The guard is proven fail-closed, not assumed: A. clean tree -> exit 0, "all 19 workflows parse" B. `actions: read` reintroduced -> exit 1, names zig.yml and the reason C. restored -> exit 0 A text-only sweep cannot satisfy this check, which is the point. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two clean-ups, both closing loose ends left by earlier sweeps. 1. GOVERNANCE — recover what was lost, fix the dangling references ------------------------------------------------------------------ #68 deleted GOVERNANCE.adoc as a duplicate of GOVERNANCE.md. It was not one. Fifteen sections existed ONLY in the .adoc, and went with it: Contribution Lifecycle · Conflict Resolution · Project Policies · Repository-Specific Conventions · Governance Evolution · See Also · Changelog "Repository-Specific Conventions" is the load-bearing one — it is where the signing requirement, the SPDX rule, the contractile layout and the .machine_readable/6a2/ convention were written down. That content is recovered here from 5501ec6^ and merged into GOVERNANCE.md, converted from AsciiDoc to Markdown. GOVERNANCE.md is now genuinely the single source, which is what #68 intended but did not achieve. The deletion also left two dangling references, now repointed: .machine_readable/contractiles/Trustfile.a2ml:74 areas: GOVERNANCE.adoc .machine_readable/contractiles/Mustfile.a2ml:38 "GOVERNANCE.adoc ... must exist" The Mustfile one is worth flagging: it is a `severity: critical` contract whose `run:` is literally test -f GOVERNANCE.adoc && test -f MAINTAINERS.adoc && test -f .github/CODEOWNERS That assertion has been FALSE since #68 and nothing went red — because nothing executes it. grep finds no runner for Mustfile contracts; validate-a2ml.sh only parses them as TOML. So a critical contract silently became false. Repointed to GOVERNANCE.md, and the assertion now genuinely holds — but the contracts being declarative-only is a separate gap, filed rather than papered over here. 2. push-email-notify.yml — deleted, not left disabled ----------------------------------------------------- Estate dual-use policy removes push-email everywhere except 007, robodog-defensive-systems-lab and defensive-multiplicity. statistikles is not one of the three, so it was already `disabled_manually`. Verified dormant: PUSH_EMAIL_ENABLED is not set on this repo, and nothing else references it. Deleting beats leaving it disabled — a disabled-but-present workflow reads as an oversight to the next person, and it is one re-run of a farm sweep away from being re-enabled. Verified: all 18 remaining workflows parse and declare jobs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
|
|
Note Automatic reviews are paused because your trial's included automatic processing has been used for this period. Upgrade now, or comment "Gitar review" to run a review anytime. Code Review ✅ ApprovedRestores four parse-dead workflows caused by malformed scalar permissions and adds a dogfood validation gate to prevent recurrence. No issues found.
OptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Gitar |




Four gates are dead on
mainright now. This restores them and stops the loop.What is broken
zig.yml,e2e.yml,container-build.yml,install-smoke.yml— the Zig FFI gate, theJulia test suite, the container build and the install smoke test — are unparseable:
All four declare permissions in the scalar form. Hanging a mapping key under a scalar
is invalid YAML.
Why nobody noticed
Actions rejects a malformed workflow at parse time → zero jobs, no check run.
Not a red X — an absence.
gh pr checksshows nothing wrong.The only visible tell, and how this was caught:
When
gh run listprints a path where it normally prints a name, the workflownever parsed.
How it came back
#68’s stated purpose (repointing codeql-action at a SHA that exists) was correct and is
untouched here. It simply carried the sweep along with it.
Same root cause both times: the sweep matches
permissions:as text, not as a YAMLnode, so it cannot distinguish the scalar form from the mapping form. The insertion is
redundant regardless —
read-allalready grants every read scope,actions: readincluded.The guard
Fixing this twice without a guard just queues up a third time. Added
.githooks/validate-workflow-yaml.sh, wired as the first job of the dogfood gate:parse every workflow, fail on any that does not parse or that declares no jobs — a
workflow can be valid YAML and still be inert.
Deliberately dumb and total. A text-only sweep cannot satisfy it.
Proven fail-closed, not assumed
exit 0— "all 19 workflows parse and declare jobs"actions: readreintroduced intozig.ymlexit 1— names the file and the reasonexit 0Case B is the one that matters: the guard fails on the exact defect it exists to catch.
Verification
yaml.safe_loadZig FFI,E2E + Aspect,Container Build,Install Smokeappear by NAME inthe checks below — their appearance is the fix; absence is the failure mode
Workflows parse (no silent-dead gates)passesFollow-up
The sweep script itself should be made YAML-aware before it is run against the estate
again — this repo is unlikely to be the only one with scalar
permissions:blocks.