Follow-through on OQ-06/ADR-011: pin the fork's structural decisions (alkstore-substrate as a vendored path-dep crate, contract-blind API boundary with contract formulas computed engine-side and pinned equivalent by the contract suite, keep-the-kept-half API fidelity for cheap cherry-picks, the W-1/W-2/dead-man's-switch/W-4 port deltas decided per item, bootstrap re-keying off error-string matching, no rename migration, deliberate upstream tracking). Consistency sweep across the doc set for the fork: annotate ADR-003/ 005/009/010 and core-contract for superseded ownership facts, fix schedule-storage table naming (ADR-009 §5, queues.md), re-key ADR-010 §6's notifications hygiene to the at-attach cap the fork scope realizes, add OQ-11 (scaffold-time residue), and complete both ADR indexes. Independent review: 0 critical, warnings addressed.
4.0 KiB
ADR-001: Reactive-core crate + per-engine crates
Status
Accepted
Context
The store must present one reactive interface (notify, streams, queues, locks, scheduler, outbox) over two backing engines, SQLite and Postgres. The engines differ sharply in how much of that surface is natively theirs:
- The SQLite engine rides honker's existing, battle-tested machinery
(published
honker-core— a port-and-adapt of a sync library to the family's async-facing-trait posture). (Ownership since resolved: the substrate is forked into owned code — ADR-011.) - The Postgres engine is the build-heavy side: LISTEN/NOTIFY wiring and the pg-boss-family queue schema are built by this crate.
A single crate with feature-gated engines would force both engines'
dependency graphs into every downstream binary that enables both
features. That is not hypothetical: rusqlite 0.40's libsqlite3-sys
link collision with sqlx's sqlite driver is a real constraint
(see ADR-003); single-driver binaries are the
only clean escape.
Scope evidence lives in docs/research/consumer-inventory.md; the
operator decision was recorded 2026-10-04 against
OQ-ST-02 (docs/research/phase-0.md).
Decision
The project ships as a family of crates:
alkstore(core) — the crate carrying the unified trait surface, types, error model, capability flags, and the contract documentation. No driver dependencies. Compile-lean by construction: the base crate has no engine machinery to keep out.alkstore-sqlite— the SQLite engine implementing the core surface. Single driver: rusqlite + the forkedalkstore-substratelineage ([ADR-003]; ownership per ADR-011).alkstore-postgres— the Postgres engine implementing the core surface. Single driver: tokio-postgres + deadpool-postgres ([ADR-004]).- A mem-shaped engine (in-tree or separate test crate) may exist as a third implementation for tests and doctests, if the test story turns out to want it. Treated as an implementation convenience, not a contract artifact — decided at implementation time, not now.
Downstream consumers depend on alkstore plus exactly one engine
crate. A consumer binary links at most one driver.
Consequences
Positive
- The engines' asymmetry of work is structural: the SQLite engine has a small, mostly-wiring job; the Postgres engine carries the build-heavy LISTEN/queue work. Neither is burdened by the other's dependencies.
- Any future engine (alkfs's in-tree needs, an ops-surface engine) is additive — a new crate implementing the core traits — rather than a feature-graph edit to one crate.
- Core-lean is structural, not a feature-discipline to be enforced by review.
- The libsqlite3-sys link-collision class of problems is eliminated by construction (single-driver binaries).
- Per-engine compilation/test gates are independent.
Negative
- A version-coordination duty: the core's trait surface is a contract the engine crates must track. Version bumps in core must be adopted by engines in lockstep when the contract changes (minor/major discipline; no trait-default drift).
- Slightly more crate plumbing; naming/publishing overhead.
- Consumers who want both engines in one binary (rare, unsupported-by design) cannot get a both-features build today.
References
- OQ-ST-02 (
docs/research/phase-0.md) — the decision record with options considered. docs/research/consumer-inventory.md— the inventory whose lean (single crate) was superseded, with the correction recorded there.- ADR-003 — the SQLite driver choice whose link-collision constraint motivates this split.
- ADR-004 — the Postgres driver choice.
- OQ-10 (
docs/architecture/open-questions.md) — trait-versioning duties created here. [ADR-003]: 003-sqlite-driver.md [ADR-004]: 004-postgres-driver.md