From e17e4d6c20191e65f25cb0b5a818fc198ed3b947 Mon Sep 17 00:00:00 2001 From: John Dvorak Date: Fri, 22 May 2026 12:00:20 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20remove=20silent=20error=20suppression=20?= =?UTF-8?q?=E2=80=94=20cache=20failures,=20box=20index=20mutation,=20clean?= =?UTF-8?q?up=20catches?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- packages/imhotep-core/src/geometry-cache.ts | 17 ++++++++++------- packages/imhotep-playwright/src/extraction.ts | 11 ++++++++--- packages/imhotep-solver/src/predicates.ts | 8 ++++---- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/packages/imhotep-core/src/geometry-cache.ts b/packages/imhotep-core/src/geometry-cache.ts index 59f1e9d..74bc1e9 100644 --- a/packages/imhotep-core/src/geometry-cache.ts +++ b/packages/imhotep-core/src/geometry-cache.ts @@ -250,7 +250,8 @@ function evictOldestEntries(cacheDir: string, maxEntries: number): void { const fullPath = join(cacheDir, f) try { return { name: f, path: fullPath, mtime: statSync(fullPath).mtimeMs } - } catch { + } catch (err) { + console.warn(`[imhotep-core] cache eviction: stat failed for ${f}: ${err instanceof Error ? err.message : err}`) return null } }) @@ -262,8 +263,8 @@ function evictOldestEntries(cacheDir: string, maxEntries: number): void { for (let i = 0; i < toRemove; i++) { try { rmSync(files[i].path) - } catch { - // ignore deletion errors + } catch (err) { + console.warn(`[imhotep-core] cache eviction: failed to remove ${files[i].path}: ${err instanceof Error ? err.message : err}`) } } } @@ -277,7 +278,8 @@ export async function readCachedWorld(cacheDir: string, cacheKey: string): Promi try { const json = await readFile(path, 'utf-8') return deserializeGeometryWorld(json) - } catch { + } catch (err) { + console.warn(`[imhotep-core] readCachedWorld failed for ${cacheKey}: ${err instanceof Error ? err.message : err}. Cache miss.`) return null } } @@ -303,8 +305,8 @@ export function clearGeometryCache(cacheDir: string = DEFAULT_CACHE_DIR): void { if (file.endsWith('.json')) { try { rmSync(join(cacheDir, file)) - } catch { - // ignore deletion errors + } catch (err) { + console.warn(`[imhotep-core] cache clear: failed to remove ${file}: ${err instanceof Error ? err.message : err}`) } } } @@ -390,7 +392,8 @@ export async function readCachedExtractionResult( try { const json = await readFile(path, 'utf-8') return deserializeExtractionResult(json) - } catch { + } catch (err) { + console.warn(`[imhotep-core] readCachedExtractionResult failed for cacheKey=${cacheKey}: ${err instanceof Error ? err.message : err}. Cache miss.`) return null } } diff --git a/packages/imhotep-playwright/src/extraction.ts b/packages/imhotep-playwright/src/extraction.ts index b8a5c23..f662b11 100644 --- a/packages/imhotep-playwright/src/extraction.ts +++ b/packages/imhotep-playwright/src/extraction.ts @@ -726,7 +726,9 @@ export async function extractWorldFastGeometry( for (const el of nodes) { el.removeAttribute('data-imhotep-runtime-id') } - }).catch(() => {}) + }).catch((err) => { + console.debug('[imhotep-playwright] fast-geometry cleanup evaluate failed:', err instanceof Error ? err.message : err) + }) } } @@ -910,7 +912,9 @@ export async function extractWorldCdp( for (const el of nodes) { el.removeAttribute('data-imhotep-runtime-id') } - }).catch(() => {}) + }).catch((err) => { + console.debug('[imhotep-playwright] CDP cleanup evaluate failed:', err instanceof Error ? err.message : err) + }) await sessionManager.detach() } } @@ -940,7 +944,8 @@ export async function extractWorld( width: Number.isFinite(measured?.width) ? Number(measured.width) : 0, height: Number.isFinite(measured?.height) ? Number(measured.height) : 0, } - } catch { + } catch (err) { + console.warn(`[imhotep-playwright] resolveViewport: page.evaluate failed (${err instanceof Error ? err.message : err}), falling back to 0x0 viewport`) return { width: 0, height: 0 } } } diff --git a/packages/imhotep-solver/src/predicates.ts b/packages/imhotep-solver/src/predicates.ts index 9ca96c2..d816f6c 100644 --- a/packages/imhotep-solver/src/predicates.ts +++ b/packages/imhotep-solver/src/predicates.ts @@ -166,17 +166,17 @@ export function getRequiredFactsForPredicate(name: string): string[] { // Built-in Predicate Evaluators // --------------------------------------------------------------------------- +const boxIndexCache = new WeakMap>() + function getBorderRect(world: GeometryWorld, subjectId: number) { const { boxes } = world; - // Build a subjectId -> boxIndex map on first use for O(1) lookups. - // This avoids O(n) linear scans on every predicate evaluation. - let index = (world as any).__boxIndex as Map | undefined; + let index = boxIndexCache.get(world); if (!index) { index = new Map(); for (let i = 0; i < boxes.subjectId.length; i++) { index.set(boxes.subjectId[i], i); } - (world as any).__boxIndex = index; + boxIndexCache.set(world, index); } const i = index.get(subjectId); if (i === undefined) {