feat: chain condition steps — defeasible/logical evidence as final chain hop
CI / publish (push) Successful in 9s
CI / test (push) Successful in 18s

A chain's FINAL (object-side) step may now reference a defeasible/logical
evidence. The compiler lowers it to a condition step
({ rule: <config>, conditionStep: true }) that the engine verifies at
(intermediate, object) instead of traversing an edge. Requires
@arbiter/core@^1.0.3 (ChainRule condition-step support).

- _expandChainSteps: a logical/defeasible/comparator evidence is expressible
  as a final condition step; non-final such steps remain a compile error
  (a condition cannot discover intermediate nodes).
- Dependency collection (generator + DSLRuntime) descends into condition-step
  rule configs, so partial-graph requirements reach through them.

Tests: ChainConditionStep (defeasible + ALWAYS steps, independent checkability,
parallel aggregation), oracle campaign chain_condition_step construct
(oracle = min(pm, pv*(1-pb))), DSLRuntime transitive required facts through a
condition step.
This commit is contained in:
John Dvorak
2026-08-03 12:08:54 -07:00
parent 2dc478f5a3
commit 351551af0f
9 changed files with 178 additions and 31 deletions
@@ -96,14 +96,6 @@ const MUTATIONS = {
'evidence can_read(user: Employee, doc: Doc) { owns(user, doc) }',
'fact can_read(user: Employee, doc: Doc)\n evidence can_read(user: Employee, doc: Doc) { owns(user, doc) }'
)
},
non_lowerable_chain_step: {
desc: 'a defeasible evidence used as a chain step (cannot lower to an edge)',
mustFail: true,
apply: () => VALID_DSL.replace(
'evidence can_enter(user: Employee, doc: Doc) { member_of(user, *g) { can_access(g, doc) } }',
'evidence can_gated(group: Group, doc: Doc) { WHEN can_access(group, doc) UNLESS banned(group) }\n evidence can_enter(user: Employee, doc: Doc) { member_of(user, *g) { can_gated(g, doc) } }'
).replace('fact can_access(group: Group, doc: Doc)', 'fact can_access(group: Group, doc: Doc)\n fact banned(group: Group)')
}
};