Files
alkgit/docs/architecture/doors.md
T
glm-5.3-flash 666abd1da4 docs: review-002 minor fixes — op PATCH semantics, repo-id grammar, ssh tuple, ADR-016 glitches
- backend.md: git/repo/update pinned as PATCH (omitted fields unchanged;
  present fields replaced wholesale) — R-3; 'already_exists' disclosure
  posture recorded (accepted create-scope oracle; resolve-side stays
  collapsed) — R-6; repo-id grammar pinned (owner/name segments, rejection-
  only parsing, percent-encoded flat record-file naming, two-placeholder
  http-route note) — R-5
- doors.md: alkssh hand-off tuple gains service + authorized-repo marker
  (ADR-016/D-3 amendment rounds missed this third tuple site) — R-4
- ADR-016: collapsed-space and broken code-span glitches — R-8
- AGENTS.md: lifecycle paragraph records both gate reviews complete and
  decomposition unblocked

Verification: docs-only; cargo doc/test/clippy/fmt clean
2026-09-30 05:30:12 +00:00

7.9 KiB

status, last_updated
status last_updated
reviewed 2026-09-30

Doors: how alkgit is exposed

What this is

alkgit (per ADR-010) owns no front doors. This document records the two door mappings that exist or are planned in the family, and the requirements alkgit places on each. The protocol crate itself is door-blind (ADR-002): every door converges on the same two substrates.

The door pattern

Doors are family infrastructure: alkhttp (exists), alkssh (planned, after alksocks), the alknet rewrite (coming). A door wraps alkcall's producer/consumer in its wire protocol; services like git, tty, tunnels, and socks5 are payloads doors optionally expose. Downstream consumers (our platform deployment, a future gitea-like app) assemble the doors they want with the payloads they want.

Auth semantics are the door's auth (http: the door's token mechanism; ssh: the door's key-based identity) resolving an alkcall Identity (the identity-extractor seam that ADR-006 needed exists only in the door, where it belongs). alkgit consumes the resolved identity and the registry record: the per-repo check is alkgit-core's authorize policy function (ADR-011, ADR-015 — public+read anonymous-first-class, write always authenticated+granted, manage for repo administration), run at ADR-007's step-3 position by every door and by the channels open-op gate. There is no door-specific auth surface in alkgit and no scope constant — per-repo grants replaced the tty:open-style gate (the single-scope shape cannot express anonymous-public fetch).

alkhttp git feature (http mounting)

Scope: an alkhttp feature that maps two route shapes onto alkgit's stateless substrate (ADR-005):

Route Service
GET /{repo}/info/refs?service=git-{upload,receive}-pack advertisement (smart prefix + capability dump + flush)
POST /{repo}/git-upload-pack V2 fetch commands (one command per POST)
POST /{repo}/git-receive-pack push (streaming ingestion, budgeted body)
GET /{repo}/info/refs?service=git-upload-archive honest refusal (not served)

{repo} is the registry id (ADR-008); resolution + ACL run before any response byte (ADR-007).

Sequencing: the feature requires alkgit on crates.io (optional dependencies must resolve), so it lands in alkhttp 0.6 after alkgit's first publish. Until then, git-over-http is served by any downstream that mounts the stateless substrate directly — POC-3's httpservice.rs is the reference implementation of exactly that mapping.

Framing facts the feature must honor (all POC-3-validated, encoded in the substrate, not re-decided): responses end at flush (never 0002); top-level flush is one-shot per response (the receive-pack sideband report's inner flush lives inside band-1 and is part of the report framing — ADR-013 §8; the rule governs protocol-level sections only); flush-only POSTs are probes answered 200-empty; request bodies stream (no accumulation); response bodies stream under back pressure (bounded mpsc → Body::from_stream); request bodies carry a budget (ADR-009 — alkhttp custom routes are unbounded by default). Push framing per ADR-013 §12 (probe/Content-Length/chunked, request/result content types).

alkssh (git-over-ssh, future)

alkgit's requirement on alkssh (to record in alkssh's spec when it exists): parse the exec-request string with a fixed grammar — git-upload-pack '<repo>' / git-receive-pack '<repo>' — never shell- interpret it (ADR-008's never-execute rule), map the door's key-based identity to the alkcall identity space, resolve the repo id against the registry, run ACL, and hand the ADR-002 duplex tuple — (identity, repo, service, authorized-repo marker, post-auth stream, limits) — to alkgit's duplex session; the exec command is the service selector (ADR-016's per-path service-establishment rule). git-upload-archive gets a fixed refusal. V2 is expected (ADR-003); GIT_PROTOCOL=version=2 rides the ssh env mechanism.

Interim: no git-over-ssh path ships with alkgit. A downstream that needs it before alkssh lands can terminate wire-ssh itself (russh or otherwise) and consume the duplex session — that is exactly the embedder path ADR-002 defines, and it works today against the POC-1 shape. It is an embedder assembly concern, not alkgit scope.

The alkcall-native path (no adapter at all)

The alk/git ALPN producer and the channels open-op (channels/git/sub, params {repo, service} — ADR-016: the params are the negotiation, the service selector, and the open-time ACL point; the establisher resolves the repo and runs authorize with the action the service selects) need zero door code — POC-1 is that shape verbatim. On the direct-ALPN path GitAdapter parses the git-daemon request line (git-upload-pack <repo>\0host=…\0\0version=2\0 / git-receive-pack <repo>\0host=…\0) as the in-band preamble (ADR-016). Any alkcall-speaking client (including alkgit's own consumer half, GitSession — ADR-017's typed fetch/push client) can use either path. This is the baseline path; the http/ssh doors are conveniences layered on top for stock git clients, and the replicator path of the p2p deployment (direct push/pull between replicators) rides it directly.

Assembly (downstream responsibility)

There is no alkgit binary (ADR-010). A deployment assembles: alkcall connection sources (alkhttp/alktls for http, alkssh later, raw ALPN for the native path) + GitAdapter + a backend implementation (the gix feature's, or its own) + Limits from config + vault for any credential material. Reference sequence for our platform deployment lives in that deployment's docs, not here.

Design Decisions

ADR Decision Summary
002 Session boundary every door consumes the same tuple
003 V2-first honest advertisement per door
007 ACL first before any protocol byte
008 Repo identity wire names are registry ids
009 Budgets limits on every session
010 Pure protocol crate doors are family infrastructure
011 Per-repo authorization authorize policy, grants in records (amended: ADR-015)
012 Registry + ops op registration surface, two op kinds (gate amended: ADR-015)
013 receive-pack V0-framed push advertisement per door, report framing
014 Negotiation one round per POST; ack section is per-round, stateless
015 Manage grant + op gate manage tier, admin-OR-manage op gate
016 Native session preamble {repo, service} open-op params, request-line preamble, service in the tuple
017 Consumer half GitSession typed client — the direct-connection push/pull primitive
018 Trait signatures + storage errors backend-seam shapes pinned (the door-blind object-storage family)

Open Questions

  • None. (OQ-08 resolved by ADR-011 — door auth mechanics stay here, registry identity model settled; ADR-012 §3 pins the op registration surface, its gate amended by ADR-015. OQ-16 — grant-key identity namespace — lives at the identity-provider seam, not the door.)

References

  • docs/research/poc-1-findings.md (duplex shape), docs/research/poc3-findings.md (http mounting evidence, framing facts)
  • alktty/alktunnels architecture docs (the template this follows)
  • ADR-010 (supersedes ADR-001/006; this file replaces http.md, ssh.md, alkgitd.md)