
## 2026-04-01
- [x] Review codebase and write a summary of the architecture, key components, and any obvious improvement areas to TASKS.md Backlog
- [x] **Backup silent failure** — `src/db/backup.ts` line 67 has an empty `catch (e) {}` block; exceptions from file restore are swallowed with no logging or user feedback.
- [x] **Title override XSS** — `src/background/dbSync.ts` accepts tab titles from content scripts (including `geminiTitles.ts`) without sanitisation and stores them in IndexedDB; they're rendered in React without escaping. Sanitise on ingest.
- [x] **Title override cache memory leak** — `titleOverrideCache` in `dbSync.ts` is an unbounded `Map` that is never pruned. Replace with an LRU/TTL cache (suggested TTL: 30 min).
- [x] **Embedding AbortController** — `queueProcessor.ts` runs up to 4 concurrent WASM embeddings with no cancellation path. Add `AbortController` support so long batches can be stopped.
- [x] **Fire-and-forget progress reporting** — Several `db.progress.put(...)` calls in `progress.ts` and callers are unawaited in hot paths; add top-level `.catch` at minimum to surface errors.
- [x] **Tests: queueProcessor.ts** — Zero tests for 500 LOC of critical background logic. Cover: operation deduplication, concurrent execution, retry behaviour, `backendPermanentlyFailed` reset, progress tracking.
- [x] **Tests: db.ts migrations** — 16 schema migrations are completely untested. Add in-memory Dexie tests for each migration path, especially v13–v16.
- [x] **Tests: dbSync.ts** — Tab activation, URL normalization edge cases, `isInitializing` guard, `titleOverrideCache` eviction.
- [x] **Tests: pageSearchIndex.ts** — Search initialization, Dexie hook updates (`creating`/`updating`/`deleting`), fallback to full scan, prefix vs. substring behaviour.
- [x] fix failing tests
- [x] **Embedding backend recovery** — `backendPermanentlyFailed` is a module-level static flag that blocks all future embedding ops for the session. Add exponential-backoff retry so a transient HuggingFace WASM failure doesn't permanently disable the feature.
- [x] **Index on `operations.status`** — `queueProcessor.ts` queries pending operations by status alone; without an index this is a full-table scan. Add a `status` index in `db.ts`.
- [x] **Replace `any` types** — 60+ uses of `any` throughout services and workers. Start with function parameters in `queueProcessor.ts`, `pageSearchIndex.ts`, and `pageSimilarity.ts`.
- [x] **Logger age-based cleanup** — `logger.ts` prunes logs probabilistically (1% chance). Replace with deterministic age-based deletion (e.g., delete logs older than 7 days) to prevent unbounded DB growth.
- [x] **Content script security audit** — Review all title-extraction content scripts (`geminiTitles.ts`, etc.) for injection vectors; consider banning `innerHTML` usage entirely.
- [x] **Implement a todo list feature** - In addition to tracking web pages, the user wants to be able to track todo items. These todo items should have an editable title, a priority, a completion status, a creation date, and a due date.  These fields should be added to the existing "Page" interfaces, so that an item may be a web page, a todo item, or both.  Naturally, todo items that are not web pages will not have a url; if it helps for database keys etc., todos may be given synthetic URLs like todo://<uuid>.  Todos should be searchable and taggable just like web pages. They should be displayed in the same UI as web pages.  The existing TODO tab should simply filter for items that are todos, perhaps identified by having a non-empty completion status (as opposed to empty, for web pages that are not todos).  There should be UI affordances for adding a new todo item, deleting a todo item, and editing the fields of a todo item.  The title should be editable in place by double-clicking.  Completed todos that are not also web pages should not be displayed by default, but there should be a way to view completed todos, perhaps via a "show completed" toggle or similar UI affordance.
- [x] **Todo: `todo://` URL crash in PageRow** — Todos appear in the main page list (`PageRow.tsx:269`) with a checkbox via the `completionStatus !== undefined` guard. Double-clicking a todo row calls `activateOrOpenTab(page.nurl.normalized, ...)` with a `todo://uuid` URL, which causes `chrome.tabs.create` to fail silently. Guard `activateOrOpenTab` (or `PageRow`) against non-http(s) schemes.
- [x] **Unawaited `chrome.tabs.create` in `chromeNavigation.ts`** — `openTab` (line 7) and `activateOrOpenTab` (line 17) call `chrome.tabs.create` without `await` and with no error handler. A `todo://` URL (or any invalid scheme) causes a silent runtime error that goes completely undetected. Add `await` and a `.catch(e => logger.warn(...))` to both call sites.
- [x] **Todo: silent error swallowing** — `TodoView.tsx` uses `.catch(() => {})` on every CRUD call (lines 50, 70, 72, 82, 114, 135, 179). Failures are invisible — no logging, no user feedback. At minimum log via `logger.error`; ideally surface a toast/error state.
- [x] **Tests: todo feature** — The entire todo feature (DB schema v18+, `createTodo`, `updateTodoTitle`, `updateTodoCompletion`, `updateTodoPriority`, `updateTodoDueDate`) has zero test coverage. Add unit tests for CRUD ops and migration path.
- [x] **`handleFetchMissingTitle` bulk sweep tries to open `todo://` URLs** — `queueProcessor.ts:252-253` scans all pages with missing/empty titles, including todo items. If a todo ever has a blank title, the bulk sweep calls `chrome.tabs.create({ url: 'todo://uuid', active: false })` at line 273, which fails silently. Fix: skip URLs that don't start with `http://` or `https://` in both the bulk and single-URL paths.
- [x] **TodoView optimistic form reset swallows `createTodo` failure** — `TodoView.tsx:179-183` clears the new-todo form state synchronously before `createTodo` resolves. If the DB write fails (quota exceeded, etc.), the user's input is silently discarded with no feedback. Fix: await `createTodo` before resetting form state, and show an error if it throws.
- [x] **Todo items have no visual distinction in main page list** — `PageRow.tsx:269` renders a checkbox for todo items (detected via `completionStatus !== undefined`) but provides no badge, icon, or label indicating the item is a todo rather than a web page. Users may be confused about which items are todos vs. tracked web pages. Add a "TODO" badge or distinct styling to todo rows in the main list.
- [x] **Todo fields not editable outside TodoView tab** — PageRow shows a completion checkbox for todos in the main list but doesn't support editing the title, priority, or due date from there. Users must switch to the TODO tab to edit these fields. Consider adding inline editing or a popover/modal for todo fields directly from PageRow.
- [x] **Empty-title todos may never get embeddings** — `pages.ts:140-142` returns early from `ensurePageTracked` when `title` is falsy, meaning todos with blank titles are never embedded and therefore not searchable by semantic similarity. Unlike web pages (which get backfilled via `fetchMissingTitle`), todos have no comparable backfill sweep. Fix: skip the early-return for `todo://` URLs, or add a `generateEmbedding` enqueue after `createTodo` succeeds even when title is empty.

