Predicates, rules, and facts
Verdict separates what is currently true in your application (facts) from the access control logic that decides what those relationships permit (rules). Both facts and rules use a shared vocabulary of named statements called predicates.
Predicates and terms
Section titled “Predicates and terms”A predicate is a named statement over 1 to 3 positional terms that evaluates to true or false:
// Unbound pattern matching across any actor, action, and resourceallow(user, action, document)
// Partially bound pattern for a specific action and resourceallow(user, "read", Document:handbook)
// Fully bound statement with concrete values in every term positionis_owner(User:alice, Document:handbook)Each expression inside the parentheses is a term:
- Ground terms (concrete values): Fixed values referencing specific entities (typed identities such as
User:aliceandDocument:handbook) or scalar literals ("read",42,true). - Variable terms (placeholders): Lowercase identifiers (
user,action,document) that match concrete values during evaluation; see Variables and matching.
Asserting ground truth with facts
Section titled “Asserting ground truth with facts”A fact is a fully bound predicate statement that records something true in your domain. In .vd syntax, write a fact as a concrete statement with no if body, ending with a semicolon:
is_owner(User:alice, Document:handbook);
Deriving conclusions with rules
Section titled “Deriving conclusions with rules”Rather than storing a separate permission record for every action a user can take, write rules that derive access from your underlying facts. A rule has a head (the conclusion before if) and a body (the conditions after if):
allow(user: User, "read", document: Document) if is_owner(user, document);Verdict derives rule conclusions on demand during evaluation. Because permissions are computed from the underlying facts when needed, your application records is_owner once, and read access updates automatically whenever ownership changes.
In Verdict policies, allow(actor, action, resource) is the standard entry point for authorization checks. Other predicates represent domain relationships, resource attributes, or reusable helpers.
Fact type declarations
Section titled “Fact type declarations”A declare declaration documents the expected term types of an input predicate for readers, editor tooling, and verdict validate:
// Declares the expected shape (no data inserted)declare is_owner(User, Document);
// Asserts a concrete fact for Alice and the handbookis_owner(User:alice, Document:handbook);Declaring your input facts lets verdict validate catch typos in predicate names and arity mismatches across your rules before you publish. See the Language Reference for all supported declaration slot forms.
Putting declarations, facts, and rules together
Section titled “Putting declarations, facts, and rules together”Combining a declaration, a concrete fact, and a rule in a .vd file produces a complete, self-contained policy model:
declare is_owner(User, Document);
is_owner(User:alice, Document:handbook);
allow(user: User, "read", document: Document) if is_owner(user, document);Depending on where a predicate appears, the same syntax performs four roles:
| Construct | Example | Role |
|---|---|---|
| Fact | is_owner(User:alice, Document:handbook); | Asserts concrete ground truth |
| Rule head | allow(user: User, "read", doc: Document) | Defines a conclusion derived when the body succeeds |
| Rule condition | ... if is_owner(user, doc); | Requires the statement to hold from a fact or rule |
| Fact type declaration | declare is_owner(User, Document); | Documents expected term types for authors and tooling |
| Query goal | allow(User:alice, "read", doc: Document) | Checks a concrete decision or finds matching values |
When you evaluate the policy, you pass a predicate expression as a query goal:
// Ground query (concrete check): Is Alice allowed to read the handbook? -> trueallow(User:alice, "read", Document:handbook)
// Open query (seeking bindings): Which documents can Alice read? -> { doc = Document:handbook }allow(User:alice, "read", doc: Document)Writing concrete facts directly in a .vd file is useful for self-contained examples and fixed policy constants. In a live application, your backend supplies changing application facts at runtime through the client SDK or REST API; see Managing Facts.
Next steps
Section titled “Next steps”- Represent entity references and scalar properties in Values and identities.
- Connect variables across conditions and understand query bindings in Variables and matching.
- Combine multiple requirements and alternative grant paths in Combining conditions.