textmachine/backend/internal/llm/attemptcut_test.go

1439 lines
71 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package llm
import (
"bufio"
"context"
"errors"
"fmt"
"io"
"log/slog"
"net"
"net/http"
"net/http/httptest"
"os"
"regexp"
"strconv"
"strings"
"sync/atomic"
"testing"
"time"
)
// attemptcut_test.go: the two things the cut-call boundary rests on — that the per-attempt deadline is
// DERIVED from the budget rather than typed, and that a delivered request is told apart from an
// undelivered one by the transport rather than by the size of what came back.
// draftGrant and editorGrant are the two real output budgets of the shipping pipeline: the draft's, and
// the editor's after one regeneration doubled it. Two, because a single grant cannot distinguish a
// formula from a constant that happens to match it.
const (
draftGrant = 8496
editorGrant = 32000
)
// vendorSeconds answers how long the vendor's own budgeting says it takes to emit n output tokens. It is
// deliberately the reciprocal ARRANGEMENT of the production formula — tokens × window ÷ budget, where
// deriveDeadline does tokens ÷ (budget ÷ window) — so a formula rewritten the wrong way round is caught.
//
// ⚠ IT PINS THE ARRANGEMENT AND NOT THE NUMBERS, and an earlier version of this comment claimed
// otherwise. Both sides read the SAME two package constants, so corrupting them moves both and the
// identity still holds: `vendorHourlyTokenBudget` was quadrupled and the whole battery stayed green.
// The numbers are pinned by TestTheVendorsPublishedPairIsWhatTheVendorPublishes, which quotes them
// against the source they came from; this function is the other half and neither replaces the other.
func vendorSeconds(n int) time.Duration {
return time.Duration(float64(n) * float64(vendorBudgetWindow) / float64(vendorHourlyTokenBudget))
}
// TestTheAttemptDeadlineIsDerivedFromTheBudget pins the FORMULA. It cannot be satisfied by any
// constant, because every expectation below is computed here from the vendor's two published numbers
// and the grant, and because the ratio assertion holds for a derivation and for nothing else.
//
// ⛔ WHY IT IS WRITTEN THIS WAY. The obvious version of this test asserts that the draft's grant
// derives to the deadline the config used to carry. That number is a PRODUCT of the formula, so
// writing it down turns the test into a pin on a literal — and the next person to see the arithmetic
// land a hair under a round number "fixes" the round number back in and the pin agrees. So: no
// expected duration appears in this file as a number at all, and TestTheDeadlineTestQuotesNoDeadline
// enforces that mechanically.
func TestTheAttemptDeadlineIsDerivedFromTheBudget(t *testing.T) {
// The claim this whole change rests on, stated as arithmetic: the deadline the shipping config
// carried is what the vendor's own rate gives for the DRAFT's budget, to within a second — which is
// why it was right there and wrong everywhere else. Asserted as agreement between two independently
// sourced numbers, one from the vendor and one from the config, with neither written down.
bare := RetryProfile{}
if got, want := bare.deriveDeadline(draftGrant), vendorSeconds(draftGrant); got != want {
t.Fatalf("draft grant %d derives to %s, the vendor's own rate says %s", draftGrant, got, want)
}
if got, want := bare.deriveDeadline(editorGrant), vendorSeconds(editorGrant); got != want {
t.Fatalf("editor grant %d derives to %s, the vendor's own rate says %s", editorGrant, got, want)
}
// The editor's doubled budget needs MORE than three times the draft's deadline. That is the whole
// finding: one attempt_s covered both, so the doubling axis was buying a budget the clock could
// never spend. The multiple is derived, not chosen — editorGrant/draftGrant.
if bare.deriveDeadline(editorGrant) <= 3*bare.deriveDeadline(draftGrant) {
t.Fatalf("the editor's doubled budget must need materially longer than the draft's: draft=%s editor=%s",
bare.deriveDeadline(draftGrant), bare.deriveDeadline(editorGrant))
}
// Doubling the budget doubles the GENERATION time and leaves the queue wait alone — the property
// that makes the slack a summand rather than a factor. True of a derivation, false of a constant,
// and false of any formula that amortized the wait over the budget.
withSlack := RetryProfile{TokensPerSecFloor: 50, QueueSlack: 7 * time.Minute}
n, twoN := 4000, 8000
single := withSlack.deriveDeadline(n) - withSlack.QueueSlack
double := withSlack.deriveDeadline(twoN) - withSlack.QueueSlack
if double != 2*single {
t.Fatalf("doubling the budget must double the generation term and nothing else: %s → %s (want %s)",
single, double, 2*single)
}
if withSlack.deriveDeadline(n) != withSlack.QueueSlack+single {
t.Fatalf("the vendor's documented queue wait is added whole, not amortized")
}
// A configured floor is USED. Without this the two arms above would both pass on a build that
// ignored the field and always took the default.
fast := RetryProfile{TokensPerSecFloor: 2 * (vendorHourlyTokenBudget / vendorBudgetWindow.Seconds())}
if got := fast.deriveDeadline(editorGrant); got != vendorSeconds(editorGrant)/2 {
t.Fatalf("a floor twice the vendor default must halve the derived time, got %s", got)
}
}
// TestTheDeadlineClampsAtBothEnds pins that attempt_s is a FLOOR and attempt_max_s a ceiling — the
// property that lets this land on every shipping config at once, because no provider can lose a second
// it has today.
func TestTheDeadlineClampsAtBothEnds(t *testing.T) {
floor := 5 * time.Minute
p := RetryProfile{AttemptTimeout: floor, TokensPerSecFloor: 50}
// A call small enough to derive under the configured deadline keeps the configured one.
if got := p.DeadlineFor(1); got != floor {
t.Fatalf("attempt_s is the FLOOR: a tiny call must keep it, got %s want %s", got, floor)
}
// One big enough to derive over it gets the derived time — otherwise nothing about this change works.
if got := p.DeadlineFor(editorGrant); got != p.deriveDeadline(editorGrant) {
t.Fatalf("a call the configured deadline cannot cover must get the derived one, got %s", got)
}
// And attempt_max_s bounds it.
capped := p
capped.AttemptMax = floor + time.Minute
if got := capped.DeadlineFor(editorGrant); got != capped.AttemptMax {
t.Fatalf("attempt_max_s must bound the derivation, got %s want %s", got, capped.AttemptMax)
}
// An unset ceiling is inert rather than zero — a zero read as a ceiling would cut every call to nothing.
if got := p.DeadlineFor(editorGrant); got <= 0 {
t.Fatalf("an unset attempt_max_s must not act as a zero ceiling, got %s", got)
}
}
// TestAnUnsetOrBrokenFloorFallsBackToTheVendorDefault: an empty field, a zero and a negative must all
// give the vendor rate. Not a division by zero, and — the one that would be silent — not a deadline of
// nothing, which would cut every call the instant it went out and bill every one of them as an estimate.
func TestAnUnsetOrBrokenFloorFallsBackToTheVendorDefault(t *testing.T) {
want := vendorSeconds(editorGrant)
for _, floor := range []float64{0, -1, -1e9} {
p := RetryProfile{TokensPerSecFloor: floor}
if got := p.deriveDeadline(editorGrant); got != want {
t.Fatalf("floor %v must fall back to the vendor rate: got %s want %s", floor, got, want)
}
if got := p.deriveDeadline(0); got != 0 && p.QueueSlack == 0 {
t.Fatalf("a zero budget derives a zero generation term, got %s", got)
}
}
}
// TestTheDeadlineTestQuotesNoDeadline is the guard on the guard. It reads THIS FILE and asserts that
// the four numbers the derivation produces for the shipping grants appear nowhere in it — so a later
// session cannot "simplify" the arithmetic above into the constant it evaluates to and keep a green
// test that pins nothing.
//
// The control value is printed with the negative, because "no matches" and "the file was not read" are
// the same output and only one of them is a passing test.
func TestTheDeadlineTestQuotesNoDeadline(t *testing.T) {
src, err := os.ReadFile("attemptcut_test.go")
if err != nil {
t.Fatal(err)
}
// ⛔ THE BANNED LIST IS DERIVED, NOT TYPED, and the first version of this test failed against
// itself for exactly the reason the ban exists: writing the four numbers into the pattern put them
// in the file. Deriving them from the formula also means the ban follows the formula — change the
// vendor's published rate and this test bans the NEW products of it without anyone remembering to.
var banned []string
for _, grant := range []int{draftGrant, editorGrant} {
secs := int(vendorSeconds(grant).Round(time.Second).Seconds())
// The neighbours too: a rounded-up «nicer» value is precisely the shape a later session would
// substitute for the derivation.
banned = append(banned, strconv.Itoa(secs-1), strconv.Itoa(secs), strconv.Itoa(secs+1))
}
hits := regexp.MustCompile(`\b(`+strings.Join(banned, "|")+`)\b`).FindAllString(string(src), -1)
// The control: two numbers that ARE in the file, sought by the same instrument. Without it «no
// matches» and «the search never ran» print identically, and only one of them is a passing test.
control := regexp.MustCompile(`\b(`+strconv.Itoa(draftGrant)+`|`+strconv.Itoa(editorGrant)+`)\b`).FindAllString(string(src), -1)
t.Logf("read %d bytes of attemptcut_test.go; banned set %v → %d hit(s); control (the two grants) → %d hit(s)",
len(src), banned, len(hits), len(control))
if len(control) < 2 {
t.Fatalf("the control literals are absent — this test is not reading what it thinks it is")
}
if len(hits) != 0 {
t.Fatalf("the derived deadlines must not appear as literals in this file; found %v — a pin on a "+
"number the formula produced is a pin on nothing", hits)
}
}
// --- the delivery boundary ---
// hangingTLS is a listener that completes the TCP connection and then says nothing at all. A client
// speaking TLS to it blocks in the handshake, so the request is NEVER WRITTEN — the one shape in which
// «nothing was bought» is true by construction, and the one this fixture exists to keep distinct from
// every other failure. It is deliberately not an httptest server: an HTTP server that merely sleeps
// receives the request first, which is the opposite case.
func hangingTLS(t *testing.T) string {
t.Helper()
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
done := make(chan struct{})
go func() {
var held []net.Conn
for {
c, err := ln.Accept()
if err != nil {
for _, h := range held {
h.Close()
}
return
}
held = append(held, c) // accepted, never spoken to
select {
case <-done:
return
default:
}
}
}()
t.Cleanup(func() { close(done); ln.Close() })
return "https://" + ln.Addr().String()
}
func cutProfile(d time.Duration) RetryProfile {
// A floor high enough that the derivation never exceeds the deadline under test: these fixtures are
// about the cut, not about the arithmetic, and a derived deadline would make them slow.
return RetryProfile{AttemptTimeout: d, MaxAttempts: 3, BackoffBase: time.Millisecond,
BackoffCap: 5 * time.Millisecond, TokensPerSecFloor: 1e9}
}
// holdUntilCut blocks a fixture's handler until the client walks away — and NEVER longer than a bound
// of its own. `<-r.Context().Done()` alone reads correct and deadlocks the fixture: httptest.Close
// waits for outstanding handlers, and a handler waiting for a disconnect the server has not noticed
// yet waits for the Close that is waiting for it. A hang has no colour — neither the battery nor a
// mutation reports one — so the bound is the difference between a red test and a silent one.
func holdUntilCut(r *http.Request) {
select {
case <-r.Context().Done():
case <-time.After(3 * time.Second):
}
}
// TestDeliveryIsWhatSeparatesAPurchaseFromAFailure walks the three rows of the boundary table on a
// real client: a request that went out and got no headers, one that went out and got an early 200 with
// nothing in it, and one that never went out at all. All three used to arrive at the same branch.
func TestDeliveryIsWhatSeparatesAPurchaseFromAFailure(t *testing.T) {
t.Run("delivered, headers never came, our deadline", func(t *testing.T) {
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
calls.Add(1)
holdUntilCut(r) // the provider has the request and is «generating»
}))
defer srv.Close()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(150 * time.Millisecond)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("want an AttemptCutError, got %T %v", err, err)
}
if !cut.Delivered {
t.Fatalf("the server RECEIVED the request; Delivered must be true")
}
if cut.AfterHeaders {
t.Fatalf("no response byte ever arrived; AfterHeaders must be false")
}
if cut.Cause != CutBySelfDeadline {
t.Fatalf("our own deadline fired with the parent alive; cause = %s", cut.Cause)
}
// The other side of the count: one delivery reports one, or the field says nothing anywhere.
if cut.Deliveries != 1 {
t.Fatalf("this request reached the provider once; Deliveries=%d", cut.Deliveries)
}
// NOT retried: the provider is still generating what we just stopped listening to.
if got := calls.Load(); got != 1 {
t.Fatalf("the server must have been asked exactly once, got %d", got)
}
})
t.Run("delivered, early 200 with empty lines, our deadline", func(t *testing.T) {
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
calls.Add(1)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte("\n")) // the vendor's documented «still queued» reply
w.(http.Flusher).Flush()
holdUntilCut(r)
}))
defer srv.Close()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(150 * time.Millisecond)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("want an AttemptCutError, got %T %v", err, err)
}
if !cut.Delivered || !cut.AfterHeaders {
t.Fatalf("a 200 arrived over a delivered request: Delivered=%t AfterHeaders=%t", cut.Delivered, cut.AfterHeaders)
}
// The BOTH-SIDES half of the field: whitespace here, JSON in the next case. A field asserted on
// one side only says nothing about whether it is computed at all.
if !cut.WhitespaceOnly {
t.Fatalf("the body was a newline; WhitespaceOnly must be true (bytes read: %d)", cut.BytesRead)
}
if got := calls.Load(); got != 1 {
t.Fatalf("a 200 that carried nothing must not be re-bought, got %d calls", got)
}
})
t.Run("delivered, cut mid-JSON, our deadline", func(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"id":"x","choices":[{"message":{"content":"половина`))
w.(http.Flusher).Flush()
holdUntilCut(r)
}))
defer srv.Close()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(150 * time.Millisecond)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("want an AttemptCutError, got %T %v", err, err)
}
if cut.WhitespaceOnly {
t.Fatalf("the body carried a fragment of a real answer; WhitespaceOnly must be false")
}
if cut.BytesRead == 0 {
t.Fatalf("BytesRead must carry what did arrive")
}
})
t.Run("NOT delivered", func(t *testing.T) {
base := hangingTLS(t)
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: base, Profile: cutProfile(120 * time.Millisecond)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
if err == nil {
t.Fatal("want an error")
}
var cut *AttemptCutError
if errors.As(err, &cut) {
t.Fatalf("the request never went out — treating it as a delivered cut would settle money for "+
"a call nobody received: %v", cut)
}
})
}
// TestACancelledRunKeepsBothTruthsInOneError is the exit-contract fixture, and both assertions live in
// ONE test on ONE error for a reason: they are the two halves of a single requirement. The process
// decides its exit code with errors.Is(err, context.Canceled), and the runner decides whether money is
// owed with errors.As(err, &AttemptCutError). Splitting them across two tests would let a change
// satisfy either one while breaking the other — a stop that exits with the wrong code, or a stop that
// silently loses the money for a call already on the wire.
func TestACancelledRunKeepsBothTruthsInOneError(t *testing.T) {
arrived := make(chan struct{})
var once atomic.Bool
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if once.CompareAndSwap(false, true) {
close(arrived)
}
holdUntilCut(r)
}))
defer srv.Close()
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-arrived // cancel only AFTER the provider has the request: this is the delivered case
cancel()
}()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(10 * time.Second)}, nil)
_, err := c.Complete(ctx, LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
if !errors.Is(err, context.Canceled) {
t.Fatalf("the exit contract reads errors.Is(err, context.Canceled); a stop that stops reporting "+
"itself as one gives the run a foreign exit code. got %T %v", err, err)
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("the same error must still say WHAT the stop interrupted, or the money for a delivered "+
"call is lost with it. got %T %v", err, err)
}
if cut.Cause != CutByParent {
t.Fatalf("cause = %s, want %s", cut.Cause, CutByParent)
}
if !cut.Delivered {
t.Fatalf("the provider had the request when the run was stopped; Delivered must be true")
}
}
// TestABrokenConnectionAfterDeliveryIsRetriedOnceAndOnlyOnce: the third cause. A socket that dies after
// the request went out is transport-shaped, so it is worth one more call — and exactly one, because the
// cap is keyed on DELIVERY rather than on a 2xx. Under the old key («did a 2xx arrive») a provider that
// answers 200 while still queueing could be re-asked under the full attempt budget.
func TestABrokenConnectionAfterDeliveryIsRetriedOnceAndOnlyOnce(t *testing.T) {
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
calls.Add(1)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"id":"x","choices":[`))
w.(http.Flusher).Flush()
// Drop the connection mid-body: the client's read fails with neither deadline expired.
hj, ok := w.(http.Hijacker)
if !ok {
t.Error("the fixture needs a hijackable response writer")
return
}
conn, _, err := hj.Hijack()
if err != nil {
t.Error(err)
return
}
conn.Close()
}))
defer srv.Close()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(5 * time.Second)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("want an AttemptCutError, got %T %v", err, err)
}
if cut.Cause != CutByConnection {
t.Fatalf("cause = %s, want %s", cut.Cause, CutByConnection)
}
if got := calls.Load(); got != 2 {
t.Fatalf("a delivered request whose socket broke is worth ONE retry and no more (max_attempts=3), got %d", got)
}
if !cut.Delivered {
t.Fatalf("the request reached the provider both times; Delivered must be true")
}
// ⛔ AND THE CALLER IS TOLD HOW MANY TIMES. The store books spend only through a checkpoint and both
// deliveries share one key, so ONE estimate covers both — an under-count, which is the ratified
// direction, but a SILENT one is what row 360 was opened about. The number is what makes it readable.
if cut.Deliveries != 2 {
t.Fatalf("the provider was asked twice and the ledger will book once; the error must carry the "+
"count or the gap is invisible again. got Deliveries=%d", cut.Deliveries)
}
}
// TestTheFloorWarningIsSaidOnceAndOnlyWhenItApplies: the operator notice that makes a new provider
// usable as DATA. It has to fire when the derived deadline overrides the configured one — and it has to
// stay silent otherwise, because a warning printed on every healthy call is a warning nobody reads.
func TestTheFloorWarningIsSaidOnceAndOnlyWhenItApplies(t *testing.T) {
fires := func(p RetryProfile, maxTokens int, calls int) int {
var seen atomic.Int32
log := newCountingLogger(&seen, "no measured generation speed")
c := newOpenAIClient("p", "http://127.0.0.1:1", "", p, nil, nil, log)
for i := 0; i < calls; i++ {
c.attemptDeadline(context.Background(), maxTokens)
}
return int(seen.Load())
}
// No floor, and a budget the configured deadline cannot cover: said, once, however many calls.
noFloor := RetryProfile{AttemptTimeout: time.Second}
if got := fires(noFloor, editorGrant, 5); got != 1 {
t.Fatalf("the notice must be said exactly once per client, got %d", got)
}
// No floor, but every call fits inside the configured deadline: nothing to warn about.
if got := fires(RetryProfile{AttemptTimeout: time.Hour}, editorGrant, 5); got != 0 {
t.Fatalf("a provider whose calls fit inside its own attempt_s must hear nothing, got %d", got)
}
// A measured floor is the answer to the notice, so it silences it.
if got := fires(RetryProfile{AttemptTimeout: time.Second, TokensPerSecFloor: 50}, editorGrant, 5); got != 0 {
t.Fatalf("a provider with a measured floor must hear nothing, got %d", got)
}
}
// countingHandler counts log records whose message contains a substring. A slog.Handler rather than a
// buffer scan: asserting on a substring of a shared buffer is the shape that gives both false reds and
// quiet greens (D39.171), and the question here — «how many times was this record emitted» — is a count
// the handler can answer exactly.
type countingHandler struct {
n *atomic.Int32
needle string
}
func (h countingHandler) Enabled(context.Context, slog.Level) bool { return true }
func (h countingHandler) Handle(_ context.Context, r slog.Record) error {
if strings.Contains(r.Message, h.needle) {
h.n.Add(1)
}
return nil
}
func (h countingHandler) WithAttrs([]slog.Attr) slog.Handler { return h }
func (h countingHandler) WithGroup(string) slog.Handler { return h }
func newCountingLogger(n *atomic.Int32, needle string) *slog.Logger {
return slog.New(countingHandler{n: n, needle: needle})
}
// TestAReplyThatOutrunsOurOwnWriteIsStillDelivered is the money leak an adversarial pass measured on
// this pack, reproduced as a pin.
//
// net/http hands back a response as soon as one arrives; WroteRequest fires later, from the write
// loop. So a provider that answers EARLY — DeepSeek documents doing exactly that while a request waits
// to be scheduled — can have its 200 overtake our own callback while the request body is still
// draining. Read as «not delivered», that call books $0 and is retried under the full attempt budget:
// the defect this whole file exists to remove, entering through the door meant to close it.
//
// The fixture forces the ordering by making the request big enough that the write cannot finish inside
// the socket buffer, and by answering before reading it. On loopback that needs megabytes; on a real
// network the window is the send buffer and the congestion window, i.e. orders of magnitude smaller.
func TestAReplyThatOutrunsOurOwnWriteIsStillDelivered(t *testing.T) {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer ln.Close()
done := make(chan struct{})
defer close(done)
go func() {
for {
c, aerr := ln.Accept()
if aerr != nil {
return
}
go func(c net.Conn) {
defer c.Close()
// Answer the moment the request LINE is in, promise a body far longer than what is
// sent — and then HOLD, reading nothing more. Two things follow, and both are needed:
// the client's own body write never finishes (nobody is draining it) and its read of
// the reply never finishes either, so what ends the call is OUR OWN deadline. That is
// what makes this deterministic. An earlier version closed the socket here instead, and
// under load the write failed first, leaving no reply to overtake anything — green
// alone, red inside a six-package baseline run.
br := bufio.NewReader(c)
if _, rerr := br.ReadString('\n'); rerr != nil {
return
}
fmt.Fprint(c, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: 4096\r\n\r\n\n")
select {
case <-done:
case <-time.After(10 * time.Second):
}
}(c)
}
}()
// A prompt big enough that the request body cannot be written into the socket buffer in one go, so
// the write is still outstanding when the reply lands.
huge := strings.Repeat("длинный исходный текст главы. ", 200000)
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: "http://" + ln.Addr().String(), Profile: cutProfile(700 * time.Millisecond)}, nil)
_, err = c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: huge}}, MaxTokens: 16})
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("a 200 came back over this request, so the provider HAS it and may bill for it; booking "+
"$0 here is the leak this pack closes, arriving through its own door. got %T %v", err, err)
}
if !cut.Delivered {
t.Fatalf("Delivered must be true once a response byte has arrived: %+v", cut)
}
if !cut.AfterHeaders {
t.Fatalf("a 200 arrived; AfterHeaders must be true: %+v", cut)
}
if cut.Cause != CutBySelfDeadline {
t.Fatalf("our own deadline is what ended this call; cause = %s (%+v)", cut.Cause, cut)
}
}
// TestAFailedWriteIsNotADelivery is the other side of the same bit, and it had NO pin at all until an
// adversarial pass removed the guard and watched both packages stay green.
//
// `WroteRequest` fires with an ERROR when the write itself failed — the request did not reach the
// provider, nothing was generated, and settling an estimate would charge a reader for a call nobody
// received. The fixture kills the socket without reading the body and without answering, so the
// callback fires with a write error and no response byte ever arrives.
func TestAFailedWriteIsNotADelivery(t *testing.T) {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer ln.Close()
go func() {
for {
c, aerr := ln.Accept()
if aerr != nil {
return
}
c.Close() // accepted, then dropped: the body write fails and nothing comes back
}
}()
huge := strings.Repeat("длинный исходный текст главы. ", 200000)
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: "http://" + ln.Addr().String(), Profile: cutProfile(3 * time.Second)}, nil)
_, err = c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: huge}}, MaxTokens: 16})
if err == nil {
t.Fatal("want an error")
}
var cut *AttemptCutError
if errors.As(err, &cut) {
t.Fatalf("the write itself failed and no reply ever came: the provider received nothing and owes "+
"nothing, so this must NOT be a paid cut. got %+v", cut)
}
}
// TestAStopDuringABackoffKeepsTheEvidence is the SECOND cancellation exit, and it was still throwing
// the evidence away after the first one stopped doing so.
//
// A run stopped during a retry backoff has an attempt behind it that may already have been delivered
// and billed. Returning a bare context error there leaves the runner nothing to settle and the chunk
// with no mark at all — the unexplained hole the whole cancelled-position machinery exists to prevent.
// The window is the entire sleep, up to a minute on the shipping config, and it opens exactly on the
// runs where a provider is flapping and an operator is therefore reaching for the stop.
//
// Both truths are asserted on one error for the same reason as the in-flight case: the exit code reads
// one and the money reads the other.
func TestAStopDuringABackoffKeepsTheEvidence(t *testing.T) {
arrived := make(chan struct{})
var once atomic.Bool
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
calls.Add(1)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, `{"id":"x","choices":[`)
w.(http.Flusher).Flush()
hj, ok := w.(http.Hijacker)
if !ok {
t.Error("the fixture needs a hijackable response writer")
return
}
conn, _, err := hj.Hijack()
if err != nil {
t.Error(err)
return
}
conn.Close() // a delivered request whose socket dies: retryable, so a backoff follows
if once.CompareAndSwap(false, true) {
close(arrived)
}
}))
defer srv.Close()
// ⚠ THE STOP IS DELAYED, and the delay is what makes this test about the backoff at all. Cancelling
// the instant the handler closes the socket is a RACE with the loop's own bookkeeping: the second
// attempt often starts first and is itself cut, so the error under test becomes a `cancelled` from
// somewhere else entirely. Measured before the delay was added: 28 failures in 80 runs, every one of
// them the wrong attempt. The window here is half a second inside a three-second sleep, and the
// call-count assertion below says outright when the fixture missed it.
ctx, cancel := context.WithCancel(context.Background())
go func() {
<-arrived
time.Sleep(500 * time.Millisecond)
cancel()
}()
p := cutProfile(5 * time.Second)
p.BackoffBase, p.BackoffCap = 3*time.Second, 3*time.Second
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: p}, nil)
_, err := c.Complete(ctx, LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
if n := calls.Load(); n != 1 {
t.Fatalf("the loop was meant to be ASLEEP before its retry when the stop landed; the server was "+
"asked %d time(s), so this run measured a different moment", n)
}
if !errors.Is(err, context.Canceled) {
t.Fatalf("a stopped run must still leave as a cancellation, got %T %v", err, err)
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("the delivered attempt behind the backoff must survive the stop, or its money is lost "+
"and the chunk is left with no mark at all. got %T %v", err, err)
}
if cut.Cause != CutByConnection || !cut.Delivered {
t.Fatalf("the evidence must be the attempt's own, not a re-labelled cancellation: %+v", cut)
}
}
// TestDeliveryEvidenceIsWhatTheMoneyBitAsks is the DIRECT table over the money bit, and it is here
// because the end-to-end fixture below cannot be the only carrier: that one depends on what net/http's
// write loop and read loop do relative to each other, and an acceptance probe of 40 iterations showed the
// subject arriving 39 times and a full 401 once — so the pin red by LUCK and the mutant survived on the
// fortieth. This one answers the same question with no race in it at all.
//
// The wants are written as LITERALS rather than computed from the expression, because a table that
// re-derives the formula it is checking agrees with any formula. All EIGHT combinations of the three bits
// are present: the first version of this table had a duplicate instead of the eighth, which looks like
// coverage and is not.
func TestDeliveryEvidenceIsWhatTheMoneyBitAsks(t *testing.T) {
for _, tc := range []struct {
name string
wrote, firstByte, answered bool
want bool
why string
}{
{name: "our bytes left for the peer", wrote: true, want: true,
why: "the request was written: the provider has it, whatever it does next"},
{name: "our bytes left and a reply came back", wrote: true, firstByte: true, answered: true, want: true},
{name: "an early 2xx overtook our own write callback", firstByte: true, answered: true, want: true,
why: "net/http returns a response as soon as the response channel fires, while WroteRequest runs on the write loop — a provider answering while the body still drains is delivery, and read as «not delivered» it was re-asked three times"},
{name: "a refusal reset the connection while we were still writing", firstByte: true, want: false,
why: "THE MONEY BIT: 401/403/413 plus an RST gives a response BYTE and a write error, so Do returns the write failure and the status line is never in our hands. Taking the byte alone as proof paid for 22 refusals in 25, one of them $0.80"},
{name: "a reply object with no byte recorded", answered: true, want: false,
why: "a state the transport does not produce — a reply implies its first byte — and the bit must not invent delivery out of the half it cannot have alone"},
{name: "nothing left and nothing came back", want: false},
{name: "a byte came back, no reply, and the write did finish", wrote: true, firstByte: true, want: true,
why: "the write is sufficient by itself; this row is what keeps the `answered` half from being read as a REQUIREMENT"},
{name: "the write finished and a reply came back with no byte recorded", wrote: true, answered: true, want: true,
why: "the eighth combination, for completeness: the write alone already decides it, so no reading of the `answered` half can take delivery away"},
} {
t.Run(tc.name, func(t *testing.T) {
var tr deliveryTrace
tr.wrote.Store(tc.wrote)
tr.firstByte.Store(tc.firstByte)
if got := tr.delivered(tc.answered); got != tc.want {
t.Fatalf("delivered(answered=%v) with wrote=%v first_byte=%v = %v, want %v — %s",
tc.answered, tc.wrote, tc.firstByte, got, tc.want, tc.why)
}
})
}
}
// TestARefusalIsNotAPurchaseEvenWhenTheReplyOutrunsTheWrite is the regression the FIX for the early-200
// leak introduced, and it is the more expensive of the two directions.
//
// A provider that REFUSES — 401, 403, 413, a quota 429 — and drops the connection while our request body
// is still writing gives GotFirstResponseByte=true and a WRITE error. http.Client.Do then returns the
// write failure, so the status line is never in our hands and the branch that reads it is never reached.
// Taking the response byte alone as proof of delivery paid an estimate for every one of those: measured
// at 22 refusals in 25, one of them $0.80 booked for a request the provider declined — and the
// delivered-cut retry sent the whole body to it a second time.
//
// ⛔ THE FIXTURE NOW MAKES THE SUBJECT NEARLY CERTAIN INSTEAD OF A COIN TOSS, and the old one is why. It
// sent a COMPLETE 401 and raced the client's read against its own reset: the acceptance probe got the
// subject 39 times in 40 and a fully-read 401 once, and on that fortieth run the test passed while asking
// about something else entirely — `delivered` was never consulted, because a parsed status goes down the
// status branch. Two things changed. A header block that is never COMPLETED cannot become a status line at
// all, so no run of this fixture can take that branch; and the server never drains the body, so a huge one
// cannot finish writing however fast the machine is.
//
// ⚠ WHAT IS STILL A WINDOW, NAMED RATHER THAN CLAIMED AWAY: the 200 ms between the partial reply and the
// reset is what gives the client's read loop time to see the byte. It is wide — that loop has nothing else
// to do — but a host that starves it for a fifth of a second would leave the trace without its first byte,
// and THEN this case is about a socket that said nothing instead. The deterministic death of the mutant
// lives in the table above, which has no timing in it at all; this case is what proves the wire can
// produce the state the table describes.
//
// The two cases are one fixture on purpose. The second is the CONTROL for the first: it proves this
// server's partial reply really does reach the client's trace as a first byte, which is the premise the
// first case cannot observe from outside (the trace is the transport's own).
func TestARefusalIsNotAPurchaseEvenWhenTheReplyOutrunsTheWrite(t *testing.T) {
var conns atomic.Int64
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer ln.Close()
go func() {
for {
c, aerr := ln.Accept()
if aerr != nil {
return
}
conns.Add(1)
go func(c net.Conn) {
// Read the request LINE and nothing else: with the body never drained, a large one fills
// the socket buffers and the client's write blocks until the reset below.
br := bufio.NewReader(c)
if _, rerr := br.ReadString('\n'); rerr != nil {
c.Close()
return
}
// A refusal whose header block never ends. The client gets a response BYTE it can never
// turn into a status line — «the status was never in our hands», as a certainty.
fmt.Fprint(c, "HTTP/1.1 401 Unau")
// Long enough that the client's reader — which has nothing else to do — has consumed those
// bytes before the reset discards them.
time.Sleep(200 * time.Millisecond)
if tc, ok := c.(*net.TCPConn); ok {
_ = tc.SetLinger(0) // RST rather than a graceful close: the pending write FAILS
}
c.Close()
}(c)
}
}()
addr := "http://" + ln.Addr().String()
t.Run("the body was still writing when the refusal arrived", func(t *testing.T) {
conns.Store(0)
huge := strings.Repeat("длинный исходный текст главы. ", 200000) // ~11 MB, and the server never reads it
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: addr, Profile: cutProfile(2 * time.Second)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: huge}}, MaxTokens: 16})
if err == nil {
t.Fatal("a refused request must not report success")
}
// ⛔ THE PREMISE, ASSERTED AND PRINTED — the half this pin used to leave to chance. A status line
// in the error means the client READ a whole reply, which is the other subject: the money bit is
// never consulted there, and a pass would be a pass about nothing.
attempts := conns.Load()
t.Logf("premise: the provider was connected to %d time(s) and the call failed with: %v", attempts, err)
if strings.Contains(err.Error(), "401") || strings.Contains(err.Error(), "status") {
t.Fatalf("the client came back with a STATUS, so this run never reached the delivery question: %v", err)
}
// Every attempt must have hit the same wall, or the verdict below is about whichever one the error
// came from: nothing was bought, so the whole retry budget is spent (cutProfile's MaxAttempts).
if attempts != 3 {
t.Fatalf("the provider was connected to %d time(s), want 3: a call that bought nothing is retried to the end of the budget, and a different number means the attempts did not all reach this wall", attempts)
}
var cut *AttemptCutError
if errors.As(err, &cut) {
t.Fatalf("the provider REFUSED this request and generated nothing; booking an estimate for it "+
"charges a reader for a call that never ran, and the delivered-cut retry sends the whole body "+
"again. got %+v", cut)
}
})
t.Run("the body got out before the refusal arrived", func(t *testing.T) {
conns.Store(0)
// A small body fits in the socket buffers, so the write COMPLETES even though nobody reads it.
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: addr, Profile: cutProfile(2 * time.Second)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "короткий текст"}}, MaxTokens: 16})
if err == nil {
t.Fatal("a reset connection must not report success")
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("a request that WAS written is delivered, and the cut is what carries that fact: %v", err)
}
t.Logf("the control: delivered=%v after_headers=%v billable=%v cause=%s connections=%d",
cut.Delivered, cut.AfterHeaders, cut.Billable, cut.Cause, conns.Load())
// THE CONTROL ITSELF: the partial reply reached the client's trace. That is the premise the case
// above stands on and cannot see, and it is asserted here where a cut exists to carry it.
if !cut.AfterHeaders {
t.Fatal("this fixture's partial reply never reached the client's trace, so the case above was not about a response byte at all — it was about a socket that said nothing")
}
// And the money: a first byte with no 2xx in hand is NOT a purchase, written or not.
if cut.Billable {
t.Fatalf("a refusal the client could not even parse was booked as billable: %+v", cut)
}
})
}
// TestARedirectIsNotADelivery: `Do` spans the WHOLE redirect chain and the delivery trace does not reset
// between its legs, so the first leg reaching a redirector sets WroteRequest for good — and a second leg
// whose connect is REFUSED still looked delivered. Measured through the ledger before the fix:
// $0.001056 booked for a `connect: connection refused` that never put a byte on any wire.
//
// The client now stops at the 3xx instead of chasing it, so a provider endpoint that redirects fails
// loud with its status rather than quietly costing money at the other end of the hop.
func TestARedirectIsNotADelivery(t *testing.T) {
// ⛔ EVERY CLIENT THIS PACKAGE BUILDS, and not just the cloud one. The guard first went only on
// keepAliveHTTPClient, and a mutation that removed it from the LOCAL client SURVIVED: this fixture
// exercised the cloud path alone, so a hole in the other constructor was invisible. They share
// attempt() and they share the delivery trace, so they must share the policy.
clients := map[string]func(base string) LLMClient{
"cloud": func(base string) LLMClient {
return NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: base, Profile: cutProfile(2 * time.Second)}, nil)
},
"local": func(base string) LLMClient {
return NewLocalClient(LocalConfig{BaseURL: base, Model: "m", Profile: cutProfile(2 * time.Second)}, nil)
},
// The third, and it was missing while the comment above already said «every». It is a deprecated
// adapter with no live provider, but it builds its own client, it sends `x-api-key`, and
// net/http strips only Authorization across a host change — so its redirect carried the key to
// the target. A fixture that says «every» and builds two of three is the shape of green that
// let the local client keep following redirects.
"anthropic": func(base string) LLMClient {
return NewAnthropicClient(AnthropicConfig{BaseURL: base, APIKey: "k", Profile: cutProfile(2 * time.Second)}, nil)
},
}
for name, build := range clients {
t.Run(name, func(t *testing.T) {
dead, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
target := dead.Addr().String()
dead.Close() // the control: this address refuses connections, so nothing can be delivered there
var hops atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
hops.Add(1)
http.Redirect(w, r, "http://"+target+"/chat/completions", http.StatusTemporaryRedirect)
}))
defer srv.Close()
_, err = build(srv.URL).Complete(context.Background(),
LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
if err == nil {
t.Fatal("a provider endpoint that redirects must fail, not silently follow")
}
var cut *AttemptCutError
if errors.As(err, &cut) {
t.Fatalf("nothing was delivered anywhere: the redirector answered and the target refuses "+
"connections, so booking money for this charges a reader for a call no endpoint "+
"received. got %+v", cut)
}
// It fails as the status it is — the operator is told the base_url sends them somewhere else.
var hse *HTTPStatusError
if !errors.As(err, &hse) || hse.Status != http.StatusTemporaryRedirect {
t.Fatalf("the 3xx itself must reach the operator, got %T %v", err, err)
}
if n := hops.Load(); n == 0 {
t.Fatalf("the redirector was never asked — this fixture measured nothing (hops=%d)", n)
}
})
}
}
// TestADeliveredCutSurvivesATerminalStatusLaterInTheChain: only the LAST error used to leave the retry
// loop, so a chain that cut a delivered request and then met a terminal 4xx returned the status alone.
// The runner then read «the request never went out», released the reservation and booked $0 for a
// generation the provider had made — and left the position with no mark either. Reachable in the ordinary
// way: a 400/401/403/413 on the retry after a broken socket.
func TestADeliveredCutSurvivesATerminalStatusLaterInTheChain(t *testing.T) {
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
if calls.Add(1) == 1 {
// First: a delivered request whose socket dies mid-body — retryable, and BILLABLE.
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, `{"id":"x","choices":[`)
w.(http.Flusher).Flush()
hj, ok := w.(http.Hijacker)
if !ok {
t.Error("the fixture needs a hijackable response writer")
return
}
conn, _, herr := hj.Hijack()
if herr != nil {
t.Error(herr)
return
}
conn.Close()
return
}
// Then: a terminal status, which ends the chain and used to erase the first attempt.
w.WriteHeader(http.StatusForbidden)
fmt.Fprint(w, `{"error":"forbidden"}`)
}))
defer srv.Close()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(3 * time.Second)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
if n := calls.Load(); n != 2 {
t.Fatalf("the fixture needs both attempts to happen, got %d — it is measuring a different chain", n)
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("the first attempt was DELIVERED and cut, so it is owed whatever ended the chain "+
"afterwards; losing it books $0 for a generation the provider made and leaves the position "+
"unmarked. got %T %v", err, err)
}
if !cut.Delivered || cut.Cause != CutByConnection {
t.Fatalf("the surviving evidence must be the cut's own: %+v", cut)
}
// And the status that ENDED the chain is still there — a caller must be able to see both.
var hse *HTTPStatusError
if !errors.As(err, &hse) || hse.Status != http.StatusForbidden {
t.Fatalf("the terminal status must also reach the caller, got %T %v", err, err)
}
}
// TestTheKeepalivePairSitsOnTheTransportTheCloudClientBuilds: the h2 keepalive bounds are worth their
// comment only if they sit on the transport the cloud client actually uses, and reading them back is
// the only way to know. tuneHTTP2 is that code path and it hands back what it set; asking
// ConfigureTransports a second time on an already-built client answers an error and no transport, so a
// check written that way asserts nothing at all.
func TestTheKeepalivePairSitsOnTheTransportTheCloudClientBuilds(t *testing.T) {
// The control comes first: both bounds are non-zero, so a build that wired NOTHING cannot pass the
// comparisons below by matching zero against zero.
if h2ReadIdleTimeout <= 0 || h2PingTimeout <= 0 {
t.Fatalf("a zero bound disables the keepalive silently: %s / %s", h2ReadIdleTimeout, h2PingTimeout)
}
// ⛔ THE CLIENT THE ENGINE ACTUALLY BUILDS, not a clone tuned beside it. Asking tuneHTTP2 on a fresh
// transport of the test's own would pass even if keepAliveHTTPClient stopped calling it at all —
// which is the shape the write bound's pin had, and it is why that pin survived its own mutation.
c, h2 := buildCloudClient()
if c == nil || h2 == nil {
t.Fatal("the cloud client could not be configured for h2 — this test measured nothing")
}
if c.Transport == nil {
t.Fatal("the cloud client has no transport at all — the bounds below would be read off nothing")
}
if h2.ReadIdleTimeout != h2ReadIdleTimeout {
t.Fatalf("the read-idle bound is not on the transport: got %s want %s", h2.ReadIdleTimeout, h2ReadIdleTimeout)
}
if h2.PingTimeout != h2PingTimeout {
t.Fatalf("the ping bound is not on the transport: got %s want %s", h2.PingTimeout, h2PingTimeout)
}
}
// billableCut answers 200 and flushes the first bytes of a body, then kills the socket: the provider
// ACKNOWLEDGED the request, so the cut is one we are billed for.
func billableCut(t *testing.T, w http.ResponseWriter) {
t.Helper()
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, `{"id":"x","choices":[`)
w.(http.Flusher).Flush()
hijackKill(t, w)
}
// freeCut kills the socket with no status line at all: the request was delivered, nothing came back, and
// nobody is owed for it.
func freeCut(t *testing.T, w http.ResponseWriter) { t.Helper(); hijackKill(t, w) }
func hijackKill(t *testing.T, w http.ResponseWriter) {
t.Helper()
hj, ok := w.(http.Hijacker)
if !ok {
t.Error("the fixture needs a hijackable response writer")
return
}
conn, _, err := hj.Hijack()
if err != nil {
t.Error(err)
return
}
conn.Close()
}
// TestAPaidCutSurvivesAPlainRetryableLaterInTheChain: a chain can be billed for an attempt that is not
// the attempt whose error ends it. Here the money is on attempt 1 and the chain ends on a 503 — an
// ordinary retryable that owes nobody anything. If the loop returns only what ended it, the engine
// settles $0 for a generation the provider made.
func TestAPaidCutSurvivesAPlainRetryableLaterInTheChain(t *testing.T) {
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
if calls.Add(1) == 1 {
billableCut(t, w)
return
}
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprint(w, `{"error":"busy"}`)
}))
defer srv.Close()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(3 * time.Second)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
if n := calls.Load(); n < 2 {
t.Fatalf("the fixture needs both attempts to happen, got %d — it is measuring a different chain", n)
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("attempt 1 was DELIVERED, ACKNOWLEDGED and cut — the chain owes money for it whatever "+
"ended it later. Returning only the 503 books $0 for a generation the provider made. got %T %v", err, err)
}
if !cut.Billable {
t.Fatalf("the surviving cut must be the BILLABLE one: %+v", cut)
}
}
// TestAFreeCutLaterDoesNotMaskThePaidCutEarlier is the same mismatch one turn harder, and it is the case
// the type test could not see. Both attempts end in a cut, so «the chain already ends carrying one» is
// true — and wrong: the ending cut was never acknowledged and costs nothing, while the earlier one was
// and does. Money, not type, decides which one the caller must be handed.
func TestAFreeCutLaterDoesNotMaskThePaidCutEarlier(t *testing.T) {
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
if calls.Add(1) == 1 {
billableCut(t, w)
return
}
freeCut(t, w)
}))
defer srv.Close()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(3 * time.Second)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
if n := calls.Load(); n < 2 {
t.Fatalf("the fixture needs both attempts to happen, got %d", n)
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("some cut must reach the caller, got %T %v", err, err)
}
if !cut.Billable {
t.Fatalf("the caller settles from ONE error, so it must be the one with the money on it: a later "+
"cut nobody acknowledged erased an earlier one the provider did. got Billable=%t cause=%s",
cut.Billable, cut.Cause)
}
}
// TestTheCancellationExitCarriesWhatTheChainOwes covers the loop's OTHER cancellation exit — the one
// taken right after an attempt rather than during a backoff (that one has its own fixture). A run
// stopped here has a paid cut behind it and an ordinary retryable in front of it, and returning only
// «cancelled + the 503» leaves the runner nothing to settle and the chunk with no mark.
func TestTheCancellationExitCarriesWhatTheChainOwes(t *testing.T) {
var calls atomic.Int32
secondLanded := make(chan struct{})
stopped := make(chan struct{})
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
if calls.Add(1) == 1 {
billableCut(t, w)
return
}
// ⛔ SYNCHRONISED ON THE STOP, NOT ON A CLOCK. The loop checks the context AFTER the attempt
// returns, so the stop has to be in place before this handler answers — and a sleep here would
// make the fixture measure whichever of the two won the race that day.
close(secondLanded)
<-stopped
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprint(w, `{"error":"busy"}`)
}))
defer srv.Close()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go func() {
<-secondLanded
cancel()
close(stopped)
}()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(3 * time.Second)}, nil)
_, err := c.Complete(ctx, LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
if n := calls.Load(); n < 2 {
t.Fatalf("the fixture needs the stop to land on the SECOND attempt, got %d calls", n)
}
if !errors.Is(err, context.Canceled) {
t.Fatalf("a stopped run must still read as cancelled — the exit code depends on it. got %T %v", err, err)
}
var cut *AttemptCutError
if !errors.As(err, &cut) || !cut.Billable {
t.Fatalf("the stop exit must carry the cut the chain owes money for; without it the runner settles "+
"nothing and the position is left unmarked. got %T %v", err, err)
}
}
// TestAPaidCutAfterAFreeOneIsTheOneTheCallerSettlesFrom is the accumulator's own case, and it is the
// order the «first cut wins» rule cannot serve. Attempt 1 is delivered and never acknowledged — nobody
// is owed for it. Attempt 2 IS acknowledged and cut, so it is the one the engine must settle. Keeping
// whichever cut came first hands the caller the free one and books $0 for a generation that was made.
func TestAPaidCutAfterAFreeOneIsTheOneTheCallerSettlesFrom(t *testing.T) {
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
switch calls.Add(1) {
case 1:
freeCut(t, w) // delivered, never acknowledged — costs nothing
case 2:
billableCut(t, w) // acknowledged, then cut — this is the money
default:
w.WriteHeader(http.StatusForbidden) // unreachable under the cap; here so a policy change fails loudly
fmt.Fprint(w, `{"error":"forbidden"}`)
}
}))
defer srv.Close()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(3 * time.Second)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
// TWO attempts, not three: only a connection cut is retryable and the delivered-cut cap makes the
// second one terminal, so the chain ends ON the paid cut. That is the premise this test rests on —
// if a policy change ever lets a third attempt happen, the count says so instead of the assertions
// quietly measuring a different chain.
if n := calls.Load(); n != 2 {
t.Fatalf("the fixture needs exactly two attempts, got %d — it is measuring a different chain", n)
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("a cut must reach the caller, got %T %v", err, err)
}
if !cut.Billable {
t.Fatalf("the chain produced a free cut and then a PAID one; the caller settles from one error, so "+
"it must be the paid one. Keeping whichever came first books $0 for a generation the provider "+
"made. got Billable=%t cause=%s", cut.Billable, cut.Cause)
}
}
// TestResponseBytesWithoutAReplyAreNotAPurchase pins the half of the money predicate that nothing else
// reaches: `answered`. A cut is billable only when the provider ACKNOWLEDGED the request with a reply —
// `Billable = answered && afterHeaders` — and the two halves fail apart. Every other fixture exercises
// the second: no response byte, so both are false and dropping the first changes nothing.
//
// This is the case where they disagree. The peer writes RESPONSE BYTES that are not a reply — a broken
// status line — so the delivery trace's first-byte flag is set while `Do` still fails and no 2xx object
// ever exists. Without `answered &&`, that reads as money owed, and the engine books an estimate for a
// call whose provider answered nothing.
func TestResponseBytesWithoutAReplyAreNotAPurchase(t *testing.T) {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer ln.Close()
go func() {
for {
c, aerr := ln.Accept()
if aerr != nil {
return
}
go func(c net.Conn) {
defer c.Close()
br := bufio.NewReader(c)
if _, rerr := br.ReadString('\n'); rerr != nil {
return
}
// Bytes on the wire, and not a reply: the trace sees a first response byte, the parser
// never sees a status line.
fmt.Fprint(c, "NOT-HTTP garbage from a broken proxy\r\n")
}(c)
}
}()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: "http://" + ln.Addr().String(), Profile: cutProfile(2 * time.Second)}, nil)
_, err = c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
if err == nil {
t.Fatal("a reply that is not a reply must not report success")
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
// Not a failure of the property under test: the request WAS delivered, so it is a cut. If the
// engine ever stops classifying it as one, this fixture is measuring nothing and says so.
t.Fatalf("premise broken: the request was delivered and the peer answered garbage, so this is a "+
"cut. got %T %v", err, err)
}
if !cut.AfterHeaders {
t.Fatalf("premise broken: the fixture must produce a FIRST RESPONSE BYTE, otherwise both halves of "+
"the money predicate are false and this test cannot tell them apart: %+v", cut)
}
if cut.Billable {
t.Fatalf("response BYTES are not a reply. The provider acknowledged nothing, so nobody is owed for "+
"this call; booking it charges a reader for a generation that was never made. %+v", cut)
}
}
// TestTheDeliveryCountCountsDeliveriesNotCuts pins the number the operator reads. The ledger line the
// engine writes beside a cut says «the provider was asked N times; ONE estimate is booked for all of
// them» — it is the only place the gap between what was generated and what was billed becomes visible,
// and it was counting CUTS. A chain that was answered a 503 and then cut delivered twice and reported
// one.
func TestTheDeliveryCountCountsDeliveriesNotCuts(t *testing.T) {
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
if calls.Add(1) == 1 {
w.WriteHeader(http.StatusServiceUnavailable) // delivered: the peer read the request to answer it
fmt.Fprint(w, `{"error":"busy"}`)
return
}
billableCut(t, w)
}))
defer srv.Close()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(3 * time.Second)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
// THREE deliveries: the 503, the cut, and the one retry a delivered cut is worth. The count is the
// premise as well as the subject — if the retry policy ever changes, this says so instead of letting
// the assertion below quietly measure a different chain.
if n := calls.Load(); n != 3 {
t.Fatalf("the fixture needs three attempts — a 503, a cut, and the cut's one retry — got %d", n)
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("premise broken: the chain must end on a cut for the count to be carried anywhere: %T %v", err, err)
}
if cut.Deliveries != 3 {
t.Fatalf("the request reached the provider THREE times — a 503 is an answer, so the peer read it — and "+
"one estimate is booked for both. Counting only the cuts makes the operator's «asked N times» "+
"line understate a mixed chain, which is the one line where that gap is visible. got %d",
cut.Deliveries)
}
}
// TestTheStopExitStillReadsAsCancelledWhenTheAttemptDidNot closes a hole this pack's own pin had, and the
// hole is instructive: the fixture beside it drives the loop through the WIRE, and there a stop lands on
// a request in flight, so the attempt's own error is already a parent-cancelled cut carrying
// context.Canceled. Its «a stopped run must still read as cancelled» assertion was therefore satisfied by
// the cut's Parent no matter what the loop's exit did — and removing the exit's `cancelledDuring`
// survived the whole battery.
//
// The case that has nothing to lean on is the one an operator actually meets: an attempt fails with an
// ORDINARY error — a 503 — and the stop arrives immediately after, before the loop decides to retry.
// Nothing in that error knows about the context, so only the exit can carry the cancellation out; if it
// does not, `tmctl` exits 1 instead of 5 and the stream publishes `failed` where a person pressed stop.
//
// It drives retryLoop directly because the wire cannot produce this ordering on purpose: the window
// between an attempt returning and the loop reading the context is a few instructions wide, and a
// fixture that raced for it would be measuring the scheduler.
func TestTheStopExitStillReadsAsCancelledWhenTheAttemptDidNot(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
plain := &HTTPStatusError{Status: http.StatusServiceUnavailable, Body: "busy"}
calls := 0
_, err := retryLoop(ctx, cutProfile(time.Second), "p", nil, func() (*openAIResponse, bool, error) {
calls++
cancel() // the stop lands while this attempt is returning, not while it is in flight
return nil, true, plain
})
if calls != 1 {
t.Fatalf("premise broken: the loop must take the stop exit on the FIRST attempt, got %d calls", calls)
}
if !errors.Is(err, context.Canceled) {
t.Fatalf("a stopped run must read as cancelled even when the attempt that was in flight failed of "+
"its own accord: the exit code (5, not 1) and the `stopped` the stream publishes both hang off "+
"this. The attempt's error knows nothing about the context, so only this exit can carry it. got %T %v",
err, err)
}
// The control: the attempt's own error must ALSO survive, or the exit would be trading one truth for
// the other — the operator needs to know a 503 is why the engine was retrying when the stop arrived.
if !errors.Is(err, plain) {
t.Fatalf("the attempt's own error must reach the caller beside the cancellation: %T %v", err, err)
}
}
// TestTheVendorsPublishedPairIsWhatTheVendorPublishes pins the two numbers every derived deadline is
// built from, and it exists because the formula test beside it cannot: both of its sides read these same
// constants, so corrupting them moves the expectation with the result and the identity still holds.
// Measured on a copy: `vendorHourlyTokenBudget` quadrupled, and `internal/llm`, `internal/config` and the
// rest of the battery all stayed green.
//
// The direction is money and it is this pack's own subject. A budget four times too generous makes every
// derived deadline four times too SHORT, so calls the provider is still generating are cut by us — and
// since this pack, a self-cut that the provider acknowledged is PAID FOR. Five of the eight catalogued
// providers run on this default.
//
// ⚠ THESE ARE SOURCE NUMBERS, NOT PRODUCTS, which is why quoting them here does not violate
// TestTheDeadlineTestQuotesNoDeadline: that gate bans the DERIVED seconds, because a pin on a number the
// formula produced is a pin on nothing. A citation of the vendor's published pair is the opposite — it is
// the one place the arithmetic touches the outside world, and it belongs written down.
func TestTheVendorsPublishedPairIsWhatTheVendorPublishes(t *testing.T) {
// anthropic-sdk-go's CalculateNonStreamingTimeout budgets one hour per 128 000 output tokens. That
// pair is the vendor's, not ours: changing either is adopting a different vendor's arithmetic, and it
// must be a decision someone makes on purpose rather than an edit nothing notices.
if vendorHourlyTokenBudget != 128000 {
t.Fatalf("the vendor's published token budget is 128000 per window; this build says %d. Every "+
"provider without its own measured floor derives its deadline from this number, and a budget "+
"too generous makes the deadline too SHORT — cutting calls the provider is still generating, "+
"which this pack now charges for", vendorHourlyTokenBudget)
}
if vendorBudgetWindow != time.Hour {
t.Fatalf("the vendor's published window is one hour; this build says %s", vendorBudgetWindow)
}
// The control: the pair is actually what the derivation uses, not two constants sitting beside it.
// Without this the assertions above would hold on a build that derived from something else entirely.
if got := (RetryProfile{}).deriveDeadline(vendorHourlyTokenBudget); got != vendorBudgetWindow {
t.Fatalf("a grant of exactly the vendor's hourly budget must derive to exactly its window — that "+
"identity is what makes the two constants above the SOURCE of the derivation rather than "+
"decoration beside it. got %s, want %s", got, vendorBudgetWindow)
}
}
// TestAnOlderCutCarriesTheChainsFinalDeliveryCount is the count's other half, and the one a chain that
// ends on a cut cannot show. Here the money is on attempt 1 and the chain goes on WITHOUT cutting again:
// two 503s, then exhaustion. `chainError` hands up attempt 1's cut because it is the one that owes — and
// the number stamped on it when it was born knows about one delivery out of three.
//
// Nothing in the error tree can repair that: the later deliveries were answers, not cuts, so no cut in
// the tree has ever seen them. Only the chain's own counter has.
func TestAnOlderCutCarriesTheChainsFinalDeliveryCount(t *testing.T) {
var calls atomic.Int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
if calls.Add(1) == 1 {
billableCut(t, w)
return
}
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprint(w, `{"error":"busy"}`)
}))
defer srv.Close()
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: srv.URL, Profile: cutProfile(3 * time.Second)}, nil)
_, err := c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: "u"}}, MaxTokens: 16})
// The premise is the shape, not just the count: a cut FIRST, then deliveries that are not cuts.
if n := calls.Load(); n != 3 {
t.Fatalf("the fixture needs a cut and then two plain answers, got %d attempts", n)
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("premise broken: the chain owes money for attempt 1 and must hand that cut up: %T %v", err, err)
}
if cut.Deliveries != 3 {
t.Fatalf("the provider was asked THREE times and one estimate covers all of them; the cut handed "+
"up was born on attempt 1 and reports %d. The later deliveries were answers, not cuts, so no "+
"cut in the error tree has ever seen them — only the chain's counter has, and the ledger line "+
"built from this number under-states the gap it exists to show", cut.Deliveries)
}
}
// TestAnUndeliveredAttemptIsNotCountedAsAsking pins the predicate the count rests on. Every other
// fixture here tells deliveries apart from CUTS; none tells them apart from ATTEMPTS, because none has
// an attempt that never reached the provider. So `askedToGenerate++` made unconditional survived
// everything: the number would say the provider was asked twice when it was asked once, in the one line
// where the generated-versus-billed gap is published.
func TestAnUndeliveredAttemptIsNotCountedAsAsking(t *testing.T) {
var conns atomic.Int32
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer ln.Close()
go func() {
for {
c, aerr := ln.Accept()
if aerr != nil {
return
}
go func(c net.Conn) {
defer c.Close()
if conns.Add(1) == 1 {
// The first attempt never reaches the provider: accepted and dropped WITHOUT reading,
// so the huge body's write fails partway and nothing was asked of anybody. A reset
// instead of this plain close would let the body land in the socket buffer first, and
// the trace would then be right to call it delivered — which is a different case.
return
}
// The second DOES reach it: the whole request is READ before anything is answered, so
// the client's write completes and the delivery trace says so. Answering early — the
// shape of the branch above — would make this attempt a failed write too, and the
// fixture would then be comparing two undelivered attempts.
br := bufio.NewReader(c)
req, rerr := http.ReadRequest(br)
if rerr != nil {
return
}
_, _ = io.Copy(io.Discard, req.Body)
req.Body.Close()
// Acknowledged, and then cut: one delivery, and money.
fmt.Fprint(c, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n{\"id\":\"x\",\"choices\":[")
if tc, ok := c.(*net.TCPConn); ok {
_ = tc.SetLinger(0)
}
}(c)
}
}()
huge := strings.Repeat("длинный исходный текст главы. ", 200000)
c := NewOpenAICompatClient(OpenAICompatConfig{Name: "p", BaseURL: "http://" + ln.Addr().String(), Profile: cutProfile(3 * time.Second)}, nil)
_, err = c.Complete(context.Background(), LLMRequest{Model: "m", Messages: []Message{{Role: "user", Content: huge}}, MaxTokens: 16})
// THREE attempts, TWO deliveries: the first never leaves, the second is delivered and cut, and a
// delivered cut is worth one retry — which delivers again and hits the cap. The count is the premise
// as well as the subject: if the retry policy moves, this says so instead of the assertion below
// quietly measuring a different chain.
if n := conns.Load(); n != 3 {
t.Fatalf("the fixture needs three attempts — one that never delivers, then a cut and its one "+
"retry — got %d", n)
}
var cut *AttemptCutError
if !errors.As(err, &cut) {
t.Fatalf("premise broken: the chain must end on the delivered attempt's cut: %T %v", err, err)
}
if cut.Deliveries != 2 {
t.Fatalf("the provider was asked TWICE across three attempts: the first request never left, so "+
"nobody was asked and nobody generated. Counting it says the engine bought three generations "+
"where it bought two, in the one line where that gap is published. got %d", cut.Deliveries)
}
}