Expand description
alkgit-substrate: the shipped backend composition for the alkgit protocol core.
The complete ADR-019 composition implementing alkgit’s backend seam
over the alkstore + alkblobs substrate — the engine-generic reactive
halves, the coherence-contract cached read provider, the family
adapter pattern with engine twins, the schema migrations, the GC
wiring, and the LFS surface. The spec is docs/architecture/ substrate.md; the crate/feature placement (the two-member workspace,
sqlite on / postgres off / lfs on) is ADR-025. The composition
consumes (identity, repo id, duplex stream, limits) and stays
front-door-blind: doors are family infrastructure. The traits it
implements and the seam types it imports —
GitRegistry,
GitRegistryStore, GitRefs,
GitPackGen, GitPackIngest,
the RepoRecord record family — are all
published by the core crate; this crate re-exports none of them.
Public API surface is the crate-root re-export list (the convention); substrate.md §public API fixes the members — the exact Rust names are each implementation task’s to pin under OQ-03’s inventory.
§The module map (per-module, one workstream one file)
error— the substrate open/construction error surface (OpenError): the fallible-constructor posture ADR-024 §1 requires (construction fails loudly; a half-migrated store refuses service). Deliberately no conversion into the core’s error types.migrations— the ADR-024 machinery (both engines’ homes since the wave-10 placement split: the co-tenant connection handlesCoTenantSqlite(sqlite) and [CoTenantPg] (postgres, whose twin re-exports it) together, the migration runners, and the pg SQL plumbing) + the initial co-tenant schema.registry— the registry adapter trait pair, the in-memory default adapter (stamp-free per ADR-024 §6), the cached read provider, the alkgit registry-pair impls, and the engine-neutralcrate::registry::HEAD_SEED_TARGETpin both twins seed with.refs— the refs co-tenant row table: the CAS-semantics reference impl (InMemoryRefTable, engine-free), the sqlite row-CAS twin (SqliteRefTable, thesqlitefeature — everyapply_updatescall in oneBEGIN IMMEDIATEtransaction on the co-tenantgit_refsrows) and the pg row-CAS twin (PgRefTable, thepostgresfeature — the same one transaction per call, the sqlite twin’s engine-swapped, the wave-7 N-c rider), the table-layer name validation (the core’svalidate_ref_namedeny-list reused, the invalid-name →funny refnameper-ref denial mapping pinned), and the unborn-HEAD symref row shape.reactor— the reactive halves: the announce composition (publish/notify/enqueue, fail-soft each), the wake runner (the provider’s invalidation trigger), the stream consumer (the cursor model + per-seq idempotency), the reconcile sweep (the crash-window closure), and the engine-generic construction wiring (Reactorfrom the engine handle + provider).sqlite/postgres— the engine twins (sqliteon /postgresoff per ADR-025), feature-gated module paths and so not linked here: a default-feature doc build does not see them. The postgres twin (postgres,w6-registry-postgres) carries the LISTEN/NOTIFY-leg asymmetry (no file-level bump exists — a lost hint leaves caches stale until the reconcile tick) and the env-gated live-pg harness tests.odb— the object front: the alkblobs git-object-family wiring (loose_form,oid_key,key_to_oid) and the syncgix_object::Find/gix_object::Exists+gix_pack::FindFind front (ObjectFrontconstructed once with per-sessionSessionFindviews, the miss-recording shape theStorageError::ObjectMissingabort maps back through) with the one sync/async bridge (ObjectFront::block_onfrom blocking pipeline tasks — never from async contexts,ObjectFront::block_in_placethere).packgen— the substrateGitPackGenimplement (PackGen): ADR-004’s pipeline over the real Find (the two-stage closure, the missing-objects abort), the ADR-014 §5 ack predicate as the realcommon_haves, and both serving shapes (direct streaming; through-store ranged windows with mid-flight digest verification over thePackCacherequest-digest cache), both serving straight into the frozen trait’s sink.ingest— the substrateGitPackIngestimplement (PackIngest): ADR-020 §2’s ingestion composition — the budgeted host working area’s index (thin bases through the substrate Find), the unpack-to-loose under the decompressed-size cap with the guards riding the w8-pin-registry’s custody seam, the full-graph connectivity walk from the pushed tips, and the working-area discard. Construction is the composition entry’s (the working area’s root is the entry’s config knob); the exact public names join the OQ-03 substrate-side inventory with the entry task.compose— the single composition entry (SubstrateAssembly): one fallible constructor per assembly (mem — the completeness shape taking the substrate engine handles; sqlite — the default single-host shape, config-opened co-tenant; postgres — the fleet/durable-shared shape, the feature), wiring the complete backend per shape: the registry pair + cached read provider + reactor (the assembly shapes, unified), the write-counter-wrapped refs table under the w8 custody/commit side, the object front, the pack serving shapes, the ingest, the registered ref-table-closure liveness source, and the maintenance chain.liveness— the GC liveness source: the ref-table closure (RefClosure, thealkblobs::LivenessSourceimplement — the full graph walk over the object front, parents included, gitlinks neither marked nor walked), the refs-rows seam (RefRows, the durable refs fingerprint the memo keys on, POC-O’s memoized-closure shape with the invalidation mechanism pinned: read-side durable fingerprint + the in-process write counter, the fleet posture stated), the write-counting refs wrapper (VersionedRefTable), and the registration wiring (RefClosure::register) — the maintenance chain’s sweep dispatch requires it.maintenance— the maintenance chain’s consumer side (MaintenanceChain): the@everysweep schedule registration (SWEEP_SCHEDULE) + the supervised scheduler runner, the worker’s claim loop overMAINTENANCE_QUEUE(theMaintenanceJob) dispatch:Sweep→ theMAINTENANCE_LOCKleader lock + the store’s sweep with the report as data;PackHousekeeping→ thePackCacherelease path), and the runner supervision (the wake runner’s restart on both stop shapes (Reactor::run_wake_runner’s collapsed quiet returns) and the reconcile tick’s driving (MaintenanceOpts).lfs— the LFS pointer-lifecycle row surface (thelfsfeature; ADR-022 §4): theLfsRowstrait over one row per reference, theInMemoryLfsRowsreference impl + the engine twins (SqliteLfsRows,PgLfsRows), the refcount semantics + the re-protection contract pinned, the repo-deletion removal legs riding the twins’ record-removal transactions unconditionally and the mem shape’s legs in the composition entry, the epoch wrapper (VersionedLfsRows, the liveness discipline’s bump-after-commit half —crate::liveness) carried by the twin assemblies themselves (the refs twins’ posture —lfs_rows()hands the wrapped surface,lfs_version()the shared counter).lfs_adapter— the storage-side batch/transfer adapter (thelfsfeature; ADR-022 §1–3): the batch/checking mapping, the pre-keyed put / ranged-fetch byte paths with the whole-span oid verification, and the wired-provider posture (LfsGrantProvider— the facade seam is the embedder’s; the adapter is door-side infrastructure, split documented in the module doc).
The pending-pin registry and the receive flow’s
committed-ref side live in the composition-internal pins module
(substrate.md §public API carries the receive-pack composition as
internal to the trait impls — no re-export): the
PendingPinRegistry (the pin bridge’s registry half — retain from
prepare, drain-with-correlation from apply, prune-stale from any
apply, drop-on-abort), the CommittedRefs wrapped GitRefs
implement (stale-prune → CAS → drain-only-after-commit, then the
post-CAS marker + announce legs fail-soft), and the
RegistryMutations legs surface (the mem shape’s fused legs plus
the engine-twin assemblies’ impls).
§The composition entry’s pinned decisions (OQ-03 inventory,
compose)
SubstrateAssembly (mem/sqlite/postgres + accessors),
AssemblyOptions, PackServing — the re-export list grows by
exactly the entry surface.
Re-exports§
pub use compose::AssemblyOptions;pub use compose::PackServing;pub use compose::SubstrateAssembly;pub use error::OpenError;pub use lfs::SqliteLfsRows;pub use lfs::InMemoryLfsRows;pub use lfs::LfsRow;pub use lfs::LfsRows;pub use lfs::VersionedLfsRows;pub use lfs_adapter::LfsActions;pub use lfs_adapter::LfsAdapter;pub use lfs_adapter::LfsAdapterConfig;pub use lfs_adapter::LfsAdapterError;pub use lfs_adapter::LfsBatchObject;pub use lfs_adapter::LfsBatchOperation;pub use lfs_adapter::LfsBatchRequest;pub use lfs_adapter::LfsBatchResponse;pub use lfs_adapter::LfsDownload;pub use lfs_adapter::LfsGrantProvider;pub use lfs_adapter::LfsHrefMint;pub use lfs_adapter::LfsObjectAnswer;pub use lfs_adapter::LfsObjectError;pub use lfs_adapter::LfsRange;pub use liveness::lfs_media_key;pub use liveness::LfsMedia;pub use liveness::RefClosure;pub use liveness::RefRow;pub use liveness::RefRowState;pub use liveness::RefRows;pub use liveness::RefRowsSnapshot;pub use maintenance::MaintenanceChain;pub use maintenance::MaintenanceOpts;pub use maintenance::SweepVerdict;pub use maintenance::WorkerEvent;pub use maintenance::LOCKED_OUT_RETRY_SECS;pub use maintenance::SWEEP_SCHEDULE;pub use migrations::CoTenantSqlite;pub use odb::key_to_oid;pub use odb::loose_form;pub use odb::oid_key;pub use odb::ObjectFront;pub use odb::SessionFind;pub use packgen::PackCache;pub use packgen::PackGen;pub use reactor::AnnounceReport;pub use reactor::AnnouncingRegistry;pub use reactor::AppliedWatermark;pub use reactor::MaintenanceJob;pub use reactor::Reactor;pub use reactor::RegistryEvent;pub use reactor::EVENTS_STREAM;pub use reactor::MAINTENANCE_LOCK;pub use reactor::MAINTENANCE_QUEUE;pub use reactor::WAKE_CHANNEL;pub use refs::SqliteRefTable;pub use refs::InMemoryRefTable;pub use refs::VersionedRefTable;pub use refs::CAS_STALE_REASON;pub use registry::CachedRegistryProvider;pub use registry::InMemoryRegistry;pub use registry::RegistryBackend;pub use registry::RegistryRead;pub use registry::RegistryRow;pub use registry::RegistryWrite;pub use registry::HEAD_SEED_TARGET;pub use sqlite::SqliteRegistry;pub use sqlite::SqliteRegistryAssembly;
Modules§
- compose
- The single composition entry (wave 8) — the complete backend assembly (substrate.md §public API: “construction wired by a single composition entry that takes the substrate engine handles (the assembly-level one-statement engine choice)”; substrate.md §assembly shapes: “Engine choice is one assembly-level statement — three shapes, zero assembly code”).
- error
- The substrate open/construction error surface — the wave-6 scaffold’s pin (ADR-024 §1’s fallible-constructor posture: construction fails loudly and a half-migrated store refuses service rather than degrading silently).
- ingest
- The substrate’s
GitPackIngestimplement (PackIngest) — ADR-020 §2’s ingestion composition, for real: the received pack indexes into a budgeted host working area (thin bases resolving through the substrate Find), the indexed objects unpack into alkblobs as loose-form objects under the git-object family (the wave-7 object front’s family put — the store’s verification-on-put is the oid re-derivation, corruption cannot enter undetected), the guards ride the w8-pin-registry’s custody seam, connectivity closes the graph from the pushed tips, and the working area is discarded. The reference shape is POC-O’singest.rs; the reference semantics are the wave-3 doubles’MemPackIngest(tests/common/mod.rsin the core crate). - lfs
- The LFS pointer-lifecycle row store (wave 9) — the durable
reference map ADR-022 §4 places alkgit-side: one row per reference,
(repo_id, oid, size), over the co-tenantlfs_objectstable that ships day-one in both engine step sets (ADR-024 §5 — the table is unconditional in the schema, thelfsfeature gates this surface consuming it, so the stamp stays unit-shaped). The repo_id is the registry-resolved id (the ops namespace on the batch’s ACL path); the oid is the LFS media oid (64 lowercase hex — the raw sha256 of the content, byte-exact theGitObjectSha256digest under alkblobs ADR-018 §1, though the row store itself carries no key arithmetic); the surface is consumed by the batch adapter (assertion at check/upload time, per-repo reads) and the LFS liveness source (the full row read feeding the sweep chain). - lfs_
adapter - The LFS batch/transfer adapter (wave 9) — the storage-side logic of
the LFS protocol’s batch/checking and byte paths, as a substrate
surface under the
lfsfeature (ADR-022 §1–2; lfs.md §1–2; the substrate-side piece of ADR-025’s LFS-surface member). The alkgit core has no native LFS op set (git-lfs speaks HTTP only) — the door is the alkhttplfsfeature (family infrastructure); this surface is what that door consumes, front-door-blind: it carries the storage-side mapping and never touches HTTP. - liveness
- The GC liveness sources over alkgit’s own durable rows (waves 7
and 9): the ref-table closure — every ref row’s full reachable
graph walk over the substrate object front — and, under the
lfsfeature, the media rows source (LfsMedia, substrate.md §GC sources 1 and 2; ADR-019 §6) — both registered as in-processalkblobs::LivenessSources on the composition’s store at the composition entry (crate::compose). - maintenance
- The GC maintenance chain’s consumer side (wave 7 — substrate.md
§GC; ADR-019 §6; POC-R’s validated cross-process run, POC-R’s
maintenance.rs): the schedule registration + the runner, the maintenance worker’s claim loop, the leader TTL lock, and the sweep dispatch — the chain that turnscrate::reactor::MAINTENANCE_QUEUE’s payload vocabulary (MaintenanceJob) into GC. - migrations
- The registry schema migrations (ADR-024) and the co-tenant connection handle.
- odb
- The substrate object front (wave 7): alkblobs as the git-object
store under the derivation family, and the sync Find the pack
pipelines consume (
gix_object::Find+gix_object::Exists,gix_pack::Find) — substrate.md §object storage; ADR-019 §1; the POC-OSubstrateOdbpattern. - packgen
- The substrate’s
GitPackGenimplement (PackGen) — pack generation over the real Find front (ObjectFront’s per-sessionSessionFindviews) and the negotiation ack seam’s real predicate (the trait’scommon_haves, ADR-014 §5) — substrate.md §object storage “Packs”; ADR-004 is authoritative for the pipeline. - reactor
- The reactive halves — the engine-generic reactor (ADR-019 §5, substrate.md §the reactive halves, POC-R’s validated composition).
- refs
- The refs co-tenant row table (substrate.md §refs, ADR-019 §2) — the
object-storage family’s third trait (
GitRefs) in three shapes: - registry
- The registry: the co-tenant tables behind the family adapter pattern (ADR-019 §3–4, substrate.md §registry, POC-R’s validated shape) — the engine-generic half of the family.
- sqlite
- The sqlite registry twin — the family adapter pattern’s default
engine assembly (ADR-019 §3, substrate.md §registry: “one trait
pair, two implements — the sqlite adapter (
sqlitefeature,alkstore-sqlite+ the co-tenant rusqlite connection)”).