Files
alkblobs/docs/architecture/hashing-and-keys.md
T
glm-5.3-flash 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
2026-10-01 14:45:32 +00:00

101 lines
4.5 KiB
Markdown

---
status: draft
last_updated: 2026-10-01
---
# Hashing and keys
## What this is
The content-address layer: the canonical hash derivation every entry is
keyed under, the tolerated legacy algorithm, the typed `Key`/`Digest`
surface the store API speaks, and the physical byte encoding of keys
inside backends. This is the crate's one-way door: key byte layouts are
persisted in backend rows and filenames, survive digest-layer evolution,
and must precede any wire consumer (AGENTS convention 5; phase-0 OQ-BL-03
residual).
## The hash family
Three tiers (ADR-002 §Decision; resolved from OQ-BL-03 after the
"multi-hash" premise dissolved — nothing forces BLAKE3 once iroh-blobs'
inheritance is rejected):
1. **Canonical — `git-blob-sha-256`:** the git oid derivation
`H("blob <len>\0" + content)` with SHA-256, uncompressed content.
Chosen because alkgit *forces* git's derivation by protocol
definition, and every other consumer (workspaces, appfile) sees
addresses, not algorithms — so one algorithm domain makes the pool
one address space and cross-consumer dedup free by construction
(ADR-005).
2. **Tolerated legacy — `git-blob-sha-1`:** existing git repositories
are overwhelmingly SHA-1; the store accepts them under the same
preamble discipline. Git's own collision-hardened SHA-1 threat model
is inherited verbatim; the store adds nothing and weakens nothing.
3. **Not present — BLAKE3:** demoted out of the crate entirely. If a
chunk-tree transfer encoding is ever adopted, it is a new decision at
a new layer (ADR-006); its verified whole-contents would register as
ordinary `git-blob-sha-256` entries.
Security posture: one algorithm across consumers is safe here — SHA-256
has no practical cross-protocol ambiguity at these input shapes, and the
preamble domain-separates the derivation (ADR-002 §Consequences).
## Key encoding (the one-way door)
Physical key bytes inside backends (POC #1 finding 5, validated in the
interop test where an oid produced by *external git* addresses the same
pool entry the store puts):
- **Algorithm identity is part of the key itself** — a per-store
single-algorithm configuration cannot express git-sha-256 and
git-sha-1 coexisting in one flat pool, which the external-oid test
proves is required.
- **Fixed-length, enum-tagged:** `1 algorithm byte + digest bytes`
(32 for sha-256, 20 for sha-1). The POC's extra "kind" tag byte is
dropped — there is exactly one key kind. Algorithm bytes are assigned
from a single registry constant in ADR-002 so external producers can
compute them.
- **Sort stability:** fixed-length enum-tagged keys sort cleanly in a
total order — required for the sweep's live-set diffs (list() walks
are plain range scans; ADR-005).
- **Opaque to backends:** the `Backend` trait speaks opaque byte keys
(ADR-003); only the store core constructs and interprets typed keys.
## The Key/Digest surface (WHAT the API exposes)
- `Digest` — an algorithm + digest pair; construction via the canonical
derivation from content (known length) or from a pre-computed pair
(interop: `from_git_oid_hex` shape validated in POC #1 finding 4).
- `Key` — the typed wrapper; `as_bytes()` / `from_bytes()` are the only
conversions across the backend boundary. Malformed key bytes
(truncated, unknown algorithm) are rejects, never guesses — the POC's
length-checking test is the standard.
- Verification semantics ride the whole-blob posture (ADR-006): put and
get paths hash-check against the canonical derivation; there is no
per-range hash relationship under this derivation (preamble includes
the length), which is the constraint ADR-006 documents rather than
works around.
## Design Decisions
| ADR | Decision | Summary |
|---|---|---|
| [002](decisions/002-canonical-hash-and-key-encoding.md) | Canonical hash + key encoding | three-tier hash policy; algorithm-in-key byte layout; the declared wire-format ADR |
## Open Questions
None owned by this document. The interop surface alkgit ultimately
needs (oid formats, hex/binary conventions at *its* boundary) is OQ-07
— alkgit's question, not a key-encoding question.
## References
- `docs/research/phase-0.md` OQ-BL-03 (resolution + key-encoding
mechanics)
- `docs/research/poc-trait-dispatch-findings.md` findings 4/5
(byte-exact git CLI validation; tagged-key coexistence)
- gix-odb (`/workspace/gitoxide/gix-odb`) — the consumer-side baseline
for object reads/writes
- ADR-002; ADR-003 (opaque byte keys at the backend boundary); ADR-006
(what verification is possible under this derivation)