Commit Graph

10 Commits

Author SHA1 Message Date
John Dvorak e17e4d6c20 fix: remove silent error suppression — cache failures, box index mutation, cleanup catches
geometry-cache.ts: replace 5 empty catch blocks with console.warn
- statSync failure, rmSync failure (x2), readCachedWorld failure,
  readCachedExtractionResult failure were all silently swallowed.
  Now emit context-bearing warnings so stale/corrupt caches are visible.

predicates.ts: replace __boxIndex as any mutation with WeakMap
- getBorderRect used (world as any).__boxIndex to cache a subject-to-
  box-index map on the world object. Replaced with module-level WeakMap
  that auto-collects when the world is GC'd. Eliminates 2 as any casts.

extraction.ts: serialize materializeSemanticSelector + debug cleanup
- 3 Promise.all sites over page.evaluate changed to sequential for..of
  to eliminate DOM modification race conditions.
- 2 .catch(()=>{}) cleanup blocks now use console.debug so failed
  cleanup is traceable when debugging.
- resolveViewport catch now emits console.warn on zero-viewport fallback.

648 SDK + 57 E2E tests pass.
2026-05-22 12:00:20 -07:00
John Dvorak a424d29ccc fix: remove design-debt shims — falsy ID bug, selector normalization, concurrency, exception swallowing
pipeline.ts: || undefined → ?? undefined (9 occurrences)
- || converts valid subject ID 0 to undefined because 0 is falsy in JS.
  This broke clause witnesses and topology references for the first subject.

domain-index.ts: remove .toLowerCase() on CSS selectors
- CSS selectors are case-sensitive (IDs, class names, attribute values).
  Lowercasing on lookup but not on storage (selectorIndex) meant case-
  sensitive selectors never matched — returning empty arrays silently.

canonical.ts: add warning when visualBoxes falls back to layout boxes
- visualBoxes ?? boxes silently substituted layout coordinates for visual
  space, producing incorrect results for transform-dependent assertions.
  Now emits console.warn so silent data corruption is visible.

extraction.ts: serialize materializeSemanticSelector calls (3 sites)
- Changed Promise.all over page.evaluate() to sequential for..of. While
  Playwright serializes CDP calls internally, concurrent DOM-modifying
  evaluate() calls create undefined execution order. Sequential resolution
  eliminates theoretical race conditions for semantic selector injection.

engine.ts: include stack trace in evaluator exception diagnostics
- Catch-all converted ALL exceptions (including TypeError from programming
  bugs) to IMH_EVALUATOR_EXCEPTION with just err.message. Now includes
  stack trace and logs to console.warn for visibility. Distinguishes
  TypeError (programming bug) from other evaluation errors.

648 SDK tests + 57 E2E hard tests pass, zero regressions.
2026-05-22 11:55:58 -07:00
John Dvorak 0a73063c76 fix: topology array reordering by subject order + unary inStackingContext
Topology array order mismatch (critical bug):
- CDP browser script iterates elements in document order (querySelectorAll),
  but solver accesses topology arrays by selector-resolution order.
- Fix: add subjectIds array to TopologyRecord tracking the backendNodeId
  at each document-order position; remapTopologyIds now reorders all 6
  topology arrays before remapping backendNodeIds to solver IDs.
- Fallback: when subjectIds is missing (cached pre-fix data), falls back
  to simple remap without reordering.

Unary inStackingContext compilation:
- compileCanonicalClauseToFormula treated inStackingContext as always binary,
  creating referenceBinding with undefined selector for unary assertions.
- Fix: add (inStackingContext && !clause.reference) to unaryPredicate/isUnary.

Hard test fixture (fixtures package):
- 29-element geometric fixture with 10 scenarios
- 57 assertions (54 spatial + 3 topology) all pass end-to-end
2026-05-22 11:38:28 -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 2eff60814d fix: force CDP extraction when formula uses variable-bound domains
- computeRequiredFacts now returns domAncestry flag by scanning formula
  bindings for parentVar references (descendants/children domains)
- extractWorld fast-path gate now requires domAncestry === false — formulas
  with parentVar domains will always use CDP extraction, which provides
  the DOM parentNodeId data needed for ancestor index construction
- Prevents silent indeterminate results when descendants(, sel) is
  used on the fast path (which lacks DOM ancestry data)
- Cache key updated to include domAncestry flag ('a') so cached fast vs
  CDP results for the same selectors don't collide
2026-05-21 18:59:09 -07:00
John Dvorak 7c61cb51ee fix: propagate formula metrics into FOL diagnostic mapping
- mapFolDiagnostic now accepts optional metrics parameter
- adaptFOLResultToImhotepResult matches solver diagnostics to
  formula results by clauseId/formulaId and passes formula-level
  metrics (gap, dimensions, stacking context, overflow, etc.)
  into the diagnostics output
- Previously mapFolDiagnostic always returned metrics: {} and
  sourceRef: {}, making compound/quantified failures undiagnosable
  for users investigating contracts
2026-05-21 17:17:06 -07:00
John Dvorak 19559b658b feat: implement variable-bound FOL domain resolution for descendants/children
- Extend DomainResolver.resolve() signature to accept optional BindingEnv
  so that parentVar domains can be resolved with runtime variable bindings
- Pass BindingEnv through evaluateForAll/evaluateExists to resolver calls
- Add buildAncestorIndex() to precompute DOM ancestor sets from CDP data
- SelectorDomainResolver now filters descendant domains by the bound parent
  when domain.parentVar is present and ancestor index is available
- Return undefined for parentVar domains when no ancestor index or env
  (prevents silent fallback to global domain resolution)
- Update all test DomainResolver mocks for new resolve interface
- Add 10 unit tests covering ancestor index construction, backward compat,
  descendant filtering, exclusion of non-descendants, empty descendants,
  missing parentVar/env, and no-ancestor-index safety
2026-05-21 17:05:35 -07:00
John Dvorak d23d2a431e feat: extract CSS contain from browser in Playwright adapter
- Add contain: cs.contain to browser-side style extraction
- Parse contain string into bitfield matching CDP extractor schema
- Add inline-size to CDP styles.ts contain parser for consistency
2026-05-21 14:05:55 -07:00
John Dvorak cec9597090 refactor: extract extraction.ts from public.ts (1935 lines)
Moved the extraction pipeline, formula analysis, selector resolution glue,
CDP extraction, canonical compilation, contract building, cardinality
evaluation, FOL diagnostic mapping, compatibility reporting, and all
module-level extraction state into a dedicated extraction.ts module.

public.ts reduced from 3568 to 1533 lines (-57%). The remaining file
contains only the imhotep() entry point, property-run internals, and
component/story/fixture entry points, plus re-exports for backward
compatibility.
2026-05-21 11:04:48 -07:00