Files
pxpipe/tests
teamchong e27c19c2a3 feat(transform): live-α charsPerToken closes not_profitable max-savings leak
The break-even gate (isCompressionProfitable) used a hard-coded
CHARS_PER_TOKEN=4 (Anthropic's English avg). Live Claude Code traffic
has α≈0.5-0.9 (1.1-2 chars/tok) — JSON-dense tool docs, structured
CLAUDE.md slabs, etc. Off-by ~3.5× on the text side at α=0.88.

Production trace (events.jsonl, 2026-05-19): 200+ requests with system
slabs 113K-170K chars hit reason="not_profitable" because the gate's
textTokensEq = len/4 was a fraction of the row-aware image-token cost.
Example event: slab=169_632 chars, cache_create_tokens=148_891. Gate's
textEq=42K rejected vs imgCost=127K. With live α (1.14 ch/tok),
textEq=149K → ACCEPT. We were leaving real cache_create money on the
table on every one of those calls.

- TransformOptions gains charsPerToken?: number. Default 4 (back-compat).
- isCompressionProfitable() takes charsPerToken as a 5th optional param;
  defensive clamp on ≤0 / NaN / Infinity falls back to CHARS_PER_TOKEN.
- All 4 internal gate call sites (static slab + reminder + tool_result
  string + tool_result array) thread o.charsPerToken through.
- ProxyConfig.transform now also accepts a function: () => TransformOptions.
  Resolved per-request inside createProxy so the host can inject dynamic
  values. Static-object form unchanged for Workers / tests.
- node.ts wraps the static transform options in a closure that asks
  dashboardState.fitCosts() each request and passes the live
  chars_per_token. Fit-null falls through to the baked-in default — no
  chicken-and-egg deadlock since normal-sized slabs still feed the fit
  ring even before the huge-slab cases get unblocked.
- 4 new gate tests: stale-default rejects the 170K newline-heavy slab;
  live α=1.14 flips the same slab to profitable; defensive clamp on
  bogus charsPerToken; end-to-end transformRequest passes through.

Tests: 269 → 273 (+4). Typecheck + build clean.
2026-05-19 14:56:30 -04:00
..