feat: evidence composition — compile-time reference resolution for evidence sub-rules
CI / publish (push) Successful in 11s
CI / test (push) Successful in 15s

An evidence may now reference another derived evidence as a sub-rule
(WHEN can_read(user, doc) where can_read is itself an evidence). Resolution
is a compile-time linker pass: after every evidence config is generated, each
direct reference to an evidence is inlined with that evidence's own (resolved)
config, so the engine evaluates a fully-resolved, acyclic config tree.

- resolveEvidenceReferences(): post-generation pass over evidence configs,
  recursing into logical/defeasible containers (when/unless/never/always/
  requires/union/intersection), always.direct nests, and comparator operands.
- Forward references resolve (all configs exist before the pass runs).
- Cycles and self-references are compile-time errors.
- _subjectAsObject scoping is preserved through inlining.
- dependsOn is recomputed after resolution, so partial-graph requirements
  reach transitively through composed evidence.
- buildDirectRule/buildPredicateRule now apply subject-scoping to top-level
  PredicateCall evidence bodies (latent gap, previously missed).
- validation: reject relation names shared across facts/sources/evidence/
  measures (a collision silently overwrote configs and read as a false cycle).

Tests: EvidenceComposition (9), DSLRuntime transitive requiredFacts, oracle
campaign composition construct, illegal-mutations cycle + cross-kind cases.
This commit is contained in:
John Dvorak
2026-08-03 11:17:30 -07:00
parent 0a744329e6
commit 88f10f9db4
7 changed files with 371 additions and 42 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@arbiter/evidence-dsl",
"version": "1.1.0",
"version": "1.2.0",
"description": "Evidence DSL v2 compiler: translates the natural Evidence DSL (ADR-000) into @arbiter/core relation configurations.",
"license": "ISC",
"type": "module",