Use a small plan fixture to prove what a Dialect actually says about instances. Source validation checks language contracts; rootform test compares produced Forms with reviewed analysis.golden files. A passing compile alone cannot prove that a provider attribute has the architectural meaning you intended.
The example below follows a local network-review Dialect that interprets one random_pet instance. Start in a project containing this source and a plan fixture. The full source and plan setup appear in Use a local Dialect. The layout at the point of testing is:
.├── dialects/│ └── network-review/│ └── dialect.rf.hcl├── fixtures/│ └── network/│ ├── plan.json│ ├── plan.tfplan│ └── analysis.golden├── main.tf├── plan.json└── plan.tfplanThe plan JSON comes from terraform show -json plan.tfplan; OpenTofu users run tofu show -json plan.tfplan. Keep the saved plan and plan JSON together: they may contain clear-text secrets, so do not commit them from a real environment. The synthetic fixture shown here is safe for review. rootform test --update writes or replaces a golden, so review its change before accepting it.
-
Check without rewriting it:
Shellrootform fmt --check ./dialects/network-reviewExit
0and no output mean canonical formatting. Exit1lists files that would change. Runrootform fmt ./dialects/network-reviewduring authoring, review the edit, then repeat the check. Formatting neither validates references nor establishes architecture meaning. -
Validate all definitions under the source root:
Shellrootform validate dialects ./dialects/network-review --color alwaysValid Dialect output OUTPUTDialect set validDialectsnetwork-review@0.1.0Exit
0proves accepted syntax, identities, references, Rule shapes, and a valid compiled artifact. An invalid definition exits1; incorrect command use exits2; a result that cannot be decided exits3. CI can use--format jsonfor stable diagnostic codes. To inspect just one selected Rule,rootform validate rule network-review.rule.service-name --dialect ./dialects/network-reviewapplies that source override for the command only. Rules and matching defines what validation checks. -
A fixture directory contains one
plan.jsonorstate.jsonand ananalysis.golden. Keep the matchingplan.tfplanbeside plan JSON when reference identity matters. First review the produced architecture, then record the golden once withrootform test ./fixtures --dialect ./dialects/network-review --update. The--updateflag writes every missing or differing golden; it is an authoring action, not a passing assertion.Now replay the reviewed case:
Shellrootform test ./fixtures --dialect ./dialects/network-review --color alwaysFixture replay output OUTPUTTests passed1 caseExit
0means every selected fixture passed or was recorded with--update.--run networknarrows by case-name substring while iterating. Exit1means a fixture differed or could not be analyzed; inspect the source address, interpretation, facts, closures, diagnostics, and sensitive-value bounds before updating the golden. Exit2means incorrect usage,3meansrootform.lockis invalid or no fixtures matched, and4means fixture files, Dialects, or the report could not be read or written. A golden is a Form, not a Terraform plan or state export. -
Run the same plan pair with the Dialect override to understand the fixture's result:
Shellrootform run ./plan.json --plan-file ./plan.tfplan \--dialect ./dialects/network-review --no-serve --color alwaysPlan summary excerpt OUTPUTPlan analyzedInput ./plan.jsonEnrichment Saved plan paired with this plan JSON (1 module)ArchitectureInstances 1Interpreted 1Facts none determinedThe one instance has an applied Rule. This Rule classifies it and emits nothing, so zero facts and closures are expected. The export does not establish which tool produced it, so no Producer row appears.
--producer terraformrecords your attestation and displaysProducer: Terraform, without a version. The Form keeps the reported version. The verified saved plan can supply traversal evidence for Rules that emit facts. If these counts change, inspect the document and golden before accepting a new result. The--no-serveflag exits after the summary; without it,runserves the Explorer on loopback. -
The fixture proves interpretation, not compliance. Follow Evaluate locally to select a Policy Pack against known facts. For a worked check that shows a pass, violation, indeterminate evidence, and no target, see Understand Policy outcomes.
rootform checkexits0only when every selected Policy evaluates a target and passes. A confirmed violation exits1; indeterminate evidence or zero targets exits3. Do not edit a generated Form to make a Policy pass. Policies over facts explains support and completeness.For target-resolution Rules, replay the same evidence with and without saved-plan enrichment. Include null, empty, unknown, sensitive, duplicate identity, wrong provider scope, external target and conflicting reference cases. Assert fact provenance and closure reasons, not only fact counts. Composition cases also assert retained roots and unresolved dependent members. Evidence and target resolution explains these boundaries.
-
Keep the diagnostic code and sanitized source range in assertions. For a match-only Rule,
rootform validate dialectsexits1and reports:Invalid Rule excerpt OUTPUTDialect set invalid (1 error)dialect.rf.hcl9:1 RULE_NO_ARCHITECTURE rule must add a classification, emission, or non-empty compositionThe range identifies the Rule declaration; the code is stable for automation.
HCL_PARSEinstead reports invalid source syntax, whileEMISSION_PATH_UNDEFINEDmeans an emitted instance lacked the declared path. See Diagnostics and limits for severity and recovery. -
After source, fixture, and Policy behavior pass, follow Dialect packaging or Policy Pack authoring for distribution checks. Packaging does not replace a reviewed golden or a real policy decision.