--- status: reviewed last_updated: 2026-09-30 --- # Open Questions All unresolved architecture questions, centrally tracked. Status values: `open` (needs resolution now), `partially resolved` (decision made but a narrower question remains — named in the entry), `resolved` (decision made, ADR recorded), `deferred(scope)` (waiting on external information — blocked-on condition stated), `deferred(unclear)` (pieces exist, shape needs investigation). See `docs/sdd_process.md` for the deferral protocol (blocker tasks in `tasks/architecture/`). **Door type** classifies reversal cost: `one-way` decisions are expensive/impossible to reverse once published (wire formats, public API shapes); `two-way` decisions can be revisited while nothing is published. Door type does not change urgency — all decisions here need resolution when their impacts say so; it records how careful the resolution must be. ## Deferred / Blocked summary | OQ | Status | Blocked on / investigation | |---|---|---| | OQ-05 | deferred(scope) | ecosystem need for sha256 | | OQ-03 | partially resolved | first-publish timing (release decision; the freeze inventory lives in backend.md/transport.md) | | OQ-16 | deferred(scope) | first cross-assembly record sharing (distributed-git phase; tracker `architecture/oq-16-grant-identity-namespace`) | OQ-02 and OQ-04 resolved this cycle (ADR-014, ADR-013); OQ-08/06/07/09/01 resolved in earlier cycles. OQ-16 is deferred but blocks nothing in v1 (grants key on cluster-local ids within one assembly). ## Theme: composition / crate shapes ### OQ-09: Slim-crate model — doors as family infrastructure, git as a payload service - **Origin**: user session (2026-09-21); ADR-006, ADR-001, ssh.md - **Status**: **resolved** — ADR-010 (pure protocol crate, the alktty/ alktunnels template): single `alkgit` crate, producer/consumer halves, backend traits with feature-gated gix, no doors, no binary; ALPN `alk/git`; http mounting → alkhttp `git` feature; git-over-ssh → alkssh (russh scaffolding dropped); the monorepo/binary framing was an init-agent artifact (vision amended). - **Resolution**: [decisions/010-pure-protocol-crate.md]. All five sub-decisions recorded there (ssh deletion, http home, crate granularity, backend-trait surface, binary fate). - **Cross-references**: ADR-001/006 (superseded), OQ-01, OQ-03, OQ-08, doors.md, backend.md, overview.md ### OQ-01: HTTP adapter home and composability (alkhttp `git` feature vs alkgit-owned factory) - **Origin**: user session question (OQ-01, resolved 2026-09-21) - **Status**: **resolved** (subsumed by OQ-09/ADR-010) — the smart-http stateless substrate stays in `alkgit` (IO-abstract); the http mounting (routes, content types, `with_extra_routes` wiring) becomes an alkhttp `git` feature published after alkgit's first publish. The ADR-006 router-factory shape is superseded; the alkhttp-side feature is the outcome. - **Cross-references**: ADR-006 (superseded), ADR-010, doors.md ### OQ-03: Downstream embedding surface (what "embeds alkgit" means concretely) - **Origin**: [overview.md], [transport.md], vision §"ALPN as a service" - **Status**: **partially resolved** — the shape is settled (ADR-010): embedding = one crate + backend traits (own storage via `default-features = false`, or the `gix`/`registry-file` features) + optional door features. What remains deferred is the publish-time API freeze itself: which type/feature/op names are pinned at first crates.io publish. ADR-012 added the `git/repo/*` op set (names + schemas) to the freeze inventory; ADR-013/014 added the push/negotiation trait surface (`GitPackIngest` binding, `GitPackGen::common_haves`); ADR-016 added the native-path preamble wire shapes (the `{repo, service}` open-op params schema and the git-daemon request-line grammar — the last native-path wire surface); ADR-017 added the `GitSession` public API; the registry types/schemas draft (backend.md §"Registry types and schemas", review 001 N-3) pinned `RepoRecord`, `RegistryError`, and the `git/repo/*` op schemas; ADR-018 pinned the object-storage trait signatures, the shared backend-seam types (`RefLine`/`RefUpdate`/`RefOutcome`/ `PreparedPush`/`PushOptions`), and `StorageError` — the backend-seam inventory is complete. - **Door type**: one-way (API freeze is registry-visible to dependents) - **Priority**: medium - **Impacts**: blocks the first publish only, not implementation. - **Blocked on**: first-publish timing (a release decision, not an architecture question). The API surface inventory lives in [backend.md](backend.md) §public API and [transport.md](transport.md) §public API. ADR-013/014 added the push/negotiation trait surface (`GitPackIngest` binding, `GitPackGen::common_haves`) to the freeze inventory; ADR-016 added the native preamble wire shapes. - **Cross-references**: ADR-010, ADR-002, ADR-012, ADR-013, ADR-014, ADR-016, ADR-018, backend.md, transport.md ## Theme: transport / protocol ### OQ-02: V2 multi-round negotiation (ack/NAK logic, `wait-for-done` retirement) - **Origin**: [transport.md], poc2-findings §"does NOT settle" - **Status**: **resolved** — ADR-014 (V2 negotiation ack loop). The duplex-capture walkthrough against git 2.43.0 (ground-truth negotiation mock, cross-checked against `fetch-pack.c`) resolved the grammar: no- `done` rounds get `acknowledgments` (`ACK ` per recognized have, `NAK` when none, flush — never `ready`, so FLUSH is always the terminator); the `done` round generates closure(wants) − closure(haves) with no cross-round server state (clients re-send wants + commons every round); `wait-for-done` stays and the advertisement text is unchanged; the ack check is a new backend-trait method (`common_haves`) keeping the honest boundary at the seam. Captures: `docs/research/negotiation-captures.md`. - **Resolution**: [decisions/014-v2-negotiation-ack-loop.md] - **Cross-references**: ADR-003, ADR-004, ADR-005, ADR-009, ADR-014, transport.md §fetch, backend.md §"The trait family" (GitPackGen) ### OQ-04: receive-pack (push) — validation gap - **Origin**: [transport.md], poc3-findings §"does NOT settle" - **Status**: **resolved** — ADR-013 (receive-pack state machine). The walkthrough against real `git push` captures (git 2.43.0: file://, git://, smart-http, plus raw stdio requests into real `git receive-pack`) resolved every listed unknown: the push path is V0-framed by upstream design (no version negotiation, ADR-003 governs fetch only); the advertisement is a V0-shaped ref advertisement (caps on the first ref line, `capabilities^{}` sentinel only for empty repos) with served set `report-status(-v2) delete-refs side-band-64k atomic ofs-delta object-format=sha1` (+ `push-options` config-gated); shallow request lines are rejected up front for v1 (symmetric with fetch); thin packs accepted with bases from the server odb (default client behavior, no capability); ingestion = `Bundle::write_to_directory_eagerly` + `gix-fsck` + one `gix-ref` transaction per push (`.keep`-guarded pack landing); CAS timing is unpack-first-then-per-ref (observed upstream order); status report is band-1 pkt-line-framed with inner flush when sideband was selected. Captures: `docs/research/push-captures.md`. - **Resolution**: [decisions/013-receive-pack-state-machine.md] - **Cross-references**: ADR-003, ADR-004, ADR-005, ADR-009, ADR-013, transport.md §receive-pack, backend.md §"The trait family" (GitRefs, GitPackIngest), doors.md ### OQ-05: sha256 support policy - **Origin**: [transport.md], git-protocol.md §"Open items" - **Status**: deferred(scope) - **Door type**: two-way - **Priority**: low - **Impacts**: none for v1 (sha1 pinned); feature-flag passthrough compiles but is untested end-to-end. - **Blocked on**: ecosystem need (a real client/repo requiring sha256) or upstream gix sha256 maturity; POC-2 left the pipeline hash-generic but untested. Tracker task: `tasks/architecture/oq-05-sha256.md`. - **Cross-references**: ADR-003, ADR-004 ## Theme: identity / auth ### OQ-08: Registry identity space + vault placement (narrowed) - **Origin**: [overview.md], [doors.md], [backend.md]; originally "identity sources per front door" - **Status**: **resolved** — ADR-011 (per-repo authorization): the identity model is alkcall's resolved `Identity` keyed on its stable logical id (alkcall ADR-025 property, referenced); alkgit stores no identity records; grants live in repo records; the public+read / always-authenticated-write policy is alkgit-core's `authorize` function (the clause ADR-007 pinned but the static ACL engine could not express); vault placement resolved as **nothing to place in v1** (no credential-shaped material in metadata). *(Grant-key id format declared deliberately open by ADR-015 §7 — the cross-identity-namespace question this leaves is tracked as OQ-16.)* - **Resolution**: [decisions/011-per-repo-authorization.md] - **Cross-references**: ADR-007, ADR-008, ADR-011, ADR-012, OQ-06, OQ-07, backend.md §GitRegistry, doors.md ### OQ-16: Grant-key identity namespace (globally-comparable ids for multi-hub grants) - **Origin**: ADR-015 §7; user session (2026-09-26) - **Status**: deferred(scope) - **Door type**: two-way (schema field format; grants are already opaque strings, so this constrains only the *contents*, not the alkgit API) - **Priority**: low (blocks nothing in v1 — grants key on alkcall's cluster-local id within one assembly, which is the only deployment v1 serves) - **Question**: what identity-id format do grants key on when repo records are shared across assemblies (the distributed/replicator deployment: contract-watching hubs mirroring grant state)? Today the id is alkcall's `Identity.id` — stable within one cluster, but meaningless across hubs. Candidate shapes: `{namespace}/{id}` compound ids (the `{user|org}/{repo}` convention familiar from self-hosted git — e.g. `alkdev/alkgit` locally, `alkimiadev/alkgit` when mirrored — extended to identity: `gh:alkimiadev`, `alk:alkdev`), did-key / contract-derived identifiers (the planned smart-contract org/user/repo model), or a two-part (authority, local-id) tuple. - **Constraints any resolution must satisfy** (recorded from ADR-015 §7): grants remain flat sets keyed on opaque strings; alkgit never parses, validates, or interprets the id — collision-freedom is the identity-provider's guarantee; a downstream namespace can be introduced at the assembly seam without an alkgit change. - **Impacts**: only the downstream identity-provider seam and the future platform app / replicator grant-sync format. The v1 `authorize` policy function, the grant schema shape, and the op gate are all id-format-agnostic by construction. - **Blocked on**: the first deployment that shares repo records across assemblies (the distributed-git phase; also touches alkcall's identity model if a family-wide id format is preferred over a payload-level namespace convention). Tracker task: `tasks/architecture/oq-16-grant-identity-namespace.md`. - **Cross-references**: ADR-011 §1, ADR-015 §7, OQ-08 ## Theme: storage / metadata ### OQ-06: Registry/metadata backing store (gix feature) - **Origin**: [backend.md] (was storage.md), ADR-008 - **Status**: **resolved** — ADR-012 (registry backing + write surface): the alknet repo/adapter pattern applied — `GitRegistry` read trait + `GitRegistryStore` write supertrait; default backing is the `registry-file` feature (per-repo record files + in-memory index, config-seeded, op-mutable, atomic writes — no gitoxide); persistence adapters (SQLite et al.) are future, separate, additive, gated by a real deployment need — the deferred "scale requirements" never gated the default, only that future adapter. - **Resolution**: [decisions/012-registry-backing-and-ops.md] §1–2, §4 - **Cross-references**: ADR-008, ADR-010 (feature story amended), ADR-011, backend.md §feature model ### OQ-07: Admin API operation set (v1 scope) - **Origin**: [overview.md], alk-stack.md §"The gitea lesson" - **Status**: **resolved** — ADR-012 (§3, §5): the crate ships a minimal CRUD op set (`git/repo/{create,delete,update,get}`) as thin call ops over `GitRegistryStore`, `Visibility::External`, always-on, gated by the global admin scope and per-repo grants. The old "Internal ops over an admin listener" framing is superseded (right mechanism, wrong axis — visible-surface = authorized-surface is served by the ACL). The gate table as written used scope+ownership and is replaced by ADR-015 (the `manage` grant tier — admin scope OR manage grant, handler- evaluated; create seeds the creator's `{read, write, manage}` grants). Ops stay record-scoped; anything beyond repo records (users, orgs) is a downstream platform crate (the recorded split trigger, ADR-012 §5) — the app compiles roles/teams into flat grants (ADR-015 §6). - **Resolution**: [decisions/012-registry-backing-and-ops.md] §3, §5 (gate amended by [decisions/015-manage-grant-and-op-gate.md]) - **Cross-references**: ADR-007, ADR-011, ADR-012, ADR-015, alkcall ADR-017/011, backend.md §"The two op kinds"