The gap a metrics layer leaves open
A metrics layer tells an agent what Total Sales is: a sum over a column, joined the right way. It does not tell the agent what a high-value client is, whether a product category that sells for less than it cost is a bug or a fact, or that the model's Products means the same thing as the Product in the ontology the rest of the organisation governs. Today the agent guesses, and a guess that produces a plausible number is the kind nobody catches.
In one sentence: an executable business rule is a condition over the model's own artefacts that the engine compiles to the query reporting its findings, and an ontology link is a SKOS mapping from an artefact to a governed concept, so the meaning lives in the model and the machine can act on it.
Executable business rules
A rule is declared in the semantic model, in YAML, as a condition over the model's own dimensions, measures and metrics. No SQL. This one says that every product category must sell for at least what it cost:
rules:
Non-Negative Margin:
type: validation
severity: error
description: Every product category must sell for at least what it cost
grain: [Product Category]
condition: {field: Gross Margin, op: ">=", value: 0}
The rule reads a metric, so it is an aggregate rule and declares the grain it is evaluated at. The engine compiles it to the query that reports its findings. Because this is a validation rule, the findings are the violations: the condition is negated in the HAVING. Gross Margin spans two fact tables, sales and purchases, so the query goes through the same Composite Fact Layer planner as any other multi-fact query, and stays correct:
WITH "composite_01" AS (
SELECT "Products"."productcat" AS "Product Category",
"Sales"."salesamount" AS "Total Sales"
FROM "orionbelt_1"."sales" AS "Sales"
LEFT JOIN "orionbelt_1"."products" AS "Products"
ON "Sales"."product" = "Products"."productid"
UNION ALL BY NAME
SELECT "Products"."productcat" AS "Product Category",
"Purchases"."purchaseamount" AS "Total Purchases"
FROM "orionbelt_1"."purchases" AS "Purchases"
LEFT JOIN "orionbelt_1"."products" AS "Products"
ON "Purchases"."purchaseproduct" = "Products"."productid"
)
SELECT "Product Category",
CAST(SUM("Total Sales") - SUM("Total Purchases") AS DECIMAL(18, 2)) AS "Gross Margin"
FROM "composite_01"
GROUP BY ALL
HAVING NOT "Gross Margin" >= 0
Four rule types cover the two things a rule is for:
- classification and eligibility rules describe members. Their findings are the rows the condition selects: the high-value clients, the low-stock products.
- validation and constraint rules state an invariant and carry a severity. Their findings are its violations.
Rules compose with all, any and not, and one rule can inline another by name, as long as both live at the same level and grain and the references form no cycle. A rule that only reads dimensions is row-level and becomes a WHERE predicate instead. Every problem the engine finds, an unknown field, a missing grain, a dimension outside the grain, a circular reference, is a structured error with a source position in the YAML.
One rule can be evaluated for its findings, or every rule can be run into a report with a status per rule, counts, sample findings and errors, so the same declarations serve as data-quality checks without a second tool.
Ontology links
The second half is about identity rather than logic. Most organisations already have concepts they govern: an enterprise glossary, an industry ontology such as FIBO, or plain schema.org. An external concept mapping ties a model artefact to one of those concepts, with a SKOS mapping relation and provenance:
ontology:
prefixes:
schema: "https://schema.org/"
dataObjects:
Products:
externalConceptMappings:
- concept: schema:Product
relation: exact
justification: curated
The relation vocabulary is SKOS: exact, close, broader, narrower, related, where broader means the external concept is the broader one. Links can sit on the model, a data object, a dimension, a measure, a metric or a rule. Compact IRIs expand against the declared prefixes, and duplicates or conflicting relations on one artefact are validation errors, not silent overwrites.
Links never change the SQL. They change what can be asked. Every loaded model is also an RDF graph, and each link becomes a skos:exactMatch or its sibling triple in it, so "which artefacts mean a schema.org Product" is a SPARQL query. A discovery API answers the same over REST: every mapping, the namespaces a model links into, and the artefacts still without a link.
What the agent gets
For an agent talking to the model over MCP, this is the difference between guessing and looking it up. Next to the tool that executes a query sit tools that list the rules, explain one with the SQL it compiles to, evaluate it for the current findings, run all rules into a report, and find which artefacts map to a given concept. The rule and the link are authored once, in the same reviewable YAML as the metrics, and reach every consumer through the same semantic sidecar.
How this compares
Metrics layers govern calculations. Some can test data, none of the tools below evaluates a declared rule over the model's own metrics at a grain, and none carries a link vocabulary an engine interprets. Each cell was checked against the vendor's documentation; the full rows, with sources, are on the comparison pages.
- dbt: data tests are SQL assertions on models, sources, seeds, snapshots and columns that return failing rows; not on a metric or at a grain. Its
metais free-form and treated as metadata only. - LookML:
testblocks assert a yes/no expression on every row of an Explore query, so an aggregate assertion is possible; they run in CI, not as a query surface.tagsare free-form strings the model does not use. - Cube: the
cubeobject has no test or rule parameter;metais free-form, with anai_contextkey for agent hints. - Malloy: no rule or assertion construct; annotations are stored verbatim and not interpreted by the compiler.
- AtScale: no rule or ontology-link object found among the documented SML objects.
Relationship to Other OrionBelt Concepts
- Composite Fact Layer (CFL) is what keeps an aggregate rule over two fact tables correct.
- Artefacts Composability Resolution (ACR) tells an agent what it may still add to a query; rules and links tell it what the artefacts mean.
- Agentic AI Data Access is the pattern these tools serve.
- In the docs: the Business Rules guide, the External Concept Mappings guide, and the OBSL graph and SPARQL guide.
Frequently Asked Questions
What is an executable business rule?
A business rule declared in the semantic model as a condition over the model's own dimensions, measures and metrics, with no SQL. The engine compiles it to the query that reports its findings: members for a classification or eligibility rule, violations for a validation or constraint rule, at a declared grain, through the same planner as any other query.
What is an external concept mapping?
A qualified link from a model artefact to a concept in an external ontology such as schema.org, FIBO or a corporate glossary, with a SKOS mapping relation and provenance. It never changes the compiled SQL; it changes what can be asked about the model, over SPARQL, REST and MCP.
Why not write business rules as SQL or dbt tests?
A rule written as SQL is bound to one warehouse and one physical schema, and an agent cannot explain, inspect or reuse it. A rule over the model's own artefacts is compiled per dialect, evaluated at its grain, kept correct across fact tables by the planner, exported into the model's RDF graph, and offered to agents as tools.
What does an AI agent gain from rules and ontology links?
The difference between guessing and looking it up: an agent can list the rules, explain one, evaluate it for the current findings, and find which artefacts mean a given ontology concept, next to the tool that executes queries.