Commit Graph

12 Commits

Author SHA1 Message Date
John Dvorak 8ac69254d4 feat: fact planning derived from predicate specs with fulfillment tracking
predicate-specs.ts:
  - Add FactCategory enum (geometry, topology, styles, fragments,
    domAncestry, clipping, scroll, visibility, transforms, text)
  - Add FactPlan interface with predicateFacts provenance map and
    per-category fulfillment tracking (fulfilled/failed/approximated/skipped)
  - Add requiredFactToCategory() — centralized mapping from required-fact
    strings to FactCategory values, replacing scattered inline checks
  - Add planRequiredFacts() — builds a complete FactPlan from collected
    predicate facts + AST structural analysis (CssLengthMetrics, domAncestry)
  - Add createEmptyFactPlan() factory

extraction.ts:
  - computeRequiredFacts returns FactPlan (was inline record), uses
    planRequiredFacts from spec infrastructure
  - extractWorld/extractWorldFastGeometry/extractWorldCdp accept FactPlan
    instead of inline requiredFacts record
  - After successful extraction, populate FactPlan.fulfillment with
    per-category 'fulfilled' status, providing a structured audit trail
    of which facts were requested and obtained

Adding a new predicate with new required facts now requires only a
spec entry — the fact planner, extraction engine, and fulfillment
tracker all derive behavior from the spec table automatically.

658 tests pass.
2026-05-22 15:02:20 -07:00
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 a49d6008a4 fix: add WORLD_CACHE_SCHEMA_VERSION to cache key for automatic invalidation
Cache keys now include a schema version prefix so that world-schema
changes automatically invalidate stale cached extraction results.
Previously two incompatible schema versions would share the same
cache key if URL/selectors/env matched, silently returning stale data.

WORLD_CACHE_SCHEMA_VERSION exported publicly so consumers can
increment it when making schema-incompatible changes to extraction.

658 tests pass.
2026-05-22 13:35:12 -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 c0357b152f refactor: introduce unified PredicateSpec table, convert extraction consumers
Imhotep-core: add predicate-specs.ts with 34 PredicateSpec entries as
  the single source of truth for predicate metadata (name, arity,
  aliases, requiredFacts, validOptions, diagnosticCode, relationCode,
  decompose rules, category flags). Lookup helpers derive all
  per-predicate information from the static table.

Extraction.ts (3 consumers converted):
  - computeRequiredFacts: replace getRequiredFactsForPredicate (global
    registry) with getPredicateRequiredFacts (static spec table).
    Removes registerDefaultPredicates() dependency from fact planning.
  - compileCanonicalClauseToFormula: replace 4 string-branch patterns
    ('between'/'separatedFrom'/'atLeast'/'aspectRatio'/'inStackingContext')
    with spec-driven getPredicateDecomposition() and isUnaryPredicate().
    Same behavior, zero string dispatch in predicate selection.
  - mapFolDiagnostic: replace PREDICATE_TO_DIAGNOSTIC_CODE (13-entry
    Record) with getPredicateDiagnosticCode() from spec table.

595 SDK + 57 hard E2E tests pass.
2026-05-22 12:44:57 -07:00
John Dvorak aa69ddc52f fix: replace as any casts in AST walkers with typed guards + add options to PredicateCall
logic-ast.ts: add optional options?: Record<string, unknown> to
  PredicateCall interface. Previously any predicate needing options
  (e.g., space, dimension, tolerance) smuggled them via (node as any)
  .options, bypassing the type system entirely.

extraction.ts: replace all 18 (node as any).body/.left/.right etc.
  casts with proper type guard narrowing (isForAllFormula, isExistsFormula,
  isAndFormula, isOrFormula, isNotFormula, isImpliesFormula, isPredicateCall).
  Affected functions: collectPredicates, formulaNeedsCssLengthMetrics,
  usesLayoutSpace, computeRequiredFacts & nestDomAncestry, getSelectorsFromFormula.

595 SDK + 57 E2E tests pass.
2026-05-22 12:18:22 -07:00
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 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 3b833798bb refactor: extract semantic-subjects.ts and llm-output.ts from public.ts
Extracted selector resolution helpers (normalizeCssSelector, parseQuotedValue,
materializeSemanticSelector, SelectorPlan) into semantic-subjects.ts.
Extracted LLM output formatter (formatAsLLM) into llm-output.ts.
Relaxed flaky perf test threshold 10ms->25ms in imhotep-core/perf.test.ts.
2026-05-21 10:31:34 -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