Expand description
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 lfs feature (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 alkhttp lfs feature (family infrastructure); this surface
is what that door consumes, front-door-blind: it carries the
storage-side mapping and never touches HTTP.
§The adapter/door split (the wave’s spec-level call, pinned here
for the gate)
ADR-025’s neutral record names the door-side batch mapping as riding alkblobs directly; the row assertion is the composition-owned piece only this surface carries. Drawn exactly:
The door’s side (never here): the JSON batch protocol parsing
and the HTTP route surface; the auth plumbing (alkhttp ADR-073’s
Basic-userinfo tolerance on the batch); the anonymous-public
anon identity synthesis (the adapter refuses an absent
identity — the door synthesizes the identity, the grant
short-circuits on the public-repo flag); href/token minting
(LfsHrefMint is the mint-input carrier — the door mints the
absolute URLs with per-action Authorization; the adapter never
mints a URL or a door token); HTTP Range-header parsing and the
206/416 responses; the object-size ceiling choice (the budget per
assembly, the door’s LfsAdapterConfig::max_object_bytes); and
the batch request’s transfers negotiation (the adapter carries
no negotiation input and answers basic — the door reads the
client’s list and refuses a request that excludes basic before
the batch reaches the adapter; the wave-9 gate’s recorded door
duty, lfs.md §1’s pinned shape).
The adapter’s side (this surface): the batch’s per-object
existence answered over the ops control plane — blobs/stat
through an
OperationContext
built with the caller’s identity and the wired ownership
provider (the POC-L door’s DirectOps binding shape as a substrate
surface); the response objects’ shapes ({oid, size, authenticated} + the per-object action grant-carriers); the row
assertion at check time (the moment the server learns the pair —
lfs.md §3, over the LfsRows surface); the
byte paths: the pre-keyed put (upload) and the ranged fetch
with per-window slice-digest verification (download); the
wired-provider requirement (never the static fallback).
What rides alkblobs directly (no substrate surface): the JSON
batch protocol itself is the door’s; the facade seam
(Store::put_as(GitObjectSha256, len, stream) / read_range) is
the in-process embedder alternative with no ops plane at all —
deliberately not re-exposed here (the embedder binds
SubstrateAssembly::blobs
directly; the adapter is the ops-plane surface). The wire ops
(blobs/put / blobs/fetch, the channel data plane) remain the
fleet/remote consumer’s form — the DirectOps-vs-loopback binding
choice sits door-side.
§The pinned protocol facts (lfs.md §1, riding the shapes)
hash_algoanswerssha256only: a batch carrying any other declared algorithm is refused (LfsAdapterError::HashAlgo— the door’s 409).verifyis not served: no batch path produces a verify action.- Transfer is
basic; the download action’s mint input is the whole media oid (range negotiation never rides the batch — the client’sRangerides the transfer GET). - The upload key is formable in advance (ADR-022 §1: under
Algorithm::GitObjectSha256the oid is the digest — the key is[0x04] + oid bytes): existence is a directblobs/staton the formed key (the translate-then-stat is direct; there is no mapping row, and nohaveuse — that is the replication diff verb).
§The byte paths (ADR-022 §2)
- Upload — the pre-keyed put. The offer carries the claimed
oid and the batch’s size; a size-less offer is a protocol error
(
LfsAdapterError::SizelessOffer— LFS clients always send size; the door refuses before the body). The put rides the put handler’s contract minus the channel: the one-read tee (a sha256 pass alongside a bounded pipe the facade put consumes concurrently viaput_as(GitObjectSha256, Some(len), …)), the claim cross-check before the facade’s EOF — a body the derivation contradicts kills the put pre-commit (LfsAdapterError::MislabeledBody: no stored content, no held pin — the zero-residue discipline the put’s stage hygiene carries on both tiers) — then the custody hand-over through theOpsContextverbs: fleet (mint_fleet, then the immediateconfirm— the upload is complete, so the token’s ticket retires at the confirmation and the mint boundary’s admission cap stays live per upload, ADR-022 §5; the fleet pin row’s TTL is the durable protection — a dropped unconfirmed ticket would hold an admission slot until process end, the wave-9 gate’s fix) or non-fleet (mint_custodial+confirm, the LFS pattern POC-L validated; a mint refusal at the admission cap isLfsAdapterError::MintRefused, answering the already-committed put honestly). The reference row is asserted at upload time too (batch check or upload — lfs.md §3). - Download — the ranged fetch. Every download serves verified
windows: the requested range (or the whole entry) is split
internally at
LfsAdapterConfig::window_bytesand each window ridesStore::read_range, whose ADR-006 slice digest is checked mid-flight — a window’s bytes are yielded only after the independently computed sha256 of exactly the returned window bytes matches the read’s slice digest; a mismatch aborts the stream mid-flight (the caller re-fetches — the ranged arm’s answer is the mid-flight-verified shape). The resolved span is budget-gated byLfsAdapterConfig::max_object_bytes— every form the adapter will actually produce counts (the range-less whole serve, the open-ended resume, any resolved span;bytes=0-is a whole download and refuses over the ceiling — the wave-9 gate’s fix, the whole-arm budget’s bypass closed). Verification, stated precisely (the gate’s fix): a whole-span download additionally rides the end-to-end oid digest check — the windows’ bytes accumulate into one sha256 pass, and the finished digest is compared against the key’s derivation digest (the identity family’s digest is the raw content’s hash, so the comparison is the oid verification the large tier’s reads carry no re-derivation for) before the last window yields. A partial span’s windows carry the length + slice checks only — the store interior’s ADR-006 digests, not an oid conclusion. The pinned window-splitting call (drawn against lfs.md’s “the door owns window splitting”, flagged for the gate): that fact governs the door binding the ops byte-path (the loopback/remote forms, wherefetch_max_total_bytesbounds the op’s ranged arm). This side of the HTTP boundary the adapter owns the arithmetic: a download call splits internally atwindow_bytesper verified window; the door’s HTTP work is Range parsing and the budget, not window counting.
§The wired ownership provider (alkcall ADR-048’s posture, composed)
The adapter takes the ownership provider as a required
constructor argument — there is no Option, no static path, and
every context it builds wires
ownership: Some(provider): the static Identity.resources
fallback is unreachable through this surface (the POC-L
gateway-gap regression’s posture; the battery pins it — an
identity carrying a static resources claim is refused unless the
wired provider grants). The shipped provider is
LfsGrantProvider: alkgit’s registry composed onto the ops ACL
— the same per-repo grants the git surface composes (ADR-011’s
posture), served through the cached read provider’s sync resolve.
alkcall ADR-048’s loud default guards the gateway dispatch spine
(the wire path); here the guard is the constructor requirement
plus the battery. The anon composition is door-side (above).
Structs§
- LfsActions
- The per-object action grants (the LFS shape:
uploadrides the absent objects’ answers for an upload batch,downloadthe present ones for a download batch; at most one side is populated per response object). - LfsAdapter
- The batch/transfer adapter — the storage-side surface the alkhttp
lfsdoor consumes (ADR-022 §1–3, lfs.md §1–2 — the adapter/door split is the module doc). Construct over the object pool, the rows surface, the wired ownership provider (required — see the module doc), and the config knobs. - LfsAdapter
Config - The batch/transfer adapter’s knobs (the door budgets the ceiling;
the adapter splits at the window). Defaults are the POC-L datums:
the 32 MiB split window and the
fetch_max_total_bytes-shaped 64 MiB object ceiling (raised per assembly to trade opens for windows — lfs.md §2). - LfsBatch
Object - One batch request object: the pointer’s oid and its mandatory size (the batch’s size is mandatory — LFS clients always send it; the door refuses the size-less form before this surface).
- LfsBatch
Request - The batch/checking request as the door hands it over (post-JSON, post-auth plumbing — the identity resolved, the operation mapped).
- LfsBatch
Response - The batch/checking response — the transfer is
basicand the served algorithm issha256(the pinned protocol facts; the door serializes the JSON shape). - LfsDownload
- The download’s verified-window stream — an
AsyncReadfed by a pump that splits the requested range at the configured window size and yields each window only after its mid-flight slice-digest check passes (the module doc’s byte-path section) — ADR-022 §2 as amended (the download byte path’s verification posture). A failed window check or a failed read surfaces as an io error at the yield point (already-delivered windows stand; the caller aborts and re-fetches). The pump ends at EOF; a zero-length whole read is an empty stream (the entry’s zero-length entry served). - LfsGrant
Provider - The wired ownership provider — alkgit’s registry composed onto the
ops ACL (the batch’s authorization posture: lfs.md §1 — the
per-repo grant governs batch access, the ADR-011 posture composed
onto the ops ACL). The alkblobs ops specs gate on
blob-namespaceresources whose id is the payload’s namespace — the repo id; this provider answers with the sameauthorizepolicy function the git surface composes:readgranted (or anonymous-public — the door’s synthesizedanonidentity rides the public-repo flag here),writeper the grant monotonicity (manage⊃write⊃read). Unknown repos deny by default — the unknown ≡ unauthorized posture. Served through the cached read provider’s sync resolve (the hot path — no await, no round trip; a stale cache delays revocation until the next refresh, the same posture the git serving path takes). - LfsHref
Mint - The action-grant carrier the response objects hold — the mint
inputs, never a URL: the door mints the absolute href and the
per-action
Authorizationfrom these (front-door-blind — no URL or door token is formed here). - LfsObject
Answer - One batch response object — the pinned shape
{oid, size, authenticated}plus the optional per-object error/actions branches.authenticatedistruewhenever the object is answered: the request rode the wired ownership provider’s grant (the ops ACL path), so every served action is server-authorized — the anonymous-public composition (the door’s synthesizedanonidentity on a public repo’s read) answers the same way. - LfsObject
Error - A per-object error, carried in the response object (the LFS
per-object error shape — the object’s
errorfield; the HTTP mapping stays the door’s). - LfsRange
- The byte range a download call serves:
[offset, offset + len)withlen = Nonemeaning to the entry’s end (the door maps the HTTPbytes=a-b/bytes=a-forms onto the explicit count).
Enums§
- LfsAdapter
Error - The adapter’s error surface (thiserror family; message-only —
the engine source types stay off the surface, the row store’s
StorageErrortext is carried). The whole-batch failures (forbidden, hash-algo) and the transfer-path failures are errors; per-object failures ride the batch response’s error objects, not this surface. - LfsBatch
Operation - The batch API’s operation half (the door maps the wire’s
"upload"/"download"onto it).