Wave-3 decomposition: SQLite engine tasks (open/opts, seam+tx, mechanisms, integration, review gate) + core value-constructor pre-work; plan synced for waves-1-2 review + ADR-023 follow-through
This commit is contained in:
1 parent
44637eea5b
commit
1269246faf
11 files changed
+883
-5
No files matched your search
@@ -0,0 +1,102 @@
|
||||
---
|
||||
id: sqlite-engine-seam-tx
|
||||
name: SQLite engine — `spawn_blocking` seam, `begin_tx`, `TxHandle`, writer-slot lease
|
||||
status: pending
|
||||
depends_on: [sqlite-engine-open-opts]
|
||||
scope: moderate
|
||||
risk: high
|
||||
impact: component
|
||||
level: implementation
|
||||
tags: [wave-3, sqlite-engine, seam]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Implement the transactional seam — the highest-risk piece of the
|
||||
engine and the shape every other mechanism task rides:
|
||||
|
||||
- The `spawn_blocking` bridge helper: every engine call (auto-commit
|
||||
and tx ops alike) round-trips a blocking thread; rusqlite
|
||||
connections are not `Send`-across-await. Establish the pattern once
|
||||
(error mapping substrate `rusqlite::Error` → `Error::Database` with
|
||||
the source chain preserved — ADR-008 §5's opaque fallback) and reuse
|
||||
it everywhere.
|
||||
- `begin_tx`: acquire the writer slot (substrate `Writer::acquire`),
|
||||
open `BEGIN IMMEDIATE`, return the boxed `TxHandle`. The handle is
|
||||
the **writer-slot lease** (ADR-007): holding it across `await`
|
||||
points parks the writer — that is the design, not a defect.
|
||||
- `TxHandle` impl: every `*_tx` method routes through the same
|
||||
connection via `spawn_blocking` (thread-affinity is handled by the
|
||||
slot lease — the connection moves with the handle, ops serialize on
|
||||
it):
|
||||
- Writes: `enqueue_tx` (stamps the engine's derived plain-queue
|
||||
defaults 300/3/5/none — no-handle-open shape, ADR-020 §3a note),
|
||||
`publish_tx`, `publish_with_key_tx` (key validation per ADR-015
|
||||
§2), `notify_tx` (substrate's `notify()` SQL function inside the
|
||||
tx — delivered only at commit), `save_offset_tx` (monotone —
|
||||
substrate's upsert already is), `outbox_enqueue_tx` (derives the
|
||||
`__alkstore_outbox:{name}` backing queue name engine-side and
|
||||
stamps the outbox's 60/5/5 set — ADR-014 §1).
|
||||
- Reads (ADR-021 §1, read-your-own-writes — they run inside the
|
||||
caller's tx): `get_job_tx`, `get_offset_tx`, `read_since_tx`,
|
||||
`read_from_consumer_tx`.
|
||||
- `commit(self: Box<Self>)`: `COMMIT` + release the writer slot.
|
||||
- **Drop = rollback** (ADR-021 §4): the handle's `Drop` impl issues
|
||||
`ROLLBACK` and releases the writer slot — panic-safe (the drop runs
|
||||
across unwinds; no panic may escape drop). This is the property
|
||||
N-5's wave-5 probe will exercise against a real engine for the
|
||||
first time — get the Drop impl right here.
|
||||
- Name validation at every entry point via core's `validation` helpers
|
||||
(shared-namespace kinds vs consumer-local; ADR-008 §4 — the
|
||||
commit-atomic path must not bypass validation).
|
||||
- Payload encoding: call core's now-fallible `encode_payload` at the
|
||||
seam; `?` the `Codec` error (ADR-023 §1 — the engines' first
|
||||
consumption of the typed signature).
|
||||
|
||||
All eleven `*_tx` methods are implemented **for real** in this task —
|
||||
the substrate surface is fully ported (wave 2), so nothing stubs. The
|
||||
opts-resolution helpers this introduces (delay-over-`run_at`,
|
||||
relative-`expires`, the derived-default stamp sets) are the shared
|
||||
engine-side arithmetic the auto-commit mechanism tasks reuse — one
|
||||
owner per formula (ADR-012 §2), written once here. The mechanism tasks
|
||||
then add what the tx path deliberately lacks: the auto-commit handles,
|
||||
the extent/duration guards, the backoff curve, the receiver bridges,
|
||||
and the scheduler runner.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `begin_tx` acquires the writer slot + `BEGIN IMMEDIATE`;
|
||||
concurrent `begin_tx` blocks (slot lease) — tested
|
||||
- [ ] All eleven `*_tx` methods implemented with entry-point
|
||||
validation; writes commit-atomic, reads see the tx's own writes;
|
||||
opts resolution (delay-over-run_at, relative-expires, derived
|
||||
default stamp sets 300/3/5/none and 60/5/5) pinned by tests
|
||||
- [ ] `commit` commits + releases the slot; drop (without commit)
|
||||
rolls back + releases the slot — no-ghosts tested for job rows,
|
||||
stream events, notifications, and offset saves
|
||||
- [ ] Drop is panic-safe (a panic unwinding through a scope holding
|
||||
the handle still rolls back and releases the slot)
|
||||
- [ ] `with_tx` (core's provided method) works end-to-end on this
|
||||
engine: Ok ⇒ commit, Err ⇒ rollback — tested
|
||||
- [ ] `encode_payload`'s `Codec` error propagates from enqueue/publish
|
||||
paths (typed, not silent)
|
||||
- [ ] Substrate errors map to `Error::Database` with source chains
|
||||
- [ ] `cargo test -p alkstore-sqlite`, clippy `-D warnings`, fmt clean
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/007-transactional-seam.md
|
||||
- docs/architecture/decisions/021-tx-reads-and-value-shape-fixes.md §1, §4
|
||||
- docs/architecture/decisions/014-outbox-tx-enqueue.md §1
|
||||
- docs/architecture/decisions/020-enqueue-opt-semantics-and-bridges.md §1–§4
|
||||
- docs/architecture/decisions/023-fourth-review-round.md §1
|
||||
- docs/architecture/engine-sqlite.md (Mapping the contract: begin_tx, handle ops, commit/rollback)
|
||||
- alkstore/src/tx.rs (the trait to implement)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
Reference in new issue
Block a user