Commit Graph

15 Commits

Author SHA1 Message Date
John Dvorak 7f40224f0f 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.
2026-05-22 13:46:54 -07:00
John Dvorak 1bc0c8e6df refactor: replace smuggled compound properties with typed FluentRelation API
fluent.ts: Add public getters isCompound, compoundOperator, compoundParts
  to FluentRelation. Add optional CompoundState to constructor. Add
  CompoundPart/CompoundState interfaces. Replace 4 (this as any)._xxx
  property smuggles in FluentCompoundBuilder._addPart() with properly
  typed constructor initialization via CompoundState.

fol-compiler.ts: Replace 3 (relation as any)._compoundParts /
  ._compoundOperator / ._isCompound duck-type reads with direct
  relation.compoundParts / relation.compoundOperator / relation.isCompound.

extraction.ts: Replace (rel as any)._compoundParts read in
  getSelectorsFromAssertion with typed compoundRel.isCompound /
  compoundRel.compoundParts access.

Eliminates 7 (as any) casts across 3 production files. Zero remaining
_compoundParts/_compoundOperator/_isCompound/_originalFirstRelation
smuggled references in any production source file.

598 SDK + 3 conformance + 57 E2E = 658 tests pass.
2026-05-22 13:31:34 -07:00
John Dvorak 9df295b915 refactor: eliminate remaining hardcoded predicate-name dispatch
Extraction.ts (3 fixes):
  - Replace 2 'inStackingContext' string checks with isVariableArityPredicate()
  - Replace 7-name diagnostic formatting if/else with spec-driven
    getPredicateSpec() checks (isDirectional → gap message,
    isSize → threshold hint, else generic)

Grammar.ts: Replace 8 hardcoded parser routing checks
  (atLeast/atMost/aspectRatio/between/clippedBy/attachedToScrollContainer/
  escapeClippingChainOf/inStackingContext) with SIZE_PREDICATE_NAMES and
  TOPOLOGY_PREDICATE_NAMES Sets derived from spec table.

Pipeline.ts: Replace 15-entry CODE_TO_CLAUSE_KIND map with runtime
  generation from PREDICATE_SPECS. Prefix derived from spec.isSize
  ('size.*') / validOptions.includes('axis') ('alignment.*') /
  else ('relation.*'). Manual override for aspectRatio code 15.

Proofs.ts: Replace 11-case switch(kind) with 5 spec-driven if/else
  branches categorized by validOptions presence (hasGap→directional,
  hasAxis→alignment) + 2 specific name checks (inside overflow,
  aspectRatio ratio). 11 predicate names → 0 hardcoded.

Lexer.ts: Export KEYWORDS map for conformance testing.

Conformance tests:
  - Solver: every BUILTIN_PREDICATES entry matches its PREDICATE_SPECS
    counterpart; every spec name (incl. aliases) has a registered
    evaluator with matching descriptor (2 tests)
  - DSL: every predicate name from collectAllPredicateNames() appears
    in the lexer KEYWORDS table (1 test)

598 SDK + 3 conformance + 57 E2E = 658 tests pass.
2026-05-22 13:15:35 -07:00
John Dvorak 283ab1b39f refactor: convert grammar predicate detection to spec table
Replace 21-item hardcoded isKeywordThatCanBePredicate array with
isPredicateName() from PredicateSpec (+ 'size' special case for
fluent API FOL bodies).

Replace 24-item parseRelation relationKinds array with
collectSpatialPredicateNames() from spec. Error message now also
auto-derives from the spec.

595 SDK + 57 E2E tests pass.
2026-05-22 12:51:20 -07:00
John Dvorak 2e27693278 refactor: convert DSL compiler relationCodes and unary check to spec table
Replace 19-entry relationCodes string-to-integer map with
getPredicateRelationCode() from PredicateSpec. Keep only
aspectRatioBetween (15) as local DSL-keyword override.

Replace string-based unary detection ('atLeast'||'atMost') in
compileSimpleAssertionToFormula with isUnaryPredicate() from spec.

595 SDK + 57 E2E tests pass.
2026-05-22 12:48:39 -07:00
John Dvorak 6f82849b4f refactor: convert validator to use predicate spec table
Replace 5 static Sets/maps (SPATIAL_RELATIONS, SIZE_RELATIONS,
VALID_OPTIONS, QUANTIFIER_COMPATIBLE, UNARY_RELATIONS) with
derivation from the unified PredicateSpec table:
  - collectSpatialPredicateNames / collectSizePredicateNames
    for category sets
  - getPredicateValidOptions for option validation
  - collectQuantifierCompatiblePredicateNames for quantifier checks
  - isUnaryPredicate for unary detection

Local override map retained for fluent API dotted size variants
('size.atLeast' etc.) and 'aspectRatioBetween' DSL keyword, which
are input conventions, not distinct predicates.

595 SDK + 57 E2E tests pass.
2026-05-22 12:46:41 -07:00
John Dvorak 07ed316135 fix: NaN guard in normalizeOptionValue + warn on silent parser drops
compiler.ts: normalizeOptionValue now rejects NaN numbers and empty
  strings. Previously typeof NaN === 'number' passed through and
  propagated into option values, causing predicate comparisons like
  value >= NaN to produce silent wrong results.

grammar.ts: parseAssertion now emits console.warn when silently
  skipping unexpected tokens or failed clauses. Previously these
  returns-null were invisible to developers.

454 solver+DSL + 57 E2E tests pass.
2026-05-22 12:08:39 -07:00
John Dvorak 9b691b2c7c 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.
2026-05-22 12:05:43 -07:00
John Dvorak 1ac30c6e18 fix: support between predicate in FOL dense DSL
- grammar.ts: add 'between' to isKeywordThatCanBePredicate() so the parser
  recognizes it as a valid predicate keyword in forall/exists formula bodies
