fix: propagate compound state through toAst() and canonical lowering

ast.ts: Add optional compoundOperator and compoundParts fields to
  RelationAssertion, allowing compound fluent assertions to carry
  their .and / .or structure through the AST layer.

fluent.ts: toAst() now emits compoundOperator/compoundParts when
  isCompound, closing the gap where compound state was silently
  dropped in canonical extraction, preset building, and validation.

lower-to-canonical.ts: Handle RelationAssertion with compound metadata
  by lowering each part as a separate grouped clause (same groupId,
  same compoundOperator), matching DSL parser compound behavior.

validator.ts: Validate options on each compound part, closing the
  false-positive validation gap where only the final relation was checked.

3 lossy code paths (extractCanonicalFromAssertion, presets.toPresetResult,
validateRelation) now preserve compound structure. Primary FOL evaluation
path was already correct (fol-compiler reads compoundParts directly).

658 tests pass.
This commit is contained in:
John Dvorak
2026-05-22 13:46:54 -07:00
parent a49d6008a4
commit 7f40224f0f
4 changed files with 54 additions and 1 deletions
+4
View File
@@ -110,6 +110,10 @@ export interface RelationAssertion extends AstNode {
subject: SelectorRef
reference: SelectorRef
options: RelationOptions
/** If set, this assertion is part of a compound (.and / .or) chain. */
compoundOperator?: 'and' | 'or'
/** Sub-relation parts forming the compound chain (including this one). */
compoundParts?: Array<{ relation: string; referenceSelector: string; options: RelationOptions }>
}
export interface RelationOptions extends AstNode {