# CI/CD Workflows This repo's `.github/workflows/` set, and the reasoning behind each — including the ones deliberately **not** built, per this project's rule that scaffolding presented as working is worse than an honest gap. That rule is why five workflows were removed in the audit below: each of them was scaffolding that could not succeed as written, and a permanently red check is worse than no check, because it trains everyone to ignore the red. ## Implemented | Workflow | Trigger | What it does | |---|---|---| | `ci.yml` | push/PR to `main` | TS/JS: typecheck, full test suite, build, `npm audit --audit-level=high` (Node 20.x/22.x/24.x matrix) | | `php-ci.yml` | push/PR touching `ports/php/**` | PHP: composer install + PHPUnit (8.1–8.3 matrix) | | `go-ci.yml` | push/PR touching `ports/go/**` | Go: build, vet, gofmt check, tests w/ coverage (1.21–1.22 matrix) | | `linter.yml` | push/PR | Static checks across all three languages: `tsc --noEmit`, `go vet`+`gofmt`, `php -l` | | `dependency-review.yml` | PR | Blocks PRs introducing high-severity vulns or copyleft-licensed deps (GPL/AGPL, which would conflict with our Apache-2.0 license) | | `labeler.yml` + `.github/labeler.yml` | PR | Auto-labels PRs by changed path (`lang: typescript`, `lang: php`, `lang: go`, `security`, `i18n`, etc.) | | `label.yml` + `.github/labels.yml` | push to label config | Keeps the repo's label set in sync with a version-controlled definition | | `publish.yml` | GitHub release published | Orchestrates `npm-publish.yml` and posts a job-summary checklist of the *other* publish targets that still need a manual step (Packagist, Docker, static hosting — see DEPLOYMENT.md) | | `npm-publish.yml` | called by `publish.yml`, or manual dispatch | Publishes to npm with provenance; requires an `NPM_TOKEN` secret | | `pages.yml` | push touching the demo/core, or manual | Deploys the vanilla-JS demo to GitHub Pages | | `stale.yml` | daily schedule | Marks inactive issues/PRs stale after 60 days, closes after 14 more (exempts `security`/`pinned`) | | `greetings.yml` | first issue/PR from a contributor | Welcome message pointing new PR authors at test/security expectations | | `generate-wiki.yml` | push touching root docs | Mirrors the root-level `.md` docs into the repo's GitHub Wiki (`README.md` → wiki `Home.md`) | | `linter.yml`'s `ts-lint` job | push/PR | Also runs `scripts/check-action-pins.mjs`, which fails if any action is referenced by tag instead of a full commit SHA | | `pages.yml`'s verify step | push touching demo/core/workflow | Runs `scripts/verify-pages-site.mjs`, which walks the module graph the demo actually imports and fails on a `node:` import or a Node-only global | CodeQL scanning is **not** in this table on purpose — it runs through GitHub's **default setup** (Settings → Security → Code scanning), which covers JavaScript/TypeScript, Go, Rust, and Actions. See the removals below for why there is no `codeql.yml` alongside it. ### Requires repository settings, not just the file Two of the above need configuration outside the workflow file, and will fail with a confusing error until it exists: - `pages.yml` — Settings → Pages → Build and deployment → Source must be **GitHub Actions**. Without it, `actions/deploy-pages` fails at the deploy job. - `generate-wiki.yml` — the repository Wiki must be enabled (Settings → Features → Wikis) and initialized with at least one page. The action cannot create the wiki repository from nothing. ## Removed in the workflow audit | Workflow | Why it was removed | |---|---| | `codeql.yml` | CodeQL **default setup** is enabled on this repo. GitHub refuses to process results from an advanced-configuration workflow while default setup is on, so this file could only ever produce a failed run. Default setup also covers more languages (Go, Rust, Actions) than this file's `javascript-typescript`-only matrix. If you ever need custom query packs, switch default setup off *first*, then restore this file. | | `summary.yml` | Ran the TS, Go, and PHP suites again on every push — duplicating `ci.yml`, `go-ci.yml`, and `php-ci.yml` — purely to render a summary table. It also could not pass: it called `phpunit` without installing it (`setup-php` was given no `tools:` input) and without a `composer install`. It was the only workflow never documented in this file. | | `screenshots.yml` | Could not run as written. `npx playwright install` fetches browsers but does not add `playwright` to `node_modules`, so the inline `require('playwright')` failed; `http-server` was likewise not a dependency. Even past that, `examples/vanilla/index.html` imports `../../dist/index.js`, which sits outside the directory being served, so the page would never render a `` for the screenshot. It also pushed commits directly to `main`. | | `fix-code.yml` | `npm run lint -- --fix --if-present` forwards `--if-present` (an *npm* flag) to ESLint, which rejects it as an unknown option — and the `lint` script is itself broken under ESLint 9 (see below). Beyond that, auto-committing to a pull request's head branch, which may live in a fork, is a pattern worth avoiding rather than repairing. | | `release-please.yml` | Release Please owns version bumps and tags, deriving them from conventional commits. This project releases in manual staged increments with hand-applied tags, so the two approaches fight over the same files (`package.json`, `.github/.release-please-manifest.json`, `CHANGELOG.md`). Pick one. Restoring this file is fine — but then stop bumping versions and tagging by hand, and let the release PRs do it. | ## Fixed rather than removed - **`ci.yml`** — the `permissions:` block was indented one level too deep, so YAML parsed it as an event named `permissions` under `on:` rather than as a top-level key. The workflow was running with the repository's default token permissions and the intended read-only restriction never applied. This is the residue of an automated "Workflow does not contain permissions" fix that landed in the wrong place; the same pattern is worth checking whenever one of those autofix PRs is merged. - **`npm-publish.yml`** — it listened for `release: published` *and* was invoked by `publish.yml`, which listens for the same event. Every release therefore started two publish runs, the second failing with a 403 because the version already existed on the registry. It now exposes only `workflow_call` and `workflow_dispatch`. - **`generate-wiki.yml`** — referenced `MASTERPROMPT.md` and `MASTERPROMPT-STAGES.md`, which do not exist in this repository. Its copy loop was also one reordering away from failing the step outright: `run:` executes under `bash -e`, and a bare `[ -f x ] && cp x` returns non-zero when the test fails, so a missing file in the *last* iteration would fail the job. Both are fixed, and `WORKFLOWS.md` is now mirrored to the wiki too. ## Known-broken, tracked separately - **Resolved (kept for the record):** `npm run lint` used to fail because ESLint 9 requires a flat `eslint.config.js`, which the repo lacked. Fixed in v0.7.2; the job is green. - **`ports/rust/`** does not build: `Cargo.toml` declares `src/lib.rs`, `tests/{model,formula,formats}_tests.rs`, and `examples/parity_check.rs`, none of which exist — the directory contains only `src/formula.rs`. This is also why CodeQL reports "Low Rust analysis quality" against the repo. ## Deliberately not implemented | Name (from reference list) | Why it's skipped, honestly | |---|---| | `defender-for-devops` | **Correction:** an earlier version of this table claimed this needs an Azure subscription the project doesn't have. That is wrong — `microsoft/security-devops-action` runs its open-source analyzers without one, and it runs green today in the sibling repo [LombokCharts](https://github.com/codinglombok/LombokCharts). The honest reason it isn't here is that it hasn't been prioritised: CodeQL default setup plus `dependency-review.yml` already cover SAST and dependency vulnerabilities, so the marginal value was judged low. Worth adding if you want its extra analyzers. | | `ossar` | **Correction:** an earlier version of this table claimed OSSAR had been retired and would fail on first run. That is wrong — `github/ossar-action` is still published (v2.0.0) and runs green today in [LombokCharts](https://github.com/codinglombok/LombokCharts). As above, the real reason is priority, not impossibility: CodeQL and `linter.yml` cover the same ground. | | `static` | Ambiguous name in the reference list — most likely "static analysis," which CodeQL (security-focused) and `linter.yml` (correctness/formatting-focused) already cover between them. Adding a third workflow with unclear scope would be duplication, not more rigor. | | `dist` | Likely a "build and attach dist artifacts to release" step — folded into `npm-publish.yml`, which already runs the build before publishing rather than needing a separate artifact-only workflow. | | `visual` / `visual-baselines` | Real visual regression testing (screenshot diffing against an approved baseline) needs an actual first-run to establish those baselines, a storage location for them, and a review process for intentional visual changes. Building a `visual-baselines` workflow with no real baseline images behind it would be fake infrastructure. This is left as an honest gap — worth doing once the Table/Sheet visual design stabilizes enough that baselines are worth committing to. | Both corrections above came from the same mistake: asserting from memory that a tool was unavailable, instead of checking. A table headed "deliberately not implemented" is worthless if its reasons are invented — "we didn't get to it" is a fine entry; "this cannot work" needs evidence. If you disagree with any of these calls — e.g. you do have Azure DevOps credentials, or you want to seed real visual-regression baselines — that's a legitimate reason to build the corresponding workflow for real. The point isn't that these are permanently out of scope, it's that they weren't faked here.