Files
alkssh/tasks/implementation/w4-git-exit-close.md
T
glm-5.3-flash dba64d65d3 docs(tasks): decompose wave 4 — the client direction
Eight implementation tasks + the gate under tasks/implementation/,
folding the wave-3 gate's four booked findings in as dedicated tasks
(the gate's own disposition — wave-4 material, not wave-3 backports).

Hardening set (server-side, independent of the client chain,
scheduled first as cheap remediation):

- w4-git-exit-close: booked item 1 — the git row's status-before-close
  by construction (the seam/shape decided + recorded in-task; the
  saturated-buffer scenario pinned on the wire)
- w4-channel-not-held-rows: booked item 2 — the guard's wire rows on
  git/tty pipe/shell, per build (test-only)
- w4-tty-coverage: booked item 3 — the channel_close-fired cancel
  path + the Closed/Break no-exit-chunk rows + the write_all
  no-deadline known-limit record
- w4-router-collision: booked item 4 — the ListenRouter
  token-collision fail-closed pre-check

Client chain (sequential logistically — one client Handler impl):

- w4-dial: the russh client stack + the connection handle + the
  client Handler skeleton at fail-closed defaults, over an in-process
  fake-sshd server double
- w4-op-rows: exec/pty, direct-tcpip, git exec over the shared
  grammar, the sftp client-side decline — the POC-3 §D.3 mechanics
- w4-reverse-listen: the -R leg — forward requests + the acceptor
  registry + late-install (the wave's highest-risk task)
- w4-lifecycle: the OQ-12 primitives (cancellable handles, clean
  disconnect, no reconnect policy)

review-wave-4 depends on all eight. The gate's item 5 (upstream asks)
stays booked with its owners — no task. Plan wave-4 section carries
the decomposition record + four flagged interpretations; wave table
status updated.

Verification: taskgraph validate ✓ (35 tasks)
2026-10-29 05:59:03 +00:00

3.3 KiB
Raw Blame History

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
w4-git-exit-close Wave 4 — git row hardening (status-before-close by construction — wave-3 gate booked item 1) pending
w3-git-mapping
narrow medium component implementation

Description

Close the wave-3 gate's only structural booked finding (review-wave-3 §Booked findings item 1): the git row's status-before-close is honored by scheduling, not by construction. Today serve_duplex_resolved splits the channel stream internally and its session halves drop when the serve returns — russh's ChannelCloseOnDrop rx-half emits a server→client CHANNEL_CLOSE inside the seam call, before serve_git_row's explicit exit_status_request. The ordering currently holds (the task's continuation queues the report in the same poll, ahead of the drop's send) and every wire row passes, but a full Sender<Msg> buffer at the serve tail could order the implicit close first and silently drop the report (russh no-ops exit_status_request for an already-closed channel) — a silent exit-report loss on a published row.

The fix wants a seam/shape change — decide + record which:

  • split the channel halves in serve_git_row and pass them into the seam (the report then rides a half the seam never closes), or
  • queue the exit report while the stream is alive (the report's send ordered before any close-contracting drop by construction), or
  • another shape that makes the ordering structural rather than scheduler-luck — the gate's reasoning and the two named options are the starting points, not the bounds.

Constraints: every existing git wire row stays green (no behavior change on the happy path — this is ordering hardening, not semantics change); the spawn-and-return constraint (ADR-006 decision 4) holds — the reporting still rides the spawned task; the tty rows are NOT in this class (their report precedes any close-contracting drop in one task — the gate verified; don't touch them). New wire row(s) pinning the construction: a saturated Sender<Msg> buffer at the serve tail (the failure scenario made real) still delivers the exit report — the by-construction property proven on the wire, not by reasoning.

Acceptance Criteria

  • The shape decided + recorded (module docs carry the reasoning); the git row's status-before-close holds by construction, not scheduling
  • Every existing git wire row green (no happy-path behavior change); the spawn-and-return constraint intact
  • New wire row(s): the saturated-buffer scenario delivers the exit report (the by-construction property pinned)
  • cargo test (+ per-feature + --all-features), clippy ×2 (-D warnings), fmt, cargo doc --no-deps pass

References

  • tasks/implementation/review-wave-3.md §Booked findings item 1 (the full finding + the two named fix shapes)
  • docs/architecture/mapping.md (the git exec row — exit-status both directions), docs/architecture/decisions/006-mapping-bridge-and-dispatch.md (decision 4 — spawn-and-return)
  • src/git_map.rs, src/serve.rs (report_exit_status_then_close — the wave-2 reporting mechanics this hardening composes with), alkgit 0.1.0 serve_duplex_resolved (the seam whose half-ownership is the question)

Notes

To be filled by implementation agent

Summary

To be filled on completion