SQLite cache bootstrap + single-issue mirror upsert (#3) #55

Merged
christian merged 1 commits from feat/sqlite-cache into main 2026-07-09 21:53:29 +00:00
Owner

Lands #3's core seam: a rebuildable SQLite mirror of the reconciled backlog — an index over gitea's durable truth, never the source of truth (D4).

What

  • cache/cache-v0.ts: the 5-table schema (issues/labels/milestones/comments/issue_events); a CacheDriver injected-IO interface (exec/run/get/all); pure row↔domain mappers.
  • upsertIssue mirrors one issue (+ its milestone), upsert-by-number so re-reconciling updates in place, never duplicates. readIssue re-derives facts from the stored label set via extractLabelFacts — facts are never stored, so the mirror can't drift from the label semantics.
  • Resolves the issue's open scope: pure mappers + SQL in core (driver-agnostic), native driver in main. Tests bind node:sqlite (present in the Node 24 test runtime) to the same seam better-sqlite3 will fill.

Acceptance

Upsert one reconciled issue → read back → assert estimateDays/priority/hardDeadline (plus upsert-in-place, no-milestone, and cache-miss cases). 143 core tests green; typecheck clean.

Deliberately out of scope (follow-up)

The main-process better-sqlite3 adapter + migrating the JSON snapshot-store onto it. It's packaging-sensitive (native module → electron-rebuild + asarUnpack) and would need a fresh .dmg verification; kept separate so the shipped build stays green. #30 (purity/rebuild test) depends on that integration, so it stays blocked until then.

🤖 Generated with Claude Code

Lands #3's core seam: a rebuildable SQLite mirror of the reconciled backlog — an index over gitea's durable truth, never the source of truth (D4). ## What - **`cache/cache-v0.ts`**: the 5-table schema (`issues`/`labels`/`milestones`/`comments`/`issue_events`); a `CacheDriver` injected-IO interface (`exec`/`run`/`get`/`all`); pure row↔domain mappers. - `upsertIssue` mirrors one issue (+ its milestone), **upsert-by-number** so re-reconciling updates in place, never duplicates. `readIssue` **re-derives `facts` from the stored label set** via `extractLabelFacts` — facts are never stored, so the mirror can't drift from the label semantics. - Resolves the issue's open scope: pure mappers + SQL in **core** (driver-agnostic), native driver in **main**. Tests bind `node:sqlite` (present in the Node 24 test runtime) to the same seam better-sqlite3 will fill. ## Acceptance ✅ Upsert one reconciled issue → read back → assert `estimateDays`/`priority`/`hardDeadline` (plus upsert-in-place, no-milestone, and cache-miss cases). 143 core tests green; typecheck clean. ## Deliberately out of scope (follow-up) The main-process **better-sqlite3** adapter + migrating the JSON snapshot-store onto it. It's packaging-sensitive (native module → electron-rebuild + asarUnpack) and would need a fresh .dmg verification; kept separate so the shipped build stays green. **#30 (purity/rebuild test) depends on that integration**, so it stays blocked until then. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
christian added 1 commit 2026-07-09 19:31:01 +00:00
A rebuildable local mirror of the reconciled backlog — an index over gitea's
durable truth, never the source of truth (D4). This lands the core seam:

- `cache/cache-v0.ts`: the 5-table schema (issues/labels/milestones/comments/
  issue_events), a `CacheDriver` injected-IO interface (exec/run/get/all), and
  pure row<->domain mappers. `upsertIssue` mirrors one issue (+ its milestone),
  upsert-by-number so a re-reconcile updates in place; `readIssue` re-derives
  `facts` from the stored label set via extractLabelFacts, so the mirror can't
  drift from the label semantics. Facts are never stored.
- Resolves #3's open scope: pure mappers + SQL in core (driver-agnostic), native
  driver in main. Tests bind node:sqlite (present in the Node 24 test runtime) to
  the same CacheDriver seam better-sqlite3 will fill in main.

Acceptance met: upsert one reconciled issue, read back, assert
estimateDays/priority/hardDeadline (+ upsert-in-place, no-milestone, and miss
cases). Core suite green; typecheck clean.

Follow-up (noted in the plan): the main-process better-sqlite3 adapter +
snapshot-store migration — packaging-sensitive (native module), kept out of this
slice so the shippable .dmg stays verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
christian merged commit 481cacd99a into main 2026-07-09 21:53:29 +00:00
Sign in to join this conversation.
No description provided.