refactor(architecture): ADR-010 — pure protocol crate (alktty template)

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).
This commit is contained in:
glm-5.3-flash committed 2026-09-21 10:54:03 +00:00
1 parent de922253a4
commit 86bf5a0cf0
37 files changed
+730 -947

No files matched your search

+103
View File
@@ -0,0 +1,103 @@
---
status: draft
last_updated: 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:
1. **`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.
2. **`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).
3. **`GitPackGen`** — (repo, wants, haves, limits) → streaming pack
(`io::Write` consumer). Negotiation-agnostic. Missing objects abort
with an error, never a broken pack (ADR-004).
4. **`GitPackIngest`** — client pack stream → indexed pack + fsck/
connectivity report. It *prepares* the validated ref updates; the
transaction itself is applied by `GitRefs` (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: `sha1` pinned (the compile-time-rejected
invariant from `docs/research/gitoxide.md`); `sha256` passthrough
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-ref` transactions (ADR-004). Validation against
real `git push` is OQ-04.
## Concurrency model
- `gix` structures: `parking_lot` short-held locks; per-session handles
moved into `spawn_blocking` tasks (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 + Sync` object-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](decisions/004-pack-pipeline.md) | Pack pipeline | `data::output` gen / `data::input` ingestion |
| [007](decisions/007-acl-before-advertisement.md) | ACL first | registry returns rule inputs |
| [008](decisions/008-registry-resolved-repo-identity.md) | Repo identity | wire names are registry ids |
| [009](decisions/009-bounded-resources-budget.md) | Budgets | limits flow into gen/ingest |
| [010](decisions/010-pure-protocol-crate.md) | 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`/`local` module (the trait + feature template)
- ADR-010 (the structural decision)