Rootform language 0.1.0 has five built-ins. They are available only in a Policy
assert expression.
Query values are opaque. They can appear only as a direct argument to
exists or length.
policy_pack "architecture-contracts" { version = "0.1.0"}
policy "subnet-has-network" { target { concept = rf.concept.subnet rules = [aws.rule.subnet] }
assert = exists( contexts(rf.context.network, rf.concept.virtual-network) )
message = "Each subnet must declare its virtual network."}
policy "subscription-has-topic" { target { rules = [aws.rule.sns-topic-subscription] }
assert = exists( relations(aws.relation.subscribes-to, aws.concept.message-topic) )
message = "Each subscription must declare its topic."}
policy "bucket-has-versioning-contribution" { target { concept = rf.concept.object-storage-container dialects = ["aws"] }
assert = length( contributions(aws.rule.s3-bucket-versioning) ) >= 1
message = "Each AWS bucket must have a versioning contribution."}This Terraform configuration can produce one target and one matching fact for
each Policy above. Export its plan JSON and pair it with the saved plan when
running Rootform so reference-based endpoints can be established. OpenTofu
users run the same commands with tofu; see Plan inputs.
Saved plans and plan JSON can contain secrets in clear text. Keep them out of
Git and public artifacts. Rootform reads them locally; it never runs Terraform
or OpenTofu and never contacts providers.
terraform { required_providers { aws = { source = "hashicorp/aws" version = "= 6.62.0" } }}
resource "aws_vpc" "main" { cidr_block = "10.20.0.0/16"}
resource "aws_subnet" "application" { vpc_id = aws_vpc.main.id cidr_block = "10.20.1.0/24"}
resource "aws_sns_topic" "events" {}
resource "aws_sns_topic_subscription" "events" { topic_arn = aws_sns_topic.events.arn protocol = "https" endpoint = "https://example.com/events"}
resource "aws_s3_bucket" "assets" { bucket = "rootform-docs-assets"}
resource "aws_s3_bucket_versioning" "assets" { bucket = aws_s3_bucket.assets.id
versioning_configuration { status = "Enabled" }}Save the configuration as built-ins/main.tf, produce its plan JSON and saved
plan, then run it with the displayed Policy Pack. The Planned stage has six
instances, three resolved facts (one of each kind), and three Policy targets.
All three Policies pass with exit 0. If a closure is indeterminate, exists
cannot claim absence and length cannot claim a complete count; inspect that
closure before treating a failed check as an architectural violation. The
plan-input guide gives the export commands.
exists(query) -> Boolean | unknownExactly one argument is required.
exists can prove presence from one confirmed fact. It cannot prove absence
without both support and completeness.
length(query) -> integer | unknownExactly one argument is required.
length returns deduplicated fact count only when query is supported and
complete. Any relevant uncertainty makes count unknown, even if some facts are
confirmed, because exact cardinality is not proved. A numeric comparison can
still be decided from the confirmed lower bound when it suffices; see
Query truth.
assert = length(contexts(rf.context.network)) == 1contexts(dimension[, target]) -> queryReturns direct outgoing Context facts from current Policy target representation.
Accepted arity is one or two.
assert = exists(contexts(rf.context.network))assert = exists( contexts(rf.context.network, rf.concept.virtual-network))Without second argument, support exists when applied Rule declares compatible
Context emission for dimension. With second argument, emission's to must
match exact Concept or Rule reference.
Function does not follow Contexts transitively.
relations(predicate[, target]) -> queryReturns direct outgoing Relation facts from current Policy target representation.
Accepted arity is one or two.
assert = exists(relations(aws.relation.subscribes-to))assert = exists( relations(aws.relation.subscribes-to, aws.concept.message-topic))Second argument matches emission's authored to contract exactly. AWS
subscription Rule emits to = concept.message-topic, so
aws.concept.message-topic is supported; replacing it with
aws.rule.sns-topic would not describe same query contract even when concrete
topic representation carries that Rule.
No inverse, recursive, or transitive relation query exists.
contributions(contributor) -> queryReturns Contributions arriving at current Policy target representation from a matching contributor.
Accepted arity is exactly one.
assert = exists(contributions(aws.rule.s3-bucket-versioning))assert = length(contributions(aws.concept.storage-configuration)) >= 1Unlike Contexts and Relations, Contributions are queried from receiving target
back toward contributors. Query considers Rules whose Contribution emission
to matches current target representation and whose own identity satisfies
contributor. A compatible contributor Rule can establish query support even
when architecture has zero instances of that Rule; facts and support are
separate.
All semantic arguments are owner-qualified in Policy source:
Linker verifies each referenced symbol against the Form before producing compiled Policy Pack.
Each query internally carries:
A known-empty emission can support complete zero result. Missing compatible emission contract means unsupported, not empty. Emission warning can leave confirmed facts while marking result incomplete.
These signals explain why exists and length differ under uncertainty.
See Evaluation for truth tables.
assert = contexts(rf.context.network)assert = exists()assert = exists(contexts())assert = length(relations(aws.relation.subscribes-to, aws.rule.sns-topic, aws.rule.subnet))assert = contributions(aws.rule.s3-bucket-versioning)assert = count(contexts(rf.context.network))Failures include bare query, wrong wrapper arity, wrong query arity, and unknown
function. Each produces POLICY_INVALID.