Files
alkstore/tasks/contract-suite-scaffold.md

7.2 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
contract-suite-scaffold Contract-suite crate scaffold + ADR-022 (suite layout decision) completed
core-trait-surface
narrow low phase implementation
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

  • Factory shape (the implementer's choice): a named trait, StoreFactory { open() -> BoxedFuture<Result<Box<dyn Store>>>; teardown() -> BoxedFuture<Result<()>> } — chosen over a function alias because teardown needs an identity to be idempotent per instance (a bare fn can't carry "this factory's backing store"), and the async surface rides core's BoxedFuture posture so implementers need no macros. One shape, documented in src/factory.rs; the ADR records the layout, not a frozen API — wave 3/4 feedback may evolve it.
  • Version-stamp convention (the "decided here" row convention): a row's doc comment carries one Contract stamp: item per contract change pinning the behavior tested, citing ADR § (never bare "v1" or dates); stamps accumulate on amendment; greppable via the exported STAMP_MARKER constant. Normative statement lives in src/version_stamp.rs — every later row cites against it. The exemplar row is stamped ADR-008 §4 + ADR-021 §3 + ADR-015 §2 (its assertions span all three changes' behavior).
  • Assertion posture: rows panic on violation (labeled with the entry point and expectation) — the test-side-artifact relaxation of the family no-panic rule, documented in the crate docs as deliberate.
  • Exemplar scope: the property runs the full validation surface — all four Store constructor kinds (listen/stream/queue/ outbox), try_lock (both name and owner), schedule (both name and queue argument — ADR-021 §3), notify, and every name-bearing *_tx twin on TxHandle (all eleven, incl. ADR-015 §2's non-empty-key rule on publish_with_key_tx), plus a with_tx spot-check proving the commit-atomic path can't bypass validation. Happy-path spot-checks (stream/queue/try_lock with a reserved-prefixed owner) prove the rejections are the validation's doing, not store-wide failure.
  • Schedule is #[non_exhaustive] (ADR-017 §3): the mock cannot struct-construct it, so the mock's schedule() returns a Database stub after running the row-validation; the row asserts only the validation outcomes, and Schedule construction stays core's own tests' business. Same for the mock's subscribe (never exercised by the row). Noted so wave 3/4 factory impls copy the posture knowingly.
  • serde_json is a direct dep of the suite (not just core's): rows construct payload Values as contract surface (ADR-020 §4's trait crossing). No driver deps — the ADR-001 §2 mirror holds.
  • Dev-dep edges are path deps (path = "../alkstore-contract-suite") with no version: correct for an unpublished internal crate — a version key would be meaningless.
  • ADR-017 §4.2's text gained a layout-resolution annotation (dated, citing ADR-022) at the deferral site — the discharge is visible from the deferring document itself.

Summary

The alkstore-contract-suite crate is scaffolded per the option-(a) layout decision: publish = false, workspace member, depends on alkstore only (+ serde_json for payload construction). It defines the StoreFactory trait (open/teardown over an isolated backing store), the version-stamp convention (Contract stamp: doc-comment items, STAMP_MARKER constant, normative statement in version_stamp.rs), and the exemplar property name_validation_rejects_empty_and_reserved — full auto-commit + tx validation surface, stamped ADR-008 §4 / ADR-021 §3 / ADR-015 §2. A tests/suite_harness.rs runs it green against a trivial in-crate mock store + factory (3 tests: the exemplar row, happy-path construction, stamp-marker check). Engine crates carry the dev-dependency edge (path-dep). ADR-022 written (docs/architecture/decisions/022-contract-suite-layout.md): option (a) chosen, one-normative-owner-per-property rationale (ADR-012 §2 mirror), factory-shape latitude stated, ADR-017 §4.2 deferral discharged (with an annotation added at the deferral site); ADR index tables in docs/architecture/README.md and overview.md updated. Workspace cargo build, cargo test (26 tests workspace wide), cargo clippy --all-targets -- -D warnings, cargo fmt --check all clean.