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.
This commit is contained in:
@@ -250,7 +250,8 @@ function evictOldestEntries(cacheDir: string, maxEntries: number): void {
|
|||||||
const fullPath = join(cacheDir, f)
|
const fullPath = join(cacheDir, f)
|
||||||
try {
|
try {
|
||||||
return { name: f, path: fullPath, mtime: statSync(fullPath).mtimeMs }
|
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
|
return null
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -262,8 +263,8 @@ function evictOldestEntries(cacheDir: string, maxEntries: number): void {
|
|||||||
for (let i = 0; i < toRemove; i++) {
|
for (let i = 0; i < toRemove; i++) {
|
||||||
try {
|
try {
|
||||||
rmSync(files[i].path)
|
rmSync(files[i].path)
|
||||||
} catch {
|
} catch (err) {
|
||||||
// ignore deletion errors
|
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 {
|
try {
|
||||||
const json = await readFile(path, 'utf-8')
|
const json = await readFile(path, 'utf-8')
|
||||||
return deserializeGeometryWorld(json)
|
return deserializeGeometryWorld(json)
|
||||||
} catch {
|
} catch (err) {
|
||||||
|
console.warn(`[imhotep-core] readCachedWorld failed for ${cacheKey}: ${err instanceof Error ? err.message : err}. Cache miss.`)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -303,8 +305,8 @@ export function clearGeometryCache(cacheDir: string = DEFAULT_CACHE_DIR): void {
|
|||||||
if (file.endsWith('.json')) {
|
if (file.endsWith('.json')) {
|
||||||
try {
|
try {
|
||||||
rmSync(join(cacheDir, file))
|
rmSync(join(cacheDir, file))
|
||||||
} catch {
|
} catch (err) {
|
||||||
// ignore deletion errors
|
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 {
|
try {
|
||||||
const json = await readFile(path, 'utf-8')
|
const json = await readFile(path, 'utf-8')
|
||||||
return deserializeExtractionResult(json)
|
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
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -726,7 +726,9 @@ export async function extractWorldFastGeometry(
|
|||||||
for (const el of nodes) {
|
for (const el of nodes) {
|
||||||
el.removeAttribute('data-imhotep-runtime-id')
|
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) {
|
for (const el of nodes) {
|
||||||
el.removeAttribute('data-imhotep-runtime-id')
|
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()
|
await sessionManager.detach()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -940,7 +944,8 @@ export async function extractWorld(
|
|||||||
width: Number.isFinite(measured?.width) ? Number(measured.width) : 0,
|
width: Number.isFinite(measured?.width) ? Number(measured.width) : 0,
|
||||||
height: Number.isFinite(measured?.height) ? Number(measured.height) : 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 }
|
return { width: 0, height: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,17 +166,17 @@ export function getRequiredFactsForPredicate(name: string): string[] {
|
|||||||
// Built-in Predicate Evaluators
|
// Built-in Predicate Evaluators
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const boxIndexCache = new WeakMap<GeometryWorld, Map<number, number>>()
|
||||||
|
|
||||||
function getBorderRect(world: GeometryWorld, subjectId: number) {
|
function getBorderRect(world: GeometryWorld, subjectId: number) {
|
||||||
const { boxes } = world;
|
const { boxes } = world;
|
||||||
// Build a subjectId -> boxIndex map on first use for O(1) lookups.
|
let index = boxIndexCache.get(world);
|
||||||
// This avoids O(n) linear scans on every predicate evaluation.
|
|
||||||
let index = (world as any).__boxIndex as Map<number, number> | undefined;
|
|
||||||
if (!index) {
|
if (!index) {
|
||||||
index = new Map<number, number>();
|
index = new Map<number, number>();
|
||||||
for (let i = 0; i < boxes.subjectId.length; i++) {
|
for (let i = 0; i < boxes.subjectId.length; i++) {
|
||||||
index.set(boxes.subjectId[i], i);
|
index.set(boxes.subjectId[i], i);
|
||||||
}
|
}
|
||||||
(world as any).__boxIndex = index;
|
boxIndexCache.set(world, index);
|
||||||
}
|
}
|
||||||
const i = index.get(subjectId);
|
const i = index.get(subjectId);
|
||||||
if (i === undefined) {
|
if (i === undefined) {
|
||||||
|
|||||||
Reference in New Issue
Block a user