- Difficulty:
- beginner
- Tools:
- github-actions, node
Problem
Documentation and directories publish code that is never executed again after it is written. It rots on someone else's release schedule, and the first person to find out is a reader who pastes it and it fails.
Trigger
Every push, through the CI workflow, and weekly against production.
Prerequisites
- 01Snippets stored as data with a declared format, not embedded in prose.
- 02The checkers available on the runner. bash, node and python3 ship on GitHub-hosted Ubuntu.
Steps
- 01
Store the declared format alongside every snippet
Without it there is nothing to check against, and a checker has to guess.
- 02
Parse each snippet with the real tool for its format node
bash -n for shell, node --check for JavaScript, a YAML and XML parse, a field count for cron. Write to a temp file whose extension the tool expects.
- 03
Check the content rules you claim to hold, in the same pass
Slug shape, field lengths, ordering, references that must resolve. A rule nothing enforces is a preference.
- 04
Exit non-zero and name every failure github-actions
One report listing every problem beats failing on the first one.
Payload · yaml
name: CI
on:
push:
branches: ["**"]
pull_request:
# The operator's machine cannot build this project: Turbopack fails to bind a
# worker port there, so local builds run --webpack while Vercel builds with
# Turbopack. That makes CI the only place a trustworthy build signal exists.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
verify:
runs-on: ubuntu-latest
env:
# Public by construction: this is the NEXT_PUBLIC_ Convex URL the browser
# already receives. Static generation reads published records at build.
NEXT_PUBLIC_CONVEX_URL: https://exciting-deer-586.convex.cloud
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- name: Types
run: npx tsc --noEmit
- name: Lint
run: npm run lint
- name: Corpus conformance
run: node scripts/check-payloads.mjs
- name: Build
run: npx next build
- name: Audit production dependencies
run: npm audit --omit=dev --audit-level=highFailure modes
- !Node picks a module format from the file extension, so a snippet written to a .javascript file fails to parse for a reason that has nothing to do with the snippet.
- !A parse check proves syntax and nothing else. A script that parses cleanly and deletes the wrong directory passes.
- !Checking only the source file misses drift in what is actually published, if the two can differ.
JSON-LD · HowTo
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "Fail the build when published content stops being valid",
"description": "A CI step parses every code snippet a site publishes using the real tool for its declared format, so a snippet that stops being valid breaks the build instead of sitting published and wrong.",
"url": "https://automationsanonymous.com/automations/fail-the-build-when-published-content-stops-being-valid",
"tool": [
{
"@type": "HowToTool",
"name": "github-actions",
"url": "https://automationsanonymous.com/tools/github-actions"
},
{
"@type": "HowToTool",
"name": "node",
"url": "https://automationsanonymous.com/tools/node"
}
],
"step": [
{
"@type": "HowToStep",
"position": 1,
"name": "Store the declared format alongside every snippet",
"text": "Without it there is nothing to check against, and a checker has to guess."
},
{
"@type": "HowToStep",
"position": 2,
"name": "Parse each snippet with the real tool for its format",
"text": "bash -n for shell, node --check for JavaScript, a YAML and XML parse, a field count for cron. Write to a temp file whose extension the tool expects.",
"url": "https://automationsanonymous.com/tools/node"
},
{
"@type": "HowToStep",
"position": 3,
"name": "Check the content rules you claim to hold, in the same pass",
"text": "Slug shape, field lengths, ordering, references that must resolve. A rule nothing enforces is a preference."
},
{
"@type": "HowToStep",
"position": 4,
"name": "Exit non-zero and name every failure",
"text": "One report listing every problem beats failing on the first one.",
"url": "https://automationsanonymous.com/tools/github-actions"
}
],
"datePublished": "2026-09-06T19:19:25.857Z"
}