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,111 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-10-07 (initial wave plan; waves 1–2 decomposed)
|
||||
---
|
||||
|
||||
# alkstore — Implementation plan
|
||||
|
||||
Wave-based decomposition of the architecture
|
||||
(`docs/architecture/`) into units of implementable work. This is a
|
||||
deliberate deviation from the SDD process's decompose-everything-upfront
|
||||
step: the architecture is large, early waves change the shape of later
|
||||
ones (the fork's outcomes feed the SQLite engine tasks; the contract
|
||||
suite's harness shape feeds both engines' verification work), and
|
||||
decomposing only the next wave or two at a time keeps each session's
|
||||
task set reviewable and lets later decompositions absorb earlier waves'
|
||||
course corrections.
|
||||
|
||||
Rhythm: decompose a wave → implement it → review gate → decompose the
|
||||
next wave. Task files live in `tasks/` (taskgraph-managed; frontmatter
|
||||
carries the categorical estimates). Wave boundaries are also review
|
||||
boundaries.
|
||||
|
||||
## The waves
|
||||
|
||||
Dependency logic in one line: core → (substrate fork ∥ postgres
|
||||
engine) → sqlite engine → contract suite → release readiness. The
|
||||
substrate fork is contract-blind (ADR-012 §2), so it needs only the
|
||||
workspace scaffold from wave 1; the Postgres engine needs only the core
|
||||
crate. Waves 2 and 4 are therefore independent of each other and could
|
||||
run in either order (or in parallel, if agents are ever available in
|
||||
parallel).
|
||||
|
||||
| Wave | Contents | Depends on | Status |
|
||||
|---|---|---|---|
|
||||
| [1](#wave-1--foundations) | Workspace scaffold; core crate (errors, value types, full trait surface); contract-suite scaffold | — | decomposed (`tasks/`) |
|
||||
| [2](#wave-2--sqlite-substrate-fork) | honker-core fork into `alkstore-sqlite/src/substrate/`: port, deltas, provenance, test floor | wave 1 (workspace scaffold only) | decomposed (`tasks/`) |
|
||||
| 3 | SQLite engine: connection architecture, re-derived queue ops on contract v1, scheduler/outbox, tx seam, SQLite backlog column | waves 1 + 2 | not yet decomposed |
|
||||
| 4 | Postgres engine: schema bootstrap, pool/open, listener/forwarder, all mechanisms, tx seam, pg backlog column | wave 1 | not yet decomposed |
|
||||
| 5 | Contract suite: the cross-engine equivalence properties (core-contract.md §Verification backlog), version-stamped per ADR-017 | waves 3 + 4 | not yet decomposed |
|
||||
| 6 | Release readiness: crate docs, deployment matrix final pass, README (written last, honestly), publish prep; mem-engine and fuzzing decisions | wave 5 | not yet decomposed |
|
||||
|
||||
## Wave 1 — Foundations
|
||||
|
||||
The core crate is contract v1 in code: the error taxonomy (ADR-008 §5),
|
||||
the value types (ADR-019 §3, ADR-020), the full trait surface
|
||||
(ADR-008 §1–§3/§8, ADR-014, ADR-019, ADR-021), and the payload encoding
|
||||
posture (ADR-020 §4). Nothing engine-specific lives here — no
|
||||
resolution arithmetic, no SQL. The equal-jitter curve, opts-stamping
|
||||
resolution, and boundary math are deliberately *not* core: ADR-012 §2
|
||||
pins each engine as the owner of one implementation, with equivalence
|
||||
pinned by the contract suite (wave 5).
|
||||
|
||||
The contract suite gets scaffolded now (not in wave 5) because its
|
||||
harness shape — a `Store`-factory-parameterized property crate — is
|
||||
easier to grow row by row as engines land than to retrofit onto two
|
||||
finished engines. Wave 5 fills it with the cross-engine equivalence
|
||||
rows; waves 3 and 4 adopt the harness for their own backlog columns.
|
||||
|
||||
## Wave 2 — SQLite substrate fork
|
||||
|
||||
The fork per ADR-011/012/013: port honker-core at `f4e53c6` into
|
||||
`alkstore-sqlite/src/substrate/`, apply the three watcher port deltas
|
||||
and the bootstrap re-keying, drop cron/experimental/cut-flag machinery,
|
||||
re-own the table family as `__alkstore_*`, carry `PROVENANCE.md` and
|
||||
the dual-license notice in-tree (ADR-018), and stand up the inherited
|
||||
test suites as the floor. The substrate stays sync and contract-blind;
|
||||
the engine layer that maps it onto the core contract is wave 3, not
|
||||
here. Reviewability against the lineage (ADR-012 §3) is a property the
|
||||
wave-2 review gate checks explicitly.
|
||||
|
||||
## Decided points
|
||||
|
||||
- **Contract-suite layout — option (a)**: a small internal
|
||||
`alkstore-contract-suite` crate (not published) exposing property
|
||||
tests parameterized over a `Store` factory; each engine crate takes
|
||||
it as a dev-dependency. One normative owner per property, mirroring
|
||||
ADR-012 §2's one-owner rule. This discharges ADR-017 §4.2's
|
||||
"decided at implementation" deferral; recorded as ADR-022 by the
|
||||
scaffold task.
|
||||
- **Engine tests vs. contract suite**: each engine wave carries its own
|
||||
mechanism tests (does the engine work); wave 5 carries the
|
||||
cross-engine *equivalence* properties (do the engines agree). The
|
||||
verification-backlog rows are mostly equivalence-shaped, so this
|
||||
split keeps wave 5 from re-testing engine internals.
|
||||
- **CI**: none, deliberately. CI and publishing are run manually
|
||||
(self-hosted Gitea; supply-chain posture). No CI-wiring task exists;
|
||||
the merge gates (`cargo test`, `cargo clippy --all-targets --
|
||||
-D warnings`, `cargo fmt --check`) are run coordinator-side.
|
||||
- **Mem engine** (ADR-001 §4) and **fuzzing adoption** (the
|
||||
alksocks/alktty/alktunnels pattern): both are "decided at
|
||||
implementation" deferrals, recorded here so they surface as explicit
|
||||
decision points in wave 6 (or earlier if the test story demands the
|
||||
mem engine sooner) rather than ambushing a later session.
|
||||
|
||||
## Review gates
|
||||
|
||||
Each wave ends in a review task (`review-wave-N`) before the next wave
|
||||
decomposes. Specific gates:
|
||||
|
||||
- **Wave 1 review** — the trait surface is versioned contract surface
|
||||
from the first release (ADR-017); a shape error found here is cheap,
|
||||
found in wave 5 it is a migration. Review checks the code against the
|
||||
pinned ADR text line by line.
|
||||
- **Wave 2 review** — diff reviewability against the honker lineage
|
||||
(ADR-012 §3's fidelity posture), provenance register completeness
|
||||
(ADR-018), floor tests green.
|
||||
- **Wave 3/4 reviews** — engine-vs-contract conformance; the backlog
|
||||
columns each engine owns.
|
||||
- **Wave 5 review** — the suite as compatibility instrument: every
|
||||
backlog row present, version-stamped, green on both engines; this is
|
||||
the gate that flips the engine specs to `stable`.
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
id: contract-suite-scaffold
|
||||
name: Contract-suite crate scaffold + ADR-022 (suite layout decision)
|
||||
status: pending
|
||||
depends_on: [core-trait-surface]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: phase
|
||||
level: implementation
|
||||
tags: [wave-1, contract-suite]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Scaffold the contract suite as a fourth, internal, unpublished crate —
|
||||
`alkstore-contract-suite` — per the layout decision recorded in
|
||||
docs/plans/implementation.md (option (a)): property tests
|
||||
parameterized over a `Store` factory, consumed by each engine crate as
|
||||
a dev-dependency. This discharges ADR-017 §4.2's "layout decided at
|
||||
implementation" deferral; the decision gets its own ADR (ADR-022) since
|
||||
it shapes the pairing instrument ADR-017 §4 names.
|
||||
|
||||
The crate:
|
||||
|
||||
- Workspace member, `publish = false`, depends on `alkstore` only.
|
||||
- Exposes a `StoreFactory` trait (or function alias — implementer's
|
||||
choice, but one shape, documented): something that yields a fresh
|
||||
`Box<dyn Store>`-shaped store over an isolated backing store (fresh
|
||||
file / fresh schema), plus teardown. The exact factory shape may
|
||||
evolve when engines adopt it (wave 3/4 feedback) — the ADR records
|
||||
the layout decision, not a frozen API.
|
||||
- A `tests/` harness that runs the property set against a supplied
|
||||
factory, structured so each backlog row is one named, independently
|
||||
runnable property with a version-stamp slot (ADR-017 §4.2: each row
|
||||
version-stamped with the contract change that added it — a
|
||||
doc-comment or attribute convention, decided here and used by every
|
||||
later row).
|
||||
- One exemplar property implemented end-to-end to prove the harness
|
||||
works — the reserved-name/empty-name validation property (pure
|
||||
contract, engine-independent, runnable against any factory): every
|
||||
name-bearing entry point rejects empty with `InvalidName` and
|
||||
reserved-prefix with `ReservedName`, on auto-commit and tx paths
|
||||
alike. This row is version-stamped `ADR-008 §4`.
|
||||
- Engine crates get the dev-dependency edge now (empty suite compiles
|
||||
against them trivially once they have code; the edge existing early
|
||||
means wave 3/4 tasks adopt the harness rather than debate it).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `alkstore-contract-suite` crate exists, `publish = false`,
|
||||
depends on core only, compiles in the workspace
|
||||
- [ ] Factory abstraction defined and documented; exemplar property
|
||||
(name validation) green against a trivial in-crate mock store
|
||||
- [ ] Version-stamp convention established and documented in the
|
||||
crate (used by the exemplar row)
|
||||
- [ ] ADR-022 written (`docs/architecture/decisions/022-contract-suite-layout.md`):
|
||||
option (a) chosen, rationale (one normative owner per property,
|
||||
ADR-012 §2 mirror), the factory-shape latitude stated, ADR-017
|
||||
§4.2 deferral discharged; ADR index tables in
|
||||
docs/architecture/README.md and overview.md updated
|
||||
- [ ] Engine crate manifests carry the dev-dependency edge
|
||||
- [ ] `cargo test` workspace-wide, clippy `-D warnings`, fmt clean
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/017-contract-versioning.md §4.2
|
||||
- docs/plans/implementation.md (Decided points)
|
||||
- docs/architecture/core-contract.md §Verification backlog
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
id: core-errors-and-validation
|
||||
name: Core error taxonomy and name validation
|
||||
status: pending
|
||||
depends_on: [scaffold-workspace]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: project
|
||||
level: implementation
|
||||
tags: [wave-1, core]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Implement the core crate's error taxonomy and the name-validation
|
||||
helpers every entry point shares.
|
||||
|
||||
**Error taxonomy** (ADR-008 §5, exact): one top-level `Error`,
|
||||
`thiserror`-typed, `#[non_exhaustive]` (ADR-017 §3 — mechanically
|
||||
enforces catch-all matching). Variants:
|
||||
|
||||
- `PayloadTooLarge { limit }` — universal variant; produced pg-side
|
||||
only (the occurrence asymmetry is engine work, not core's — core
|
||||
defines the variant and its doc text)
|
||||
- `ReservedName { name }`
|
||||
- `InvalidName { name }`
|
||||
- `Closed`
|
||||
- `Codec`
|
||||
- `Database` — the opaque fallback; engine detail rides the source
|
||||
chain (`#[source]`), no engine-specific variants ever minted
|
||||
|
||||
**Name validation** (ADR-008 §4): a shared validation helper applied at
|
||||
every name-bearing entry point — non-empty (`InvalidName`) and
|
||||
reserved-prefix rejection for the `__alkstore_` prefix
|
||||
(`ReservedName`). The helper distinguishes the two name classes:
|
||||
|
||||
- Shared-namespace kinds (channels, streams, queues, outboxes, locks,
|
||||
schedule names): non-empty + reserved-prefix rejected.
|
||||
- Consumer-local identifier classes (stream-consumer names, `owner` on
|
||||
`try_lock`, `worker_id` on claims): non-empty only — a leading
|
||||
`__alkstore_` is legal (ADR-008 §4 third-round annotation).
|
||||
|
||||
Also the reserved-string constant: `__alkstore_listener_reconnected__`
|
||||
(the one v1-reserved string, ADR-008 §4) — public in core so the pg
|
||||
engine and the contract suite reference the same constant.
|
||||
|
||||
`Result<T>` alias in the crate's prelude shape. No panics; no
|
||||
`unwrap()`/`expect()`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `Error` with exactly the six v1 variants, `#[non_exhaustive]`,
|
||||
`thiserror`-derived, `Database` carrying `#[source]`
|
||||
- [ ] Validation helper(s) covering both name classes, unit-tested
|
||||
(empty, whitespace-only, reserved-prefix, reserved string
|
||||
itself, legal names)
|
||||
- [ ] Reserved-string constant exported
|
||||
- [ ] `cargo test -p alkstore`, clippy `-D warnings`, fmt clean
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/008-contract-v1-pinning.md §4, §5
|
||||
- docs/architecture/decisions/017-contract-versioning.md §3
|
||||
- docs/architecture/core-contract.md §Errors, §Naming / reserved namespace
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
@@ -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
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
id: core-value-types
|
||||
name: Core value types (opts, Job, Schedule, StreamEvent, Wake, StopToken)
|
||||
status: pending
|
||||
depends_on: [core-errors-and-validation]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: project
|
||||
level: implementation
|
||||
tags: [wave-1, core]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Implement the core crate's value types — everything the trait surface
|
||||
(see `core-trait-surface`) takes and returns. Shapes are pinned; this
|
||||
task invents nothing.
|
||||
|
||||
**Opts structs** (ADR-008 §1, ADR-010 §3/§3a, ADR-020 §1–§3; NOT
|
||||
`#[non_exhaustive]` — ADR-017 §3, consumers construct them):
|
||||
|
||||
- `EnqueueOpts { delay: Option<i64>, run_at: Option<i64>, priority:
|
||||
i64, max_attempts: Option<i64>, expires: Option<i64> }` — `Default`
|
||||
gives all-`None`/priority 0. Field semantics (delay-over-run_at,
|
||||
relative expires) are *engine-side resolution* — core carries only
|
||||
the fields and their doc text.
|
||||
- `QueueOpts { visibility_timeout_s: i64, max_attempts: i64,
|
||||
backoff_base_s: i64, dead_letter_retention_s: Option<i64> }` —
|
||||
`Default` = 300/3/5/None (ADR-010 §3).
|
||||
- `ScheduleOpts { priority: i64, max_attempts: Option<i64>, expires:
|
||||
Option<i64> }` — types identical to their `EnqueueOpts` twins.
|
||||
|
||||
**Consumer-read types** — `#[non_exhaustive]` (ADR-017 §3):
|
||||
|
||||
- `Job` — the full ADR-019 §3 field list: `id: i64, queue: String,
|
||||
state: JobState, payload: Vec<u8>, priority: i64, run_at: i64,
|
||||
attempts: i64, max_attempts: i64, worker_id: Option<String>,
|
||||
claimed_at: Option<i64>, claim_expires_at: Option<i64>, created_at:
|
||||
i64, expires_at: Option<i64>, visibility_timeout_s: i64,
|
||||
backoff_base_s: i64, dead_letter_retention_s: Option<i64>,
|
||||
last_error: Option<String>, died_at: Option<i64>` — plus
|
||||
`payload_as<T>()` decoding stored bytes with `Codec` on failure
|
||||
(ADR-020 §4).
|
||||
- `JobState` enum: `Pending | Processing | Dead`.
|
||||
- `Schedule { name: String, spec: String, queue: String, opts:
|
||||
ScheduleOpts }` (ADR-019 §3).
|
||||
- `StreamEvent { offset: i64, stream: String, key: Option<String>,
|
||||
payload: Vec<u8>, created_at: i64 }` (ADR-015 §3) — plus
|
||||
`payload_as<T>()`.
|
||||
- `Wake { channel: String }` (ADR-008 §3).
|
||||
|
||||
**StopToken** (ADR-019 §4): `#[derive(Clone)]`, `cancel()` flips every
|
||||
clone, `is_cancelled()`. Core-owned; the await mechanics are
|
||||
engine-internal (tokio watch per engine) — core's token is the
|
||||
contract-visible handle. Implement with a `std::sync::Arc<AtomicBool>`
|
||||
or equivalent; engines may wrap their own watch channels around it.
|
||||
|
||||
**Payload encoding posture** (ADR-020 §4): the trait crosses
|
||||
`serde_json::Value`; core provides the encode helper (serialize the
|
||||
`Value` to bytes — the stored form) and the `payload_as<T>` decode
|
||||
convenience used by `Job`/`StreamEvent`. `serde`/`serde_json` are
|
||||
core's only dependencies.
|
||||
|
||||
All types re-exported from `src/lib.rs` (module-per-file under `src/`,
|
||||
family standard). Doc comments on public API carry the pinned
|
||||
semantics text (e.g. `heartbeat`'s absolute-reset note) — the docs are
|
||||
part of the contract.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] All types above with the exact pinned fields/types/derives;
|
||||
`#[non_exhaustive]` on read types, absent on opts structs
|
||||
- [ ] `Default` impls: `EnqueueOpts` (all-None/0), `QueueOpts`
|
||||
(300/3/5/None), `ScheduleOpts`
|
||||
- [ ] `payload_as<T>` round-trips a serde_json `Value` through encode →
|
||||
decode; non-serializable target type yields `Codec`
|
||||
- [ ] `StopToken`: cancel on a clone flips all clones; unit-tested
|
||||
- [ ] `cargo test -p alkstore`, clippy `-D warnings`, fmt clean
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/008-contract-v1-pinning.md §1, §3
|
||||
- docs/architecture/decisions/010-queue-semantics-depth.md §3, §3a
|
||||
- docs/architecture/decisions/015-streams-depth.md §3
|
||||
- docs/architecture/decisions/017-contract-versioning.md §3
|
||||
- docs/architecture/decisions/019-mechanism-handle-surfaces.md §3, §4
|
||||
- docs/architecture/decisions/020-enqueue-opt-semantics-and-bridges.md §1–§4
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
id: fork-port-connection-watcher
|
||||
name: Fork port — connection architecture + watcher machinery
|
||||
status: pending
|
||||
depends_on: [fork-substrate-scaffold]
|
||||
scope: broad
|
||||
risk: medium
|
||||
impact: component
|
||||
level: implementation
|
||||
tags: [wave-2, substrate]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Port the connection/watcher half of honker-core into
|
||||
`alkstore-sqlite/src/substrate/` — the machinery the quality read
|
||||
verified clean and ADR-011 §scope inherits near-verbatim. Source:
|
||||
`/workspace/honker/honker-core/src/` @ `f4e53c6` (`lib.rs` ~4k lines,
|
||||
`shm_watcher.rs`, `kernel_watcher.rs`).
|
||||
|
||||
**Port (the kept half, ADR-011 / quality-read §6):** the PRAGMA/WAL
|
||||
open posture + `set_journal_mode_wal` retry logic; `Writer`; `Readers`;
|
||||
the polling watcher + `SharedUpdateWatcher` + `WatcherDeathGuard` +
|
||||
`stat_identity` dead-man's switch; the `in_savepoint` /
|
||||
`UnwindUndo` mutation-discipline machinery; the REAL-coercion arg
|
||||
helpers; the notify scalar + notifications table; stream functions;
|
||||
lock functions.
|
||||
|
||||
**Port deltas (ADR-012 §4 — the only deliberate behavior changes):**
|
||||
|
||||
- W-1: bounded reconnect backoff in the watcher loop (no ~1000
|
||||
open-attempts/sec on a vanished db file).
|
||||
- W-2: watcher spawn becomes fallible; callers (the engine, wave 3)
|
||||
surface the failure at open time.
|
||||
- Dead-man's switch: the db-file-identity-change panic is replaced by
|
||||
a deliberate watcher-fatal death (log the precise diagnostic, exit
|
||||
through the ordinary death path); `WatcherDeathGuard`'s
|
||||
death-closes-subscribers behavior unchanged.
|
||||
|
||||
**Drops (do not port):** `cron.rs`; the `kernel-watcher` /
|
||||
`shm-fast-path` experimental watcher backends and their optional deps
|
||||
(`notify`, `memmap2`, `libc`); the rate-limit and result tables; the
|
||||
superseded queue functions (the queue half is re-derived in a separate
|
||||
task).
|
||||
|
||||
**Table naming:** `_honker_*` → `__alkstore_*` across the ported
|
||||
storage surface (ADR-011; ADR-010 §8 authorization). No online
|
||||
migration machinery — fresh bootstrap only (ADR-012 §5).
|
||||
|
||||
**Fidelity posture (ADR-012 §3):** keep upstream's module structure and
|
||||
internal function names for the kept half, including lineage tokens
|
||||
(`Writer`, `run_poll_loop`, `in_savepoint`). Renames confined to the
|
||||
table family and the hygiene deltas. The port is mechanical where
|
||||
possible — the diff against the lineage must stay reviewable.
|
||||
|
||||
**Discipline deltas (family standard, ADR-012 §4):** no comments in
|
||||
code (doc comments on the substrate's internal public surface fine),
|
||||
no panics in library code (the dead-man's-switch delta is the big
|
||||
one), no `unwrap()`/`expect()` outside tests. The substrate stays sync
|
||||
— no tokio, no asyncification.
|
||||
|
||||
**Bootstrap re-keying (ADR-012 §5):** the fork owns the bootstrap;
|
||||
append-column migrations stay; the duplicate-column race swallow is
|
||||
re-keyed to `pragma_table_info` verification (present ⇒ benign race,
|
||||
absent ⇒ propagate) — upstream's error-string matching is not
|
||||
inherited.
|
||||
|
||||
**Tests (the floor, ADR-011):** inherit honker-core's suites for the
|
||||
ported machinery — PRAGMA/WAL, watcher lifecycle + failure handling,
|
||||
savepoint + multiprocess pressure — adapted to the new table names and
|
||||
the three port deltas. These run as engine-crate tests (the substrate
|
||||
is not separately testable through a public seam).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Kept machinery ported with upstream names/structure preserved;
|
||||
diff vs. lineage reviewable (the wave-2 review checks this)
|
||||
- [ ] Three watcher deltas applied; dead-man's switch exits without
|
||||
panicking; `WatcherDeathGuard` still closes all subscribers
|
||||
- [ ] Dropped machinery absent (no cron, no experimental watchers, no
|
||||
rate-limit/result tables, no superseded queue functions)
|
||||
- [ ] Table family is `__alkstore_*`; bootstrap fresh-only; race
|
||||
swallow re-keyed to `pragma_table_info`
|
||||
- [ ] Inherited test suites green (adapted); watcher-death-closes-
|
||||
subscribers test present
|
||||
- [ ] Substrate is sync (no tokio imports); no panics/`unwrap()` in
|
||||
library code; clippy `-D warnings`, fmt clean
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/011-sqlite-substrate-fork.md (scope register)
|
||||
- docs/architecture/decisions/012-forked-substrate-design.md §3–§5
|
||||
- docs/research/quality-read-honker-core.md §6 (the fork scope), §2 (watcher verdict)
|
||||
- /workspace/honker @ f4e53c6 (the lineage)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
id: fork-provenance-and-floor
|
||||
name: Fork provenance register completion + inherited-test floor green
|
||||
status: pending
|
||||
depends_on: [fork-port-connection-watcher, fork-rederive-queue-ops]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: component
|
||||
level: implementation
|
||||
tags: [wave-2, substrate]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Close out the fork's bookkeeping and verify the test floor end-to-end
|
||||
(ADR-018's adoption discipline; ADR-011's tests clause):
|
||||
|
||||
- **`PROVENANCE.md` delta register**: entries for every delta the port
|
||||
actually made, category-tagged per ADR-018's categories — the three
|
||||
watcher deltas (W-1, W-2, dead-man's switch), the table-family
|
||||
rename, the bootstrap re-keying, the drops (recorded as
|
||||
not-ported), the re-derivation (new code, contract-derived names),
|
||||
and any mechanical adaptations the port surfaced that the plan
|
||||
didn't anticipate. Each entry: what, why, the decision citation.
|
||||
- **License/provenance cross-check**: the notice matches the actual
|
||||
ported content; the register's revision citation (`f4e53c6`) matches
|
||||
what was actually diffed.
|
||||
- **Test floor**: run the full engine-crate test suite (inherited +
|
||||
contract-property) as one gate; fix or explicitly record any
|
||||
inherited test that the deltas legitimately changed (e.g. the
|
||||
dead-man's-switch panic test becomes a watcher-fatal-death test).
|
||||
- **Lineage-diff sanity pass**: produce (locally, not committed) the
|
||||
diff of the substrate subtree vs. the honker-core sources at
|
||||
`f4e53c6` and skim it for accidental divergence — anything not
|
||||
covered by a register entry is either fixed or registered. This is
|
||||
the wave-2 review's primary input.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `PROVENANCE.md` register complete: every delta categorized and
|
||||
cited; no unregistered divergence from the lineage
|
||||
- [ ] License notice accurate; revision citation verified
|
||||
- [ ] Full substrate test floor green in one run; changed inherited
|
||||
tests documented in the register
|
||||
- [ ] Lineage diff skimmed; findings recorded
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/018-provenance-register-and-cherry-picks.md
|
||||
- docs/architecture/decisions/011-sqlite-substrate-fork.md (tests clause)
|
||||
- docs/research/quality-read-honker-core.md §6
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
@@ -0,0 +1,111 @@
|
||||
---
|
||||
id: fork-rederive-queue-ops
|
||||
name: Fork re-derivation — queue ops on contract v1 (stamps, claim, sweep, get_job)
|
||||
status: pending
|
||||
depends_on: [fork-port-connection-watcher]
|
||||
scope: broad
|
||||
risk: high
|
||||
impact: component
|
||||
level: implementation
|
||||
tags: [wave-2, substrate]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Re-derive the queue machinery in the substrate on contract v1 — the
|
||||
new-code half of the fork (ADR-011's re-derivation list; quality-read
|
||||
§6). This is the highest-risk task of wave 2: it is where ADR-010's
|
||||
semantics depth becomes SQL, and where the upstream defect class (the
|
||||
unreleased fix train's savepoint hardening, the `.ok()` error
|
||||
swallows) must be *not* inherited.
|
||||
|
||||
**Re-derive (contract-derived names; the substrate API stays
|
||||
contract-blind — primitives in, primitives out, ADR-012 §2):**
|
||||
|
||||
- **Enqueue + stamping** (ADR-010 §3a): job rows carry the
|
||||
`QueueOpts` stamps (`visibility_timeout_s`, `max_attempts`,
|
||||
`backoff_base_s`, `dead_letter_retention_s`) plus the `EnqueueOpts`
|
||||
resolution inputs. The *resolution rules* (delay-over-run_at,
|
||||
relative-expires, which stamps apply per call shape) are engine-layer
|
||||
work (wave 3) — the substrate's enqueue takes already-resolved
|
||||
primitive stamp values.
|
||||
- **Single-statement claim** with per-row visibility from the job's
|
||||
stamps: exactly-once handout under concurrency (POC-pinned shape),
|
||||
`attempts += 1` per claim, claim ordering `priority DESC, ready-time
|
||||
ASC, enqueue order`, claimant column stamped, `claimed_at` +
|
||||
`claim_expires_at` set (ADR-019 §3's `Job` fields; ADR-021 §2).
|
||||
- **Savepoint-guarded retry/fail/dead-letter** (ADR-010 §1–§4): the
|
||||
DELETE→INSERT dead-letter moves are savepoint-hardened (the #133
|
||||
defect class — a mid-flight error must strand the row in *neither*
|
||||
table); retry computes nothing itself (the engine passes the
|
||||
resolved delay in — the curve is engine-layer arithmetic per
|
||||
ADR-012 §2); budget exhaustion and `fail` move to dead with
|
||||
`last_error`/`died_at`; the pinned default strings (`"failed"`,
|
||||
`"max attempts exceeded"`) are engine-layer (contract-derived
|
||||
strings do not belong in the contract-blind substrate — pass them
|
||||
in).
|
||||
- **Both-states no-stranded-rows `sweep_expired`** (ADR-010 §5): moves
|
||||
every past-`expires_at` row (pending and processing) to dead with
|
||||
`last_error='expired'`, and enforces `dead_letter_retention_s`
|
||||
deletion. Single-statement atomic per queue.
|
||||
- **Dead-visible `get_job`** (ADR-010 §1): reads dead rows with
|
||||
stamps, `claimed_at`, `last_error`, `died_at` — the zombie hole and
|
||||
dead-visibility gap are the fork's motivating fixes; both land here.
|
||||
- **Handle-op validity predicate support** (ADR-010 §2): the
|
||||
ack/heartbeat/retry/fail transitions carry the uniform predicate
|
||||
(row `processing` + caller's claim deadline unexpired) — false, not
|
||||
error, on refusal; the ack-vs-reclaim race resolves atomically.
|
||||
- **Scheduler tick over the new enqueue** with `@every` next-boundary
|
||||
math (numeric, a few lines — cron machinery not ported): the
|
||||
`__alkstore_scheduler_tasks` storage, boundary advance + fire
|
||||
enqueue + row-locked advance, the 64-cap catch-up (ADR-009 §4). The
|
||||
leadership-lock loop pattern is ported with the lock machinery; the
|
||||
boundary math is the re-derivation.
|
||||
|
||||
**Schema:** the `__alkstore_*` job/dead/scheduler table family with the
|
||||
stamp columns and `claimed_at` (ADR-012 §5 — the re-derivation adds
|
||||
them); partial indexes matching the claim hot path, dead rows outside
|
||||
it, single clock source (second-precision timestamps), per queues.md
|
||||
§Namespaces.
|
||||
|
||||
**Tests:** the contract-property floor — no-stranded-rows, dead-visible
|
||||
`get_job`, stamps immutability, claim exclusivity under concurrency,
|
||||
the validity predicate's refusal boundaries, savepoint hardening
|
||||
(mid-flight-error stranding test), scheduler boundary/catch-up math.
|
||||
Plus the inherited queue-machinery tests adapted where applicable.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] All re-derived ops above present with contract-blind primitive
|
||||
APIs (no contract types, no error-taxonomy types in the
|
||||
substrate)
|
||||
- [ ] Savepoint hardening proven by test: a forced mid-flight error in
|
||||
the dead-letter move strands no row in either table
|
||||
- [ ] No `.ok()`-style error swallows (the D-class defects); all
|
||||
substrate errors propagate typed
|
||||
- [ ] Claim exclusivity under concurrent claims (multi-connection
|
||||
test); reclaim consumes an attempt; validity predicate refuses
|
||||
lapsed-deadline ops as values (false), not errors
|
||||
- [ ] `sweep_expired` moves both states; retention deletion enforced;
|
||||
no-stranded-rows property test green
|
||||
- [ ] Scheduler: boundary advance + fire atomic under row lock;
|
||||
64-cap catch-up; `@every` math unit-tested (s|m|h|d)
|
||||
- [ ] `get_job` sees dead rows with full stamp/error fields
|
||||
- [ ] `cargo test -p alkstore-sqlite`, clippy `-D warnings`, fmt clean
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/010-queue-semantics-depth.md (§1–§6, §8)
|
||||
- docs/architecture/decisions/009-scheduler-collapse.md §3–§4
|
||||
- docs/architecture/decisions/012-forked-substrate-design.md §2, §5
|
||||
- docs/research/quality-read-honker-core.md §3 (defect register), §6
|
||||
- docs/research/reference-honker-machinery.md (the lineage mechanics, file/line cites)
|
||||
- docs/architecture/queues.md (the semantics this realizes)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: fork-substrate-scaffold
|
||||
name: Fork scaffold — substrate subtree, provenance register, licenses
|
||||
status: pending
|
||||
depends_on: [scaffold-workspace]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: component
|
||||
level: implementation
|
||||
tags: [wave-2, substrate]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Create the fork's home and its provenance apparatus before any code
|
||||
moves (ADR-011, ADR-012 §1 as amended by ADR-013, ADR-018):
|
||||
|
||||
- `alkstore-sqlite/src/substrate/` module subtree, wired into the
|
||||
engine crate's module tree (`mod substrate;` — internal, never
|
||||
re-exported through the engine's public API; ADR-012 §2's
|
||||
contract-blind boundary starts structurally).
|
||||
- `PROVENANCE.md` at the subtree root per ADR-018: upstream identity
|
||||
(honker-core, checkout `/workspace/honker` @ `f4e53c6`, package
|
||||
`node-v0.5.1-10-gf4e53c6`), license (MIT OR Apache-2.0), the fork
|
||||
decision citation (ADR-011), and the empty delta register structure
|
||||
(per-delta, category-tagged entries — the categories ADR-018 pins;
|
||||
the port deltas of `fork-port-deltas` are the first entries).
|
||||
- The dual-license notice carried in-tree (MIT OR Apache-2.0 text, per
|
||||
ADR-012 §1's scaffold-time list).
|
||||
- The substrate's `Cargo.toml`-independent posture: the subtree
|
||||
compiles as engine-crate modules; its dependencies (rusqlite) come
|
||||
from the engine crate's manifest.
|
||||
|
||||
This task moves no machinery — it establishes where the fork lives,
|
||||
who it is, and how its lineage is tracked, so the port tasks land into
|
||||
a finished frame.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `src/substrate/` exists, wired as an internal module, empty or
|
||||
stub content only
|
||||
- [ ] `PROVENANCE.md` complete per ADR-018 (identity, revision,
|
||||
license, decision citation, delta-register structure)
|
||||
- [ ] Dual-license notice in-tree
|
||||
- [ ] Engine crate still compiles; clippy/fmt clean
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/011-sqlite-substrate-fork.md
|
||||
- docs/architecture/decisions/012-forked-substrate-design.md §1
|
||||
- docs/architecture/decisions/013-fold-substrate-into-sqlite.md
|
||||
- docs/architecture/decisions/018-provenance-register-and-cherry-picks.md
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: review-wave-1
|
||||
name: Review gate — wave 1 (core contract surface)
|
||||
status: pending
|
||||
depends_on: [core-trait-surface, contract-suite-scaffold]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: project
|
||||
level: review
|
||||
tags: [wave-1, review]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Review the wave-1 output before wave 2/3/4 work builds on it. The core
|
||||
trait surface is versioned contract surface from the first release
|
||||
(ADR-017) — a shape error found here is cheap; found in wave 5 it is a
|
||||
migration. This review is line-by-line against the pinned ADR text,
|
||||
not a general code review.
|
||||
|
||||
Check:
|
||||
|
||||
- **Trait surface vs. ADR text** — every method set and signature in
|
||||
`core-trait-surface` against ADR-008 §1–§3/§8, ADR-014, ADR-019 §1–§5,
|
||||
ADR-021: exact names, exact field types, the one-shot/repeatable
|
||||
split (`heartbeat(&self)` vs `self: Box<Self>` ops), the
|
||||
`recv_timeout`/no-`recv_timeout` asymmetry between the two receiver
|
||||
traits, `with_tx`'s pinned signature.
|
||||
- **Value types vs. ADR text** — `Job`'s full field list (including
|
||||
`claimed_at`, ADR-021 §2), `StreamEvent`'s shape (ADR-015 §3), opts
|
||||
structs' types and defaults (ADR-010 §3, ADR-020), the
|
||||
`#[non_exhaustive]` split (read types yes, opts structs no —
|
||||
ADR-017 §3).
|
||||
- **Error taxonomy** — exactly six variants, no extras; `Database`
|
||||
opaque with source chain; the pinning rule respected.
|
||||
- **Validation** — both name classes correct (shared-namespace vs
|
||||
consumer-local; ADR-008 §4 third-round annotation).
|
||||
- **Family standards** — no panics, no `unwrap()`/`expect()` outside
|
||||
tests, no comments in code (doc comments on public API fine),
|
||||
module-per-file, re-exports from `lib.rs`.
|
||||
- **Lean core** — no engine machinery, no resolution arithmetic, no
|
||||
SQL-shaped anything in core (ADR-012 §2's boundary).
|
||||
- **Suite scaffold** — ADR-022 exists and is coherent with ADR-017;
|
||||
exemplar property green; stamp convention usable.
|
||||
- **Gates** — `cargo test` (workspace), `cargo clippy --all-targets --
|
||||
-D warnings`, `cargo fmt --check` all green.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Every divergence from pinned ADR text found and fixed (or an ADR
|
||||
amendment proposed if the text itself is wrong)
|
||||
- [ ] All gates green
|
||||
- [ ] Findings recorded (task Summary or review notes)
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/008-contract-v1-pinning.md
|
||||
- docs/architecture/decisions/019-mechanism-handle-surfaces.md
|
||||
- docs/architecture/decisions/021-tx-reads-and-value-shape-fixes.md
|
||||
- docs/plans/implementation.md (Review gates)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: review-wave-2
|
||||
name: Review gate — wave 2 (substrate fork)
|
||||
status: pending
|
||||
depends_on: [fork-provenance-and-floor]
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: component
|
||||
level: review
|
||||
tags: [wave-2, review]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Review the substrate fork before wave 3 builds the engine on it.
|
||||
Primary lens: **diff reviewability against the lineage** (ADR-012 §3's
|
||||
fidelity posture — the fork's economics rest on future cherry-picks
|
||||
staying cheap) and **the defect class staying out** (the fork's
|
||||
reason for existing).
|
||||
|
||||
Check:
|
||||
|
||||
- **Fidelity**: the kept half's module structure and internal names
|
||||
match the lineage; renames confined to the table family and hygiene
|
||||
deltas; the diff vs. `/workspace/honker` @ `f4e53c6` contains
|
||||
nothing unregistered.
|
||||
- **Port deltas**: W-1/W-2/dead-man's-switch applied as decided; no
|
||||
other behavior changes smuggled in; W-4 (RW watcher connection)
|
||||
deliberately kept.
|
||||
- **Drops**: cron, experimental watchers + their optional deps,
|
||||
rate-limit/result tables, superseded queue functions — absent, and
|
||||
their absence registered.
|
||||
- **Re-derivation vs. ADR-010**: stamps land per §3a; the claim
|
||||
statement's ordering and visibility semantics match §1–§2; the
|
||||
validity predicate is uniform across ack/heartbeat/retry/fail;
|
||||
savepoint hardening real (test-read it, don't trust the test name);
|
||||
sweep covers both states; the curve/boundary arithmetic is *not* in
|
||||
the substrate (contract-blind boundary — ADR-012 §2).
|
||||
- **Provenance**: register complete and accurate per ADR-018; license
|
||||
notice correct.
|
||||
- **Family standards** in the substrate: sync only, no panics, no
|
||||
error swallows, no comments (doc comments fine).
|
||||
- **Gates**: full engine-crate test suite, clippy `-D warnings`, fmt
|
||||
clean.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Lineage diff reviewed; every divergence registered or fixed
|
||||
- [ ] Re-derivation matches ADR-010's pinned semantics (spot-checked
|
||||
against the ADR text, not just the tests)
|
||||
- [ ] Provenance register accurate
|
||||
- [ ] All gates green
|
||||
- [ ] Findings recorded; wave 3 decomposition may proceed
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/012-forked-substrate-design.md §3
|
||||
- docs/architecture/decisions/010-queue-semantics-depth.md
|
||||
- docs/architecture/decisions/018-provenance-register-and-cherry-picks.md
|
||||
- docs/plans/implementation.md (Review gates)
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
@@ -0,0 +1,70 @@
|
||||
---
|
||||
id: scaffold-workspace
|
||||
name: Cargo workspace scaffold (three crates per ADR-001)
|
||||
status: pending
|
||||
depends_on: []
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: project
|
||||
level: implementation
|
||||
tags: [wave-1, workspace]
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Create the Cargo workspace and the three crates of the ADR-001 split,
|
||||
so every later task lands in an existing, compiling structure:
|
||||
|
||||
- `alkstore` — the core crate (contract surface only; no driver
|
||||
dependencies, ever).
|
||||
- `alkstore-sqlite` — engine crate stub; manifest carries the rusqlite
|
||||
dependency (^0.40, `bundled` feature per ADR-003) and the core path
|
||||
dependency. No code yet beyond an empty lib.
|
||||
- `alkstore-postgres` — engine crate stub; manifest carries
|
||||
tokio-postgres 0.7.x + deadpool-postgres 0.14.x (ADR-004) and the
|
||||
core path dependency. No code yet beyond an empty lib.
|
||||
|
||||
Workspace-level: shared `[workspace.package]` fields (edition, license
|
||||
MIT OR Apache-2.0, repository), `resolver = "2"` (or 3 per edition),
|
||||
and a root `Cargo.toml` with `members`. Crate versions are `0.1.0`
|
||||
placeholders — ADR-017 §1 pins the initial *release* at 1.0.0; that
|
||||
bump is wave 6's release task, not this one.
|
||||
|
||||
The engines' manifests must pin the core dependency as a path
|
||||
dependency with the version field set (the ADR-017 §4.1 manifest-pin
|
||||
carrier) — `alkstore = { version = "0.1", path = "../alkstore" }`
|
||||
shape, so the pin exists from the first commit.
|
||||
|
||||
Family standards apply from this commit onward: tokio async runtime,
|
||||
`thiserror` errors, no panics in library code, no `unwrap()`/`expect()`
|
||||
outside tests, no comments in code (doc comments on public API fine).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `cargo build` at the workspace root compiles all three crates
|
||||
- [ ] `alkstore` has zero non-dev dependencies (serde/serde_json are
|
||||
the allowed exception — ADR-020 §4 puts payload encoding in core)
|
||||
- [ ] `alkstore-sqlite` depends only on `alkstore` + rusqlite;
|
||||
`alkstore-postgres` only on `alkstore` + tokio-postgres +
|
||||
deadpool-postgres (+ tokio)
|
||||
- [ ] Engine manifests carry the versioned core path pin (ADR-017 §4.1
|
||||
carrier 1)
|
||||
- [ ] `cargo clippy --all-targets -- -D warnings` and
|
||||
`cargo fmt --check` pass
|
||||
- [ ] No CI wiring is added (manual CI per docs/plans/implementation.md)
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/decisions/001-crate-split.md
|
||||
- docs/architecture/decisions/003-sqlite-driver.md (rusqlite pin)
|
||||
- docs/architecture/decisions/004-postgres-driver.md (pg driver pins)
|
||||
- docs/architecture/decisions/017-contract-versioning.md §4.1
|
||||
- docs/plans/implementation.md
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
Reference in new issue
Block a user