refactor: remove global mutable state — registry guard, compat warning, stats

predicates.ts: Replace defaultPredicatesRegistered boolean guard with
  sentinel predicate check inside the registry. registerDefaultPredicates()
  is now always safe to call — no module-scope flag that can drift out
  of sync with the actual registry state. clearPredicateRegistry() no
  longer needs to manually reset a flag.

extraction.ts:
  - Replace compatibilityWarningEmitted process-singleton boolean with
    WeakSet<ImhotepUi> (warnedUis). Each ImhotepUi instance now gets its
    own compatibility warning, fixing the bug where two pages would share
    a single warning gate.
  - Export resetExtractionPathStats() for test isolation of fast-path
    and CDP fallback counters.

598 SDK + 3 conformance + 57 E2E = 658 tests pass.
This commit is contained in:
John Dvorak
2026-05-22 13:52:09 -07:00
parent 7f40224f0f
commit 1a8f308f71
2 changed files with 17 additions and 7 deletions
+8 -4
View File
@@ -151,7 +151,6 @@ export function listRegisteredPredicates(): string[] {
export function clearPredicateRegistry(): void {
globalPredicateRegistry.clear();
defaultPredicatesRegistered = false;
}
export function getPredicateDescriptor(name: string): PredicateDescriptor | undefined {
@@ -1196,11 +1195,16 @@ export const hasGapPredicate: PredicateEvaluator = {
// Register Defaults
// ---------------------------------------------------------------------------
let defaultPredicatesRegistered = false;
/** Sentinel registered to detect if defaults were already installed. */
const DEFAULT_SENTINEL = '__imhotep_defaults_registered__'
export function registerDefaultPredicates(): void {
if (defaultPredicatesRegistered) return;
defaultPredicatesRegistered = true;
if (globalPredicateRegistry.get(DEFAULT_SENTINEL)) return
// Register sentinel first so partial failures don't cause infinite loops.
globalPredicateRegistry.register({
descriptor: { name: DEFAULT_SENTINEL, arity: 0, domains: [], requiredFacts: [] },
evaluateTuple: () => ({ truth: 'indeterminate' }),
})
registerPredicate(widthPredicate);
registerPredicate(heightPredicate);
registerPredicate(abovePredicate);