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>
53 lines
2.6 KiB
Markdown
53 lines
2.6 KiB
Markdown
# 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`.
|