From 5dbce4f3fbfd5ed1d83b59dc7b972ed17ce27e7e Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Sat, 3 Oct 2026 10:48:07 +0800 Subject: [PATCH] perf(claude): prefilter JSON payloads before diagnostic walks - Add ASCII pre-filter to skip expensive gjson traversals for title helper and 1h TTL checks - Check raw bytes for target keywords before initiating full JSON walks - Fall back to full inspection when printable ASCII Unicode escapes are detected Closes: #6291 --- .../executor/helps/claude_diagnostics.go | 10 +- .../executor/helps/claude_json_prefilter.go | 50 ++++++ .../helps/claude_json_prefilter_fuzz_test.go | 147 ++++++++++++++++++ .../helps/claude_json_prefilter_test.go | 137 ++++++++++++++++ 4 files changed, 343 insertions(+), 1 deletion(-) create mode 100644 internal/runtime/executor/helps/claude_json_prefilter.go create mode 100644 internal/runtime/executor/helps/claude_json_prefilter_fuzz_test.go create mode 100644 internal/runtime/executor/helps/claude_json_prefilter_test.go diff --git a/internal/runtime/executor/helps/claude_diagnostics.go b/internal/runtime/executor/helps/claude_diagnostics.go index 3c83b9733..c43fe6cfe 100644 --- a/internal/runtime/executor/helps/claude_diagnostics.go +++ b/internal/runtime/executor/helps/claude_diagnostics.go @@ -441,6 +441,12 @@ func isClaudeTitleHelperInstruction(body []byte) bool { } func isClaudeTitleHelperRequest(body []byte) bool { + // Without an output_config key the request is a helper only if one of the + // system title instructions below appears, so skip the walks when none can. + if !jsonMayContainASCII(body, "output_config", "naming a coding session", "Return a short title", + "Write the title in the predominant language") { + return false + } props := gjson.GetBytes(body, "output_config.format.schema.properties") if props.Exists() { if props.Get("title").Exists() && len(props.Map()) == 1 { @@ -527,7 +533,9 @@ func IsClaudeSubagentRequest(headers http.Header, body []byte) bool { // ClaudePayloadHas1hTTL reports whether the request payload contains any cache_control // block with ttl set to "1h". func ClaudePayloadHas1hTTL(payload []byte) bool { - if len(payload) == 0 || !gjson.ValidBytes(payload) { + // A ttl of "1h" is the JSON string "1h"; its quotes are structural and never + // escaped, so a payload without that token cannot match. + if len(payload) == 0 || !jsonMayContainASCII(payload, `"1h"`) || !gjson.ValidBytes(payload) { return false } has1h := false diff --git a/internal/runtime/executor/helps/claude_json_prefilter.go b/internal/runtime/executor/helps/claude_json_prefilter.go new file mode 100644 index 000000000..32509c7d9 --- /dev/null +++ b/internal/runtime/executor/helps/claude_json_prefilter.go @@ -0,0 +1,50 @@ +package helps + +import "bytes" + +// jsonMayContainASCII reports whether decoding the JSON document body could +// yield a key or string value containing any of needles. +// +// It lets the request classifiers below skip their gjson walks: a Claude Code +// request body carries the whole conversation (often several MB), and each +// walk re-scans it. bytes.Contains is far cheaper than a gjson walk. +// +// Every needle must be printable ASCII without '\\' or '/' (JSON may spell +// '/' as `\/`). A '"' may only stand at +// either end of a needle, where it matches a structural string delimiter +// (`"1h"` matches the whole string value 1h). JSON can only +// spell such a character as itself or as a \u00XX escape, so when body holds +// no \u escape of a printable ASCII character, a needle that is absent from +// the raw bytes is absent from every decoded string too. If such an escape is +// present the function answers true and the caller falls back to its full +// walk, so the result never changes, only the cost. +func jsonMayContainASCII(body []byte, needles ...string) bool { + if hasPrintableASCIIUnicodeEscape(body) { + return true + } + for _, needle := range needles { + if bytes.Contains(body, []byte(needle)) { + return true + } + } + return false +} + +// hasPrintableASCIIUnicodeEscape reports whether body contains a \u00XX +// escape whose first hex digit is 2-7, i.e. a printable ASCII character. It +// errs only toward "yes": it also matches DEL (7F), malformed escapes such as +// a 2-7 digit followed by a non-hex character, an escape truncated after that +// digit, and an escaped backslash followed by literal text such as `\\u0041`. +// Each of those only makes the caller fall back to a full walk. +func hasPrintableASCIIUnicodeEscape(body []byte) bool { + for rest := body; ; { + i := bytes.Index(rest, []byte(`\u00`)) + if i < 0 || i+4 >= len(rest) { + return false + } + if c := rest[i+4]; c >= '2' && c <= '7' { + return true + } + rest = rest[i+4:] + } +} diff --git a/internal/runtime/executor/helps/claude_json_prefilter_fuzz_test.go b/internal/runtime/executor/helps/claude_json_prefilter_fuzz_test.go new file mode 100644 index 000000000..295e1e07d --- /dev/null +++ b/internal/runtime/executor/helps/claude_json_prefilter_fuzz_test.go @@ -0,0 +1,147 @@ +package helps + +import ( + "strings" + "testing" + + "github.com/tidwall/gjson" +) + +// referenceIsClaudeTitleHelperRequest is isClaudeTitleHelperRequest without +// the jsonMayContainASCII pre-filter (the v8.0.11 implementation). +func referenceIsClaudeTitleHelperRequest(body []byte) bool { + props := gjson.GetBytes(body, "output_config.format.schema.properties") + if props.Exists() { + if props.Get("title").Exists() && len(props.Map()) == 1 { + return isClaudeTitleHelperInstruction(body) + } + return false + } + matchesSystemTitleInstruction := func(t string) bool { + return strings.Contains(t, "naming a coding session") || + strings.Contains(t, "Return a short title") || + strings.Contains(t, "Write the title in the predominant language") + } + system := gjson.GetBytes(body, "system") + if system.IsArray() { + for _, part := range system.Array() { + if matchesSystemTitleInstruction(part.Get("text").String()) { + return true + } + } + } else if matchesSystemTitleInstruction(system.String()) { + return true + } + messages := gjson.GetBytes(body, "messages") + if messages.IsArray() { + for _, msg := range messages.Array() { + if msg.Get("role").String() == "system" { + content := msg.Get("content") + if content.IsArray() { + for _, part := range content.Array() { + if matchesSystemTitleInstruction(part.Get("text").String()) { + return true + } + } + } else if matchesSystemTitleInstruction(content.String()) { + return true + } + } + } + } + return false +} + +// referenceClaudePayloadHas1hTTL is ClaudePayloadHas1hTTL without the +// jsonMayContainASCII pre-filter (the v8.0.11 implementation). +func referenceClaudePayloadHas1hTTL(payload []byte) bool { + if len(payload) == 0 || !gjson.ValidBytes(payload) { + return false + } + has1h := false + checkBlock := func(item gjson.Result) bool { + cc := item.Get("cache_control") + if cc.IsObject() && cc.Get("ttl").String() == "1h" { + has1h = true + return false + } + return true + } + for _, key := range []string{"tools", "system"} { + if arr := gjson.GetBytes(payload, key); arr.IsArray() { + arr.ForEach(func(_, item gjson.Result) bool { + return checkBlock(item) + }) + if has1h { + return true + } + } + } + if messages := gjson.GetBytes(payload, "messages"); messages.IsArray() { + messages.ForEach(func(_, msg gjson.Result) bool { + content := msg.Get("content") + if content.IsArray() { + content.ForEach(func(_, item gjson.Result) bool { + return checkBlock(item) + }) + } + return !has1h + }) + } + return has1h +} + +// bs is one backslash; the seeds below build JSON escapes from it. +const bs = `\` + +var prefilterSeeds = []string{ + ``, + `{}`, + `not json`, + `{"system":"naming a coding session"}`, + `{"system":"naming a` + bs + `u0020coding session"}`, + `{"system":[{"text":"Return a short ` + bs + `u0074itle"}]}`, + `{"system":"Return a short title`, + `{"messages":[{"role":"system","content":[{"text":"Write the title in the predominant language"}]}]}`, + `{"messages":[{"role":"system","content":"naming a coding session"}`, + `{"output_config":{"format":{"schema":{"properties":{"title":{}}}}},"messages":[{"content":""}]}`, + `{"output_` + bs + `u0063onfig":{"format":{"schema":{"properties":{"title":{}}}}},"system":"Return a short title"}`, + `{"output_config":{"format":{"schema":{"properties":{"title":{},"x":{}}}}}}`, + `{"system":"` + bs + `ud83d` + bs + `ude00 naming a coding session"}`, + `{"system":"` + bs + `/naming a coding session` + bs + `"}`, + `{"system":"` + bs + bs + `u0041 naming"}`, + `{"system":"` + bs + `u00`, + `{"messages":[{"content":[{"cache_control":{"ttl":"1h"}}]}]}`, + `{"messages":[{"content":[{"cache_control":{"ttl":"` + bs + `u0031h"}}]}]}`, + `{"tools":[{"cache_control":{"ttl":"1` + bs + `u0068"}}]}`, + `{"system":[{"cache_control":{"ttl":"5m"}}],"note":"1h"}`, + `{"tools":[{"cache_control":{"ttl":"1h"}}]}`, + `{"messages":[{"content":[{"cache_control":{"ttl":1}}]}]}`, +} + +func checkPrefilterEquivalence(t *testing.T, body []byte) { + t.Helper() + if got, want := isClaudeTitleHelperRequest(body), referenceIsClaudeTitleHelperRequest(body); got != want { + t.Fatalf("isClaudeTitleHelperRequest(%q) = %v, reference %v", body, got, want) + } + if got, want := ClaudePayloadHas1hTTL(body), referenceClaudePayloadHas1hTTL(body); got != want { + t.Fatalf("ClaudePayloadHas1hTTL(%q) = %v, reference %v", body, got, want) + } +} + +func TestPrefilterMatchesReferenceOnSeeds(t *testing.T) { + for _, seed := range prefilterSeeds { + checkPrefilterEquivalence(t, []byte(seed)) + } +} + +// FuzzPrefilterMatchesReference checks the pre-filtered classifiers against +// the full walks on arbitrary bytes: go test -fuzz FuzzPrefilterMatchesReference +func FuzzPrefilterMatchesReference(f *testing.F) { + for _, seed := range prefilterSeeds { + f.Add([]byte(seed)) + } + f.Fuzz(func(t *testing.T, body []byte) { + checkPrefilterEquivalence(t, body) + }) +} diff --git a/internal/runtime/executor/helps/claude_json_prefilter_test.go b/internal/runtime/executor/helps/claude_json_prefilter_test.go new file mode 100644 index 000000000..d85e88724 --- /dev/null +++ b/internal/runtime/executor/helps/claude_json_prefilter_test.go @@ -0,0 +1,137 @@ +package helps + +import ( + "fmt" + "strings" + "testing" +) + +func TestJSONMayContainASCII(t *testing.T) { + tests := []struct { + name string + body string + needles []string + want bool + }{ + {"absent", `{"system":"hello"}`, []string{"naming a coding session"}, false}, + {"present", `{"system":"naming a coding session"}`, []string{"naming a coding session"}, true}, + {"any needle", `{"output_config":{}}`, []string{"naming", "output_config"}, true}, + {"escaped space falls back", `{"system":"naming a\u0020coding session"}`, []string{"naming a coding session"}, true}, + {"escaped letter falls back", `{"s":"n\u0061ming"}`, []string{"naming"}, true}, + {"upper hex falls back", `{"s":"\u004E"}`, []string{"N"}, true}, + {"escaped backslash is conservative", `{"s":"\\u0041"}`, []string{"zzz"}, true}, + {"control escape keeps shortcut", `{"s":"a\u001bbé"}`, []string{"naming"}, false}, + {"truncated escape", `{"s":"\u00`, []string{"naming"}, false}, + {"quoted value", `{"ttl":"1h"}`, []string{`"1h"`}, true}, + {"quoted value absent", `{"ttl":"5m","note":"11h"}`, []string{`"1h"`}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := jsonMayContainASCII([]byte(tt.body), tt.needles...); got != tt.want { + t.Fatalf("jsonMayContainASCII(%s, %q) = %v, want %v", tt.body, tt.needles, got, tt.want) + } + }) + } +} + +// The pre-filters must never change an answer, including when the matched +// text is spelled with \u escapes. +func TestPrefilteredClassifiersKeepEscapedMatches(t *testing.T) { + escapedTitle := `{"model":"m","system":[{"type":"text","text":"You are naming a\u0020coding session."}],` + + `"messages":[{"role":"user","content":"hi"}]}` + if !isClaudeTitleHelperRequest([]byte(escapedTitle)) { + t.Fatal("escaped system title instruction must still be detected") + } + plainTitle := `{"model":"m","system":"Return a short title for this.","messages":[{"role":"user","content":"hi"}]}` + if !isClaudeTitleHelperRequest([]byte(plainTitle)) { + t.Fatal("plain system title instruction must be detected") + } + schemaTitle := `{"model":"m","output_config":{"format":{"schema":{"properties":{"title":{"type":"string"}}}}},` + + `"messages":[{"role":"user","content":"x"}]}` + if !isClaudeTitleHelperRequest([]byte(schemaTitle)) { + t.Fatal("title schema request must be detected") + } + ordinary := `{"model":"m","system":"You are Claude Code.","messages":[{"role":"user","content":"Return a short answer"}]}` + if isClaudeTitleHelperRequest([]byte(ordinary)) { + t.Fatal("ordinary request must not be a title helper") + } + escaped1h := `{"messages":[{"role":"user","content":[{"type":"text","text":"x","cache_control":{"type":"ephemeral","ttl":"\u0031h"}}]}]}` + if !ClaudePayloadHas1hTTL([]byte(escaped1h)) { + t.Fatal("escaped 1h ttl must still be detected") + } + fiveMinutes := `{"messages":[{"role":"user","content":[{"type":"text","text":"took 11h","cache_control":{"type":"ephemeral","ttl":"5m"}}]}]}` + if ClaudePayloadHas1hTTL([]byte(fiveMinutes)) { + t.Fatal("5m ttl must not count as 1h") + } +} + +// largeClaudeCodeBody builds a Claude Code style request with n tool round +// trips, about 2.2 KB each, ending with the top-level keys Claude Code sends +// after messages. +func largeClaudeCodeBody(n int) []byte { + var b strings.Builder + b.WriteString(`{"model":"claude-opus-5-5","messages":[`) + output := strings.Repeat(`line of tool output with \"quotes\", tabs\t and a \u001b[0m reset `, 30) + for i := 0; i < n; i++ { + if i > 0 { + b.WriteByte(',') + } + fmt.Fprintf(&b, `{"role":"assistant","content":[{"type":"tool_use","id":"toolu_%d","name":"Bash","input":{"command":"ls %d"}}]},`, i, i) + fmt.Fprintf(&b, `{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_%d","content":"%s"}]}`, i, output) + } + b.WriteString(`],"system":[{"type":"text","text":"x-anthropic-billing-header: cc_version=2.1.286;"},`) + b.WriteString(`{"type":"text","text":"You are Claude Code.","cache_control":{"type":"ephemeral","ttl":"5m"}}],`) + b.WriteString(`"tools":[{"name":"Bash","input_schema":{"type":"object"}}],"metadata":{"user_id":"u"},`) + b.WriteString(`"max_tokens":64000,"thinking":{"type":"adaptive"},"stream":true}`) + return []byte(b.String()) +} + +func BenchmarkIsClaudeProbeOrHelperRequestLarge(b *testing.B) { + body := largeClaudeCodeBody(1500) + b.SetBytes(int64(len(body))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + if IsClaudeProbeOrHelperRequest(body) { + b.Fatal("ordinary request classified as probe or helper") + } + } +} + +func BenchmarkClaudePayloadHas1hTTLLarge(b *testing.B) { + body := largeClaudeCodeBody(1500) + b.SetBytes(int64(len(body))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + if ClaudePayloadHas1hTTL(body) { + b.Fatal("5m payload reported as 1h") + } + } +} + +// The worst cases: a printable-ASCII escape forces the full walk, so the +// pre-filter's scan is pure overhead. +func BenchmarkClaudePayloadHas1hTTLLargeEscapeFallback(b *testing.B) { + body := largeClaudeCodeBody(1500) + body = append([]byte(`{"note":"\u0041",`), body[1:]...) + b.SetBytes(int64(len(body))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + if ClaudePayloadHas1hTTL(body) { + b.Fatal("5m payload reported as 1h") + } + } +} + +func BenchmarkClaudePayloadHas1hTTLLargeEscapeFallbackLate(b *testing.B) { + body := largeClaudeCodeBody(1500) + if len(body) > 1 && body[len(body)-1] == '}' { + body = append(body[:len(body)-1], []byte(`,"late_escape":"\u0041"}`)...) + } + b.SetBytes(int64(len(body))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + if ClaudePayloadHas1hTTL(body) { + b.Fatal("5m payload reported as 1h") + } + } +}