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

114 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
status: draft
last_updated: 2026-10-04
---
# SQLite engine
The `alkstore-sqlite` engine implements
[core-contract.md](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](decisions/003-sqlite-driver.md)),
`bundled-sqlite` for hermetic builds. No `.so` runtime artifacts, no
vendored patches
([ADR-003](decisions/003-sqlite-driver.md),
[ADR-001](decisions/001-crate-split.md)).
- 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](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](decisions/006-wake-and-delivery-contract.md)).
- 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](decisions/002-feature-scope.md)); semantics depth design in [queues.md](queues.md) |
| named locks | honker's lock machinery |
| scheduler / outbox | honker's counterparts, per [queues.md](queues.md) |
| begin_tx | acquires the writer slot, opens `BEGIN IMMEDIATE`, returns the caller-held handle ([ADR-007](decisions/007-transactional-seam.md)) |
| handle ops | each `*_tx` op round-trips `spawn_blocking` to the same connection (thread-affinity note in [ADR-007](decisions/007-transactional-seam.md)) |
| 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](decisions/007-transactional-seam.md) 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](decisions/006-wake-and-delivery-contract.md)).
- 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](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)](decisions/005-dependency-ownership.md) is this engine's only
open dependency gate: if it names a defect or an upstream-unwon't
change, the fork posture
([ADR-005](decisions/005-dependency-ownership.md)) fires and this
engine's substrate becomes owned code. Until then, published-library
consumption stands.
## Design Decisions
| ADR | Decision | Summary |
|---|---|---|
| [001](decisions/001-crate-split.md) | Crate split | single-driver engine crate |
| [002](decisions/002-feature-scope.md) | Feature scope | which rows this engine serves |
| [003](decisions/003-sqlite-driver.md) | Driver | rusqlite + honker-core, bridged seam, inherited watcher |
| [005](decisions/005-dependency-ownership.md) | Ownership | published honker-core; named fork triggers |
| [006](decisions/006-wake-and-delivery-contract.md) | Wake contract | data_version watcher, coalescing, death-closes-receivers |
| [007](decisions/007-transactional-seam.md) | Tx seam | writer-slot lease, `BEGIN IMMEDIATE`, `spawn_blocking` round-trips |
## Open Questions
Open questions are tracked in
[open-questions.md](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](queues.md)) (open)
- **OQ-05**: queue semantics depth on honker's machinery (open)