## What and why
Closes #
## Verification
- [ ] `npm test` —
- [ ] `npm run typecheck` — 0 errors (root + app)
- [ ] `npm run lint` — 0 errors
- [ ] `npm run test:electron:all` —
- [ ] New tests actually run in CI (`.github/workflows/`)
- [ ] No existing assertion was loosened
- [ ] Every capability described above was exercised end to end from the
outermost entry point (including anything shown in a screenshot)
- [ ] Re-ran the checks above on the current head, after the most recent merge
## Deliberately out of scope
---
Renderer / Electron UI — expand if you touched app/src/renderer or row rendering
- [ ] Reader-anchor assertion added — content settling above the viewport does
not move the row the user is looking at
- [ ] Async media covered at mount, size-available, and load/error — not only the
final state
- [ ] Tested both at rest and mid-scroll (`virtual-core` skips compensation for
measured rows when scrolling backward)
- [ ] No `loading="lazy"` on virtualized rows
- [ ] No hardcoded colors or type sizes in shadow DOM (`var(--muted)` etc.)
- [ ] One visual treatment per user-visible concept
- [ ] Library calling conventions either accept both shapes or are pinned in code
- [ ] Every renderer probe has a deadline and an `error` → reject path
- [ ] No assertion with sub-pixel headroom (self-calibrate instead)
Provider adapter — expand if you touched packages/core/src/providers
- [ ] Read `claude.ts`, `codex.ts`, and `kimi.ts` in full first
- [ ] Session identity is composite (e.g. normalized cwd + header id), not the
source id alone
- [ ] A test actually calls `discover()` against each supported directory layout
- [ ] Directory layout verified against upstream source or format docs
- [ ] Canonical transcript invariant holds: direct assembly == SQLite round-trip
(ADR-0007)
- [ ] Text-less records (image-only, aborted-with-usage) still emit a row
- [ ] `indexVersionMarker` bumped if uuid format, role normalization, or any
stored-row shape changed
- [ ] "Should not be displayed" uses `visibility`, not a new meaning for
`is_sidechain`
- [ ] Cursor detects same-millisecond rewrites (mtime + ctime + size + inode)
- [ ] Unknown/newer versions are skipped and recorded, not thrown on
Schema / migration — expand if you touched schema.sql or schema-migrations.ts
- [ ] `schema.sql` hash updated in `tests/provider-schema-stability.test.mjs`,
with justification above
- [ ] Destructive DDL runs inside `runWriteTransaction`
- [ ] Completion is not inferred from the target state's own name — interrupting
at any line self-heals on the next start
- [ ] Validation rejects anything SQLite would reject, before any mutation
- [ ] Checked that no table carries its own arguments that a blanket write would
erase
- [ ] External input spliced into DDL has an allowlist and an injection test
Main process / untrusted input — expand if you touched app/src/main
- [ ] Transcript-derived paths do not reach `shell.openPath` unguarded;
confirmation dialogs default to Cancel
- [ ] File reads triggered by transcript content are allowlisted to known roots
- [ ] No `innerHTML` / detached `
Indexing / daemon — expand if you touched indexer.ts, provider-indexing.ts, or write coordination
- [ ] Read-only while the daemon heartbeat is fresh — no write connection,
migration, PRAGMA change, checkpoint, or indexing
- [ ] Anything needing periodic refresh has a refresh point that is genuinely
called repeatedly, including on existing installations
- [ ] Configuration mismatch under `daemon_active` is an explicit error, not a
silent fall back to a stale index
- [ ] Trigger vs. full-rebuild choice is justified above