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:
glm-5.3-flash committed 2026-10-08 10:57:29 +00:00
1 parent 44637eea5b
commit 1269246faf
11 files changed
+883 -5

No files matched your search

+91
View File
@@ -0,0 +1,91 @@
---
id: sqlite-engine-queues
name: SQLite engine — queues (`Queue`, claims, job handles, backoff curve)
status: pending
depends_on: [sqlite-engine-seam-tx]
scope: moderate
risk: medium
impact: component
level: implementation
tags: [wave-3, sqlite-engine]
---
## Description
Implement `Store::queue` and the full `Queue` + `JobHandle` traits
over the substrate's re-derived queue ops (`enqueue`, `claim_batch`,
`ack`, `ack_batch`, `heartbeat`, `retry`, `fail`, `cancel`, `get_job`,
`sweep_expired` — wave 2's owned code):
- `queue(name, opts)` — validated constructor; the handle carries the
`QueueOpts` stamps future enqueues resolve over (ADR-010 §3a).
- `enqueue(payload, opts)` — the one handle-carrying shape: resolve
`EnqueueOpts` over **this handle's opts** (delay-over-`run_at`
precedence, relative-`expires` → absolute `expires_at`, per-call
`max_attempts` override — ADR-020 §1–§3); one clock read per
enqueue; `encode_payload` at the seam.
- `claim_one` / `claim_batch` — through the writer slot (claims are
writes); map the substrate's JSON row output into `Job` +
boxed `JobHandle`s. **Extent guard (ADR-023 §2)**: `n <= 0` yields
the empty `Vec` at the trait-impl entry, before the substrate —
`claim_batch(-1)` must never claim the whole queue (the `LIMIT -1`
dialect artifact dies here; the substrate passes `n` through
contract-blind). `worker_id` non-empty (`InvalidName`).
- `JobHandle` impl: `job()` (the row value), `ack`/`retry`/`fail`
(one-shot, `self: Box<Self>`), `heartbeat(extend)` (repeatable,
absolute reset). The uniform validity predicate is the substrate's;
refusals are `Ok(false)`, never errors.
- **The backoff curve — engine-side, this task**: `retry(err, None)`
computes the equal-jitter exponential from the job's stamped
`backoff_base_s`: `delay ∈ [base·2^(a−1)/2, base·2^(a−1)]`, capped
at 1 hour (ADR-010 §3's pinned formula — the engine owns one
implementation; wave 4 re-derives it identically and wave 5 pins
equivalence). Jitter needs a randomness source — use the substrate's
existing posture if one exists, else `std`-only (no `rand` dep
without a decision; a hash-of-id-and-time fallback is acceptable if
documented — flag the choice in Notes). `retry(err, Some(d))` passes
`d` through.
- `ack_batch(ids)` — per-id validity predicate, count returned.
- `cancel(job_id)`, `get_job(job_id)` (sees dead rows — map
`last_error`/`died_at`), `sweep_expired()` (no leader lock
required).
- Exhaustion dead-letters with the substrate's pinned default strings
(`"max attempts exceeded"`; `fail(None)` → `"failed"`).
## Acceptance Criteria
- [ ] Full `Queue` + `JobHandle` impls; enqueue→claim→ack lifecycle
works; stamps visible via `get_job` match the resolution rules
- [ ] Extent guard: `claim_batch(n <= 0)` claims nothing (empty
`Vec`, no error, never the whole queue) — pinned per ADR-023
§2's backlog row
- [ ] Exactly-once handout under concurrent claims (two workers, one
row — the POC-pinned property, engine-tested here)
- [ ] Backoff curve: `retry(err, None)` delays land in the pinned
range (statistical test over many retries, tolerance-bounded);
cap at 1 hour; `Some(d)` overrides
- [ ] Validity predicate: lapsed-deadline ops refuse with `Ok(false)`
(heartbeat, ack, retry, fail); reclaim consumes an attempt
- [ ] Dead-letter: exhaustion moves to dead with the pinned default
strings; `get_job` sees dead rows with `last_error`/`died_at`
- [ ] `sweep_expired` moves expired rows (both states) + applies
retention; returns the moved count
- [ ] `cargo test -p alkstore-sqlite`, clippy `-D warnings`, fmt clean
## References
- docs/architecture/core-contract.md (queues section)
- docs/architecture/decisions/010-queue-semantics-depth.md §1–§5
- docs/architecture/decisions/019-mechanism-handle-surfaces.md §2, §3
- docs/architecture/decisions/020-enqueue-opt-semantics-and-bridges.md §1–§3
- docs/architecture/decisions/023-fourth-review-round.md §2
- docs/architecture/queues.md (Retry/backoff, Dead-letter)
- alkstore-sqlite/src/substrate/queue_ops.rs
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion