Observe, Back Up, Restore, and Reconstruct
Recover customer outcomes by rebuilding each state owner in dependency order, not by trusting one green dashboard.
Run it in the public monorepo
This course is built around the public Zheta Kubernetes Lab monorepo. The excerpt below is runnable source, not pseudocode.
Source: services/evidence/app.py
for receipt, event in BROKER.receive("evidence"):
event["evidence_id"] = event.get("evidence_id") or __import__("hashlib").sha256(__import__("json").dumps(event, sort_keys=True).encode()).hexdigest()
STORE.append(event)
BROKER.acknowledge("evidence", receipt)
Code to reality
- Declared intent
- Receive broker deliveries, append idempotent evidence, acknowledge only after success, and expose tenant-scoped queries.
- Interpreter
- A background subscriber reads local HTTP-broker or SQS receipts; the SQL store deduplicates by evidence ID before acknowledgement.
- Software effect
- Append failure leaves a message available for redelivery; repeated delivery yields one durable event returned by an authenticated query.
- Hardware effect
- The evidence process consumes CPU for hashing and commits database pages to durable storage.
- Observable evidence
- Receipt and acknowledgement observations, forced redelivery, one stored evidence ID, authenticated organization query, and restart prove the contract.
Start with the people and the result they need
The source tables below remain the detailed contract. Begin with these customer paths:
- D29-UC-01
- Person: Support engineer
- Job: Diagnose a failed generated-app action across services
- Observable result: One trace joins customer request, logs, metrics, release, actor, and owned records without exposing secrets
- D29-UC-02
- Person: Disaster-recovery commander
- Job: Restore durable data and reconstruct the platform in an isolated account
- Observable result: Restored tenant and artifact pass integrity and lifecycle probes within RPO/RTO
Turn each customer job into a testable story
Now turn each customer job into a story with a result that an engineer can check:
- D29-US-01
- Story: As a support engineer, I want tenant-scoped traces connected to releases and services, so that I can diagnose without broad data access
- Observable acceptance: Accepted/denied queries record actor, tenant, time window, trace, release, service, result, environment, and audit ID
- D29-US-02
- Story: As a disaster-recovery commander, I want a rehearsed bottom-up reconstruction, so that backup claims become customer-visible recovery
- Observable acceptance: Dossier contains recovery point, Terraform/Git revisions, restored IDs, integrity checks, RPO/RTO, affected replay, unaffected control, and run
Add real state and observable proof
Finally trace each story through the system that owns its state and the evidence that proves the outcome:
- D29-FLOW-01
- Trigger: Support receives a failed publish evidence ID
- Responsible systems: OpenTelemetry instrumentation/collector, metrics/log/trace stores, Forge services, release/evidence stores
- Authoritative state: Each service store for domain state; telemetry stores for observations; provider audit for access
- Owned record: RecoveryPoint
- Observable evidence: Actor, tenant, trace, release, observations, owner-directed action, recovered response, environment, time, and audit ID
- Failure signal: Broken correlation, stale signal, secret/tenant leakage, wrong release, or failed replay
- D29-FLOW-02
- Trigger: Scheduled isolated recovery rehearsal begins
- Responsible systems: Backup service, Aurora/S3/KMS, Terraform, EKS, Argo bootstrap, GitOps, Kubernetes, probe runner
- Authoritative state: Backup catalog/data stores, Terraform state/Git, AWS/Kubernetes APIs, application/evidence stores
- Owned record: RestoreRun
- Observable evidence: Recovery point, restored resources, revisions, identities, integrity, probes, RPO/RTO, production control, environment, time, and run ID
- Failure signal: Missing key/snapshot, integrity mismatch, stale state, unavailable API, unready workload, wrong revision, or failed customer probe
The enterprise problem and today’s slice
Enterprise problem: Metrics can show a healthy pod while customer data is unrecoverable, and a backup can exist while restore credentials, keys, or procedures fail. Whole-course context: The incoming runtime scales workloads and machines with bounded evidence; today protects its durable state and operational knowledge. Today’s slice: We correlate metrics, logs, and traces; back up Aurora and object artifacts; rehearse restore into isolated staging; and reconstruct VPC, EKS, Argo CD, workloads, and customer flow from authoritative sources. End-of-day evidence: Recovery point, restore resource IDs, Git/Terraform revisions, cluster and workload identities, positive/negative customer probes, recovery times, environment, timestamp, run, and trace IDs form a disaster-recovery dossier. Still unsolved: Production launch approval and live traffic remain deferred.
Customer use cases
A backup is useful only if an accountable operator can restore a consistent customer workflow within objectives. Recovery point objective (RPO) bounds tolerable data loss; recovery time objective (RTO) bounds restoration time.
| Use case ID | Actor | Customer job | Success outcome | Denial or recovery evidence |
|---|---|---|---|---|
| D29-UC-01 | Support engineer | Diagnose a failed generated-app action across services | One trace joins customer request, logs, metrics, release, actor, and owned records without exposing secrets | Unauthorized tenant trace access is denied while scoped support access succeeds |
| D29-UC-02 | Disaster-recovery commander | Restore durable data and reconstruct the platform in an isolated account | Restored tenant and artifact pass integrity and lifecycle probes within RPO/RTO | Corrupt/incomplete restore is rejected; source production remains unaffected as positive control |
Actor-centred user stories
Observability and recoverability are related but not interchangeable: telemetry explains behavior, while backup and declarative sources recreate state. These stories require both.
| Story ID | Use case IDs | User story | Observable acceptance conditions |
|---|---|---|---|
| D29-US-01 | D29-UC-01 | As a support engineer, I want tenant-scoped traces connected to releases and services, so that I can diagnose without broad data access | Accepted/denied queries record actor, tenant, time window, trace, release, service, result, environment, and audit ID |
| D29-US-02 | D29-UC-02 | As a disaster-recovery commander, I want a rehearsed bottom-up reconstruction, so that backup claims become customer-visible recovery | Dossier contains recovery point, Terraform/Git revisions, restored IDs, integrity checks, RPO/RTO, affected replay, unaffected control, and run |
End-to-end product flows
Recovery must start from a declared customer impact and proceed through substrate, API, state, workloads, then product evidence. Restoring only one database is not a complete application recovery.
| Flow ID | Use case IDs | Path | Trigger | Numbered steps | Terminal evidence |
|---|---|---|---|---|---|
| D29-FLOW-01 | D29-UC-01 | Happy | Support receives a failed publish evidence ID | 1. Authorize tenant scope. 2. Resolve trace and release. 3. Inspect metrics, logs, spans, and owned records. 4. Identify failing boundary. 5. Repair through its owner. 6. Replay and compare. | Actor, tenant, trace, release, observations, owner-directed action, recovered response, environment, time, and audit ID |
| D29-FLOW-02 | D29-UC-02 | Recovery | Scheduled isolated recovery rehearsal begins | 1. Select immutable recovery point. 2. Create isolated network and data targets. 3. Restore database/artifacts and verify integrity. 4. Recreate EKS from Terraform. 5. Bootstrap Argo CD. 6. Reconcile digest from Git. 7. Run positive and denied lifecycle probes. 8. Measure RPO/RTO and destroy rehearsal safely. | Recovery point, restored resources, revisions, identities, integrity, probes, RPO/RTO, production control, environment, time, and run ID |
The minimal recovery model joins accountable action to a customer-observable proof.
System design derived from the flows
Different desired-state owners require a bottom-up order: AWS substrate, intended EKS API, Terraform mapping, Kubernetes controllers, GitOps revision, then customer response. A green upper layer cannot override a failed lower layer.
| Use case ID | Entry point | Responsible services | Authoritative store | Failure evidence |
|---|---|---|---|---|
| D29-UC-01 | Evidence/trace ID and scoped support portal | OpenTelemetry instrumentation/collector, metrics/log/trace stores, Forge services, release/evidence stores | Each service store for domain state; telemetry stores for observations; provider audit for access | Broken correlation, stale signal, secret/tenant leakage, wrong release, or failed replay |
| D29-UC-02 | Approved recovery runbook | Backup service, Aurora/S3/KMS, Terraform, EKS, Argo bootstrap, GitOps, Kubernetes, probe runner | Backup catalog/data stores, Terraform state/Git, AWS/Kubernetes APIs, application/evidence stores | Missing key/snapshot, integrity mismatch, stale state, unavailable API, unready workload, wrong revision, or failed customer probe |
The diagram climbs from stored recovery point through physical/cloud substrate to controllers, workload state, and customer evidence.
SRP keeps telemetry, backup, infrastructure, delivery, and domain restoration under separate owners; DRY rebuilds from the same modules and base. IoC/DI switches restored adapters, MVC preserves domain checks during replay, and PubSub queues are reconstructed from authoritative job state rather than treated as databases.
Data model and ownership
Backups cannot merge provider metadata, runtime state, generated-app rows, and source-enterprise data into one unscoped archive. Each owner defines retention, encryption, restore, export, and deletion.
Generated-application database: Required in this slice — isolated restore proves generated-app tenant data, constraints, authorization predicates, and deletion independently of provider records.
| Record or entity | Store and owner | Primary key | Foreign key or opaque reference | Tenant key | Material constraint | Lifecycle and deletion | Use case IDs |
|---|---|---|---|---|---|---|---|
| RecoveryPoint | Backup catalog, owned by Data Reliability | recovery_point_id | Opaque Aurora snapshot, S3 version, KMS key, schema, and source refs | environment_id | Immutable, encrypted, integrity/checksum, retention, and restore role required | Create, verify, retain/lock, expire by policy after legal hold | D29-UC-02 |
| RestoreRun | Evidence Store, owned by Operations Assurance | restore_run_id | Opaque recovery point, Terraform, cluster, release, and trace refs | environment_id | Isolated target, no source mutation, positive/negative probes, RPO/RTO required | Plan, execute, seal, review, clean target, retain dossier | D29-UC-01, D29-UC-02 |
| RestoredTenant | Restored generated-app database, owned by generated application | app_tenant_id | Opaque original tenant and recovery point refs | app_tenant_id | PK/FK, uniqueness, row authorization, and deletion policy pass integrity checks | Restore in isolation, validate/export proof, erase rehearsal copy | D29-UC-02 |
The durable recovery point, run dossier, and restored tenant now retain separate authority and deletion outcomes.
Run read-only evidence checks first
Mutation before observation can destroy the clues needed to select the right owner. Run this labelled snippet from the public monorepo using stable paths infra/stacks/prod, argocd/applicationsets/forge-prod.yaml, and scripts/smoke-product.sh.
: "${AWS_PROFILE:?set the approved AWS profile}" "${AWS_REGION:?set the intended AWS region}" "${EXPECTED_ACCOUNT_ID:?set the intended 12-digit AWS account}"
actual_account="$(aws --profile "$AWS_PROFILE" --region "$AWS_REGION" sts get-caller-identity --query Account --output text)"
[ "$actual_account" = "$EXPECTED_ACCOUNT_ID" ] || { echo "AWS account mismatch" >&2; exit 1; }
terraform -chdir=infra/stacks/prod state list
aws --profile "$AWS_PROFILE" --region "$AWS_REGION" eks update-kubeconfig --name zheta-forge-prod --alias zheta-forge-prod
aws --profile "$AWS_PROFILE" --region "$AWS_REGION" eks describe-cluster --name zheta-forge-prod --query 'cluster.status'
kubectl --context zheta-forge-prod get nodes
kubectl --context zheta-forge-prod -n argocd get application forge-prod -o wide
test -n "${FORGE_URL:?set FORGE_URL to the explicit reachable production control-plane URL}"
FORGE_URL="$FORGE_URL" FORGE_TOKEN="${FORGE_TOKEN:?set the explicit bearer token}" ./scripts/smoke-product.sh
The current Terraform module actually declares three Aurora clusters, versioned encrypted S3, a KMS-encrypted AWS Backup vault, daily backup plan, and production 35-day retention. It does not prove a restore; launch remains blocked until a separate-account restore run records integrity, authorization, RPO, and RTO.
| Effect field | What happens |
|---|---|
| Declared intent | Observe infrastructure mapping, provider reality, API/runtime, GitOps, and customer path independently |
| Interpreter | Terraform, AWS API, Kubernetes API, Argo CD resources, and Forge HTTP server |
| Software effect | No desired state changes; evidence gains fresh boundary observations |
| Hardware effect | APIs and product use small CPU/network capacity to answer |
| Evidence | State addresses, cluster status, nodes, revision/health, response, freshness, environment, run, and trace |
Key takeaways
Recovery is a customer workflow reconstructed across multiple owners.
- Observe bottom-up before mutation or state surgery.
- Test restore, integrity, authorization, RPO, and RTO in isolation.
- Metrics, logs, traces, backups, Terraform, Git, and controllers complement rather than replace one another.
Checklist
The platform is recoverable only when the rehearsal ends in customer evidence.
- [ ] Positive and denied support queries preserve tenant scope
- [ ] Recovery point, key, schema, and checksum are verified
- [ ] Reconstruction follows substrate to API to state to workload to customer
- [ ] Rehearsal copy is erased and dossier retained