Three failing test suites blocked CI. All three were test defects, not application bugs. Integration tests (integration/database.test.ts) ------------------------------------------------ The suite set NODE_ENV=test, which makes cache.cached() short-circuit both its Redis read (src/lib/cache.ts:226) and its write (:249). A suite whose stated purpose is exercising the real Redis path therefore never touched Redis. Switched to NODE_ENV=development, the only non-production value src/env.ts accepts, so the shared-cache code paths are genuinely covered. Three assertions then needed correcting for real Redis semantics: - `await cache.cached(...)` followed by `.resolves` can never hold: await yields a value, not a Promise. Assert the value directly. - A cached negative result is stored as the JSON encoding of null, so `redis.get(key)` returns "null", not null. - The news negative-cache key does not exist at all, so `ttl()` returned -2. Now that the write path is live the key is created and the TTL assertion holds as originally written. UI tests (src/app/admin/prefixes/prefix-dialog.tsx) --------------------------------------------------- The form-reset effect had `isOpen` removed from its dependency array. The component returns null when closed, so the effect only ever ran on mount: reopening the dialog no longer cleared the fields and a dismissed-but- unsaved edit reappeared. Two tests in e2e/ui/unsaved-changes.spec.ts caught this. Restored the dependency and documented why it is load-bearing. The remaining edits in this branch drop stale biome-ignore comments that suppressed useExhaustiveDependencies and noArrayIndexKey diagnostics. Where the suppression had been load-bearing for behaviour, the underlying dependency is now listed explicitly rather than silenced. Verified: check (toolchain, audit, lint, i18n, typecheck), unit 3315 passed, integration 20 passed, UI 72 passed / 2 skipped.
Catalog Studio code map
studio-client.tsx composes the workspace, selection and actions. Keep reusable data handling outside its render tree.
Client responsibilities
studio-filters.ts: pure filtering and sorting of the loaded furniture list; never mutates the input array.use-studio-translations.ts: language selection, persisted defaults and translation requests.use-furniture-jobs.ts: queue submission, retry identity, polling and completion notifications.furniture-jobs.tsx: job history and retry controls.use-furniture-inspection.ts: cancellable inspection requests and explicit rechecks.furniture-inspector.tsx: local component status, source comparison and repair controls.import-review.tsx: import review, actionable review groups and attachment confirmation.import-recommendation.ts: completion, conflict and verification recommendations from inspected component evidence.studio-types.ts: shared client data types.
Server responsibilities
src/lib/services/furniture-inspection.ts: reads SQL, catalog offers, furnidata and asset presence.src/lib/furni/studio-inspection.ts: shared validation, comparison and completeness classification.src/lib/services/furniture-repair.ts: preflight, preservation options and post-repair verification.src/lib/services/furni-job-worker.ts: durable queued work and per-item results.
Keep client modules free of filesystem/database imports. Background refreshes must not reset open editors or unsaved input. Completion status must come from verification, not optimistic UI flags.
Detail navigation keeps the mounted workspace state and restores the list scroll position and originating control on close. Escape closes an open detail before clearing selection. Furniture responses must belong to the latest list request; source changes invalidate pending detail, review and delete state. Selection is never persisted outside the mounted workspace.