## 2026-04-01
- [x] Todo items should use the same row component as web pages, and correspondingly the web page row component should offer todo features-- e.g. turn a page into a todo by setting a "pending" status or a priority.  The web row component should not become taller to achieve this.  Perhaps some "progressive disclosure" treatment can keep things compact, hiding the todo fields unless they're activated.
- [x] add the todo fields to the inspector
- [x] make a clearer graphical distinction between selected tags and proposed tags in the inspector

## 2026-04-02
- [x] **P1 — `renormalizeOne` crashes on pages with undefined `openedUrls`/`openerUrls`** — `db.ts:386-387` calls `.map()` directly on `newPage.openedUrls` and `newPage.openerUrls` without null guards (unlike `timeAdjacentUrls` at line 388 which has `|| []`). Old DB entries from pre-schema versions will throw a TypeError. Fix: add `|| []` to match `timeAdjacentUrls`.
- [x] **P1 — `similarityWorker.ts` undefined graph array crash** — Lines 75, 77, 78 call `.includes()` directly on `selectedPage.timeAdjacentUrls`, `openedUrls`, and `openerUrls` without null-checking. These are optional on `DBPage`; if absent, the worker throws and similarity search silently fails. Fix: add `|| []` guards.
- [x] **P1 — Invalid `sendMessage` call in Options** — `Options.tsx:138` calls `chrome.runtime.sendMessage('reloadPrefs')` with a bare string instead of a message object `{ type: 'reloadPrefs' }`; MV3 requires an object and the call is unawaited. Fix: pass `{ type: 'reloadPrefs' }` and await/catch the result.
- [x] **P2 — `backup.ts` user-cancellation throws unhandled exception** — `restore()` and `setBackupDir()` call `window.showOpenFilePicker()` / `window.showDirectoryPicker()` without catching the `DOMException` thrown on user cancel. Surfaces as an uncaught promise rejection in Options. Fix: catch `DOMException` with name `'AbortError'` and silently ignore.
- [x] **P2 — `handleFetchMissingTitle` timeout fires after tab is closed** — `queueProcessor.ts:287` starts a 10-second `setTimeout` without storing the ID. When the happy-path listener fires first, the `finally` block closes the temp tab; 10 seconds later the timeout calls `chrome.tabs.get()` on the already-closed tab, generating a spurious runtime error. Fix: store the ID and `clearTimeout` when the listener resolves.
- [x] **P2 — `PageRow` edit modal form state not reset on dismiss** — The `onClose` callback only calls `setTodoEditOpen(false)` without resetting `editTodoTitle`, `editTodoPriority`, and `editTodoDueDate`. Re-opening the modal shows stale unsaved values. Fix: reset all three state variables in `onClose`.
- [x] **P2 — `EditTodoModal` allows saving priority/due-date with empty title** — `PageRow.tsx:123-132` skips `updateTodoTitle` when `title.trim()` is empty but still calls `updateTodoPriority` and `updateTodoDueDate`, leaving the DB inconsistent. Fix: disable Save when title is empty, or fall back to the stored title.
- [x] **P2 — `activateOrOpenTab` calls `activateTab` with undefined `tabId`** — `chromeNavigation.ts:15` calls `activateTab(windowId, tabId)` in the `else if (windowId)` branch where `tabId` is only defined in the `if (tab)` branch above. This is a dead no-op. Fix: remove the dead `activateTab` call.
- [x] **P2 — "Automate..." context menu item appears for todo items in `PageRow`** — `PageRow.tsx:406-408` shows the menu item unconditionally. For `todo://` URLs the `new URL()` call throws and generates a nonsensical pattern. Fix: hide when `page.completionStatus !== undefined`, matching the "Edit Todo..." guard.
- [x] **P2 — Add-todo button lacks disabled state when title is empty** — `TodoView.tsx` returns early from `handleAdd` when `newTitle.trim() === ''` but the button is always enabled; users get no feedback. Fix: disable the button when title is empty.
- [x] **P3 — Unused `loadPrefsFromDB` import in `dbSync.ts`** — `dbSync.ts:6` imports `loadPrefsFromDB` and never uses it. Remove.
- [x] **P3 — `fetchPagesByTabId` is a dead stub** — `pages.ts:631` exports `(tabs: Tab[]) => {}`, never implemented or called. Remove.
- [x] **P3 — Empty `highlighted` reducer** — `windowsSlice.ts:365` registers a `highlighted` action with a no-op body. Either implement it or delete it.

