engineering / pipeline

Push → tests → tag → publish → live QA. Nobody touches a version number.

Every merge to dev becomes a numbered, tested, published release without a human in the loop — and the pipeline checks its own work after deploying.

this deploy
commit
pipeline run
The principle

If releasing takes effort, you stop releasing

A vibe-coded service usually dies one of two deaths: it stops shipping (because deploys became scary) or it ships broken (because deploys were manual). The fix for both is the same and it is cheap: make the pipeline own the release. Here the version file is written only by CI — a rule the team's own agents must obey — so every push to dev produces exactly one tag, one changelog anchor, one published site, in order, every time.

push to dev
   │
   ▼
 test        31 unit tests + 2 Playwright integration suites — red gate = no release
   │
   ▼
 tag         version bumped + git tag pushed by CI (minor on dev, major on main)
   │
   ▼
 publish     version stamped into every page footer + version.txt,
             every same-origin asset URL cache-busted with ?v=<version>,
             engineering JSON emitted, site deployed to GitHub Pages
   │
   ▼
 live QA     the pipeline then fetches the LIVE site: right version? every stamped
             asset resolves? samples, prompts, engine origin + CORS, outbound links?
The estates

Two branches, two estates, one gate

dev → GitHub Pages (production, for now)

dev publishes the live domain after the full gate. Decision of 6 Aug 2026: dev and main go to the same place for now, and dev is treated as production; a separate main estate is a future split, stated publicly rather than implied.

qa → Netlify (preview)

The qa branch runs the same test gate, then deploys to Netlify stamped <next-version>-qa.<sha> — the next release previewed under an honest name. The version file is never touched here; the truth comes from the tags.

A caught bug that shaped this pipeline

After one deploy, the page offered a new checkbox while the browser was still running the previous release's JavaScript — GitHub Pages caches modules for ten minutes (issue 026). Since then CI stamps ?v=<version> onto every same-origin asset URL, so fresh HTML can never pair with stale code, and the live-QA job verifies every stamped URL resolves.

Receipts