- impl EngineWindowState on PgLoBackend: ensure_gc_schema creates
gc_window only (never gc_pins, never the embedder's liveness
table), window_stage upserts idempotent per (key, deadline),
window_take is the one atomic DELETE ... RETURNING step over the
<= boundary with the 42P01 -> empty virgin-take split
- nothing of EngineFleetState exists on this engine (ADR-012 §5's
pg-lo row: fleet pins live on the kv host, sweep lock no); the
one-window-host dormancy posture is recorded in the impl doc
- five contract tests mirror the postgres/sqlite suites (schema-only
+ row shape, stage idempotence/restage, take-exact-set/never-twice,
the <= boundary with nanosecond slack, both virgin shapes);
env-driven, skipping cleanly server-less, green live against the
harness server
Verification: cargo test (default + --features pg-lo, server-less
and live), clippy -D warnings (default, pg-lo, + the pure builds
"pg-lo,mem" and "postgres,pg-lo"), cargo fmt --check, cargo doc --no-deps
Implement the pg-lo engine (ADR-009, POC #7 C1-C7) in src/pg_lo.rs
behind feature pg-lo (default-off), plus the shared-helper home the
task's design points resolve into src/pg_common.rs.
- Engine: seven Backend methods + put_staged; the lo_entries companion
table is the contract authority (list/size/has/CAS table-level;
pg_largeobject read only by the orphan sweep's candidate enumeration);
one-tx puts with 512 KiB lowrite statements (LOWRITE_CHUNK, the C2
knee), the descriptorless lo_get window cursor (READ_CHUNK; EOF
clamping + the unexpected-EOF clean failure), the held-tx staging
cursor aggregating 64 KiB windows, one-tx deletes, the complete
single-snapshot list, the 42P01 read-only virgin-store split, and the
crate-internal reap_orphans (scope-noted, planted-orphan contract
test). Posture deltas in the module doc (catalog space never
returned / VACUUM FULL runbook line / autovacuum inherited / the
cached-get capacity facts). Nothing of EngineFleetState; the window
family remains engine-pg-lo-window.
- Shared helpers (pg_err, 42P01, quote_identifier, size clamp, i64-nanos
encoding, build_pool, PgOpts, test janitors) move to src/pg_common.rs
gated cfg(any(postgres, pg-lo)); PgOpts's public re-export widens
(definition moved; crate::postgres::PgOpts path held by re-export);
src/postgres.rs's changes are mechanical swaps.
- LO isolation (C7 lesson): per-test dedicated databases + DatabaseJanitor
(WITH (FORCE)); zero LO/schema/database residue on the shared harness
db (pre-existing public.lo_entries exploration residue found and
removed).
- 18 in-module tests, env-driven (ALKBLOBS_PG_*), skipping cleanly
server-less; all green against the pglo-poc harness server.
Verified: cargo test (69/19/3), --features pg-lo live (87/19/3, 18/18
pg-lo), --features postgres live (103/36/3), --all-features (176/71/4);
clippy -D warnings green for default, pg-lo, postgres, all-features,
--no-default-features --features "pg-lo,mem" and "postgres,pg-lo";
cargo fmt --check; cargo doc --no-deps.
- PG-1: sweep_lock_acquire reaps a lease whose held session died
(in-instance session-loss reaping, ADR-013 §2) — previously the
mutex answered Ok(false) until an explicit release; new test
terminates the lease's own backend via pg_terminate_backend and
re-acquires without a release
- PG-3: the engine-level pg tests now drop their per-test schemas
(test_support::SchemaJanitor, the Harness deref-guard wrapper in
src/postgres.rs's tests, fresh_opts carrying a janitor in the
construction tests) — 380 leaked abt_* schemas on the shared
harness db are 0 after every run now
- PG-2: PgJointTx's doc records the mid-flight-drop hazard (deadpool
Fast recycle never resets transaction state; the clause bodies'
failure paths all ROLLBACK — the store core's joint-tx driver owes
pin_commit on every path from begin_joint_tx; wave 6 amendment)
Verification: cargo test (69/19/3), --features mem (124/54/4),
--features postgres vs server (103/36/3, 51 clean skips server-less),
--all-features vs server (158/71/4), pg-pure (76/19/3);
clippy -D warnings green (default/postgres/all-features/pg-pure);
fmt --check green; shared-db schema residue 0; cargo doc clean
- `KvEngine::Postgres` slotted in: all six kv-op dispatch arms, the
`KvCursor::Postgres` materializing body behind `AnyCursor`'s kv arm
(the recorded sub-enum design point, landed as predicted), and the
engine-neutral `ensure_gc_schema` call creating `gc_pins` +
`gc_window` in the fresh schema at construction (the fleet host's
both-tables row, ADR-012 §5)
- The two named constructors behind feature `postgres` (default-off):
`dual_tier_postgres_local(config, opts, root, threshold,
window_delay)` — the fleet-capable-kv production shape — and
`kv_only_postgres(config, opts, threshold, window_delay)`; the DSN
connection settings + engine opts ride the constructor parameters,
never invented defaults. `PgOpts` is pub and re-exported from
`lib.rs` (it is on the public constructor signature now)
- The sweep's durable form runs on the postgres host: the form body
extracted into `sweep_window_durable<W: EngineWindowState>` (sqlite's
arm delegates, behavior unchanged), both SQL-backed arms keyed off
the kv-engine enum, never a flag — wave 5's pg-lo dormancy slots in
without reshaping
- Non-fleet posture recorded on both constructors (ADR-012 §3):
implicitly `fleet: false`, the ADR-005 in-process protocol verbatim,
the `fleet: true` declaration is wave 6 and slots in without
reshaping
- Stale scope notes updated to the landed state (engine-representation
doc, `KvCursor` design point, fleet-declaration paragraph,
one-window-host paragraph, postgres module doc, gc.rs companion-seam
note); the batch-delete helper's scope note stays (wave 6 consumer)
- 5 new env-driven construction tests (skipping server-less): the
modes construct and introspect, both GC tables exist in the fresh
schema, the window-delay default is the pinned 5-min constant and
tunable (`0` legal), the kv-only rejection wiring is unchanged, the
dual-tier shape round-trips through both tiers, and the durable
form is observed staging/executing across sweeps on the postgres
host
Verification: `cargo test` 69/19/3 ok; `cargo test --features postgres`
102/19/3 ok live (pglo-poc harness) and green server-less;
`cargo test --no-default-features --features postgres` (the pg-pure
build, ADR-013 §4) 75/2/3 ok server-less; `cargo test --all-features`
157/54/4 ok; clippy `-D warnings` green (default, postgres, pg-pure,
all-features); `cargo fmt --check` green; `cargo doc --no-deps` clean.
- EngineWindowState: the both-tables ensure_gc_schema (gc_pins with the
(key, owner) identity + gc_window), idempotent window_stage (the
upsert discipline per (key, deadline)), and window_take as one atomic
DELETE ... RETURNING with the <= boundary
- EngineFleetState: PgJointTx (the pooled checkout carrying a
session-level BEGIN), joint_put (the CAS clause inside the held tx),
pin_commit (pin-row upsert-renewals + commit, rollback-on-failure =>
zero residue), pin_renew (expiry = now + DEFAULT_PIN_TTL, never
resurrects), pin_check (the two-variant classification), arbitrate
(the FOR UPDATE finger-lock folding pins + registered liveness-table
references), and the engine-side register_liveness_source home
- The sweep lease: the session-scoped pg advisory lock with the
namespaced FNV lock key and the same-connection acquire/release
holding discipline (the lease's checkout stored until release)
- 13 contract tests (28 postgres tests total), env-driven, skipping
cleanly server-less; verified green against the live pglo-poc
harness server; clippy/fmt green default + --features postgres
Verification: cargo test (69/19/3 ok), cargo test --features postgres
server-less (97 ok, 28 skips) and live (97 ok), cargo test
--all-features (152/54/4 ok), cargo clippy -D warnings (both configs),
cargo fmt --check, cargo doc --no-deps.
The 'postgres' kv-tier engine (ADR-007, feature 'postgres', default-off)
against the wave-1 trait: the sqlite engine's structural twin on a
Pooled-Postgres driver cluster.
- One engine-owned schema (default 'alkblobs'; quoted-identifier
boundary via the alkstore quote_identifier pattern) holding the B5
row shape — key bytea PK / value bytea NOT NULL / size bigint NOT
NULL, WITH (fillfactor = 90) — idempotently bootstrapped at
construction; autovacuum and the ~40x small-tier storage overhead
recorded as posture, not silence
- deadpool pool with DEFAULT_MAX_SIZE = 8 (load-bearing, POC #5 B2);
per-connection prepare_cached discipline (B5: statements die with
sessions); the synchronous_commit parity knob as connect options on
every pooled connection (default 'on', configurable, alkstore
src/opts.rs mechanics)
- CAS first-writer-wins (INSERT ... ON CONFLICT DO NOTHING) on both
put forms; metadata-only size probe riding the PK index (EXPLAIN
gate-tested); EXISTS has; materializing get cursor; degenerate
in-memory stage with both hygiene forms (fail_commit injection)
- list: the single-statement MVCC-snapshot cursor (portal-batched row
stream, keys only); crate-internal batch-delete helper
(DELETE ... WHERE key = ANY() over bytea[]), scope-noted until
wave 6; virgin-store read-only split via SQLSTATE 42P01 mapping
- 15 in-module unit tests, env-driven (ALKBLOBS_PG_*), skipping
cleanly server-less; green against the dockerized pglo-poc harness
server (:15432)
Verified: cargo test; cargo test --features postgres (84 lib tests);
cargo test --all-features (139); clippy all-targets, default +
features + all-features, -D warnings; fmt --check; doc --no-deps.
- resolve or unlink 25 preexisting rustdoc warnings: broken
intra-doc links (error variants), public-docs-linking-private-items
(crate-internal cursor/registry names), and one stale reference to a
`Store::window_host` that never existed (the form branch is
`sweep_window`'s engine-enum match)
- `clamped` runs its arithmetic in u64 and narrows to usize after
clamping, so a wide u64 offset can never wrap onto a small slice
position on narrow-pointer targets; the cursor contract tests pin
the overflowing-offset and overflowing-length forms
- zero rustdoc warnings under RUSTDOCFLAGS=-D warnings
Verification: cargo test (69+19+3 green), cargo test --all-features
(124+54+4 green), cargo clippy --all-targets -- -D warnings green,
cargo fmt --check green, RUSTDOCFLAGS=-D warnings cargo doc --no-deps
green.
Reviewed the wave-3 commits (engine-sqlite, engine-sqlite-window,
store-sqlite-construction, store-sweep-durable-window,
suite-column-sqlite) against the cited ADR/spec text line by line:
ADR-003/007/008 §2, ADR-010 §2, ADR-012 §1/§5/§6.7, store-api.md,
implementation.md §Review gates — the engine-vs-contract conformance
(suite column green server-less in the default build; the window
family contract-tested per its applicability row; virgin-store
semantics incl. the no-tables-yet form; the size metadata-only
discipline proven index-riding), the durability posture (WAL +
synchronous=NORMAL verified at open; the single-writer ceiling posture,
not hedge), the durable sweep form vs ADR-008 §2/ADR-012 §6.7 (stage at
mark_end + window; next-sweep execution with raced execution-time
re-arbitration; schedule-relative exact counts; aborts stage and
execute nothing), the seam reduction (gc_window only; no pin rows, no
sweep-lock body, no EngineFleetState), and the blocking discipline
(all rusqlite in spawn_blocking). Named design points audited as
resolved; family conventions clean; no wave-4 amendments arise.
Inline fixes (review-of-record):
- src/gc.rs: the seam's window_stage doc retired the wave-1
lazy-create hedge for the shipped constructor-at-open posture
(a tableless database surfaces the engine error on stage;
per-engine tolerances are each engine's recorded posture)
- tasks/engine-sqlite-window, store-sweep-durable-window,
suite-column-sqlite: stray placeholder lines above the filled
Notes/Summary removed (the wave-2 gate's same cleanup)
- tests/conformance/README.md: trailing newline added
Verification (all re-run green after the fixes):
- cargo test (default): 69 lib + 19 conformance + 3 git-interop
- cargo test --features mem / --all-features: 124 lib + 54
conformance + 4 git-interop each
- cargo clippy --all-targets -- -D warnings (default + all-features)
- cargo fmt --check
- cargo doc --no-deps at the pre-existing warning baseline (26)
Wave 4 (postgres) decomposition is unblocked.
The first durable delete window (single-node), beside the inline form:
- sweep_window branches on the delete window's host — the kv-engine
enum (KvEngine::Sqlite -> durable; KvEngine::Mem -> inline body,
extracted verbatim so the wave-2 mem/local suites stay green
unchanged)
- the durable form, per sweep under the lease and after the shared
protect consult: window_take(now) executes the overdue set with
execution-time re-arbitration through the same arbitrated_delete
path (consult_protect = false — the sweep's protect consult covers
its execution phase; vanished candidates settle into the cancelled
count), then marks unchanged, then stages the candidate-dead set at
visible_after = mark_end + window (the constructor-tunable delay;
ZERO = execute-on-next-sweep)
- report counts exact relative to the schedule (staged-this-sweep vs
executed-this-sweep); aborts execute nothing, stage nothing, delete
nothing
- unit tests: two-sweep exact-count shapes at delay 0, future-delay
staging with idempotent re-stage, the race across the delay (put
during the window survives; the unpinned twin deletes), the
vanished-candidate form, and the three abort shapes on sqlite
Verification: cargo test (default 69 lib tests), --all-features (124),
--no-default-features --features mem (101), clippy -D warnings
(default and --all-features), cargo fmt --check — all green.
- KvEngine::Sqlite slots in; all six kv ops dispatch; the kv cursor
body dispatches through a new KvCursor sub-enum behind AnyCursor's
one kv arm (the kv-arm-over-multiple-kv-engines design point,
recorded)
- dual_tier_sqlite_local (kv = sqlite + large = local, the
default-build production shape) and kv_only_sqlite constructors —
both feature-gated on sqlite (default-on), both taking the
threshold and the delete-window delay, fallible where I/O is
fallible (Err(Error::Io) per the dual_tier_mem_local pattern)
- ensure_gc_schema runs at construction via the engine-neutral
KvEngine call (sqlite's body creates gc_window only); the
window-delay shipped default is the pinned
DEFAULT_DELETE_WINDOW_DELAY (5 min, ADR-008 §2), constructor-
tunable, Duration::ZERO legal — the store carries the value for
the sweep's durable form to consume
- the one-window-host posture recorded in the module doc (the
durable window hosts on the kv engine when it is SQL-backed; wave
5's pg-lo dormancy slots in without reshaping)
- stale empty-set scaffolding updated to the landed state: the
#[allow(unused_variables)] attrs off the KvEngine methods; the
scope notes in store.rs, backend.rs, sqlite.rs, gc.rs
- constructor unit tests: mode/threshold/window-delay introspection,
the GC schema observed in the fresh database (window table present,
gc_pins never), kv-only rejection wiring unchanged, and the
dual-tier shape round-tripping end-to-end through both tiers
Verification: cargo test 62 passed (default; 5 new tests), cargo test
--all-features 117, cargo test --features mem 117, --no-default-
features --features mem 97; cargo clippy --all-targets -- -D warnings
clean (default + all-features); cargo fmt --check clean; cargo doc
--no-deps at the pre-existing warning baseline.
- impl EngineWindowState for SqliteBackend, the window family only per
ADR-012 §5's sqlite row; no pin-clause or sweep-lock body exists —
EngineFleetState is never implemented on this engine
- ensure_gc_schema creates gc_window only (never gc_pins; the embedder's
liveness table is never created — ADR-008 schema ownership)
- window_stage is a key-keyed upsert: idempotent per (key, deadline),
a re-stage at a new deadline updates the row
- window_take is one atomic DELETE … RETURNING with the <= now
boundary; future rows left in place; tableless take is a no-op read,
tableless stage surfaces the engine error (the recorded read/write
tolerance split)
- visible_after encodes as signed i64 nanoseconds from the epoch
(recorded design point; sub-second precision for test tunings)
- six clause contract tests per the ADR-012 §5 sqlite row
Verification: cargo test green (58 lib + 5 integration);
cargo clippy --all-targets -- -D warnings green; cargo fmt --check green.
Implements the sqlite kv-tier engine per ADR-003/007/010 §1 behind
feature `sqlite` (default-on): the B5 row shape (key BLOB PK / value
BLOB / size INTEGER NOT NULL), INSERT OR IGNORE CAS first-writer-wins
on both put forms, the EXISTS has probe, the materializing cursor body
with len() from the size column, the degenerate in-memory stage with
both hygiene forms, the indexed-column size probe (plan-tested), the
no-tables-yet virgin-store read tolerance (tested against a tableless
database file), WAL + synchronous=NORMAL verified at open, prepare_cached
discipline, and every rusqlite operation in spawn_blocking under the
recorded single-connection posture.
Task: tasks/engine-sqlite.md (status: completed). The engine-state
window family and store construction remain in their own tasks.
Verification:
- cargo test — 58 pass (11 new sqlite in-module tests)
- cargo clippy --all-targets -- -D warnings — clean
- cargo fmt --check — clean
- cargo check --no-default-features — green
Read the wave-2 implementation against the pinned ADR text line by
line (ADR-003/005/006/010/011/012/013 §2, store-api.md): the three
numbered unknown-length rules each test-backed, the delete-window
ordering invariants (arbitrate-at-delete-time, pin-before-publish on
both put paths and both tiers, raced conversion ordering,
delete-then-recover), abort-as-data with all three causes, dispatch
purity + fall-through + constructor modes + kv-only's two put-time
rejection points, stage-hygiene exact counts on both engines (incl.
the Drop-cancellation story), both suite columns green/ADR-stamped/
traceable with the factory binding recorded, the dispatch-coverage
shape exercised, all eight named design points recorded and
consistent, and the staged-put key-at-commit amendment audited
accepted. No wave-3 amendments arise.
Inline fixes applied by the gate:
- facade.rs: stale Batch::add dead-code allow + stale task-pointer
comment removed (put_in_batch's call sites landed)
- dispatch.rs: module-level allow(dead_code) removed (route/Tier now
driven; clippy clean without it), scope note updated
- backend.rs: the allow kept but its scope note corrected to what is
actually dead (trait name, kv put until wave 3)
- mem.rs: stale constructor doc line updated to the landed state
- tasks/gc-protocol.md: stray placeholder lines removed
Verification: cargo test (42 lib + 2 conformance + 3 git-interop),
cargo test --features mem and --all-features (97 lib + 37 conformance
+ 4 git-interop), clippy --all-targets and --all-features --all-targets
(-D warnings), fmt --check — all green post-fix. Wave 3 decomposition
unblocked.
- `put(len: Option<u64>, stream: impl AsyncRead + Unpin + Send) -> (Key, Pin)`:
known-length one-pass flow; unknown-length buffer-to-threshold flow with
the mid-stream fresh-stage flush (ADR-003 option (d), three numbered rules:
flush-and-continue, derivation over the eventual stored artifact as a
whole via buffer form and StagingCursor read-back form, zero residue on
stream error)
- staged-put seam amended (operator sign-off): `put_staged()` keyless
handout, `StagingCursor::commit(self, key)` publishes under the
store-core-resolved key — the canonical key completes at stream end and
the wave-1 handout shape could not express the commit-rename flow
- pin-before-publish rides the arbitration lock on both paths and both
tiers; dedup re-puts refcount the existing entry
- Batch seam: `Store::batch()` + `put_in_batch()`, members publish pin-
before-publish, group pins drop together on `Batch::commit` (new public
verb) or drop
- kv-only rejection (ADR-012 §6.2): known-length over-threshold rejects
immediately (stream never read), unknown-length at mid-stream overflow;
zero residue; error carrier `Io(String)` (named design point)
- declared-len mismatch rejects `Verification` zero-residue (named design
point); stream shape generic-no-dyn (named design point)
- incremental BlobHasher (pinned byte-equal to Algorithm::derive);
AnyStaging cursor dispatch; git-interop put-path leg against
git hash-object; eleven put-path behavior tests
Verification: cargo test (default/--features mem/--all-features) green;
clippy --all-targets -D warnings green in all three feature shapes;
cargo fmt --check green; cargo doc --no-deps at the 24-warning baseline.
The gc-protocol task (ADR-005; abort-as-data per ADR-012 §1; non-SQL
inline window staging per ADR-012 §5) wired on the Store facade:
- src/gc.rs — GcHome + RegistryCore: one arbitration lock over per-key
pin refcounts, in-flight delete markers, and the registered source
lists; async pin minting (acquire) that blocks on in-flight deletes
(ADR-005's re-put case (a) delete-then-recover without engine I/O
under the lock); the ordered-step convert primitive (pin release +
registration in one section); batch one-step release; the
single-node sweep lease (the in-process analog of ADR-013 §2).
- src/facade.rs — Pin/Batch carry the registry back-reference and own
their drop release (batch drop decrements every member in one
ordered step); new public vocabulary LivenessSource, ProtectCallback,
Registration, re-exported from lib.rs.
- src/store.rs — sweep() (single-flight → zero-source safe default →
protect consult → mark over both tiers' list() union → arbitrate at
delete time → ~100/batch commit → exact-count report or
abort-as-data), direct delete() (existence probe → full protection
set per ADR-012 §6.4 → GcRefuse/Missing/delete through the
fall-through), and the registration/unregistration verbs.
- 16 new tests + the facade pin/batch shape test reworked on the wired
machinery: exact counts across both tiers, abort shapes, dedup
refcounts, batch drops, live-shared sources, the conversion ordered
step sequentially and raced, sweep-vs-pinned-put (64 rounds, every
schedule, byte-identical delete-then-recover), publish-after-mark,
no-torn reads under a window, single-flight contention, and
malformed-list sweeps as operational errors.
- tasks/gc-protocol.md — status completed; named design points recorded
in Notes.
Verification: cargo test (default) 46 passed; --features mem and
--all-features 89 passed each; cargo clippy --all-targets -- -D
warnings (default and --all-features) clean; cargo fmt --check clean;
cargo doc --no-deps at the pre-existing baseline (no new warnings).
- Public `(len, stream)` shape: `Store::get` returns
`Option<(u64, Blob)>`; `Blob` (src/facade.rs) is a bounded, re-entrant
windowed reader over the new crate-internal `AnyCursor` tier dispatch
(mem materializing / local pread body families) — engine cursors
never leak onto the surface; no chunk-iterator machinery.
- Verification-on-get pinned against ADR-006: kv-tier materialized
reads whole-blob hash-check at get time (mismatch = Err(Verification),
never a further fall-through); the large tier's streaming open is
metadata + handle only (put-path verification + slice digests are its
story); `read_range` carries slice digests only, on both tiers.
- `stat` rides the trait's `size` probe (never a content load) into
`EntryMeta { len, algorithm }`; `has` is the pure existence probe;
both fall through kv -> large like every key-addressed op (ADR-012
§6.1) — consult order, not routing (never consults `tier_for`).
- Miss shapes enforced (the error module's behavioral note): both-tier
misses are Ok(None) on get/stat, false on has, Err(Missing) on
read_range; `src/error.rs` wave-2 deferral notes updated to enforced
state.
- `list` decided Vec<Key>: materialized, sorted total-order union of
both tiers (the sweep consumes the engines' enumeration directly);
malformed pool bytes are fatal `Err(KeyInvalid)`, never a silent
skip.
- `KeyInvalid` at the facade boundary: ops take opaque key bytes and
convert via `Key::from_bytes` once (`boundary_key`); engines never
see typed keys.
- Twelve read-path tests: virgin-store shapes per mode (dual-tier,
mem-only, kv-only), the `(len, stream)` windows, fall-through,
kv-first (decoy content in the large tier), both verification
postures, list union/sort/pool-fatality, and malformed-key
rejection on every op.
Task: tasks/store-read-paths.md (design points recorded in Notes for
the wave-2 review gate).
Verification: cargo test (default), cargo test --features mem, cargo
test --all-features green; cargo clippy --all-targets -- -D warnings
green in all three feature shapes; cargo fmt --check green; cargo doc
--no-deps clean beyond the pre-existing private-intra-doc-links class.
The wave-2 facade skeleton and routing (tasks/store-construction.md):
the public surface consumers program against, with the ops methods
still to land against it in store-read-paths/gc-protocol/store-put-paths.
- src/store.rs — the public `Store` type (engine-blind, ADR-007/008/
010) over crate-internal tier enums (`KvEngine`{mem}, `LargeEngine`{
local}): the engine-representation design point decided as concrete
+ enum dispatch, generic rejected (pub(crate) engines, no dyn);
the three constructor modes as named constructors — `mem_only`,
`kv_only_mem`, `dual_tier_mem_local` (the ADR-012 §6.3
dispatch-coverage shape) — with `StoreMode` introspection; the
write-side routing seam (`tier_for`), the read-side fall-through
order (`kv()` then `large()`, ADR-012 §6.1), and the `GcHome`
GC-state field; the ADR-012 §3 fleet declaration ruled deferred to
the engine waves (nothing fleet-valid is constructible yet)
- src/dispatch.rs — the pure routing function (`route`, at-or-below
→ kv), `DEFAULT_DISPATCH_THRESHOLD` (128 KiB) exported at the
crate root, boundary-value unit tests (exactly-at-threshold,
degenerate tunings, purity)
- src/gc.rs — `GcHome`: the store-instance GC-state home the
gc-protocol task fills (in-process; fleet state stays on the
engine-state seam per ADR-010 §2/ADR-012 §4)
- tests/conformance — the wave-2 binding made as anticipated: the
factory's `Store` associated type collapsed into the concrete
`alkblobs::Store` (`open` vends it directly), recorded in
factory.rs + README; the wave-1 mock probe retired, replaced by
mem-gated binding demo factories (binding.rs) over both
constructible shapes
Verification: `cargo test` (default), `cargo test --features mem`,
`cargo test --all-features` green (41/53/53 unit + conformance
targets green in all three shapes); `cargo clippy --all-targets
-- -D warnings` green in all three feature shapes; `cargo fmt
--check` green; `cargo doc --no-deps` adds no warnings beyond the
pre-existing private-intra-doc-links class.
- LocalBackend: flat {hex-prefix}/{hex-prefix}/{hex} sharding over
lowercase-hex-of-Key::as_bytes filenames (self-describing; the
list-decode round-trip recorded for the review gate); virgin-store
reads are no-ops
- staged put: unique stage files under {root}/staging/, commit-rename
is the publish, CAS first-writer-wins, every failure path (discard,
failed commit, Drop cancellation) converges on zero residue
- read cursor: pread loop over the immutable committed file, EOF
clamping, provided read_range composing the slice-digest convention
- all file I/O in spawn_blocking; size is a stat, never a content load
- list walks the committed tree and is fatal (Error::Io, path named)
on anything that does not decode — complete and well-formed
- 11 in-module unit tests incl. exact-count stage hygiene over all
failure forms and the success form
Verification: cargo test (44 green), clippy --all-targets/--all-features
-D warnings, fmt --check — all clean
Task: tasks/engine-local.md
- src/mem.rs: MemBackend implements Backend (seven methods + put_staged,
name "mem") over Arc<parking_lot::Mutex<BTreeMap<..>>>; CAS
first-writer-wins puts, materializing MemCursor body, degenerate
in-memory MemStaging whose commit publishes via the same CAS clause
and self-discards on failure; discard leaves zero residue.
- CAS re-put is dedup for both put forms; reads are no-ops on the
virgin store; delete carries Missing; size is metadata-only.
- Eight in-module tests mirror the wave-1 double's assertions: method
contract, list well-formedness, cursor body read contract + ADR-006
range digest, empty-entry round-trip, staged happy path, and both
hygiene forms (fail_commit test hook stands in for media failure).
- backend.rs: clamped promoted pub(crate) — the shared EOF-clamping
arithmetic both mem cursor bodies compose (no per-engine duplicate).
Verification: cargo test --features mem (33+7 green); cargo test
(default) green; clippy --all-features --all-targets -D warnings green;
fmt --check green.
The wave-1 contract surface: everything engine-blind that waves 2-6
implement against. No engine bodies, no facade behavior logic.
- src/backend.rs: the pub(crate) Backend trait — seven methods +
put_staged, opaque byte keys/values, size metadata-only, list
complete-and-well-formed, virgin-store reads as no-ops (ADR-003,
ADR-008); the ReadCursor/StagingCursor I/O seams with the read_range
slice-digest convention (ADR-006) at one seam; unit tests against
both body-family doubles, a test-double engine, and the stage-hygiene
invariant's two forms (discard; commit failure self-discards).
- src/gc.rs: the engine-state companion seam as EngineWindowState /
EngineFleetState — ADR-012 §5's applicability table expressed
structurally (no dead machinery); JointTx ownership rule pinned in
the signature (store holds the tx; engine contributes mechanics).
- src/facade.rs: EntryMeta, Pin, Batch, SweepReport, GcAbortCause
(x3, #[non_exhaustive]), PinState with lifecycle contracts
(ADR-005, ADR-012 §1); re-exported from lib.rs.
- Design points pinned for the wave-1 review gate in
tasks/core-trait-and-types.md: pub(crate) trait visibility,
associated-type put-form shapes, AFIT + associated types (no dyn).
Verification: cargo test (26 lib + 3 git-interop), cargo test
--all-features, clippy --all-targets -D warnings (default and
--all-features), cargo fmt --check, cargo doc --no-deps — all green.
Wave 1 task core-hashing-keys: the crate's declared one-way door,
implemented byte-exact to ADR-002.
- src/hashing.rs: Algorithm (exactly GitBlobSha256 canonical /
GitBlobSha1 tolerated; BLAKE3 absent), Digest (known-length
derivation H("blob <len>\0" + content) as primary constructor;
from_git_oid_hex interop constructor, lowercase-only acceptance),
and the hashing::registry constants (0x01/0x02, 0x00 reserved; new
algorithm = new ADR)
- src/keys.rs: typed Key wrapper; as_bytes/from_bytes are the only
backend-boundary conversions; 1 algorithm byte + digest bytes
(33/21 total); rejects-never-guesses validation -> Error::KeyInvalid
- tests/git_interop.rs: the load-bearing test — byte-exact derivation
against the `git hash-object` CLI, both algorithms, small and
75-KiB content; external-oid round-trip into pool keys; both oid
formats coexisting in one flat pool
- named design point (oid hex policy): lowercase-only acceptance,
recorded in the task Notes and on from_git_oid_hex
Verified: cargo test (15 passed), cargo clippy --all-targets -- -D
warnings, cargo fmt --check, cargo test --all-features — all green.