Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

WA2 Intent Language Specification

Version: 0.1.18
Status: Draft


1. Overview

The WA2 Intent Language is a declarative domain-specific language for expressing architectural policies, validation rules, and derived knowledge over a graph-based model of infrastructure.

1.1 Purpose

WA2 enables:

  • Classification: Deriving semantic meaning from infrastructure configuration
  • Validation: Asserting architectural requirements
  • Guidance: Providing actionable feedback with appropriate severity

1.2 Execution Phases

The language operates in two ordered phases:

  1. Derive Phase — Enrich the graph with computed facts (model building)
  2. Rule Phase — Evaluate conditions and emit findings (validation only)

Policies and profiles control which rules are active and how their outcomes affect overall policy success.

1.3 Design Principles

  • Queries are the primary way to inspect the model
  • Modal operators (must/should/may) control both severity and control flow
  • Derives cannot fail; rules can
  • Policies select and constrain rules; they don’t modify rule behavior

2. Lexical Structure

2.1 Character Set

Source files are UTF-8 encoded.

2.2 Whitespace and Comments

Whitespace    ::= ' ' | '\t' | '\n' | '\r' .
LineComment   ::= '//' [^\n]* '\n' .
BlockComment  ::= '/*' .* '*/' .

Comments and whitespace are ignored except as token separators.

2.3 Keywords

namespace  use        type       struct     enum       predicate
instance   rule       derive     policy     profile
must       should     may
let        for        in         if         else       match      as
query      add        true       false      empty

2.4 Identifiers

Ident         ::= [a-zA-Z_][a-zA-Z0-9_]* .
QualifiedName ::= Ident (':' Ident)* .

Examples: foo, core:Store, aws:cfn:Resource

2.5 Literals

