fix: UploadPackV2 must not emit acks section when client sends done #21

merged colechristensen cole.christensen@gmail.com wants to merge fix/upload-pack-v2-done-skip-acks into main
No CI

Closes #37

Summary

  • When `done` is in the fetch request, skip the acknowledgments section entirely and respond with `[shallow-info] + packfile` directly.
  • Modern git (`fetch-pack.c` v2.53, line 1715-1723) transitions from `FETCH_SEND_REQUEST` → `FETCH_GET_PACK` — bypassing `FETCH_PROCESS_ACKS` — whenever `send_fetch_request` returned `done_sent=1`. `FETCH_GET_PACK` expects `packfile` (or optional shallow-info / wanted-refs / packfile-uris) and dies with `expected ‘packfile’, received ‘acknowledgments’` if we lead with acks.
  • Previous fix (PR #19) always-emit-acks-when-haves-were-sent was wrong; client is only in PROCESS_ACKS when it has NOT sent `done`.

Why existing tests missed it

Every test that exercised `done` happened to use `done + 0 haves`, which hits the `build_acknowledgments(_repo, [], _) -> «»` branch and correctly omits acks. The hephaestus trace showed 6 haves + `done` in the same request.

Regression coverage

  • `upload_pack_v2_negotiation_test.exs` — state-machine test driving `UploadPackV2.feed` with `done + unknown haves`, asserting response’s first pkt-line is `packfile`, never `acknowledgments`.
  • Real-git-client multi-round test seeding 300 unrelated side commits on the client to force the negotiator past `MAX_IN_VAIN=256`, reproducing the hephaestus scenario end-to-end (tagged `:slow`).
  • Three pre-existing tests that baked in the wrong acks-after-done invariant updated to assert the correct protocol shape.

Test plan

  • `mix test –include integration –include slow` — 800/800 pass
  • `mix format –check-formatted`
  • `mix credo –strict` — no new warnings introduced
  • After deploy to anvil.fangorn.io, verify `git fetch` in hephaestus succeeds (final acceptance test)
Created Apr 19, 2026 at 15:24 UTC | Merged Apr 19, 2026 at 17:51 UTC by colechristensen cole.christensen@gmail.com