CI & Deploy Verify
End-to-end health check for wcygan.net. Three phases, always run in order — each phase short-circuits diagnosis for the next.
Phase 1 — GitHub Actions CI on main
gh run list --branch main --limit 3
Look at the top row:
completed+success→ CI green, move to phase 2.in_progress/queued→ wait for it. Options:- Block:
gh run watch <id> --exit-status - Glance: rerun
gh run list --branch main --limit 1
- Block:
completed+failure→ stop. Fix CI first.- Get the failed step:
gh run view <id> --log-failed | tail -80 - Rerun after fix:
gh run rerun <id>(same commit) or push a new commit.
- Get the failed step:
The workflow is .github/workflows/ci.yml — build → typecheck → test.
Phase 2 — Cloudflare deploy
deno task --eval "wrangler deployments list" | tail -12
Each deploy entry has Created: timestamp and a version ID. The most recent one should be newer than your push time. If not:
- Cloudflare Workers Builds may still be running — check the Cloudflare dashboard (Workers & Pages →
wcygan-net→ Deployments). - If multiple pushes happened in quick succession, only the latest produces a live deploy (Cloudflare debounces).
For a specific version:
deno task --eval "wrangler deployments list --name wcygan-net"
deno task --eval "wrangler versions list --name wcygan-net" | tail -10
Phase 3 — Regression suite against production
./scripts/verify-prod.sh
Exit 0 = all checks pass. Exit 1 = at least one check failed, with per-check diagnosis printed.
Covers:
- Core routes return 2xx/3xx:
/,/about,/posts,/really-good-software. - Static-asset dot-rejection guard:
/rss.xml,/will_cygan_resume.pdf,/favicon.ico→ 200. Validates thatsrc/lib/routing/static-asset-guard.tsstill works in prod. - Removed routes stay 404:
/feed,/mermaid-examples. Guarantees the audit cleanup didn't regress. - RSS content:
/rss.xmlis well-formed XML with<rss>root and<atom:link>self-reference. - Build fingerprint: homepage HTML contains
__TSR_(TanStack build) and no__sveltekit(stale Worker).
Run against a preview or local build:
./scripts/verify-prod.sh --base http://localhost:3000
./scripts/verify-prod.sh --base https://<branch>.wcygan-net.pages.dev
Verbose mode prints the URL + status code on failure:
./scripts/verify-prod.sh --verbose
One-shot end-to-end
gh run list --branch main --limit 1 \
&& deno task --eval "wrangler deployments list" | tail -6 \
&& ./scripts/verify-prod.sh
All three exit cleanly → deploy is healthy.
Common failure patterns
| Symptom | Phase | Likely cause | Next step |
|---|---|---|---|
| CI failed on typecheck | 1 | routeTree.gen.ts stale — deno task build must run first |
Check .github/workflows/ci.yml build step order |
| CI green, no new Cloudflare deploy | 2 | Cloudflare Workers Builds not configured to watch branch | Dashboard → Workers & Pages → project → Settings → Builds |
Phase 3 fingerprint fails (__sveltekit present) |
3 | Old CDN cache or failed deploy | Load verify-live-stack skill; purge zone cache if needed |
/rss.xml → 404 but CI is green |
3 | public/rss.xml not committed or Nitro copy failed |
Verify public/rss.xml exists locally and in .output/public/ |
/feed → 200 (regression) |
3 | Someone re-added src/routes/feed.tsx |
Grep repo for feed.tsx; remove route |
Dot-rejection /will_cygan_resume.pdf → 404 in prod |
3 | isStaticAssetSlug changed or guard removed |
Check src/lib/routing/static-asset-guard.ts and its test |
| Phase 1 + 2 pass, homepage 5xx | 3 | Runtime error in prerendered HTML or Worker config drift | Check Cloudflare dashboard → Workers → Logs |
Related skills
verify-live-stack— deeper fingerprint/cache diagnostics when Phase 3 fails (e.g., distinguishing stale CDN vs failed deploy).cloudflare-static-deploy— the deploy pipeline this skill verifies the output of.github-actions-troubleshooter— when Phase 1 fails and you need to fix the workflow itself.
Adding new regression checks
Edit scripts/verify-prod.sh — it's plain bash using curl + grep, no deps beyond what ships on macOS / Ubuntu. Use the existing helpers:
status_is URL CODE— exact status matchstatus_in URL CODE [CODE ...]— status is one ofbody_contains URL PATTERN— response body matches grep pattern
Each check wraps with check "name" <helper> <args>. Failures are counted and named in the summary. Keep checks independent — no shared state between them.