Release A step 4: deployment state, blue/green activation, publishing rewrite #7
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Full spec:
docs/separation-plan.mdon branchsite-separation, section "4. Deployment and Ansible" + "Revision and deployment model". This issue is Release A, step 4 — the deployment-state/activation/publishing half of the site-separation plan. Steps 2–3 (site contract, extraction, compatibility CI) are already done (see the plan's own Status Log). This step is NOT done and is a precondition for cutting over production to the site-separation model.Scope, in the plan's own implementation order:
docs/runtime-inputs.mdalready has the audit; the "apply on publish" decision for booking hours/email templates/sender name is already made — 2026-10-15). Remaining: actually move those runtime reads off the live checkout onto a release snapshot (see below).git worktreeat the target SHA) and an immutable site checkout at the resolved SHA.deployswap's in-place binary swap: Two slots (coach-api@<site>-a/-b), one atomiccurrentpointer switch + nginx reload for both HTML and API together. The invariant: the live deployment is always either the previous healthy pair or the new healthy pair, never a mix.refs/publish-attempts/<attempt-id>), idempotent attempt IDs, forward-only site-history policy, separate "publish accepted" vs. "deployment succeeded/failed" outcomes reported to the admin.flock-based lock per site instance covering the whole attempt (revision selection → activation → manifest update), replacing today's in-processrebuildMu(which doesn't coverdeploy.shrun bycoach-deploy.service).make releasetarget + acd.ymlfirst step that both refuse to tag/deploy a commit without a passing cross-site compatibility result bound to that exact SHA.systemd-rununits (DynamicUser=yes, minimal root, no secrets, no network, output as a tar stream over stdout) — treatsite/client/layoutsas potentially hostile code. Step-0 prototypes already proved the sandbox/blue-green/publication-recovery guarantees on a Debian 12/systemd 252 VM (2026-10-14, seetools/prototypes/README.md); rerun on the actual production host with the pinned Hugo version before cutover.Production-readiness gates (from the plan, must pass before cutover — not new scope, just the acceptance criteria):
X-Release-Idprobe + health checks).Do not expand this issue's scope beyond what's above — the plan is explicit that Release A should not grow further once this lands.
Started. First slice landed:
fa797a3onsite-separation— "apply on publish, not on admin Save" (the plan's finding 1 / already-decided 2026-10-15 item fromdocs/runtime-inputs.md).internal/locales.ReloadOverridesis now startup-only;HandleSaveContentcalls a new pureValidateOverridesfordata/email-templates.yaml(validates, never applies), and thesite.yamlsender-name live-apply call is removed entirely. Tests updated (TestHandleSaveContent_EmailTemplates_ValidContentSavesButDoesNotApplyLivereplaces the old "...AppliesLive" test) and full suite (go build ./...,go test ./...) passes.Remaining before this issue is done, in the plan's own order:
deployswap's in-place swap).site.yaml/features.yaml/email-templates/language-list reads offContentRootonto the release'ssite/snapshot (needs release directories to exist first).Admin UI copy noting "applies on publish" (the plan also asks for this) not yet added — deliberately deferred rather than rushing unreviewed copy; needs i18n (en/fr parity,
tests/layout_strings_test.go's no-hardcoded-strings check) done properly, not as an afterthought to this commit.Candidate checkouts landed:
3b12511on site-separation. New internal/deployment package — NewCandidateCheckout(buildsRoot, attemptID, engineRepoDir, engineSHA, siteRepoDir, siteSHA) builds one attempt's isolated engine (git worktree, no network) + site (local clone, real independent .git) pair, never touching either live checkout. Cleanup deregisters the worktree and removes the attempt dir, idempotent. 6 tests against real git repos (no mocks): exact-SHA checkout, live checkouts untouched, duplicate attempt IDs rejected, failure leaves no dangling worktree, Cleanup idempotent, two sites' builds roots independent. Full go build/vet/test ./... passes.Deliberately NOT done here (next steps, in the plan's order): resolving a branch to a SHA (the coordinator's job, "site revision rule" — this package only ever takes already-resolved SHAs), immutable build jobs, the attempt journal, recovery, release directories + blue/green activation, runtime snapshot wiring, the publishing rewrite, per-site locking, the release gate, and the build-isolation sandbox.