Home / Projects / Orchestrata Ultimate / Decisions / ADR index / ADR-0025

ADR-0025: The governance rulebase bans dynamic predicate construction

field value
Status Accepted
Date 2026-07-24
Register factory (docs/adr, 4-digit ids)
Source docs/adr/0025-ban-dynamic-predicate-construction.md — permalink at bdafa201a (unchanged on master since that commit)
Wiki register entry ADR-0025 (wiki status: Accepted)

← ADR-0024 · ADR-0026 →

The record

Context

Two independent mechanisms depend on statically analysing the rulebase's call graph:

Both are unsound if the call graph is not statically knowable. call/N on an unbound goal, and assert/retract, make the set of predicates a rule may consult undecidable at analysis time — so the projection can silently under-select (false green, ADR-0006's exact failure) and the stratification lint can pass a rule whose real dependencies it never saw.

This constraint is load-bearing for two mechanisms and appears nowhere in the spec.

Decision

In the governance rulebase (constitution, patterns, project rules — not application code):

Alternatives rejected

Consequences

Note — the engine question this raised is settled (ADR-0027)

Prior-art research observed that these restrictions are exactly the static checks production policy engines enforce natively (Soufflé's stratified negation, Rego's recursion ban, Cedar's decidable SMT fragment), and asked whether hand-rolling them meant Prolog was the wrong engine.

ADR-0027 settles that: we retain Prolog. Rego and Cedar are disqualified because they remove recursion, which our transitive-closure knowledge-graph queries require; Soufflé has no incremental evaluation, which SWI's incremental tabling already gives us in production. So this ADR stands on its own merits — the ban is what makes ADR-0006's projection-completeness check and ADR-0010's stratification lint sound — and not as a symptom of a wrong engine choice.

Current state of compliance

A survey of the 16 rulebases (~3,096 lines) on 2026-07-24 found the discipline largely already practised: zero call(, and assert/retract appearing almost entirely in comments documenting that Python asserts only ground facts. The outstanding remediation backlog is 121 \+ occurrences requiring stratification review and 18 cuts to remove.

Provenance

Round-3 Opus (#12) and Fable (C-6), both noting the constraint is load-bearing for two mechanisms and stated nowhere. The engine question, raised by the 2026-07-24 prior-art research, is resolved in ADR-0027.

Relations of ADR-0025

Rulings cited

None.

Specs cited