Evidence · How close AWS is
reference-k8s
hand-written reference shape kept in this repository, built on live/e2e/estate-k8s (namespace, ConfigMap, ServiceAccount, Service) plus a Deployment on the node image’s own pause container and a two-instance count ConfigMap; the kubernetes lane’s first estate, run against a kind cluster (#1067)
Set: growing. Lane: kubernetes.
Clear. Every headline stage passes.
| Stage | Verdict | Duration | Detail |
|---|---|---|---|
| Cold deploy | pass | 1m2s | 7 objects (namespace, 3 ConfigMaps, ServiceAccount, Service, Deployment) from plain terraform against kind v1.36.1, a real terraform.tfstate with 7 instances, zero tofu-estate labels read back with kubectl; the identical shape cold-deployed by stock on a second cluster as every later stage’s oracle |
| Migrate | pass | 4s | 7 of 7 stamped, 0 skipped; every object carries tofu-estate=reference-k8s, read back with kubectl |
| Replan from nothing | pass | 5s | the plan with no state file is empty; all 7 identities (NAMESPACE/NAME) confirmed present with kubectl |
| No-op apply | pass | 6s | no-op apply (0 added, 0 changed, 0 destroyed); objects carrying tofu-estate=reference-k8s unchanged at 7 across the estate’s five kinds, counted with kubectl |
| Drift and reconverge | pass | 10s | one ConfigMap tampered with kubectl patch; choudoufu proposed exactly kubernetes_config_map.app (0 add, 1 change, 0 destroy), matching stock’s own plan on the oracle cluster for the same tamper; apply changed 1 and the value reads back as configured. BREAK=1 tampers a second object and the single-object assertion correctly fails |
| Rename | pass | 10s | moved block: kubernetes_service_account.app -> .team with zero churn (no add, no change, no destroy), the live object untouched and still labelled, read with kubectl; stock’s plan for the same moved block on the oracle cluster is also zero churn. The moved-block half only: live-mv has no Kubernetes leg, because the object carries no address to rewrite (#1066). A bare block rename without a moved block is zero churn here too, since the block name is not part of the object’s identity; BREAK=1 renames the object’s own metadata.name instead, which plans a replace, and the zero-churn assertion correctly fails |
| Remove a block | pass | 16s | deleting kubernetes_service_account.team’s block proposed exactly one destroy (0 add, 0 change, 1 destroy) at the sweep’s synthetic orphan address kubernetes_service_account_v1.orphan_refk8s_app (“Owned and undeclared: 1 live resource will be destroyed”) - the object is found by its label, which carries no address, and filed under the versioned type since no block declares the kind any more - applied cleanly, the object gone from the cluster (kubectl get serviceaccount: NotFound) and the next plan empty; stock’s plan for the same removal on the oracle cluster is also exactly one destroy; the Deployment’s ReplicaSet and Pod, which carry no estate label, were never proposed. BREAK_REMOVE=1 keeps the block and no destroy is proposed |
| Change count | pass | 26s | scaling kubernetes_config_map.shard from 2 to 1 destroyed exactly shard-1, planned at the sweep’s orphan address kubernetes_config_map.orphan_refk8s_shard-1 since the label carries no index (shard-0 untouched, both read with kubectl); back to 2 created exactly kubernetes_config_map.shard[1] under the same name; the next plan is empty; stock’s plans for the same two changes on the oracle cluster have the identical shape. BREAK_COUNT=1 asserts the lower index was destroyed and correctly fails |
| Replace with create_before_destroy | n/a | A Kubernetes name is unique within its namespace, so nothing can be created before the object it replaces is destroyed; a forced replacement is destroy-then-create, which this stage does not measure. | |
| Crash between create and destroy | n/a | The create-before-destroy window this stage interrupts does not exist on Kubernetes (see day2_replace). | |
| Teardown | pass | 18s | apply -destroy removed exactly the 6 remaining objects in one apply, the namespace is gone and no object of any of the estate’s five kinds carries tofu-estate=reference-k8s (kubectl, every namespace); stock’s destroy of the same estate on the oracle cluster also removed exactly the 6 its state held |
| Plan, review, apply | pass | 16s | plan -out wrote one update (app-config gains reviewed=yes); the world then moved out of band (a stray label on shard-0, kubectl, never choudoufu) and apply of the saved plan refused with “The approved plan no longer matches the live system” at exit 3, nothing applied (kubectl reads no reviewed key); with the label removed the identical file applied, 0 added, 1 changed, 0 destroyed, and reviewed=yes reads back; stock’s own planfile applied on the oracle cluster in the unchanged case. BREAK_APPROVAL=1 expects success after the move and correctly fails |
| Greenfield apply | pass | 17s | 7 objects applied fresh with a live block and no terraform.tfstate, every one labelled tofu-estate=reference-k8s (kubectl, five kinds); the record store held 8 file(s); replanned empty with and without the cache; the cluster’s inventory (ConfigMap data, the Service’s ports and selector, the Deployment’s replicas and container, the ServiceAccount and namespace) matches stock’s cold deploy on the same cluster object by object, labels never compared. BREAK=1 drops the Deployment from the expected inventory and the match correctly fails |
| Strict profile (not a headline stage) | pass | 12s | every strict toggle on (secrets = refuse, no_source_create = refuse, marker_repair = never with a markers “record” selection naming kubernetes_config_map) against a scratch estate carrying random_password.db: exactly one refusal, Logical resource is not admitted under strict { secrets = “refuse” }; the other two toggles are on and silent. BREAK_STRICT=1 turns secrets back to “store” and the refusal disappears |
Last run at commit e17f62ae44 on 2026-09-12T14:41:53Z, exit code 0, against emulator image ghcr.io/lex00/floci@sha256:0bbeb43075c9df9c7e06311cd4eec99a354594d304faa4fe5899b494a009d23d. Total run time 3m23.2s.
Oracle: stock terraform 1.15.8, stock tofu 1.12.5. Stale: the current pin is terraform 1.16.1, tofu 1.12.6.
Reproduce it
go run ./tools/gauntlet run reference-k8s
Needs Docker (the emulator is pulled at the pinned digest), the AWS CLI, and a
stock terraform or tofu binary on PATH for the cold deploy. The script is
live/e2e/reference-k8s/run.sh; BREAK=1 corrupts its assertions to show they are load-bearing.