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.
117 lines
5.1 KiB
Markdown
117 lines
5.1 KiB
Markdown
---
|
|
status: draft
|
|
last_updated: 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](decisions/001-crate-decomposition.md) | Crate decomposition | core = storage, transport-blind |
|
|
| [004](decisions/004-pack-pipeline.md) | Pack pipeline | `data::output` generation, `data::input` streaming ingestion |
|
|
| [007](decisions/007-acl-before-advertisement.md) | ACL before advertisement | core supplies rule inputs, adapters enforce |
|
|
| [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 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" |