97cdf682c4b1a8813fc75f14d932edc0f8fb46dd
47
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
97cdf682c4 |
docs(review): the wave-3 review gate — every gate check 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. |
||
|
|
3f8e8158a7 |
feat(tests): the conformance suite's sqlite column — the durable-schedule SQL-backed column green (wave 3)
- The first SQL-backed column: the default-build production shape (kv = sqlite + large = local, feature sqlite default-on) runs the form-independent reference rows verbatim (INV-1, INV-6, the NoLivenessSources/ProtectFailed abort shapes, the kv-only rejection row against kv-only(sqlite)) and grows the durable-schedule sweep rows — exact counts asserted relative to the staged schedule (ADR-012 §6.7): two-sweep counts over the full protection set, the race across the window delay (a re-put landing during the window survives the executing sweep), the holder-stages-only lease shape, INV-5 through durable-schedule outcomes, and the schedule-relative INV-2/INV-3 readings - Dispatch rows mirror the local column's family with the placement oracle adapted by medium: the sqlite file's pool/window rows vs the root's committed files; virgin-store reads as no-ops on a fresh file (the no-tables-yet tolerance engine-instrumented, this row its facade form) - Factories: dual-tier sqlite+local and kv-only(sqlite), instance- tracked temp sites (fresh sqlite file + private root per open; idempotent panicking-row-safe teardown), the column-tuned threshold and the test window-delay tuning (Duration::ZERO — execute-on-next- sweep); the module is cfg(feature = "sqlite"), default-on — the column runs in every default cargo test, server-less, never skips - Shared fixtures moved to rows.rs (committed_file_count, staging_file_count, slice_digest, LatchProtect pub(crate)) so the columns share them without the mem gate - README: the schedule-relative reading for SQL-backed columns recorded (citing ADR-012 §6.7), the sqlite rows table inventory, Current state (three columns) Verification: cargo test (default) green — 69 lib + 19 conformance + 3 git-interop; cargo test --features mem green (124 lib + 54 conformance); cargo check --all-features --tests green; cargo clippy --all-targets -- -D warnings green; cargo fmt --check green. |
||
|
|
fb8326c4d5 |
feat(store): the sweep's durable form — staged candidates, next-sweep execution
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. |
||
|
|
2993df0e36 |
feat(store): the sqlite constructor wiring — the default-build store shapes
- 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. |
||
|
|
51d8f6525f |
feat(gc): the sqlite engine-state window family — the durable single-node delete window
- 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. |
||
|
|
908fb5d2dd |
feat(engines): the sqlite kv engine — the default engine, first SQL-backed (wave 3)
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 |
||
|
|
758ccfb359 |
docs(tasks): decompose wave 3 — the sqlite kv engine, the durable delete window, the first SQL-backed column
Six tasks against the wave-2 contract surface as reviewed (no amendments from the gate): - engine-sqlite: the default kv engine — WAL + synchronous=NORMAL, prepared statements, the indexed size column probe (B5's row shape), has-as-EXISTS, virgin-store no-tables-yet tolerance, spawn_blocking discipline - engine-sqlite-window: the engine-state seam's window family only (ADR-012 §5's reduction — gc_window, stage/take; no pin rows, no sweep-lock body) - store-sqlite-construction: KvEngine::Sqlite slots in, the dual-tier/kv-only constructors with the constructor-tunable window delay (default 5 min), ensure_gc_schema at construction, the one-window-host posture - store-sweep-durable-window: the sweep's SQL-backed form — overdue rows execute with re-arbitration before/alongside marking, candidates stage at mark_end + window, counts exact relative to the schedule (ADR-012 §6.7); the inline form preserved verbatim - suite-column-sqlite: the first SQL-backed column, server-less — form-independent reference rows mirror directly; the sweep rows are schedule-relative (the recorded INV-4/5 mirror amendment) - review-wave-3: the engine-wave gate (engine-vs-contract conformance) Verification: dependency graph validated (all ids resolve, no cycles, topological order clean); docs-only change. Refs: docs/plans/implementation.md §Wave 3 |
||
|
|
79cf1f0220 |
docs(review): the wave-2 review gate — every gate check 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. |
||
|
|
45c456989f |
feat(tests): the conformance suite's local column — the dual-tier dispatch-coverage shape green (wave 2)
- tests/conformance/local_column.rs: the first dual-tier column, run against the kv = mem + large = local factory (ADR-012 §6.3) — fresh temp-root store per open, per-instance tracked roots, idempotent teardown safe against abandoned/panicking rows (structural tests included); never skips (mem-gated — the dual-tier constructor rides feature mem until wave 3 provides an ungated kv engine) - the reference INV row set (rows.rs) mirrored against the dual-tier factory at a column-declared tuned threshold (1024), so the shared matrix and race fixtures exercise both tiers' bodies (INV-7) - dispatch rows grown: pure-function routing across put paths and re-puts with an on-disk placement oracle (tier residency is facade-invisible; with kv = mem the medium is the oracle), threshold boundary legs at the tuned and shipped-default thresholds with the constructor-tuned re-route leg, and fall-through per op with both-tier miss shapes (ADR-003/ADR-012 §6.1/§6.3/§6.5) - local-specific rows: on-disk stage-hygiene exact counts over both put paths (the real stage form, INV-3), pread windows over committed files with slice digests verified independently (ADR-006/ADR-010), virgin-store no-ops on a fresh root, and exact sweep counts over a both-tiers pool (INV-4/INV-5's both-tiers form) - rows.rs shared fixtures made pub(crate); README records the column's row inventory (§Columns beyond the reference set), the declared- threshold posture, and the new current state - stat-as-stat rides the mirrored INV-6 row's over-threshold legs; the Drop-cancellation hygiene form stays per-engine (recorded) Verification: cargo test (default) green; cargo test --features mem green (97 lib + 37 conformance + 4 git-interop); cargo test --all-features green; clippy --all-targets -D warnings green in both feature shapes (default + all-features); cargo fmt --check green; cargo doc --no-deps shows only the pre-existing warning class |
||
|
|
f86e20a217 |
feat(tests): the conformance suite's mem column — the reference row set green (wave 2)
- rows.rs: the reference row set (INV-1…6 + two constructor-mode rows), factory-generic and engine-uniform, every row ADR-stamped and traced to the backlog: round-trips over the content matrix on both put paths, dedup (same/cross-path), stage hygiene (both paths, both injectable failure modes, kv-degenerate residue via sweep outcomes), sweep safety (full-protection-set happy shape, all three GcAbortCause abort shapes incl. the single-flight SweeperLock lease, the sweep-vs-pinned-put race), list correctness through exact sweep outcomes only, stat discipline, mem-only posture, and kv-only put-time rejection (threshold discovered by free probes; immediate/ mid-stream rejections and at-threshold-lands legs) - mem_column.rs: the column's factories — mem-only (reference host) and kv-only(mem) at a declared threshold — fresh isolated opens, no-op idempotent teardown; structural factory-contract tests cover isolation and teardown against a panicking row - README: the reference row set recorded (INV-7's basis — what other columns mirror), the row-lifecycle convention, column plan and current state updated - task suite-column-mem: status completed, notes and summary filled Verification: cargo test --features mem (97 lib + 18 conformance + 4 git-interop), cargo test (default), cargo test --all-features, clippy --all-features --all-targets -D warnings, fmt --check, and cargo doc --no-deps — all green |
||
|
|
539dabcbf7 |
feat(store): the put seam — two internal paths, the three numbered rules, Batch, kv-only rejection
- `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. |
||
|
|
889be4cada |
feat(gc): the in-process GC protocol — pins, liveness, delete windows, sweep, direct delete
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). |
||
|
|
f1f505a910 |
feat(store): the read paths — get/stat/read_range/has/list on the fall-through rule
- 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.
|
||
|
|
532adfa707 |
feat(store): the Store facade — constructor modes, size-threshold dispatch, the factory binding
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.
|
||
|
|
856d436f81 |
feat(engines): the local large-tier engine — sharded files, stage-then-commit-rename, pread cursors
- 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
|
||
|
|
0b43ea1449 |
feat(engines): the mem contract-reference engine — first real engine (wave 2)
- 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. |
||
|
|
6bce301c55 |
docs(tasks): decompose wave 2 — mem + local engines, facade, in-process GC, first suite columns
Nine tasks against the wave-1 contract surface as reviewed (no amendments from the gate): - engine-mem / engine-local (parallel, dependency-free): the two engines; local owns the stage-hygiene exact-count tests and the Drop-cancellation story the wave-1 review recorded - store-construction: the Store type, constructor modes, size-threshold dispatch; binds the conformance factory's Store associated type - store-read-paths ∥ gc-protocol: read ops with the ADR-012 §6.1 fall-through rule; the ADR-005 in-process protocol (pins, liveness, delete windows, abort-as-data, GcRefuse with the full protection set) - store-put-paths: the two put paths behind one signature, ADR-003's three numbered rules, pin-before-publish, Batch, kv-only rejection - suite-column-mem → suite-column-local: the reference column, then the dual-tier dispatch-coverage shape mirroring it - review-wave-2: the gate (facade/dispatch/GC vs ADR-003/005/012) Verification: dependency graph validated (all ids resolve, no cycles, topological order clean); docs-only change. Refs: docs/plans/implementation.md §Wave 2 |
||
|
|
c1d9494c11 |
docs(tasks): the wave-1 review gate — the one-way-door audit green
Every gate check read against the cited ADR text: the key encoding holds byte-exact against ADR-002 (tags, lengths, rejects, sort order, preamble abstraction, live git-CLI interop, lowercase oid policy recorded); the trait + I/O seams + engine-state seam match ADR-003/ 010 and ADR-012 §5's reduced table; the error model's five variants and single-enum altitude reading match store-api.md/ADR-012 §6.5; the feature graph matches ADR-013 §4; all named design points audited consistent; the suite convention and backlog are traceable; family conventions clean. One inline fix: publish keyword `bao` -> `git` (excluded technology named in metadata). Wave 2 decomposition unblocked, no amendments. Verified: cargo test (26 lib + 4 conformance + 3 git-interop passed), cargo clippy --all-targets -- -D warnings, cargo clippy --all-features --all-targets -- -D warnings, cargo fmt --check, cargo check --all-features, cargo check --no-default-features --features pg-lo. |
||
|
|
327b952e4d |
feat(tests): the conformance suite's home — conventions, invariant backlog, harness skeleton (wave 1)
- tests/conformance/README.md: the convention doc — row naming (property- stated names, engine dimension is the column), the Contract stamp: format (the alkstore ADR-017 §4.2 convention adapted), the one- normative-owner-per-property rule, the factory contract (fresh isolated instance per open, idempotent teardown, safe over an abandoned instance), the SKIP posture (SQL-attached columns skip cleanly server-less; acceptance requires green against the server), the invariant backlog (the seven store-api.md §Invariants registered as the rows-to-grow table with pinning citations), and the mem-first column plan (mem is the contract-reference engine, ADR-011 §2) - harness skeleton, compile-able with zero rows: StoreFactory (fresh + isolated + idempotent-teardown contract; the Store associated type is wave 2's binding point for the facade type), stamp.rs (the marker + convention anchor), backlog.rs (in-code registry with a traceability gate asserting INV-1..7 mirror §Invariants in order) - no engine-specific code; no dependencies added Verification: cargo test (33 passed across lib + 3 targets), cargo clippy --all-targets -- -D warnings, cargo fmt --check |
||
|
|
0547c17876 |
feat(backend): the Backend trait, I/O seams, engine-state seam shape, and facade value types (ADR-003/010)
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. |
||
|
|
fef05b4ec5 |
feat(keys): the content-address layer — canonical hash derivation and key encoding (ADR-002)
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.
|
||
|
|
fc5ab57d18 |
feat(errors): the one-enum error family with altitude discipline
- src/error.rs: thiserror Error enum with the five ADR-012 \u00a76.5 variants (Missing, Verification, Io(String), GcRefuse, KeyInvalid); doc comments carry store-api.md \u00a7Error model's semantics and the one-enum/two-altitude discipline (trait's effective members are Missing/Verification/Io/KeyInvalid; facade re-exposes with GcRefuse) - no #[non_exhaustive] per the ADR-pinned variant set; Error derives Debug/PartialEq/Eq - lib.rs re-exports Error - unit tests: variant construction, the single-enum altitude shape, and the Missing-is-never-get/stat-absence doc contract (facade behavioral enforcement lands in wave 2) - tasks/core-error-model.md: status completed; Notes + Summary filled Verified: cargo test, cargo clippy --all-targets -- -D warnings, cargo fmt --check |
||
|
|
24d1c68343 |
feat(crate): scaffold the ADR-013 §4 feature graph and module skeleton
- Declare the decided feature graph in the manifest: sqlite default-on (rusqlite 0.40 bundled), postgres (tokio-postgres 0.7 + deadpool-postgres 0.14), mem (dependency-free), pg-lo pulling the shared pg driver cluster only (no postgres implication, ADR-010 §1), ops (alkcall 0.8.1, default-off); local ungated - Replace the placeholder crate body with the module skeleton: lib.rs re-export shape, ungated stubs (hashing, error, backend, facade, dispatch, gc, local), engine stubs behind #[cfg(feature)] (mem, pg_lo, postgres, sqlite, ops); stubs are doc-comment-only so wave-1 tasks own the module bodies Verification: cargo test green (default); cargo check --all-features resolves the full graph; cargo check --no-default-features --features pg-lo resolves with rusqlite provably absent (tree-inverted match) — the ADR-010 §1 no-implication rule; clippy --all-targets -D warnings and cargo fmt --check clean. Task: tasks/scaffold-crate-features.md (wave 1) |
||
|
|
8a2df4fa57 |
docs(plans): implementation plan — wave-based decomposition; wave 1 decomposed into tasks/
- docs/plans/implementation.md: the meta plan (alkstore pattern) — nine waves, dependency logic, decided points, review gates. Scope authority: v0.1.0 ships the full surface (all five engines, fleet GC, ops). - Wave 1 decomposed: scaffold-crate-features, core-error-model, core-hashing-keys, core-trait-and-types, suite-scaffold, review-wave-1 (the one-way-door gate). - Waves 2-9 shaped in the plan; each decomposes after the prior wave's review gate. Verification: cargo test / clippy -D warnings / fmt --check green (docs-only change). |
||
|
|
6f6ab19b8e |
docs(architecture): fix YAML-invalid frontmatter; changelog text moves to notes
- last_updated annotations containing ': ' ('family composition: ...',
'feature graph re-pinned: ...', 'REQ-5 added: ...') broke Gitea's
frontmatter parser in docs/architecture/README.md,
backends-and-dispatch.md, and requirements.md
- last_updated is now a bare date; the annotation lives in a quoted
notes field across all annotated architecture docs
- convention documented in .opencode/agents/architect.md: bare
last_updated date, quoted notes, quotes required for ': ' scalars
Verification: all docs/**/*.md frontmatter parsed with yaml.safe_load
(16/16 OK); cargo test, clippy --all-targets -D warnings, fmt --check pass
|
||
|
|
bee86b0dbd |
docs(architecture): ADR-013 — family composition, reactive boundary, sweep lease; OQ-11 resolved
- No sibling (alkstore) dependency in-core; reactivity is deployment-layer composition above the facade — cadence stays embedder-owned (ADR-005), with alkstore the named substrate for it; in-crate notify/scheduler/queues/invalidation hooks are non-goals. - Fleet sweeper lock pinned as 'named exclusive sweep lease' semantics; shipped provider unchanged (pg advisory clause); provider swaps are ADR-007-shaped substitution doors. - Composition contract for downstream ADRs: co-tenancy of CAS/GC state + reactive machinery + consumer/liveness tables on one fleet host; no-cross-store-atomicity ruled; compensation rests on idempotent re-puts, windowed deletes, sweeps-as-report-data. - OQ-11 resolved (the register's one live circular hedge): engine features pull their own driver clusters — sqlite becomes feature 'sqlite' (default-on, carries rusqlite); 'kv'/'large' tier features retired; 'local' ungated; pg-pure builds are supported, non-default. Deciding fact already in-tree (REQ-2/ADR-009). - requirements.md: UC-4/REQ-5 records the composition facts (operator record 2026-10-11, corroborated by alkstore's consumer-inventory). - Publish guard stated pre-code: facade ships before publish; semver-is-contract from first publish (alkstore ADR-017 discipline). - Amended accepted ADRs' feature wording (ADR-010 §1, ADR-011 §3/§4, ADR-003) with supersession notes; README/overview/open-questions/ backends/store-api/gc aligned; parked index now empty. Verification: docs-only round (no Rust surface touched); full-tree single-value check on the feature graph and sweep-lease wording. |
||
|
|
7b9d904b8a |
docs(architecture): ADR-012 — pre-decomposition consistency rulings; tree verified single-valued
Full-tree review before task decomposition found five composition
defects (mechanisms specced correctly in isolation, composition
unruled) and a set of caller-facing gaps. ADR-012 rules each:
- Sweeps are never errors: aborts are GcAbortCause report data in
Ok(SweepReport) (ProtectFailed / SweeperLock / NoLivenessSources);
GcAborted retired from the error enum; direct-delete refusal is
the GcRefuse error covering the full protection set
- Pin token gains its wire shape: blobs/put response {token, digest};
blobs/have's token-renewal form (one digest + token); token
validity domain = the minting serving node, process-lifetime
mapping
- Fleet mode is an explicit constructor declaration (fleet: true),
never inferred from engine choice
- All fleet GC state hosts on the fleet's kv engine (postgres) — one
arbitration domain; large=pg-lo fleet nodes required onto the same
pg instance (composite predicate's new clause); large=local fleet
puts pin-row-first, publish-second
- Engine-state seam reduced: sqlite pin/sweep-lock bodies dropped
(dead machinery); non-SQL engines stage delete-window candidates
in-process; one-window-host rule per instance
- Facade clarifications: fall-through for all key-addressed ops,
kv-only put-time rejection, mem+local dual-tier valid, error-model
member/return-shape ruling (trait/facade family split), has ->
bool, PinState variants, fleet liveness-table registration form,
window executor = the next sweep
Alignment edits across all specs and ADR-005/008/009/010/011
(bracketed corrections per the established pattern); OQ-11 (pg-only-kv
feature graph) added to the parked index for auditability.
Verification: two independent review passes; all findings resolved;
verdict READY for task decomposition.
|
||
|
|
abf8c5ae9c |
docs(architecture): ADR-010/011 — I/O seams, GC-state home, vocabulary; pre-decomposition consistency round
ADR-010 (new): the Backend trait's I/O seams pinned before any code — 'get' returns a crate-internal read cursor (kv engines materialize; 'local' pread loop; pg-lo lo_get windows), 'put' has two named forms (whole-value kv / staged-put large); GC state is store-core-owned via a crate-internal contract-tested engine-state seam on the SQL-backed engines (backends never learn liveness — ADR-005 verbatim); the store core holds the joint entry+pin transaction (corrects ADR-009 §2's ownership statement); kv-tier fleet-validity rule added (mirror of ADR-008 §3); ops pin-token TTL race resolved (the token IS the pin; renewal rides have/re-put; pause-past-TTL falls to delete-then-recover); feature graph pinned (pg-lo does not imply postgres). ADR-011 (new): vocabulary pinned — tier (contract, exactly two) vs engine (concrete impl, exactly five); store instance / node / fleet split (fleet = pool-sharing, not node count — fixes requirements.md's self-contradiction with REQ-2); mem demoted from 'backend'/'testing tier' to the kv tier's third engine (contract-reference engine); fs tier renamed 'large' including the feature name (last free moment before code exists); constructor modes pinned (dual-tier default, kv-only, mem-only) plus the composite fleet-validity predicate. Consistency round across all specs and ADR-003/004/007/008/009: stale pg-lo passages resolved per ADR-009's supersession; ADR-008 owner 'node id' → store-instance id; threshold wording corrected (conservative edge, not midpoint, of the 128-256 KiB crossover zone); SweepReport shape specced; mem classification unified; 008/009 ADR files renamed to match the tier rename; README deferral-policy recap aligned (third category = decided-but-sequenced work, not a parking kind); POC crate list completed. Verification: two independent architecture review rounds (the first found 4 criticals — unpinned trait I/O shapes, missing fleet-state seam, node/fleet self-contradiction, pin-token/TTL conflict — all resolved; final round: zero criticals); all markdown links resolve; ADR tables complete (11 ADRs). |
||
|
|
9bbe6f3ad9 |
docs(architecture): ADR-009 — pg-lo admitted as the fs tier's second engine on POC #7
- ADR-009 (new): postgres Large Objects ship as the fs tier's second engine (feature pg-lo, default-off), admitted on POC #7's passed gate (contract 10/10, durable put ~= fs at >=1 MiB, lo_get window gets, transactional LO lifecycle = zero crash orphans). Engine shape: companion table (lo_entries) is the contract authority; put = one tx (lo_create + lowrite + row + pin); get = descriptorless lo_get windows (lo_*64 discipline); named operator deltas (catalog space never returned / autovacuum inherited / sweep for the legacy bypass class only) and named performance deltas (cached-get 20-50x behind page-cache fs single-stream, ~700 MB/s aggregate at 16 readers = the fleet serving picture). - Ripple: backends-and-dispatch (pg-lo shipped; fleet locality contract gains the whole-fleet-pg-lo option), overview (layer map, feature table + pg-lo row, OQ -> shipped pointer), requirements (engine def + REQ-2 note updated), README (current-state + ADR table), store-api (invariant 1/6 engine lists), ADR-008 Status amendment (pg-lo posture superseded by ADR-009), open-questions (audit trail completed: decided -> sequenced -> completed). Verification: docs-only; all cross-references resolve (ADR/REQ/POC); register, findings, spec, and both engine-ADR status lines agree. |
||
|
|
cee97defba |
docs(research): POC #7 — postgres Large Objects as the fs-tier pg-lo engine, passed
The ADR-008 pg-lo admission POC ran in a standalone crate (/workspace/alkblobs-pglo-poc): PgLoBackend over the ADR-003/008 trait contract (including size), 10/10 exact-count sweep-outcome contract tests, clippy/fmt clean; dockerized postgres:16-alpine on :15432, POC #5 driver stack (tokio-postgres + deadpool) via SQL lo_* functions, no new dependency. Gate verdict: passed, with named deltas. - Performance: durable put 60-65 MB/s at >=1 MiB, within 1.5x of — and below 1 MiB beating — durable local fs on this fsync-slow disk; cached gets 70-180 MB/s single-stream, ~0.7 GB/s aggregate over 16 readers (20-50x behind page-cache fs — the honest named delta) - Contract: companion table is the list()/size()/CAS authority (never the catalogs); stage-then-commit; GC-participating lo_unlink delete - Handles: the tx-scoped descriptor is real but pool-compatible via descriptorless lo_get(oid, off, len) windows — window gets keep handle-acquire p99 at 1-6 ms under readers <= pool; held descriptor is the fallback posture - Vacuum: pg_largeobject pages churn-reused, never returned; tracked by autovacuum; rel-size monitoring named as an ops requirement - Crash/orphan: LO creation is transactional — kill/terminate mid-write-tx leaves zero orphan pages; the only orphan class is a committed LO bypassing the companion table (planted, reaped by the ~7 ms/oid sweep; committed content survives byte-exact) - Harness lessons: lo_lseek is int4 — the 64 variants are the >2 GiB discipline; shared-table parallel tests are unsound (per-test CREATE DATABASE isolation) Docs: new poc-pglo-findings.md; poc-pglo-spec.md status passed; register OQ-BL-06 #7 marked passed; ADR-008 pg-lo bullet updated (duplicate bullet removed) + backends-and-dispatch/open-questions cross-references. Verification: cargo test --release (10 passed), clippy -D warnings, fmt --check in /workspace/alkblobs-pglo-poc. |
||
|
|
281c37876e |
docs(architecture): ADR-008 — trait size probe, fleet GC, fs-tier engines; requirements anchor
- requirements.md (new): the three use cases pinned as REQ-1..4 with the node/pool/fleet/engine vocabulary defined once — ends per-session re-derivation of consumer facts. REQ-2 (replicator fleet over one shared pg pool, incl. large-blob serving) is recorded as a planning fact predating all POCs, on the operator's authority. - ADR-008: Backend trait gains size(key) length probe (before any backend ships data — ADR-002 one-way-door discipline); fleet GC mechanism (DB-backed pin rows committed atomically with entries, TTL+renewal semantics, liveness = embedder-owned table, protect callback is single-node-only, advisory-locked single sweeper, staged re-arbitrated delete window on both engines); fs tier becomes engine-selectable (local default; pg-lo named candidate) with the fleet locality contract (shared media or re-routing; mixed tiers are a documented deployment invariant, not a constructor-provable one). - poc-pglo-spec.md (new): POC #7 spec — pg Large Objects as the fs tier's pg-lo engine; instruments, decision gate, registered in phase-0.md OQ-BL-06. - ADR-003/005 status amendments point to ADR-008's extensions; specs ripple (backends/store-api/gc/ops/overview/README). - open-questions.md: deferral-policy header gains the decisions-vs- sequenced-work distinction; pg-lo's why-not-parked audit trail recorded. - research fixes: postgres POC renumbered #4->#5 to the canonical register (phase-0 OQ-BL-06), redb cross-refs fixed, thinking- artifact sentence in B1 replaced with the honest reading. Verification: docs-only change; reference-integrity sweep across the tree (ADR/REQ/POC refs resolve); architecture-reviewer pass on the delta — original 3 criticals addressed, its follow-up (fleet liveness form, pin TTL, staged-delete semantics, enforceability, shared-media caveats) fixed in this commit. |
||
|
|
395d58cf3f |
docs(architecture): ADR-007 — two kv engines (sqlite + postgres) behind one trait
Dissolve OQ-10's circular "standing offer" framing and record the engine decision the POC evidence already supported: - ADR-007 (new): kv tier ships sqlite (default) + postgres (feature `postgres`, default-off), constructor-selected per node; records the deployment economics (classical kv+fs+relational downstream stack collapses to one relational engine + fs), the pg impl contract (POC #5 B5 posture deltas), the CI sweep-safety gate under --all-features, redb ruled out (POC #6), and posture defaults as deferred cost in the ADR-006 pattern - ADR-003: amended status (engine pin widened by ADR-007); kv entry notes the widened engine set - ADR-004: reconciliation note — the "two backends" count is tiers, not engines - backends-and-dispatch.md: tier≠engine distinction, pg engine section, co-tenancy note (same-file consumer writes share sqlite's single-writer ceiling), substitution-door precedent - open-questions.md: OQ-10 resolved-by-ADR-007, with the why-this-is-not-Schrödinger's-code record (a deployment running alkblobs cannot pre-exist the pg engine — OQ-09 precedent); parked index narrowed to OQ-07/OQ-08 - overview.md: layer map + dependency posture reflect the `postgres` feature; README.md: ADR-007 in tables + corollary applications - phase-0.md / pg+redb findings: promotion + supersession notes Trigger framing survives only as deployment guidance (which engine a node chooses — topology, not throughput), not as a gate on the crate's own work. Verified: cargo test, clippy --all-targets -D warnings, fmt --check. Docs-only change (Phase 1 architecture); no implementation yet. |
||
|
|
1af9399900 |
docs(architecture): OQ-10 — postgres as the second shipped kv engine, a standing offer on a deployment trigger
Records the two-engine story the POC #5/#6 round established, in the terms this crate's boundary uses (engine, not backend; trait contract as the admission gate): - OQ-10 (externally-owned standing offer): open the postgres-kv ADR when a multi-tenant replicator deployment materializes. Trigger is topology, not throughput — cross-machine write access to one pool (throughput pressure / sqlite's flatline is the early warning). Names the trigger-time work: PgKv impl + engine-posture deltas (synchronous_commit, pooling/prepared-statement discipline, autovacuum, ~40x storage overhead) + the sweep-safety proof (vacuum-stable list() cursor, exact-count sweep tests). Sequenced: sqlite stays Phase 1 mainline; evidence base is done and waiting. - poc-postgres-kv-findings.md: engine deployment posture section — the three use cases (self-hosted git serving, p2p replicator nodes, agent-workspace pools) mapped onto the measured curves; per-node choice as the form of the fork; honker parity stack named for the pg side (LISTEN/NOTIFY + pgboss-rs, deployment layer). No code changes; engine work parallelizes against the fixed contract. |
||
|
|
5eea656295 |
docs(research): POCs #5/#6 — postgres and redb as the kv engine, both substitution-seam inputs
Post-convergence engine studies against the ADR-003 kv pin, using POC #3's harness unchanged (sqlite/fs arms byte-identical) plus the concurrency axis POC #3 never measured: - #5 postgres (B1-B6): solo pg floor ~1 ms (fsync-dominated, strace- decomposed), ~40x storage overhead; decisive scale-out — pg PUTs ~12x at 12 conns / ~37k ops/s while sqlite flatlines at its ~1.2k WAL single-writer ceiling. Viable future ADR for the multi-client replicator shape; durability/ops posture change, not a drop-in. - #6 redb (C1-C6): the "2-7x over sqlite" folklore inverted — sqlite ~430x over redb at crash-consistent puts (redb Immediate = 1 fdatasync/commit, 8-30 ms on this disk; its None tier is not crash-consistent). Reads ~530k/s but irrelevant. Ruled out at a durability-tier mismatch: WAL-NORMAL's shipped tier is not expressible in redb 4.x's two-level API. - Net: sqlite's pin now has four-way triangulated evidence (fs vs sqlite #3, pg #5, redb #6, lineage citation); batched commits proven as the universal lever across all three engines. Code: /workspace/alkblobs-postgres-poc, /workspace/alkblobs-redb-poc (standalone crates per the POC placement convention; 14 inherited tests passing in each, clippy -D warnings + fmt clean). Verification: no src/ changes — docs only; both POC crates verified (test/clippy/fmt) with findings recorded above. |
||
|
|
e403b22e26 |
docs(architecture): clarify Backend trait scope and kv/sqlite framing
The backends spec read as if the Backend trait were a general storage abstraction and 'two backends, exactly' banned other storage in a deployment — so a downstream wanting sqlite manifests appeared forced into implementing a third backend, the exact weld ADR-004 forbids. - backends-and-dispatch.md: state plainly that the trait is a CAS-tier contract (immutable digest-keyed entries, GC-shaped list/delete) and never a host for manifest/index storage; consumer storage is beside-the-pool. 'Two, exactly' counts trait impls shipped, not storage per deployment. kv: tier name vs pinned sqlite engine made explicit. - ADR-004: add the explicit corollary under the consumer-seams point. |
||
|
|
b18521a0e6 |
docs(architecture): dissolve OQ-09's self-referential deferral
- OQ-09 resolved closed-by-default (deny-unlisted), decided on risk asymmetry in hand, not on a first deployment the crate itself must create; named reopen condition instead of a parked wait - delete oq-09-ops-visibility-tracker.md (watch-task for an event the crate itself gates — never collapses) - fix doc-lifecycle circularity: externally-owned OQs no longer block a spec's `reviewed` promotion - gc-and-namespaces: "until a consumer names a requirement" reframed as re-entry via a new ADR, not a parked question - README: state the corollary explicitly — facts this crate must create (its own first deployment/consumer) are never deciding inputs Verified: full-text sweep for stale OQ-09 deferral/tracker references comes up clean across docs/ and tasks/. |
||
|
|
4b5009d85a |
docs(architecture): Phase 1 spec tree — 7 specs, ADRs 001-006, OQ tracker
- overview/hashing/store-api/backends/gc/ops specs + README index, all draft status with YAML frontmatter and cross-referenced ADR/OQ - ADR-001: substrate posture (store layer alkcall-free = family conformance, not deviation) + ops placement decided (feature-gated module, no consumer-waited deferral) - ADR-002: canonical git-blob-sha-256 + key encoding — the declared wire-format ADR (one-way door) - ADR-003: backend contract, sqlite/fs/mem tiers, pure-function dispatch, no migration, unknown-length buffering semantics pinned - ADR-004: exactly two production backends; manifest/path-tree layers are consumer-side (the corrected two-vs-three-backends framing) - ADR-005: pooled CAS, three liveness sources, delete windows with pin-before-publish + delete-time arbitration (race closed), no ambient scheduling - ADR-006: whole-blob verification; chunk-tree encodings excluded by scoping, not deferred on a paused consumer - open-questions.md: OQ-BL-01..06 resolved with ADR cross-refs; OQ-07 /08 externally-owned, OQ-09 deferred(scope) with SDD tracker task - AGENTS.md: status updated to Phase 1, gix-odb path corrected Verification: cargo test / clippy -D warnings / fmt --check clean |
||
|
|
7d9ac8a6ec |
docs(research): correct layer vocabulary — alkcall has no transport code
- Verified against alkcall 0.8.1: no networking deps; Connection wraps a caller-provided established stream (ADR-012 dial/call decoupling) - 'transport' was being used loosely for 'wire/ops protocol'; now reserved for endpoints/dialing/byte-moving, which is in neither crate. Ops/framing/ACL surface = wire/ops protocol (alkcall's layer) - Vision sentence, scope line, OQ-BL-01 argument, and alkcall prior-art entry rewritten with the accurate layering; alkcall entry now states the transport-free fact explicitly - iroh-blobs-eval.md: 'welded to their transport' -> 'welded to their protocol stack (endpoints/transport weld on above it)' Verification: cargo test / clippy -D warnings / fmt --check clean |
||
|
|
b0b385d94e |
docs(research): settle OQ-BL-01 substrate — ops surface rides alkcall, with the argument recorded
- The 'alkcall usage undecided with the first wire consumer' posture was an inherited assumption, never a decision; it conflated iroh- blobs' actual weld (no Store trait, store inseparable from irpc — convention 7's rejection target) with having a protocol substrate under the ops layer at all - Settled: ops surface is alkcall-shaped — validated JSON control ops (OperationSpec/JSON Schema, ADR-016 error schemas), binary data channels via the channel_open marker (ADR-047; Sub ADR-021 fetch, Pub/Sink ADR-046 put), ACL via AccessControl + ownership (ADR-011) under the ADR-017 privilege model; an in-band op/auth scheme would duplicate reviewed family machinery (convention 6 already mandates the seam) - Store layer stays substrate-agnostic (principle 1 unchanged); alkcall enters only at the ops module/sibling boundary - Remaining Phase 1 ADR scope reduced to placement: feature-gated ops module (lean) vs sibling crate - Synced vision sentence, scope line, alkcall prior-art entry, OQ-BL-05 ACL line, recommended approach, decision table Verification: cargo test / clippy -D warnings / fmt --check clean |
||
|
|
1f905003d0 |
docs(research): Phase 0 convergence — settle OQs, add decision table + ADR backlog
- phase-0.md: fold chronological accretion into a settled posture; status -> converged; OQ-BL-01..06 restated as settled-base + named residuals; new Convergence section (recommended approach, decision table, Phase 1 ADR backlog); plan section marked complete - iroh-blobs-eval.md: fix crossover numbers (64-128 -> 128-256 KiB, matching POC #3 finding A4) and B-finding -> finding-A4 reference - poc-largeblob-findings.md: summary-table label fix (B-finding -> finding A4); align small-blob multiplier with measured 9-10x Verification: cargo test / clippy -D warnings / fmt --check clean |
||
|
|
6b278fb490 |
docs(research): POC #3 passed — large-blob streaming + sqlite-vs-fs benchmark
- POC #3 (register OQ-BL-06) executed and passed: streaming LFSObject-shaped put/get at the store layer; fanout seam (serve-while-persisting) validated as broadcast above the backends; fs range reads with the verification gap documented (preamble makes slice-vs-whole verification impossible — chunk-tree encoding sharpened to a transfer-layer conditional) - sqlite-vs-fs micro-benchmark: first-party anchor for the small-blob belief (~9-10x sqlite at 1-16 KiB, crossover ~128-256 KiB, 128 KiB default lean); harness re-runnable on real media - Stage-file hygiene tests caught a real leak (one temp file per failed put) — fixed; all failure paths converge on discard - Pack tension resolved in shape from the gix-odb read: packs as large blobs served by range reads; object-level dedup lives in the loose tier - iroh-blobs-eval.md written against the current checkout (e82cbdc / v0.103.0): actor/message-protocol pattern, fs backend layout, verification, do-not-inherit + keep lists - alknet probe re-check demoted to historical cross-check only: alknet's code is not a design input (decomposed; substrate is alkcall); its small-blob perf claim was asserted-never-measured, superseded by A4 - phase-0 register complete: no open POCs; next step is convergence -> Phase 1 Verification: POC crate (standalone /workspace/alkblobs-largeblob-poc) 14 tests pass, clippy -D warnings clean, fmt clean; digests byte-exact vs the real git hash-object CLI on both streaming put paths |
||
|
|
493516424a |
docs(research): POC #1 passed — trait contract + digest + dispatch
POC code: /workspace/alkblobs-trait-poc (17 tests passing, clippy -D warnings + fmt clean; digests validated byte-exact against the real git hash-object CLI, both object formats) Findings (poc-trait-dispatch-findings.md, 8): - lean Backend trait (opaque byte keys, complete list(), put-path pinning) is sufficient; Key typed wrapper lives at the boundary - redb traps: list() key-vs-value destructure (silent until GC catches it — malformed list is as deadly as incomplete), virgin-db TableDoesNotExist on first read, no in-memory db (temp file used) - pinning: Pinned RAII guard + refcount map works; batch-scope pins and the sweep-vs-put race are named Phase 1 requirements (iroh DeleteSet = prior art) - git-blob preamble abstraction validated; external-git oids address pool entries with zero indirection (the OQ-BL-03 resolution, implementation-confirmed) - tagged key format ([algo byte][digest]) makes git-sha256 + git-sha1 coexist; sort-stable for sweep diffs - dual dispatch works as simply as hoped; routing deterministic - namespace tables: protect callback MUST share live state (the snapshot-install bug proves the API lesson: register_liveness_source shape, not install_into) - GC semantics verified: exact deletion counts, abort-callback, delete-then-recover byte-identical re-put phase-0.md: POC #1 marked passed, #2 absorbed (validated), #4 covered in miniature (concurrency half deferred to Phase 1 impl work); OQ-BL-02 base settled; OQ-BL-03 implementation-validated; OQ-BL-05 mechanism settled with findings folded in; plan updated (POC #3 is the last open POC) |
||
|
|
cde279b76d |
docs: hash simplification — canonical git-family hash resolves BLAKE3
- OQ-BL-03 RESOLVED: BLAKE3's presence traced to pure iroh-blobs inheritance; with that rejected the multi-hash framing dissolves. Three tiers: canonical git-blob-sha-256 (git oids + every other consumer share one address domain — cross-consumer dedup free), tolerated git-blob-sha-1 (protocol necessity, git's hardened-SHA-1 threat model), conditional BLAKE3 (only if a bao-like chunk-tree encoding is ever adopted; confined to that encoding layer) - Principle 2 rewritten (one canonical hash, git-family derivation); alkgit consumer entry updated (the 'hash conflict' was an artifact of the BLAKE3 inheritance); p2p section notes strengthened dedup - OQ-BL-04: verification options no longer BLAKE3-mandatory; chunk- tree encoding note — verified wholes register under the canonical hash so chunked and whole-file paths dedup together - POC register: #2 absorbed into #1 (postamble abstraction + SHA-1 tolerance are #1's trait work); #3 gains the sqlite-vs-fs micro-benchmark pull-out - AGENTS.md convention 5 aligned (canonical git-family derivation) |
||
|
|
55450d6bf0 |
docs(research): consolidate GC/pooling round into phase-0
- iroh-blobs GC mechanics verified against current checkout: mark-and-sweep (named tags + TempTag RAII + ProtectCb with abort), format-aware mark traversal, DeleteSet write-safety, no namespaces (flat tags) — our namespace concept maps onto their machinery - rudolfs prior art section: StorageKey(ns, oid) composite key + decorator storage stack; THE ANTI-PATTERN inverted (physically namespaced storage defeats cross-tenant dedup); list() is load-bearing; verify-as-decorator; streaming LFSObject + fanout - OQ-BL-03: oid<->hash mapping DISSOLVED — git's oid derivation is itself a hash algorithm (domain-separated preamble); per-algorithm namespaces; mapping only reappears for transfer-vs-storage hashes - OQ-BL-05 consolidated: physically flat/logically namespaced; tags are the root table; references stay above the crate; mark-and-sweep with protect-callback lean (a) + TempTag pinning; traversal ownership (a/b/c) is the Phase 1 ADR - POC register updated: #1 adds list() completeness + pinning contract, #2 reframed as validating oid-dissolution, #4 as the GC worked example; 'what each POC decides' section added |
||
|
|
5e0a594cfd |
docs(research): fold p2p-git/dedup discussion into phase-0
- Consumers: add agent workspaces (third consumer); add the p2p shape section (contract/gossip/replicator sketch) and pin what it implies here: pooled CAS per node, repos/workspaces as hash-reference sets - Principles: add 6 (pooling is the point) and 7 (whole-file CAS default; CDC scoped to large-binary edits; fixed-size trees not inherited) - OQ-BL-01: ops surface upgraded from speculative to likely (have/need + verified fetch), crate-boundary question remains - OQ-BL-04: chunking scoped; new sub-question — chunking in store encoding vs manifest layer - New OQ-BL-05: pooling/GC — namespace shape, lifetime strategies, the pack tension (constrains store surface) - POC register: add #4 (pooled CAS + GC); note pack tension rides #3 - gix-odb: note alternates/object-pools as cross-repo dedup prior art |
||
|
|
7f7f70b220 |
feat: initial repo setup (Phase 0 scaffolding)
- AGENTS.md: repo conventions adapted from alkcall/alksocks (store posture, multi-hash requirement, no-iroh-wire rule; no fuzz gate yet) - Cargo.toml + src/lib.rs: bare lean lib skeleton (tokio async, thiserror) - docs/research/phase-0.md: Phase 0 draft — vision, prior art (iroh-blobs store, gix-odb, alknet appfile probe, alkcall), OQ register, POC plan - .gitignore, LICENSE-APACHE/MIT - Re-pointed stale alknet/alkcall references in .opencode/agents/ and docs/sdd_process.md Verification: cargo build/test, cargo clippy --all-targets -- -D warnings, cargo fmt --check, cargo doc --no-deps — all pass |
||
|
|
357311d27b | init |