Config: jivo_bot -> bot (убраны неиспользуемые webhook_secret/outbound_url/token
- транспорт Jivo уже удалён), jivosite убран целиком (виджет больше не нужен).
Env: JIVO_BOT_* -> BOT_*; JIVO_WIDGET_ID/VITE_JIVO_WIDGET_ID удалены.
tours_enabled выключен по умолчанию (BOT_TOURS_ENABLED=false) — экскурсии
«Показать на портале» уходили не по теме вопроса (живая проверка 13.07.2026),
чинить релевантность отдельно; сторож-тест не даёт включить незаметно.
Заодно убраны обнаруженные хвосты того же виджета, оставшиеся от прежних
задач: JivoLivenessProbe (класс+тест+регистрация в мониторинге внешних
сервисов), плитка «JivoSite» в админ-дашборде, встроенный скрипт виджета
в welcome.blade.php, осиротевший тест resources/js/.../JivoWidget.vue
(компонент уже был удалён ранее), declaration VITE_JIVO_WIDGET_ID.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Прежний сторож проверял только «не file»: без ключа config вернул бы null,
и проверка прошла бы впустую. Теперь ключ обязан быть redis или array,
и сам класс обязан брать именно это хранилище, а не общий кэш приложения.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Файловый Cache::increment() под параллельной нагрузкой (10 x 30) досчитал 77 из 300 —
защита от накрутки счёта (пауза/час/IP/сутки) продавливалась параллельным скриптом.
ChatRateLimiter теперь берёт своё хранилище (services.jivo_bot.limiter_store, по
умолчанию redis, в тестах array) и считает через атомарные add()+increment(), а не
через фасад RateLimiter на общем кэше. Ручная проверка на живом Redis: 300 из 300.
Защита денег для публичного чата (лендинг открыт всему интернету,
каждый ответ бота ~0,44 руб): пауза 2 сек между репликами, лимит
вопросов в час (гость 20 / вошедший 60), потолок реплик на разговор
(40), лимит по IP в час (60) и общий суточный потолок ответов (1500)
с одноразовым письмом-тревогой владельцу при пробитии. Отказ всегда
вежливый — клиент получает текст, а не молчание.
Заменяет JivoBotController+JivoBotClient на ChatController (POST /api/chat/message)
и ProcessJivoMessageJob на ProcessChatMessageJob. Реплику клиента теперь пишет
контроллер и возвращает её номер (message_id); джоба получает этот номер и берёт
историю строго до него, не отправляя ответ во внешний Jivo — он ложится в bot_dialogs,
откуда его заберёт своё окошко (Задача 3). Мозг бота не менялся.
Спека: docs/superpowers/specs/2026-07-13-own-chat-widget-design.md §5
jivo_chat_id -> chat_id + добавлены source/user_id/ip (спека
2026-07-13-own-chat-widget-design §5). Историческая миграция создания
таблицы не тронута.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
В трёх статьях было написано «не берёт трубку → заменим». Это ошибка: замену
мы не делаем, и бот честно обещал её клиентам.
Тон тонкий, тему сглаживаем:
- не обещать замену/возврат («заменим», «вернём деньги») — AnswerGuard::promisesReplacement;
- но и не рубить дверью («замена не полагается», «деньги не возвращаются») — тоже режем;
- мягко: недозвон — обычное дело; совет СМС → звонок позже → мессенджер; спорный
случай на support@liderra.ru, специалист разбирает индивидуально, без обещаний;
- не выдумывать срок ответа поддержки (она 24/7).
Статьи: zamena-zayavki.md переписана, поправлены kak-rabotat-s-nomerom.md и sdelki.md.
Два старых теста охраняли прежнее (неверное) правило — переписаны под новое.
Тесты 130/130. Бот НЕ на проде.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- «скидка ЗА ОБЪЁМ» больше не считается просьбой скидки: бот отвечает про
ступени тарифа, а не уводит к специалисту.
- «где посмотреть мою ступень / мой лимит» — вопрос про портал, а не про
личные данные клиента: эскалация снята.
- Цена ↔ ниша/регион: правило по СМЫСЛУ (AnswerGuard::priceTiedToNiche).
Враньё «цена зависит от ниши» возвращалось ПЯТЬЮ формулировками —
регулярка на каждую не работает. Честное «цена НЕ зависит от региона»
сохраняется.
- Вырезано: «на тысячу выйдет от 2 до 20 заявок» (реально максимум 4),
«работаем не со всеми нишами» / «есть направления, с которыми мы не
сотрудничаем» (ограничений по нишам НЕТ), «не берёт трубку — забей»
(такую заявку МЕНЯЮТ), «баланс на паузе не потратится», выдуманные сроки
зачисления по счёту.
- Промпт: цена только от ступени объёма; запретных ниш нет.
- Статьи: тронута ТОЛЬКО строка topics (синонимы поиска), тексты не менялись.
Тесты 126/126. Бот НЕ на проде.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Прогон 46 диалогами (250 реплик подряд в одном чате) вскрыл то, чего не видел
прогон отдельными вопросами:
- Клиент оставил телефон → бот не отвечал ВООБЩЕ: письмо в поддержку слалось
синхронно внутри ответа, SMTP не отозвался → упала вся задача (tries=1).
Теперь номер в чате = заявка на звонок: принимаем всегда (даже без просьбы
бота), письмо уходит через очередь и не может уронить ответ.
- Бот «забывал» себя: сторож резал цену, взятую из истории чата, ответ пустел
→ эскалация. Числа из своих прошлых ответов теперь разрешены; память чата
3 → 5 пар реплик; в эскалационную ветку тоже передаётся история.
- AnswerGuard: + телефон поддержки (его нет), + юр-гарантии в новых оборотах
(«Да, законно», «Штраф не прилетит»), + враньё «на паузе списаний нет»,
+ выдумки про 18:00/ночь, + «цена зависит от ниши»; снимает висящее «Но…»
и голое «Правильно, не будут» после вырезанной лжи.
- Промпт: не повторять сказанное, не поддакивать клиенту, без нумерованных списков.
- pravilo-18-00.md: 18:00 — граница для ИЗМЕНЕНИЙ, а не конец приёма заявок.
Тесты 120/120. Бот НЕ на проде.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Сторож секретов (gitleaks) видел в докблоке живой российский номер — это был
ПРИМЕР формата для распознавания, не ПДн. Заменён на +7 9XX XXX-XX-XX.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Прогнал 250 вопросов через настоящий вебхук шесть раз и сравнил четыре модели
вслепую силами судей-агентов. Итоги — в docs findings.
Модель. Появился переключатель services.jivo_bot.llm: yandex (данные не покидают
РФ) либо aitunnel (зарубежные модели через российский шлюз). По слепому сравнению
Claude Haiku 4.5 выиграл финал у Gemini 157:24 и у обеих моделей Яндекса: он
полнее, точнее по кнопкам и цифрам и говорит как человек, а не справочник.
Три замка, потому что живая модель = самоуверенная модель:
- PersonalDataMask — телефоны и почта вырезаются ДО отправки в любую модель
(клиент оставляет номер в чате; за границу ПДн уходить не должны).
- ChatTextCleaner — markdown и смайлики (Jivo их не рисует): было 191 ответ
с разметкой, стало 0.
- AnswerGuard — режет юридические гарантии («вас не оштрафуют», «мы гарантируем»,
«не нарушаем закон») и ЛЮБУЮ цену, которой нет в выданных статьях. Пусто после
чистки → зовём живого специалиста.
Поиск по инструкции переписан: выбрасываются вопросительные слова (из-за них
«какие у вас тарифы» находило выгрузку в Excel), ранжирование сперва по заголовку
и синонимам, выдача — три РАЗНЫЕ статьи и каждая целиком, плюс починка опечаток
(«каг сазадь праэкт») и учёт прошлой реплики в коротких «а это платно?».
Инструкция: 40 → 51 статья. Новые — по фактам владельца: бесплатный тест и
подарок 1000 ₽, «мы канал, а не реклама», СМС → через час звонок, средние
показатели (8–12 из 100 разговаривают, ещё 5–7 по СМС), номер не вернётся
30 дней, замена брака, вывод остатка, поддержка 24/7, удаление данных, ниши.
Вычищено враньё: минус баланса, «списали без заявки», пауза вечером, выходные,
«Вся РФ», статус «Отказ» (его нет — есть «Не реализовано»), amoCRM, платный
повторный сбор, нарастающий итог тарифных ступеней.
Тесты: 106 из 106. Каждая найденная тупость закреплена тестом.
НЕ НА ПРОДЕ. Выкат — только по прямой команде владельца.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1. 🔴 МОЙ КОСЯК: на «как получить номер человека, заходящего на сайт» бот отвечал
«нельзя» — то есть отговаривал клиента от того, ЧТО МЫ И ПРОДАЁМ. Владелец:
«как нельзя, а мы чем занимаемся?!». Теперь: «это ровно то, что делает Лидерра —
создайте проект, укажите сайт, контакты пойдут в Сделки».
2. «Все ли номера с источника цепляет система?» — нет, ПРИМЕРНО ПОЛОВИНУ: передавать
можно только абонентов с согласием (требование закона). Формулировка владельца.
3. «Как подписать договор с юрлицом?» — у нас публичная ОФЕРТА, подписывать нечего.
Слово «договор» убрано из стоп-тем; новая статья: оферта (/legal/offer), политика,
возврат + закрывающие документы (счёт → оплата → акт, УСН без НДС).
Деньги/жалобы/претензии — по-прежнему живой специалист.
Все три проверены ЖИВЬЁМ через настоящий вебхук чата (а не в обход очереди).
Инструкция: 41 статья. Pest бот 58/58.
🪤 Урок: после правки кода бота ОБЯЗАТЕЛЬНО перезапускать queue:work — воркер
кэширует бут. Владелец видел старые ответы, пока я радовался зелёным тестам.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Владелец прогнал бота вживую: «там тупежа жуть какая-то». Разобрал журнал —
каждая тупость закрыта тестом.
1. 🔴 «откуда приходят номера телефонов?» — бот плёл про Конкурентное поле вместо
честного ответа (операторы + согласие абонента). Статья усилена.
2. «как получить номер человека, зашедшего на сайт» — теперь прямой ответ: НЕЛЬЗЯ,
мы не ставим счётчик на чужой сайт и не снимаем посетителей.
3. «законно ли брать телефоны с сайтов конкурентов» — да: это контакты фирм
из открытых источников, не персональные данные граждан.
4. Формат сайта и номера в проекте — бот сдавался, хотя это в статье. Дописано явно.
5. Клиентское слово «выгрузка» (= поставка заявок) — новая статья «Когда пойдут
заявки и когда прекратятся».
6. 🔴 «могут ли работать 2-3 человека?» — ЛОЖНАЯ эскалация: голое слово «человек»
стояло в стоп-темах. Стоп-паттерн переписан: ловим просьбу позвать ЖИВОГО
(позовите/соедините/живой человек), а не любое упоминание. Плюс статья про команду.
7. «а что ты вообще знаешь?» — бот нёс чушь про паузу проектов. Новая статья-оглавление.
8. «придут ли СМС?» — теперь прямо: СМС/Телеграм/пуш нет, только почта и колокольчик.
9. 🔴 ИИ начинал ответ с «в инструкции этого нет», а СЛЕДОМ отвечал верно — и мы
глушили весь ответ эскалацией. Теперь отговорку выкидываем; в промпт добавлено:
«нет» и «нельзя» — это ТОЖЕ ответ, а не отсутствие ответа.
Проверено вручную стоп-темы: «позовите живого человека», «какие операторы», «поставщик»
— по-прежнему эскалация. Pest бот 54/54 (12 новых тестов), Vitest каталога 8/8.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Вопрос владельца: «а цены в нём надо актуализировать руками или он сам тянет?»
Ответ был неприятный: руками. Цифры (300/50 руб, тарифные ступени) стояли текстом
в статьях — поменяли бы цену в админке, бот продолжил бы врать про деньги.
Теперь в статьях стоят метки {{цена_подбора}}, {{цена_изучения}}, {{тарифы}},
а сервис LivePrices подставляет живые значения из system_settings и pricing_tiers
В МОМЕНТ ОТВЕТА — без переиндексации базы знаний. Нет цены в настройках — метка
не протекает клиенту, бот отсылает к экрану, где цена написана всегда.
Из текстов экскурсий цифры цен тоже убраны (фронт не знает БД): шаг подсвечивает
строку с ценой в самом окне — она всегда актуальная.
Проверено живьём: поменял цену в настройках на 450 — бот сразу назвал 450.
Pest 42/42 (3 новых теста), Vitest каталога 8/8.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Владелец: «клиентам надо подсказывать — от того, как они сформируют поле,
зависит весь дальнейший поиск». Плюс просьба вычитать инструкцию и экскурсии
на враньё и ловушки.
Добавлено предупреждение (и в экскурсии collect-competitors/proposals, и в статьи):
перед переносом конкурента в поле открыть сайт и справочник ссылками — тот ли это
бизнес, тот ли город, живой ли адрес. По грязной карточке мы найдём не те источники,
а изучение каждого конкурента стоит 50 руб.
Ревизия (агент сверил 36 статей и 31 экскурсию с кодом) — закрыто:
1. Вебхук обещал автоматическую отправку событий, которой НЕТ. Теперь честно:
сейчас только тестовый запрос; заявки забирать по API-ключу или выгрузкой.
2. Колонка «Город»: оговорка, что в редком запасном случае там регион проекта.
3. Отчёты: фильтры «Проект»/«Менеджер» пока только «Все» — сказано прямо.
4. Цены автоподбора: «актуальная цена всегда в самом окне».
5. Статьи «Портал на телефоне» и «Откуда заявки» больше не ведут на чужую
экскурсию про сделки (у них своей нет — кнопки просто не будет).
6. Синонимы: «портал на телефоне» и «заявки в свою CRM» находили не то.
Pest 39/39, Vitest 1227/1227. Живой прогон вопросов — отвечает верно.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Владелец застрял на шаге «Цена» (экскурсия про сбор конкурентов): карточка встала
ниже видимой части окна и вдобавок была накрыта виджетом Jivo — кнопку «Далее»
нажать было нечем, экскурсия превращалась в тупик.
1. Позиция карточки прижимается к экрану (clampTop): она всегда целиком видна,
какой бы низкой ни была цель шага.
2. z-index экскурсии поднят выше Jivo (виджет рисует себя поверх всего).
Оба бага сначала воспроизведены тестами. Vitest 1227/1227. Живьём: все 4 шага
экскурсии collect-competitors — карточка в экране, «Далее» кликабельна.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Владелец нажал «Показать на портале» в чате и не смог посмотреть: его выкинуло
на «Вход», после входа увело на дашборд (адрес экскурсии потерян), а сверху сел
приветственный тур «Добро пожаловать в Лидерру».
1. LoginView теперь возвращает клиента по redirect (роутер его уже сохранял) —
/dashboard?tour=dupes открывается сразу после входа. Чужой адрес в redirect
игнорируется (защита от подмены ссылки).
2. WelcomeTour молчит, если в адресе есть ?tour= — экскурсия из чата важнее.
Оба бага сначала воспроизведены тестами. Vitest 1225/1225. Проверено живьём:
гость → ссылка бота → форма входа → сразу «Шаг 1 из 4» нужной экскурсии.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat(bot): всеобъемлющая инструкция (36 статей) + 31 узкая экскурсия, которая открывает окна
Живой урок владельца 12.07.2026: «дубли чистятся в 2-х местах, а бот выдумал третье»,
«стыдно такого бота показывать», «видео показываем полное, а я спрашиваю про одно —
надо резать», «надо не только кнопку показывать, а и что за ней».
База знаний: 17 обзорных статей → 36 узких по темам. Портал обойдён целиком
(5 агентов): все экраны, окна, подсказки «(?)», тексты ошибок, внутренние правила.
Новое, чего бот не знал: дубли в ДВУХ местах (Поле и Предложения) + окно «источник
уже есть»; правило 18:00; почему приходит меньше лимита; оплата по счёту и акты;
списания; безопасность и 2FA; отчёты; массовые действия; регистрация.
Экскурсии: 15 → 31, каждая на свою тему (3–7 шагов). Раннер GuidedTour научен
шагу `open` — сам открывает окно/вкладку и подсвечивает то, что ВНУТРИ
(окно дублей, форму подбора, диалог пополнения, панель тарифов, карточку сделки).
99 новых якорей data-tour расставлено по всему порталу (4 агента).
Поиск: веса в tsvector (заголовок A / синонимы B / текст C) — иначе на «чистка
дублей» первой всплывала статья «Списания» из-за мимоходного упоминания «поля».
Тесты: Pest бот 39/39, Vitest 1222/1222. Новые сторожа: у каждой статьи есть
экскурсия; экскурсия не короче 3 и не длиннее 7 шагов; каждая цель экскурсии
реально существует в разметке; экскурсии про действия обязаны открывать окно.
Живая проверка в браузере: экскурсия про дубли сама открыла окно объединения
и перешла на второе место чистки.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@
Претензия владельца 12.07.2026: «видео мало и они обрубленные».
Причина «обрубленности» найдена живым прогоном: раннер НЕ переключал экраны —
шаг про «Проекты» показывался поверх «Биллинга». Фикс GuidedTour: при переходе
на шаг с другим route зовём router.push (TDD-тест «шаг на другом экране»).
Каталог: 6 → 15 экскурсий, все минимум по 3 шага (тест-сторож в TourCatalog.spec):
start (4 шага), create-project (6), top-up-balance (6), tariffs (4), balance-pause (4),
deals (4), kanban (3), konkurentnoe-pole (6), change-source (4), security (4),
notifications (3), import (4), api (3), dashboard (4), support (3).
Якоря data-tour расставлены по портале (3 агента): биллинг (кошелёк, запас,
ступени, вкладки, сумма, способ оплаты), проекты (фильтры, карточка, меню, тип
источника, лимит, регионы, дни), сделки (фильтры, таблица, экспорт), канбан,
импорт, дашборд, настройки (вкладки, 2FA, матрица уведомлений), Поле (собрать,
вручную, дубли, вкладки, карточка, легенда, изучение), помощь (FAQ, форма).
Каждая из 17 статей инструкции получила свою экскурсию (frontmatter tour:).
Vitest 1216/1216, Pest бот 46/46, живая проверка в браузере: экскурсия сама
переходит между экранами и подсвечивает цели.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Правило владельца 12.07.2026: оператора в чате может не быть, поэтому бот НЕ
переводит диалог (INVITE_AGENT убран из авто-флоу). Не смог ответить (личный
вопрос, стоп-тема, незнание) → просит номер телефона → как только клиент его
оставил, контакт уходит письмом в поддержку, а клиенту — «Спасибо, передал».
- ContactCapture: распознаёт номер в любом формате (+7/8/скобки/дефисы) → 79161234567
- BotContactRequestMail + шаблон: телефон, вопрос-на-котором-спасовал, id чата,
переписка целиком, время → services.support.email
- ProcessJivoMessageJob: ждём контакт, если прошлый ответ бота просил номер;
номера нет (клиент передумал/спросил другое) — отвечаем как обычно
- тексты эскалации переписаны под сбор контакта
TDD: BotContactCaptureTest (4 новых) + обновлены 4 теста прежней механики. 46/46.
Живая проверка на стенде: вопрос → просьба → номер → письмо с полной перепиской.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Владелец 12.07.2026 дал суть: номера передают операторы связи, и только по тем
абонентам, кто дал согласие на передачу данных третьим лицам и на рекламные
предложения. Раньше бот на «а где вы берёте эти номера?» честно эскалировал —
теперь отвечает сам, юридически корректно.
+ otkuda-zayavki.md: источник данных (операторы связи), согласие абонента как
основание, 152-ФЗ, никаких «слитых» баз; практика для клиента (звонить можно
и нужно быстро, вежливо завершать при отказе); честная оговорка «заявка —
интерес, не гарантия продажи»; юрвопросы → живой специалист.
Границы держатся (проверено живьём): «какой конкретно оператор — Билайн? МТС?» →
эскалация; «эти номера только мне достаются?» → эскалация (эксклюзивность —
жёсткая стоп-тема). Поставщик и модель распределения не раскрываются.
TDD: тест на РЕАЛЬНОЙ базе знаний (3 формулировки вопроса → статья про операторов).
42/42 зелёные.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Живой урок владельца 12.07.2026: на «зачем лидерра нужна и чем отличается
от конкурентов» бот понял «конкурентов» буквально и рассказал про раздел
«Конкурентное поле». Ценностного предложения в базе знаний просто не было.
+ o-servise.md: оплата за результат (нет абонплаты), 7 ступеней, прозрачные
списания, управление лимитами/регионами/паузой, никаких обязательств, старт
за минуты + 1000₽ новичку, заявки сразу в CRM, кому подходит, честная оговорка
«заявка — это интерес, а не гарантированная продажа».
TDD: тест ищет на РЕАЛЬНОЙ базе знаний (help:rebuild-knowledge внутри теста) —
топ-1 по вопросу не должен быть «Конкурентное поле». 41/41 зелёные.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Разведка портала 5 агентами (экраны, биллинг/настройки, Конкурентное поле,
все подсказки (?), внутренние правила) → база знаний бота выросла 4 → 15 статей:
начало работы (что такое заявка, подарок 1000₽), проекты (лимиты/регионы/дни,
правило 18:00 МСК), тарифы (7 ступеней, списание по факту), пополнение (100₽,
карта/счёт/акт), баланс и пауза (разморозка «всё-или-ничего»), сделки и канбан
(5 статусов, экспорт), Конкурентное поле (сбор 300₽/изучение 50₽, очередь,
ручной режим, дубли, метки номеров), смена источника, настройки и 2FA,
уведомления, импорт CSV, API/webhook, мобильная версия, дашборд, поддержка.
Защита коммерческой тайны (проверено агентом-цензором — 15/15 статей чисто):
ни слова про поставщика/каналы/закупку и про то, что заявка может уйти не только
одному клиенту; вопросы об эксклюзивности и перепродаже — жёсткая стоп-тема
(бот не отвечает НИ В КАКУЮ сторону, зовёт живого специалиста), внутренние
движки не упоминаются, ложных обещаний (авто-возврат, «Команда») нет.
Стоп-темы разделены: HARD (деньги/скидки/юр/эксклюзив — всегда) и PERSONAL
(«мой баланс») с исключением HOWTO — «перенести мои заявки из амоцрм» больше
не уходит к человеку, бот рассказывает про импорт.
TDD: 40/40 зелёные. Живая проверка 20+ вопросов на стенде.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Живой урок владельца 12.07.2026 («а что такое объединить дубли?»):
- LLM признался «в инструкции этого нет» (слабое ИЛИ-совпадение по общим словам),
а мы лепили кнопку «Показать на портале» → теперь такой ответ = честная
эскалация без кнопок (регэксп-детектор признания)
- статья konkurentnoe-pole: «Найти и объединить дубли» 🧹 — пары-двойники,
подтверждение клиента, бесплатно, счётчик на кнопке
- TDD: тест «не знаю без кнопки», 38/38 зелёные
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Живой урок владельца 12.07.2026 («а сам руками я могу?» — бот талдычил про ИИ за 300₽):
- ProcessJivoMessageJob: последние 6 реплик чата → история для LLM (хвосты
«👉 Показать…» срезаются), только СВОЙ чат
- BotAnswerService/YandexGptClient: история между system и текущим вопросом;
пустой поиск досыпается прошлой репликой клиента
- статья konkurentnoe-pole: ручное добавление конкурента/точек/источников — бесплатно,
кнопка «+ Добавить вручную» (фича существует, бот о ней не знал)
- TDD: 3 новых теста, все 37 зелёные
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Два живых бага демо 12.07.2026 (TDD, 34/34 зелёные):
- KnowledgeSearch: websearch_to_tsquery требует ВСЕ слова вопроса; «зачем он нужен»
ронял поиск в пусто → добавлен мягкий запасной проход через ИЛИ (plainto | )
- BotAnswerService STOP_PATTERN: «какой у меня сейчас баланс» проскакивал стоп-тему
(слова между «у меня» и «баланс») → допускаем до 3 слов разрыва, сч[её]т
- Протокол: журнал 12.07 (аккаунт Jivo, канал, цвет, ключ zofyNxmnRP, стенд-проверка)
- Скриншоты живой проверки виджета в findings
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>