amorson.me

Улучшения: агент · голос · архитектура

Ночь 16→17.07.2026 · всё найдено по коду (здесь — имена файлов; полные пути со строками — в ночных отчётах анализа, дам по запросу).

Легенда. Усилие: S часы · M дни · L неделя+. Связи: → мульти = пререквизит мультиклиники, → он-премис = пререквизит он-премиса.
Разделы: Топ-находки ночи · A. Ядро/агент · B. Голос · C. Hub/флот · D. Безопасность · E. Процессы и поставка · Быстрые победы · Вопросы на созвон

Топ-находки ночи (обсудить в первую очередь)

1

Голос обходит защитные механизмы ядра

Текстовый канал проходит конвейер гейтов: blocklist, «красная кнопка» (отключение бота), secondary-гейт для клиник с политикой «новых пациентов — оператору», фильтр устаревших сообщений. Голос заходит через /chat напрямую — ни один из этих гейтов на звонки не действует. Пример последствия: клиника нажала «красную кнопку» — бот молчит в чатах, но продолжает отвечать по телефону.

api.py (путь /chat) vs gateway/handler.py (стадии 1.2/1.25/1.55) · M → мульти (на 40 клиник рассинхрон политик умножится)

2

Fail-open конфигурации клиники

Загрузчик клиники при отсутствующем YAML молча возвращает пустой дефолтный конфиг — агент стартует «клиникой-призраком» без каталога услуг и правил. При этом один clinic_id из прод-списка ядра не имеет файла конфига в репо, а /chat без явного clinic_id подставляет дефолт "test". Три мелочи, складывающиеся в тихий сценарий «бот работает не той клиникой и никто не заметил».

clinic_loader.py (fail-open + прод-список), api.py (default "test") · SM (fail-fast + валидатор схемы + обязательный clinic_id) · → мульти → он-премис

3

Четыре копии конвейера сообщений

handle_inbound / handle_inbound_stream / /chat / /chat/stream синхронизируются вручную — уже расходились (фиксы «зеркалить» PD-531/535/572). Плюс в голосе роутинг «префикс → бекенд» продублирован 4 раза (воркер + token-server). Каждый новый канал/режим умножает риск.

gateway/handler.py + api.py; voice: 04-воркер + token_server · L (аккуратная консолидация) · → мульти

4

Секрет-гигиена

Реальный shared-secret LLM-прокси закоммичен в нескольких .env.example и в доках двух репо; LLM-прокси ходят по HTTP с секретом в заголовке; пароли инфраструктуры зашиты в компоузы; ключ наблюдаемости светится в CI. Пока это «своё облако» — терпимо; при передаче кода заказчику (он-премис) — стоп-фактор.

детали в разделе D · M (ротация + secrets-менеджмент + TLS на прокси) · → он-премис

5

Перевод звонка — blind, без возврата

Если в клинике не взяли трубку — busy и hangup, пациент потерян на самом дорогом шаге. Warm transfer (мост с брифингом оператора) + очередь + «мы перезвоним» — прямой прирост конверсии и обязательный элемент для «горячей линии страны».

voice: 04-воркер (transfer-механика), asterisk dialplan · M · → мульти

A. Ядро / агент

