Implementation plan: wave-based decomposition; waves 1-2 decomposed (11 tasks)
docs/plans/implementation.md records the wave structure (core -> substrate fork || pg engine -> sqlite engine -> contract suite -> release), the decided points (contract-suite layout = option (a), engine-tests vs equivalence-suite split, no CI, mem-engine/fuzzing deferrals surfaced), and the review-gate rhythm. Wave 1 (foundations): workspace scaffold, core errors/validation, value types, trait surface, contract-suite scaffold (+ADR-022), review gate. Wave 2 (substrate fork): fork scaffold/provenance, connection+watcher port, queue-op re-derivation on contract v1, provenance/floor close, review gate.
This commit is contained in:
1 parent
83767e880b
commit
49743c690e
12 files changed
+1009
No files matched your search
@@ -0,0 +1,117 @@
|
||||
---
|
||||
id: core-trait-surface
|
||||
name: Core trait surface (Store, TxHandle, mechanism handles, receivers)
|
||||
status: pending
|
||||
depends_on: [core-value-types]
|
||||
scope: moderate
|
||||
risk: medium
|
||||
impact: project
|
||||
level: implementation
|
||||
tags: [wave-1, core]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Implement the core crate's full trait surface — contract v1 in code.
|
||||
Every shape is pinned by ADR text; this task is faithful transcription,
|
||||
and it is the surface both engines implement in waves 3–4, so shape
|
||||
errors here are the expensive kind. The wave-1 review gate checks this
|
||||
task line-by-line against the ADRs.
|
||||
|
||||
**`Store` trait** (ADR-008 §1/§6, ADR-019 §1, ADR-009 §1):
|
||||
|
||||
```text
|
||||
begin_tx() -> Box<dyn TxHandle + Send>
|
||||
notify(channel, payload)
|
||||
listen(channel) -> Box<dyn WakeReceiver>
|
||||
stream(name) -> Box<dyn StreamHandle>
|
||||
queue(name, opts) -> Box<dyn Queue>
|
||||
outbox(name) -> Box<dyn Outbox>
|
||||
try_lock(name, owner, ttl) -> Option<Box<dyn Lock>>
|
||||
schedule(name, spec, queue, payload, opts) -> Result<Schedule>
|
||||
unschedule(name) -> bool
|
||||
run_schedules(stop: StopToken) -> Result<()>
|
||||
```
|
||||
|
||||
Constructors/options live in engine crates (ADR-008 §6) — core defines
|
||||
only the trait. Name-bearing methods validate at the entry point
|
||||
(shared helper from `core-errors-and-validation`); the trait's doc
|
||||
contract states that obligation (engines must reject before any round
|
||||
trip, on auto-commit and tx paths alike).
|
||||
|
||||
**`TxHandle` trait** (ADR-008 §2, ADR-014, ADR-015 §2, ADR-021 §1/§4):
|
||||
`enqueue_tx`, `publish_tx`, `publish_with_key_tx`, `notify_tx`,
|
||||
`save_offset_tx`, `get_job_tx`, `get_offset_tx`, `read_since_tx`,
|
||||
`read_from_consumer_tx`, `outbox_enqueue_tx`, `commit(self:
|
||||
Box<Self>) -> Result<()>`. Drop = rollback is an engine obligation
|
||||
stated in the trait docs. No generic methods (object safety); payloads
|
||||
cross as `serde_json::Value`; async methods use the boxed-future form
|
||||
(family-standard async trait posture).
|
||||
|
||||
**Mechanism handles** (ADR-019 §1, exact method sets): `Queue { name,
|
||||
enqueue, claim_one, claim_batch, ack_batch, cancel, get_job,
|
||||
sweep_expired }`; `StreamHandle { name, publish, publish_with_key,
|
||||
read_since, read_from_consumer, save_offset, get_offset, trim_to,
|
||||
subscribe }`; `Outbox { name, enqueue, run_once }`; `Lock { name,
|
||||
renew, release(self: Box<Self>) }`; `JobHandle { job(&self) -> &Job,
|
||||
ack(self), retry(self, err, delay) -> bool, fail(self, err) -> bool,
|
||||
heartbeat(self, extend) -> bool }` — the one-shot/repeatable split is
|
||||
deliberate (heartbeat takes `&self`).
|
||||
|
||||
**Receivers** (ADR-008 §3/§8): `WakeReceiver { recv() ->
|
||||
Option<Wake>, try_recv() -> Result<Option<Wake>>, recv_timeout(d) ->
|
||||
Result<Option<Wake>> }` (timeout expiry = `Ok(None)`; `Err` carries
|
||||
`Database`/`Closed` only); `EventReceiver { recv() ->
|
||||
Option<Result<StreamEvent>>, try_recv() -> Result<Option<StreamEvent>>,
|
||||
read_since(offset, limit) -> Result<Vec<StreamEvent>>,
|
||||
save_offset(&mut self) -> Result<()>, offset() -> i64 }` — no
|
||||
`recv_timeout` on `EventReceiver` (deliberate absence, ADR-008 §8
|
||||
third-round annotation).
|
||||
|
||||
**`run_once` delivery callable** (ADR-019 §5): consumer-supplied async
|
||||
callable taking `Box<dyn JobHandle>`, returning the boxed future of
|
||||
`Result<()>`; object-safe encoding (named one-method trait object or
|
||||
`&mut dyn FnMut` form — implementer's choice under the pinned
|
||||
semantics).
|
||||
|
||||
`with_tx` (ADR-007, signature pinned 2026-10-07): `with_tx(f) ->
|
||||
Result<()>` with `f: FnOnce(&mut dyn TxHandle) -> BoxedFuture<Result<()>>`
|
||||
— `Ok` ⇒ commit, `Err`/drop/panic ⇒ rollback; non-generic, values
|
||||
return through captured state, no handle escapes the closure. This
|
||||
lives on the `Store` trait as a provided method (default body over
|
||||
`begin_tx`).
|
||||
|
||||
All traits re-exported from `src/lib.rs`. Doc comments carry the
|
||||
pinned semantics (guarantee-row references, validity predicate,
|
||||
drop=rollback, no-claim_tx absence rationale).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Every trait above with the exact pinned method sets and
|
||||
signatures; compiles as object-safe (`Box<dyn ...>` everywhere
|
||||
the contract says)
|
||||
- [ ] `with_tx` provided method present with the pinned signature
|
||||
- [ ] A compile-probe test constructs `Box<dyn TxHandle>`,
|
||||
`Box<dyn Queue>`, etc. from a trivial local impl, proving object
|
||||
safety of the whole surface
|
||||
- [ ] Trait docs state: entry-point validation obligation, drop =
|
||||
rollback, the uniform handle-op validity predicate reference,
|
||||
heartbeat's absolute-reset semantics, no `claim_tx` rationale
|
||||
- [ ] `cargo test -p alkstore`, clippy `-D warnings`, fmt clean
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/core-contract.md (the seam, mechanism contracts)
|
||||
- docs/architecture/decisions/008-contract-v1-pinning.md §1–§3, §6, §8
|
||||
- docs/architecture/decisions/007-transactional-seam.md
|
||||
- docs/architecture/decisions/014-outbox-tx-enqueue.md
|
||||
- docs/architecture/decisions/019-mechanism-handle-surfaces.md §1–§5
|
||||
- docs/architecture/decisions/021-tx-reads-and-value-shape-fixes.md
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
Reference in new issue
Block a user