Structural decision (OQ-09 resolved): alkgit follows the alktty/ alktunnels template — a single published protocol crate on alkcall channels, no binary, no front doors. - ADR-010 supersedes ADR-001 (crate decomposition) and ADR-006 (http router factory); both marked Superseded - Single crate at repo root: Cargo.toml with gix feature (default-on backend implementations; wire layer compiles without it — gix-hash always-on with sha1 per the compile-time-rejected invariant), crates/ workspace deleted, src/lib.rs stub in place - doors.md replaces http.md/ssh.md/alkgitd.md: alkhttp git-feature sequencing (after first publish), alkssh requirement (fixed-grammar exec dispatch), native alk/git path, downstream assembly - backend.md replaces storage.md: GitRegistry/GitRefs/GitPackGen/ GitPackIngest traits (ingest validates, refs commits — single CAS home), gix feature encodes POC-2 prerequisites - transport.md reframed for the single crate; backend traits replace hook traits in the public API - OQ-09 resolved (all five sub-decisions in ADR-010), OQ-01 resolved (subsumed), OQ-03 narrowed to publish-freeze, OQ-08 narrowed to registry identity + vault placement, OQ-07 rescoped to the gix feature's registry impl - vision.md v2: single-binary/monorepo framing corrected as init-agent artifact; POC checklist marked complete - AGENTS.md + .opencode agent specs updated to the new shape Verification: cargo build (default + no-default-features), cargo test --all-features, clippy --all-features -D warnings, fmt --check all pass. Third review round: zero critical, all warnings/suggestions addressed (GitPackGen signature amended in ADR-004, stale anchors fixed, ADR-006 body tense normalized, CAS split stated, vision residuals cleaned).
4.6 KiB
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-09-21 |
Backend traits: the storage seam
What this is
The payload side of the protocol crate: the traits a service deployer
implements (or consumes via the feature-gated gix implementation) so the
git protocol can talk to storage. Per ADR-010 this mirrors alktty's
TtyBackend pattern — traits in-crate, real implementation behind a
feature. Unlike alktunnels (no backend trait), git needs the seam: pack
generation/ingestion is too heavy to hard-wire.
The trait family (ADR-010 sub-decision 4)
Four traits, kept small and orthogonal — the protocol crate never sees gix types:
GitRegistry— repo id → (storage root, visibility, ACL scope). The authoritative mapping (ADR-008); resolution failure is indistinguishable from authorization failure (ADR-007). Metadata holds vault references, never secrets.GitRefs— listing for advertisement (refs + peeled tags + symref targets, the ls-refs response data) and ref transactions (CAS apply for receive-pack, name validation per git ref rules + reserved- namespace deny-list).GitPackGen— (repo, wants, haves, limits) → streaming pack (io::Writeconsumer). Negotiation-agnostic. Missing objects abort with an error, never a broken pack (ADR-004).GitPackIngest— client pack stream → indexed pack + fsck/ connectivity report. It prepares the validated ref updates; the transaction itself is applied byGitRefs(single CAS home — ingest validates, refs commits). Budgeted (ADR-009 max pack size); blocking-thread friendly.
Minimal-vs-full was the open sub-question; resolved as full family —
the four traits are each one or two methods plus types, and collapsing
them (e.g. refs into the registry) would force one impl block per
downstream where independent seams are cheaper to satisfy. The gix
feature implements all four; a downstream with its own object store
implements 3–4 and reuses 1–2, or none of it.
The gix feature (default on)
alkgit = { default-features = true }— wire layer + gix backend;default-features = false— wire/protocol layer only (an embedder brings its own backend). Hash:sha1pinned (the compile-time-rejected invariant fromdocs/research/gitoxide.md);sha256passthrough feature (OQ-05 policy unchanged).- Encodes the POC-2 prerequisites by construction: odb handle sharing
(
Arc<Store>shared, per-session handles,prevent_pack_unload()+ignore_replacements = true), generation on blocking threads, O(counts) memory, missing-objects abort. - Received-pack ingestion via
gix-pack::data::input(streaming-input)gix-fsck+gix-reftransactions (ADR-004). Validation against realgit pushis OQ-04.
Concurrency model
gixstructures:parking_lotshort-held locks; per-session handles moved intospawn_blockingtasks (POC-2's shape: store shared, handle per session, generation on blocking threads).- Poisoned locks:
unwrap_or_else(|e| e.into_inner())(convention 2). - The traits are
Send + Syncobject-safe; impls run under the adapter's tokio context.
Public API surface
Crate-root re-exports (the alktty pattern): backend traits + types,
GitAdapter/register_openable (producer), GitSession (consumer),
substrate types, Limits, protocol error enums; gix-feature types
(GixBackend-family) exported under the feature. The embedder-facing
freeze point remains OQ-03 (narrowed: it is now this crate's own publish,
not a multi-crate freeze).
Design Decisions
| ADR | Decision | Summary |
|---|---|---|
| 004 | Pack pipeline | data::output gen / data::input ingestion |
| 007 | ACL first | registry returns rule inputs |
| 008 | Repo identity | wire names are registry ids |
| 009 | Budgets | limits flow into gen/ingest |
| 010 | Pure protocol crate | traits in-crate, gix behind a feature |
Open Questions
- OQ-06: registry backing store (deferred(scope) — the trait is what matters; the gix feature can ship a config-file/classic-on-disk impl, and richer backing is downstream's choice).
- OQ-04: pack ingestion validation (deferred(unclear)).
- OQ-05: sha256 policy (deferred(scope)).
References
docs/research/gitoxide.md(API contract notes — normative for the gix impl)docs/research/poc2-findings.md(generation pipeline + prerequisites)- alktty
backend.rs/localmodule (the trait + feature template) - ADR-010 (the structural decision)