Proves the D4 purity invariant: delete the cache → resync → no durable truth lost. The cache is a rebuildable index over gitea, never a source of truth. Two tests, one per durable cache that actually exists:
packages/core/src/cache/cache-purity-v0.test.ts — file-backed node:sqlite (main binds better-sqlite3 to the same CacheDriver seam). Build the SQLite mirror from a representative gitea snapshot (open+closed, milestones, reassignment, empty labels), capture every re-derived field, rm the .sqlite file, rebuild from the same snapshot → assert byte-identical. Plus a structural D4 guard: every issues column must map to a gitea field, so a future user-authored column that would break rebuild-ability fails the test instead of silently breaking the invariant.
apps/desktop/src/main/snapshot-store.test.ts — the shipped durable cache is the JSON snapshot-store. Delete the file → loadSnapshot returns null (degrades to no-cache, never throws), which forces the next getSnapshot to reconcile fresh from gitea. Corrupt/partial files likewise. This stands up vitest for the desktop main process (first unit tests there); electron is mocked, the snapshot path is injected.
Scope note — no native better-sqlite3 shipped
The SQLite mirror has no consumer on any hot path yet (scheduler/forecast/agent all run off the in-memory reconcile snapshot). Wiring it into main — native module + electron-rebuild + asarUnpack + a fresh .dmg re-verify — would add packaging risk for zero runtime benefit and put the verified .dmg at risk. The purity invariant is proven at the seam for both caches; the native driver migration is deferred until SQLite is load-bearing.
Closes #30.
Proves the D4 purity invariant: **delete the cache → resync → no durable truth lost.** The cache is a rebuildable index over gitea, never a source of truth. Two tests, one per durable cache that actually exists:
**`packages/core/src/cache/cache-purity-v0.test.ts`** — file-backed `node:sqlite` (main binds better-sqlite3 to the same `CacheDriver` seam). Build the SQLite mirror from a representative gitea snapshot (open+closed, milestones, reassignment, empty labels), capture every re-derived field, **`rm` the .sqlite file**, rebuild from the same snapshot → assert byte-identical. Plus a **structural D4 guard**: every `issues` column must map to a gitea field, so a future user-authored column that would break rebuild-ability fails the test instead of silently breaking the invariant.
**`apps/desktop/src/main/snapshot-store.test.ts`** — the *shipped* durable cache is the JSON snapshot-store. Delete the file → `loadSnapshot` returns `null` (degrades to no-cache, never throws), which forces the next `getSnapshot` to reconcile fresh from gitea. Corrupt/partial files likewise. This stands up **vitest for the desktop main process** (first unit tests there); electron is mocked, the snapshot path is injected.
### Scope note — no native better-sqlite3 shipped
The SQLite mirror has no consumer on any hot path yet (scheduler/forecast/agent all run off the in-memory reconcile snapshot). Wiring it into main — native module + electron-rebuild + `asarUnpack` + a fresh .dmg re-verify — would add packaging risk for zero runtime benefit and put the verified .dmg at risk. The purity invariant is proven at the seam for **both** caches; the native driver migration is deferred until SQLite is load-bearing.
### Verification
- core: 157 passed (incl. 3 new purity tests) · `tsc --noEmit` clean
- desktop: 4 passed (new suite) · `tsc --noEmit` clean
🤖 Generated with [Claude Code](https://claude.com/claude-code)
christian
added 1 commit 2026-07-09 22:03:07 +00:00
The cache is a rebuildable index over gitea, never a source of truth (D4).
Two tests lock that invariant where the durable cache actually lives:
- packages/core: cache-purity-v0.test.ts — file-backed node:sqlite. Build the
SQLite mirror from a gitea snapshot, capture every re-derived field, delete the
.sqlite file, rebuild from the same snapshot, assert byte-identical. Plus a
structural D4 guard: every issues-table column must map to a gitea field, so a
future user-authored column can't silently break rebuild-ability.
- apps/desktop: snapshot-store.test.ts — the shipped durable cache is the JSON
snapshot-store. Delete the file → loadSnapshot returns null (degrades to
no-cache, never throws), which is what forces the next getSnapshot to reconcile
fresh from gitea. Corrupt/partial files are likewise treated as no-cache.
Stands up vitest for the desktop main process (first unit tests there);
electron is mocked, snapshot path is injected.
No native better-sqlite3 shipped: the SQLite mirror has no consumer on any hot
path yet, so wiring it into main (native module + asarUnpack + dmg re-verify)
would add packaging risk for no runtime benefit. The purity invariant is proven
at the seam for both caches; the native driver migration is deferred until
SQLite becomes load-bearing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #30.
Proves the D4 purity invariant: delete the cache → resync → no durable truth lost. The cache is a rebuildable index over gitea, never a source of truth. Two tests, one per durable cache that actually exists:
packages/core/src/cache/cache-purity-v0.test.ts— file-backednode:sqlite(main binds better-sqlite3 to the sameCacheDriverseam). Build the SQLite mirror from a representative gitea snapshot (open+closed, milestones, reassignment, empty labels), capture every re-derived field,rmthe .sqlite file, rebuild from the same snapshot → assert byte-identical. Plus a structural D4 guard: everyissuescolumn must map to a gitea field, so a future user-authored column that would break rebuild-ability fails the test instead of silently breaking the invariant.apps/desktop/src/main/snapshot-store.test.ts— the shipped durable cache is the JSON snapshot-store. Delete the file →loadSnapshotreturnsnull(degrades to no-cache, never throws), which forces the nextgetSnapshotto reconcile fresh from gitea. Corrupt/partial files likewise. This stands up vitest for the desktop main process (first unit tests there); electron is mocked, the snapshot path is injected.Scope note — no native better-sqlite3 shipped
The SQLite mirror has no consumer on any hot path yet (scheduler/forecast/agent all run off the in-memory reconcile snapshot). Wiring it into main — native module + electron-rebuild +
asarUnpack+ a fresh .dmg re-verify — would add packaging risk for zero runtime benefit and put the verified .dmg at risk. The purity invariant is proven at the seam for both caches; the native driver migration is deferred until SQLite is load-bearing.Verification
tsc --noEmitcleantsc --noEmitclean🤖 Generated with Claude Code