Semantic Assembly Format
Low-level explicit-ID grammar used to prove canonical compilation and conformance.
Semantic Assembly Format (SAF) 1.0 is an engineering syntax for proposing Modeller
meaning. Modeller.Parsing compiles source documents to the canonical
context package, authored
model, source provenance,
and ordered diagnostics through one interface:
ParseResult DefinitionParser.Parse(
IEnumerable<SourceDocument> documents,
ParseOptions options,
CancellationToken cancellationToken = default)SAF remains an executable parser input, but it is not the business-facing Readable Modelling Language. Its explicit identities and flat statements support conformance, diagnostics, and parser bootstrapping while RML and its authoring anti-corruption layer are developed.
The syntax is not a second semantic model. Package loading and semantic validation remain authoritative after compilation. The parser does not persist, resolve dependencies, execute expressions, generate output, or supply implicit domain defaults.
Common syntax
- UTF text is interpreted as lines.
- Blank lines and lines beginning with
#are non-semantic. - Each statement begins with a lowercase keyword.
- Attributes use
name=value; values containing spaces use double quotes. - Stable identities and semantic relationships use UUIDv7 values.
- Statement order, document order, filenames, comments, and formatting are non-semantic.
- One
language 1.0and onecontextstatement are required across the source set.
Language 1.0 statements
| Statement | Required attributes |
|---|---|
context | id, name, slug, version |
decision | id, name, slug, inputs, hit-policy; optional export=true |
decision-conclusion | owner decision ID, id, name, slug |
decision-row | owner, id, name, slug, conditions, conclusion, finding-code; optional missing-findings |
entity | id, name, slug, lifecycle-id, lifecycle-name, lifecycle-slug |
stage | owner entity ID, id, name, slug |
fact | id, name, slug, type; optional export=true |
rule | id, name, slug, inputs, expression, conclusion identity/name/slug; optional true-findings, false-findings, missing-findings, and export=true |
behaviour | id, name, slug, entity |
outcome | owner behaviour ID, id, name, slug |
binding | owner, rule, purpose, facts mappings |
transition | owner, id, name, slug, lifecycle, source, target, outcome |
Language 1.0 deliberately supports only the explicit and(fact-id,...) rule
expression needed by the first ACCS slice. Unsupported expression forms return
parse.expression.unsupported; they are never evaluated or coerced.
Finding mappings use comma-separated fact-id:stable-code entries and make
Child Care explanation meaning explicit rather than inferred by the runtime.
Decision conditions use comma-separated fact-id:true, fact-id:false, or
fact-id:any entries. Language 1.0 supports the Unique
hit policy: complete typed input
combinations match exactly one row. Overlapping or incomplete tables fail at
runtime binding; row order never acts as a fallback.
Child Care example
language 1.0
context id=0191...0001 name="Child Care" slug=child-care version=1.0.0
fact id=0191...0006 name="Active enrolment exists" slug=active-enrolment-exists type=Truth export=true
rule id=0191...0008 name="Determine ACCS eligibility" slug=determine-accs-eligibility inputs=0191...0006 expression=and(0191...0006) true-findings=0191...0006:accs.active-enrolment-confirmed missing-findings=0191...0006:accs.active-enrolment-required conclusion-id=0191...0009 conclusion-name="Eligible" conclusion-slug=eligible export=trueThe complete fixture compiles to semantic digest
sha256:6d1448c32127c49571d2a7ea5982045b7aa74ed28da2d7323ac5360b94ed6728,
the same digest as canonical JSON.
The child-care-accs-decision-table.modeller fixture expresses Classify ACCS
eligibility with explicit Eligible and Ineligible conclusions. It
compiles to semantic digest
sha256:63e39411df24b9ee59614cc8d3fae4397e79272f85ac99b8fc2d97eda4e7a37a,
the same digest as its Child Care 1.1 canonical package.
Provenance and diagnostics
Every named statement retains a package-relative document, one-based line and column, and span length. Reference paths retain their exact token spans. Validation diagnostics are mapped back through those paths; an unknown input Fact therefore points to the Fact UUID in Determine ACCS eligibility, not merely to the file or Rule.
Malformed or incomplete syntax, unsupported language versions, invalid models, document/statement/token limits, unsafe document names, and cancellation return structured results. Parser or validation exception text is never exposed as a diagnostic.
Limits and security
ParseOptions.Language1 limits a source set to 1,048,576 characters, 10,000
semantic statements, and 100,000 attribute tokens. Source document names must
be package-relative and cannot traverse above the package. The grammar is flat, so authored nesting cannot create
recursive parser work. Source is tokenized and compiled as data; substitutions,
scripts, and expressions are never executed.
Legacy import
LegacyDefinitionAdapter exposes the versioned legacy-domain-root/1.0 path.
It supports only a legacy domain plus version and requires an explicit
current context UUID, display name, and slug. The adapter records the legacy
identifier-to-stable-ID mapping and retains the original source span.
Legacy services lists mix deployment and ownership ideas and are rejected as
ambiguous. Entities, endpoints, templates, and other legacy constructs remain
unsupported until a reviewed mapping and fixture proves equivalent meaning;
the adapter never guesses or silently accepts them.
Editor protocols consume this parser through the editor-integration reference, preserving the same diagnostic identities and source spans rather than defining a second language or validation path.