Files
boxmaker/docs/plans/M2a/14-inferproxy-close.md
T
kyleandClaude Fable 5.1 58c7738721 Review M2a: accept with two follow-up tasks; record models and lessons
The branch passes every check, including make verify-device on
straylight and repeated timing runs under load. Reading and probing
found that inferproxy does not pass an upstream close on to a client
that is still sending, and that the chunked body reader delivers a
stream only when the caller's buffer fills or the stream ends. Both
were also gaps in the tasks and tests, so tasks 14 and 15 carry the
fixes with new tests checked against the reference.

The Model column is corrected: tasks 04 to 06 and 08 to 13 were Ornith.
Lessons gain four implementer tips and five task-writing tips; three
rules are promoted to AGENTS.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-18 15:43:06 -07:00

2.6 KiB

M2a task 14: pass the upstream's close on to the client (review follow-up)

Branch: m2a (run git switch m2a; git status --short must be empty, otherwise stop) Commit subject: Close the client side when the upstream closes, in inferproxy

Goal

The M2a review found that inferproxy only closes towards the client after the client has stopped sending. loopd's HTTP client never stops sending on its own: it keeps its side open until it drops the connection. So when llama-server closes, or dies in the middle of an answer, the client is not told; it sits until its own liveness timeout and reports Stalled instead of StreamClosedEarly, thirty seconds late. A body that runs to the close would hang the same way.

Task 02, rule 3, said: "When the server stops sending, the exchange is over: close both." The current code waits for both copy threads to finish instead. This was partly the plan's fault: every test client in forward.rs half-closed after sending, so the gap could not show. The new test sends without half-closing.

Files

  • Copy (replacing the old one): crates/inferproxy/tests/forward.rs
  • Modify: crates/inferproxy/src/lib.rs, docs/implementer-log.md

Required behaviour

  • When the server-to-client copy ends, for any reason, shut down the client connection (both directions) and the server connection, so that the client's read returns 0 at once and the client-to-server copy thread ends. Do this after releasing the open-connection place, as rule 4 of task 02 requires.
  • Everything else from task 02 still holds, including the half-close when the client stops sending first.

Steps

  • 1. Copy. git switch m2a, then cp docs/plans/M2a/files/crates/inferproxy/tests/forward.rs crates/inferproxy/tests/
  • 2. See it fail. cargo test -p inferproxy --test forward. Expected: 1 of 7 fails, the_upstreams_close_reaches_a_client_that_is_still_sending, with a timeout.
  • 3. Fix lib.rs. Run cargo fmt --all.
  • 4. See it pass. cargo test -p inferproxy --test forward, ten times in a row. Expected: 7 passed every time.
  • 5. Run the gate. make gate. Expected last line: gate: ok.
  • 6. Log and commit. git add crates/inferproxy docs/implementer-log.md && git commit

Done when

  • cargo test -p inferproxy --test forward reports 7 passed, ten runs in a row; make gate prints gate: ok; cmp crates/inferproxy/tests/forward.rs docs/plans/M2a/files/crates/inferproxy/tests/forward.rs prints nothing.

Stop and report if

  • Passing the new test breaks forwards_both_ways_and_passes_the_half_close_on.