Files
alkssh/tasks/implementation/w3-git-mapping.md
T
glm-5.3-flash d1f755f2d9 docs(tasks): decompose wave 3 — the server mappings
Six implementation tasks + the gate under tasks/implementation/,
chained sequentially (the mappings replace stubs in the same Handler
impl and share the decline-matrix test binaries):

- w3-seam-config: the serve-config's per-feature seam handles
  (alktty backends/ownership/selector; the alkgit quartet/pipeline/
  push-options flag) + the optional sibling deps — wave 3's first
  course correction to the wave-1 config surface
- w3-decline-tracing: the wave-2 gate's booked finding — the
  decline/serve-path tracing vocabulary, landed before the mappings
- w3-git-mapping: the full exec grammar replaces the wave-2 probe +
  the serve_duplex_resolved dispatch + the store-and-take handoff
- w3-tty-session: the translation bridge + the exit-derivation
  contract (rules 1-6, the signum table)
- w3-tunnel-direct: the route-1 bridge (accept only after the fabric
  open succeeds) + set_identity propagation + the capacity-across-
  fabric-window mechanics
- w3-tunnel-listen: the -R listen flow + the forwarded-tcpip data
  leg (the POC-untested leg; the stop-and-book provision)
- review-wave-3: the gate

The plan carries the wave-3 decomposition record with four
interpretations flagged for the gate (the serve-config course
correction, the already-discharged server-side sftp bullet, the
w3-tunnel-listen open mechanics, the booked-items' wave-3 homes).
taskgraph validate: 26 tasks, clean.

Sibling pins verified against crates.io at decomposition time:
alktty 0.8.1 / alkgit 0.1.0 / alktunnels 0.4.1 / alkcall 0.10.1.
2026-10-28 12:32:13 +00:00

124 lines
6.4 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.
---
id: w3-git-mapping
name: Wave 3 — the git mapping (exec grammar + alkgit dispatch)
status: pending
depends_on: [w3-decline-tracing]
scope: moderate
risk: medium
impact: phase
level: implementation
---
## Description
Land the git branch of the spine (ADR-006 decision 2, exec-only) — the
alkforge primary purpose: the full exec grammar replaces the wave-2
skeleton probe, and the git row becomes a real dispatch to the
published alkgit seam. Everything POC-3 stage A proved, re-landed as
contract.
- **The full grammar** (replaces `dispatch::classify_exec` — the
wave-2 interpretation's named replacement; its 7 probe unit rows
migrate): `git-{upload,receive}-pack '<path>'` — quoted/unquoted
paths; strip the quotes and the leading `/` (POC-3 stage A rows:
what real OpenSSH git sends); unknown services
(`git-send-pack`, `git-upload-archive`) → decline-with-reason, the
honest surface; service-only (no repo) → decline-with-reason —
POC-3 §A: SSH exec must carry the repo; per-length limits consumed
at last — `Limits::max_exec_command_len` enforced **before** any
parse or allocation (decline-first, alloc-never; the wave-2
carried-not-enforced reservation). Decide the wire shapes per
decline class (open/reply vocabulary, whether "unknown service" and
"not git at all" share a reason shape) and record.
- **Repo path → repo_id, no existence oracle**: the parse validates
via `alkgit::validate_repo_id` (1–2 segments, charset, ≤ 100 bytes)
and hands the id through — alkssh never resolves; the
**collapsed generic denial before any protocol byte** is
`serve_duplex_resolved`'s `SubstrateError::AccessDenied` posture,
contract-pinned here: over the SSH channel, no pack/ref byte
precedes the denial band (the POC-3 §A.5 byte-order evidence, now a
test row). Decide the `.git`-suffix normalization against the
alkgit registry contract (what vanilla git sends vs
`validate_repo_id`'s grammar) and record.
- **The dispatch** — the git row becomes real: the taken channel
(the store-and-take handoff lands **here first** — the accepted
channel is stored at the open, `channels.remove(&id)` →
`into_stream()` in the spawned serving task; the session task
reuses the store) → `alkgit::serve_duplex_resolved(repo_id,
identity, service, duplex, limits, registry, refs, packgen,
ingest, push_options_negotiated, pipeline)` — the serve-config's
`git` seam handle (`w3-seam-config`), the resolved identity riding
the `identity` param. Process-mode dialect: alkgit speaks first
(the V0 advertisement, no service prefix) — nothing alkssh-side;
verify the dialect holds over the channel duplex with a byte-level
row.
- **Exit-status both directions** (POC-3 §A.5): clean serve end →
`exit-status(0)`... decide the code mapping (`SubstrateError`
outcomes → the code — POC evidence: denied → the client observed
`ExitStatus{1}`; vanilla git exits 0 on success) — sent before
close, from the spawned task via the cloned `Session::handle()`
(the wave-2 mechanics reused). Record the decision.
- **Identity** — the parked wave-2 deferred item discharges here:
the resolved identity (the bridge's `auth_succeeded` ride-along)
reaches the seam — assert it live (the authorize-path/witness row
the harness can observe; decide the cheapest row) so the
visible-surface invariant is observable through the git row.
- **Contract rows through the harness, per build** — the
`tests/dispatch_core.rs` skeleton rows upgraded: git-only serves
the git row through the doubles (clone/push semantics over the
in-mem composition), declines plain exec/pty/shell (parse-then-fail,
no resource alloc); session-only still declines git-parseable exec;
none-build still declines at open; under `--all-features` the
routing holds. The declined rows keep their wire shapes
(`channel_failure`, channel usable / serving-path failure+close per
class).
- **The real-tool smoke** — one `git clone` (2.43+) through the
harness against hand-rolled in-mem alkgit doubles (alkgit's `Mem*`
are test-private — alkssh hand-rolls the minimal quartet per
`alkgit/src/backend.rs:164-254`'s noop shapes; never sibling-checkout
paths, never copies of the doubles' code). Decide the tooling
posture (require git in the environment vs conditional-skip —
skipped-with-reason at most, never silently green) and record.
## Acceptance Criteria
- [ ] The full grammar replaces the probe (quoted/unquoted, unknown-
service vs non-git decline rows, service-only decline, the
`max_exec_command_len` pre-parse cap); the probe's unit rows
migrate/extend
- [ ] The git row dispatches to `serve_duplex_resolved` over the
channel duplex; process-mode dialect verified byte-level;
declined routes and the `AccessDenied`-before-protocol-bytes
order pinned by contract rows
- [ ] The store-and-take handoff lands (channel stored at open, taken
in the serving task), structured so the session task reuses it
- [ ] The exit-status mapping (clean end / terminal error) decided +
recorded; status before close from the spawned task
- [ ] The identity ride asserted live through the seam (the parked
wave-2 item discharged here)
- [ ] The decline-matrix rows per build green through the harness
(git-only / session-only / none / all-features), each with its
contract stamp; the real-tool clone smoke row
- [ ] `cargo test`, `cargo test --features git --test <git rows>`,
`cargo test --all-features`, clippy ×2 (`-D warnings`), fmt,
`cargo doc --no-deps` pass
## References
- docs/architecture/mapping.md (the git channel-type row; §Session-
channel dispatch — decline-first-alloc-never; §the structural
constraint)
- docs/architecture/decisions/006-mapping-bridge-and-dispatch.md
(decision 2 — exec-only; decision 4 — spawn-and-return)
- docs/architecture/decisions/004-auth-dispositions.md (the identity
ride), docs/architecture/auth.md §Server direction (step 4)
- docs/research/poc-3-mapping-bakeoff.md §Stage A (the grammar rows,
the denial byte-order, the exit evidence, the spawn rule)
- docs/research/mapping-table.md (the validated research ancestor)
- alkgit 0.1.0: `serve_duplex_resolved` (`src/duplex.rs:1412`),
`SubstrateError` (`src/substrate.rs:116`), `validate_repo_id`
(`src/registry.rs:132`), the trait shapes (`src/backend.rs:164-254`)
## Notes
> To be filled at implementation time.