- compiler.ts: add special case in compileDenseFOLToFormula for
  between(, min, max, dimension?) that extracts numeric args into
  options ({min, max, dimension}) instead of dropping them in the generic
  arg loop. The existing betweenPredicate evaluator already handles these.
- fol-dense-combinations.test.ts: replace GAP test with two verified-working
  tests for between and between with dimension
2026-05-22 10:48:26 -07:00
John Dvorak 1bc92e1f7d fix: CDP extraction concurrency + topology ID remapping + predicate completeness
CDP protocol fixes:
- session.ts: getDocumentRootNodeId() now pushes {depth:-1} full DOM tree
  (was shallow default, causing querySelectorAll to find zero nodes)
- extraction.ts: serialize resolveSelector calls (was concurrent Promise.all,
  CDP DOM.querySelectorAll is not safe for concurrent calls on same session)

Topology ID mismatch fixes (critical — backendNodeId vs solver subject ID):
- extraction.ts: add remapTopologyIds() — builds Map<backendNodeId,solverId>
  from world.subjects.domNodeId/ids, remaps all 6 topology arrays +
  clipping.subjectId + scroll.containerId
- topology.ts: createsStackingContext() now checks contain:paint|layout
  (both create stacking contexts per CSS spec, was missing)
- topology.ts: evaluateInStackingContext() handles unary (no reference)

Predicate completeness:
- predicates.ts: 3 new evaluators — intersects, touches, hasGap (indices 31-33)
- predicates.ts: escapeClippingChainOf replaced indeterminate stub with
  deterministic 2-ary evaluator (overflow + clip chain + ancestry checks)
- predicates.ts: attachedToScrollContainer arity 1→2, checks reference match
- predicates.ts: 7 aliases + 4 alignment aliases promoted to BUILTIN_PREDICATES

DSL grammar fixes:
- grammar.ts: isKeywordThatCanBePredicate() extended with all missing keywords
- lower-to-canonical.ts: add TopologyAssertion lowering (was silently dropped)
- compiler.ts: add intersects/touches/hasGap relation codes
- validator.ts: add option sets for new predicates
- lexer.ts: add intersects/touches/hasGap token kinds

Safety + infrastructure:
- joins.ts: MAX_CARTESIAN_TUPLES=100,000 guard with descriptive error
- extraction.ts: computeRequiredFacts() registers defaults + broadens topology gate
- package.json: add missing imhotep-state dependency to imhotep-playwright

Tests:
- 9 new predicate tests (intersects, touches, hasGap, escapeClippingChainOf)
- Convert stale separatedFrom/contains GAP tests to working assertions
- Add computeRequiredFacts topology gating tests (public.test.ts)
2026-05-22 10:20:06 -07:00
John Dvorak b4ae8e9134 fix: children($var) domain compilation and resolver support
- Add children branch in convertDomain() alongside descendants —
  children() now correctly maps to parentVar: '$parent'
  instead of falling through to the default branch which reversed
  the parentVar/selector mapping.
- SelectorDomainResolver now handles parentVar domains with no
  CSS selector filter (children domain collects all registered
  subject IDs, then filters by parent via ancestor index).
- All 1072 tests pass across 14 packages.
2026-05-21 20:13:57 -07:00
John Dvorak 4ff56d61c2 feat: wire directional alignment predicates into dense DSL grammar
- Add leftAlignedWith/rightAlignedWith/topAlignedWith/bottomAlignedWith
  to lexer TokenKind union and keyword map
- Add to grammar.ts consumeRelation() recognized relation kinds
- Dense DSL users can now write: '.a' leftAlignedWith '.b', etc.
  (previously returned parser error 'Expected relation')
2026-05-21 14:39:01 -07:00
John Dvorak 70f528fbab chore: polish for FOL contract delivery (CHANGELOG, CLI guardrails, metadata)
- Update CHANGELOG.md for 1.1.0 (date, refactoring, repository fixes)
- Add overwrite guardrails to imhotep-cli init — skips existing files
- Add bugs/homepage/keywords metadata to 5 public packages
- Mark imhotep-bench and imhotep-fixtures as private packages
- Add selector field to SourceReference interface (core types)
- Remove 7  casts from check-all.ts (folAst.position, cardinality results)
- Generate package-lock.json for reproducible installs
2026-05-21 11:58:31 -07:00
John Dvorak dd64e1e34a v1.1.0: repo polish, CI fixes, version alignment, dead artifact cleanup
Root package: renamed to imhotep-monorepo, fixed broken scripts (test:unit/integration/e2e),
removed inappropriate root deps, fixed build order, updated clean script

CI: branch trigger main->master, npm ci->npm install, GitHub cache URL->Gitea

Docs: replaced scaffolded root README with real project README, added package READMEs
for imhotep/imhotep-playwright/imhotep-dsl/imhotep-core, added RELEASE.md checklist

Version: all 14 packages and root aligned to 1.1.0, CHANGELOG test count fixed (1125)

Metadata: 14 repository URLs github->gitea, 13 package descriptions added,
imhotep-cli exports field added, SECURITY.md updated for Gitea+disclosure email

Quality: noEmitOnError:true in 13 tsconfigs, collapsed duplicate interfaces in public.ts,
clippedBy test->test.skip, fixed broken dynamic import in imhotep index.test.ts,
694 generated src artifacts cleaned, V8 logs removed, .gitignore updated
2026-05-21 10:10:11 -07:00
John Dvorak 92deb689cd v1.1.0: pooled runtime, 959 tests, production hardening (0 squash) 2025-08-15 10:00:00 -07:00