aboutsummaryrefslogtreecommitdiffstats

About

This document specifies the runtime that executes Sol. Everything in the first sections is implemented in lib/ and tested; the last section specifies what the runtime owes the future and how it will grow without changing the meaning of what already runs.

Object model

The VM manipulates a small set of value kinds, all immutable:

terms (Term.t)
canonical closed values. Integers and strings ground the tower; rationals are irreducible with denominator greater than one; records are nonempty labeled tuples in canonical attribute order; #() is the empty sequence. Canonicity is sealed at construction, so structural equality is value equality and a term can be hashed as it stands.
patterns (Pattern.t)
terms open over logic variables. Rule heads, rule bodies, goals and answers are patterns.
substitutions (Pattern.Subst.t)
the unification store. Grow only; unification runs an occurs check because Sol terms are finite.
expressions (World.expr)
compiled propositions: application, conjunction, disjunction, denial, universal.
relation definitions (World.def)
a table (schema plus finite stored tuples) or a rule set. Rules carry their name, head bindings, body, and, when recursive, the decrease witness label that admission found.
worlds
whatever satisfies the WORLD module type: a total answer to "which definition lives under this name". The engine holds no other state about storage.

Execution

One mechanism runs everything: goal search over a substitution.

A relational expression flattens into goals. Each step, the engine runs any goal decidable under the current substitution:

  • a builtin decides membership, unifies equality, computes or solves arithmetic, compares, or enumerates a bounded range;
  • a table application scans finite facts, unifying goal bindings against each tuple;
  • a rule application unfolds: variables rename apart with an unlexable stamp, goal bindings unify with the head, and the body's goals join the queue. Unfolding requires every recursive rule's witness argument ground, which turns the admission proof into a runtime termination measure;
  • a denial runs once its variables are ground, refuting by exhaustive search of a total subproblem;
  • a universal runs once its quantifier is decidable, checking the body against every quantifier solution.

Goals that are not yet decidable wait. When only waiting goals remain, membership residuates and search rejects: if every remaining goal is builtin membership, the answer carries them as residual constraints; if any is a stalled search, the plan is rejected with the stuck goals named. This is the whole of the distinction the specification demands: membership checks or residuates, constraints wait, generation only under bounds, and non total plans do not execute.

Answers are the query's free variables resolved to canonical values, plus the residual constraints the answer is conditioned on; the common case is ground and residue free. Variables that live only under a universal are not answer variables. Integrity criteria accept only residue free proof: a conditioned answer admits no fact.

Totality accounting

The engine terminates on every admitted program. The argument, each piece machine checkable and one piece machine checked today:

  1. every rule that unfolds recursively carries its component's lexicographic measure, all positions ground at unfolding, and every call cycle through the component strictly decreases it;
  2. strict containment decreases a natural measure, the induced order is well founded (proven in theories/Decrease.v), and the lexicographic product of well founded orders is well founded;
  3. tables are finite, builtins decide or defer without search, and bounded generators enumerate finite ranges;
  4. disjunction and rule choice branch finitely.

The containment check itself is no longer hand written: admission runs the checker extracted from theories/DecreaseChecker.v, where its soundness (a successful check really is strict containment, leaves and labels included) and the decrease theorem are proven. What remains trusted: the injective conversion from Pattern.t to the checker's term shape, the two equality functions handed to it, and the surrounding admission logic. Each future extraction shrinks that list.

Integrity control hooks

Admission is the integrity boundary. Facts enter a world only through: groundness, exact schema match, primitive domain membership decided by the host, and membership criteria solved against the complete extension. A criterion is an ordinary expression with one free variable, so foreign keys, refinements and range checks are the same hook. Embedded hosts run the same hook by constructing pending checks and solving them with the same engine.

Interaction with stored relations

The engine never owns storage. A world answers find, now state scoped: the reserved at: label names the state a stored relation is read from, stripped before unification and demanded ground before the read runs. A world also answers transition: transition relations like Insert are the world's, never the engine's; the VM unifies the successor state with after: and defers ungrounded chains. The standalone world ignores states and has no transitions (decision 5). lib/branch is the reference stateful world: content-addressed states, append-only store, tip per branch, commit as compare and swap, and the linearity check of decision 6 over transition chains. RNT implements the same contract against its kernel. See docs/states.org.

Error and proof obligation reporting

Two error channels, both total:

  • admission errors name the offense: the rule without a decrease, the mutual cycle, the unknown reference, the ill typed fact, the violated criterion;
  • planning errors name the stuck goals, which is the language telling you which variable to bind or which search to bound.

Nothing is deferred as an unproven obligation; a program is admitted whole or not at all.

What the runtime owes the future

Specified, not yet implemented; each grows admission or planning without changing admitted semantics:

  • richer propagation: the interval store today reads domains and one-sided comparisons; difference constraints between variables, arithmetic relations, and propagation through record structure are the next strengths;
  • symbolic discharge beyond the interval fragment: algebraic identities of relations (universals mentioning Plus and kin), and arithmetic decrease measures for recursion that structural containment cannot see;
  • Rocq certificates as admission evidence, and extraction of the lexicographic search itself (the containment core is already extracted);
  • lowering of finite first order subplans to RNT's Plan.t algebra with Sakura's cardinality tags, per decision 9;
  • tabling for shared subderivations, an optimization the pure semantics licenses.