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
+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 {