1.0.9

Fixed (#369, ocr review — прогон инструмента)

  • Адресация прогона ocr review (Open Code Review) по диапазону v1.0.6→v1.0.8: (1) HIGH — клиентский tool_batch_end при битом JSON в существующей записи с тем же message_id проваливался в appendMessage и создавал вторую запись с тем же server id (сломан инвариант «один id — одна строка»); теперь warn + сохранение существующей записи; добавлен также guard на title-mismatch при том же id; (2) HIGHturn_end после ask_user уходил без токенов: ask_user-ветка actor’а не переносила _tokens_used/_tokens_max в мету (как прочие терминальные ветки) — добавлено; (3) channelInteractive заменён на канонический channels.WSChannelName (дублирования имени канала больше нет); (4) сборка эха message_persisted вынесена в единый assistantPersistedEchoMessage (role-строка в одном месте, 4 сайта); (5) warn при успехе персиста tool_iteration без строки и при провале публикации эха в OnAssistantPersisted (паритет #351 «события не исчезают молча»); (6) isServerMessage-фильтр в findIndex tool-батча (паритет с assistant-веткой); (7) уточнён комментарий о жизненном цикле pendingAsk в turn_end. Отклонены с обоснованием: «форма ask_user зависает» (форма обязана жить до явного действия пользователя — паритет с поведением до B3), content-матч первой записи (порядок эхо = порядок строк), user_id: 0 (предсуществующее, аватары эти строки не рендерят), утечка Role в чужие события (риск nil), сужение int на 32-бит (таргеты сборки 64-бит). Повторный прогон ocr review по правкам — 0 замечаний. Тесты: дубликат server id при битом content, title-mismatch.