From 9cd10256c4e60a5589af0cd9e08e5caec36e4adf Mon Sep 17 00:00:00 2001 From: simbiot-harness Date: Tue, 29 Sep 2026 21:07:12 +0000 Subject: [PATCH] =?UTF-8?q?fix(ladder):=20=D0=B7=D0=B0=D0=BD=D1=8F=D1=82?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=20=D1=83=D1=80=D0=BE=D0=B2=D0=BD=D1=8F?= =?UTF-8?q?=20=D0=B2=20=D1=81=D1=80=D0=B5=D0=B7=D0=B5=20=D0=B8=D0=B7=20run?= =?UTF-8?q?ning-=D0=B7=D0=B0=D0=B4=D0=B0=D1=87,=20=D0=B0=20=D0=BD=D0=B5=20?= =?UTF-8?q?cycle=5Fstate.busy=20(t-260929170039-aad557)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit busy в read model всегда False — истинная занятость живёт в памяти планировщика, событий для неё нет. Срез показывал «ожидает», пока часовой уровень держал running-задачу. TaskClaimed закрепляет уровень за задачей в проекции — теперь срез показывает «занят (running-задача)». --- harness/tg_inbox.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/harness/tg_inbox.py b/harness/tg_inbox.py index b6434ef..cd93c1e 100644 --- a/harness/tg_inbox.py +++ b/harness/tg_inbox.py @@ -176,17 +176,29 @@ def notify_chat(text: str): def ladder_snapshot() -> str: - """Срез лестницы для Telegram: уровни, занятость, задачи, эскалации.""" + """Срез лестницы для Telegram: уровни, занятость, задачи, эскалации. + + Занятость: busy в read model всегда False (истинное состояние живёт + в памяти планировщика, событий для него нет), поэтому выводим её из + running-задач: TaskClaimed закрепляет уровень за задачей в проекции. + Уровень без задачи (чистый дайджест-тик) здесь выглядит как «ожидает» — + приемлемо: дайджест-тик короткий, а взятие задачи — главный кейс. + """ model = es.run_projections() cs = model.get("cycle_state") or {} + tasks_all = list((model.get("tasks") or {}).values()) + running_levels = {t.get("level") for t in tasks_all if t.get("status") == "running"} order = ["sec", "min", "hour", "day"] lines = [] for name in order: st = cs.get(name) or {} - busy = "🔧 занят" if st.get("busy") else "ожидает" + if name in running_levels: + busy = "🔧 занят (running-задача)" + else: + busy = "ожидает" lines.append(f"{'🔹' if name != 'sec' else '⚡'} {name}: {busy}, тиков {st.get('ticks', 0)}" + (f", ошибок {st['errors']}" if st.get("errors") else "")) - tasks = list((model.get("tasks") or {}).values()) + tasks = tasks_all tasks.sort(key=lambda t: t.get("created") or "", reverse=True) board = [t for t in tasks if t.get("status") in ("ready", "running")] lines.append(f"📋 готово/в работе: {sum(1 for t in tasks if t['status'] == 'ready')}/"