Release Process - Fighter90/career-ops-ui GitHub Wiki

Release Process

Verify a deploy by behaviour, not by the version string (v1.228.5). Until v1.228.5 /api/health re-read package.json per request, so a process still serving pre-deploy code reported the post-deploy version โ€” a deploy that copied files and never restarted looked like a success. The version is now captured at module load and describes the RUNNING code, so a stale process reports the old one. Still check something behavioural after every deploy: a route the release added, or a count the release changed. rsync without --delete also leaves files deleted upstream in place on the server, which is how a dangling symlink survived a release.

Doctrine: one fix per release

The default cadence is one change per release, sequenced HIGH โ†’ MEDIUM โ†’ LOW, never bundled โ€” a discipline proven over the 32-release v1.58.x cycle (all CI-green). Batching is justified only when items share the same CSS/tests surface and close out a cycle. Feature releases (like v1.118.0) are the exception and ship as one coherent parity pack.

Versioning

  • package.json is the source of truth (SemVer). The SPA footer reads it via /api/health.
  • The parent's VERSION file is reported separately as parentVersion โ€” the two drift independently (e.g. UI v1.118.0 โ†” parent v1.18.0).
  • Conventional commits: feat / fix / refactor / docs / test / chore / perf / ci, optional scope, ! for breaking.

The per-release checklist

Every release ships all of the following:

  1. Version bump in package.json.
  2. CHANGELOG ร—17 โ€” the English entry plus all 16 translated CHANGELOGs at the new version. Gate: scripts/check-changelog-parity.mjs.
  3. README ร—17 โ€” release banner, badges (tests count), and breadcrumb updated in all 17 READMEs.
  4. Help ร—17 โ€” every help-guide section touched by the release updated in all 17 docs/help/<lang>.md bundles; H2/H3 count gates bumped if sections were added.
  5. i18n keys ร—17 โ€” new UI strings in all 17 locale dicts + regenerated snapshot.
  6. Tests โ€” new coverage for the change; all four suite baselines (unit / Playwright / smoke E2E / comprehensive E2E) kept โ‰ฅ the previous floor (unit: 3210 at v1.237.1).
  7. QA prompt โ€” a new qa/QA-REGRESSION-PROMPT-v<version>.md delta driver (see Testing and QA).
  8. Docs/SDD โ€” docs/architecture/* updated in the same PR when routes/flows changed.
  9. Playwright live verify against the running server.
  10. Pre-commit AI review LGTM (advisory) + ci.yml green (the hard gate โ€” watch the run, not just the local hook).
  11. Redeploy the local instance.

Tag โ†’ Release โ†’ Publish

The flow to GitHub Packages (npm.pkg.github.com, package @fighter92/career-ops-ui):

  1. Merge to main with CI green.
  2. Push the tag v<version> โ€” the tag fires the Release workflow (GitHub Release creation).
  3. The Publish workflow is release-event triggered but must be dispatched manually when needed: gh workflow run โ€” never npm publish locally.

GSD pipeline (for non-trivial changes)

The repo uses spec-driven development: discuss โ†’ spec โ†’ plan โ†’ execute โ†’ verify โ†’ review via the gsd-* skills. No non-trivial code change without a written spec and plan first. Planning artifacts live in .planning/ (gitignored scratch); specs that graduate become permanent under docs/specs/ and docs/adr/. Trivial changes (single-file fix, typo, version bump) skip the ceremony.

Guardrails

  • Never --no-verify, --force, or git reset --hard without explicit approval โ€” pre-commit hooks fail for a reason.
  • One PR = one logical change; unrelated fixes get their own branch.
  • Branch protection on main; merges require green status checks (with the documented CodeQL false-positive dismissal exception โ€” see Security).
โš ๏ธ **GitHub.com Fallback** โš ๏ธ