From d8f6d2a80423e1358dc138f767621dbc6e361d3a Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Fri, 25 Sep 2026 08:41:30 -0700 Subject: [PATCH] v1.1 plan: state the ReverseProxy abort behaviour the fix depends on; note the second stop Co-Authored-By: Claude Fable 5.1 --- docs/plans/v1.1/01-review-fixes.md | 9 ++++++++- docs/plans/v1.1/README.md | 8 ++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/plans/v1.1/01-review-fixes.md b/docs/plans/v1.1/01-review-fixes.md index a9bab18..e034519 100644 --- a/docs/plans/v1.1/01-review-fixes.md +++ b/docs/plans/v1.1/01-review-fixes.md @@ -33,7 +33,14 @@ 2. **`/_crossbar/usage` JSON** encodes an empty result as `[]`: initialise the slice (`rows := []store.UsageRow{}` / `make(..., 0)`) before encoding, on every `by` value and with or without `since`. The text form prints its header line even with no rows. -3. Nothing else changes. Existing tests must keep passing; the two new ones must pass. +3. **Environment fact you need:** when the client disconnects while `httputil.ReverseProxy` is + copying the response and the request came through a real `http.Server`, `ServeHTTP` does not + return — it panics with `http.ErrAbortHandler`, which the server swallows. Code after + `rp.ServeHTTP` never runs on that path. Write the accounting row from a **deferred** function + in `forward`: `recover()`, record (status 499 when the recovered value is `http.ErrAbortHandler` + or the request context is done), then re-panic with the same value so the server keeps its + semantics. Exactly one row per request on every path. +4. Nothing else changes. Existing tests must keep passing; the two new ones must pass. ## Steps diff --git a/docs/plans/v1.1/README.md b/docs/plans/v1.1/README.md index f1aafe2..ad3fc13 100644 --- a/docs/plans/v1.1/README.md +++ b/docs/plans/v1.1/README.md @@ -32,3 +32,11 @@ Branch `v1.1`. One task, one fresh OpenCode session, one commit. the sandbox refused a `/tmp` scratch program (the I9 pattern, third time tonight). The rule against ending a turn on a refusal lived only in v1's task 05; it is now in `AGENTS.md`, so every task carries it. Resumed from the working tree. +- 2026-09-25, task 01, second session: two of three tests passing; the mid-stream cancel wrote + no row because `httputil.ReverseProxy` does not return when the client disconnects mid-copy on a + real server — it panics with `http.ErrAbortHandler`, so code after `rp.ServeHTTP` never runs. + Ornith tried to read the Go source tree to find that out; the sandbox refused (outside the + repository) and the session ended on the refusal again. Two faults: the task text did not state + the environment's behaviour (mine — the customer describes the world the code runs in), and the + model ended a turn on a refusal (its, fourth time). Third session given the fact and told to + record from a deferred function with `recover()`.