From f6977a961aec7fe4415fe2349d15164074d7fa44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?m=C3=BCde?= Date: Sun, 5 Jul 2026 20:09:11 +0200 Subject: [PATCH] perf(hive-claude): match rate-limit markers on raw line, drop re-serialize --- hive-claude/src/classify.rs | 11 ++++++----- hive-claude/src/driver.rs | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/hive-claude/src/classify.rs b/hive-claude/src/classify.rs index dad9fbec..93eb9255 100644 --- a/hive-claude/src/classify.rs +++ b/hive-claude/src/classify.rs @@ -65,12 +65,13 @@ impl Sentinels { } } - /// Trust a rate-limit hit on a JSON `error` event's serialized form. - pub(crate) fn scan_stdout_json(&self, event: &serde_json::Value) { + /// Trust a rate-limit hit only on a JSON `error` event (so a model + /// *discussing* a rate limit in prose can't trigger it). The `type` gate + /// needs the parsed `event`; the marker match runs on `raw`, the original + /// line — the same bytes, so we don't re-serialize the value. + pub(crate) fn scan_stdout_json(&self, event: &serde_json::Value, raw: &str) { if event.get("type").and_then(|t| t.as_str()) == Some("error") - && RATE_LIMIT_MARKERS - .iter() - .any(|m| event.to_string().contains(m)) + && RATE_LIMIT_MARKERS.iter().any(|m| raw.contains(m)) { self.rate_limited.store(true, Ordering::Relaxed); } diff --git a/hive-claude/src/driver.rs b/hive-claude/src/driver.rs index c40ea456..76c3d267 100644 --- a/hive-claude/src/driver.rs +++ b/hive-claude/src/driver.rs @@ -151,7 +151,7 @@ async fn pump_stdout(stdout: ChildStdout, sink: &impl Sink, sentinels: &Sentinel while let Ok(Some(line)) = lines.next_line().await { sentinels.scan_line(&line); if let Ok(event) = serde_json::from_str::(&line) { - sentinels.scan_stdout_json(&event); + sentinels.scan_stdout_json(&event, &line); sink.on_event(&event); } else { sentinels.scan_rate_limit_text(&line);