BEHAVES AS transitive now emits bounded multi_hop configs (direct checks and
evidence references), fixing a silent no-op. NOT builds keep _subjectAsObject
scoping so unary predicates negate the right node, and value-typed evidence
objects gate by exact edge value. Recompiling a scope uninstalls its stale
relation configs (compileMultiple coexistence preserved). Sources become
injectable relations honored by requiredFacts with a within-X recency gate.
Duplicate definition fields and three common declaration mistakes (within on a
fact, two BEHAVES clauses, limit on a non-pattern body) now produce targeted
errors. Provider edges referencing unknown nodes are warned and dropped.
An evidence whose config contains a chain step referencing ITSELF is now
unrolled at compile time into a bounded transitive closure: a union of paths
— base, hop+base, hop²+base, …, hop^N+base — where `hop` is the recursive
chain's steps before the self-reference and the depth N comes from the
pattern's `limit N` (or the compiler's maxRecursionDepth default, 3). The
base (the evidence's non-recursive statements) is verified as a condition
step at each path's terminal node, so the engine needs no new machinery.
- Chain configs carry the pattern's `limit` as maxDepth.
- resolveEvidenceReferences detects a self-reference (_findSelfReference),
extracts the base (_extractBase), and unrolls (_unrollRecursiveEvidence).
- Pure recursion with no base case is a compile-time error; mutual cycles
between distinct evidence remain a compile-time error.
Example: can_access_via = can_access OR (reports_to + can_access_via) up to
the declared limit grants access inherited up a reporting chain.
Tests: Recursion (unroll shape, base + multi-hop grants, depth-limit
enforcement, default depth, pure-recursion error, mutual-cycle guard).
The Evidence DSL (ADR-000) is a thin declarative layer that compiles to
engine rule types. It has zero runtime coupling to the core engine
(DSLCompiler takes an arbiter as a duck-typed argument; the only shared
code was the ip-utils helpers, now local). Extracting it into its own
package keeps the core artifact free of the DSL surface.
- @arbiter/evidence-dsl depends on @arbiter/core (config formats are the
compilation target)
- deep-path exports for the compiler, parser, generator, validation,
and built-in functions (the surface the core's DSL tests consume)
- tests moved alongside; generate-parser script + peggy devDep local
- CI: test on push, publish on v* tags