fix: close out remaining audit findings — type safety, equivalence, deprecations
lower-to-canonical.ts: clauseEquivalent now compares compoundOperator and compoundGroupId. Previously, compound assertions with different operators (.and vs .or) were considered equivalent. fol-compiler.ts: adaptGrammarFormulaToLogicAst validates node.kind against known formula kinds (forall/exists/and/or/not/implies/predicate) before passing through as FormulaNode. Previously any object with a 'kind' property was blindly cast. predicates.ts / registry.ts: @deprecated tags on globalPredicateRegistry and globalClauseRegistry. Both are still functional but consumers should transition to explicit injection via LogicEngineOptions / EvaluationOptions. 454 solver+DSL tests pass, zero regressions.
This commit is contained in:
@@ -616,6 +616,8 @@ export function clauseEquivalent(a: CanonicalClauseDescriptor, b: CanonicalClaus
|
|||||||
a.flags === b.flags &&
|
a.flags === b.flags &&
|
||||||
a.quantifier === b.quantifier &&
|
a.quantifier === b.quantifier &&
|
||||||
a.envGuard === b.envGuard &&
|
a.envGuard === b.envGuard &&
|
||||||
|
a.compoundOperator === b.compoundOperator &&
|
||||||
|
a.compoundGroupId === b.compoundGroupId &&
|
||||||
frameEquivalent(a.frame, b.frame) &&
|
frameEquivalent(a.frame, b.frame) &&
|
||||||
stateEquivalent(a.state, b.state) &&
|
stateEquivalent(a.state, b.state) &&
|
||||||
toleranceEquivalent(a.tolerance, b.tolerance) &&
|
toleranceEquivalent(a.tolerance, b.tolerance) &&
|
||||||
|
|||||||
@@ -36,12 +36,15 @@ import { FluentQuantifier as FQ, FluentRelation as FR } from 'imhotep-dsl'
|
|||||||
* - If the node has a `type` property, it's in grammar.ts shape and needs conversion.
|
* - If the node has a `type` property, it's in grammar.ts shape and needs conversion.
|
||||||
*/
|
*/
|
||||||
function adaptGrammarFormulaToLogicAst(node: any): FormulaNode {
|
function adaptGrammarFormulaToLogicAst(node: any): FormulaNode {
|
||||||
// Already in logic-ast.ts shape — pass through
|
|
||||||
if (node && typeof node === 'object' && 'kind' in node) {
|
if (node && typeof node === 'object' && 'kind' in node) {
|
||||||
return node as FormulaNode
|
const kind = node.kind
|
||||||
|
if (kind === 'forall' || kind === 'exists' || kind === 'and' || kind === 'or' ||
|
||||||
|
kind === 'not' || kind === 'implies' || kind === 'predicate') {
|
||||||
|
return node as FormulaNode
|
||||||
|
}
|
||||||
|
throw new TypeError(`Unknown formula kind: ${kind}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not an object or null — cannot adapt
|
|
||||||
if (!node || typeof node !== 'object') {
|
if (!node || typeof node !== 'object') {
|
||||||
throw new TypeError('Cannot adapt non-object formula node')
|
throw new TypeError('Cannot adapt non-object formula node')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ export class PredicateRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global default instance for backward compatibility.
|
/** @deprecated Use explicit PredicateRegistry injection via LogicEngineOptions.predicateRegistry. */
|
||||||
export const globalPredicateRegistry = new PredicateRegistry();
|
export const globalPredicateRegistry = new PredicateRegistry();
|
||||||
|
|
||||||
export function registerPredicate(evaluator: PredicateEvaluator): void {
|
export function registerPredicate(evaluator: PredicateEvaluator): void {
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ export class ClauseRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global default instance for backward compatibility.
|
/** @deprecated Use explicit ClauseRegistry injection via EvaluationOptions.registry. */
|
||||||
export const globalClauseRegistry = new ClauseRegistry();
|
export const globalClauseRegistry = new ClauseRegistry();
|
||||||
|
|
||||||
/** Register a clause family so the engine can route evaluation. */
|
/** Register a clause family so the engine can route evaluation. */
|
||||||
|
|||||||
Reference in New Issue
Block a user