docs(architecture): ADR-016 — native session preamble (review 001 A-3)
- new ADR-016: channels open-op params pinned as {repo, service}
(channels/git/sub, additionalProperties: false); direct-ALPN GitAdapter
parses the git-daemon request line (POC-1-verbatim grammar, capture-
backed); session tuple gains the service dimension on both substrates;
GitSession mirrors the shapes; version deliberately stays out of the
preamble (service fully determines the state machine)
- amend ADR-002/005/010 (tuple, substrate inputs, open-op params pin) and
transport.md/doors.md/overview.md/backend.md accordingly
- add the ADR-016 wire shapes to OQ-03's freeze inventory; note in
AGENTS.md convention 9 that the alkgit-specific framing now exists and
is pinned
- review 001: A-3 marked resolved
verification: cargo test, clippy -D warnings, fmt --check, doc — clean
This commit is contained in:
1 parent
201c7a1fce
commit
41b0894740
12 files changed
+293
-51
No files matched your search
@@ -120,8 +120,9 @@ implementation agents.
|
|||||||
|
|
||||||
9. **Wire formats are stable one-way doors** — once a wire surface is
|
9. **Wire formats are stable one-way doors** — once a wire surface is
|
||||||
published (the git smart protocol is defined upstream and not ours to
|
published (the git smart protocol is defined upstream and not ours to
|
||||||
change; any alkgit-specific alkgit↔alkgit framing will get ADRs when it
|
change; the one existing piece of alkgit-specific framing — the native
|
||||||
exists), its shape must not change. Protocol capability advertisement
|
session preamble, ADR-016 — is pinned and in the OQ-03 freeze
|
||||||
|
inventory), its shape must not change. Protocol capability advertisement
|
||||||
is honest: never advertise what we don't serve.
|
is honest: never advertise what we don't serve.
|
||||||
|
|
||||||
10. **Feature flags** — optional surface is feature-gated: `gix`
|
10. **Feature flags** — optional surface is feature-gated: `gix`
|
||||||
|
|||||||
@@ -24,7 +24,10 @@ are the publish-freeze timing (OQ-03, a release decision), sha256
|
|||||||
policy (OQ-05, deferred on ecosystem need), and the grant-key identity
|
policy (OQ-05, deferred on ecosystem need), and the grant-key identity
|
||||||
namespace (OQ-16, deferred on the first cross-assembly deployment —
|
namespace (OQ-16, deferred on the first cross-assembly deployment —
|
||||||
blocks nothing in v1). ADR-015 resolved
|
blocks nothing in v1). ADR-015 resolved
|
||||||
review 001's A-1 (the repo-op gate) with the `manage` grant tier.
|
review 001's A-1 (the repo-op gate) with the `manage` grant tier; ADR-016
|
||||||
|
resolved its A-3 (the native session preamble — `{repo, service}`
|
||||||
|
open-op params, the git-daemon request line on the direct path, and the
|
||||||
|
service dimension in the session tuple).
|
||||||
|
|
||||||
## Architecture Documents
|
## Architecture Documents
|
||||||
|
|
||||||
@@ -55,6 +58,7 @@ review 001's A-1 (the repo-op gate) with the `manage` grant tier.
|
|||||||
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack state machine (V0-framed push, thin-pack, unpack-first CAS) | Accepted |
|
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack state machine (V0-framed push, thin-pack, unpack-first CAS) | Accepted |
|
||||||
| [014](decisions/014-v2-negotiation-ack-loop.md) | V2 negotiation ack loop (no `ready`, wait-for-done stays) | Accepted |
|
| [014](decisions/014-v2-negotiation-ack-loop.md) | V2 negotiation ack loop (no `ready`, wait-for-done stays) | Accepted |
|
||||||
| [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant tier + repo-op gate (admin scope OR manage grant) | Accepted |
|
| [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant tier + repo-op gate (admin scope OR manage grant) | Accepted |
|
||||||
|
| [016](decisions/016-native-session-preamble.md) | Native session preamble (`{repo, service}` params, request line, service in tuple) | Accepted |
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
|
|||||||
@@ -143,9 +143,11 @@ alkgit ships both alkcall op kinds from one crate — the first family
|
|||||||
payload to do so (alktty/alktunnels: open ops only; alknet-docker,
|
payload to do so (alktty/alktunnels: open ops only; alknet-docker,
|
||||||
planned: call ops only):
|
planned: call ops only):
|
||||||
|
|
||||||
- **Open op** (`alk/git` via `register_openable`; repo id in the
|
- **Open op** (`channels/git/sub` via `register_openable`; open-op
|
||||||
open-op params) — the binary half: negotiation + ACL point (ADR-007),
|
params `{repo, service}` — ADR-016) — the binary half: negotiation +
|
||||||
yields the duplex git session.
|
service selector + ACL point (ADR-007; the service selects the
|
||||||
|
`authorize` action, read for fetch / write for push), yields the
|
||||||
|
duplex git session.
|
||||||
- **Call ops** (`git/repo/{create,delete,update,get}`) — the JSON half:
|
- **Call ops** (`git/repo/{create,delete,update,get}`) — the JSON half:
|
||||||
thin `OperationSpec`+handler pairs over `Arc<dyn GitRegistryStore>`,
|
thin `OperationSpec`+handler pairs over `Arc<dyn GitRegistryStore>`,
|
||||||
`Visibility::External`, always-on (no gitoxide). `create` is gated by
|
`Visibility::External`, always-on (no gitoxide). `create` is gated by
|
||||||
@@ -173,6 +175,7 @@ planned: call ops only):
|
|||||||
| [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant + op gate | `manage` tier, admin-scope-OR-manage gate, create seeds manage |
|
| [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant + op gate | `manage` tier, admin-scope-OR-manage gate, create seeds manage |
|
||||||
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack | thin-pack ingestion, transaction CAS, report framing |
|
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack | thin-pack ingestion, transaction CAS, report framing |
|
||||||
| [014](decisions/014-v2-negotiation-ack-loop.md) | Negotiation | ack loop, `common_haves` seam, no `ready` |
|
| [014](decisions/014-v2-negotiation-ack-loop.md) | Negotiation | ack loop, `common_haves` seam, no `ready` |
|
||||||
|
| [016](decisions/016-native-session-preamble.md) | Native session preamble | `{repo, service}` open-op params, request-line preamble, service in the tuple |
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
# ADR-002: Front-door-blind core — the session boundary
|
# ADR-002: Front-door-blind core — the session boundary
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
Accepted
|
|
||||||
|
Accepted (tuple amended by ADR-016: the session is per-service —
|
||||||
|
`service` ∈ {upload-pack, receive-pack} joins the tuple, selected at
|
||||||
|
establishment on every path)
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
@@ -30,16 +33,24 @@ Alternatives considered:
|
|||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
The transport exposes two session entry points, both consuming the same
|
The transport exposes two session entry points, both consuming the same
|
||||||
tuple (peer identity, resolved repo, limits):
|
tuple (peer identity, resolved repo, service, limits) — the service
|
||||||
|
(upload-pack vs receive-pack) is explicit at establishment on every path
|
||||||
|
(ADR-016): doors select it by route/exec command; the native paths carry
|
||||||
|
it in the open-op params or the in-band request line:
|
||||||
|
|
||||||
1. **Duplex session** (ssh, git://, any stream door): transport consumes a
|
1. **Duplex session** (ssh, git://, any stream door): transport consumes a
|
||||||
`BiStream`-shaped duplex byte stream (`AsyncRead + AsyncWrite + Unpin`,
|
`BiStream`-shaped duplex byte stream (`AsyncRead + AsyncWrite + Unpin`,
|
||||||
the alkcall `BiStream` contract, alkcall ADR-005/009) and runs the
|
the alkcall `BiStream` contract, alkcall ADR-005/009) and runs the
|
||||||
advertise-once → command-loop state machine. Adapters hand it over after
|
service-selected advertise-once → command-loop state machines (V2
|
||||||
ACL and repo resolution (ADR-007, ADR-008).
|
advertisement for fetch; the V0 ref advertisement for push — both are
|
||||||
|
server-emitted firsts, so the service must precede the stream).
|
||||||
|
Adapters hand it over after ACL and repo resolution (ADR-007,
|
||||||
|
ADR-008).
|
||||||
2. **Stateless session** (smart-http): transport consumes a
|
2. **Stateless session** (smart-http): transport consumes a
|
||||||
(request-reader, response-writer) pair per http request and runs one
|
(request-reader, response-writer) pair per http request and runs one
|
||||||
command per invocation, matching smart-http's stateless framing. The
|
command per invocation, matching smart-http's stateless framing; the
|
||||||
|
door's route supplies the service even here (nothing in a POST body
|
||||||
|
distinguishes the services before parsing — ADR-016). The
|
||||||
same core state machines run under both entry points.
|
same core state machines run under both entry points.
|
||||||
|
|
||||||
Storage-facing side: the wire layer calls the backend traits for advertisement data,
|
Storage-facing side: the wire layer calls the backend traits for advertisement data,
|
||||||
@@ -69,5 +80,6 @@ follow-up 2).
|
|||||||
(stateless shape validated)
|
(stateless shape validated)
|
||||||
- alkcall ADR-005 (`BiStream` type), ADR-009 (BiStream as handler leaf)
|
- alkcall ADR-005 (`BiStream` type), ADR-009 (BiStream as handler leaf)
|
||||||
- ADR-005 (substrate types detail), ADR-007/008 (what adapters do before
|
- ADR-005 (substrate types detail), ADR-007/008 (what adapters do before
|
||||||
calling transport)
|
calling transport), ADR-016 (the service selection this document's
|
||||||
|
tuple carries)
|
||||||
- overview.md §"Crate map"
|
- overview.md §"Crate map"
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
# ADR-005: Session substrate types — duplex + stateless over one state machine
|
# ADR-005: Session substrate types — duplex + stateless over one state machine
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
Accepted
|
|
||||||
|
Accepted (substrate inputs amended by ADR-016: both substrates receive
|
||||||
|
the service dimension explicitly)
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
@@ -32,16 +34,19 @@ If adapters or handlers hand-roll any of this, each gets it subtly wrong.
|
|||||||
`alkgit` owns the substrate layer; doors and handlers see
|
`alkgit` owns the substrate layer; doors and handlers see
|
||||||
friendly types:
|
friendly types:
|
||||||
|
|
||||||
1. **`Session` (duplex)** — wraps (stream, limits) into the pkt-line
|
1. **`Session` (duplex)** — wraps (stream, limits, service) into the
|
||||||
session: owns the split/compat bridge, the request reader (command line
|
pkt-line session: owns the split/compat bridge, the request reader (command line
|
||||||
+ pre-delim lines + args + flush, with the `reset()` discipline and the
|
+ pre-delim lines + args + flush, with the `reset()` discipline and the
|
||||||
unconditional-error-break rule), and the writer (sideband sink with
|
unconditional-error-break rule), and the writer (sideband sink with
|
||||||
65000-byte chunks, idempotent flush). Seed: POC-1's `serve_v2`.
|
65000-byte chunks, idempotent flush). The service selects the
|
||||||
2. **`StatelessRequest` (http)** — wraps (request-reader, response-writer)
|
advertisement and state machine at start (ADR-016). Seed: POC-1's
|
||||||
per POST: performs the capability-dump skip, the delim-aware arg split,
|
`serve_v2`.
|
||||||
|
2. **`StatelessRequest` (http)** — wraps (request-reader, response-writer,
|
||||||
|
service) per POST: performs the capability-dump skip, the delim-aware arg split,
|
||||||
and the flush-only response rule (no `0002`, idempotent flush,
|
and the flush-only response rule (no `0002`, idempotent flush,
|
||||||
200-empty for flush-only probes). Seed: POC-3's `httpservice.rs` +
|
200-empty for flush-only probes); the door's route supplies the
|
||||||
`BodyReader`.
|
service (nothing in a POST body distinguishes the services — ADR-016).
|
||||||
|
Seed: POC-3's `httpservice.rs` + `BodyReader`.
|
||||||
3. **One protocol core** — the V2 state machines (ADR-003) run under both
|
3. **One protocol core** — the V2 state machines (ADR-003) run under both
|
||||||
substrates; the stateless substrate presents each POST as a command
|
substrates; the stateless substrate presents each POST as a command
|
||||||
invocation. Version dispatch happens at session start, in one place.
|
invocation. Version dispatch happens at session start, in one place.
|
||||||
@@ -67,5 +72,6 @@ exactly one task drives a given sink (POC-2's `SidebandSink` contract).
|
|||||||
follow-ups 1–2
|
follow-ups 1–2
|
||||||
- `docs/research/poc3-findings.md` §"Course corrections" 1, follow-ups 2, 4
|
- `docs/research/poc3-findings.md` §"Course corrections" 1, follow-ups 2, 4
|
||||||
- `docs/research/gitoxide.md` §"Wire format"
|
- `docs/research/gitoxide.md` §"Wire format"
|
||||||
- ADR-002 (substrate shapes), ADR-003 (V2-first), ADR-004 (sink = io::Write)
|
- ADR-002 (substrate shapes), ADR-003 (V2-first), ADR-004 (sink = io::Write),
|
||||||
|
ADR-016 (service selection in the substrate inputs)
|
||||||
- transport.md §substrate
|
- transport.md §substrate
|
||||||
@@ -21,8 +21,9 @@ The git service fits that pattern exactly:
|
|||||||
alkcall `ProtocolHandler` for the `alk/git` ALPN → `accept_bi()` →
|
alkcall `ProtocolHandler` for the `alk/git` ALPN → `accept_bi()` →
|
||||||
duplex V2 session, plus a `register_openable` helper so a git session is
|
duplex V2 session, plus a `register_openable` helper so a git session is
|
||||||
openable through the `alk/channels` multiplexer (alktty ADR-007/009
|
openable through the `alk/channels` multiplexer (alktty ADR-007/009
|
||||||
pattern: the channels open-op carries the negotiation — here, the repo
|
pattern: the channels open-op carries the negotiation — here, the
|
||||||
id as params, which is also the natural ACL enforcement point).
|
`{repo, service}` params (ADR-016), which is also the natural ACL
|
||||||
|
enforcement point).
|
||||||
- **Consumer half** = a typed `GitSession` client (alktty's `TtySession`
|
- **Consumer half** = a typed `GitSession` client (alktty's `TtySession`
|
||||||
analog) driving fetch/push against a remote alkgit service — the
|
analog) driving fetch/push against a remote alkgit service — the
|
||||||
alkcall-native primitive for replication/mirroring in the alknet
|
alkcall-native primitive for replication/mirroring in the alknet
|
||||||
@@ -58,9 +59,12 @@ template:
|
|||||||
crates.io as `alkgit`.
|
crates.io as `alkgit`.
|
||||||
- **Producer half**: `GitAdapter` (direct `alk/git` ALPN via
|
- **Producer half**: `GitAdapter` (direct `alk/git` ALPN via
|
||||||
`ProtocolHandler`) + channels `register_openable` (open-op params carry
|
`ProtocolHandler`) + channels `register_openable` (open-op params carry
|
||||||
the repo id — the negotiation, and the ACL enforcement point).
|
`{repo, service}` — ADR-016's schema; the negotiation, the service
|
||||||
|
selector, and the ACL enforcement point; the service at open time is
|
||||||
|
what lets the gate run the correct `authorize` action per ADR-011/015).
|
||||||
- **Consumer half**: `GitSession` typed client with `connect_direct` and
|
- **Consumer half**: `GitSession` typed client with `connect_direct` and
|
||||||
`open_via_channels` constructors.
|
`open_via_channels` constructors — both send the ADR-016 preamble
|
||||||
|
(request line / open-op params) including the service.
|
||||||
- **Backend traits** (registry, refs, pack-gen, pack-ingest) in-crate;
|
- **Backend traits** (registry, refs, pack-gen, pack-ingest) in-crate;
|
||||||
`gix` implementation behind the default-on `gix` feature (disable it to
|
`gix` implementation behind the default-on `gix` feature (disable it to
|
||||||
embed your own storage).
|
embed your own storage).
|
||||||
|
|||||||
@@ -0,0 +1,187 @@
|
|||||||
|
# ADR-016: The native session preamble — service selection on the `alk/git` paths
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted (resolves review 001 A-3; amends ADR-002's session tuple,
|
||||||
|
ADR-005's substrate inputs, and ADR-010's open-op params pin)
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Every door selects the git *service* (upload-pack vs receive-pack) before
|
||||||
|
the protocol starts: http by route (`POST /{repo}/git-upload-pack` vs
|
||||||
|
`…/git-receive-pack`, doors.md), ssh by the parsed exec command
|
||||||
|
(`git-upload-pack '<repo>'` / `git-receive-pack '<repo>'`, doors.md's
|
||||||
|
alkssh requirement). The native paths have no equivalent, and review 001
|
||||||
|
(A-3, critical) established that as written push is unservable over the
|
||||||
|
`alk/git` ALPN:
|
||||||
|
|
||||||
|
1. **Channels path** (`register_openable`): the open-op params are pinned
|
||||||
|
as "repo id" only (ADR-010, overview crate map). Both consequences the
|
||||||
|
review named follow: the open-time ACL point cannot evaluate the write
|
||||||
|
tier — the reason the repo id rides the params is that the open op is
|
||||||
|
the negotiation + ACL enforcement point (ADR-007's resolve→authorize
|
||||||
|
runs at open time), but `authorize(record, identity, action)` is
|
||||||
|
per-action (ADR-011/015: read for fetch, write for push) and with no
|
||||||
|
service in the params the gate cannot know which check to run; and the
|
||||||
|
session cannot choose its state machine — both advertisements are
|
||||||
|
server-emitted firsts on the duplex path (the V2 capability
|
||||||
|
advertisement per ADR-003; the V0 ref advertisement per ADR-013 §2),
|
||||||
|
so the server cannot even choose which first bytes to emit.
|
||||||
|
|
||||||
|
2. **Direct-ALPN path** (`GitAdapter`): no preamble is pinned anywhere.
|
||||||
|
The connection is symmetric — a push client waits for the server's ref
|
||||||
|
advertisement while the server waits for the client — so with no
|
||||||
|
in-band service carrier the path deadlocks by construction. POC-1's
|
||||||
|
bridge carried the service in-band (the git-daemon request line) but
|
||||||
|
that framing was never adopted as an alkgit contract; AGENTS.md
|
||||||
|
convention 9 requires alkgit-specific wire framing to get an ADR, and
|
||||||
|
none existed.
|
||||||
|
|
||||||
|
3. **The session tuple lacks the dimension**: ADR-002's tuple and
|
||||||
|
transport.md's substrate inputs are "(peer identity, resolved repo,
|
||||||
|
limits)" (+ the ADR-007 authorized-repo marker) — no service selector.
|
||||||
|
Even on the stateless substrate, where the door's route selects the
|
||||||
|
service, the substrate input must carry it explicitly: nothing in a
|
||||||
|
POST body reliably distinguishes an upload-pack POST from a
|
||||||
|
receive-pack POST before parsing. `GitSession` (the consumer half)
|
||||||
|
mirrors whatever is pinned here.
|
||||||
|
|
||||||
|
The version dimension is *not* part of this gap: fetch is V2-only
|
||||||
|
(ADR-003 — V0/V1 fetch clients get a clear error) and push is V0-framed
|
||||||
|
unconditionally (ADR-013 §1 — no version negotiation exists on the push
|
||||||
|
path), so the service alone fully determines the state machine. One
|
||||||
|
field suffices; this ADR states that as the reason the shape is stable
|
||||||
|
under future version policy changes.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
**The service is explicit at session establishment on every native path;
|
||||||
|
the preamble carriers are the channels open-op params (JSON
|
||||||
|
`{repo, service}`) and the git-daemon request line (direct ALPN), and
|
||||||
|
the session tuple gains the service dimension.**
|
||||||
|
|
||||||
|
1. **Channels open-op params are `{repo, service}`** — JSON, both
|
||||||
|
required, `service ∈ {"git-upload-pack", "git-receive-pack"}`
|
||||||
|
(string enum), `additionalProperties: false` (the alksocks `{}`-schema
|
||||||
|
precedent: unknown fields fail rather than get silently ignored, so
|
||||||
|
extensions stay additive and fail-closed — the first extension already
|
||||||
|
exists at v1). The op is `channels/git/sub` with the
|
||||||
|
`ChannelOpenSpec::new("alk/git")` marker (the alktty
|
||||||
|
`channels/tty/sub` convention, alkcall ADR-047). The params are the
|
||||||
|
open-time ACL point (ADR-010 unchanged in *position* — the establisher
|
||||||
|
resolves the repo and runs `authorize(record, identity, read|write)`
|
||||||
|
with the action selected by the service; write requires identity plus
|
||||||
|
the write-or-manage grant per ADR-011/015) *and* the service selector:
|
||||||
|
the service at open time is what lets the gate run the correct check
|
||||||
|
instead of deferring the write check into the session. `git-upload-
|
||||||
|
archive` is not in the enum, so the open op rejects it at the gate —
|
||||||
|
the same fixed refusal every door applies, one layer earlier.
|
||||||
|
Registry-side errors map into alkcall's `channel:open_failed`
|
||||||
|
vocabulary (the establisher pattern; no phantom channel). The
|
||||||
|
registry-side ACL in the `AccessControl` stays empty (per-repo grant
|
||||||
|
checks are handler-side per ADR-011/015 — there is no static scope
|
||||||
|
gate to express them with).
|
||||||
|
|
||||||
|
2. **Direct-ALPN `GitAdapter` parses the git-daemon request line**
|
||||||
|
(POC-1 verbatim, capture-backed against real git 2.43 — poc-1-findings
|
||||||
|
§2, push-captures git:// framing): one pkt-line, client-sent before
|
||||||
|
the server speaks —
|
||||||
|
|
||||||
|
- fetch: `git-upload-pack <repo>\0host=<host>\0\0version=2\0`
|
||||||
|
- push: `git-receive-pack <repo>\0host=<host>\0`
|
||||||
|
|
||||||
|
The server parses the line, resolves the repo, runs
|
||||||
|
`authorize` with the action the service selects, and only then emits
|
||||||
|
the advertisement (ADR-007's resolve→authorize order, unchanged).
|
||||||
|
`host` and `version=2` extras are parsed and accepted verbatim; the
|
||||||
|
version then flows through the existing dispatch exactly as if real
|
||||||
|
git had spoken — a V0/V1 fetch request gets ADR-003's existing clear
|
||||||
|
error (the request line carries `version=2` for fetch; a request line
|
||||||
|
without it, or with an unrecognized version token, is the same
|
||||||
|
V0/V1-decline path). Malformed lines (unknown service, empty repo id)
|
||||||
|
fail before any advertisement; repo resolution and authorization
|
||||||
|
failures collapse per ADR-008 (unknown ≡ unauthorized). This is
|
||||||
|
alkgit-specific wire format on a published ALPN — it enters OQ-03's
|
||||||
|
freeze inventory (one-way). The grammar is also the one a git://-to-
|
||||||
|
`alk/git` bridge would need anyway, and it is the framing
|
||||||
|
`GitSession::connect_direct` sends — the two native paths speak one
|
||||||
|
preamble dialect.
|
||||||
|
|
||||||
|
3. **The session tuple gains the service dimension.**
|
||||||
|
|
||||||
|
- Duplex: `(identity, repo, service, authorized-repo marker, stream,
|
||||||
|
limits)`.
|
||||||
|
- Stateless: `(identity, repo, service, marker, request-reader,
|
||||||
|
response-writer, limits)` — the door's route still selects the
|
||||||
|
service (doors.md), but the substrate input carries it explicitly.
|
||||||
|
- The service in the tuple is *the* state-machine selector: the
|
||||||
|
transport layer dispatches on it alone (version never rides the
|
||||||
|
preamble — consequence of the fetch-V2-only / push-V0-framed split
|
||||||
|
above).
|
||||||
|
|
||||||
|
4. **`GitSession` mirrors the same shapes**: `connect_direct` sends the
|
||||||
|
request-line preamble before waiting for the server; `open_via_
|
||||||
|
channels` sends the same `{repo, service}` params schema.
|
||||||
|
|
||||||
|
5. **Rejected alternatives** (recorded so the decomposer does not
|
||||||
|
reinvent them):
|
||||||
|
|
||||||
|
- *Repo-only params + service learned in-band post-open*: the open
|
||||||
|
gate would admit the channel before knowing the action, deferring
|
||||||
|
the write check past channel establishment — directly weakening the
|
||||||
|
ADR-007 posture the params exist to serve.
|
||||||
|
- *Two open ops* (`…/up`, `…/rec`): buys nothing — per-repo grant
|
||||||
|
checks are handler-evaluated (ADR-011/015), not static per-op scope
|
||||||
|
gates, so separate ops get no extra enforcement from the registry;
|
||||||
|
they double the registration and discovery surface.
|
||||||
|
- *JSON preamble on the direct path*: a binary pkt-line stream would
|
||||||
|
carry a length-framed JSON dialect nobody can debug with standard
|
||||||
|
git tooling, inventing a second preamble form to keep in sync with
|
||||||
|
the channels params for zero benefit.
|
||||||
|
- *No preamble / out-of-band service on the direct path*: the
|
||||||
|
connection is symmetric; without an in-band carrier the path
|
||||||
|
deadlocks at birth.
|
||||||
|
- *Two ALPNs* (`alk/git-up`, `alk/git-rec`): breaks the one-ALPN-per-
|
||||||
|
payload family convention (`alk/tty`, `alk/tunnel`, `alk/socks5`)
|
||||||
|
and doubles every door's surface.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- **Positive:** push over `alk/git` is servable (the server knows which
|
||||||
|
advertisement to emit); the open-time gate evaluates the correct
|
||||||
|
`authorize` action — the write tier is enforced at the gate the way
|
||||||
|
ADR-007 intends, not deferred into the session; `GitSession`'s
|
||||||
|
constructor shapes become concrete (A-5 unblock); the freeze inventory
|
||||||
|
gains its last native-path wire surface, pinned *before* decomposition
|
||||||
|
as the review required.
|
||||||
|
- **Negative:** the `{repo, service}` params schema and the request-line
|
||||||
|
grammar are alkgit-specific wire surfaces on a published ALPN
|
||||||
|
(one-way doors; OQ-03 inventory) — pinned exactly so nothing ad-hoc
|
||||||
|
hardens first. The stateless substrate gains one required input every
|
||||||
|
http door must now supply (the route already knows it).
|
||||||
|
- **Neutral:** the version dimension stays where it already lives
|
||||||
|
(ADR-003 fetch dispatch / ADR-013 push framing); the direct-path
|
||||||
|
request line parses-and-accepts `host=` and `version=2` so a future
|
||||||
|
protocol version rides an established grammar, not a new field.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- Review 001 A-3 (the trigger; the recommendation this ADR adopts after
|
||||||
|
deliberation), OQ-03 (the freeze inventory this ADR's wire shapes enter)
|
||||||
|
- ADR-002 (session boundary — tuple amended), ADR-005 (substrate types —
|
||||||
|
inputs amended), ADR-010 (open-op params pin — amended; producer/
|
||||||
|
consumer halves unchanged), ADR-007 (resolve→authorize before any
|
||||||
|
protocol byte), ADR-008 (unknown ≡ unauthorized), ADR-003 (V2-only
|
||||||
|
fetch; the version-decline path), ADR-013 §1–2 (push V0-framed;
|
||||||
|
server-speaks-first advertisement), ADR-011/015 (`authorize` actions,
|
||||||
|
write grant)
|
||||||
|
- alkcall ADR-047 (channel open ops are operations; `channels/<alpn>/sub`
|
||||||
|
convention), ADR-049 (the establisher phase — open-time validation and
|
||||||
|
ACL-adjacent checks), alktty `src/channels.rs` (`channels/tty/sub`
|
||||||
|
template: partial registry schema + establisher full-parse + ACL)
|
||||||
|
- `docs/research/poc-1-findings.md` §2 (the capture-backed request-line
|
||||||
|
shape), `docs/research/push-captures.md` (git:// framing of the push
|
||||||
|
request line), AGENTS.md convention 9 (alkgit-specific framing needs
|
||||||
|
this ADR)
|
||||||
|
- transport.md §substrate, doors.md §"The alkcall-native path",
|
||||||
|
overview.md §crate map
|
||||||
@@ -87,11 +87,17 @@ an embedder assembly concern, not alkgit scope.
|
|||||||
|
|
||||||
## The alkcall-native path (no adapter at all)
|
## The alkcall-native path (no adapter at all)
|
||||||
|
|
||||||
The `alk/git` ALPN producer and the channels open-op (repo id in the
|
The `alk/git` ALPN producer and the channels open-op (`channels/git/sub`,
|
||||||
open-op params) need zero door code — POC-1 is that shape verbatim. Any
|
params `{repo, service}` — ADR-016: the params are the negotiation, the
|
||||||
alkcall-speaking client (including alkgit's own consumer half,
|
service selector, and the open-time ACL point; the establisher resolves
|
||||||
`GitSession`) can use it. This is the baseline path; the http/ssh doors
|
the repo and runs `authorize` with the action the service selects) need
|
||||||
are conveniences layered on top for stock git clients.
|
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`) can use either path. This is the baseline path; the
|
||||||
|
http/ssh doors are conveniences layered on top for stock git clients.
|
||||||
|
|
||||||
## Assembly (downstream responsibility)
|
## Assembly (downstream responsibility)
|
||||||
|
|
||||||
@@ -117,6 +123,7 @@ deployment's docs, not here.
|
|||||||
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack | V0-framed push advertisement per door, report framing |
|
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack | V0-framed push advertisement per door, report framing |
|
||||||
| [014](decisions/014-v2-negotiation-ack-loop.md) | Negotiation | one round per POST; ack section is per-round, stateless |
|
| [014](decisions/014-v2-negotiation-ack-loop.md) | Negotiation | one round per POST; ack section is per-round, stateless |
|
||||||
| [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant + op gate | `manage` tier, admin-OR-manage op gate |
|
| [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant + op gate | `manage` tier, admin-OR-manage op gate |
|
||||||
|
| [016](decisions/016-native-session-preamble.md) | Native session preamble | `{repo, service}` open-op params, request-line preamble, service in the tuple |
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,11 @@ resolved in earlier cycles. OQ-16 is deferred but blocks nothing in v1
|
|||||||
optional door features. What remains deferred is the publish-time API
|
optional door features. What remains deferred is the publish-time API
|
||||||
freeze itself: which type/feature/op names are pinned at first
|
freeze itself: which type/feature/op names are pinned at first
|
||||||
crates.io publish. ADR-012 added the `git/repo/*` op set (names +
|
crates.io publish. ADR-012 added the `git/repo/*` op set (names +
|
||||||
schemas) to the freeze inventory.
|
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).
|
||||||
- **Door type**: one-way (API freeze is registry-visible to dependents)
|
- **Door type**: one-way (API freeze is registry-visible to dependents)
|
||||||
- **Priority**: medium
|
- **Priority**: medium
|
||||||
- **Impacts**: blocks the first publish only, not implementation.
|
- **Impacts**: blocks the first publish only, not implementation.
|
||||||
@@ -77,9 +81,9 @@ resolved in earlier cycles. OQ-16 is deferred but blocks nothing in v1
|
|||||||
[backend.md](backend.md) §public API and [transport.md](transport.md)
|
[backend.md](backend.md) §public API and [transport.md](transport.md)
|
||||||
§public API. ADR-013/014 added the push/negotiation trait surface
|
§public API. ADR-013/014 added the push/negotiation trait surface
|
||||||
(`GitPackIngest` binding, `GitPackGen::common_haves`) to the freeze
|
(`GitPackIngest` binding, `GitPackGen::common_haves`) to the freeze
|
||||||
inventory.
|
inventory; ADR-016 added the native preamble wire shapes.
|
||||||
- **Cross-references**: ADR-010, ADR-002, ADR-012, ADR-013, ADR-014,
|
- **Cross-references**: ADR-010, ADR-002, ADR-012, ADR-013, ADR-014,
|
||||||
backend.md, transport.md
|
ADR-016, backend.md, transport.md
|
||||||
|
|
||||||
## Theme: transport / protocol
|
## Theme: transport / protocol
|
||||||
|
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ Single crate `alkgit`:
|
|||||||
|
|
||||||
| Half | Contents | POC evidence |
|
| Half | Contents | POC evidence |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Producer | `GitAdapter` (`alk/git` ALPN via alkcall `ProtocolHandler`), channels `register_openable` (repo id in open-op params — the negotiation + ACL point) | POC-1 verbatim |
|
| Producer | `GitAdapter` (`alk/git` ALPN via alkcall `ProtocolHandler`; parses the ADR-016 request-line preamble), channels `register_openable` (`channels/git/sub` — open-op params `{repo, service}`, the negotiation + service selector + ACL point; ADR-016) | POC-1 verbatim |
|
||||||
| Consumer | `GitSession` typed client (`connect_direct`, `open_via_channels`) — the replication/mirroring primitive for alknet | new, small (TtySession analog) |
|
| Consumer | `GitSession` typed client (`connect_direct`, `open_via_channels`) — sends the same ADR-016 preamble shapes | new, small (TtySession analog) |
|
||||||
| Substrate | duplex session + stateless request/response layer (ADR-005); wire framing, V2 state machines (ADR-003) | POC-1, POC-3 |
|
| Substrate | duplex session + stateless request/response layer (ADR-005); wire framing, V2 state machines (ADR-003) | POC-1, POC-3 |
|
||||||
| Backends | `GitRegistry` (+ write supertrait), `GitRefs`, `GitPackGen`, `GitPackIngest` traits; impls behind the default-on `gix` (engine) and `registry-file` (records) features | POC-2 (gix impl) |
|
| Backends | `GitRegistry` (+ write supertrait), `GitRefs`, `GitPackGen`, `GitPackIngest` traits; impls behind the default-on `gix` (engine) and `registry-file` (records) features | POC-2 (gix impl) |
|
||||||
| Management ops | `git/repo/*` call ops over `GitRegistryStore` (ADR-012 §3) — the JSON half alongside the `alk/git` open op (first dual-kind payload; ADR-012 §5) | thin over the store trait |
|
| Management ops | `git/repo/*` call ops over `GitRegistryStore` (ADR-012 §3) — the JSON half alongside the `alk/git` open op (first dual-kind payload; ADR-012 §5) | thin over the store trait |
|
||||||
@@ -79,7 +79,7 @@ multi-round negotiation are design-complete against real-client captures
|
|||||||
| ADR | Decision | Summary |
|
| ADR | Decision | Summary |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| [001](decisions/001-crate-decomposition.md) | Crate decomposition | **superseded by ADR-010** |
|
| [001](decisions/001-crate-decomposition.md) | Crate decomposition | **superseded by ADR-010** |
|
||||||
| [002](decisions/002-front-door-blind-core.md) | Session boundary | (identity, repo, stream, limits) — unchanged, load-bearing |
|
| [002](decisions/002-front-door-blind-core.md) | Session boundary | (identity, repo, service, stream, limits) — unchanged, load-bearing; service per ADR-016 |
|
||||||
| [003](decisions/003-protocol-v2-first.md) | V2-first protocol | V2-only fetch both doors; push is V0-framed by upstream design (ADR-013); honest advertisement |
|
| [003](decisions/003-protocol-v2-first.md) | V2-first protocol | V2-only fetch both doors; push is V0-framed by upstream design (ADR-013); honest advertisement |
|
||||||
| [004](decisions/004-pack-pipeline.md) | Pack pipeline | `data::output` gen / `data::input` ingestion |
|
| [004](decisions/004-pack-pipeline.md) | Pack pipeline | `data::output` gen / `data::input` ingestion |
|
||||||
| [005](decisions/005-session-substrate-types.md) | Substrate types | duplex + stateless APIs over one state machine |
|
| [005](decisions/005-session-substrate-types.md) | Substrate types | duplex + stateless APIs over one state machine |
|
||||||
@@ -93,7 +93,7 @@ multi-round negotiation are design-complete against real-client captures
|
|||||||
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack | V0-framed push machine, thin-pack acceptance, unpack-first CAS |
|
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack | V0-framed push machine, thin-pack acceptance, unpack-first CAS |
|
||||||
| [014](decisions/014-v2-negotiation-ack-loop.md) | Negotiation | ack loop, `common_haves` seam, no `ready` |
|
| [014](decisions/014-v2-negotiation-ack-loop.md) | Negotiation | ack loop, `common_haves` seam, no `ready` |
|
||||||
| [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant + op gate | `manage` tier, admin-OR-manage gate, create seeds manage |
|
| [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant + op gate | `manage` tier, admin-OR-manage gate, create seeds manage |
|
||||||
| [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant + op gate | `manage` tier, admin-OR-manage gate, create seeds manage |
|
| [016](decisions/016-native-session-preamble.md) | Native session preamble | `{repo, service}` open-op params, request-line preamble, service in the tuple |
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
@@ -101,7 +101,9 @@ Key questions tracked in [open-questions.md](open-questions.md):
|
|||||||
|
|
||||||
- **OQ-03**: publish-time API freeze inventory (the `git/repo/*` op set
|
- **OQ-03**: publish-time API freeze inventory (the `git/repo/*` op set
|
||||||
and the trait family enter it; ADR-012, ADR-013/014's trait additions;
|
and the trait family enter it; ADR-012, ADR-013/014's trait additions;
|
||||||
the ADR-015 three-action grant shape must land in it).
|
the ADR-015 three-action grant shape must land in it; the ADR-016
|
||||||
|
native preamble wire shapes — `{repo, service}` params schema and the
|
||||||
|
request-line grammar — entered it).
|
||||||
- **OQ-05**: sha256 policy (deferred(scope), low).
|
- **OQ-05**: sha256 policy (deferred(scope), low).
|
||||||
- **OQ-16**: grant-key identity namespace (deferred(scope); blocks
|
- **OQ-16**: grant-key identity namespace (deferred(scope); blocks
|
||||||
nothing in v1 — ADR-015 §7).
|
nothing in v1 — ADR-015 §7).
|
||||||
|
|||||||
@@ -22,16 +22,25 @@ full decision (what each substrate owns and why); the surface is:
|
|||||||
|
|
||||||
- **Duplex session** (the `alk/git` ALPN producer, channels-opened git
|
- **Duplex session** (the `alk/git` ALPN producer, channels-opened git
|
||||||
sessions, embedder stream doors) — input: (peer identity, resolved repo
|
sessions, embedder stream doors) — input: (peer identity, resolved repo
|
||||||
id, authorized-repo marker, duplex stream, `Limits`). The marker is a
|
id, service, authorized-repo marker, duplex stream, `Limits`). The
|
||||||
type the door/adapter constructs only after the ADR-007 check passes
|
marker is a type the door/adapter constructs only after the ADR-007
|
||||||
(skipping the check is a type error — ADR-007; D-3). Encapsulates the
|
check passes (skipping the check is a type error — ADR-007; D-3). The
|
||||||
split/compat/packetline
|
service is selected at establishment on every native path (ADR-016:
|
||||||
bridge, the request reader (delim-aware parsing, `reset()` discipline,
|
the channels open-op params `{repo, service}`, or the in-band
|
||||||
break-on-error), and the sideband writer.
|
git-daemon request line the direct-ALPN `GitAdapter` parses,
|
||||||
|
POC-1-verbatim), and selects the state machine: the V2 capability
|
||||||
|
advertisement for fetch, the V0 ref advertisement for push — both are
|
||||||
|
server-emitted firsts, so the service must precede the stream.
|
||||||
|
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 `git`
|
- **Stateless session** (smart-http doors, e.g. alkhttp's future `git`
|
||||||
feature) — input: (peer identity, resolved repo id, authorized-repo
|
feature) — input: (peer identity, resolved repo id, service,
|
||||||
marker, request-reader, response-writer, `Limits`) per http POST; adds
|
authorized-repo marker, request-reader, response-writer, `Limits`) per
|
||||||
the http-framing rules
|
http POST. The door's route still selects the service (doors.md), but
|
||||||
|
the substrate input carries it explicitly — nothing in a POST body
|
||||||
|
distinguishes an upload-pack POST from a receive-pack POST before
|
||||||
|
parsing (ADR-016). Adds the http-framing rules
|
||||||
(capability-dump skip, flush-only responses, probe handling). IO-abstract:
|
(capability-dump skip, flush-only responses, probe handling). IO-abstract:
|
||||||
the door supplies reader/writer; see [doors.md](doors.md) for the
|
the door supplies reader/writer; see [doors.md](doors.md) for the
|
||||||
mounting.
|
mounting.
|
||||||
@@ -145,7 +154,8 @@ a partial ref list is the worst failure mode an advertisement can have
|
|||||||
|
|
||||||
Crate-root re-exports (alktty pattern; the full list in
|
Crate-root re-exports (alktty pattern; the full list in
|
||||||
[backend.md](backend.md) §public API): `GitAdapter` + `register_openable`,
|
[backend.md](backend.md) §public API): `GitAdapter` + `register_openable`,
|
||||||
`GitSession`, substrate types, `Limits`, the backend traits (ADR-010's
|
`GitSession`, substrate types (including the service selector and the
|
||||||
|
authorized-repo marker), `Limits`, the backend traits (ADR-010's
|
||||||
seam), protocol error enums; gix-feature types under the feature.
|
seam), protocol error enums; gix-feature types under the feature.
|
||||||
Publish-freeze point: **OQ-03**.
|
Publish-freeze point: **OQ-03**.
|
||||||
|
|
||||||
@@ -161,11 +171,13 @@ Publish-freeze point: **OQ-03**.
|
|||||||
| [010](decisions/010-pure-protocol-crate.md) | Pure protocol crate | wire layer is backend-trait-only |
|
| [010](decisions/010-pure-protocol-crate.md) | Pure protocol crate | wire layer is backend-trait-only |
|
||||||
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack | V0-framed push machine, thin-pack acceptance, unpack-first CAS |
|
| [013](decisions/013-receive-pack-state-machine.md) | receive-pack | V0-framed push machine, thin-pack acceptance, unpack-first CAS |
|
||||||
| [014](decisions/014-v2-negotiation-ack-loop.md) | Negotiation | ack loop, no `ready`, wait-for-done stays |
|
| [014](decisions/014-v2-negotiation-ack-loop.md) | Negotiation | ack loop, no `ready`, wait-for-done stays |
|
||||||
|
| [016](decisions/016-native-session-preamble.md) | Native session preamble | `{repo, service}` open-op params, request-line preamble, service in the tuple |
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
- **OQ-03**: publish/API freeze (partially resolved — single-crate shape
|
- **OQ-03**: publish/API freeze (partially resolved — single-crate shape
|
||||||
settled by ADR-010).
|
settled by ADR-010; the native-path preamble shapes entered the freeze
|
||||||
|
inventory via ADR-016).
|
||||||
- **OQ-05**: sha256 policy (deferred(scope)).
|
- **OQ-05**: sha256 policy (deferred(scope)).
|
||||||
- OQ-02 resolved (ADR-014 — ack loop design).
|
- OQ-02 resolved (ADR-014 — ack loop design).
|
||||||
- OQ-04 resolved (ADR-013 — receive-pack state machine).
|
- OQ-04 resolved (ADR-013 — receive-pack state machine).
|
||||||
@@ -176,7 +188,7 @@ Publish-freeze point: **OQ-03**.
|
|||||||
`docs/research/poc3-findings.md` (the normative wire behavior —
|
`docs/research/poc3-findings.md` (the normative wire behavior —
|
||||||
observed against real git, not docs' grammar)
|
observed against real git, not docs' grammar)
|
||||||
- `docs/research/push-captures.md` (the push-path normative record —
|
- `docs/research/push-captures.md` (the push-path normative record —
|
||||||
ADR-013's basis)
|
ADR-013's basis; the git:// request-line framing ADR-016 adopts)
|
||||||
- `docs/research/negotiation-captures.md` (the negotiation normative
|
- `docs/research/negotiation-captures.md` (the negotiation normative
|
||||||
record — ADR-014's basis)
|
record — ADR-014's basis)
|
||||||
- `docs/research/git-protocol.md` (inventory + observed corrections)
|
- `docs/research/git-protocol.md` (inventory + observed corrections)
|
||||||
|
|||||||
@@ -760,7 +760,7 @@ criticals are ADR-writing work, not code):
|
|||||||
|----|---------|----------------|--------|------|--------|
|
|----|---------|----------------|--------|------|--------|
|
||||||
| A-1 | op-gate OR not expressible in `AccessControl` | new ADR (or ADR-012 §3 amendment): handler-side two-tier check, create keeps static scope gate | small | none | **resolved (ADR-015)** — option (a) shape with the OR-term generalized to the `manage` grant |
|
| A-1 | op-gate OR not expressible in `AccessControl` | new ADR (or ADR-012 §3 amendment): handler-side two-tier check, create keeps static scope gate | small | none | **resolved (ADR-015)** — option (a) shape with the OR-term generalized to the `manage` grant |
|
||||||
| A-2 | `async fn` traits not dyn-compatible | ADR-012 §1 + backend.md amendment: `#[async_trait]`; add `async-trait = "0.1"` to manifest | small | none | **resolved** — all five traits `#[async_trait]`, desugared boxed form pinned in the freeze inventory (OQ-03), dep in manifest |
|
| A-2 | `async fn` traits not dyn-compatible | ADR-012 §1 + backend.md amendment: `#[async_trait]`; add `async-trait = "0.1"` to manifest | small | none | **resolved** — all five traits `#[async_trait]`, desugared boxed form pinned in the freeze inventory (OQ-03), dep in manifest |
|
||||||
| A-3 | native preamble / service dimension unpinned | new ADR: open-op params `{repo, service}`, session tuple + stateless entry gain the service selector, `GitAdapter` preamble pinned | moderate | wire-format (freeze inventory) | open |
|
| A-3 | native preamble / service dimension unpinned | new ADR: open-op params `{repo, service}`, session tuple + stateless entry gain the service selector, `GitAdapter` preamble pinned | moderate | wire-format (freeze inventory) | **resolved (ADR-016)** — `{repo, service}` open-op params (`channels/git/sub`, `additionalProperties: false`), git-daemon request line on the direct path (POC-1 verbatim, freeze inventory), service in both substrate tuples, `GitSession` mirrors the shapes |
|
||||||
| A-4 | done-round boundary set unverified | ADR-014 §2 + transport.md clause: boundary = `common_haves`-filtered haves | trivial | none | **resolved** — boundary set is the recognized subset (`common_haves`-filtered), amendment clause in ADR-014 §2 + transport.md §fetch |
|
| A-4 | done-round boundary set unverified | ADR-014 §2 + transport.md clause: boundary = `common_haves`-filtered haves | trivial | none | **resolved** — boundary set is the recognized subset (`common_haves`-filtered), amendment clause in ADR-014 §2 + transport.md §fetch |
|
||||||
| A-5 | consumer half unspecified | user scope decision, then amendment or small ADR (recommended: thin wrapper, deps carried with purpose) | small | scope | open |
|
| A-5 | consumer half unspecified | user scope decision, then amendment or small ADR (recommended: thin wrapper, deps carried with purpose) | small | scope | open |
|
||||||
| A-6 | trait execution model unspecified | backend.md paragraph + transport.md rephrase: async traits, wire-layer permit, impl-internal spawn_blocking | small | none | **resolved** — backend.md concurrency model: wire layer enforces the ADR-009 permit around gen/ingest trait calls; impls own internal `spawn_blocking` (ADR-009/ADR-013 aligned) |
|
| A-6 | trait execution model unspecified | backend.md paragraph + transport.md rephrase: async traits, wire-layer permit, impl-internal spawn_blocking | small | none | **resolved** — backend.md concurrency model: wire layer enforces the ADR-009 permit around gen/ingest trait calls; impls own internal `spawn_blocking` (ADR-009/ADR-013 aligned) |
|
||||||
|
|||||||
Reference in new issue
Block a user