The publish bump (core/w5-publish) over the green wave-5 gate:
- manifest: version 0.0.1 -> 0.1.0; the substrate's inter-crate pin
follows (alkgit = { path = "..", version = "0.1.0" })
- the family LICENSE-MIT / LICENSE-APACHE files added (every sibling
crate ships them; the package listing gained the two files)
- CHANGELOG: the 0.1.0 entry dated and the stale 0.0.1-note dropped
- tests: the two agent-string pins moved from the hardcoded version
to env!(CARGO_PKG_VERSION) — the src side builds the agent string
from the manifest version, so the pins now hold across bumps
Verification: cargo test (workspace), cargo test --all-features,
cargo test -p alkgit, both clippies (-D warnings), cargo fmt --check,
cargo doc --no-deps (0 warnings), the fuzz corpus gate (13/13),
cargo publish --dry-run --allow-dirty (77-file package) — all green.
9.2 KiB
Changelog
All notable changes to this crate are documented here. The format is based on Keep a Changelog, and this crate adheres to Semantic Versioning.
0.1.0 - 2026-10-23
The founding entry — the protocol core's first release. alkgit is
the git smart protocol for the alk family as a pure protocol crate
(ADR-010, the alktty/alktunnels template): the producer and consumer
halves of the git smart protocol riding alkcall channels on the
alk/git ALPN, with the backend seam (five #[async_trait] traits)
every storage implementation implements. The crate carries no binary
and no front doors — the alkhttp git/lfs features and alkssh are
family infrastructure; a downstream app embeds this crate, brings its
own door, and supplies its backends. The shipped alkstore + alkblobs
composition is the separate alkgit-substrate crate; this crate is
substrate-free by construction (ADR-025's two-member workspace).
The posture is honest advertisement (ADR-003): the wire advertises
exactly what is served — fetch=wait-for-done with the full ack loop,
object-format=sha1 pinned (the sha256 feature gates a passthrough
per OQ-05), unimplemented surface declined fail-closed rather than
half-served, and every session bounded by budgets (ADR-009): wall
clock, request bodies, advertisement refs, negotiation rounds, haves
per round, pack sizes, the ingestion decompressed-size cap, the
packless peek window, and the blocking-pool concurrency.
Added
Wave 1 — the seam (engine-blind, everything later waves compose against):
- The backend-trait family (ADR-018 §4):
GitRegistry/GitRegistryStore(the registry family) andGitRefs/GitPackGen/GitPackIngest(the object-storage family, allSend + Sync + #[async_trait], dyn-compatible, keyed on the resolvedRepoRecord). - The wire-shape seam types (ADR-018 §5):
RefLine(with the unbornoid: Nonesymref form),RefUpdate,RefOutcome,PreparedPush,PushOptions. - The registry record:
RepoRecord+Visibility+AccessAction(the ADR-015 three-action grant shape, opaque grant keys,deny_unknown_fieldsserde) and the repo-id grammar (validate_repo_id, backend.md §repo-id grammar). - The error model:
RegistryError(five variants) andStorageError(three variants) — infrastructure errors areErr, protocol failures are values (ADR-018 §7). - The budget model
Limits(ADR-009) with every default pinned;max_object_size(the ingestion decompressed-size cap) added in wave 5 pre-freeze. - The session-substrate machinery shapes (ADR-005): the duplex
pkt-line layer (
Session,Sideband,RawTail) and the stateless smart-http framing (StatelessRequest,StatelessResponse,BodyReader), plus the error taxonomy (SubstrateError,Service). - The in-memory backend test doubles (the contract-reference convention — every protocol wave's conformance work runs its machines against them).
Wave 2 — the wire serves fetch (upload-pack, dependency-free):
- The V2 advertisement (
advertise_v2— exactly the honest capability list, ADR-003) and the ls-refs machine (serve_ls_refs/parse_ls_refs_args— peel/symrefs/ref-prefix arguments, the unborn-HEAD symref line; the wave-5 rider-1 capture corrected the wire form to the upstream literalunborntoken — a zero-oid HEAD is a fetch want of the null oid for a real client). - The negotiation ack loop (ADR-014):
serve_fetch_round+parse_fetch_args— no-donerounds answered with the exactacknowledgmentsgrammar (ACK <oid>per recognized have,NAKonly when no ACKs, neverready), the done round streamingclosure(wants) − closure(recognized subset)as the packfile section, the want-less round answered empty — all behind theGitPackGen::common_havesseam (exists + is-commit). - The serving entries:
serve_duplex(advertisement-once + command loop under the wall clock) andserve_stateless_post/serve_stateless_advertisement(one POST = one command invocation, response rules: one-shot flush, never0002), both taking the ADR-007AuthorizedRepomarker by type. - The authorization front:
authorize(the ADR-011/015 policy function — public read allows anonymous, write is always authenticated + granted, unknown-repo ≡ unauthorized) andvalidate_ref_name(ADR-013 §9's deny-list). - The native transport (ADR-002/016):
GitAdapter(the direct-ALPN producer half), the git-daemon request-line grammar (parse_request_line/read_request_line), and thechannels/git/subchannels open op (register_openable) — unknown ≡ unauthorized collapsed to one generic denial at the gate.
Wave 3 — receive-pack (ADR-013 as amended by ADR-020):
- The V0 push advertisement (
advertise_v0): caps NUL-attached on the first ref line, thecapabilities^{}sentinel for empty repos, private repos advertise nothing (ACL first). - The push request machine (
parse_push_request/serve_receive_pack): command grammar (create/delete zero-id shapes), shallow rejection up front,push-optionsgated off v1,receive-pack's nothing-to-do shape. - The bounded packless peek (ADR-020 §1): the
packless_peekwindow with the four ordering rules pinned (push-options consumed before the peek; zero-bytes → packless CAS-only path; a partial pack header is a malformed-push error, never a silent downgrade). - The pack stream seam:
bridge_pack_source(the async→blocking relay,PackSourceBridge/PackSourceFault) — wire-side pack-size budget, the raw-tail escape on both substrates — andGitPackIngest::prepare(the prepare/apply split; the single CAS home inGitRefs::apply_updates; every failure framed as theunpack ngleg, neverErr). - The status report framing (ADR-013 §8): band-1-wrapped with its
inner flush when
side-band-64kwas selected, bare otherwise — substrate-owned so handlers cannot get it wrong.
Wave 4 — the consumer half + the op family:
GitSession(ADR-017 as amended by ADR-023): the typed git client over gix-transport's git-daemonConnectionon the alkcallBiStreamcompat halves.connect_directrides the ADR-016 request-line preamble;open_via_channelstakes the post-open stream.ls_refs+fetchspeak the client side of the same V2 grammar we serve (full ack-loop negotiation, rounds as full stateless commands, the done round's pack streamed to the caller's sink);pushis the hand-rolled send-pack (mirror of ADR-013's server shapes — gitoxide has no send-pack), with the client riders: a packless push holds the write side open until the report (ADR-020 §3) and every push reads the full report before the session could drop (ADR-023 §5). Client-direction budgets fail closed typed.- The
git/repo/*call-op family (ADR-012 §3/§5, gate per ADR-015 §3):create/delete/update/getasOperationSpec+ handler pairs overArc<dyn GitRegistryStore>(register_repo_ops), the PATCH semantics (review 002 R-3), the error-code table with the unknown ≡ unauthorized collapse, create seeding the caller's{read, write, manage}grants and minting ownership.
Wave 5 — validation & release readiness:
- The session split (review 005 R-1):
session_fetch/session_pushas flat sibling modules — zero public-API change. - The ingestion decompressed-size cap (review 004 R-2,
pre-freeze):
Limits::max_object_size— pack-declaration- independent expansion bounding with incremental inflate (no allocation sized by the declared size); a breach is pack-level validation (unpack ng), never a session error. - OQ-19 rider 2, the positive-ack capture: multi-have no-
donerounds ack each recognized have in request order and the done round's boundary set equals the recognized subset — validated on both serving substrates (disposition: validated, no retraction). - OQ-19 rider 1, the unborn-HEAD real-client validation:
git ls-remoteand a real clone of an unborn repo complete over both substrate doors, the unborn HEAD symref line served per the upstream literal-unbornemission (disposition: validated; the machine-side flush-only session end landed with the capture — the client's trailing flush is the quiet end, not a fault). - OQ-19 rider 3, the real-client grammar tokens (validated against
git 2.43.0 over both substrate doors):
include-tagaccepted and honored by omission (un-gated in the real client's V2 send path; the pack is the want closure as generated);session-id=honestly retracted (the advertisement never declares the capability, so a conforming client never sends it; the fail-closed decline stays); shallow/filter/server-option declined as unimplemented surface. - The
fuzz/harness: libFuzzer targets over the crate's ingress surfaces (the pkt-line framings, the request-line grammar, the negotiation command ingress, the repo-id grammar, the open-op params) with the committed corpus gate joining the verification list.
Notes
- The
sha256feature is a passthrough (wire capability line + request-side validation) — not a storage-format offer; the pinned default is sha1 (OQ-05).