Files
alkstore/docs/architecture/engine-sqlite.md
T
glm-5.3-flash 4391f6e879 docs: open Phase 1 — architecture spec set over the Phase 0 evidence
docs/architecture/ now exists: README index, overview, five component
specs (core-contract, engine-sqlite, engine-postgres, queues,
deployment), ADR-001..007 carrying the Phase 0 resolved decisions
(crate split, feature scope, per-engine drivers, dependency
ownership, wake contract, tx seam), and the centralized
open-questions tracker promotion: OQ-ST-01..08 mirror to OQ-01..08
one-to-one with statuses/resolutions carried; new Phase 1 questions
append (OQ-09 scheduler collapse, OQ-10 contract versioning).
Open Phase 1 work: OQ-04 contract pinning (high), OQ-05 queue
semantics depth (high), OQ-06 honker-core quality read (high;
fork-trigger gate), OQ-08 capability surface, OQ-09, OQ-10.

Erratum fixed in phase-0 OQ-ST-04 (thread-affinity friction is
SQLite-side, previously garbled as pg-side) and a stale scheduler-
boundary pointer corrected in consumer-inventory.md. Two review
passes run (findings: OQ-promotion numbering faithfulness, ADR
back-reference sync) — all critical/warning findings resolved.
2026-10-04 18:13:10 +00:00

5.5 KiB
Raw Blame History

status, last_updated
status last_updated
draft 2026-10-04

SQLite engine

The alkstore-sqlite engine implements core-contract.md on rusqlite + published honker-core. This spec records WHAT the engine is internally (its connection architecture, seam, and wake plumbing) — not code-level HOW. Decisions live in ADRs; per-contract obligations live in the core spec and are not restated here.

Identity and posture

  • Single driver: rusqlite (riding honker-core's pin), bundled-sqlite for hermetic builds. No .so runtime artifacts, no vendored patches (ADR-003, ADR-001).
  • Sync machinery, async-facing trait: honker-core is sync (std threads, blocking iterators); the engine bridges at the trait seam per the family-standard posture (alktty REQ-TTY-01 precedent). Every engine call runs in spawn_blocking.
  • Single-host by nature: file-backed, one machine, NFS-two-writers unsupported (honker's honesty posture, inherited). See deployment.md.

Connection architecture

  • Writer — one dedicated connection; the only one permitted to write. Serializes all mutations (WAL single-writer, modeled honestly, not fought).
  • Readers — a small pool of read connections for lookups and claim/ack work.
  • Watcher — honker-core's SharedUpdateWatcher: a dedicated thread polling PRAGMA data_version at the default 1 ms cadence, fanning out to listeners, overtriggering on purpose (waking all subscribers per poll tick, even when several commits coalesced inside one tick — wake is a hint; consumers re-read indexed state, ADR-006).
  • Each connection runs honker's bootstrap at open: pragmas (WAL, synchronous=NORMAL, busy timeout), attach_notify, attach_honker_functions, bootstrap_honker_schema (the alknet-filesystem POC's wiring shape).

Mapping the contract

Contract piece Engine realization
notify / listen honker's notify functions inside the caller's tx; listen() bridges the watcher's fanout into a tokio receiver (one spawn_blocking thread per subscription doing blocking_send)
streams honker's stream machinery; explicit offset saves through the tx seam
queues honker's queue functions (ADR-002); semantics depth design in queues.md
named locks honker's lock machinery
scheduler / outbox honker's counterparts, per queues.md
begin_tx acquires the writer slot, opens BEGIN IMMEDIATE, returns the caller-held handle (ADR-007)
handle ops each *_tx op round-trips spawn_blocking to the same connection (thread-affinity note in ADR-007)
commit/rollback releases the writer slot

Obligations and constraints

  • A long transaction parks the writer (the slot lease is the honest model). Contract docs must surface this so consumers budget transactions (ADR-007 negative consequence).
  • Watcher failure handling is inherited: on watcher death, every subscriber's receiver closes (WatcherDeathGuard behavior) — consumers see the close, never a silent hang (ADR-006).
  • Wake coalescing: bursts inside one poll tick produce one wake; correctness is preserved by the re-read contract (POC-pinned: missed-wake stress with correct post-burst re-reads).
  • Deployment note: honker-core 0.5 pins rusqlite ^0.40.1, whose rustc floor is ≥ 1.99; binaries linking this engine carry that requirement (deployment.md matrix).
  • The optimization path, if seam throughput ever demands it: a dedicated std-thread bridge (one thread owning the writer conn, ops over mpsc — measured ~2× the spawn_blocking shape at p50 in POC #1), or a raised watcher cadence for idle CPU. Neither is the default.

What rides on the fork question

Nearly all of honker-core's surface is consumed (Writer/Readers/ SharedUpdateWatcher/attach_*). The quality read (OQ-06) is this engine's only open dependency gate: if it names a defect or an upstream-unwon't change, the fork posture (ADR-005) fires and this engine's substrate becomes owned code. Until then, published-library consumption stands.

Design Decisions

ADR Decision Summary
001 Crate split single-driver engine crate
002 Feature scope which rows this engine serves
003 Driver rusqlite + honker-core, bridged seam, inherited watcher
005 Ownership published honker-core; named fork triggers
006 Wake contract data_version watcher, coalescing, death-closes-receivers
007 Tx seam writer-slot lease, BEGIN IMMEDIATE, spawn_blocking round-trips

Open Questions

Open questions are tracked in open-questions.md. Key questions affecting this document:

  • OQ-06: honker-core quality read — fork-trigger assessment (open)
  • OQ-09: scheduler collapse into queues (shared with queues.md) (open)
  • OQ-05: queue semantics depth on honker's machinery (open)