Skip to content

Rootform interprets plan JSON or state JSON locally. It masks sensitive values before retaining requested paths, selects at most one Rule per managed or data instance, closes that Rule's emissions, and evaluates selected Policies over one architecture stage within a Form. It never runs Terraform or OpenTofu or contacts providers. A saved Form can be reopened after validation without reinterpreting the original input.

For the mental model, see Policies over facts.

Architecture evaluation pipeline

  1. Read observed instances and their provider bindings from the plan or state export.
  2. Classify Rule candidates, then select at most one per instance.
  3. Attach optional Concept meaning and resolve ordered composition members per root instance.
  4. Resolve Context, Relation, and Contribution emissions into per-instance closures and facts.
  5. Record stage accounting, diagnostics, and the Form.
  6. If Policies were selected, link and evaluate them against the selected stage.

This order matters: a Policy cannot treat an unclosed emission or failed interpretation as proof that a fact is absent.

Instance population and stages

InputAvailable stagesDefault Policy target
Plan JSONplanned; refreshed and reconstructed recorded when prior evidence permitsplanned
State JSONOne Recorded architecturerecorded
Saved FormIts stagesForm default stage; both sides for a comparison Form

Base Representation

Every observed managed and data instance has a Representation, even without an applied Rule. A plan's reconstructed Recorded stage is never a Policy evaluation target. A plan can include Reported drift (Recorded to Refreshed) and Planned changes (Refreshed to Planned). A cross-input comparison has no Policy predicate that proves drift.

Rule selection

A candidate must match resource mode, exact type, provider source, then a known-true where predicate. The provider version envelope belongs to the Dialect manifest; the instance selector does not compare an observed exact version. More than one accepted Rule yields RULE_MATCH_AMBIGUOUS; an unresolved predicate prevents choosing around uncertainty. An unbound provider produces PROVIDER_UNBOUND and failed interpretation. Exactly one accepted Rule applies; otherwise the instance remains represented but unclassified. There is no first-match order. Rules and matching has the selection table.

Composition application

Composition records each established member and each unresolved member on the root instance. An unresolved earlier member leaves a dependent later member unavailable, while an independent later member may still resolve. The root Rule, Concept, and emissions remain available. See Member resolution and Unresolved members.

Predicate truth

Rule predicates compare known scalar values. Boolean operations use three-valued logic: false && unknown is false, true || unknown is true, and !unknown remains unknown. Only final known true accepts a Rule. Unknown, sensitive, or missing evidence is never silently false.

ABA && BA || B
truetruetruetrue
truefalsefalsetrue
trueunknownunknowntrue
falsefalsefalsefalse
falseunknownfalseunknown
unknownunknownunknownunknown

The operations are commutative, so swapping A and B gives the remaining cases.

Fact derivation

Emission closure

Each active emission has one closure per source instance and stage. A known matching value or verified Planned-stage identity traversal can establish a fact. on_null and on_empty decide whether a known missing value proves absent or remains indeterminate. Unknown, sensitive, unavailable, ambiguous, and conflicting evidence never proves absence. A list can retain proven facts while another element keeps its closure indeterminate. A fact records its Rule, emission, closure, target and value, traversal, or both evidence.

Policy linking

A Policy Pack links against the Form's exact semantic owner identities. A missing definition, conflicting selection, or incompatible semantic digest prevents a policy decision.

Policy target selection

Target dimensions combine with AND; entries within one list combine with OR. Representations with an applied Rule can be selected. A failed or indeterminate interpretation whose candidate Rule could satisfy the target is also selected for an indeterminate evaluation. An unverified instance population can make target coverage incomplete. A carried instance stays in Planned because the plan neither changes nor deletes it, but the plan did not evaluate it. Missing evidence from it cannot produce a pass or violation. A Policy with zero targets has zero per-target evaluations and contributes no compliance decision.

Query truth

exists(query)

Matching factsQuery supportedRelevant closures completeexists(query)
One or moreEitherEitherTrue
ZeroYesYesFalse
ZeroNoEitherUnknown
ZeroYesNoUnknown

One confirmed matching fact makes exists true even when another relevant closure is indeterminate. This proves presence, not exact cardinality or complete target coverage.

length(query)

length(query) has an exact deduplicated count only for supported, complete evidence. A numeric comparison may still be decided from a proven lower bound when evidence is incomplete; otherwise it is unknown. Negative assertions need complete relevant closures, so an indeterminate closure cannot make !exists(...) pass. Boolean operators preserve three-valued truth: a known false decides &&, a known true decides ||, and other combinations with unknown remain unknown. See Built-ins for signatures.

Worked example

For a subnet Rule emitting network Context to a VPC:

