Structural decision (OQ-09 resolved): alkgit follows the alktty/ alktunnels template — a single published protocol crate on alkcall channels, no binary, no front doors. - ADR-010 supersedes ADR-001 (crate decomposition) and ADR-006 (http router factory); both marked Superseded - Single crate at repo root: Cargo.toml with gix feature (default-on backend implementations; wire layer compiles without it — gix-hash always-on with sha1 per the compile-time-rejected invariant), crates/ workspace deleted, src/lib.rs stub in place - doors.md replaces http.md/ssh.md/alkgitd.md: alkhttp git-feature sequencing (after first publish), alkssh requirement (fixed-grammar exec dispatch), native alk/git path, downstream assembly - backend.md replaces storage.md: GitRegistry/GitRefs/GitPackGen/ GitPackIngest traits (ingest validates, refs commits — single CAS home), gix feature encodes POC-2 prerequisites - transport.md reframed for the single crate; backend traits replace hook traits in the public API - OQ-09 resolved (all five sub-decisions in ADR-010), OQ-01 resolved (subsumed), OQ-03 narrowed to publish-freeze, OQ-08 narrowed to registry identity + vault placement, OQ-07 rescoped to the gix feature's registry impl - vision.md v2: single-binary/monorepo framing corrected as init-agent artifact; POC checklist marked complete - AGENTS.md + .opencode agent specs updated to the new shape Verification: cargo build (default + no-default-features), cargo test --all-features, clippy --all-features -D warnings, fmt --check all pass. Third review round: zero critical, all warnings/suggestions addressed (GitPackGen signature amended in ADR-004, stale anchors fixed, ADR-006 body tense normalized, CAS split stated, vision residuals cleaned).
5.5 KiB
status, last_updated
| status | last_updated |
|---|---|
| draft | 2026-09-21 |
alkgit: Git Smart Protocol (wire layer)
What it is
The wire half of the alkgit protocol crate: pkt-line session substrates,
protocol V2 state machines (advertisement, ls-refs, fetch, receive-pack),
and the substrate types that keep doors and handlers from touching
futures_io or raw packetline APIs. Depends on alkcall and — only under
the gix feature — the backend implementations (ADR-010). The wire layer
itself is backend-trait-only, which is what makes default-features = false compile without gix.
Substrate layer (ADR-005)
Two session entry points over one state-machine core. ADR-005 owns the full decision (what each substrate owns and why); the surface is:
- Duplex session (the
alk/gitALPN producer, channels-opened git sessions, embedder stream doors) — input: (peer identity, resolved repo id, duplex stream,Limits). Encapsulates the split/compat/packetline bridge, the request reader (delim-aware parsing,reset()discipline, break-on-error), and the sideband writer. - Stateless session (smart-http doors, e.g. alkhttp's future
gitfeature) — input: (peer identity, resolved repo id, request-reader, response-writer,Limits) per http POST; adds the http-framing rules (capability-dump skip, flush-only responses, probe handling). IO-abstract: the door supplies reader/writer; see doors.md for the mounting.
Both substrates feed the same V2 state machines; statelessness is a substrate property (per-request state), not a protocol fork.
Protocol core (ADR-003: V2-first)
Advertisement
- Emitted once per duplex session (never between commands — real git hangs on re-advertisement); per-request-set on http (stateless: the client re-sends the dump).
- Honest capability list: exactly what we serve (
ls-refs=unborn,fetch=wait-for-donefor the v1 done-path policy — ADR-003 pins the values; OQ-02 may extend them when multi-round lands,object-format=sha1). Unimplemented features are declined by omission (validated against real git, POC-1).git-upload-archiveis not served (fixed refusal — ADR-008's never-execute rule, ssh analog in doors.md).
ls-refs
- Parse
command=ls-refs(peel, symrefs, ref-prefix), stream ref lines from the backend's listing, flush.ref-prefixfiltering is client-driven.
fetch
- Parse wants/haves/done/args; object-format check (reject mismatches — POC-1 to-do).
- Negotiation policy (v1 initial): full-closure pack on
done(POC-validated). Multi-round ack/NAK negotiation: OQ-02. - Pack generation via
GitPackGen(ADR-004), streamed over sideband on duplex / sideband-in-response on http; generation runs onspawn_blockingwith the owned handle moved in (POC-2's shape: store shared, handle per session, generation on blocking threads). - Round/haves budgets enforced here (ADR-009).
receive-pack (push)
- Parse update requests (
<old> <new> <ref>+ shallow lines), ingest the pack stream (POC-3-verified: request bodies stream), apply CAS transactions, emit status report. The capability set, shallow policy, CAS timing, and exact status-report shape are OQ-04's investigation target (design intent: shape per OQ-04's resolution). - Ingestion via
GitPackIngest(ADR-004); validation pending — OQ-04 (includes the receive-pack version surface, which ADR-003's fetch-V2 decision does not cover).
Error taxonomy
- io errors are terminal (session ends); protocol errors map to pkt-line
error bands (duplex) or http status + body (stateless). Substrate-level
thiserrorenum; no panics in library code (convention 2).
Limits
Every session carries Limits (ADR-009): negotiation rounds, haves per
round, receive-pack max size, wall clock, sideband chunk size (fixed
65000), advertisement ref cap. Missing Limits is a type-level error.
Public API surface (v1)
Crate-root re-exports (alktty pattern; the full list in
backend.md §public API): GitAdapter + register_openable,
GitSession, substrate types, Limits, the backend traits (ADR-010's
seam), protocol error enums; gix-feature types under the feature.
Publish-freeze point: OQ-03.
Design Decisions
| ADR | Decision | Summary |
|---|---|---|
| 002 | Session boundary | duplex + stateless entry points |
| 003 | V2-first | honest advertisement, V0/V1 declined |
| 004 | Pack pipeline | generation on blocking threads, O(counts) |
| 005 | Substrate types | request reader, sideband sink, http framing rules |
| 009 | Budgets | Limits in every session tuple |
| 010 | Pure protocol crate | wire layer is backend-trait-only |
Open Questions
- OQ-02: V2 multi-round negotiation (open — efficiency, not correctness).
- OQ-04: receive-pack state machine + validation (deferred(unclear)).
- OQ-03: publish/API freeze (partially resolved — single-crate shape settled by ADR-010).
- OQ-05: sha256 policy (deferred(scope)).
References
docs/research/poc-1-findings.md,docs/research/poc2-findings.md,docs/research/poc3-findings.md(the normative wire behavior — observed against real git, not docs' grammar)docs/research/git-protocol.md(inventory + observed corrections)docs/research/gitoxide.md§"Wire format" (packetline contracts)- alktty
wire.rs/session.rs/adapter.rs(the template's half shapes)