Files
alkgit/docs/architecture/storage.md
T
glm-5.3-flash 8f73da5d12 docs(architecture): phase 1 bootstrap — specs, 9 ADRs, OQ tracker
Architecture documentation structure per sdd_process phase 1:

- README index (doc table, ADR table, lifecycle), overview with crate
  map, dependency rules, and security invariants
- Component specs: storage, transport, http, ssh, alkgitd (all draft)
- ADRs 001-009: crate decomposition, front-door-blind core, V2-first
  protocol, pack pipeline (data::output generation / data::input
  ingestion), session substrate types, http adapter composition
  (proposed, OQ-01), ACL-before-advertisement, registry-resolved repo
  identity, bounded-resources budgets
- open-questions.md: OQ-01..08 with two deferred(scope), one
  deferred(unclear), door-type definitions, blocker tracker tasks in
  tasks/architecture/
- v1 ssh-door decision recorded: russh terminates wire SSH in alkgitd;
  alkcall channels stay the internal substrate (OQ-03 partially
  resolved)

Two review rounds (fresh-context subagent): 4 critical + 17 warnings
fixed in round one; zero critical + 4 warnings + 5 suggestions fixed in
round two. All ADR/OQ cross-references verified resolving.
2026-09-21 03:55:33 +00:00

5.1 KiB

status, last_updated
status last_updated
draft 2026-09-21

alkgit-core: Storage

What it is

The repository storage layer: repo registry, object database wrappers, ref store, pack generation/ingestion, and access-rule input types. It is transport-agnostic and front-door-blind (ADR-001): it knows nothing about pkt-lines, http, or ssh.

Why this shape

gitoxide provides the primitives (odb, packs, refs, fsck, objects); the generation-pipeline decision is ADR-004 (POC-2-validated). The crate exists to (a) wrap gix with a coherent session-safe API (gix_odb::Cache is not Sync — the sharing rules are enforced by the API in this crate), (b) own the registry (ADR-008), and (c) hold the ACL input types the adapters and alkcall share.

Components

Repository registry

  • Authoritative (repo id → storage root, visibility, ACL scope) mapping.
  • Wire repo names are registry IDs, never paths (ADR-008); resolution failure is indistinguishable from authorization failure (ADR-007).
  • Backing store: open — OQ-06. Core defines the trait; alkgitd picks the backing. Metadata holds no secrets (vault references at most).
  • Storage roots are server-configured; the registry maps IDs onto them.

Repository access (Repo)

  • Opens a (storage root, hash algo) into an object database + ref store.
  • Wraps gix_odb::Store sharing: Arc<Store> shared across sessions, per-session handles (to_handle_arc() + prevent_pack_unload() + ignore_replacements = true — the POC-2 prerequisites). The public API hands out handles, never the raw Cache.
  • Ref listing for advertisement: refs + peeled tags + symref targets, the ls-refs response data.
  • Ref transactions: CAS apply for receive-pack (gix-ref transaction module), with name validation (git ref rules + reserved-namespace deny-list; docs/research/git-protocol.md §security notes).

Pack generation (fetch side)

  • Type: (odb handle, wants, haves, limits) → streaming pack (io::Write consumer). Negotiation-agnostic: negotiation produces the boundary sets, the writer streams them (ADR-004).
  • Encodes the POC-2 composition: tip peeling → commit-ancestry walk → TreeContents count → entries → bytes; missing objects abort (never emit a broken pack); entry statistics surface as metrics.
  • Memory profile is O(counts) — the budget model (ADR-009) bounds aggregate work, not internal buffering.

Pack ingestion (receive side)

  • Client pack stream → indexed pack + fsck/connectivity report + per-ref CAS application. Uses gix-pack streaming-input + gix-fsck + gix-ref transactions. Shape is designed (ADR-004); validation against real git push is pending — OQ-04.
  • Received pack size is budgeted (ADR-009 max pack size); ingestion runs on blocking threads like generation.

Access-rule input types

  • The types alkcall AccessControl::check consumes for repos: visibility (public/private), identity-based read/write. Deliberately input types: the evaluation function lives in alkcall (single source of authorization logic); invocation/wiring happens in the adapters (ADR-007). Core defines what a repo's rule set looks like.
  • v1 scope: repo visibility + identity read/write, nothing richer (vision §"Primary deployment target").

Concurrency model

  • Store/registry structures: parking_lot short-held locks (project convention 3).
  • odb handles: per-session, owned, moved into spawn_blocking tasks.
  • Ref transactions: serialized per-ref by gix-ref's lock files; the registry mapping's read-mostly synchronization (ArcSwap-class or equivalent) is part of OQ-06's backing decision.
  • Poisoned locks: unwrap_or_else(|e| e.into_inner()) per convention 2.

Public API surface (v1)

lib.rs re-exports (module structure per convention 14): registry trait + types, Repo/handle types, pack generate/ingest types, ref-transaction API, ACL input types, error enums (thiserror, no panics, no unwrap outside tests). The embedder-facing freeze point is tracked in OQ-03.

Design Decisions

ADR Decision Summary
001 Crate decomposition core = storage, transport-blind
004 Pack pipeline data::output generation, data::input streaming ingestion
007 ACL before advertisement core supplies rule inputs, adapters enforce
008 Repo identity wire names are registry IDs
009 Budgets limits flow into generation/ingestion

Open Questions

  • OQ-06: registry backing store (deferred(scope) — blocked on metadata-scale requirements).
  • OQ-04: receive-pack ingestion validation (deferred(unclear) — pieces decided, push state machine needs a walkthrough/POC).
  • OQ-03: embedder-facing API freeze (deferred(scope)).

References

  • docs/research/gitoxide.md (the API contract notes are normative here)
  • docs/research/poc2-findings.md (generation pipeline + prerequisites)
  • docs/research/git-protocol.md §"Server-side pack generation"