From df4d00ee290f0768b7b4cbfad1d01730d1a393bc Mon Sep 17 00:00:00 2001 From: Pierre De Lancre Date: Thu, 24 Sep 2026 18:09:49 +0300 Subject: [PATCH] =?UTF-8?q?harness:=20throttle=20bubble=20edits=20?= =?UTF-8?q?=E2=80=94=20cap=2012/bubble,=20min=208s=20interval?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Element X chokes loading rooms with long m.replace edit chains (the tool bubble got an edit per tool call — dozens per turn). Throttle pushes; the final state still flushes via the reply/closing path. --- src/matrix_harness.zig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/matrix_harness.zig b/src/matrix_harness.zig index 782b1e4..f89b36a 100644 --- a/src/matrix_harness.zig +++ b/src/matrix_harness.zig @@ -201,6 +201,8 @@ const PROGRESS_ARG_CHARS = 120; const PROGRESS_RET_CHARS = 400; /// Char cap for the bubble body (edits re-send the full body every time). const PROGRESS_MAX_CHARS = 3500; +/// Edit throttling: Element X chokes on long m.replace edit chains. +const PROGRESS_MAX_EDITS = 12; const Progress = struct { alloc: std.mem.Allocator, @@ -212,6 +214,8 @@ const Progress = struct { reply_event_id: ?[]u8 = null, // the streamed-reply message (edited live) reply: std.ArrayListUnmanaged(u8) = .empty, // accumulated reply text replied: bool = false, // true once the full reply was edited in + last_edit_ms: i64 = 0, + edits_done: usize = 0, fn deinit(self: *Progress) void { if (self.event_id) |e| self.alloc.free(e); @@ -309,6 +313,14 @@ const Progress = struct { } fn push(self: *Progress) void { + // Throttle: Element X chokes on long m.replace edit chains, so cap + // total edits per bubble and rate-limit to ~1 per 8 seconds. The + // final state is always flushed by the caller (flush()). + const now_ms: i64 = @intCast(@divTrunc(std.Io.Clock.now(.real, self.io).nanoseconds, std.time.ns_per_ms)); + if (self.edits_done >= PROGRESS_MAX_EDITS) return; + if (now_ms - self.last_edit_ms < 8000 and self.edits_done > 0) return; + self.last_edit_ms = now_ms; + self.edits_done += 1; const id = self.event_id orelse { std.debug.print("DBG push: no event_id, blocks={d}\n", .{self.blocks.items.len}); return;