- 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
101 lines
4.6 KiB
Markdown
101 lines
4.6 KiB
Markdown
# ADR-004: Exactly two backends; manifest layers stay above the crate
|
||
|
||
## Status
|
||
|
||
Accepted
|
||
|
||
## Context
|
||
|
||
An early Phase 0 framing — "using two backends is ugly" — shaped several
|
||
rounds before being edited away, but the correction it was reaching for
|
||
arrived only in the Phase 1 review, and needs recording so no future
|
||
round reabsorbs the concern incorrectly:
|
||
|
||
- There are **always** two physical backends in this problem: storage
|
||
for small content (fast, kv/sqlite) and the filesystem for large
|
||
content. This is not ugly, it is the measured shape of the problem
|
||
(POC #3 A4: crossover ~128-256 KiB; SQLite ~9-10× faster below it).
|
||
- The "two backends is ugly" sentiment was actually about a **third
|
||
layer** in the old alknet-filesystem research — the *virtual
|
||
filesystem / appfile* stack: path trees, branches, tombstones,
|
||
filename↔hash maps living *alongside* the blob store (in that research,
|
||
literally a co-equal SQLite store beside iroh-blobs).
|
||
|
||
If left implicit, this misframing has two failure modes: (a) this crate
|
||
absorbs a path-tree/manifest layer ("three backends"), growing tables,
|
||
schemas, and branching semantics that belong to consumers; (b) this
|
||
crate shapes itself such that a future vfs builder must hack around it.
|
||
alkfs is a pending consumer precisely of that manifest layer — this ADR
|
||
is the boundary it will build against.
|
||
|
||
## Decision
|
||
|
||
**This crate ships exactly two production backends and nothing more;
|
||
every manifest/namespace/path-tree layer is a consumer, by construction
|
||
and by contract.** (A non-production ephemeral `mem` tier exists for
|
||
tests — ADR-003; it is not a storage story and does not extend this
|
||
boundary.)
|
||
|
||
1. **Two production backends is the complete set.** kv/sqlite (small)
|
||
+ fs (large) cover the scale economics with measured evidence
|
||
(ADR-003); no other physical tier is needed by any current or
|
||
planned consumer's *blob* needs.
|
||
2. **The "third backend" is not this crate's layer.** The vfs/appfile
|
||
shape — path→hash mapping, branches/tombstones/deltas per workspace,
|
||
the alknet-filesystem lineage — is storage *above* the pool:
|
||
reference sets over hashes (ADR-005's namespace machinery), not a
|
||
Backend implementation. Consumers build it on their own storage
|
||
(alkfs's path tree, alkgit's refs).
|
||
3. **The store provides the seams the manifest layer needs, and nothing
|
||
that forces it to hack:**
|
||
- hash-addressed put/get with a verified, git-interop-compatible
|
||
addressing scheme (ADR-002) — manifests reference entries by the
|
||
same canonical addresses git uses;
|
||
- liveness registration so manifest-holds maps to GC roots without
|
||
the store learning manifest formats (ADR-005);
|
||
- `stat`/`read_range` — enough for serving path-resolved content and
|
||
large-file ranges;
|
||
- pinned batch puts — manifest-atomic multi-file writes are
|
||
protected in flight (ADR-005).
|
||
4. **Namespacing at the store level is logical only** (ADR-005):
|
||
reference tables above, flat bytes below. If a consumer wants
|
||
physical isolation per tenant/repo, that is two pool deployments (a
|
||
topology choice), never a namespace flag inside one.
|
||
|
||
## Consequences
|
||
|
||
**Positive**
|
||
|
||
- The crate's scope stays testable and small: two backends, one pool,
|
||
one hash domain. No schema/versioning surface for manifest formats —
|
||
consumers iterate on theirs freely.
|
||
- alkgit and alkfs build their (very different) mapping layers on one
|
||
shared pool without either bending the store; their manifests interop
|
||
at the address level by construction.
|
||
- The alknet-filesystem lineage is honored as *shape guidance* for
|
||
consumers (branches, write sessions, chain walks), with zero of its
|
||
storage-layer mechanics (SQLite path tables, honker wiring, CRDT
|
||
sync) leaking in here.
|
||
|
||
**Negative**
|
||
|
||
- Consumers each re-build the small amount of manifest plumbing they
|
||
need (a reference table and a root registration). This is deliberate:
|
||
the manifest needs of alkgit (git refs) and alkfs (path trees) are
|
||
different enough that a shared one would fit neither.
|
||
|
||
**Neutral**
|
||
|
||
- If a future consumer *did* want a first-party manifest layer, it
|
||
would be a sibling crate over this one (e.g. `alkfs` itself), not an
|
||
extension of this crate.
|
||
|
||
## References
|
||
|
||
- `docs/research/phase-0.md` (settled approach: pooled CAS; OQ-BL-05)
|
||
- `/workspace/@alkdev/alknet/docs/research/alknet-filesystem/poc-summary.md`
|
||
— the historical lineage this ADR explicitly bounds (not a design
|
||
input)
|
||
- ADR-003 (the two backends), ADR-005 (namespaces as reference sets)
|
||
- [overview.md](../overview.md) (consumer map: alkgit, alkfs);
|
||
[backends-and-dispatch.md](../backends-and-dispatch.md) |