Files
alkgit/docs/architecture/open-questions.md
T
glm-5.3-flash b6040d36a9 docs(architecture): N-3 — registry types/schemas pinned (freeze-inventory draft)
- new backend.md §"Registry types and schemas": RepoRecord serde shape
  (three-action grants per ADR-015, opaque grant keys, storage_root
  omitted from all op responses per ADR-008); the five-variant
  RegistryError set with wire mappings; the four git/repo/* op
  request/response schemas with additionalProperties: false inputs and
  the git:repo:* error-code namespace
- the not_found/forbidden collapse carries one wire code ('unauthorized')
  per N-2's rule; AlreadyExists is create-side only (no existence oracle)
- OQ-03 inventory note + review 001 N-3 marked resolved — review 001 is
  now 14/14

verification: cargo test, clippy -D warnings, fmt --check, doc,
publish --dry-run — clean
2026-09-30 04:21:03 +00:00

240 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
status: draft
last_updated: 2026-09-25
---
# 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.
- **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, 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 <oid>` 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"