Resolves review 001 finding A-1 (critical): ADR-012 §3's "scope
git:admin OR ownership" gate is not expressible in alkcall's
AccessControl (AND-composition). Resolution is the review's option (a)
shape with the OR-term generalized: the per-repo grant action set gains
manage, authorize(record, identity, read|write|manage) becomes the
single policy function for git access and repo administration, and the
delete/update/get gate is admin scope OR manage grant (handler-side,
generic FORBIDDEN, unknown-repo = unauthorized per ADR-008). Repo
create seeds the creator's {read, write, manage} grants —
administration is grantable, so collaborators/bots/app-compiled roles
work without global scopes. Ownership stays as alkcall spawn-tracking
(mint at create unchanged); "ownership never implies git access" is
superseded.
- ADR-015 (new): manage grant tier, op gate, flat-grants-as-replication-
substrate, opaque grant-key rule
- ADR-011: action set + policy domain amended, references updated
- ADR-012 §3: gate table replaced, two-tier paragraph superseded
- backend.md/doors.md/overview.md: gate + grant restatements, ADR tables
- OQ-16 (new, deferred(scope)): grant-key identity namespace —
globally-comparable ids for cross-assembly/replicator grant state;
tracker task tasks/architecture/oq-16-grant-identity-namespace.md
- review 001: A-1 marked resolved (ADR-015)
- vision.md: supersession notes (Internal-ops framing, v1 grant set)
Verification: cargo test, clippy -D warnings, fmt --check, doc --no-deps
all clean.
12 KiB
status, last_updated
| status | last_updated |
|---|---|
| draft | 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
alkgitcrate, producer/consumer halves, backend traits with feature-gated gix, no doors, no binary; ALPNalk/git; http mounting → alkhttpgitfeature; 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_routeswiring) becomes an alkhttpgitfeature 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 thegix/registry-filefeatures) + 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 thegit/repo/*op set (names + schemas) to the freeze inventory. - 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 §public API and transport.md
§public API. ADR-013/014 added the push/negotiation trait surface
(
GitPackIngestbinding,GitPackGen::common_haves) to the freeze inventory. - Cross-references: ADR-010, ADR-002, ADR-012, ADR-013, ADR-014, 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-donerounds getacknowledgments(ACK <oid>per recognized have,NAKwhen none, flush — neverready, so FLUSH is always the terminator); thedoneround generates closure(wants) − closure(haves) with no cross-round server state (clients re-send wants + commons every round);wait-for-donestays 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 pushcaptures (git 2.43.0: file://, git://, smart-http, plus raw stdio requests into realgit 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 setreport-status(-v2) delete-refs side-band-64k atomic ofs-delta object-format=sha1(+push-optionsconfig-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+ onegix-reftransaction 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
Identitykeyed 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'sauthorizefunction (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/alkgitlocally,alkimiadev/alkgitwhen 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
authorizepolicy 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 —
GitRegistryread trait +GitRegistryStorewrite supertrait; default backing is theregistry-filefeature (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 overGitRegistryStore,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 (themanagegrant 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"