The operator, recorded
15 sessions, recorded at the terminal against a four-node kind cluster with the operator installed from its chart. Each one is checked while it runs: a recording is published only if every condition it claims held on the live cluster. Open one to read the session in full; Play types it out where it stands.
- Kubernetes1.37.0
- Operatorb98f92bed240
- Ptahv0.13.0
- Executorsha256:f68968558f06
- Recorded2026-10-10
- Checks held178
- Runs15
These sessions were recorded against Ptah v0.13.0. The supported executor is now v0.15.0, so read them as evidence about the operator's behavior rather than as a check that these commands still run unchanged today.
A replay of a verified run, not a live cluster. Nothing on this page talks to anything.
# The lab is one cluster, built from the versions this repository declares.$ demo/bin/lab versionskubernetes 1.37.0kind v0.33.0operator b98f92bed240a4a34cde9c6bf5bc0cdc07da6d96executor e2e-registry.demo.svc.cluster.local:5000/ptah-executor@sha256:f68968558f0634c1e388f2be3f8d9d0f7c5916631abe16c5bae55d21e8e909c0ptah v0.13.0 # The operator runs in its own namespace, two replicas, one leader.$ kubectl -n "$OPERATOR_NAMESPACE" get deploymentNAME READY UP-TO-DATE AVAILABLE AGEptah-operator-cert-rotator 1/1 1 1 10mptah-operator 2/2 2 2 10m # Available means the install finished. The image is a digest, so one exact build runs.$ kubectl -n "$OPERATOR_NAMESPACE" get deployment -o json \ | jq -r '.items[].spec.template.spec.containers[].image'e2e-registry.demo.svc.cluster.local:5000/ptah-operator@sha256:18aafa202d6ebd9a5e65ffb026eb016cfad52eb14224ee8d8891f5eff55b63cde2e-registry.demo.svc.cluster.local:5000/ptah-operator@sha256:18aafa202d6ebd9a5e65ffb026eb016cfad52eb14224ee8d8891f5eff55b63cd # Three resources -- the desired state, the plan, and the decision that lets it run.$ kubectl get crd -o custom-columns=NAME:.metadata.name,ESTABLISHED:'.status.conditions[?(@.type=="Established")].status' \ ptahschemas.operator.ptah.run ptahschemaplans.operator.ptah.run ptahschemaapprovals.operator.ptah.runNAME ESTABLISHEDptahschemas.operator.ptah.run Trueptahschemaplans.operator.ptah.run Trueptahschemaapprovals.operator.ptah.run True # The namespace it works in. Credentials are Secrets; the policy cannot be edited.$ kubectl -n "$NAMESPACE" get secret,configmapNAME TYPE DATA AGEsecret/demo-database Opaque 6 10msecret/demo-database-broken Opaque 1 3m1ssecret/demo-mysql-database Opaque 5 10msecret/demo-registry Opaque 4 10msecret/demo-registry-pull kubernetes.io/dockerconfigjson 1 10msecret/demo-shadow-database Opaque 2 10m NAME DATA AGEconfigmap/demo-migration-verification-policy 1 10mconfigmap/demo-verification-policy 1 10mconfigmap/e2e-verification-policy 1 11mconfigmap/kube-root-ca.crt 1 11mconfigmap/ptah-plan-664b0a2d1a26340c2113e29e-000 1 34s
- Stand up the labLabA four-node kind cluster, the chart from a package, and every image pinned by digest.$ demo/bin/lab versions
- Adopt a database that already has a schemaLifecycleRecord the history a database already earned, and let the operator carry on from there.$ kubectl -n "$NAMESPACE" exec deploy/demo-psql -- psql -c "SELECT * FROM shipments ORDER BY id"
- Start a new database from a checkpointLifecycleA fresh database runs the snapshot and what came after it, and ends up where the long way ends.$ ls demo/migrations-checkpoint | grep -v down
- Apply a schemaLifecyclePublish a schema as an artifact, point the operator at it, and watch it converge.$ cat demo/schemas/v1.sql
- Manage reference dataLifecycleRows declared beside the tables that hold them, reconciled through the same plan.$ sed -n '/ptah:schema:table name="regions"/,/^}/p' demo/reference/v1/catalog.go
- Change the schemaLifecycleA second revision, a new digest, and the difference applied as one plan.$ kubectl -n "$NAMESPACE" exec deploy/demo-psql -- psql -c "\dt"
- Ship a second release onto rows that already existLifecycleA backfill that runs against real data, and a history that says it ran once.$ APPLY=Always demo/bin/lab manifest shipments "$(cat demo/.lab/release-1-digest)" | kubectl apply -f -
- Run a prepared migration sequenceLifecycleNumbered SQL files in an artifact, matched against the database's own record of what has run.$ ls demo/migrations
- Refuse a destructive changeSafetyThe third revision drops a column. The policy says no, and says so before anything runs.$ kubectl -n "$NAMESPACE" exec deploy/demo-psql -- psql -c "INSERT INTO customers (id, email) VALUES (1, 'a@example.test') RETURNING id, email"
- Approve a planSafetyWith apply set to OnApproval, nothing runs until a person approves that exact plan.$ APPLY=OnApproval demo/bin/lab manifest storefront "$(cat demo/.lab/digest)" | tee demo/.lab/storefront.yaml
- Retire a used approvalSafetyAn approval describes one plan against one observed state. Applying it moves that state.$ kubectl -n "$NAMESPACE" get ptahschema storefront -o jsonpath='{.status.phase}{"\n"}{.status.plan.fingerprint}{"\n"}'
- Close the driftOperationsSomeone changes the database by hand. The operator notices and puts it back.$ kubectl -n "$NAMESPACE" get ptahschema storefront -o json
- Fail, then recoverOperationsPoint it at a database that is not there. It says so, keeps trying, and converges when it is.$ APPLY=Always demo/bin/lab manifest storefront "$(cat demo/.lab/digest)"
- Recover a MySQL migration that stopped halfwayOperationsDDL that committed, a run nobody can retry, and a repair decided by what the database holds.$ APPLY=Always demo/bin/lab manifest deliveries "$(cat demo/.lab/deliveries-1-digest)" | kubectl apply -f -
- Suspend and resumeOperationsOne field stops reconciliation without deleting anything, and resuming picks up where it stopped.$ kubectl -n "$NAMESPACE" get ptahschema storefront -o json