feat: implement directional alignment predicate evaluators (no more NYI)

- Replace makeNotImplementedPredicate stubs for leftAlignedWith,
  rightAlignedWith, topAlignedWith, bottomAlignedWith with real
  evaluators delegating to alignedWithPredicate with axis option
- Update logic-engine.test.ts to expect real evaluation results
  instead of IMH_FEATURE_NOT_YET_IMPLEMENTED
This commit is contained in:
John Dvorak
2026-05-21 14:36:02 -07:00
parent 8dae898304
commit 96bcce1ddb
2 changed files with 34 additions and 10 deletions
@@ -361,7 +361,7 @@ describe('predicate calls', () => {
assert.ok(!result.diagnostics.some((d) => d.code === 'IMH_FEATURE_NOT_YET_IMPLEMENTED')); assert.ok(!result.diagnostics.some((d) => d.code === 'IMH_FEATURE_NOT_YET_IMPLEMENTED'));
}); });
it('returns not-yet-implemented for aligned-with variants', () => { it('evaluates aligned-with directional variants correctly', () => {
const world = makeWorld(); const world = makeWorld();
const variants = ['leftAlignedWith', 'rightAlignedWith', 'topAlignedWith', 'bottomAlignedWith']; const variants = ['leftAlignedWith', 'rightAlignedWith', 'topAlignedWith', 'bottomAlignedWith'];
for (const variant of variants) { for (const variant of variants) {
@@ -391,11 +391,12 @@ describe('predicate calls', () => {
}; };
const result = evaluateLogic(input); const result = evaluateLogic(input);
assert.strictEqual(result.passed, false, `Expected ${variant} to fail`); // Elements 1 (0,0,100,40) and 2 (110,50,210,90) are not aligned
assert.ok( // on any side, so all directional alignments should produce determinate
result.diagnostics.some((d) => d.code === 'IMH_FEATURE_NOT_YET_IMPLEMENTED'), // false results (not IMH_FEATURE_NOT_YET_IMPLEMENTED).
`Expected ${variant} to produce IMH_FEATURE_NOT_YET_IMPLEMENTED` assert.strictEqual(result.passed, false, `Expected ${variant} to evaluate, not return NYI`);
); assert.strictEqual(result.formulaResults.length, 1);
assert.strictEqual(result.formulaResults[0].outcome, 'fail');
} }
}); });
}); });
+27 -4
View File
@@ -972,10 +972,33 @@ export const separatedFromPredicate: PredicateEvaluator = {
return makePredicateResult(pass ? 'true' : 'false', metrics, [subjectId, referenceId]); return makePredicateResult(pass ? 'true' : 'false', metrics, [subjectId, referenceId]);
}, },
}; };
export const leftAlignedWithPredicate = makeNotImplementedPredicate('leftAlignedWith'); export const leftAlignedWithPredicate: PredicateEvaluator = {
export const rightAlignedWithPredicate = makeNotImplementedPredicate('rightAlignedWith'); descriptor: { name: 'leftAlignedWith', arity: 2, domains: ['element', 'element'], requiredFacts: ['subject.primaryBox', 'reference.primaryBox'] },
export const topAlignedWithPredicate = makeNotImplementedPredicate('topAlignedWith'); evaluateTuple(world, tuple, options) {
export const bottomAlignedWithPredicate = makeNotImplementedPredicate('bottomAlignedWith'); return alignedWithPredicate.evaluateTuple(world, tuple, { ...options as Record<string, unknown>, axis: 'left' });
},
};
export const rightAlignedWithPredicate: PredicateEvaluator = {
descriptor: { name: 'rightAlignedWith', arity: 2, domains: ['element', 'element'], requiredFacts: ['subject.primaryBox', 'reference.primaryBox'] },
evaluateTuple(world, tuple, options) {
return alignedWithPredicate.evaluateTuple(world, tuple, { ...options as Record<string, unknown>, axis: 'right' });
},
};
export const topAlignedWithPredicate: PredicateEvaluator = {
descriptor: { name: 'topAlignedWith', arity: 2, domains: ['element', 'element'], requiredFacts: ['subject.primaryBox', 'reference.primaryBox'] },
evaluateTuple(world, tuple, options) {
return alignedWithPredicate.evaluateTuple(world, tuple, { ...options as Record<string, unknown>, axis: 'top' });
},
};
export const bottomAlignedWithPredicate: PredicateEvaluator = {
descriptor: { name: 'bottomAlignedWith', arity: 2, domains: ['element', 'element'], requiredFacts: ['subject.primaryBox', 'reference.primaryBox'] },
evaluateTuple(world, tuple, options) {
return alignedWithPredicate.evaluateTuple(world, tuple, { ...options as Record<string, unknown>, axis: 'bottom' });
},
};
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Register Defaults // Register Defaults