In policy as code, how does a declarative match document differ from a rule written as a single expression?
answer
- three shapes, not three syntaxes
- data compared versus value computed
- path languages select, they do not decide
- expressiveness against review speed
basics
~20 sA match document states the shape a resource must have, and the engine compares the resource against that shape. An expression rule is a boolean over the resource's fields that the engine evaluates. Shape comparison versus computed verdict.
solid answer
~50 sRule languages come in three broad styles. A logic language lets you name intermediate rules and quantify over a collection, and it returns a set of violations — an empty set means allow. A declarative match document is data: it states the shape a resource must have, and the engine walks the pattern and the object together, field by field. An expression language such as CEL states the whole decision as one expression that evaluates to a value, with no I/O and no unbounded loops, so it always terminates. Path and query languages such as JSONPath and JMESPath are not deciders at all — they select values, and the rule around them says what a selected value means. The real trade is expressiveness against how fast a second person can confirm the rule matches the written standard.
go deeper
Be ready to open a policy repository and say which style each rule is written in — a shape to match, one boolean expression, or named logic rules — and what the engine does with the result.
Explain the mechanics: a match document is compared structurally against the object, an expression is evaluated to a value with no I/O, and a logic rule yields a set of results the engine reads as violations.
Show that you pick the style to fit both the rule and the people who will review it, and that you recognise when a rule has outgrown the style it was written in.
Own the consequence for the platform: the style you standardise on decides who can author guardrails, who can review them, and which class of rule you simply cannot state.
## What a rule language has to do A policy engine turns a document — a Kubernetes manifest, a rendered Helm or Kustomize output, an infrastructure plan, a build description — into a verdict. The rule that produces the verdict is written in one of three broad styles. The style is not a syntax preference: it decides what the rule can express at all, and it decides how quickly somebody other than the author can read the rule and agree that it says what the written standard says. ## 1. A logic language A logic language in the Datalog tradition lets you declare named rules that refer to one another. A rule body is a set of conditions that all have to hold; the engine tries the body against the input data and collects the results. Two properties matter: - **Quantification.** You can say things of the form *for every element of this collection, some other element must exist with a related property*. That is what lets a rule cross from one object to another. - **Intermediate names.** You can define `multi_replica_workloads` and `budgets_covering(labels)` and then write the top-level rule in terms of those names, so each named piece corresponds to one clause of the written standard. The output is typically a set of violation messages rather than a single boolean; an empty set means nothing was found to complain about. Evaluation reads the input data only — there is no side effect and nothing is fetched mid-decision. ## 2. A declarative match document Here the rule is written in the same serialization as the thing it judges. You state the shape a resource must have — or must not have — and the engine compares the incoming object against the pattern field by field. There is no control flow to trace, because the rule is data. That buys a lot. Such rules diff cleanly in review, can be generated, and can be read by an engineer who understands the resource but has never seen the policy system before. A reviewer's eye goes straight to the field names, which are the same field names the standard talks about. The ceiling is hard, though: a shape describes **one** object. There is no way to express *for every X there exists a Y*, no way to name an intermediate result, and only whatever comparison vocabulary the matcher itself provides. ## 3. An expression language The whole rule is a single expression over the input that evaluates to a value, usually a boolean. CEL is the common example in this space. Expression languages used for policy are deliberately restricted: no I/O, no side effects, no unbounded iteration. Quantifiers exist as macros that range over data already present in the input rather than as general loops. That restriction is the point. Evaluation terminates by construction, and the cost of a rule can be reasoned about before it is allowed to run on the path of every change. The price is that everything has to fit into one expression — there is no place to name a sub-result and reuse it, so a rule that needs three ideas becomes three nested ideas on one line. ## Where path and query languages fit JSONPath and JMESPath are frequently described as if they were policy languages. They are not: they are **selection** languages. They answer *what is at this location*, or *which elements of this list match this filter*, and they hand back the selected data. Something else still has to turn that into a decision — a comparison in a match document, a test inside an expression, or an engine convention such as *a non-empty selection is a violation*. Reading a rule built out of a path expression therefore means understanding both the path semantics and the convention wrapped around it, which is a common source of review confusion. ## How to tell them apart in a repository - If the artifact looks like the resource with required values filled in, it is a match document, and its ceiling is one object. - If the artifact is one line of boolean logic over field paths, it is an expression, and it terminates but cannot be decomposed. - If the artifact declares named rules that call one another and yield messages, it is a logic language, and it can quantify and join. ## The trade you are actually making Every step up in expressiveness costs review speed. The most expressive style states a cross-object requirement — for example *every workload with more than one replica must have a matching PodDisruptionBudget* — directly, and cannot be stated at all as a single shape. The least expressive style is the one a stranger can confirm in ten seconds. A control that is correct and unreviewable is a control that exists on paper: nobody can attest that it still matches the standard, and nobody dares change it. Pick the least expressive style that can honestly state the rule, and step up only when the requirement genuinely demands it.
- Where do JSONPath and JMESPath fit in this picture?They are selection languages, not decision languages. They pull a value out of the document — a field, a filtered list, a count. Something else still has to say whether that value is acceptable: a comparison in a match document, a test inside an expression, or an engine convention that treats a non-empty selection as a violation. On their own they answer what is there, never whether it is allowed.
- Why is a match document usually described as data rather than code?Because it is written in the same serialization as the object it judges — the resource shape with the required values filled in. There is no control flow to follow; the engine walks the pattern and the object together. That is why such rules diff, generate and review well, and it is exactly why they cannot express anything needing quantification or a reference to a second object.
A match document is a passport photo template: hold the picture against it and see if it fits. An expression is a single yes/no formula. A logic language is a checklist whose items can refer to each other.
saying these in an interview costs you the question
- Calls every policy language just YAML with if-statements
- Thinks a policy expression language can loop arbitrarily
- Believes a JSONPath expression by itself decides allow or deny
- Assumes the styles differ in syntax only, not expressiveness