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

6.4 KiB
Raw Blame History

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
w3-git-mapping Wave 3 — the git mapping (exec grammar + alkgit dispatch) pending
w3-decline-tracing
moderate medium phase 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.