Evidence for source.vpc_idClosureexists(contexts(...))
Known matching identity or verified endpoint traversalresolvedTrue
Known null with on_null = "absent"absentFalse, if relevant population complete
Unknown until applyindeterminate(unknown_until_apply)Unknown
No selected subnet instanceNo evaluationNo decision

A false assertion is a violation; an unknown assertion is indeterminate. If a different target has a confirmed violation, that violation takes precedence in the check result.

Indeterminate and no-decision reasons

Reason in resultWhy evidence cannot decideReader action
unknown_until_applyPlanned value is not known before applyCheck the selected stage, verify any saved-plan pairing, and confirm that the reference uses a supported traversal. Use later plan or state evidence when the normal workflow provides it.
sensitiveValue is maskedChange the Dialect to use safe identity evidence if possible
ambiguous_unknown, uncomparable_candidate, duplicate_identity, identity_incompleteCandidate identity or uniqueness is unsettledInspect candidate counts and declared identities
reference_ambiguousEvaluated value conflicts with verified traversalInspect the plan pair and Rule endpoint/identity declarations
unavailable, external_deniedEvidence cannot be read or external target is disallowedSupply a paired saved plan when relevant; review the external policy
interpretation_failedCandidate Rule could not apply safelyRead the instance diagnostic
population_unverifiedAn instance that could affect target coverage was not verifiedAnalyze a complete plan or state export

These reasons can appear on a closure, evaluation, or coverage entry according to where uncertainty arose. external_denied does not authorize claiming that the external object is absent. A Policy with zero targets has no evaluation and outcome no_target, which makes the result status no_decision; a check with no selected Policies makes no compliance claim. An unavailable requested stage or incompatible Pack fails evaluation with its own diagnostic.

Per-target outcomes

OutcomeMeaning
passedAssertion known true
violatedAssertion known false; Policy message applies
indeterminateRequired evidence or assertion undecidable

no_target is the Policy outcome when a selected Policy has zero targets; it is not a passed per-target result. A check with no selected Policies makes no compliance claim.

Aggregate result and exit status

Aggregate result status

A confirmed violation takes precedence over indeterminate evaluations. Without one, an indeterminate evaluation or incomplete target coverage produces indeterminate. If neither applies, a selected Policy with no target, or no selected Policy, produces no_decision. A passing Policy does not cancel another Policy's missing target; every selected Policy must evaluate at least one target and pass for the aggregate status to be passed. Only passed is a compliance claim.

PriorityConditionStatus
1At least one confirmed violationviolated
2Indeterminate evaluation or incomplete target coverageindeterminate
3A selected Policy has no target, or no Policy is selectedno_decision
4Every selected Policy evaluated a target and passedpassed

These are the aggregate status values of the Policy result written by rootform check. A check that cannot evaluate has status failed. rootform explain policy <policy> --result <file> --format json reports the selected Policy's outcome in each recorded architecture. Text and Markdown summaries render no_decision as NO DECISION.

For a comparison Form, check evaluates both the Before and After sides by default. --side before|after|both selects the scope; --stage requires one side. The JSON Policy result has one architectures entry for each evaluated side, and SARIF has one run per evaluated side. The overall verdict is stated once.

rootform check exit status

ConditionReported resultrootform check exit
Every selected Policy was evaluated and passedpassed0
At least one confirmed violation, even with indeterminate results elsewhereviolated1
No verdict: indeterminate, no target, nothing selected, a side that could not be evaluated, an input that was refused, or an invalid rootform.lockIndeterminate, no decision, or not checked3
Invalid command use or unknown Policy selectorUsage error2
Input or report could not be read or writtenOperational failure4

rootform run analyzes or compares architecture and never selects or evaluates Policies. It exits 0 when the Form was produced or opened, 2 for incorrect usage, 3 when an input was refused or a requested stage is unavailable, and 4 when an input or output file, or the explorer, failed. To gate a plan, state, or saved Form, use rootform check. With --policy-pack and no --policy, check evaluates every Policy in the overlay Policy Packs. A zero-target Policy produces a NO DECISION verdict and exits 3. A reported drift entry alone does not change check status. The JSON Form stores architecture evidence, not Policy results. Check reports can be written as JSON, Markdown, or SARIF; explain policy <policy> --result <file> inspects a recorded result without reevaluation. See Outputs and exit status.

Determinism and limits

The same input and semantic selection produce canonical, byte-identical Forms. Facts deduplicate while retaining bounded provenance. Exceeding a semantic or policy bound fails closed rather than returning partial compliance. Diagnostics and limits lists the bounds. Continue with Test and validate to prove a Dialect against planned evidence.