tools/terralith-gen, generated at -scale 1 by this estate’s own crossing script: a synthetic single-state terralith of stock Terraform - IAM-dominated with deliberate copy-paste duplication, a small ECS layer and a Route53 fan-out, expanded with count, for_each and a module-nested pod (issues #564 and #574). No upstream repository: the artifact is the generator, and “the same estate at 4x” is -scale 4 rather than a second fixture.
Set: core. Lane: reference.
Why it is in the core set: the one estate shaped like the thing the product is FOR - a single-state monolith a stranger would bring to an adoption (#546) - rather than a module example; every other core estate is a small published module, so a headline bar without this one does not read the product’s own claim
Clear. Every headline stage passes.
| Stage | Verdict | Duration | Detail |
|---|---|---|---|
| Cold deploy | pass | 2m3s | stock terraform applied 79 resources at scale=1 from unmodified terralith-gen output into BOTH accounts (COLD keeps its terraform.tfstate for migrate to adopt from and is confirmed carrying no tofu-address tag; GREEN was enumerated at 34 objects, proved non-vacuous by a deliberately-added role, then destroyed back to an enumerated-empty account - issue #564’s own proof, unchanged) |
| Migrate | pass | 43s | live-import ratified 38 of 79 instances as eligible and stamped all 38 with 0 failed and 41 skipped (untaggable, identity composed from an already-stamped parent); every one of the 79 addresses in stock’s own terraform state list - this stage’s oracle - is accounted for by name in the report |
| Replan from nothing | pass | 4s | post-migration plan is empty; six rendered identities asserted BY VALUE against the AWS CLI across four separate tagging surfaces (Route 53, IAM, ECS, EC2), including the count-indexed aws_iam_role.count_team[1] and the module-nested, double-indexed module.team_pod[“pod-a”].aws_iam_role.pod_role[0] |
| No-op apply | pass | 6s | no-op apply (0 added, 0 changed, 0 destroyed); the estate is enumerated object by object before and after - 34 objects across IAM/Route53/ECS/EC2, byte-identical listings, never a bare count - and the tofu-estate-tagged count is unchanged at 38 |
| Drift and reconverge | pass | 33s | one live object mutated out of band through the AWS CLI; choudoufu’s next plan proposed fixing exactly aws_vpc.main and nothing else (0 add, 1 change, 0 destroy), matching stock’s own plan for the identical mutation on cold_deploy’s own state (B4, taken before any marker existed); the apply changed exactly 1 resource, the Name tag reads back as configured and the tofu-address marker is unchanged |
| Rename | pass | 18s | moved block: aws_iam_instance_profile.team_0000_profile renamed with zero churn (0 add, 1 change, 0 destroy) and the plan itself showed the tofu-address marker being rewritten in place; live-mv: team_0001_profile renamed with no moved block at all, reported as a real cloud write; both live instance-profile ids unchanged and both markers read back at the NEW address via the AWS CLI; stock’s own oracle over the identical two renames on cold_deploy’s state (B1) is also zero churn (No changes., both moves reported); the plan after both renames is empty |
| Remove a block | pass | 7s | deleting two blocks - the taggable, marked aws_iam_instance_profile.team_0002_profile and the UNTAGGABLE aws_iam_role_policy.team_0002_inline, whose parent role stays declared - proposed exactly two destroys (0 add, 0 change, 2 destroy) in an order the cloud accepted, matching stock’s own plan for the same two removals on cold_deploy’s state (B2); the apply destroyed exactly two, both objects are confirmed gone and the parent role confirmed still live via the AWS CLI, and the next plan is empty |
| Change count | pass | 17s | the estate’s OWN count block - six declarations across four resource types, two of them untaggable - scaled 2 to 1 and back: exactly six index-[1] destroys then exactly six index-[1] creates, no index-[0] instance touched in either plan, matching stock’s own applied cycle over the identical six-block shape in a separate account (G1); across the whole cycle count_team[0]’s live role id was unchanged and its marker still reads aws_iam_role.count_team[0], count_team_profile[0]’s still reads aws_iam_instance_profile.count_team_profile[0], the recreated count_team[1] carries aws_iam_role.count_team[1], and the plan afterwards is empty |
| Replace with create_before_destroy | pass | 12s | changing aws_iam_instance_profile.team_0004_profile’s ForceNew name under create_before_destroy proposed exactly one isolated replace at the same declared address (1 to add, 0 to change, 1 to destroy), matching stock’s own plan for the identical change on cold_deploy’s state (B3); the apply created the new object and destroyed the old one, the old name no longer resolves and the new one carries the declared address’s marker (both read via the AWS CLI), and the next plan is empty with no collision |
| Crash between create and destroy (planned) | not run | ||
| Teardown (planned) | not run | ||
| Plan, review, apply (planned) | not run | ||
| Greenfield apply | pass | 1m2s | choudoufu applied 79 resources into an account a stock destroy had left enumerated empty (A2), and its cloud matches stock’s cold deploy across 79 structural facts compared object by object with marker tags never read on either side - the oracle this stage names. Also, beyond the oracle: the six representative identities are correct by value via the AWS CLI across Route 53/IAM/ECS/EC2; the apply persisted 78 records, matching stock’s own instance list type for type except for the 1 aws_ecs_task_definition instance(s), which get none (reported, not endorsed - the marker IS written on it and nothing here is observably worse for it); the next plan is empty; and with the local record store deleted outright every one of the 79 objects is still found - nothing created, destroyed or replaced, 41 of them untaggable and composing from a stamped parent - with the only movement being 1 residue-held aws_ecs_service update(s), which is what deleting the residue store (issue #275) means rather than a divergence |
| Strict profile (not a headline stage) | not run | - | this crossing script does not exercise the strict toggles: strict is Headline:false in tools/gauntlet/stages.go so it moves neither bar, and a toggle-by-toggle refusal fixture is a separate unit from the crossing this script exists to be. live/e2e/reference-ec2-vpc/run.sh’s PART G is the pattern for the estate that does carry one |
Last run at commit fcb55698e7 on 2026-08-31T11:51:55Z, exit code 0, against emulator image ghcr.io/lex00/floci@sha256:c55d74e13e96c8b132056677337dba0084bb0b427cb039be2dbf9a8b7efc0948. Total run time 5m26.1s.
Oracle: stock terraform 1.15.8, stock tofu 1.12.5. Stale: the current pin is terraform 1.16.0, tofu 1.12.6.
Reproduce it#
go run ./tools/gauntlet run terralith-scaleNeeds 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/terralith-scale/run.sh; BREAK=1 corrupts its assertions to show they are load-bearing.