Concepts

Runtime EDB

Supply a complete snapshot of request facts to one bounded policy evaluation.

The EDB (Extensional Database) contains the input facts supplied by the application for one evaluation. For example, owns("alice", "roadmap.pdf") says who owns a document. A fact is ground when it contains concrete values, not variables.

The solver reads this input and derives new facts in the result, not in the EDB. The loaded ruleset supplies the rules; the domain supplies the allowed predicate names, arities and roles. The public input buffer is independent of a policy: its contents are checked against the selected policy when solving.

For programming details, see C Stable EDB, Python EDB or TypeScript EDB.

Why EDB exists

EDB separates what changes for each request from the rules reused across requests.

ConcernExampleLifetime
Runtime inputOwnership, sharing and a user's sensitivity level.Facts supplied for this evaluation.
Reusable logicAn owner may read a document if the required conditions hold.Loaded once; evaluated for many requests.
Input responsibilityThe application supplies the evidence the policy needs.Checked before each authorization decision.

For the document_access example, the EDB might contain:

DATALOG
owns("alice", "roadmap.pdf").
shared_with("bob", "roadmap.pdf").
sensitivity_level("alice", 4).
sensitivity_level("bob", 3).

Those facts change per request. The ruleset does not.

Where EDB fits

The EDB sits between caller input and solver output.

ARCHITECTUREFrom request facts to a result
    • Applicationobserves the request
    • Input EDBstores concrete facts
    • Solveapplies the prepared policy
    • Resultinput snapshot + conclusions

EDB vs IDB

TypeSourceExample
EDBApplication supplies facts at runtime.owns("alice", "roadmap.pdf")
IDBSolver derives facts by applying rules.allow("alice", "roadmap.pdf")
POLICY_FACTPolicy author writes facts directly in the source.blocked("mallory"). when blocked/1 has that role.

EDB facts are what the application reports. IDB facts are what the policy concludes. A predicate has exactly one of these three origins.

Lifecycle

Create the input buffer once, then build the complete facts for a request.

ARCHITECTUREOne input batch, one evaluation
    • Create bufferchoose bounded capacities
    • Add factsone fact or an atomic batch
    • Solvevalidate, sort and deduplicate
    • Inspect resultquery and optional explanations
    • Release resultthe session can solve again

There is no separate EDB finalization step in the current public API. Solving prepares the engine's input snapshot internally.

For another request:

  • Release the previous result before solving again on the same session.
  • Clear or reset the input buffer, or create another buffer.
  • Supply the new request's complete facts, then solve with the same session.

Clearing an input buffer does not release a result. Conversely, closing or changing the input buffer does not change a returned result's snapshot. C permits reuse of the buffer directly; Python seals a successfully solved EDB and provides reset() to start a new batch. The programming pages describe each binding's exact lifetime rules.

Adding facts

Two vocabulary modes

There are two places where the same string can appear, with different checks.

Where the string appearsExampleMust be declared in domain atoms?
Policy sourcenot(blocked("mallory"))Yes, by default. It is a constant chosen by the policy author.
Runtime EDBblocked("mallory") supplied for a requestNo. It is a request value supplied by the application.

The short rule:

Constants in .dl are policy vocabulary. Facts in the EDB are runtime evidence.

Declaring "mallory" in atoms does not insert a fact. It permits that string to be written in policy source. Inline loading always requires declared source strings; a manifest loader has an explicit permission to accept undeclared policy-source atoms. That permission does not allow undeclared predicates.

Strings that belong to the policy program (operation names, deny codes, protected branch names) are written in the .dl source. Strings observed at request time (user names, paths, messages) belong in the EDB. Both are matched by their string value during evaluation.

What is a fact?

A fact has a predicate name and a fixed number of typed terms.

DATALOG
owns("alice", "roadmap.pdf").
age("bob", 34).
active(true).
  • owns/2 has two terms: a user and a document, both strings.
  • age/2 has two terms: a string and an integer.
  • active/1 has one term: a boolean.

The predicate must be declared EDB in the selected domain. A POLICY_FACT predicate belongs to policy source; an IDB predicate belongs to rule conclusions. Neither can be injected as runtime input.

Every predicate has exactly one arity. If owns/2 is declared, supplying owns("alice") is a shape error, not a different relation. See Predicate identity.

Input insertion copies predicate names and string values into the buffer. A batch is atomic: if one entry cannot be added, none of that batch is added. Shape and storage checks happen on insertion; checks against the selected domain, including the declared arity and EDB role, happen when solving.

The three term types

TypeUse whenExample
SymbolA name, path or string identifier."alice", "roadmap.pdf"
IntegerA whole number.42, -7, 1024
BooleanA true/false value.true, false

Runtime integers are signed 64-bit values. A variable such as User is a placeholder in a rule, not a fourth kind of value accepted in an EDB fact.

Integer inputs can be tested by arithmetic filters such as Score + 1 >= 10. The filter tests already-bound values; it does not create new ones. Numeric aggregates have a narrower supported value range; see the language guide.

Why symbols are different from ints and bools

Internally, the engine interns strings: it associates each distinct string with a compact identifier so later comparisons can use identifiers instead of comparing all the bytes again.

StringInternal identity in one evaluation
"alice"One identifier.
"bob"A different identifier.
"alice" againThe same identifier as before.

The public input API accepts strings, not identifiers you must intern yourself. The engine reconciles policy constants and runtime strings when preparing the evaluation.

EDB constraints

ConstraintWhat is bounded
Stored entriesThe number of added facts, before deduplication.
Text storageCopied predicate names and string terms.
ArityThe number of terms accepted in a fact.
Facts per predicateThe selected profile's relation capacity, checked during evaluation.

These bounds are not all checked at the same moment. An insertion can fail because the buffer is full; solving can fail because facts do not match the domain or exceed a relation capacity. Neither failure publishes a partial result. For numeric capacities, status names and diagnostics, see C Stable errors.

What you have learned

KEEP THIS MODEL

Build a complete input snapshot
  • Request facts are concrete inputs

    Each fact gives a predicate name and its typed values, not rule variables. Supply all facts needed to evaluate the current request.

  • The application chooses trustworthy evidence

    The engine evaluates the supplied facts; it does not authenticate them or invent missing evidence.

  • Copied inputs and results have separate lifetimes

    The input buffer copies its strings. Clearing or closing it does not change a result already returned by a successful solve.

  • A batch is inserted together

    If batch insertion fails, none of its new facts are added. Domain and relation-capacity checks also occur during solving.

  • Limits fail explicitly

    Insertion can fail when input storage is full; solving can fail when facts violate the domain or relation limits. Neither failure publishes a partial result.