Contract-suite scaffold: alkstore-contract-suite crate + ADR-022 (suite layout decision), engine dev-dep edges (ADR-017 §4.2 discharged, ADR-012 §2 mirror)
This commit is contained in:
1 parent
eefee9ec1d
commit
621415cc47
15 files changed
+1028
-7
No files matched your search
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-10-07 (ADR-021 + third-round follow-through resolved)
|
||||
last_updated: 2026-10-07 (ADR-022: contract-suite layout resolved)
|
||||
---
|
||||
|
||||
# alkstore — Architecture
|
||||
@@ -56,6 +56,7 @@ pending architecture review and OQ resolution.
|
||||
| [019](decisions/019-mechanism-handle-surfaces.md) | Mechanism-handle surfaces — handle traits (`Queue`/`StreamHandle`/`Outbox`/`Lock`/`JobHandle`), `Job`/`Schedule` shapes, `worker_id` identity, core `StopToken` | Accepted |
|
||||
| [020](decisions/020-enqueue-opt-semantics-and-bridges.md) | Enqueue-option semantics — delay/run_at precedence, relative `expires`, scheduler stamp source, serde_json payload encoding | Accepted |
|
||||
| [021](decisions/021-tx-reads-and-value-shape-fixes.md) | Third review round — tx-read methods on `TxHandle`, `Job.claimed_at`, `schedule()` queue-argument validation, drop = rollback, receiver close/error arms | Accepted |
|
||||
| [022](decisions/022-contract-suite-layout.md) | Contract-suite layout — shared internal suite crate, properties parameterized over a store factory (discharges ADR-017 §4.2's deferral) | Accepted |
|
||||
|
||||
## Open Questions
|
||||
|
||||
|
||||
@@ -211,6 +211,11 @@ not a runtime descriptor):
|
||||
shared crate, workspace test target, or per-engine module — is a
|
||||
test-side convenience decided at implementation
|
||||
([ADR-001](001-crate-split.md) §4's posture for test artifacts).
|
||||
*(Layout resolved 2026-10-07:
|
||||
[ADR-022](022-contract-suite-layout.md) — the shared internal
|
||||
`alkstore-contract-suite` crate; engines take it as a
|
||||
dev-dependency and drive the rows against their own stores via a
|
||||
`StoreFactory` the suite defines.)*
|
||||
3. **Engine-crate docs**: each engine's docs state the contract
|
||||
version(s) it implements — the same standing-statement altitude
|
||||
as its deployment posture (ADR-016 §3's carrier 2).
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
# ADR-022: Contract-suite layout — a shared internal suite crate, properties parameterized over a store factory
|
||||
|
||||
## Status
|
||||
|
||||
Accepted (2026-10-07, Phase 1 wave-1 — discharges
|
||||
[ADR-017](017-contract-versioning.md) §4.2's "layout decided at
|
||||
implementation" deferral)
|
||||
|
||||
## Context
|
||||
|
||||
[ADR-017](017-contract-versioning.md) §4.2 matured the verification
|
||||
backlog ([core-contract.md](../core-contract.md)
|
||||
§Verification backlog) into the *contract suite* — the pairing
|
||||
instrument whose version-stamped rows make "this engine implements
|
||||
contract vN" an auditable claim. What that ADR deliberately deferred
|
||||
was the suite's *layout*: shared crate, workspace test target, or
|
||||
per-engine module — "a test-side convenience decided at
|
||||
implementation ([ADR-001](001-crate-split.md) §4's posture for test
|
||||
artifacts)."
|
||||
|
||||
The implementation plan decoupled the decision from wave 5 (where the
|
||||
suite fills with cross-engine equivalence rows) and pulled the
|
||||
scaffold into wave 1, with the reasoning recorded in
|
||||
[implementation.md](../../plans/implementation.md): the 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, and
|
||||
the engine crates' dev-dependency edge existing early means wave 3/4
|
||||
tasks *adopt* the harness rather than debate it.
|
||||
|
||||
The candidate layouts, at implementation:
|
||||
|
||||
- **(a) A shared internal suite crate** — `alkstore-contract-suite`,
|
||||
`publish = false`, depending on core only; each engine crate takes
|
||||
it as a dev-dependency and drives the rows against its own factory.
|
||||
- **(b) A workspace test target** — the rows live as integration
|
||||
tests inside one workspace member (core, or a dedicated tests-only
|
||||
member), with engines contributing fixtures.
|
||||
- **(c) Per-engine modules** — each engine crate carries its own copy
|
||||
of the property set in its own test tree.
|
||||
|
||||
Shape facts that narrow the choice:
|
||||
|
||||
- The rows are parameterized over a *store factory*, not a store: each
|
||||
property needs a fresh store over an isolated backing store (fresh
|
||||
file / fresh schema) so rows never observe one another's state —
|
||||
something a shared fixture alone does not give.
|
||||
- The rows are *the same text* for both engines — that is the point of
|
||||
the equivalence pinning ([ADR-012](012-forked-substrate-design.md)
|
||||
§2: the engines' arithmetic is "tested into equivalence" by the
|
||||
suite). Two copies of a property is the classic drift surface: one
|
||||
copy gets strengthened and the other silently lags.
|
||||
- The suite is a dev-side instrument; nothing in it belongs on any
|
||||
published artifact's dependency graph (dev-dependency edges only).
|
||||
- [ADR-017](017-contract-versioning.md) §4.2 also pinned *per-row
|
||||
version stamps* (the contract change that added the row — the same
|
||||
no-silent-change discipline §2), and the version-stamp convention
|
||||
needed a normative owner decided now, since every later row cites it.
|
||||
|
||||
## Decision
|
||||
|
||||
**Option (a): the suite is a shared internal crate —
|
||||
`alkstore-contract-suite`**, unpublished (`publish = false`), a
|
||||
workspace member, depending on `alkstore` only (no driver deps, ever —
|
||||
the mirroring of [ADR-001](001-crate-split.md) §2's core rule keeps the
|
||||
suite compilable against any factory). Each engine crate takes it as a
|
||||
**dev-dependency** and drives the rows in its own test target against
|
||||
a factory it defines: a fresh store over an isolated backing store per
|
||||
run, plus teardown.
|
||||
|
||||
- **One normative owner per property** —
|
||||
[ADR-012](012-forked-substrate-design.md) §2's one-owner rule
|
||||
applied to test artifacts: each property's text, assertion strength,
|
||||
and version stamp live in exactly one place. Per-engine copies
|
||||
(option (c)) double the owners and drift; the suite crate is the
|
||||
single owner, engines are executors.
|
||||
- **A crate, not a test target** (over option (b)): the suite's rows
|
||||
must be *callable from each engine's* test binary — a dev-dependency
|
||||
is the Cargo mechanism for exactly that shape. It also gives the
|
||||
suite a compilation gate of its own and a `publish = false` marker
|
||||
recording its internal posture in the manifest, where
|
||||
[ADR-005](005-dependency-ownership.md)'s published-by-default
|
||||
default is answered in the artifact itself.
|
||||
- **The factory abstraction is the suite's API**: a minimal
|
||||
`StoreFactory` trait (open/fresh, teardown) over the boxed-future
|
||||
posture the contract traits use. The exact factory shape is
|
||||
deliberately *not frozen* — it may evolve as engines adopt the
|
||||
harness (wave 3/4 feedback); this ADR records the **layout**
|
||||
decision. Suite-side changes (rows, assertion strength, factory
|
||||
shape) are contract-non-events ([ADR-017](017-contract-versioning.md)
|
||||
§2 class 4 — the suite tests the contract, it is not contract
|
||||
surface); a suite row added to pin a *contract* addition carries
|
||||
that addition's ADR as its version stamp, and the class-2/3 change
|
||||
itself rides ADR-017's discipline on the core crate's side.
|
||||
- **The version-stamp convention is the suite crate's, documented
|
||||
there** ([version stamp module](../../../alkstore-contract-suite/src/version_stamp.rs)):
|
||||
a row's doc comment carries one `Contract stamp:` item per contract
|
||||
change that pinned the behavior tested, citing the ADR §. The
|
||||
exemplar row (entry-point name validation — empty → `InvalidName`,
|
||||
reserved prefix → `ReservedName`, auto-commit and tx paths alike)
|
||||
is stamped `ADR-008 §4` (+ ADR-021 §3, ADR-015 §2 for the rows its
|
||||
assertions encompass) and proves the harness end-to-end against a
|
||||
trivial in-crate mock store.
|
||||
|
||||
## Consequences
|
||||
|
||||
**Positive**
|
||||
|
||||
- The equivalence discipline has a mechanical home: one row text, run
|
||||
on both engines by their factories — the no-ghosts, ordering, and
|
||||
arithmetic-equality claims (wave 5's rows later) are one property
|
||||
each, not one per engine.
|
||||
- The engine/dev-dependency edge existing from wave 1 makes adoption
|
||||
the default path for waves 3/4 (their backlog-column tasks run the
|
||||
rows, not re-derive them) — the reason the scaffold was pulled
|
||||
forward from wave 5.
|
||||
- `publish = false` plus core-only deps keeps the artifact off every
|
||||
published graph and compilable anywhere (A mem-shaped engine, if
|
||||
wave 6 wants one ([ADR-001](001-crate-split.md) §4's deferral), can
|
||||
implement the same `StoreFactory` and reuse the suite verbatim).
|
||||
|
||||
**Negative**
|
||||
|
||||
- A dev-dependency edge is graph-visible but Cargo-weak: the suite
|
||||
cannot enforce that an engine actually *ran* it (dev-deps can be
|
||||
ignored by a careless release). The enforcement is process-side —
|
||||
the wave-3/4 review gates and [ADR-017](017-contract-versioning.md)
|
||||
§4.2's release-time suite requirement, the same honesty posture the
|
||||
rest of the pairing carriers ride.
|
||||
- The factory shape's latitude is a small standing surface: engines
|
||||
will each own a factory impl, and a shapes-drift (e.g. someone adds
|
||||
a pool-reuse knob) needs review discipline to keep the two
|
||||
implementations comparable. The ADR's stated rule — factory changes
|
||||
are suite-crate changes first — bounds it.
|
||||
|
||||
## References
|
||||
|
||||
- [ADR-017](017-contract-versioning.md) §4.2 — the deferral this ADR
|
||||
discharges; the version-stamp duty the convention implements; class
|
||||
4's suite-is-not-contract boundary.
|
||||
- [ADR-001](001-crate-split.md) §4 — the test-artifact posture the
|
||||
layout defers by; the mem-engine note's possible suite reuse.
|
||||
- [ADR-012](012-forked-substrate-design.md) §2 — the one-normative-
|
||||
owner rule the layout mirrors; the "tested into equivalence" framing.
|
||||
- [core-contract.md](../core-contract.md) §Verification backlog — the
|
||||
rows the suite matures from.
|
||||
- docs/plans/implementation.md "Decided points" — the wave-1 pull-
|
||||
forward rationale and the option-(a) record this ADR formalizes.
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-10-07 (ADR-021 — third review round: tx reads, value-shape fixes, schedule queue validation, drop=rollback, receiver arms)
|
||||
last_updated: 2026-10-07 (ADR-022 — contract-suite layout: shared internal suite crate)
|
||||
---
|
||||
|
||||
# alkstore — Overview
|
||||
@@ -85,6 +85,7 @@ Per [ADR-002](decisions/002-feature-scope.md):
|
||||
| [019](decisions/019-mechanism-handle-surfaces.md) | Mechanism-handle surfaces (handle traits, `Job`/`Schedule` shapes, `worker_id`, `StopToken`) | Accepted |
|
||||
| [020](decisions/020-enqueue-opt-semantics-and-bridges.md) | Enqueue-option semantics (delay/run_at, expires, scheduler stamp source, payload encoding) | Accepted |
|
||||
| [021](decisions/021-tx-reads-and-value-shape-fixes.md) | Third review round (tx-read methods on `TxHandle`, `Job.claimed_at`, `schedule()` queue-argument validation, drop = rollback, receiver close/error arms) | Accepted |
|
||||
| [022](decisions/022-contract-suite-layout.md) | Contract-suite layout (shared internal suite crate, store-factory parameterization) | Accepted |
|
||||
|
||||
## Non-goals
|
||||
|
||||
|
||||
Reference in new issue
Block a user