Repository navigation
gateway: close the full mutation run's last survivors; client cut mid-upload is not billed (D259) - #121
Merged
Conversation
…s survivors (D259)
59 survivors of the full beyond-ai suite (triage3: proxy 25, usage 10, translate 4, peek 2,
route 2; triage4: proxy 3, translate 7, peek 2, usage 4). Every kill verified by hand-applying the
mutant and running the targeted test.
Bug (D259): a client that closed mid-upload (a Content-Length body with bytes still to come, a
chunked body without its last chunk) was billed an input estimate as if the provider had the
whole request. Pingora marks such a body done (is_body_done), so body_delivered read the half the
provider was sent as delivered and logging's no_head path estimated it. body_delivered now also
rejects a downstream premature-close error (client_body_cut_short, pingora's context string, as
h2_body_unsent does). Found while killing the error_while_proxy Downstream mutant.
Real gaps (new tests):
- Admission: a declared /{provider} body past the budget is refused before a byte is read; a BYO
request takes no tenant slot; a body of exactly MAX_REQUEST_BODY streams through.
- Headers: anthropic-version is added only to a translated walk, never to a Messages relay; a
translated and a signed JSON answer are chunked to an HTTP/1.1 client.
- error_while_proxy: a reset before a small body is sent fails over (header-won walk); a client
that resets mid-upload is not failed over; a read timeout on a reused connection is not resent.
- Billing: an error event after output is billed an estimate.
- Large bodies: a FullBody re-run skips an unserved candidate (PDF on grok-build-0.1).
- Units: route first_key with 2 and 3 keys, the key cooldown expires, InputTally's two-chain cut
on long plain runs, the bounded Anthropic usage head, OaiToResp reasoning items (index change,
text after a signature, a whole signed thinking block, one summary part per item), a tool call
opened with its arguments, str_value decodes an escaped value.
Dead or simplified: scan_buffered's ':' and '-' depth guards (now as unguarded as the two walks it
replaces; the ':' guard diverged from them on invalid JSON, pinned by two corpus cases);
InputTally::text's aux guards; TALLY's PUNCT1 / DIGITS3 arms (same as the default arm);
map_request's a == b arm (already gone); the request buffer's pre-size now reads
RequestCtx::rewrites_body after the context is built; tracks_terminal and keep_usage_head
helpers; find_event_end accepts any blank line (a \n then \r\n blank line too, as SSE allows), so
its look-behind is gone; de_service_tier's visit_some (serde_json's deserialize_any never calls it).
Equivalent, excluded with reasons: MAX_CATALOG_OUTPUT_TOKENS's > vs >=, KEY_NODES' 1 + n vs 1 * n,
InputTally::run's cut gate, tracks_terminal widened, keep_usage_head widened, the FullBody
unserved guard (true; pinned by a catalog invariant test), str_value's raw fast path (false),
de_service_tier's expecting.
Already handled before this pass: tally_eager (now its own fn, excluded), the >= on the replay
buffer (past_replay_buffer, verified killed), de_service_tier's visit_none / visit_u64 (excluded),
the FullBody reset mask's << (killed by claims_reliability).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk
…imate) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The final batch of the full cargo-mutants run over gateway core (usage, translate, proxy, peek, circuit_breaker, route): 59 full-suite survivors (43 from the 329-survivor re-test, 16 from shard 27 and the mutants a load-flaky replica test had falsely "caught").
exclude_re(each checked with--list)Every kill verified by applying the mutant and watching the targeted test fail.
Bug (D259, low, billing): a managed client that closed mid-upload was billed an input estimate — pingora marks a prematurely closed body done, so
body_deliveredsaw it as delivered. Newclient_body_cut_shortrejects pingora's premature-close errors. Test:cut_short::a_client_that_closes_mid_upload_is_not_billed_an_estimate(Content-Length and chunked).Behaviour changes from simplification:
scan_buffereddrops its:depth guard to agree with the two scanners it replaced (differed only on invalid JSON; corpus cases pin it);find_event_endaccepts\n\r\nas an event end, as the SSE spec allows.Notable new coverage:
/{provider}body over budget refused before reading;anthropic-versiononly on translated walks;error_while_proxyfailover/no-failover on resets and reused-connection timeouts; error-after-output still billed an estimate; large-body re-run skips an unserved candidate; Chat→Responses reasoning items.Known gap (not fixed): a client that stalls mid-upload is still failed over when the upstream read timeout fires.
🤖 Generated with Claude Code
https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk