WR-02: capture docker run exit directly (not the piped head exit) so a
chatty booting image can't SIGPIPE to 141 and false-PASS; require the
FATAL guard marker in output as a positive assertion.
WR-05: strip comment lines and use anchored fixed-string (grep -qF)
matching so a commented-out rule can't satisfy the hygiene check and
patterns aren't treated as regexes.
- Static assertions step: verifies .dockerignore exists, covers all forbidden
patterns (.env, node_modules, apps/api/scripts, .git, .planning, apps/api/tests,
apps/pwa/e2e), and --target production is still pinned in publish.yml (T-16-19)
- Boot-smoke step: runs freshly-built sha_tag image with NODE_ENV=production +
DEV_AUTH_BYPASS=true; fails if image starts (EXIT==0) or times out (EXIT==124),
passes on any other non-zero exit — proves D-08 guard fires in shipped image (T-16-18)
- Both steps ordered after build and before push; a hygiene failure blocks publish (T-16-20)
- Separate 'Build and push' into 'Build production image' (build only) and 'Push image' steps
- Creates insertion point between build and push for hygiene assertions (Task 2)
- Preserves --target production, Dockerfile path, both tags, and root context
- WR-04 immutable-tag-first push ordering preserved in push step
- Replace "three required checks (CI / fast-checks, CI / api, CI / harness)"
with the new gating surface: CI / fast-checks + CI / gate
- Note that CI / api and CI / harness are conditionally skipped on doc-only PRs
and gated via the always-running CI / gate aggregate
- Comment-only change; no job/step/env/trigger modified
- Create .gitea/workflows/publish.yml (push-to-main only, name=Publish)
- Strip publish job, push trigger, and MILESTONE env from ci.yml
- Eliminates orphaned CI / publish (pull_request) status on PRs
- Preserves all three required PR status contexts unchanged