disaster-control/workplans/DISCTL-WP-0002-resilience-foundation.md
codex cf487a9fa2
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
fix(workplan): point workplan at its authoritative projection id
The file carried an identifier minted by the retired local hub while central
held a different record for the same file — ADR-010's same-filename,
different-UUID duplicate-registration class.

Central is authoritative (ADR-010 decision 1) and decision 6 says to mitigate
by changing the repository file rather than editing central, so the file adopts
central's id. The cache-side id dies with the cache.

Refs CUST-WP-0068

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2583210@bnt-lap001
Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
2026-08-25 17:37:50 +02:00

5.6 KiB
Raw Permalink Blame History

id type title domain repo status owner topic_slug created updated state_hub_workstream_id
DISCTL-WP-0002 workplan Resilience foundation: registers, policy, first tested restore infotech disaster-control finished grok custodian 2026-07-04 2026-07-07 73d2ecb3-e594-4a7c-920d-8753198eb6ec

Resilience foundation: registers, policy, first tested restore

Stand up the minimum viable Resilience Control Plane for Coulomb Social / Helix Forge: know what exists (registers), what must survive (policy, RTO/RPO), how it comes back (runbook, panic sheet), and prove it once (drill + evidence).

Driven by history/2026-07-04-initial-risk-analysis.md — priority order R2 (untested restores), R9 (silent backup failure), R3 (backup-deleting breach), R4/R5 (identity & secret recovery), R10 (control plane single-homed), R1 (full server loss). Design source: specs/ResilienceControlSetup.md.

The same-day Forgejo/Railiance assessment (history/2026-07-04-forgejo-backup-strategy-assessment.md) proved the Forgejo restore path (RAIL-HO-WP-0005-T09) and handed this repo a pickup queue: its items 78 are T03/T04/T06 below; its cross-repo items are tracked by T08.

Mirror disaster-control off the primary Gitea (R10)

id: DISCTL-WP-0002-T01
status: done
priority: high
state_hub_task_id: "0d7e27f6-1290-45da-b76a-407b7b039e95"

This repo must survive the disasters it describes. Add at least one mirror on infrastructure independent of CoulombCore/Gitea (e.g. GitHub private mirror or secondary machine), document the mirror location in README, and note how the mirror is refreshed.

Asset and data registers with Tier-0 recovery paths (R4, R7, R8, R12)

id: DISCTL-WP-0002-T02
status: done
priority: high
state_hub_task_id: "59f04771-25cf-4bde-adf0-8a1cd418dc1f"

Write AssetRegister.yaml and DataRegister.yaml seeded with the current stack: domains/DNS/registrar, email, Stripe, Bubble.io, OpenRouter, Gitea, CoulombCore content, k3s, databases, backup storage, secrets/OpenBao. Every T0 entry must record its recovery path (backup admin, MFA recovery, break-glass). Every T1 entry must name its source of truth and backup mechanism (or mark it backup: none honestly). Use the tier model from the spec (§2).

ResiliencePolicy and RTO/RPO matrix (R1, R6)

id: DISCTL-WP-0002-T03
status: done
priority: high
state_hub_task_id: "8c119835-0c97-4556-ab98-42267688e432"

Write ResiliencePolicy.md (operating principle, tier definitions, drill cadence, evidence requirement) and RTO-RPO-Matrix.md with explicit per-system targets, starting from the spec's suggested values (§3): RPO ≤ 24h everywhere, RTO ≤ 1 day full recovery, RTO ≤ 48h for code/content/control plane.

BackupPolicy with credential separation and monitoring (R3, R9)

id: DISCTL-WP-0002-T04
status: done
priority: high
state_hub_task_id: "d6b9b621-c901-48c0-be4c-7bc98245de99"

Write BackupPolicy.md: 3-2-1 + immutable/offline model, per-stream mechanisms (gitea dump + mirrors, restic, k3s etcd snapshots, Bubble/Stripe exports, SOPS/age secret vault), and two hard rules with verification steps — (a) backup-storage credentials never live on the production host with delete permission; (b) backup job success and repository integrity are checked on a defined schedule with a named alerting path.

Full-server-loss restore runbook and panic sheet (R1, R11)

id: DISCTL-WP-0002-T05
status: done
priority: medium
state_hub_task_id: "c413734b-7a17-4164-bf72-0de18fd509c4"

Write RestoreRunbooks/01-full-server-loss.md (new machine → Ansible → secret recovery → data restore → k3s redeploy → validate → DNS cutover → evidence report) and the one-page panic sheet: where backups are, who has access, how to rebuild, how to rotate secrets, how to switch DNS — written so a competent stranger could execute it.

First restore drill with evidence file (R2)

id: DISCTL-WP-0002-T06
status: done
priority: high
state_hub_task_id: "c816efa0-bbc2-4612-9a8f-a03bd83ca7c0"

The 2026-07-04 Forgejo drill (evidence in railiance-infra) proved that path; this task covers the next untested system: restore one Gitea repo/dump or decrypt the secret vault from cold, onto a clean target. Write TestEvidence/restore-drill-2026-MM-DD.md with measured RTO/RPO, result, issues found, and follow-up actions; also copy or link the Forgejo drill evidence so this repo holds the complete evidence trail. Define the recurring drill cadence (pickup item 7). This task is the exit criterion for the workplan: no drill evidence here, not finished.

Incident playbooks (R3, R4, R5, R6, R7)

id: DISCTL-WP-0002-T07
status: done
priority: medium
state_hub_task_id: "ee7254a8-5adf-4913-bb47-bf94e59c88ec"

Write the five playbooks under IncidentPlaybooks/: ransomware/hostile access, credential leak, accidental delete / data corruption, provider outage (Bubble/Stripe/OpenRouter/DNS/email), loss of admin identity. Keep each to one page of numbered steps per the spec (§6).

Track cross-repo backup pickup queue (R2, R9)

id: DISCTL-WP-0002-T08
status: done
priority: medium
state_hub_task_id: "af9ae2ca-5af8-45af-9301-8c28e78ea32a"

Drive closure of the cross-repo items from the Forgejo assessment's pickup queue (items 16: backup destination decision #7, CNPG ScheduledBackup, scheduled forgejo dump, railiance-backup tool, Gitea pre-cutover snapshot, apps-pg coverage). Implementation lives in railiance-platform / railiance-apps / railiance-infra; this repo tracks status and records the outcome in the registers and BackupPolicy as each item lands.