docs(ops): bring the cutover runbook in line with the live cluster - #172
Merged
Conversation
Docs-only plan: bring the cutover runbook and the operator docs it leans on into line with the environments that exist as of 2026-09-10 (cfp-live-cluster, GitOps release pins, filesystem private storage, the published-branch refresh pipeline, the Slack SSO plan). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jmpurQpBHXD9yLFEGUriR
The runbook still described a DNS flip with a lowered TTL, a staging host that never existed, an S3 bucket, a data-repo `main` branch, and a T+90/T+180 claim window + password purge. None of that matches what is deployed: - Production runs in cfp-live-cluster (ns codeforphilly-ng) at next.codeforphilly.org, alongside laddr in code-for-philly. The apex and *.codeforphilly.org already resolve to that cluster's gateway, so T-0 is one commit moving the apex/www listeners and HTTPRoute hostnames from _gateways/code-for-philly.yaml to _gateways/codeforphilly-ng.yaml and flipping CFP_SITE_HOST. Rollback is a revert of that commit. - The data repo has no `main`; the refresh is import -> merge legacy-import into published (thousands of deleted-by-us conflicts for pruned spam, resolved by taking the import) -> prune -> push, which hot-reloads sandbox and prod. First run: 36,254 -> 22,625. - Slack SAML can only be tested in the real workspace, so the plan is SSO-optional first, Test configuration against the next.* metadata, then update only the SSO URL at cutover. A bad SAML flip is fixed in Slack, not by moving the hostname back. - Legacy password sign-in persists indefinitely per account-migration.md; the T+90 mailout and T+180 purge sections are gone, and the announcement templates no longer tell members their password is going away. - Monitoring: nothing external exists yet; the T+1h window says so instead of pointing at UptimeRobot. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jmpurQpBHXD9yLFEGUriR
…itOps Image publishing is no longer manual and production is not a future `cfp-prod-cluster`: container-publish.yml pushes :vX.Y.Z on every release tag, and each cluster repo (cfp-sandbox-cluster, cfp-live-cluster) pins the app by .holo/sources/codeforphilly-ng.toml plus images[].newTag in codeforphilly-ng/app/kustomization.yaml, applied through the releases/k8s-manifests -> deploys/k8s-manifests PR. The hand-built :sandbox image is kept only as an emergency escape hatch. Private storage is a filesystem PVC in both environments; the S3 sections are marked supported-but-unused rather than "production". Secrets are the three SealedSecrets in cfp-live-cluster/codeforphilly-ng.secrets/ (codeforphilly-secrets, codeforphilly-saml carried over from laddr's saml2, the deploy key), edited with kubeseal --merge-into. Namespaces, the hot-reload secret name, the pod-clone volume type and the monitoring status note are corrected to match. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jmpurQpBHXD9yLFEGUriR
The export command pointed at a `laddr` database and a `users` table with Handle/PasswordHash columns that don't exist. The live database is `emergence-site` (the `codeforphilly` schema on the same server is a stale 2024 copy), table `people`, columns Username/Email/Password, and the export runs inside the laddr pod with the Habitat-packaged mysql client against the service's client.cnf. The production load is kubectl cp onto the pod's private-storage PVC followed by a rollout restart, same as sandbox; the GCS/S3 upload section is reduced to a note for the unused s3 backend. Records the first prod load (2026-09-10, 21,761 profiles/credentials) and warns that repeating it resets rehashed credentials now that sign-ins are live at next.codeforphilly.org. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jmpurQpBHXD9yLFEGUriR
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015jmpurQpBHXD9yLFEGUriR
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Docs-only. Brings
docs/operations/cutover.mdand the operator docs it leans on into line with what actually exists as of 2026-09-10, so the person running cutover isn't reading instructions written before the live cluster, the release flow, or the first data refresh existed. Plan:plans/cutover-runbook-reality.md.What changed
cfp-live-cluster/ nscodeforphilly-ng/next.codeforphilly.org(alongside laddr incode-for-philly); sandbox iscfp-sandbox-cluster/ nscodeforphilly-rewrite-sandbox/next-v2.codeforphilly.org.cfp-prod-clusterandcodeforphilly-rewrite-staging.k8s.phl.ioare gone from every doc; there is no separate staging.wwwlisteners + HTTPRoute hostnames from_gateways/code-for-philly.yamlto_gateways/codeforphilly-ng.yamland flippingCFP_SITE_HOST; rollback isgit revert.next.codeforphilly.orgstays as a permanent alias. TTL-lowering and DNS-propagation steps removed.develop→Release: vX.Y.Z→ tag →container-publish.yml; cluster repos pin via.holo/sources/codeforphilly-ng.toml+images[].newTag, applied throughreleases/k8s-manifests→deploys/k8s-manifests. "Manual today" language removed; the:sandboxbuild is an emergency escape hatch only.legacy-credentials-import.md, the bucket checklist item, and thedeploy.mdbucket-provisioning section are replaced/qualified (S3 stays a supported, unused backend).cfp-live-cluster/codeforphilly-ng.secrets/(codeforphilly-secrets,codeforphilly-samlcarried over from laddr'ssaml2,codeforphilly-data-deploy-key),kubeseal --merge-intorecipe, GitHub OAuth org app "Code for Philly" with no callback edit at cutover.SAML_ENTITY_ID; SSO-optional first, Slack "Test configuration" against thenext.*metadata, update only the SSO URL at T-0; rollback note says a bad SAML flip is fixed in Slack, not by moving the hostname.main; pipeline is import → mergelegacy-importintopublished(thousands of deleted-by-us / modified-by-them conflicts for pruned spam, resolved by taking the import) → prune → push;notify-deployments.ymlhot-reloads sandbox + prod and its prod URL must move to the apex at cutover. First refresh 2026-09-09/10: 36,254 → 22,625.emergence-site.people(Username,Email,Password) via the Habitat mysql client inside the laddr pod; load iskubectl cp+rollout restart. First prod load 2026-09-10: 21,761.account-migration.mdlegacy password sign-in persists indefinitely); dangling#cutover-window-policylink removed; announcement templates no longer tell members their password is going away.sandbox-deploy.mdnow says GitOps is the path; namespace fixes (-n codeforphilly,codeforphilly-staging);codeforphilly-rewriterepo-name mentions in ops docs;.claude/CLAUDE.mddeploy section.Verified against local clones
cfp-live-cluster(pins, gateways, secret names/keys, kustomization patch),cfp-sandbox-cluster,codeforphilly-data-published(notify-deployments.yml),CodeForPhilly/opstf/dns, and theBuild k8s-manifestsworkflow.Not verifiable from the repos (encoded as stated by the operator)
Slack SSO behavior (enterprise-only test workspaces, "SSO optional" fallback), GitHub OAuth app names and the subdomain-redirect behavior, the MySQL schema/table/column names and Habitat client path, the merge-conflict shape, and the import/load counts.
Spec drift noticed, not fixed here (docs-only PR)
specs/architecture.md:STORAGE_BACKEND"s3in production"; entrypoint "git reset --hard origin/main";overlays/staging/+overlays/production/.specs/behaviors/private-storage.md: "s3backend (production)" and the bucket-versioning requirement, while both deployed environments runfilesystemon a PVC with no versioning.cutover-mailout.tstemplate says "Accounts unclaimed for one year may be retired" — no spec backing.Recorded in the plan's Follow-ups.
Validation
npm run lintclean (no code touched).cfp-prod-cluster,staging.k8s,cutover-window-policy,T+180,RESEND,-n codeforphillyreturn nothing underdocs/and.claude/.🤖 Generated with Claude Code
https://claude.ai/code/session_015jmpurQpBHXD9yLFEGUriR