feat: intermediate chain condition steps + _subjectIsObject unary scoping
- _expandChainSteps: a logical/defeasible evidence referenced by a chain step
is now a condition step ({ rule, conditionStep }) at ANY position. As the
FINAL step the engine verifies it at (intermediate, object); as an
INTERMEDIATE step the engine expands it from the current node (rule-based
reachability: base edges' destinations filtered by the rule's
defeaters/requirements) and continues traversal from each discovered node.
- buildPredicateRule / buildDirectRule: unary predicate calls whose subject
entity IS the evidence's object parameter (trusted(other) inside
peer_trusted(user, other)) are marked _subjectIsObject (was: only subject-var
calls got _subjectAsObject). Requires @arbiter/core@^1.0.4.
Tests: ChainConditionStep intermediate expansion; oracle campaign gains a
chain_intermediate_condition construct (oracle = min(peer*(1-trusted), read)).
This commit is contained in:
@@ -33,8 +33,11 @@ const FACTS = `
|
||||
fact owner(group: Group, doc: Doc)
|
||||
fact granted(user: Employee, doc: Doc)
|
||||
fact group_perm(group: Group, doc: Doc)
|
||||
fact banned(user: Employee)
|
||||
fact group_banned(group: Group)
|
||||
fact banned(user: Employee)
|
||||
fact peer(user: Employee, other: Employee)
|
||||
fact trusted(other: Employee)
|
||||
fact doc_read(user: Employee, doc: Doc)
|
||||
fact mfa(user: Employee)
|
||||
`;
|
||||
|
||||
@@ -142,6 +145,20 @@ function buildProgram(kind, ps) {
|
||||
oracle = Math.min(pm, pv * (1 - pb));
|
||||
break;
|
||||
}
|
||||
case 'chain_intermediate_condition': {
|
||||
// peer_trusted (a defeasible evidence) as an INTERMEDIATE chain step:
|
||||
// the engine expands it from the source (peer edges filtered by the
|
||||
// trusted defeater) then continues to can_read. Oracle = min of the
|
||||
// surviving peer leg and the read leg.
|
||||
const [pp, pt, pr] = ps;
|
||||
evidence = `evidence peer_trusted(user: Employee, other: Employee) { WHEN peer(user, other) UNLESS trusted(other) }
|
||||
evidence can_via(user: Employee, doc: Doc) { peer_trusted(user, *p) { doc_read(p, doc) } }`;
|
||||
edges.push({ src: 'u:1', relation: 'peer', dst: 'p:1', possibility: pp });
|
||||
edges.push({ src: 'p:1', relation: 'trusted', dst: 'p:1', possibility: pt });
|
||||
edges.push({ src: 'p:1', relation: 'doc_read', dst: 'doc:9', possibility: pr });
|
||||
oracle = Math.min(pp * (1 - pt), pr);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error(`unknown construct: ${kind}`);
|
||||
}
|
||||
@@ -162,6 +179,10 @@ function runCheck({ kind, ps }) {
|
||||
arbiter.addNode('u:1', 'Employee');
|
||||
arbiter.addNode('g:1', 'Group');
|
||||
arbiter.addNode('doc:9', 'Doc');
|
||||
for (const e of edges) {
|
||||
arbiter.addNode(e.src, e.dst === 'doc:9' ? 'Doc' : 'Employee');
|
||||
arbiter.addNode(e.dst, e.dst === 'doc:9' ? 'Doc' : 'Employee');
|
||||
}
|
||||
const compiler = new DSLCompiler(arbiter);
|
||||
const compiled = compiler.compile(dsl, 'oracle');
|
||||
if (!compiled.success) {
|
||||
@@ -178,7 +199,7 @@ function runCheck({ kind, ps }) {
|
||||
|
||||
const CONSTRUCTS = ['direct', 'chain', 'tuple_to_userset', 'fusion_min', 'fusion_max',
|
||||
'when_unless', 'never_always', 'requires_when', 'composition', 'chain_step_composition',
|
||||
'chain_condition_step'];
|
||||
'chain_condition_step', 'chain_intermediate_condition'];
|
||||
|
||||
describe('DSL generative oracle parity (rigor)', () => {
|
||||
it('generated legal DSL compiles and every check matches the oracle', async () => {
|
||||
@@ -220,6 +241,10 @@ describe('DSL generative oracle parity (rigor)', () => {
|
||||
arbiter.addNode('u:1', 'Employee');
|
||||
arbiter.addNode('g:1', 'Group');
|
||||
arbiter.addNode('doc:9', 'Doc');
|
||||
for (const e of edges) {
|
||||
arbiter.addNode(e.src, e.dst === 'doc:9' ? 'Doc' : 'Employee');
|
||||
arbiter.addNode(e.dst, e.dst === 'doc:9' ? 'Doc' : 'Employee');
|
||||
}
|
||||
const compiled = new DSLCompiler(arbiter).compile(dsl, 'sweep');
|
||||
assert.ok(compiled.success, `${kind} compile failed: ${(compiled.errors || []).join('; ')}`);
|
||||
for (const e of edges) arbiter.addRelation(e.src, e.relation, e.dst, { possibility: e.possibility });
|
||||
|
||||
Reference in New Issue
Block a user