SIGN IN SIGN UP

fix(claude): send Anthropic header names with the real client's casing

CPA negotiates ALPN http/1.1 with Anthropic, so header names are not lowercased
by HPACK and reach the server verbatim. The casing is therefore part of the
fingerprint, and six of the eighteen names CPA emits were wrong because Go
canonicalises everything passed through Header.Set: anthropic-beta,
anthropic-dangerous-direct-browser-access, anthropic-version, x-app,
x-client-request-id and X-Stainless-OS. Writing the map keys directly is the
only way to keep the original casing.

This also fixes ordering at no extra cost. Go sorts header names bytewise when
it serialises a request, and the captured order of the real client is exactly
that same bytewise sort. Host, User-Agent and Content-Length stay misplaced
because Go writes them ahead of the sorted block; a test records that gap and
will fail if it ever closes.

The pass runs at the send boundary rather than inside applyClaudeHeaders: the
rewritten keys are unreachable through Header.Get, and doing it earlier hid
these headers from the rest of the pipeline. The boundary is a single
doClaudeUpstreamRequest helper pinned by a structural test, after a mutation
check showed that dropping the call from the streaming path alone was otherwise
undetectable. Expected order is pinned by serialising the request and reading
the header lines back, not by inspecting the header map.
S
sususu committed
a20626f1eee946c0344d3692f7c3465619f1c410
Parent: 6912a74