StringLiteral ::= '"' [^"]* '"' .
BoolLiteral   ::= 'true' | 'false' .

2.6 Operators and Punctuation

{  }  (  )  [  ]  /  *  =  ,  :  =>  _

3. Grammar

3.1 Top-Level Items

File ::= Item* .

Item ::= NamespaceDecl
       | UseDecl
       | TypeDecl
       | StructDecl
       | EnumDecl
       | PredicateDecl
       | InstanceDecl
       | RuleDecl
       | DeriveDecl
       | PolicyDecl
       | ProfileDecl
       | ProfileSelection .

3.2 Declarations

NamespaceDecl ::= 'namespace' Ident '{' Item* '}' .

UseDecl ::= 'use' QualifiedName .

TypeDecl ::= Annotation* 'type' Ident .

StructDecl ::= Annotation* 'struct' Ident '{' FieldDecl* '}' .
FieldDecl  ::= Ident ':' TypeRef .

EnumDecl    ::= Annotation* 'enum' Ident '{' VariantList '}' .
VariantList ::= Ident (',' Ident)* ','? .

PredicateDecl ::= 'predicate' Ident .

InstanceDecl ::= 'instance' QualifiedName ':' QualifiedName .

3.3 Rules and Derives

RuleDecl   ::= 'rule' Ident '{' Statement* '}' .

DeriveDecl ::= 'derive' Ident '{' Statement* '}' .

3.4 Policies and Profiles

PolicyDecl    ::= 'policy' Ident '{' PolicyBinding* '}' .
PolicyBinding ::= Modal QualifiedName .

ProfileDecl ::= 'profile' QualifiedName '{' ProfileItem* '}' .
ProfileItem ::= 'policy' QualifiedName .

ProfileSelection ::= 'profile' QualifiedName .

3.5 Statements

Statement ::= LetStatement
            | ForStatement
            | IfStatement
            | ModalStatement
            | AddStatement .

LetStatement ::= 'let' Ident '=' Expr .

ForStatement ::= 'for' Ident 'in' Expr '{' Statement* '}' .

IfStatement ::= 'if' Expr '{' Statement* '}' ('else' '{' Statement* '}')? .

ModalStatement ::= Modal Expr ModalMetadata? .
ModalMetadata  ::= '{' MetadataItem (',' MetadataItem)* ','? '}' .
MetadataItem   ::= 'subject' ':' Expr
                 | 'area' ':' QualifiedName
                 | 'message' ':' StringLiteral .

AddStatement ::= 'add' '(' Expr ',' QualifiedName ',' Expr ')' .

Modal ::= 'must' | 'should' | 'may' .

3.6 Expressions

Expr ::= PrimaryExpr AsExpr? .

PrimaryExpr ::= QueryExpr
              | AddExpr
              | MatchExpr
              | EmptyExpr
              | QualifiedName
              | Ident
              | StringLiteral
              | BoolLiteral
              | '_' .

AsExpr ::= 'as' '(' QualifiedName ')' .

QueryExpr     ::= 'query' '(' QueryPath ')' .
QueryPath     ::= QueryStep ('/' QueryStep)* .
QueryStep     ::= NodeTest Predicate* .
NodeTest      ::= QualifiedName | Ident | '*' .
Predicate     ::= '[' PredicateExpr ']' .
PredicateExpr ::= QueryPath
                | QueryPath '=' StringLiteral .

AddExpr ::= 'add' '(' Expr ',' QualifiedName ',' Expr ')' .

MatchExpr ::= 'match' Expr '{' MatchArm* '}' .
MatchArm  ::= Pattern (',' Pattern)* '=>' Expr ','? .
Pattern   ::= Ident | 'else' .

EmptyExpr ::= 'empty' '(' Expr ')' .

3.7 Annotations

Annotation    ::= '@#' Ident '(' AnnotationArg (',' AnnotationArg)* ')' .
AnnotationArg ::= Ident '=' Literal .

4. Type System

4.1 Graph Model

The system operates on a directed graph of entities connected by predicates.

ConceptDescription
EntityA node in the graph with a unique identity
PredicateA named relationship between entities or from entity to literal
Triple(Subject, Predicate, Object) where Object is Entity or Literal

4.2 Built-in Types

TypeDescription
wa2:TypeA type definition
wa2:PredicateA predicate definition
wa2:NamespaceA namespace
wa2:subTypeOfEnum variant relationship
wa2:typeType assignment predicate
wa2:containsContainment relationship

4.3 Enum Types

Enums define a closed set of valid values:

enum DataCriticality {
    Disposable,
    NonCritical,
    Important,
    BusinessCritical,
    MissionCritical
}

Each variant becomes an entity with wa2:subTypeOf pointing to the enum type.

4.4 Evaluation Results

Expressions evaluate to one of:

ResultDescription
EntitySingle entity reference
SetZero or more entities
LiteralString value
EmptyAbsence of value

5. Semantics

5.1 Truthiness

A value is truthy if:

ResultTruthy When
EntityAlways
SetNon-empty
LiteralNon-empty string and not "false"
EmptyNever

A value is falsy if not truthy.

5.2 Query Semantics

query(path/to/target)
  • Traverses the graph following the path
  • Returns a Set of matching entities or literals
  • Empty set if no matches

Variable Binding: If the first path segment is an unqualified name that matches a bound variable, traversal starts from that entity:

let source = query(store/core:source)
let tags = query(source/aws:Tags)  // starts from 'source'

Predicates: Filter results:

query(core:Store[core:Evidence/data:isCritical])  // stores with critical evidence
query(source/aws:Tags/*[aws:Key = "Environment"])  // tags with specific key

5.3 Modal Statements

Modal statements are the primary mechanism for expressing requirements.

must <expr> { subject: <expr>, area: <name>, message: <string> }
should <expr> { ... }
may <expr> { ... }

Evaluation:

  1. Evaluate expression
  2. If truthy → continue to next statement
  3. If falsy:
    • Create finding with specified metadata
    • Apply guard behavior based on modal

Modal Behavior Matrix:

ModalOn FalsyGuardSeverity
mustFailYesError
shouldWarnYesWarning
mayPassNoInfo

Guard Behavior: When guard applies, remaining statements in the current block are skipped. Outer scopes continue.

for store in stores {
    should query(store/core:Evidence) {
        message: "Store needs evidence"
    }
    // If above fails, this line is skipped for this store:
    let evidence = query(store/core:Evidence)
    add(evidence, wa2:contains, fact)
}
// Loop continues with next store

5.4 As-Conversion

The as(Type) operator validates and converts values:

let criticality = query(tag/aws:Value) as(DataCriticality)

Behavior:

  1. Evaluate inner expression to get literal value
  2. Check if value matches a variant of the target enum
  3. If valid → return the value
  4. If invalid → return Empty

Type Not Found: If the target type does not exist, this is always an error regardless of context (framework bug).

5.5 Match Expressions

match <expr> {
    Pattern1, Pattern2 => result1,
    Pattern3 => result2,
    else => default
}
  • Evaluates expression to get a literal value
  • Tests patterns in order
  • Returns result of first matching arm
  • else matches anything

5.6 Add Expressions

add(subject, predicate, object)
  • Creates a triple in the graph
  • Returns the subject entity
  • _ as subject creates a blank node
let evidence = add(_, wa2:type, core:Evidence)  // new blank node
add(store, wa2:contains, evidence)               // link to store

5.7 Empty Check

empty(expr)
  • Returns truthy ("true") if expression is empty/falsy
  • Returns Empty if expression is non-empty/truthy

6. Execution Model

6.1 Phase Order

1. Load Model (e.g., CloudFormation projection)
2. Load Framework (types, predicates, derives, rules, policies)
3. Select Profile
4. Derive Phase (fixed-point, model building)
5. Rule Phase (sequential by policy order, validation only)
6. Collect Findings

6.2 Derive Phase

Purpose: Enrich the graph with computed facts.

Constraints:

AllowedNot Allowed
add statements/expressionsmust modal
should, may modals
Blank nodes (_)

Execution:

  • Runs to fixed-point (until no new facts are added)
  • Order of derives does not matter (monotonic)
  • Guards operate normally (should/may skip remaining statements in block on failure)
  • Findings from should are collected as warnings

Rationale: Derives build the model; they cannot cause overall failure. A missing tag might prevent evidence creation, but that’s detected by rules.

6.3 Rule Phase

Purpose: Evaluate conditions and produce findings. Rules do not modify the model.

Constraints:

AllowedNot Allowed
must, should, may modalsadd statements/expressions
QueriesBlank nodes (_)

Execution:

  • Model is stable (derives have completed)
  • Only rules referenced by the selected profile’s policies are executed
  • Rules execute in policy declaration order
  • Modal statements evaluate immediately

Rationale: Rules validate a complete model. Since derives run first, all computed facts are available when rules execute.

6.4 Policy and Profile

Profile: Selects which policies are active.

profile production {
    policy data_protection
    policy compliance_checks
}

Policy: Binds rules with execution modals that control sequential flow.

policy data_protection {
    must all_stores_classified
    must critical_stores_protected
    should encryption_enabled
}

Two-Phase Execution:

  1. Derive phase completes first (model building)
  2. Rule phase executes rules in policy order

Policy Modal Semantics:

The policy modal controls whether execution continues to the next rule based on whether the current rule produced any Error-level findings:

Policy ModalRule OutcomeEffect
mustHas ErrorsStop policy, report Fail
mustNo ErrorsContinue to next rule
shouldHas ErrorsNote degraded, continue
shouldNo ErrorsContinue to next rule
mayAnyAlways continue

A rule “passes” if it produces no Error-level findings (warnings and info are acceptable).

Policy Outcomes:

OutcomeMeaning
PassAll rules passed
DegradedAll must rules passed, but some should rules failed
FailAt least one must rule failed

Example:

policy protect_stores_based_on_classification {
    must all_stores_must_be_classified    // stops if this produces Errors
    must ensure_critical_stores_protected // only runs if above passed
}

Per-Entity Dependencies: Handled naturally through evidence model. A rule checking for protection evidence will only match stores that have classification evidence, because the derive that creates protection evidence depends on classification evidence existing.

6.5 Fixed-Point Iteration

Derives execute in a fixed-point loop:

repeat until no change:
    for each derive:
        execute body
        track (derive, binding) to avoid reprocessing same entity

Maximum iterations are bounded to prevent infinite loops.

Rules do not use fixed-point iteration; they execute once per entity in policy order.

6.6 Namespace Resolution

  • Unqualified names inside namespace X { ... } resolve to X:name
  • use statements import namespaces for reference
  • Type references in as(Type) are qualified by current namespace if unqualified

7. Findings

7.1 Structure

A finding consists of:

FieldTypeDescription
subjectEntityThe entity this finding relates to
areaEntityThe type/category for educational content
messageStringHuman-readable action to resolve
severityEnumcore:Error, core:Warning, core:Info
assertionStringRule name and modal that produced this

7.2 Production

Findings are produced only by:

  • Modal statements (must, should, may)

as(Type) produces no findings; it returns Empty on invalid values.

7.3 Severity Mapping

ModalSeverity Entity
mustcore:Error
shouldcore:Warning
maycore:Info

8. Examples

8.1 Complete Example

use core
use aws:cfn
use data

// Define classification taxonomy
enum DataCriticality {
    Disposable,
    NonCritical,
    Important,
    BusinessCritical,
    MissionCritical
}

// Activate policies
profile production {
    policy protect_critical_data
}

// Define policy requirements
policy protect_critical_data {
    must all_stores_classified
    must critical_stores_protected
}

// Rule: all stores need classification
rule all_stores_classified {
    for store in query(core:Store) {
        let source = query(store/core:source)
        must query(store/core:Evidence/data:Criticality) {
            subject: source,
            area: data:Criticality,
            message: "Store must have criticality classification"
        }
    }
}

// Rule: critical stores need protection
rule critical_stores_protected {
    for store in query(core:Store[core:Evidence/data:isCritical]) {
        let source = query(store/core:source)
        must query(store/core:Evidence/data:isResilient) {
            subject: source,
            area: data:isResilient,
            message: "Critical stores must be protected from loss"
        }
    }
}

// Derive: extract classification from tags
derive classification_from_tags {
    for store in query(core:Store[core:source/aws:cfn:Resource]) {
        let source = query(store/core:source)
        let dc_tag = query(source/aws:Tags/*[aws:Key = "DataCriticality"])
        
        should dc_tag {
            subject: source,
            area: DataCriticality,
            message: "Add a DataCriticality tag to this resource"
        }
        
        let criticality = query(dc_tag/aws:Value) as(DataCriticality)
        should criticality {
            subject: source,
            area: DataCriticality,
            message: "DataCriticality tag must be a valid classification"
        }
        
        // Create evidence
        let evidence = add(_, wa2:type, core:Evidence)
        add(store, wa2:contains, evidence)
        let fact = add(_, wa2:type, data:Criticality)
        add(evidence, wa2:contains, fact)
        
        // Determine if critical
        let is_critical = match criticality {
            Disposable, NonCritical, Important => false,
            else => true
        }
        
        // Mark as critical if applicable
        if is_critical {
            let crit_fact = add(_, wa2:type, data:isCritical)
            add(evidence, wa2:contains, crit_fact)
        }
    }
}

8.2 Guard Behavior Example

derive example {
    for item in query(core:Item) {
        // If this fails, remaining statements for this item are skipped
        should query(item/core:required_field) {
            message: "Item needs required_field"
        }
        
        // Only reached if above passes
        let value = query(item/core:required_field)
        add(item, core:processed, value)
    }
    // Loop continues with next item regardless of guard
}

8.3 As-Conversion Examples

Standalone validation (returns value or Empty):

let criticality = query(tag/aws:Value) as(DataCriticality)
should criticality {
    message: "Tag value must be valid"
}

9. Reserved for Future

The following features are not yet implemented but are under consideration:

  • Aggregation functions (count, sum, all, any)
  • Arithmetic expressions
  • Rule return values and policy constraints on outcomes
  • Negation in queries (not)
  • Optional chaining in queries
  • Import/export between files
  • Macros and code generation

10. References

10.1 Grammar Summary

Whitespace    ::= ' ' | '\t' | '\n' | '\r' .
LineComment   ::= '//' [^\n]* '\n' .
BlockComment  ::= '/*' .* '*/' .

Ident         ::= [a-zA-Z_][a-zA-Z0-9_]* .
QualifiedName ::= Ident (':' Ident)* .

StringLiteral ::= '"' [^"]* '"' .
BoolLiteral   ::= 'true' | 'false' .

File ::= Item* .

Item ::= NamespaceDecl
       | UseDecl
       | TypeDecl
       | StructDecl
       | EnumDecl
       | PredicateDecl
       | InstanceDecl
       | RuleDecl
       | DeriveDecl
       | PolicyDecl
       | ProfileDecl
       | ProfileSelection .

NamespaceDecl ::= 'namespace' Ident '{' Item* '}' .

UseDecl ::= 'use' QualifiedName .

TypeDecl ::= Annotation* 'type' Ident .

StructDecl ::= Annotation* 'struct' Ident '{' FieldDecl* '}' .
FieldDecl  ::= Ident ':' TypeRef .

EnumDecl    ::= Annotation* 'enum' Ident '{' VariantList '}' .
VariantList ::= Ident (',' Ident)* ','? .

PredicateDecl ::= 'predicate' Ident .

InstanceDecl ::= 'instance' QualifiedName ':' QualifiedName .

RuleDecl   ::= 'rule' Ident '{' Statement* '}' .

DeriveDecl ::= 'derive' Ident '{' Statement* '}' .

PolicyDecl    ::= 'policy' Ident '{' PolicyBinding* '}' .
PolicyBinding ::= Modal QualifiedName .

ProfileDecl ::= 'profile' QualifiedName '{' ProfileItem* '}' .
ProfileItem ::= 'policy' QualifiedName .

ProfileSelection ::= 'profile' QualifiedName .

Statement ::= LetStatement
            | ForStatement
            | IfStatement
            | ModalStatement
            | AddStatement .

LetStatement ::= 'let' Ident '=' Expr .

ForStatement ::= 'for' Ident 'in' Expr '{' Statement* '}' .

IfStatement ::= 'if' Expr '{' Statement* '}' ('else' '{' Statement* '}')? .

ModalStatement ::= Modal Expr ModalMetadata? .
ModalMetadata  ::= '{' MetadataItem (',' MetadataItem)* ','? '}' .
MetadataItem   ::= 'subject' ':' Expr
                 | 'area' ':' QualifiedName
                 | 'message' ':' StringLiteral .

AddStatement ::= 'add' '(' Expr ',' QualifiedName ',' Expr ')' .

Modal ::= 'must' | 'should' | 'may' .

Expr ::= PrimaryExpr AsExpr? .

PrimaryExpr ::= QueryExpr
              | AddExpr
              | MatchExpr
              | EmptyExpr
              | QualifiedName
              | Ident
              | StringLiteral
              | BoolLiteral
              | '_' .

AsExpr ::= 'as' '(' QualifiedName ')' .

QueryExpr     ::= 'query' '(' QueryPath ')' .
QueryPath     ::= QueryStep ('/' QueryStep)* .
QueryStep     ::= NodeTest Predicate* .
NodeTest      ::= QualifiedName | Ident | '*' .
Predicate     ::= '[' PredicateExpr ']' .
PredicateExpr ::= QueryPath
                | QueryPath '=' StringLiteral .

AddExpr ::= 'add' '(' Expr ',' QualifiedName ',' Expr ')' .

MatchExpr ::= 'match' Expr '{' MatchArm* '}' .
MatchArm  ::= Pattern (',' Pattern)* '=>' Expr ','? .
Pattern   ::= Ident | 'else' .

EmptyExpr ::= 'empty' '(' Expr ')' .

Annotation    ::= '@#' Ident '(' AnnotationArg (',' AnnotationArg)* ')' .
AnnotationArg ::= Ident '=' Literal .

10.2 Severity Reference

ContextModalFinding ProducedSeverityGuard
Modal statementmustYesErrorYes
Modal statementshouldYesWarningYes
Modal statementmayYesInfoNo
expr as(T)invalidNoReturn Empty
expr as(T)type not foundAlways Error

10.3 Built-in Predicates

PredicateDomainRangeDescription
wa2:typeEntityTypeAssigns type to entity
wa2:subTypeOfTypeTypeEnum variant relationship
wa2:containsEntityEntityContainment/child relationship
core:sourceNodeResourceLinks derived node to source
core:subjectFindingEntityEntity the finding relates to
core:areaFindingTypeCategory for educational content
core:messageFindingLiteralHuman-readable guidance
core:severityFindingSeverityError/Warning/Info
core:assertionFindingLiteralRule and modal that produced finding

10.4 Item Type Constraints

ItemQueriesAddAllowed ModalsCreates
deriveshould, mayWarning, Info
rulemust, should, mayError, Warning, Info

These constraints are enforced at compile time (lowering phase).