Files
alkgit/CHANGELOG.md
T
glm-5.3-flash 0dd5721290 chore(release): alkgit 0.1.0
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.
2026-10-23 12:29:44 +00:00

9.2 KiB
Raw Permalink Blame History

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) and GitRefs / GitPackGen / GitPackIngest (the object-storage family, all Send + Sync + #[async_trait], dyn-compatible, keyed on the resolved RepoRecord).
  • The wire-shape seam types (ADR-018 §5): RefLine (with the unborn oid: None symref form), RefUpdate, RefOutcome, PreparedPush, PushOptions.
  • The registry record: RepoRecord + Visibility + AccessAction (the ADR-015 three-action grant shape, opaque grant keys, deny_unknown_fields serde) and the repo-id grammar (validate_repo_id, backend.md §repo-id grammar).
  • The error model: RegistryError (five variants) and StorageError (three variants) — infrastructure errors are Err, 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 literal unborn token — 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-done rounds answered with the exact acknowledgments grammar (ACK <oid> per recognized have, NAK only when no ACKs, never ready), the done round streaming closure(wants) − closure(recognized subset) as the packfile section, the want-less round answered empty — all behind the GitPackGen::common_haves seam (exists + is-commit).
  • The serving entries: serve_duplex (advertisement-once + command loop under the wall clock) and serve_stateless_post / serve_stateless_advertisement (one POST = one command invocation, response rules: one-shot flush, never 0002), both taking the ADR-007 AuthorizedRepo marker by type.
  • The authorization front: authorize (the ADR-011/015 policy function — public read allows anonymous, write is always authenticated + granted, unknown-repo ≡ unauthorized) and validate_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 the channels/git/sub channels 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, the capabilities^{} 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-options gated off v1, receive-pack's nothing-to-do shape.
  • The bounded packless peek (ADR-020 §1): the packless_peek window 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 — and GitPackIngest::prepare (the prepare/apply split; the single CAS home in GitRefs::apply_updates; every failure framed as the unpack ng leg, never Err).
  • The status report framing (ADR-013 §8): band-1-wrapped with its inner flush when side-band-64k was 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-daemon Connection on the alkcall BiStream compat halves. connect_direct rides the ADR-016 request-line preamble; open_via_channels takes the post-open stream. ls_refs + fetch speak 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); push is 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 / get as OperationSpec + handler pairs over Arc<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_push as 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-done rounds 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-remote and a real clone of an unborn repo complete over both substrate doors, the unborn HEAD symref line served per the upstream literal-unborn emission (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-tag accepted 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 sha256 feature is a passthrough (wire capability line + request-side validation) — not a storage-format offer; the pinned default is sha1 (OQ-05).