ЧтоЗачемУсилие
Пробросить гейты (blocklist/red-button/secondary/staleness) в /chat-путь
api.py, gateway/handler.py
единое поведение каналов (топ-1)M
Fail-fast загрузки клиники + JSON-schema валидатор YAML (26 файлов — копипаста)
clinic_loader.py, clinics/*
конец «клиник-призраков», защита от дрейфа 40 конфиговM → мульти
Таймзона клиники вместо московского хардкода (5+ мест: 4 модуля + api + SQL напоминаний)
tools/crm.py, medflex_plugin.py, confirmation_scheduler.py, agents/booking.py, api.py, db/booking_confirmation_runs.py
без этого ни одна не-московская клиника не работает корректноS → мульти
Нормализация телефонов → E.164 (сейчас только +7)
identity.py, crm/ident_plugin.py
испанский номер не пройдёт identityS → мульти
Кэши без TTL/лимитов: слоты, пациенты, брони (in-memory; инцидент уже был)
tools/crm.py, crm/routing_adapter.py, tools/booking_patient.py
память, устаревшие слоты, потеря при рестартеM
Стабильные id слотов (сейчас нумерация от порядка выдачи)
tools/crm.py, ident_plugin.py
гонки: «Вариант 2» ≠ тот же слот при повторном вызовеM
Контекст-переменные (8+ штук, класс багов «протечки между ходами», PD-356)
tools/crm.py + agents/*
свести в единый turn-контекстL
Молчаливый фолбэк чекпойнтера на память при недоступном Postgres
graph.py
диалог «забывается» без алерта — сделать громкимS
Слоты из CRM: N+1 запрос на врача; без специализации — опрос всех врачей
crm/ident_plugin.py
latency и нагрузка на CRM; для cross-clinic умножитсяM → мульти
print()-отладка в проде; /graph без авторизации
tools/crm.py, ident_plugin.py, api.py
логи/поверхностьS
Перенос на связке «новая бронь + заявка админу на отмену» открывает окно двойной записи
tools/crm.py, action_queue
риск двойных визитов; бэкстоп на чтение-CRM инертенM

B. Голос

ЧтоЗачемУсилие
Warm transfer + возврат звонка при неответе клиники (топ-5)
04-воркер, dialplan
конверсия горячей линииM
DID из атрибутов SIP-участника вместо парсинга имени комнаты; убрать env-прибитую клинику
04-воркер, dialplan, livekit-sip
фундамент «номер страны/клиники» — сейчас DID теряетсяM → мульти
Свести 4 копии роутинга «префикс→бекенд» в один источник (отдавать из ядра)
04-воркер + token_server
расползание конфигов; дубликаты-опечатки уже естьM
Филлер: стартовать с задержкой ~300–500мс и отменять при раннем первом чанке
llm-адаптер
сейчас филлер играет даже при мгновенном ответе — лишняя паузаS
Язык как параметр voice-runtime (STT/TTS/нормализация/диктовка per язык)
voice_runtime + YAML ядра
испанский/английский; сейчас язык прошитL → мульти → он-премис
Приветствие-WAV не перебивается голосом пациента (отдельный трек)
04-воркер (preroll)
заговорил поверх приветствия — оно не остановитсяSM
PD-419 (перебивания) и PD-482 (филлеры на приветствиях) — в коде не начаты, barge-in на дефолтах SDK
04-воркер
два верхних тикета голосового UXM
Локальный STT-плагин (faster-whisper) как альтернативный стек
новый плагин по образцу существующих
блокер он-премиса №1 + независимость от облакаL → он-премис
FAQ-кэш: эмбеддинги через сетевой вызов перед решением — рассмотреть локальную модель
semantic_faq_cache
latency + автономностьM
Монки-патчи SDK (3 места) — заменить на официальные хуки при апгрейде livekit-agents
04-воркер, tts_factory
хрупкость к обновлениямM
Телефонные конфиги (dispatch rule, транк) не воспроизводимы из репо — сделать IaC
deploy/notes → код
сейчас поднимается руками по заметкамSM → он-премис

C. Hub / флот

ЧтоЗачемУсилие
Пиновка версии ядра при деплое (сейчас клонится свежий main)
hub deploy-механика
воспроизводимость; без этого 40 клиник = 40 «снежинок»SM → он-премис
Bulk-деплой волнами + rollback
hub
обновить 40 клиник ≠ 40 кликовML → мульти
Персистентные сессии админов (сейчас in-memory: рестарт = разлогин всех)
hub auth
операционка флотаSM
Роли «оператор сети / супервайзер страны» (сейчас админ = ровно 1 клиника)
hub admin-модель
центральный колл-центр сетиM → мульти
Деплой-auth: фронт шлёт токен query-параметром, бэк ждёт заголовок (PD-598/599); токен в URL попадает в логи
hub фронт+API
сломано и небезопасноS
Мёртвый функционал: страница качества бьёт в несуществующие ручки; внутренняя дока описывает удалённые API
hub фронт/доки
гигиена, ложные ожиданияS
GitHub-auth на каждый запрос (2 внешних вызова, без кеша) + деплой клоном с github.com
hub auth/deploy
rate limit, зависимость рантайма от GitHubM → он-премис
Автосинк промптов: снять молчаливый try/except вокруг sync_all
hub lifespan
провал синка станет видимым (красный деплой), а не тихим — июльский инцидент ловился бы сразуS

D. Безопасность

ЧтоФактУсилие
Ротация скомпрометированного прокси-секретареальный секрет закоммичен в .env.example (5+ файлов) и доках двух репоS + ротация → он-премис
TLS на LLM-проксисейчас HTTP, секрет в заголовке открытым текстом через интернетSM
Пароли инфраструктуры из компоузов → env/secretsслабые дефолтные креды БД и сервисов наблюдаемости (PD-295)M
Общий API-ключ на весь флот клиникодин ключ пациентской поверхности для всех инстансовM
HTTPS на hub-nginx, security-заголовки, rate-limitсейчас :80 без TLS за периметромM
deploy-лог может содержать секреты .env; GitHub-токен в localStoragehubSM
SSH-деплой со StrictHostKeyChecking=noMITM-поверхность деплояS
Роль-гвард только на клиенте (вкладки суперадмина)сервер не проверяет роль на части ручекM

E. Процессы и поставка

ЧтоЗачемУсилие
Релизный «дистрибутив»: пин версий тройки репо + миграции + промпты (см. развилку №5)воспроизводимость, он-премис, откатыML → он-премис
Прибить теги docker-образов (сейчас местами :latest, включая медиа-стек)невоспроизводимые окруженияS
Интеграционный smoke тройки (core+hub+voice) в CIсовместимость версий сейчас никем не проверяетсяM
Док-гниль: голосовые STATUS/DEMO_GUIDE/HOWTO описывают апрельское состояниеонбординг, ложные инструкцииS
Единый дамп «эффективной конфигурации» голоса (env-флаги + YAML двухслойно, сумму не видно)дебаг конфигураций за минуты, а не раскопкиSM
Судья по сессиям (PD-501) — доводить: рубрика для живых диалогов + запись скоровкачество на потоке; любая миграция LLM без evals невозможнаM → он-премис

Быстрые победы (можно в ближайший спринт)

  1. Таймзона вместо московского хардкода (5+ мест) + E.164-телефоны — разблокирует любую не-РФ клинику. S
  2. Fail-fast загрузки конфига клиники + обязательный clinic_id в /chat. S
  3. Филлер с задержкой 300–500мс. S — минус лишняя пауза на каждом быстром ответе.
  4. Снять молчаливый try/except с синка промптов. S — провал станет видимым сразу.
  5. Громкий алерт на фолбэк чекпойнтера в память. S
  6. Ротация прокси-секрета + TLS на прокси. SM
  7. Деплой-auth хаба (заголовок vs query) + убрать токен из URL. S
  8. Пин версии ядра при деплое клиники. SM
  9. Валидатор YAML клиник в CI. SM
  10. IaC для dispatch rule/транка голоса. SM
Связка с большими темами. Почти всё из «быстрых побед» — пререквизиты мультиклиники и он-премиса: сначала гигиена (конфиги, секреты, версии), затем каскад/реестр/identity (развилки мультиклиники), затем локализация голосового стека (он-премис). Порядок даёт пользу на каждом шаге, даже если большие сделки сдвинутся.

Вопросы на созвон

  1. Согласны, что топ-1 (голос обходит гейты) — первый приоритет надёжности? Кто берёт?
  2. Какие 3–5 «быстрых побед» берём в ближайший спринт и кто владелец каждой?
  3. Кто владелец секрет-ротации и TLS на прокси — до любых разговоров о передаче кода наружу?
  4. PD-419/PD-482 (перебивания и филлеры) — планируем в голосовой спринт или откладываем осознанно?

Тикеты, где уже есть контекст: PD-295, PD-356, PD-419, PD-469, PD-482, PD-501, PD-531/535/572, PD-598/599. Полные отчёты с path:line — в ночных отчётах анализа (17.07), дам по запросу.