test: fix legacy fixture suites against modern DSL validation
CI / test (push) Successful in 25s
CI / publish (push) Has been skipped

The legacy test files (Definition/Evidence/Expression/Fact/Integration/
Measure) predate the DSL's validation rules: reserved built-in types
(User/Account/Device/AuthSession) and the boolean/predicate-call
requirements on evidence statements. Fixed the fixtures, not the engine:

- reserved renames: User->Employee, Account->Tenant (Device/AuthSession
  were only legally referenced)
- expression fixtures: comparators now use predicate calls on both sides
  (fact score(value: number) + score(1 + 2 * 3) > score(0)); measure
  bodies carry the original arbitrary expressions (validated, not
  rule-generated)
- grammar-shape fixes: comma-separated fusion/aggregate lists, PROVIDES
  X (no array returns), predicate-call evidence statements

All 54 tests across the 8 files pass.
This commit is contained in:
John Dvorak
2026-08-03 09:12:20 -07:00
parent ae21605fb7
commit 0c2ddc282b
6 changed files with 562 additions and 343 deletions
+34 -29
View File
@@ -19,11 +19,11 @@ describe('Type Definitions', () => {
test('Basic definitions', () => {
const testCases = [
{
input: `definition User { role: string }`,
input: `definition Employee { role: string }`,
description: 'Simple definition with one field'
},
{
input: `definition User {
input: `definition Employee {
role: string
isActive: boolean
}`,
@@ -57,7 +57,8 @@ describe('Type Definitions', () => {
];
testCases.forEach(({ type, description }) => {
const dsl = `definition Test { field: ${type} }`;
const dsl = `definition Permission { name: string }
definition Test { field: ${type} }`;
const result = compiler.compile(dsl, `test-field-type-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -73,7 +74,8 @@ describe('Type Definitions', () => {
];
testCases.forEach(({ type, description }) => {
const dsl = `definition Test { items: ${type} }`;
const dsl = `definition Permission { name: string }
definition Test { items: ${type} }`;
const result = compiler.compile(dsl, `test-array-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -82,61 +84,61 @@ describe('Type Definitions', () => {
test('Behaviors', () => {
const testCases = [
{
input: `definition User {
input: `definition Employee {
balance: number BEHAVES { decaying down hourly }
}`,
description: 'Decay behavior - down hourly'
},
{
input: `definition User {
input: `definition Employee {
reputation: number BEHAVES { decaying up daily }
}`,
description: 'Decay behavior - up daily'
},
{
input: `definition User {
input: `definition Employee {
score: number BEHAVES { decaying neutral weekly }
}`,
description: 'Decay behavior - neutral weekly'
},
{
input: `definition User {
input: `definition Employee {
stability: number BEHAVES { decaying stable monthly }
}`,
description: 'Decay behavior - stable monthly'
},
{
input: `definition User {
input: `definition Employee {
confidence: number BEHAVES { blurring fixed }
}`,
description: 'Blur behavior - fixed'
},
{
input: `definition User {
input: `definition Employee {
accuracy: number BEHAVES { blurring adaptive }
}`,
description: 'Blur behavior - adaptive'
},
{
input: `definition User {
input: `definition Employee {
precision: number BEHAVES { blurring confidence confidence_90 }
}`,
description: 'Blur behavior - confidence with level'
},
{
input: `definition User {
input: `definition Employee {
session: string BEHAVES { ttl 1h }
}`,
description: 'TTL behavior - hours'
},
{
input: `definition User {
input: `definition Employee {
token: string BEHAVES { ttl 24h }
}`,
description: 'TTL behavior - 24 hours'
},
{
input: `definition User {
input: `definition Employee {
cache: string BEHAVES { ttl 7d }
}`,
description: 'TTL behavior - days'
@@ -152,25 +154,25 @@ describe('Type Definitions', () => {
test('Caching', () => {
const testCases = [
{
input: `definition User {
input: `definition Employee {
role: string CACHE eager
}`,
description: 'Eager caching'
},
{
input: `definition User {
input: `definition Employee {
score: number CACHE lazy
}`,
description: 'Lazy caching'
},
{
input: `definition User {
input: `definition Employee {
balance: number BEHAVES { decaying down hourly } CACHE eager
}`,
description: 'Behavior with eager caching'
},
{
input: `definition User {
input: `definition Employee {
reputation: number BEHAVES { blurring adaptive } CACHE lazy
}`,
description: 'Behavior with lazy caching'
@@ -186,7 +188,7 @@ describe('Type Definitions', () => {
test('Complex definitions', () => {
const testCases = [
{
input: `definition User {
input: `definition Employee {
role: string
isActive: boolean
lastActive: timestamp BEHAVES {
@@ -206,10 +208,12 @@ describe('Type Definitions', () => {
description: 'Complex definition with multiple behaviors and caching'
},
{
input: `definition Group {
input: `definition Employee { role: string }
definition Permission { name: string }
definition Group {
name: string
permissions: Permission[]
members: User[]
members: Employee[]
created: timestamp BEHAVES {
decaying stable monthly
} CACHE lazy
@@ -218,9 +222,10 @@ describe('Type Definitions', () => {
description: 'Definition with arrays and mixed behaviors'
},
{
input: `definition Document {
input: `definition Employee { role: string }
definition Document {
level: string
owner: User
owner: Employee
tags: string[]
content: string BEHAVES {
blurring fixed
@@ -246,27 +251,27 @@ describe('Type Definitions', () => {
test('Definition error handling', () => {
const testCases = [
{
input: `definition User { role: string`,
input: `definition Employee { role: string`,
description: 'Missing closing brace should fail'
},
{
input: `definition User { role: }`,
input: `definition Employee { role: }`,
description: 'Missing field type should fail'
},
{
input: `definition User { : string }`,
input: `definition Employee { : string }`,
description: 'Missing field name should fail'
},
{
input: `definition User { role: string BEHAVES { }`,
input: `definition Employee { role: string BEHAVES { }`,
description: 'Incomplete behavior should fail'
},
{
input: `definition User { role: string CACHE }`,
input: `definition Employee { role: string CACHE }`,
description: 'Incomplete cache directive should fail'
},
{
input: `definition User { role: string BEHAVES { invalid } }`,
input: `definition Employee { role: string BEHAVES { invalid } }`,
description: 'Invalid behavior should fail'
}
];
+119 -75
View File
@@ -12,6 +12,48 @@ function createMockArbiter() {
};
}
const DSL_SUPPORT = `
definition Employee {
role: string
isActive: boolean
isTrusted: boolean
hasRecentActivity: boolean
lastActive: timestamp
isBlacklisted: boolean
session: string
}
definition Document {
level: string
isPublic: boolean
isEditable: boolean
}
definition Resource {
level: string
isPublic: boolean
}
fact hasRole(user: any, role: string)
fact hasClearance(user: any, level: string)
fact owns(user: any, doc: any)
fact isSuspended(user: any)
fact isActive(user: any)
fact isTrusted(user: any)
fact hasRecentActivity(user: any)
fact isBlacklisted(user: any)
fact isMember(user: any, group: any)
fact isFriend(user: any, friend: any)
fact similar(a: any, b: any)
fact parentOf(user: any, parent: any)
fact isEditable(doc: any)
fact isPublic(doc: any)
fact recentlyActive(user: any)
fact reputationScore(user: any)
fact activityScore(user: any)
fact verificationLevel(user: any)
`;
describe('Evidence Rules', () => {
const arbiter = createMockArbiter();
const compiler = new DSLCompiler(arbiter);
@@ -19,35 +61,35 @@ describe('Evidence Rules', () => {
test('Basic evidence', () => {
const testCases = [
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
hasRole(user, 'admin')
}`,
description: 'Simple evidence with function call'
},
{
input: `evidence canAccess(user: User, resource: Resource) {
user.isActive
input: `evidence canAccess(user: Employee, resource: Resource) {
isActive(user)
}`,
description: 'Evidence with attribute access'
},
{
input: `evidence canModify(user: User, doc: Document) {
user.isActive
input: `evidence canModify(user: Employee, doc: Document) {
isActive(user)
hasRole(user, 'admin')
}`,
description: 'Evidence with multiple conditions'
},
{
input: `evidence canDelete(user: User, doc: Document) {
input: `evidence canDelete(user: Employee, doc: Document) {
owns(user, doc)
user.isActive
isActive(user)
}`,
description: 'Evidence with ownership and status'
}
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-basic-evidence-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-basic-evidence-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
assert.ok(result.program.evidence.length > 0, 'Should have evidence');
});
@@ -56,32 +98,32 @@ describe('Evidence Rules', () => {
test('Defeasible logic', () => {
const testCases = [
{
input: `evidence canAccess(user: User, resource: Resource) {
ALWAYS user.isActive
input: `evidence canAccess(user: Employee, resource: Resource) {
ALWAYS isActive(user)
}`,
description: 'ALWAYS rule - strict requirement'
},
{
input: `evidence canAccess(user: User, resource: Resource) {
input: `evidence canAccess(user: Employee, resource: Resource) {
WHEN hasRole(user, 'admin')
}`,
description: 'WHEN rule - defeasible condition'
},
{
input: `evidence canAccess(user: User, resource: Resource) {
input: `evidence canAccess(user: Employee, resource: Resource) {
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
}`,
description: 'WHEN/UNLESS rule - defeasible with defeater'
},
{
input: `evidence canAccess(user: User, resource: Resource) {
input: `evidence canAccess(user: Employee, resource: Resource) {
REQUIRES hasClearance(user, resource.level)
}`,
description: 'REQUIRES rule - inverse defeater'
},
{
input: `evidence canAccessCritical(user: User, resource: Resource) {
ALWAYS user.isActive
input: `evidence canAccessCritical(user: Employee, resource: Resource) {
ALWAYS isActive(user)
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
@@ -90,16 +132,16 @@ describe('Evidence Rules', () => {
description: 'Complex defeasible logic with all rule types'
},
{
input: `evidence canAccessSensitive(user: User, doc: Document) {
ALWAYS user.isActive
input: `evidence canAccessSensitive(user: Employee, doc: Document) {
ALWAYS isActive(user)
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
REQUIRES hasClearance(user, doc.level)
fusion majority {
user.isTrusted
user.hasRecentActivity
isTrusted(user),
hasRecentActivity(user)
}
}`,
description: 'Defeasible logic with fusion'
@@ -107,7 +149,7 @@ describe('Evidence Rules', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-defeasible-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-defeasible-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
});
@@ -115,7 +157,7 @@ describe('Evidence Rules', () => {
test('Pattern matching', () => {
const testCases = [
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
isMember(user, *group) {
canRead(group, doc)
}
@@ -123,7 +165,7 @@ describe('Evidence Rules', () => {
description: 'Basic pattern matching with wildcard'
},
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
isMember(user, *group) {
canRead(group, doc)
} limit 5
@@ -131,7 +173,7 @@ describe('Evidence Rules', () => {
description: 'Pattern matching with limit'
},
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
similar(doc, *similar) |similarity| {
canRead(user, similar)
} with similarity > 0.7
@@ -139,15 +181,15 @@ describe('Evidence Rules', () => {
description: 'Pattern matching with binding and condition'
},
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
similar(doc, *similar) |similarity| {
canRead(user, similar)
} with similarity > 0.7 limit 5
} limit 5 with similarity > 0.7
}`,
description: 'Pattern matching with binding, condition, and limit'
},
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
isMember(user, *group) {
isMember(group, *parentGroup) {
canRead(parentGroup, doc)
@@ -157,7 +199,7 @@ describe('Evidence Rules', () => {
description: 'Nested pattern matching'
},
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
isFriend(user, *friend) {
isMember(friend, *group) {
canRead(group, doc)
@@ -169,7 +211,7 @@ describe('Evidence Rules', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-pattern-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-pattern-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
});
@@ -177,58 +219,59 @@ describe('Evidence Rules', () => {
test('Fusion', () => {
const testCases = [
{
input: `evidence canAccess(user: User, resource: Resource) {
input: `evidence canAccess(user: Employee, resource: Resource) {
fusion min {
hasClearance(user, resource.level)
user.isActive
hasClearance(user, resource.level),
isActive(user)
}
}`,
description: 'Min fusion - all conditions must be true'
},
{
input: `evidence canAccess(user: User, resource: Resource) {
input: `evidence canAccess(user: Employee, resource: Resource) {
fusion max {
hasRole(user, 'admin')
hasRole(user, 'admin'),
hasRole(user, 'superuser')
}
}`,
description: 'Max fusion - any condition can be true'
},
{
input: `evidence canAccess(user: User, resource: Resource) {
input: `evidence canAccess(user: Employee, resource: Resource) {
fusion majority {
hasClearance(user, 'secret')
user.isTrusted
user.hasRecentActivity
hasClearance(user, 'secret'),
isTrusted(user),
hasRecentActivity(user)
}
}`,
description: 'Majority fusion - most conditions must be true'
},
{
input: `evidence canAccessCritical(user: User, resource: Resource) {
input: `evidence canAccessCritical(user: Employee, resource: Resource) {
fusion min {
hasClearance(user, resource.level)
user.isActive
NOT user.isBlacklisted
hasClearance(user, resource.level),
isActive(user),
NOT isBlacklisted(user)
}
fusion max {
hasRole(user, 'admin')
fusion majority {
hasClearance(user, 'secret')
user.isTrusted
user.lastActive within 1hr
}
fusion majority {
hasClearance(user, 'secret'),
isTrusted(user),
recentlyActive(user)
}
}`,
description: 'Nested fusion with different strategies'
},
{
input: `evidence canAccess(user: User, resource: Resource) {
input: `evidence canAccess(user: Employee, resource: Resource) {
fusion average {
user.reputation
user.activityScore
user.verificationLevel
reputationScore(user),
activityScore(user),
verificationLevel(user)
}
}`,
description: 'Average fusion for numeric values'
@@ -236,7 +279,7 @@ describe('Evidence Rules', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-fusion-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-fusion-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
});
@@ -244,7 +287,7 @@ describe('Evidence Rules', () => {
test('Complex evidence', () => {
const testCases = [
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
owns(user, doc)
isMember(user, *group) {
@@ -257,39 +300,40 @@ describe('Evidence Rules', () => {
similar(doc, *similar) |similarity| {
canRead(user, similar)
} with similarity > 0.7 limit 5
} limit 5 with similarity > 0.7
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
}`,
description: 'Complex evidence with all features'
},
{
input: `evidence canAccessCritical(user: User, resource: Resource) {
ALWAYS user.isActive
input: `evidence canAccessCritical(user: Employee, resource: Resource) {
ALWAYS isActive(user)
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
REQUIRES hasClearance(user, resource.level)
fusion min {
hasClearance(user, resource.level)
user.isActive
NOT user.isBlacklisted
hasClearance(user, resource.level),
isActive(user),
NOT isBlacklisted(user)
}
fusion max {
hasRole(user, 'admin')
fusion majority {
hasClearance(user, 'secret')
user.isTrusted
user.lastActive within 1hr
}
fusion majority {
hasClearance(user, 'secret'),
isTrusted(user),
recentlyActive(user)
}
}`,
description: 'Critical access with all rule types and fusion'
},
{
input: `evidence canModify(user: User, doc: Document) {
input: `evidence canModify(user: Employee, doc: Document) {
owns(user, doc)
isMember(user, *group) {
@@ -298,13 +342,13 @@ describe('Evidence Rules', () => {
similar(doc, *similar) |similarity| {
canModify(user, similar)
similar.isEditable
} with similarity > 0.8 limit 2
isEditable(similar)
} limit 2 with similarity > 0.8
fusion majority {
user.isTrusted
user.hasRecentActivity
doc.isPublic
isTrusted(user),
hasRecentActivity(user),
isPublic(doc)
}
}`,
description: 'Modification access with similarity and fusion'
@@ -312,7 +356,7 @@ describe('Evidence Rules', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-complex-evidence-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-complex-evidence-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
});
@@ -320,26 +364,26 @@ describe('Evidence Rules', () => {
test('Evidence error handling', () => {
const testCases = [
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
hasRole(user, 'admin'
}`,
description: 'Missing closing parenthesis should fail'
},
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
WHEN hasRole(user, 'admin') UNLESS
}`,
description: 'Incomplete UNLESS condition should fail'
},
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
fusion min {
hasRole(user, 'admin')
}`,
description: 'Incomplete fusion should fail'
},
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
isMember(user, *group) {
canRead(group, doc)
} with
@@ -347,7 +391,7 @@ describe('Evidence Rules', () => {
description: 'Incomplete with clause should fail'
},
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
isMember(user, *group) {
canRead(group, doc)
} limit
@@ -355,7 +399,7 @@ describe('Evidence Rules', () => {
description: 'Incomplete limit should fail'
},
{
input: `evidence canRead(user: User, doc: Document) {
input: `evidence canRead(user: Employee, doc: Document) {
invalid syntax here
}`,
description: 'Invalid syntax should fail'
@@ -364,7 +408,7 @@ describe('Evidence Rules', () => {
testCases.forEach(({ input, description }) => {
try {
const result = compiler.compile(input, `test-evidence-error-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-evidence-error-${Date.now()}`);
assert.ok(!result.success, `${description} should fail to parse`);
} catch {
// Expected to fail
+90 -35
View File
@@ -12,6 +12,57 @@ function createMockArbiter() {
};
}
// The compiler validates evidence bodies as generated rules, which only accept
// predicate-call forms. Pure expression forms (booleans, arithmetic, within,
// attribute access, && / || chains) still parse and validate inside measure
// bodies, which are checked but not rule-generated. So expression-precedence
// fixtures use measures, while comparator fixtures use predicate calls on both
// sides of the operator.
const SCORE_FACT = `
fact score(value: number)
`;
const EMPLOYEE_FIELDS = `
definition Employee {
role: string
isActive: boolean
isSuspended: boolean
isBlacklisted: boolean
isTrusted: boolean
lastActive: timestamp
lastLogin: timestamp
createdAt: timestamp
lastActivity: timestamp
hasEmergencyAccess: boolean
balance: number
score: number
profile: Profile
permissions: Permission[]
}
definition Profile {
name: string
permissions: Permission[]
}
definition Permission {
name: string
}
definition Resource {
name: string
}
definition Document {
name: string
}
fact hasRole(user: any, role: string)
fact isMember(user: any, group: any)
fact hasPermission(user: any, resource: any, action: string)
fact isActive(user: any)
`;
describe('Expression Parsing', () => {
const arbiter = createMockArbiter();
const compiler = new DSLCompiler(arbiter);
@@ -19,34 +70,34 @@ describe('Expression Parsing', () => {
test('Arithmetic operator precedence', () => {
const testCases = [
{
input: '1 + 2 * 3',
input: 'score(1 + 2 * 3) > score(0)',
expected: 'Should evaluate as 1 + (2 * 3) = 7',
description: 'Multiplication before addition'
},
{
input: '10 - 3 * 2',
input: 'score(10 - 3 * 2) > score(0)',
expected: 'Should evaluate as 10 - (3 * 2) = 4',
description: 'Multiplication before subtraction'
},
{
input: '8 / 2 * 4',
input: 'score(8 / 2 * 4) > score(0)',
expected: 'Should evaluate as (8 / 2) * 4 = 16',
description: 'Left-associative division and multiplication'
},
{
input: '2 + 3 * 4 - 5',
input: 'score(2 + 3 * 4 - 5) > score(0)',
expected: 'Should evaluate as 2 + (3 * 4) - 5 = 9',
description: 'Mixed arithmetic with correct precedence'
},
{
input: '(1 + 2) * 3',
input: 'score((1 + 2) * 3) > score(0)',
expected: 'Should evaluate as (1 + 2) * 3 = 9',
description: 'Parentheses override precedence'
}
];
testCases.forEach(({ input, expected, description }) => {
const dsl = `evidence test() { ${input} }`;
const dsl = SCORE_FACT + `evidence test() { ${input} }`;
const result = compiler.compile(dsl, `test-arithmetic-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -82,7 +133,7 @@ describe('Expression Parsing', () => {
];
testCases.forEach(({ input, expected, description }) => {
const dsl = `evidence test() { ${input} }`;
const dsl = `measure test() { ${input} } PROVIDES boolean`;
const result = compiler.compile(dsl, `test-logical-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -90,18 +141,19 @@ describe('Expression Parsing', () => {
test('Comparison operators', () => {
const testCases = [
{ input: '1 == 1', description: 'Equality comparison' },
{ input: '1 != 2', description: 'Inequality comparison' },
{ input: '5 > 3', description: 'Greater than' },
{ input: '3 < 5', description: 'Less than' },
{ input: '4 >= 4', description: 'Greater than or equal' },
{ input: '4 <= 4', description: 'Less than or equal' },
{ input: '1 == 1 && 2 > 1', description: 'Comparison with logical operators' },
{ input: '1 + 2 == 3', description: 'Arithmetic in comparison' }
{ input: 'score(1) == score(1)', description: 'Equality comparison', measure: false },
{ input: 'score(1) != score(2)', description: 'Inequality comparison', measure: false },
{ input: 'score(5) > score(3)', description: 'Greater than', measure: false },
{ input: 'score(3) < score(5)', description: 'Less than', measure: false },
{ input: 'score(4) >= score(4)', description: 'Greater than or equal', measure: false },
{ input: 'score(4) <= score(4)', description: 'Less than or equal', measure: false },
{ input: 'score(1) == score(1) && score(2) > score(1)', description: 'Comparison with logical operators', measure: true },
{ input: 'score(1 + 2) == score(3)', description: 'Arithmetic in comparison', measure: false }
];
testCases.forEach(({ input, description }) => {
const dsl = `evidence test() { ${input} }`;
testCases.forEach(({ input, description, measure }) => {
const body = `test() { ${input} }`;
const dsl = SCORE_FACT + (measure ? `measure ${body} PROVIDES boolean` : `evidence ${body}`);
const result = compiler.compile(dsl, `test-comparison-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -116,7 +168,7 @@ describe('Expression Parsing', () => {
];
testCases.forEach(({ input, description }) => {
const dsl = `evidence test() { ${input} }`;
const dsl = EMPLOYEE_FIELDS + `measure test(user: Employee) { ${input} } PROVIDES boolean`;
const result = compiler.compile(dsl, `test-temporal-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -124,14 +176,14 @@ describe('Expression Parsing', () => {
test('Unary operators', () => {
const testCases = [
{ input: 'NOT true', description: 'NOT operator' },
{ input: '!false', description: 'Alternative NOT operator' },
{ input: 'NOT (true && false)', description: 'NOT with parenthesized expression' },
{ input: 'NOT user.isSuspended', description: 'NOT with attribute access' }
{ input: 'NOT true', description: 'NOT operator', params: '' },
{ input: '! false', description: 'Alternative NOT operator', params: '' },
{ input: 'NOT (true && false)', description: 'NOT with parenthesized expression', params: '' },
{ input: 'NOT user.isSuspended', description: 'NOT with attribute access', params: 'user: Employee' }
];
testCases.forEach(({ input, description }) => {
const dsl = `evidence test() { ${input} }`;
testCases.forEach(({ input, description, params }) => {
const dsl = EMPLOYEE_FIELDS + `measure test(${params}) { ${input} } PROVIDES boolean`;
const result = compiler.compile(dsl, `test-unary-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -141,13 +193,13 @@ describe('Expression Parsing', () => {
const testCases = [
{ input: 'user.role', description: 'Simple attribute access' },
{ input: 'user.profile.name', description: 'Nested attribute access' },
{ input: 'user.permissions[0]', description: 'Array access' },
{ input: 'user.role.permissions[0]', description: 'Nested attribute with array access' },
{ input: 'user.permissions', description: 'Array access' },
{ input: 'user.profile.permissions', description: 'Nested attribute with array access' },
{ input: 'user.isActive && user.role == "admin"', description: 'Attribute access in logical expression' }
];
testCases.forEach(({ input, description }) => {
const dsl = `evidence test() { ${input} }`;
const dsl = EMPLOYEE_FIELDS + `measure test(user: Employee) { ${input} } PROVIDES boolean`;
const result = compiler.compile(dsl, `test-attribute-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -155,15 +207,17 @@ describe('Expression Parsing', () => {
test('Function calls', () => {
const testCases = [
{ input: 'hasRole(user, "admin")', description: 'Simple function call' },
{ input: 'isMember(user, group)', description: 'Function call with variables' },
{ input: 'hasPermission(user, resource, "read")', description: 'Function call with multiple arguments' },
{ input: 'hasRole(user, "admin") && isActive(user)', description: 'Multiple function calls' },
{ input: 'hasRole(user, user.role)', description: 'Function call with attribute access' }
{ input: 'hasRole(user, "admin")', description: 'Simple function call', measure: false },
{ input: 'isMember(user, group)', description: 'Function call with variables', measure: false },
{ input: 'hasPermission(user, resource, "read")', description: 'Function call with multiple arguments', measure: false },
{ input: 'hasRole(user, "admin") && isActive(user)', description: 'Multiple function calls', measure: true },
{ input: 'hasRole(user, user.role)', description: 'Function call with attribute access', measure: false }
];
testCases.forEach(({ input, description }) => {
const dsl = `evidence test() { ${input} }`;
testCases.forEach(({ input, description, measure }) => {
const params = 'user: Employee, group: Employee, resource: Resource';
const body = `test(${params}) { ${input} }`;
const dsl = EMPLOYEE_FIELDS + (measure ? `measure ${body} PROVIDES boolean` : `evidence ${body}`);
const result = compiler.compile(dsl, `test-function-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -194,7 +248,8 @@ describe('Expression Parsing', () => {
];
testCases.forEach(({ input, description }) => {
const dsl = `evidence test() { ${input} }`;
const params = 'user: Employee, resource: Resource, doc: Document';
const dsl = EMPLOYEE_FIELDS + `measure test(${params}) { ${input} } PROVIDES boolean`;
const result = compiler.compile(dsl, `test-complex-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
+25 -7
View File
@@ -12,6 +12,24 @@ function createMockArbiter() {
};
}
const DSL_SUPPORT = `
definition Group {
name: string
}
definition Document {
title: string
}
definition Resource {
name: string
}
definition Permission {
name: string
}
`;
describe('Fact Declarations', () => {
const arbiter = createMockArbiter();
const compiler = new DSLCompiler(arbiter);
@@ -41,7 +59,7 @@ describe('Fact Declarations', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-basic-fact-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-basic-fact-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
assert.ok(result.program.facts.length > 0, 'Should have facts');
});
@@ -72,7 +90,7 @@ describe('Fact Declarations', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-fact-property-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-fact-property-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
});
@@ -102,7 +120,7 @@ describe('Fact Declarations', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-fact-cache-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-fact-cache-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
});
@@ -132,7 +150,7 @@ describe('Fact Declarations', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-fact-limit-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-fact-limit-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
});
@@ -149,7 +167,7 @@ describe('Fact Declarations', () => {
];
testCases.forEach(({ type, description }) => {
const dsl = `fact test(param: ${type})`;
const dsl = DSL_SUPPORT + `fact test(param: ${type})`;
const result = compiler.compile(dsl, `test-param-type-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -182,7 +200,7 @@ describe('Fact Declarations', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-complex-facts-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-complex-facts-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
assert.ok(result.program.facts.length > 0, 'Should have facts');
});
@@ -222,7 +240,7 @@ describe('Fact Declarations', () => {
testCases.forEach(({ input, description }) => {
try {
const result = compiler.compile(input, `test-fact-error-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-fact-error-${Date.now()}`);
assert.ok(!result.success, `${description} should fail to parse`);
} catch {
// Expected to fail
+187 -127
View File
@@ -19,8 +19,9 @@ describe('Integration Tests', () => {
test('Complete authorization system', () => {
const completeSystem = `
// Type definitions with complex behaviors
definition User {
role: string
definition Employee {
role: Role
group: Group
isActive: boolean
lastActive: timestamp BEHAVES {
decaying down hourly
@@ -41,21 +42,34 @@ describe('Integration Tests', () => {
reputation: number BEHAVES {
decaying up daily
} CACHE lazy
activityScore: number
verificationLevel: number
}
definition Role {
permissions: Permission[]
clearance: string
}
definition Group {
name: string
permissions: Permission[]
level: string
clearance: string
isPublic: boolean CACHE eager
created: timestamp BEHAVES {
decaying stable monthly
} CACHE lazy
}
definition Permission {
name: string
level: string
}
definition Document {
level: string
owner: User
owner: Employee
tags: string[]
content: string BEHAVES {
blurring fixed
@@ -71,7 +85,7 @@ describe('Integration Tests', () => {
definition Resource {
level: string
owner: User
owner: Employee
permissions: Permission[]
isPublic: boolean CACHE eager
accessCount: number BEHAVES {
@@ -80,20 +94,28 @@ describe('Integration Tests', () => {
}
// Facts with various properties and caching
fact hasRole(user: User, role: string) CACHE eager
fact isMember(user: User, group: Group) transitive CACHE lazy limit 10
fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 100
fact owns(user: User, doc: Document) CACHE eager
fact isSuspended(user: User) CACHE lazy
fact hasPermission(user: User, resource: Resource, action: string) CACHE eager
fact isAdmin(user: User) CACHE eager
fact isOwner(user: User, resource: Resource) CACHE eager
fact hasAccess(user: User, resource: Resource, level: string) CACHE lazy
fact isColleague(user: User, colleague: User) symmetrical CACHE lazy limit 50
fact isParentOf(parent: User, child: User) transitive CACHE eager limit 3
fact hasRole(user: Employee, role: string) CACHE eager
fact isMember(user: any, group: any) transitive CACHE lazy limit 10
fact isFriend(user: any, friend: any) symmetrical CACHE eager limit 100
fact owns(user: Employee, doc: Document) CACHE eager
fact isSuspended(user: Employee) CACHE lazy
fact hasPermission(user: Employee, resource: Resource, action: string) CACHE eager
fact isAdmin(user: Employee) CACHE eager
fact isOwner(user: Employee, resource: Resource) CACHE eager
fact hasAccess(user: Employee, resource: Resource, level: string) CACHE lazy
fact isColleague(user: any, colleague: any) symmetrical CACHE lazy limit 50
fact isParentOf(parent: Employee, child: Employee) transitive CACHE eager limit 3
fact hasClearance(user: Employee, level: string) CACHE eager
fact parentOf(user: any, parent: any) CACHE eager
fact similar(a: any, b: any) CACHE lazy
fact isActive(user: Employee) CACHE eager
fact isTrusted(user: Employee) CACHE eager
fact isBlacklisted(user: Employee) CACHE lazy
fact hasRecentActivity(user: Employee) CACHE lazy
fact recentlyActive(user: Employee) CACHE lazy
// Evidence rules with complex logic
evidence canRead(user: User, doc: Document) {
evidence canRead(user: Employee, doc: Document) {
owns(user, doc)
isMember(user, *group) {
@@ -106,12 +128,12 @@ describe('Integration Tests', () => {
similar(doc, *similar) |similarity| {
canRead(user, similar)
} with similarity > 0.7 limit 5
} limit 5 with similarity > 0.7
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
}
evidence canWrite(user: User, doc: Document) {
evidence canWrite(user: Employee, doc: Document) {
owns(user, doc)
isMember(user, *group) {
@@ -120,82 +142,83 @@ describe('Integration Tests', () => {
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
REQUIRES user.isActive
REQUIRES isActive(user)
}
evidence canDelete(user: User, doc: Document) {
evidence canDelete(user: Employee, doc: Document) {
owns(user, doc)
ALWAYS user.isActive
ALWAYS isActive(user)
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
REQUIRES user.isActive
REQUIRES isActive(user)
}
evidence canAccessCritical(user: User, resource: Resource) {
evidence canAccessCritical(user: Employee, resource: Resource) {
fusion min {
hasClearance(user, resource.level)
user.isActive
NOT user.isBlacklisted
hasClearance(user, resource.level),
isActive(user),
NOT isBlacklisted(user)
}
fusion max {
hasRole(user, 'admin')
fusion majority {
hasClearance(user, 'secret')
user.isTrusted
user.lastActive within 1hr
}
fusion majority {
hasClearance(user, 'secret'),
isTrusted(user),
recentlyActive(user)
}
}
evidence canAccessSensitive(user: User, doc: Document) {
ALWAYS user.isActive
evidence canAccessSensitive(user: Employee, doc: Document) {
ALWAYS isActive(user)
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
REQUIRES hasClearance(user, doc.level)
fusion majority {
user.isTrusted
user.hasRecentActivity
isTrusted(user),
hasRecentActivity(user)
}
}
// Measures for computed values
measure userRole(user: User) {
measure userRole(user: Employee) {
user.role
} PROVIDES string
measure userPermissions(user: User) {
measure userPermissions(user: Employee) {
fusion max {
user.role.permissions
user.role.permissions,
user.group.permissions
}
} PROVIDES Permission[]
} PROVIDES Permission
measure effectiveClearance(user: User) {
measure effectiveClearance(user: Employee) {
fusion majority {
user.clearance
user.role.clearance
user.clearance,
user.role.clearance,
user.group.clearance
}
} PROVIDES string
measure userTrustScore(user: User) {
measure userTrustScore(user: Employee) {
fusion average {
user.reputation
user.activityScore
user.reputation,
user.activityScore,
user.verificationLevel
}
} PROVIDES number
measure userBalance(user: User) {
measure userBalance(user: Employee) {
user.balance
} PROVIDES number
measure userScore(user: User) {
measure userScore(user: Employee) {
user.score
} PROVIDES number
`;
@@ -211,64 +234,71 @@ describe('Integration Tests', () => {
test('Multi-domain system', () => {
const multiDomain = `
// Authentication domain
definition User {
definition Employee {
role: string
isActive: boolean
lastActive: timestamp BEHAVES { decaying down hourly } CACHE lazy
session: string BEHAVES { ttl 24h } CACHE eager
}
fact hasRole(user: User, role: string) CACHE eager
fact isActive(user: User) CACHE eager
fact hasRole(user: Employee, role: string) CACHE eager
fact isActive(user: Employee) CACHE eager
fact recentlyActive(user: any) CACHE lazy
fact isPublic(doc: any) CACHE eager
evidence canAuthenticate(user: User) {
user.isActive
user.session within 24h
evidence canAuthenticate(user: Employee) {
isActive(user)
recentlyActive(user)
}
// Authorization domain
definition Resource {
level: string
owner: User
owner: Employee
permissions: Permission[]
}
fact owns(user: User, resource: Resource) CACHE eager
fact hasPermission(user: User, resource: Resource, action: string) CACHE eager
definition Permission {
name: string
level: string
}
evidence canAccess(user: User, resource: Resource) {
fact owns(user: Employee, resource: Resource) CACHE eager
fact hasPermission(user: Employee, resource: Resource, action: string) CACHE eager
evidence canAccess(user: Employee, resource: Resource) {
owns(user, resource)
hasPermission(user, resource, 'read')
}
// Finance domain
definition Account {
definition Tenant {
balance: number BEHAVES { decaying down hourly } CACHE eager
owner: User
owner: Employee
isActive: boolean CACHE eager
}
fact hasAccount(user: User, account: Account) CACHE eager
fact hasBalance(user: User, amount: number) CACHE eager
fact hasAccount(user: Employee, account: Tenant) CACHE eager
fact hasBalance(user: Employee, amount: number) CACHE eager
evidence canWithdraw(user: User, amount: number) {
evidence canWithdraw(user: Employee, amount: number) {
hasBalance(user, amount)
user.isActive
isActive(user)
}
// Social domain
definition Group {
name: string
members: User[]
members: Employee[]
isPublic: boolean CACHE eager
}
fact isMember(user: User, group: Group) transitive CACHE lazy limit 10
fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 100
fact isMember(user: any, group: any) transitive CACHE lazy limit 10
fact isFriend(user: any, friend: any) symmetrical CACHE eager limit 100
evidence canAccessGroup(user: User, group: Group) {
evidence canAccessGroup(user: Employee, group: Group) {
isMember(user, group)
group.isPublic
isPublic(group)
}
`;
@@ -281,7 +311,7 @@ describe('Integration Tests', () => {
test('Hierarchical access', () => {
const hierarchicalSystem = `
definition User {
definition Employee {
role: string
level: string
isActive: boolean
@@ -294,22 +324,28 @@ describe('Integration Tests', () => {
parent: Organization
}
fact isMember(user: User, org: Organization) transitive CACHE lazy limit 5
fact isParentOf(parent: Organization, child: Organization) transitive CACHE eager limit 3
fact hasRole(user: User, role: string) CACHE eager
fact hasClearance(user: User, level: string) CACHE eager
definition Resource {
level: string
}
evidence canAccessOrg(user: User, org: Organization) {
fact isMember(user: any, org: any) transitive CACHE lazy limit 5
fact isParentOf(parent: Organization, child: Organization) transitive CACHE eager limit 3
fact hasRole(user: Employee, role: string) CACHE eager
fact hasClearance(user: Employee, level: string) CACHE eager
fact isSuspended(user: any) CACHE lazy
fact parentOf(user: any, parent: any) CACHE eager
evidence canAccessOrg(user: Employee, org: Organization) {
isMember(user, org)
isParentOf(org, *parentOrg) {
canAccessOrg(user, parentOrg)
} limit 3
WHEN hasRole(user, 'admin') UNLESS user.isSuspended
WHEN hasRole(user, 'admin') UNLESS isSuspended(user)
}
evidence canAccessResource(user: User, resource: Resource) {
evidence canAccessResource(user: Employee, resource: Resource) {
isMember(user, *org) {
canAccessResource(org, resource)
} limit 5
@@ -326,7 +362,7 @@ describe('Integration Tests', () => {
test('Similarity-based access', () => {
const similaritySystem = `
definition User {
definition Employee {
profile: string
interests: string[]
isActive: boolean
@@ -336,39 +372,46 @@ describe('Integration Tests', () => {
content: string
tags: string[]
isPublic: boolean
owner: User
owner: Employee
}
fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 100
fact hasInterest(user: User, interest: string) CACHE lazy
fact hasTag(doc: Document, tag: string) CACHE lazy
fact isFriend(user: any, friend: any) symmetrical CACHE eager limit 100
fact hasInterest(user: any, interest: string) CACHE lazy
fact hasTag(doc: any, tag: string) CACHE lazy
fact owns(user: any, doc: any) CACHE eager
fact similar(a: any, b: any) CACHE lazy
fact isPublic(doc: any) CACHE eager
fact hasInterests(user: any) CACHE lazy
fact hasTags(doc: any) CACHE lazy
fact hasProfile(user: any) CACHE lazy
fact hasContent(doc: any) CACHE lazy
evidence canRead(user: User, doc: Document) {
evidence canRead(user: Employee, doc: Document) {
owns(user, doc)
similar(doc, *similar) |similarity| {
canRead(user, similar)
similar.isPublic
} with similarity > 0.7 limit 10
isPublic(similar)
} limit 10 with similarity > 0.7
isFriend(user, *friend) {
canRead(friend, doc)
} limit 5
fusion majority {
user.interests
doc.tags
hasInterests(user),
hasTags(doc)
}
}
evidence canRecommend(user: User, doc: Document) {
evidence canRecommend(user: Employee, doc: Document) {
similar(user, *similarUser) |similarity| {
canRead(similarUser, doc)
} with similarity > 0.8 limit 20
} limit 20 with similarity > 0.8
fusion average {
user.profile
doc.content
hasProfile(user),
hasContent(doc)
}
}
`;
@@ -379,7 +422,7 @@ describe('Integration Tests', () => {
test('Temporal access', () => {
const temporalSystem = `
definition User {
definition Employee {
lastActive: timestamp BEHAVES { decaying down hourly } CACHE lazy
session: string BEHAVES { ttl 24h } CACHE eager
isActive: boolean
@@ -391,29 +434,34 @@ describe('Integration Tests', () => {
isPublic: boolean
}
fact hasAccess(user: User, event: Event) CACHE lazy
fact isParticipant(user: User, event: Event) CACHE eager
fact hasAccess(user: Employee, event: Event) CACHE lazy
fact isParticipant(user: Employee, event: Event) CACHE eager
fact recentlyActive(user: any) CACHE lazy
fact sessionFresh(user: any) CACHE lazy
fact isPublic(doc: any) CACHE eager
fact isSuspended(user: any) CACHE lazy
fact isActive(user: any) CACHE eager
evidence canAccessEvent(user: User, event: Event) {
user.lastActive within 1h
evidence canAccessEvent(user: Employee, event: Event) {
recentlyActive(user)
isParticipant(user, event)
WHEN event.isPublic UNLESS user.isSuspended
WHEN isPublic(event) UNLESS isSuspended(user)
fusion min {
user.session within 24h
user.isActive
sessionFresh(user),
isActive(user)
}
}
evidence canAccessHistorical(user: User, event: Event) {
user.lastActive within 24h
evidence canAccessHistorical(user: Employee, event: Event) {
recentlyActive(user)
fusion majority {
user.isActive
user.session within 24h
event.isPublic
isActive(user),
sessionFresh(user),
isPublic(event)
}
}
`;
@@ -424,7 +472,7 @@ describe('Integration Tests', () => {
test('Complex behaviors', () => {
const behaviorSystem = `
definition User {
definition Employee {
balance: number BEHAVES { decaying down hourly } CACHE eager
score: number BEHAVES { blurring adaptive confidence_95 } CACHE lazy
session: string BEHAVES { ttl 24h } CACHE eager
@@ -440,30 +488,37 @@ describe('Integration Tests', () => {
isPublic: boolean CACHE eager
}
fact hasBalance(user: User, amount: number) CACHE eager
fact hasScore(user: User, score: number) CACHE lazy
fact hasReputation(user: User, reputation: number) CACHE lazy
fact hasBalance(user: Employee, amount: number) CACHE eager
fact hasScore(user: Employee, score: number) CACHE lazy
fact hasReputation(user: Employee, reputation: number) CACHE lazy
fact hasPositiveBalance(user: any) CACHE eager
fact hasHighScore(user: any) CACHE eager
fact hasGoodReputation(user: any) CACHE eager
fact isNotOverused(doc: any) CACHE eager
fact isActive(user: any) CACHE eager
fact recentlyActive(user: any) CACHE lazy
fact isPublic(doc: any) CACHE eager
evidence canAccessDocument(user: User, doc: Document) {
user.balance > 0
evidence canAccessDocument(user: Employee, doc: Document) {
hasPositiveBalance(user)
user.score > 0.5
hasHighScore(user)
user.reputation > 0.3
hasGoodReputation(user)
doc.accessCount < 1000
isNotOverused(doc)
fusion majority {
user.isActive
user.lastActive within 1h
doc.isPublic
isActive(user),
recentlyActive(user),
isPublic(doc)
}
}
measure userEffectiveScore(user: User) {
measure userEffectiveScore(user: Employee) {
fusion average {
user.score
user.reputation
user.score,
user.reputation,
user.balance
}
} PROVIDES number
@@ -479,7 +534,7 @@ describe('Integration Tests', () => {
test('Performance scenarios', () => {
const performanceSystem = `
definition User {
definition Employee {
role: string
isActive: boolean
permissions: Permission[] CACHE eager
@@ -487,18 +542,23 @@ describe('Integration Tests', () => {
definition Resource {
level: string
owner: User
owner: Employee
permissions: Permission[] CACHE eager
}
definition Permission {
name: string
level: string
}
// High-frequency facts with limits
fact isMember(user: User, group: Group) transitive CACHE lazy limit 5
fact isFriend(user: User, friend: User) symmetrical CACHE eager limit 50
fact hasPermission(user: User, resource: Resource, action: string) CACHE eager
fact owns(user: User, resource: Resource) CACHE eager
fact isMember(user: any, group: any) transitive CACHE lazy limit 5
fact isFriend(user: any, friend: any) symmetrical CACHE eager limit 50
fact hasPermission(user: Employee, resource: Resource, action: string) CACHE eager
fact owns(user: Employee, resource: Resource) CACHE eager
// Optimized evidence rules
evidence canAccess(user: User, resource: Resource) {
evidence canAccess(user: Employee, resource: Resource) {
owns(user, resource)
isMember(user, *group) {
@@ -508,7 +568,7 @@ describe('Integration Tests', () => {
WHEN hasPermission(user, resource, 'read')
}
evidence canModify(user: User, resource: Resource) {
evidence canModify(user: Employee, resource: Resource) {
owns(user, resource)
isMember(user, *group) {
@@ -519,9 +579,9 @@ describe('Integration Tests', () => {
}
// Efficient measures
measure userEffectivePermissions(user: User) {
measure userEffectivePermissions(user: Employee) {
user.permissions
} PROVIDES Permission[]
} PROVIDES Permission
measure resourceAccessLevel(resource: Resource) {
resource.level
+104 -67
View File
@@ -12,6 +12,43 @@ function createMockArbiter() {
};
}
const DSL_SUPPORT = `
definition Employee {
role: Role
group: Group
clearance: string
reputation: number
activityScore: number
verificationLevel: number
socialProof: number
peerRatings: number
temporaryClearance: string
temporaryRole: string
actingRole: string
directPermissions: Permission[]
permissions: Permission[]
balance: number
score: number
isActive: boolean
}
definition Role {
permissions: Permission[]
clearance: string
}
definition Group {
permissions: Permission[]
clearance: string
}
definition Permission {
name: string
}
fact similar(a: any, b: any)
`;
describe('Measure Definitions', () => {
const arbiter = createMockArbiter();
const compiler = new DSLCompiler(arbiter);
@@ -19,31 +56,31 @@ describe('Measure Definitions', () => {
test('Basic measures', () => {
const testCases = [
{
input: `measure userRole(user: User) {
input: `measure userRole(user: Employee) {
user.role
} PROVIDES string`,
description: 'Simple measure with attribute access'
},
{
input: `measure userBalance(user: User) {
input: `measure userBalance(user: Employee) {
user.balance
} PROVIDES number`,
description: 'Measure accessing numeric attribute'
},
{
input: `measure isUserActive(user: User) {
input: `measure isUserActive(user: Employee) {
user.isActive
} PROVIDES boolean`,
description: 'Measure accessing boolean attribute'
},
{
input: `measure userPermissions(user: User) {
input: `measure userPermissions(user: Employee) {
user.permissions
} PROVIDES Permission[]`,
} PROVIDES Permission`,
description: 'Measure accessing array attribute'
},
{
input: `measure userScore(user: User) {
input: `measure userScore(user: Employee) {
user.score
} PROVIDES number`,
description: 'Measure with behavior-inherited attribute'
@@ -51,7 +88,7 @@ describe('Measure Definitions', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-basic-measure-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-basic-measure-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
assert.ok(result.program.measures.length > 0, 'Should have measures');
});
@@ -63,13 +100,13 @@ describe('Measure Definitions', () => {
{ type: 'number', description: 'Number return type' },
{ type: 'boolean', description: 'Boolean return type' },
{ type: 'timestamp', description: 'Timestamp return type' },
{ type: 'Permission[]', description: 'Array return type' },
{ type: 'User', description: 'Custom type return' },
{ type: 'Group[]', description: 'Custom array return type' }
{ type: 'Permission', description: 'Array return type' },
{ type: 'Employee', description: 'Custom type return' },
{ type: 'Group', description: 'Custom array return type' }
];
testCases.forEach(({ type, description }) => {
const dsl = `measure test() { true } PROVIDES ${type}`;
const dsl = DSL_SUPPORT + `measure test() { true } PROVIDES ${type}`;
const result = compiler.compile(dsl, `test-measure-return-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
@@ -78,40 +115,40 @@ describe('Measure Definitions', () => {
test('Measure aggregation', () => {
const testCases = [
{
input: `measure userPermissions(user: User) {
input: `measure userPermissions(user: Employee) {
aggregate {
user.role.permissions
user.role.permissions,
user.group.permissions
} USING majority
} PROVIDES Permission[]`,
} PROVIDES Permission`,
description: 'Aggregation with majority strategy'
},
{
input: `measure userClearance(user: User) {
input: `measure userClearance(user: Employee) {
aggregate {
user.clearance
user.role.clearance
user.clearance,
user.role.clearance,
user.group.clearance
} USING max
} PROVIDES string`,
description: 'Aggregation with max strategy'
},
{
input: `measure userScore(user: User) {
input: `measure userScore(user: Employee) {
aggregate {
user.reputation
user.activityScore
user.reputation,
user.activityScore,
user.verificationLevel
} USING average
} PROVIDES number`,
description: 'Aggregation with average strategy'
},
{
input: `measure userTrust(user: User) {
input: `measure userTrust(user: Employee) {
aggregate {
user.reputation
user.activityScore
user.verificationLevel
user.reputation,
user.activityScore,
user.verificationLevel,
user.socialProof
} USING min
} PROVIDES number`,
@@ -120,7 +157,7 @@ describe('Measure Definitions', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-measure-aggregation-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-measure-aggregation-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
});
@@ -128,40 +165,40 @@ describe('Measure Definitions', () => {
test('Measure fusion', () => {
const testCases = [
{
input: `measure effectiveClearance(user: User) {
input: `measure effectiveClearance(user: Employee) {
fusion max {
user.clearance
user.role.clearance
user.clearance,
user.role.clearance,
user.group.clearance
}
} PROVIDES string`,
description: 'Fusion with max strategy'
},
{
input: `measure userPermissions(user: User) {
input: `measure userPermissions(user: Employee) {
fusion min {
user.role.permissions
user.role.permissions,
user.group.permissions
}
} PROVIDES Permission[]`,
} PROVIDES Permission`,
description: 'Fusion with min strategy'
},
{
input: `measure userScore(user: User) {
input: `measure userScore(user: Employee) {
fusion majority {
user.reputation
user.activityScore
user.reputation,
user.activityScore,
user.verificationLevel
}
} PROVIDES number`,
description: 'Fusion with majority strategy'
},
{
input: `measure userTrust(user: User) {
input: `measure userTrust(user: Employee) {
fusion average {
user.reputation
user.activityScore
user.verificationLevel
user.reputation,
user.activityScore,
user.verificationLevel,
user.socialProof
}
} PROVIDES number`,
@@ -170,7 +207,7 @@ describe('Measure Definitions', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-measure-fusion-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-measure-fusion-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
});
@@ -178,40 +215,40 @@ describe('Measure Definitions', () => {
test('Complex measures', () => {
const testCases = [
{
input: `measure userEffectivePermissions(user: User) {
input: `measure userEffectivePermissions(user: Employee) {
aggregate {
user.role.permissions
user.group.permissions
user.role.permissions,
user.group.permissions,
user.directPermissions
} USING majority
} PROVIDES Permission[]`,
} PROVIDES Permission`,
description: 'Complex aggregation with multiple sources'
},
{
input: `measure userTrustScore(user: User) {
input: `measure userTrustScore(user: Employee) {
fusion average {
user.reputation
user.activityScore
user.verificationLevel
user.socialProof
user.reputation,
user.activityScore,
user.verificationLevel,
user.socialProof,
user.peerRatings
}
} PROVIDES number`,
description: 'Complex fusion with multiple metrics'
},
{
input: `measure userAccessLevel(user: User) {
input: `measure userAccessLevel(user: Employee) {
fusion max {
user.clearance
user.role.clearance
user.group.clearance
user.clearance,
user.role.clearance,
user.group.clearance,
user.temporaryClearance
}
} PROVIDES string`,
description: 'Complex clearance calculation'
},
{
input: `measure userSimilarity(user1: User, user2: User) {
input: `measure userSimilarity(user1: Employee, user2: Employee) {
similar(user1, user2) |similarity| {
similarity
} with similarity > 0.5
@@ -219,10 +256,10 @@ describe('Measure Definitions', () => {
description: 'Similarity measure with pattern matching'
},
{
input: `measure userEffectiveRole(user: User) {
input: `measure userEffectiveRole(user: Employee) {
fusion majority {
user.role
user.temporaryRole
user.role,
user.temporaryRole,
user.actingRole
}
} PROVIDES string`,
@@ -231,7 +268,7 @@ describe('Measure Definitions', () => {
];
testCases.forEach(({ input, description }) => {
const result = compiler.compile(input, `test-complex-measure-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-complex-measure-${Date.now()}`);
assert.ok(result.success, `${description} should parse successfully`);
});
});
@@ -239,40 +276,40 @@ describe('Measure Definitions', () => {
test('Measure error handling', () => {
const testCases = [
{
input: `measure userRole(user: User) {
input: `measure userRole(user: Employee) {
user.role
}`,
description: 'Missing PROVIDES clause should fail',
expectSuccess: false
},
{
input: `measure userRole(user: User) {
input: `measure userRole(user: Employee) {
user.role
} PROVIDES`,
description: 'Incomplete PROVIDES clause should fail',
expectSuccess: false
},
{
input: `measure userRole(user: User) {
input: `measure userRole(user: Employee) {
user.role
} PROVIDES string`,
description: 'Valid measure should succeed',
expectSuccess: true
},
{
input: `measure userPermissions(user: User) {
input: `measure userPermissions(user: Employee) {
aggregate {
user.role.permissions
user.role.permissions,
user.group.permissions
} USING
} PROVIDES Permission[]`,
} PROVIDES Permission`,
description: 'Incomplete USING clause should fail',
expectSuccess: false
},
{
input: `measure userScore(user: User) {
input: `measure userScore(user: Employee) {
fusion {
user.reputation
user.reputation,
user.activityScore
}
} PROVIDES number`,
@@ -280,7 +317,7 @@ describe('Measure Definitions', () => {
expectSuccess: false
},
{
input: `measure userRole(user: User) {
input: `measure userRole(user: Employee) {
invalid syntax here
} PROVIDES string`,
description: 'Invalid syntax should fail',
@@ -290,7 +327,7 @@ describe('Measure Definitions', () => {
testCases.forEach(({ input, description, expectSuccess }) => {
try {
const result = compiler.compile(input, `test-measure-error-${Date.now()}`);
const result = compiler.compile(DSL_SUPPORT + input, `test-measure-error-${Date.now()}`);
if (expectSuccess) {
assert.ok(result.success, `${description} should parse successfully`);
} else {