## 2026-04-03
- [x] "syncing from browser" has become exceptionally slow.  Did some recent change cause some database contention or async problems?

## 2026-04-03
- [x] crashed with "Maximum call stack size exceeded"

## 2026-04-03
- [x] Add a UI affordance for turning an existing web page into a todo.

## 2026-04-03
- [x] Call the priorities "P0", "P1", and "P2".  Wherever these show up, color-code them and make them bold-- including in the priority selector

## 2026-04-03
- [x] Window modification times are still reset when the extension reloads.  I forget what decision we made about this previously.  Can we instead use the max of the timestamps when a tab within the window was activated?

## 2026-04-05
- [x] Generating embeddings is very slow.  Can anything be done to make that faster?  Also I'm concerned that queuing a large number of embeddings produces some database or async contention and may be the cause of mysterious crashes.

## 2026-04-06
- [x] The extension occasionally crashes, with no informative messages in the logs.  Look for any possible causes-- memory leaks, fork bombs, etc.

## 2026-04-06
- [x] Make no code changes; this just triggers the worker to run a build

## 2026-04-06
- [x] add tabvana build and publish download site

## 2026-04-06
- [x] add tabvana build and publish download site

## 2026-04-06
- [x] Replace the readme with a new one describing the project and its features

## 2026-04-06
- [x] Add a button to the header to reload the extension during development.  Maybe protect this with a "dev mode" flag, which can just be true for now.

## 2026-04-06
- [x] Design an icon for the extension for use in the url bar
