← все проекты

AITODO — Мой день

Редизайн aitodo вокруг одной страницы «Мой день»: режим дня + задачи на таймлайне, фокус, клиенты, бэклог, ИИ-строка. Концепция: myvisionagency.ru/lab/aitodo-day

repo: E:/Проекты для Гитхаба/Новое поколение TODO (сервер aitodo:/opt/TODO-New, docker compose)server: prod https://aitodo.myvisionagency.ru, контейнеры aitodo-backend/frontend/postgres/redis
В РАБОТЕS1 · С1 · Мой день5/8

Цель: Страница /my-day: таймлайн (режим дня + задачи), режим в БД, галочки, панели Фокус/Бэклог

Бэкенд: routine_blocks + routine_logs + миграция 019 + API /api/routine
✓ Модели, alembic 019 (stamped, таблицы создал create_all), CRUD блоков + /day + /log, RAG-запись при создании/отметке
feature
Фронт: страница /my-day — таймлайн с жёлобом часов, галочки режима, сейчас/следующее
✓ Две дорожки, раскладка пересечений задач по колонкам, линия «сейчас», задачи без времени отдельной полосой
feature
Панели Фокус и Бэклог + «→ в план» + модалка настройки режима (импорт из Идеального дня)
✓ Фокус через useFocusTimer (синхронно с виджетом), бэклог pending → todo на выбранный день + открытие TaskDetailModal
feature
Пункт «Мой день» в сайдбаре + деплой на aitodo
✓ Задеплоено: https://aitodo.myvisionagency.ru/my-day (200)
feature
Проверка глазами владельца + мелкие правки по фидбеку
feature
Верхняя навигация вместо сайдбара 18 пунктов (Мой день·Задачи·Календарь·Фокус·Ещё)
✓ TopNav.tsx: 4 пункта + «Ещё» (15 разделов, 2 колонки), мобильное меню; Header без lg:left-64, логотип, компактный чип состояния; Sidebar отключён; убран мёртвый линк lia.myvisionagency.online
feature
Блок «Без времени» на дне читается как бэклог, а не как задачи на сегодня
14.09 владелец: «оно просто без времени стоит, я даже не понял что это задачи на день». Задачи, кинутые на день с разбора, лежат в блоке «БЕЗ ВРЕМЕНИ» над таймлайном и не воспринимаются как план дня. Нужно: заголовок вида «На сегодня, час не назначен», счётчик минут, визуальная связь с днём (или сразу авто-раскладка при открытии), и отдельно отличать «через ИИ» от своих.
bug
Раскладка ставит задачи «через ИИ» на таймлайн второй дорожкой, а не в «Без времени»
15.09 владелец: «не нравится, что без времени столько задач при пустом месте в сетке; давай заполнять по графику, чтобы перед глазами; задачи через тебя можно наслаивать друг на друга». Сейчас /api/day/layout пропускает via_ai (не время владельца), и они висят в блоке сверху, который он не читает. Нужно: (1) layout кладёт via_ai задачи по рабочим окнам параллельной дорожкой, поверх задач владельца, без учёта его вместимости; (2) на таймлайне «Мой день» вторая колонка/полупрозрачный слой «через ИИ»; (3) «занято/свободно» по-прежнему считает только владельца. Сегодня расставлено руками через /plan со start.
feature
готовS2 · С2 · Клиенты3/3

Цель: Сущность clients + touches, страница-пайплайн, панель «сегодня написать» на Моём дне

Бэкенд: clients + client_touches, миграция 020, API /api/clients (+/today, касания)
✓ Статусы new→contacted→dialog→waiting→client/refused, источник, next_contact_date; касание обновляет last_contact и спрашивает следующую дату; RAG-записи
feature
Страница /clients: пайплайн 6 колонок + модалка (статусы, заметка, журнал касаний, архив)
✓ Бейджи «написать сегодня/просрочено», быстрые даты след. касания (завтра/+3/+нед), пункт «Клиенты» в TopNav
feature
Панель «Клиенты» на /my-day: кому написать сегодня + счётчики пайплайна + «Написал ✓»
✓ GET /api/clients/today; кнопка открывает модалку сразу с формой касания
feature
готовS3 · С3 · Лия-руки1/1

Цель: ИИ-строка на Моём дне: создание задач/бэклог/перенос через tool-парсер с превью-подтверждением

ИИ-строка Лии на /my-day: parse + превью-подтверждение + исполнение
✓ POST /api/ai-command/parse (gpt-4o-mini, только парсинг; превью и исполнение — код): create_task/add_to_backlog/reschedule_task/complete_task/complete_routine. Фронт AiCommandBar: чипы-примеры, превью «Лия поняла… Ок?», исполнение через существующие tasksApi/routineApi
feature
готовS4 · С4 · Полировка3/3

Цель: Вкладка «Неделя», объединение двух страниц фокуса, drag идей из бэклога на таймлайн

Вкладка «Неделя» на /my-day: 7 колонок, режим N/M, задачи, клик в день
✓ Стрелки листают неделю по 7 дней; сегодня подсвечен
feature
Drag идей из бэклога на таймлайн (время по месту дропа, шаг 15 мин)
✓ HTML5 dnd, зелёный индикатор времени; «→ в план» остался как альтернатива
feature
Супер-фокус на странице /focus: полоска активного челленджа
✓ День N из M + прогресс-бар, ссылка в /super-focus; страницы объединены логически, «Фокус» один пункт в нав
feature
готовS5 · С5 · Лия видит всё4/4

Цель: Клиенты и режим дня в телеграм-Лие (lia-v2) + веб ИИ-строке; клиенты в утреннем брифе

lia-v2: 8 тулов клиентов и режима дня + методы AitodoClient
✓ CLIENT_TOOLS (get/today/add/update/touch) + ROUTINE_TOOLS (day/check/add_block) в backend/tools/clients_routine.py; request_raw без авто-слэша (иначе 307); X-User-Id auth; бэкапы .bak-20260727
feature
lia-v2: клиенты + режим дня в утреннем брифе 08:00
✓ proactive/routines.py: шаги get_clients_today и get_routine_day + секции 🤝/🗓 в формате брифа
feature
Веб ИИ-строка: add_client + log_client_touch с превью
✓ /api/ai-command/parse: 2 новых действия, контекст клиентов с /my-day; исполнение через clientsApi
feature
Старый telegram-bot (V1, выключен): те же 8 тулов на будущее
✓ telegram-bot/main.py в TODO-New обновлён, но контейнер не запущен — живая Лия это lia-v2 (/opt/lia-v2)
feature
готовS6 · С6 · Виджеты для ПК9/9

Цель: Десктопные виджеты Windows (спорт, задачи/бэклог, фокус поверх окон, музыка) с синхронизацией через API aitodo

6.1 Бэкенд: дневная норма у workout_types + миграция
Поле daily_target (nullable float) + unit уже есть. Alembic ревизия после 020. Существующие тренировки не трогаем. Доказательство: строка из базы, ответ сервера.
✓ Поле daily_target у workout_types, миграция 021 накатана на прод (alembic 021), 6 типов и 6 тренировок целы, дамп базы снят
feature
6.2 Бэкенд: GET /workouts/today — прогресс за сегодня с учётом часового пояса
По каждому типу с нормой: сделано, осталось, проценты. Считает код. Параметр tz_offset_minutes, день по местному времени.
✓ GET /api/workouts/today?tz_offset_minutes: done_today/remaining/percent считаются запросом к базе, сходятся с суммой primary_value
feature
6.3 Бэкенд: часовой пояс в /focus-sessions/stats
Сейчас день считается по UTC, в Екатеринбурге цифра «за сегодня» врёт до 05:00. Добавить tz_offset_minutes, не сломав веб /my-day и Лию.
✓ tz_offset_minutes в /api/focus-sessions/stats, «сегодня» от местной полуночи (from +05:00), без параметра поведение прежнее
feature
6.4 Каркас Electron: трей, автозапуск, окна, вход, очередь синхронизации
Папка desktop/ в репо. Безрамочные окна: перетаскивание, сворачивание в заголовок, закрытие, запоминание позиций. Вход по логину и паролю, токен в safeStorage. Локальный кэш + outbox с ретраями.
✓ Electron + esbuild без нативных модулей: трей, автозапуск, безрамочные окна с перетаскиванием, сворачиванием и уголком размера, вход с токеном в safeStorage, очередь отправки в state.json
feature
6.5 Виджет Спорт
Нормы списком: сделано из нормы, осталось, проценты, полоска. Быстрый плюс и произвольное число. Добавить, изменить, удалить норму. Сброс дня по местной полуночи.
✓ Виджет «Спорт»: нормы, проценты, быстрые кнопки и своё число, создание, правка и удаление нормы. Не проверен вживую до входа владельца
feature
6.6 Виджет Задачи и бэклог
Группы Сейчас / Дальше / Бэклог. Ввод строки в бэклог, «в план на сегодня», закрытие галочкой, дописать подпункт в задачу.
✓ Виджет «Задачи»: Сейчас / Дальше / Бэклог, запись в бэклог, «в план на сегодня», закрытие, подпункты. Не проверен вживую до входа владельца
feature
6.7 Виджет Фокус поверх всех окон
Старт, стоп, таймер сессии, время за сегодня. alwaysOnTop уровня screen-saver, не перекрывается браузером и VS Code. Подхват активной сессии после перезагрузки.
✓ Виджет «Фокус»: старт и стоп, таймер, время за сегодня, alwaysOnTop screen-saver с подтверждением каждые 4 секунды, подхват открытой сессии
feature
6.8 Музыка для фокуса
Плеер из локальной папки с mp3: играть, пауза, следующий, громкость, повтор. Путь в настройках, пустое состояние объясняет куда класть файлы.
✓ Плеер из локальной папки через схему aitodo-media с проверкой пути: играть, пауза, следующий, громкость, повтор, вперемешку
feature
6.9 Сдача: установщик .exe, проверка на живом ПК, ревьюер, документация
electron-builder NSIS, автозапуск при входе в Windows. Проверка на машине владельца, агент-ревьюер, ACCEPTANCE / DECISIONS / SCOPE-CUTS, ворклог.
✓ Установщик «Виджеты aitodo Setup 1.0.0.exe» собран дважды (второй раз с фиксом автозапуска). Живая проверка снимками экрана: виджеты рисуются, задачи и нормы приходят с сервера, счётчик суток обнулился к новому дню, фокус держится поверх развёрнутого браузера, плеер видит папку с музыкой. Документация и срезанные углы записаны. Агента-ревьюера не запускал: разрешения на подагентов не было.
feature
ревьюS7 · С7 · Проекты и рабочий день8/8

Цель: Раздел «Проекты» (проекты по группам, спринты со сроком, задачи, бэклог проекта), привязка задач и бэклога к проекту, виджеты «Проекты» и «Мой день»

7.1 Данные: миграция 022
projects: группа, признак архива, порядок. Новая таблица sprints (проект, название, цель, начало, конец, статус, порядок). tasks: project_id, sprint_id, estimate_minutes. Канбан (columns/cards) не трогаем.
✓ Миграция 022 накатана (alembic 022): у projects группа и порядок, таблица sprints, у tasks project_id/sprint_id/estimate_minutes. Связи переведены на SET NULL. Миграция смотрит на фактическое состояние базы: прод разошёлся с моделями (emoji и is_archived у projects, project_id у tasks уже были). 4 проекта, 12 колонок, 5 карточек, 253 задачи до и после.
feature
7.2 API проектов и спринтов
Список проектов со счётчиками (бэклог, в работе, активный спринт), CRUD спринтов, сводка проекта одним ответом: спринты с задачами + бэклог проекта.
✓ GET /projects/overview со счётчиками и активным спринтом (два групповых запроса, без N+1), GET /projects/{id}/summary одним ответом, CRUD спринтов. Один активный спринт на проект; найден и починен баг «новый активный спринт гасил сам себя» (нужен flush до снятия активности у остальных).
feature
7.3 API планирования дня
Фильтры задач по project_id и sprint_id, постановка задачи в день со слотом (scheduled_date + start/end), снятие из дня. Часовой пояс клиента.
✓ Фильтры задач project_id/sprint_id/only_general/day с часовым поясом, POST /tasks/{id}/plan (дата + слот, из бэклога сама в план) и /unplan. Проверено ответами сервера: слот 10:00–10:45 из оценки 45 минут, снятие возвращает в бэклог.
feature
7.4 Веб: раздел «Проекты»
Страница: список по группам с цветом и счётчиками, вход в проект, спринты аккордеонами, задачи со статусом и оценкой, бэклог проекта со строкой ввода, переносы бэклог→спринт и задача→мой день. Пункт в TopNav.
✓ Страница /projects: проекты по группам с цветом и счётчиками, вход в проект, спринты со сроком и статусом, задачи с оценкой и статусом, бэклог проекта со строкой ввода, переносы в спринт и в мой день, пункт в TopNav. Прогнано мышью в браузере: проект, спринт, задача, отправка в день.
feature
7.5 Веб: связи проекта с бэклогом и днём
Выбор проекта в общем бэклоге и в карточке задачи, фильтр бэклога по проекту, цвет проекта у задач на таймлайне «Мой день».
✓ В общем бэклоге выбор проекта у каждой идеи и фильтр по проекту (фильтр же адрес новой записи). Цвет проекта полосой на таймлайне «Мой день». Побочно починен старый баг: бэклог грузил сто последних задач любого статуса и показывал 16 идей вместо 21.
feature
7.6 Виджет «Проекты»
Список проектов с цветом и счётчиками, создание проекта, вход в проект: спринты, задачи, бэклог проекта. Добавить задачу, отправить в мой день.
✓ Виджет «Проекты»: список по группам с цветом и счётчиками, создание проекта, вход в проект со спринтами, задачами и бэклогом, отправка задачи в день. Проверен снимком окна на живых данных.
feature
7.7 Виджет «Мой день»
Лента по часам на сегодня: режим дня и задачи слотами, отметка «сейчас», цвета проектов. Поставить задачу на время, перенести из бэклога, взять из проектов.
✓ Виджет «Мой день»: лента по часам (режим дня + задачи слотами), подсветка текущего блока, цвета проектов, «добрать работу» с фильтром бэклог/проекты, «поставить на время» одним запросом. Заодно починены подпункты в виджете «Задачи»: сервер отдаёт subtasks, а читался checklist.
feature
7.8 Сдача спринта 7
Деплой по явному «да», доказательства ответами сервера и снимками, ACCEPTANCE по пунктам, установщик, docs/DESKTOP_WIDGETS.md и раздел про проекты, SCOPE-CUTS, dev-sync.
✓ Бэкенд и веб выкачены на прод по «да», бэкап снят, тестовые данные вычищены. Установщик 1.1.0 собран. Написаны docs/PROJECTS.md, обновлены DESKTOP_WIDGETS.md, ACCEPTANCE (с доказательствами) и SCOPE-CUTS-LOG. Не закрыто мышью: часть кнопок в вебе и действия в новых виджетах, это за владельцем.
feature
В РАБОТЕS8 · С8 · Входящие: одно место для всего20/21

Цель: Одно место, куда падает что угодно из любого канала (текст, пересылка, голос, файл) и не теряется: сущность «входящие», Лия как приёмник, виджет и страница для разбора

8.1 Данные: сущность «входящие»
Таблица inbox_items: источник (telegram/voice/file/manual/email/meeting), ссылка на исходник, автор, текст, расшифровка, файлы, подсказки (заголовок/проект/оценка/срок), статус new/task/dropped, связь с задачей. Миграция 023.
✓ Таблица inbox_items, миграция 023 на проде. Источник, ссылка на исходник, автор, текст, расшифровка, файлы, подсказки, статус new/task/dropped.
feature
8.2 API входящих
POST /api/inbox (текст + файлы), GET /api/inbox?status=, POST /api/inbox/{id}/to-task (создаёт задачу с проектом), /to-backlog, /drop. Разметка проекта по совпадению названия — кодом, не моделью. Файлы через существующий uploads.
✓ API входящих: положить, список со счётчиками, в задачу (создаёт задачу с проектом и переносит вложения), выкинуть, вернуть. Проект угадывается кодом по названию, проверено: «в Клиенты» → проект 8, «Пульс цен» → пусто (такого проекта нет, не выдумывает).
feature
8.3 Расшифровка голоса на стороне aitodo
Сервис транскрипции (OpenAI gpt-4o-mini-transcribe / whisper-1 на существующем ключе), пригодный и для будущих встреч: сменный движок, чтобы добавить Groq и локальный whisper без переписывания.
✓ Сервис расшифровки со сменным движком, по умолчанию Groq whisper-large-v3-turbo (3,6 ₽/час вместо 32 ₽ у OpenAI). Ключ Groq в .env, приложение его видит, путь проверен живым запросом. Платная разметка голосов только по явному флагу.
feature
8.4 Лия как приёмник
Не команда → во входящие: текст, пересылка (с ссылкой на сообщение и автором), голосовуха (расшифровка), документ и фото (файл в uploads). Ответ одной строкой «записал: ... → проект». Команды работают как раньше.
✓ Лия принимает: пересылки, файлы, фото, аудио и видео идут во входящие без вызова модели (обработчик до общего), плюс инструменты inbox_add и inbox_list для «запиши». Инструментов стало 53. Проверено вызовом инструмента изнутри контейнера: запись доехала до базы как source=telegram.
feature
8.5 Виджет «Входящие»
Поле ввода, перетаскивание файла в окно, список входящих с источником, три кнопки разбора. Счётчик непрозобранного в трее.
✓ Виджет «Входящие»: список с источником и автором, разбор в три кнопки с выбором проекта, строка записи, перетаскивание файла в окно.
feature
8.6 Страница /inbox в вебе
То же в браузере: список, разбор, файлы, ссылка на исходник.
✓ Страница /inbox: вкладки неразобранное и выкинутое, разбор, ссылка на исходник, пустое состояние. Пункт в TopNav первым; «Календарь» уехал в «Ещё», иначе меню налезало на индикаторы.
feature
8.7 Сдача
Деплой по «да», доказательства: голосовуха из телеграма доехала во входящие с расшифровкой, файл сохранён, задача создалась с проектом. Документация docs/INBOX.md, ACCEPTANCE, dev-sync.
feature
8.8 Календарь: неделя, разворот окна, цвета
Виджет «Мой день»: переключатель день/неделя, семь колонок с раскладкой по часам и прибитой шапкой дней, клик по клетке ставит встречу на этот день и час, легенда цветов по проектам, разворот окна на весь экран, выбранный вид запоминается. В вебе починен щелчок по времени: было округление к ближайшим 15 минутам и клик по 15:00 давал 15:15, теперь магнит к часу.
✓ Проверено снимком: шапка дней прибита, сегодня подсвечен, блоки стоят по времени, линия «сейчас» на месте. Не проверено мышью: разворот на весь экран и создание встречи кликом по клетке.
feature
8.9 Календарь: правка времени и карточка задачи
По замечанию владельца: в форме постановки день, время и длительность стали полями (ткнул мимо — поправил, а не кликал заново). Клик по блоку задачи открывает карточку в виджете: название, день, время, длительность, проект, кнопки готово / снять с дня / удалить / открыть в aitodo. Раньше на клике стояла заглушка со всплывашкой.
✓ Типы чистые, собрано, приложение перезапущено. Мышью проверяет владелец: правка времени в форме и сохранение карточки.
feature
8.10 Прогон разбора на настоящей встрече
Запись 19.08.2026, 43 минуты, 587 МБ видео. ffmpeg локально вынул звук в opus 24k моно (7 МБ), загрузка на /api/meetings/audio, расшифровка Groq whisper-large-v3-turbo за 24 секунды (28 388 знаков), разбор gpt-4o-mini. Итого около 3 рублей.
✓ Разбор осмысленный: тема «контент-стратегия и реклама в соцсетях», саммари, решение, две задачи (медиаплан до 25 числа, автоматизация КП) — обе автоматом легли во «Входящие» со ссылкой meeting:1, плюс повисший вопрос и прозвучавший срок. Файлы саммари.md и разбор.json легли в папку встреч. СЛАБОЕ МЕСТО: у этой записи микрофон и собеседники сведены в одну дорожку (разница каналов −91 дБ), поэтому роли не разделились: «Говорящий 1, 100% времени», тезисы сторон слились. Для будущих встреч решается записью через виджет (две дорожки, те же 3 ₽), для этой — платной разметкой за ~23 ₽, владелец решает.
test
↑ 8.11 Документы по встрече: подробный md и синопсис PDF
Формат по образцу владельца. Расшифровка Groq переведена на verbose_json — появились таймкоды по отрезкам, реплики склеиваются в блоки по минуте. Промпт разбора расширен: решения с таймкодами, задачи с ответственным/сроком/триггером/уверенностью, разделы обсуждения по темам, развилка (тезис-антитезис), статус-факты, риски, вехи, что требует подтверждения владельца, следующая контрольная точка. Новые блоки лежат одним json-полем meetings.extra (миграция 025), чтобы следующий блок не требовал миграции. Рендер в app/services/meeting_docs.py: markdown с шапкой полями и таблицами + светлый синопсис карточками. Маршруты GET /meetings/{id}/docs и POST /meetings/{id}/redigest (пересборка разбора по сохранённой расшифровке, без повторной оплаты распознавания). Виджет после записи сам пишет саммари.md, синопсис.html и печатает синопсис.pdf скрытым окном.
✓ Проверено на записи 19.08 (43 мин): таймкоды в решениях 00:00-01:29 и 10:12-11:39, документы в папке встречи, PDF 63 КБ. Слабое место: gpt-4o-mini выдаёт мало деталей (2 решения, 2 задачи на 43 минуты) против образца владельца. Ждём решения по модели разбора: 0,3 руб/встреча против ~5 руб за сильную модель.
feature
↑ 8.12 Пересборка приложения: владелец сидел на сборке от 12.08
Обнаружено при проверке: запущенная программа «Виджеты aitodo» была собрана 12.08 и держала блокировку единственного экземпляра, из-за чего версия из исходников молча выходила. В той сборке нет «Входящих», «Встречи», недели в календаре и карточки задачи — то есть всей работы спринта 8. Дополнительно: ELECTRON_RUN_AS_NODE от VS Code прилетает в дочерний процесс и запускает Electron как Node, launch надо делать с чистым окружением.
✓ npm run dist пересобрал, папка запуска E:\...itodo-widgets обновлена через robocopy /MIR, приложение запущено (10 процессов, asar от 19.08 11:52, внутри inbox/meeting/day). Старая сборка остановлена.
bug
↑ 8.13 Разбор встречи по окнам вместо одного прохода
Владелец заметил: в разборе только начало встречи. Проверка подтвердила, что расшифровка полная (554 отрезка, 0-2575 сек из 2579, две паузы больше 20 сек), а обобщала модель: одна просьба на 28 тыс. знаков давала 2 решения и 2 задачи. Переделано на карту-свод: код режет встречу на окна по 8 минут / 7 тыс. знаков, модель выписывает факты из каждого окна отдельно (по 4 параллельно), код сшивает и чистит повторы, затем один проход на связный текст по уже собранным фактам. Плюс смысловая склейка: сравнение по буквам не ловит «прописать медиаплан» и «накидать общий план с бюджетом», поэтому модель отдаёт группы номеров, а склеивает код, выбирая формулировку с ответственным и сроком.
✓ На той же записи: решений 2 -> 8, задач 2 -> 12, темы от 00:00 до 41:40, 4 пункта на подтверждение, 6 открытых вопросов. Пересборка идёт по сохранённой расшифровке, повторно за распознавание не платим: около 1 рубля за прогон, 20-30 секунд.
bug
8.14 Чистка задач разбора: владелец, пустые значения, входящие
Найдено при разборе живой встречи. 1) В графе ответственного стояло слово null строкой и метка «Говорящий 1» — теперь оба случая дают прочерк. 2) В сроке задачи тоже попадалось слово null: чистка и на сборке, и на отрисовке, чтобы старые разборы выглядели чисто. 3) «Маша — 0% времени» у человека, которого лишь упоминали: доля времени теперь только у тех, кто есть в записи голосом, остальные помечаются «упомянут на встрече». 4) Задачи без названного владельца не уезжали во «Входящие» и терялись — теперь уезжают с пометкой «владелец не назван, решить при разборе». 5) Пересборка разбора уносила в «выкинутые» неразобранные пункты от прошлой версии, чтобы во «Входящих» не лежали две формулировки одной задачи.
✓ Проверено на встрече 19.08: в документах слово null не встречается ни разу, участники «Говорящий 1 — 100%» и «Влад — упомянут», во «Входящих» 11 активных пунктов и 15 автоматически убранных от прошлых прогонов.
bug
↑ 8.15 Запись встречи не уходила: nginx резал на 10 МБ
Владелец записал встречу 1 ч 35 мин виджетом, отправка упала с 413 Request Entity Too Large. Дорожки 13 и 15 МБ, вместе 28 МБ, а в /etc/nginx/sites-enabled/aitodo-mva стоял client_max_body_size 10M. Поднято до 300M, для location /api/ добавлены proxy_read_timeout и proxy_send_timeout 1800s и proxy_request_buffering off: разбор часовой встречи идёт минутами в том же запросе, 60 секунд его обрывали. Бэкап конфига рядом, nginx -t пройден.
✓ Запись дослана тем же файлом, ответ 201 за 52 секунды. Запись не потерялась: виджет пишет файлы на диск до отправки.
bug
↑ 8.16 Две дорожки склеивались без времени, диалог рассыпался
transcribe_two_tracks складывал дорожки одна за другой: два огромных куска с start=0, сначала весь монолог владельца, потом весь чужой. Из-за этого окно разбора было одно на 1,5 часа и разбор снова выходил поверхностным. Теперь реплики берутся из отрезков обеих дорожек и сшиваются по времени, получается диалог с ролями «Ты» и «Собеседник». Резчик окон научился делить один огромный блок по тексту, а разбор помечает флагом, было ли в расшифровке настоящее время: без времени таймкоды не печатаются ни в md, ни в синопсисе, чтобы не было ссылок на «00:00».
✓ На встрече 1 ч 35 мин: окон 9, решений 18, задач 9, на подтверждение 3, вопросов 7, тем 9. Роли разделились: Собеседник 90%, Ты 10%. Таймкодов у этой записи нет: расшифровка сделана до фикса.
bug
↑ 8.17 Кривая кодировка папки встреч и досылка записи
Виджет писал записи в E:/Р СћРЎР‚... — путь попал в state.json от сборки 12.08 в неверной кодировке и жил там, потому что настройки читаются из состояния, а не из значений по умолчанию. Записи ложились в отдельный кривой корень на диске E. Папка перенесена в «Транскрибации встреч и саммори», кривой корень удалён, путь в состоянии исправлен. Плюс: вместо страницы ошибки nginx с тегами виджет показывает человеческую причину (413 — файл больше разрешённого, 401 — сессия истекла), и появилась кнопка «Дослать запись»: отправка идёт тем же путём из файлов на диске, перезаписывать встречу не надо.
✓ Папка встреч в настройках: E:/Транскрибации встреч и саммори, обе встречи лежат там. Приложение пересобрано и запущено (10 процессов). Кнопка досылки мышью не проверена.
bug
8.18 Склейка повторов теряла задачи
Смысловая склейка на gpt-4o-mini объединяла разные дела: за один прогон список задач усох с 15 до 6. Промпт ужесточён (сомневаешься — не объединяй), и добавлена проверка в коде: склейка проходит только при общем значимом слове (грубые основы по первым пяти буквам) или высокой похожести строк. Иначе пункт остаётся отдельным. Приоритет: лишний пункт в списке не страшен, потерянная задача страшна.
✓ После правки на той же записи 18 решений и 9 задач вместо 7 и 6. Разброс между прогонами остался — это модель.
bug
↑ 8.19 Ответственный за задачу — из метки дорожки, а не из слова «я»
Владелец показал: почти все задачи встречи висели на нём, включая «показать, как дорабатывать изображения в Photoshop» — это дело дизайнера. Причина: модель видела в реплике слово «я» и ставила owner_is_me, не различая, чья это реплика. Переделано: модель теперь отдаёт said_by (метка блока, где задача прозвучала) и owner_kind (сам / собеседник / третий / неясно), а владельца выводит код по функции resolve_owner. Правило: сказал «сделаю» владелец записи — его задача; сказал то же собеседник — задача собеседника; «сделай» в адрес другого переворачивает владельца; названо третье лицо — берётся имя; неясно или запись одной дорожкой — владелец не назван, пункт уезжает в «Входящие» на разбор. В каждой задаче сохраняется said_by, чтобы было видно, из чьей реплики она взята.
✓ На встрече с дизайнером было 15 задач «на меня», стало 2 моих и 15 на собеседника. Photoshop, гайд по шрифтам, каталог рамок, дизайн-ревью ушли дизайнеру. Проверено по синопсису.
bug
↑ 8.20 Модель разбора: DeepSeek V4 Flash вместо gpt-4o-mini
Владелец попросил DeepSeek Flash. Сверился с каталогом OpenRouter: deepseek/deepseek-v4-flash, 0,083 доллара за миллион входных и 0,165 за выходные против 0,15 и 0,60 у gpt-4o-mini, то есть дешевле и вдвое, и вчетверо. Заодно потребовалась устойчивость: ответ обрывался на полуслове (поднял max_tokens до 12000 и добавил починку обрезанного json по последнему целому элементу), иногда приходил пустой content вместо json (теперь своя ошибка и потеря одного окна вместо падения запроса). В промпте развёл решение и задачу, плюс код выкидывает решение, дословно повторяющее задачу.
✓ На встрече с дизайнером 19 решений и 33 задачи против 18 и 9 у mini, формулировки конкретные: шрифт Inter, отклонён Baldet, цвета fit yellow 400/200, NanoBanana только для фото, шаблоны в Figma, созвон 25-го. Владельцы расставлены верно. Разбор полуторачасовой встречи меньше рубля, время 3 минуты против 30 секунд у mini — это цена качества.
feature
8.21 Грабля OpenRouter: скорость уводит к пожатой модели
Разбор на DeepSeek занимал 7 минут. Добавил provider sort throughput — стало 2:45, но в русском тексте начали выпадать буквы: «цифрово идентики», «выступю пртив», «чисты цвеа», Figma превратилась в «Film». json при этом валидный, код не падает, видно только глазами в готовом документе. Причина: среди быстрых поставщиков попадаются сильно квантованные копии. Лечение: sort throughput вместе с quantizations fp8/bf16/fp16/fp32 — 3:08 и чистый текст.
✓ Записал в память как общую граблю для всех проектов через OpenRouter, не только aitodo.
bug
ревьюS9 · С9 · План дня и поля задачи8/8

Цель: Один список разбора, перенос задач мышкой на время, честные поля задачи и пометка встречи

9.1 Входящие и бэклог одним списком «Разобрать»
✓ Страница /backlog показывает заметки входящих и идеи одним потоком, у заметок кнопки Запланировать/Отложить/Выкинуть. /inbox ведёт туда же, в меню один пункт. Данные не переносил: сущности остались свои.
task
9.2 Страница «Спланировать день» с переносом мышкой
✓ Новая /plan-day: слева задачи без времени, справа сетка дня по 30 минут. Перетащил — встало время и длительность, обратно в список — время снялось. Проверено на проде.
task
9.3 Конвертация спрашивает день и время
✓ Окно «Когда сделать»: быстрые кнопки (сегодня утром/после обеда/завтра), дата-время и длительность. Раньше молча ставило сегодня.
task
9.4 Перетаскивание задач по времени в «Моём дне»
✓ Блок задачи тянется мышкой, длительность сохраняется. Сделано на том же механизме, что и перенос из бэклога.
task
9.5 Поля задачи: «Когда начать» + «Сколько времени»
✓ Убран блок «Запланированное время», дедлайн переименован в «Когда начать» (пишет scheduled_start), длительность кнопками 15/30/45/1ч/1,5ч/2ч/3ч или своё. Миграция 026 перенесла старые дедлайны в scheduled_start — 158 задач сохранили время.
task
9.6 Описание: рост под текст, файлы, чек-лист + пометка «встреча»
✓ Описание тянется при наборе и принимает файлы перетаскиванием и вставкой из буфера (до 10 МБ). Пометка «встреча» отдельным полем is_meeting (не тегом) — своя рамка в списке, календаре и «Моём дне».
task
9.x Повторяющиеся задачи: время паттерна считалось UTC, еженедельная ПЦ уезжала с 11:00 на 16:00
Владелец «миллион раз правил» экземпляр, а генератор каждую неделю создавал новый по времени паттерна как UTC.
✓ recurring_tasks.py: calculate_next_occurrences берёт users.timezone (Asia/Yekaterinburg), день недели и час считает по поясу, хранит UTC. Проверка функции: паттерн 11:00 пн → 2026-09-21 06:00 UTC. Экземпляр 1112 поправлен на 11:00 Екб. Выкачено 21.09.
bug
9.y «Остановить серию» не останавливала: JSON паттерна правился на месте, SQLAlchemy не видел
✓ stop_recurring_series: новый dict вместо мутации; проверено: end_date записан у 1166-1168, экземпляры 1181-1218 отменены. Выкачено 21.09.
bug
готовS10 · Проверки по сроку1/4

Цель: Отложенные проверки: сработало ли то, что чинили

Встречи: ушло ли удвоение фраз в расшифровке
21.08 в расшифровке встречи 4 каждая фраза шла дважды и вылезали выдумки Whisper на тишине («Продолжение следует», подписи субтитров с ютуба). Выкатил чистку: фильтр по no_speech_prob>0.6, compression_ratio>2.4, список выдуманных фраз, склейка повторов в окне 45 секунд. На старых данных выкинуло 126 отрезков из 380. Осталась неясность: внутри одной реплики текст тоже повторялся — это похоже на эхо из колонок в микрофон, то есть проблема в самом звуке, а не в расшифровке. КОМАНДА ПРОВЕРКИ (после следующей записанной встречи): curl -s 'https://aitodo.myvisionagency.ru/api/meetings/?limit=1' -H "Authorization: Bearer $TOKEN" Взять transcript, посчитать пары почти одинаковых соседних реплик (difflib > 0.82 в окне 8 реплик). Было: 433 пары на 380 реплик. Должно стать близко к нулю. Если повторы внутри одной реплики остались — смотреть звук: ffprobe запись-микрофон.webm и запись-система.webm в папке встречи, проверить, не слышен ли собеседник в микрофонной дорожке (эхо из колонок).
✓ Проверено 31.08 на встрече 11 (54 минуты, 672 реплики): пар почти одинаковых соседних реплик ноль, было 433 на 380. Чистка от 21.08 сработала. Но всплыла другая беда: Whisper на своей дорожке ломал лицо глагола, «доработаю» слышалось как «доработают». Ушли с Whisper на GigaAM, разбор пересобран.
check
AITODO С21: сторож звонков — встречи записываются с начала?
⏱ 09.10 · просрочено 21 дн.
С 02.10 виджет 1.3.0 сам предлагает записать встречу, когда Телемост, Зум, Телеграм или Скайп для бизнеса берут микрофон. Через неделю проверить, что запись теперь начинается вовремя и окошко не мешает. КОМАНДА ПРОВЕРКИ (сравнить два списка за неделю, время в UTC, +5 = Екатеринбург): ssh aitodo "cd /opt/TODO-New && docker compose exec -T postgres psql -U aitodo_user -d aitodo -c \"select started_at, title, duration_seconds/60 as min from meetings where user_id=6 and started_at >= '2026-10-02' order by 1\"" ssh aitodo "cd /opt/TODO-New && docker compose exec -T postgres psql -U aitodo_user -d aitodo -c \"select scheduled_start, title from tasks where user_id=6 and is_meeting and status<>'cancelled' and scheduled_start between '2026-10-02' and '2026-10-09' order by 1\"" ХОРОШО: у встреч с созвоном запись начинается не позже 5 минут от начала встречи; прошедшие встречи недели видны в виджете «Мой день» в виде «неделя». ПЛОХО: записи стартуют с опозданием как раньше (01.10: Телемост 15:27, запись 15:34) — спросить владельца, появлялось ли окошко; ложные окошки (голосовые в Телеграме, выключенный микрофон в звонке) — смотреть журнал срезанных углов С21, пункт 5. Заодно: решение владельца по 17 встречам в бэклоге не из Битрикса (закрыть как прошедшие?).
check
Linear: пришла ли сводка «ждут ответа» 08.10 в 10:00 и живые уведомления
⏱ 08.10 · просрочено 22 дн.
Проверка: ssh aitodo "docker logs --since 26h aitodo-backend 2>&1 | grep -i linear" — должны быть «в сводке «ждут ответа»: N» и «новых уведомлений: N» без «Linear не пускает». В базе: select reminder_type,is_sent,sent_at from lia_reminders where reminder_type like linear% order by id desc limit 5; — is_sent=true. Спросить владельца, пришло ли в @fitleadmy_bot и не шумно ли.
check
🔴 Диск данных aitodo: не забился ли снова дампами Paperclip (28.10 падали базы LeadForge и AITODO)
⏱ 30.10 · сегодня
28.10 /mnt/docker-data был 100%: часовые дампы Paperclip (~45 МБ, 149 шт. за неделю). Дампы старше 3 суток перенесены в /var/hold-paperclip-backups-20261028 (4,6 ГБ, корень). Без смены ротации (напр. часовые за сутки + суточные за 7 дней) диск полный ~31.10. Проверка: ssh aitodo "df -h /mnt/docker-data /; docker ps --format '{{.Names}} {{.Status}}' | grep -i postgres". Норма: данные < 90%, базы healthy. Удаление hold-папки и смена ротации — только по «да» владельца.
check
ревьюS11 · С11 · Битрикс: задачи и встречи с работы5/6

Цель: Забирать задачи и встречи из рабочего портала в план дня, уведомлять в телеграм

11.1 Клиент к порталу и разбор механики
✓ Вебхук читает задачи, календарь и профиль. Поймано и записано в код две ловушки портала: методы задач живут под правом «task» в единственном числе (с «tasks» отказ), а фильтр «!=STATUS» со списком портал понимает наоборот и отдаёт ровно закрытые задачи — заменено на сравнение числом «<5».
task
11.2 Время встреч читается верно
✓ Поле DATE_FROM_TS_UTC на портале смещено на пояс (13:00 Екб приходит как 03:00 UTC вместо 08:00 — двойная конвертация Битрикса). Время берём из DATE_FROM плюс смещение события. Проверено: 13:00 и 16:00 встали как в портале.
task
11.3 Перенос в план без дублей
✓ Таблица связей bitrix_links: внешний номер, отпечаток содержимого, отметки об уведомлении. Миграция 027. Задача с дедлайном получает старт за два дня до срока, встреча занимает время в дне и получает пометку «встреча». Удалённое руками не возвращается. Три захода подряд — ни одного дубля.
task
11.4 Уведомления Лии
✓ Одно сообщение на заход, только про новое и про перенесённое: проактивный чекер в этом проекте уже выключали за спам. Проверено, что бот видит чат владельца; отказ телеграма больше не проходит молча — код смотрит на ответ.
task
11.5 Планировщик каждые пять минут
✓ Задание bitrix_sync в APScheduler. Ручки /api/bitrix/status, /preview и /sync для проверки руками. Ключ портала только в .env, в коде и в дашборде его нет.
task
11.x Заглушки «Встреча», поставленные нами в Битрикс Фит Лида, возвращаются синком в AITODO дублями
21.09: семь «Встреча» (10831-10837) приехали задачами 1204-1211 поверх встреч ПЦ. Отменены руками. Решение: синк пропускает события с NAME=«Встреча» без описания, созданные нашим вебхуком (или помечать их в описании маркером).
bug
ревьюS12 · С12 · Качество разбора встреч5/5

Цель: Русский язык без иероглифов, отбор задач от болтовни, контекст встречи в каждом пункте

12.1 Иероглифы в задачах: язык проверяется кодом
✓ Модель deepseek-v4-flash китайская и на длинных окнах уплывала на свой язык: на встрече 26.08 девять задач из сорока семи пришли по-китайски, включая тему встречи. Правило языка добавлено в оба промпта (окна и сводный текст), плюс проверка кодом: нашли иероглифы — просим ещё раз по-русски, второй отказ — выкидываем чужие пункты и подписи. Проверено на данных встречи 9.
task
12.2 Отбор задач от разговорной шелухи
✓ В промпте прямо стояло «выписывай ВСЕ задачи, даже мелкие, лучше десять пунктов чем два общих» — отсюда сорок семь пунктов с «Допилить» и «Нажать ещё раз». Заменено правилами: задача = дело после встречи с результатом; не задача — то, что сделали по ходу, и общие намерения. Плюс отбор кодом перед Входящими (worth_inbox): иероглифы, обрывки короче 14 знаков, одно общее слово, низкая уверенность без срока. На встрече 9: 46 задач, во Входящие прошло бы 34.
task
12.3 Контекст встречи в каждом пункте
✓ Задача помнит встречу: поле meeting_id, миграция 028, связь в модели. Входящие отдают контекст (название, тема, дата) одним запросом на список. Видно в «Разобрать», в бэклоге, в карточке задачи и в виджете. Проставил связь у 9 задач, конвертированных ранее. Убрал китайскую тему у встречи 9.
task
12.4 Описание пункта без повторов
✓ Описание больше не дублирует название задачи и не пишет заново «Со встречи X» (это в подписи). Вместо повтора — «Начинать когда» и «Прозвучало на 15:08», чтобы найти место в записи. Почищено 72 уже существующих пункта.
task
12.5 Виджет: окно не замирает на разборе
✓ Сервер отдаёт решения объектами, виджет ждал строк — экранирование падало, окно замирало на «Разбираю встречу» и записать новую было нельзя. Экранирование терпит любой тип, отрисовка обёрнута в защиту с запасным экраном, «Записать новую» и «Проверить разбор» доступны сразу, поздний ответ не перебивает новую запись. Примечание про роли убрано из поля ошибки.
task
готовS13 · С13 · Знания по проектам7/10

Цель: Единый склад материалов по проектам и контекст, который ИИ находит сам

13.1 Спроектирована архитектура склада знаний
✓ Страница myvisionagency.ru/lab/aitodo-znaniya: четыре уровня (контур, проект с паспортом, материал, куски для поиска), четыре точки входа, правило «сначала код сужает до проекта, потом поиск по смыслу», бриф собирается кодом. Разобрано что уже есть: pgvector установлен, таблица памяти 282 записи но только личное, 288 тысяч знаков расшифровок, MCP в репо только про деплой.
task
13.2 Контур, вид, паспорт и алиасы у проекта
✓ Миграция 029. Контур work_1/work_2/own отдельно от группы: он решает, что уходит наружу и что нельзя показывать не тому работодателю. Паспорт — один экран, который ИИ читает первым. Алиасы — как проект называют в жизни.
task
13.3 Поиск проекта по фразе человека
✓ GET /api/projects/resolve: нормализация без пробелов и регистра, точное совпадение по названию и алиасам, затем вхождение. Двусмысленность не разрешаем сами — отдаём варианты («контент завод» = два проекта). Проверено: «фл» и «фитлид» находят Фит Лид, «навесы», «аитуду», «кз идеи» — свои проекты. Ловушка: маршрут /resolve перехватывался /{project_id}, пришлось поднять выше по файлу.
task
13.4 Экран паспорта на странице проектов
✓ Компонент ProjectPassport: контур кнопками, вид, алиасы чипсами, паспорт с подсказкой по структуре (чем занимается, ЦА, что пробовали, кто решает, чего обещать нельзя). Сохраняется по месту, без кнопки «сохранить».
task
13.5 Заполнить паспорта проектов
Контуры и алиасы проставлены у шести проектов из фактов. Осталось: сам текст паспортов (у владельца), контур «Пульс цен» (нет однозначного признака) и решение, создавать ли три проекта-бренда первой работы (Искра, Рабочее место маркетинга, СММ-Агент — видны в задачах Битрикса).
✓ Паспорта заполнены словами владельца: Пульс цен (B2B маркетплейс, рубрики стройка, металлопрокат, промышленность, трафик 4-5 млн в месяц с внешним), Фит Лид (блогинговое агентство и партнёрка, fit-lead.ru), Искра (распаковка личности и архетипы, uiskra.ru, не путать с клиентом 1skra.ru), СММ Агент (бот и сайт помощи с постами, сммагент.рф). Структура контуров исправлена: работа 1 это Пульс цен целиком (календарь Outlook), работа 2 это Фит Лид Групп с тремя брендами (её Битрикс). Заведены проекты СММ Агент и Искра, задачи из Битрикса разложены по брендам.
task
13.6 Материалы, куски и поиск по смыслу
Второй этап по плану: таблица материалов (вид, откуда, файлы, состояние, связи), нарезка длинных текстов на куски, векторы, страница «Знания» у проекта, пересчёт того что накопилось.
task
13.7 Точки входа: телеграм, встречи, веб
Третий этап: голосовое и файл в знания через Лию с подтверждением проекта, идеи со встречи кнопкой в материалы, перетаскивание файлов на странице проекта. Файлы до 50 МБ у себя, видео ссылкой с расшифровкой звука.
task
13.8 Инструменты для Клода
Четвёртый этап: найти проект, бриф проекта, искать в знаниях, положить материал, кусок расшифровки. Та же база, что у Лии.
task
13.9 Сводка дня и недели — форма старта планирования
✓ GET /api/day/brief: встречи и задачи по дням, вместимость по рабочим блокам режима, просроченное, задачи без времени по контурам, сколько ждёт разбора, состояние паспортов. Считает код, не модель. На живых данных показала правду: неделя вперёд пустая, 83 пункта на разбор, 58 задач без времени, у всех приоритет средний и 30 минут по умолчанию, рабочие блоки режима заведены без дней недели.
task
13.10 Страница «Раскидать» для быстрой разметки
✓ /sort: один пункт крупно, проекты цифрами на клавиатуре, пробел отложить, ноль выкинуть. Задачи без проекта и входящие одной очередью; входящее уходит в бэклог проекта. Сделана под просьбу владельца разметить сотню записей за раз. Плюс разложены 14 бесхозных задач, у которых проект понятен из названия.
task
ревьюS14 · С14 · Люди, телеграм, ритуал планирования7/7

Цель: Знания о людях, подключённый основной телеграм и повторяемый формат планирования дня

14.1 Скилл plan-day: формат планирования упакован
✓ ~/.claude/skills/plan-day: сводка сервера, поиск дел в бэклоге чтобы не плодить дубли, правила раскладки (мелочи в один блок, тяжёлое крупным куском вдали от созвонов, встречи с пометкой, проект обязателен), структура контуров и способ добыть токен.
task
14.2 Карточки людей: сущность, страница, поиск по имени
✓ Таблица people (миграция 030), API с методом «дописать» (добавляет строку, не перезаписывает — знание растёт по ходу), поиск по любой форме имени, страница /people с полями «как ставит задачи и что ждёт», «что любит и не любит», «как с ним говорить».
task
14.3 Основной телеграм подключён, только чтение
✓ Telethon на cfru, сессия /opt/aitodo-tg/main.session (600, папка 700), доступы приложения и прокси переиспользованы у intent-radar. Отправки в скриптах нет намеренно. Разрешение в настройках Клода узкое: только эта папка. Владельцу сказано про пароль в командной строке и про отзыв сеанса в настройках телеграма.
task
14.4 Папки телеграма = контуры
✓ Пульс цен 18 чатов (работа 1), Фитлид 18 (работа 2), Клиенты 52 (своё), My vision 4. Принадлежность сообщения к контуру теперь определяется кодом по папке, а не догадкой. Записано в память telegram-main-account.
task
14.5 Карточки на 62 человека из адресной книги
✓ Создано 58, четыре существующие дополнены (Нина, Артём, Мария, Настя) без дублей. Имя и роль взяты из того, как владелец сам подписал контакт («Денис Верстальщик Пульс»), контур из папки. Ничего не выдумано: где роли нет — пусто.
task
14.6 Сканер «висит без твоего ответа»
✓ Детерминированное правило вместо поиска задач моделью: тебя упомянули или ответили на твоё сообщение, и после этого ты в чате не писал. По двум рабочим папкам нашлось всего 2 висяка, из них по делу один (Нина сохранила обратную связь клиента). Вывод: 106 непрочитанных в SMM-чате — это контент и согласования, а не потерянные задачи; настоящая груда в самом АИТОДУ (83 на разбор, 58 без времени).
task
14.7 Медитация 20 минут ежедневно
✓ Была 15 минут (08:30–08:45). Стало 08:25–08:45, пять минут взяты у прогулки; категория переведена в health. Режим забит без зазоров с 05:00 до 21:00, свободного места не было.
task
ревьюS15 · С15 · Склад материалов и сборщик из телеграма52/53

Цель: Знания по проектам складываются и находятся: файлы, разборы, идеи с привязкой к проекту и источнику

15.1 Таблица материалов и куски для поиска
✓ Миграция 031: materials (вид, состояние, проект, источник, автор, когда сказано, файлы, метки) и material_chunks с колонкой вектора на 1536. Резка длинного текста с перехлёстом 150 знаков, чтобы фраза на стыке не пропадала. Отдельно от задач и входящих намеренно: задача закрывается и уходит, знание живёт годами.
task
15.2 API склада: положить, найти, разложить
✓ POST /api/materials (повторный сбор того же источника дубля не создаёт — проверено), GET со фильтрами по проекту, виду и состоянию, GET /search с жёсткими границами проекта (по названию или алиасу), PATCH с пересборкой кусков при правке текста, DELETE.
task
15.3 Сборщик знаний из телеграма
✓ tg-harvest.py: файлы, ссылки и длинные разборы из чатов рабочей папки. Только читает и печатает json — записью занимается вызывающая сторона, поэтому скрипт на сервере физически ничего не меняет. Второй проход отбора отсекает поздравления, приветствия, файлы без имени и подписи, ссылки без пояснения.
task
15.4 Первый сбор по Фит Лиду
✓ 45 дней, 18 чатов, 1821 сообщение. Кандидатов 326, после отбора залито 264 материала в проект Фит Лид с автором, датой и ссылкой на сообщение. Проверено поиском: «амбассадорская» находит pdf программы от Нины, «KPI» — факт Таргоша, «отпуск» — график от Галины.
task
15.5 Поймана своя же ошибка в разборе аргументов
✓ Первый прогон дал 2 кандидата вместо 326: флаги вида «--days 45» через пробел превращались в единицу (int(True)). Разбор аргументов переписан, принимает оба вида. Урок: молчаливый недосбор выглядит как «данных нет».
task
15.6 Векторы для поиска по смыслу
Два подтверждённых аргумента на живых данных. Первый: пересказ не находится — «аутрич блогерам» не даёт «блогеры под задачи бренда». Второй: падежи — «матрица боли» не находит «матрицу боли», потому что поиск по подстроке. Нужен проход, считающий векторы кусков (text-embedding-3-small) и поиск по близости внутри границ проекта. Сейчас в складе около 340 материалов, прогон стоит порядка 20-30 копеек. Ждём согласия владельца.
✓ Сервис material_search: векторы пачками по 64 куска (не по одному тексту на запрос), поиск GET /api/materials/ask по косинусному расстоянию с порогом 0.62 и жёсткими границами проекта. Посчитано 366 кусков, около 30 копеек. Проверено на тех же запросах, что раньше давали ноль: «аутрич блогерам» находит список блогеров, «матрица боли» находит «матрицу боли» (падежи), «что Нина говорила про распаковки» — нужное знание с цитатой, «кто в отпуске в сентябре» — график от Галины.
task
15.7 Скачивание файлов в склад
Сейчас у файла записано только имя, тип и размер — сам файл остался в телеграме. По решению владельца: до 50 МБ качаем к себе, видео ссылкой. Тогда можно будет искать по содержимому pdf и таблиц.
✓ Лимит загрузчика поднят с 10 до 50 МБ по решению владельца, добавлены типы csv, pptx, ppt, rtf. Скачано и залито 76 документов (pdf, xlsx, docx, md), 60 привязаны к материалам; видео (.mov, .mp4) оставлены ссылкой, как договорились. Папка uploads проброшена на хост, файлы переживают пересборку. Ловушка Telethon: пользователя по одному номеру он не отдаёт, пока сессия его не видела — 30 файлов из 79 не скачались, лечится словарём сущностей из get_dialogs.
task
15.8 Голосовые превращаются в знания и задачи
✓ Ручка POST /api/voice/from-audio: расшифровка через Groq, материал вида «расшифровка» с автором и датой, знания отдельными карточками (искать «что Нина говорила про брендбук» надо по мысли, а не по всей записи), задачи только предлагаются. Повторно тот же голосовой не расшифровывается — проверка по ссылке на сообщение, на двух записях она сработала и деньги не ушли.
task
15.9 Первый прогон голосовых Фит Лида
✓ 23 голосовых за 60 дней (21 от Нины, 2 от Кирилла), 18 минут, около 4 рублей с согласия владельца. Расшифровано 21, две уже были в складе. Вынуто 54 знания, предложено 18 задач. По решению владельца заведено 10 свежих задач (с 27.08) в бэклог Фит Лида со ссылкой на материал и автором; старые и два мутных пункта («оставить договоры в подвешенном состоянии») остались только знанием.
task
15.10 Голосовые в сборщике классифицировались неверно
✓ Файлы без имени по 0.1-0.4 МБ от Нины отбор выкидывал как «скриншоты без подписи» — на деле это были голосовые. Признак голосового: у звукового вложения флаг voice. Теперь голосовые собираются отдельным проходом.
task
15.11 Сбор по Пульс цен и Клиентам
✓ Пульс цен: 53 кандидата, залито 50 материалов. Клиенты: 52 кандидата из 5 живых чатов (остальные 47 за 45 дней молчали), залито 34 с раскладкой по клиентским проектам по названию чата. Голосовых в этих папках почти нет — одно сообщение на 70 чатов, значит голосом общается именно Нина.
task
15.12 Люди: роли ключевых сотрудников
✓ Со слов владельца: Нина Николаевна Тарасова — генеральный директор Фит Лид, Кирилл Уланов — креативный директор (ведёт соцсети СММ Агента и Искры), Артём Таргош — диджитал-маркетолог, Михаил Соколов — ИТ-директор, Mari — СММ (ведёт соцсети Фит Лида, присылает посты на согласование).
task
15.13 Оценка размера задачи правилом
✓ Сервис task_sizing: размер по действию в названии — «спросить» 15 мин, «встретиться» 30, «выяснить почему» 60, «сделать с нуля» 120. Подсказка едет в задачах, входящих и сводке дня; своя оценка человека её перебивает. На 99 живых задачах: 11 мелких, 16 встреч и правок, 34 средних, 38 крупных. Раньше у всех стояло 30 минут по умолчанию, из-за чего вместимость дня считалась по числу, которого никто не ставил.
task
15.14 Вместимость дня и неделя в раскладке
✓ В «Спланировать день» полоса: занято из вместимости, при переборе краснеет, под ней рабочие окна режима. Дней стало семь вместо трёх. Рабочим блокам режима проставлены пн-пт (были «каждый день»), поэтому суббота и воскресенье больше не считаются рабочими — до этого система думала, что в воскресенье 9,5 рабочих часов.
task
15.15 Размер задачи клавишей в «Раскидать»
✓ Под пунктом четыре кнопки размера, клавиши q w e r, подсказка предвыбрана. Проект ставится цифрой и уносит размер тем же запросом: если подсказка верна — одно нажатие вместо двух.
task
15.16 Неделя разложена по нагрузке
✓ Владелец назвал девять результатов недели (навесы закрыть, КЗ добить и встретиться, дашборд ПП в ПЦ, дашборд Фит Лида, автопостинг, интервью по СММ Агенту, принять человека от Насти, продлить Искру, начать стратегию). Разложено 24 задачи на вт-пт по 300-330 минут в день при вместимости 570 — остаток под входящие встречи. Создано 5 задач, которых в бэклоге не было. Ловушка: «Литген» в названиях задач это расшифровка слова «лидген», из-за неё задача 402 про приём человека от Насти сначала не нашлась.
task
15.17 Голосовые Нины: расшифровка и знания
✓ Расшифровано 10 голосовых (12 минут, около рубля): 6 сегодняшних от Нины, 3 вчерашних, 1 от Артёма. Создано 46 материалов: 10 расшифровок и 36 знаний. Прогон пачкой повторяет ручку /api/voice/from-audio, но без HTTP — файлы лежат на сервере, а ручка принимает по одному. Содержание: механика фикс плюс токены, 62 подписчика чата и откуда пришли, безопасность данных при загрузке, идея с петличкой, конкурент Трэдси.
task
15.18 Разбор голосового не знал, кто говорит
✓ Запись Артёма «Саш, приветствую… я вряд ли смогу выйти» модель озаглавила «Саша не сможет работать»: она принимала обращение за имя говорящего. Теперь имя автора идёт в запрос отдельной строкой, и в промпте сказано, что обращение в начале — это собеседник. После правки заголовок стал «Артём не сможет работать сегодня в полную силу». Проверено переразбором всех десяти записей: исправилось 7 заголовков из 10.
task
15.19 Встречи и задачи из чатов во Входящие
✓ Новый читатель tg-agenda.py на cfru (только чтение): отбирает сообщения с признаками встречи и поручения по словам и по времени в тексте — сборщик знаний их не брал, он ищет длинные разборы. За 3 дня 37 сообщений, из них 9 адресованы владельцу, разложены во Входящие с автором, датой и цитатой. Плюс 17 содержательных сообщений в склад сборщиком знаний.
task
15.20 Скрипты писали в тестовую учётку
✓ Все скрипты захода запускались с user_id 1 (newuser@example.com), а владелец — user_id 6 (logonchek@mail.ru). 63 материала и 18 входящих легли не в тот кабинет. Обнаружено сверкой: склад показал 63 материала вместо 424. После разрешения владельца перенесено 48 материалов и 18 входящих; 15 остались в тестовой учётке как дубли уже имеющегося. Побочный эффект ошибки: три вчерашних голосовых Нины расшифрованы повторно, дедуп проверял чужую учётку. ВПРЕДЬ: user_id владельца в AITODO — 6, не 1.
task
15.21 Поиск по смыслу отдавал ссылки вместо ответа
✓ На выросшей базе (472 материала) «почему Артём не работает» находило его же ссылку на workspace.ru с почтой. Причина: кусок из ссылок и реквизитов смысла не несёт, но вектор к нему снисходителен. Первая попытка (порог по виду материала и длине тела) причину не поймала — списком ссылок оказывалась и «наработка». Рабочее правило: доля русских букв в куске меньше половины — порог ужесточается с 0.62 до 0.40. Проверено на 9 вопросах: 8 отвечают верно, амбассадорская программа и KPI по-прежнему находятся.
task
15.22 База знаний по проектам в складе
✓ Разбор встречи по документообороту Фит Лид (27 КБ) нарезан на 15 материалов по разделам и залит в склад вместе с полной расшифровкой (75 КБ), ссылка kb:fitlead/документооборот. Инструменты вынесены в репозиторий: backend/scripts/kb_cut.py (нарезка по разделам, темы раздела в название, шапка с темой в тело) и kb_store.py (заливка с дедупом по source_ref, владелец по почте, проект по названию, досчёт векторов). Повторный залив обновляет материалы, а не плодит копии — проверено тремя прогонами, всего материалов осталось 488.
task
15.23 Скилл knowledge-base
✓ ~/.claude/skills/knowledge-base/SKILL.md: куда складывать знания и как достать. Триггеры на добавление («добавь в базу знаний по проекту») и на вопросы («как в <проекте> сделать X», «что говорил <человек> про X»). Внутри: карта где что лежит (склад — источник истины, папки на диске — исходники), железные правила, команды нарезки и заливки, чем проверять. README базы знаний Фит Лида переписан под ту же логику.
task
15.24 Поиск в складе: слова плюс смысл
✓ Чистый векторный поиск на 488 материалах отвечал неверно на 4 вопроса из 10: «как сделать договор» отдавало раздел «Финансы» и материал со словом «договорённости», «кто отвечает за скаутинг» уходило в мусор. Добавлен гибрид: буквальные совпадения слов вопроса идут первыми, смысл добирает остальное. Слова берутся префиксами по 6 букв («догово» находит договор и договоры), аббревиатуры (ДО, КП, РИМ, CMO) ищутся по границам слова, название проекта из слов вопроса выбрасывается, совпадение в заголовке весит больше. После правки все 10 вопросов отвечают верным материалом первым.
task
15.25 Названия материалов базы знаний
✓ Три ошибки собственного залива, найденные проверкой поиска: (1) префикс «ДО» у каждого названия сделал аббревиатуру из вопроса совпадающей со всеми материалами сразу — перенёс её в шапку тела; (2) раздел «Что на CMO повесили / договорённости» ловил заголовком вопросы про договоры — переименован в «Что поручили директору по маркетингу (CMO)», это же связало вопрос с аббревиатурой; (3) название «Маркетинг» не говорило ничего — теперь процессы раздела перечислены в названии, извлекаются из выделенного жирным с фильтром (отбрасываются даты, имена и предлоги: в АйТи попадали «14.08» и «Галя»).
task
15.26 Свой баг: import re перед from __future__
✓ При правке materials.py вставил import re выше from __future__ import annotations — это SyntaxError при импорте, а ast.parse его не ловит (позицию future-импортов он не проверяет). Файл прошёл бы проверку и упал на выкате. ВПРЕДЬ: проверять модуль через py_compile.compile(..., doraise=True), а не ast.parse.
task
15.27 Единый читатель телеграма tg-collect
✓ На cfru /opt/aitodo-tg/tg-collect.py: один проход по чатам вместо четырёх скриптов, которые каждый заново шли по истории тех же чатов. Фильтр и по папкам, и по людям (человек берётся целиком, даже если его чат вне папок). За проход раскладывает по типам: голосовое (по флагу voice, а не по расширению), файл (со скачиванием, документы до 50 МБ, видео ссылкой), повестка (признаки встречи и поручения), наработка, ссылка. Проверено на 2 днях: 13 голосовых, 4 файла, 35 повесток, 7 наработок, 7 ссылок.
task
15.28 Оцифровка файлов: file_text
✓ backend/scripts/file_text.py: pdf через pypdf, docx через python-docx, xlsx через openpyxl (таблицы в текст, не в разметку — поиску границы ячеек мешают), csv/txt/md/json как есть, rtf чисткой управляющих последовательностей. Живёт на моей машине, потому что в образе AITODO из читалок только openpyxl, а ставить библиотеки в прод ради разбора — менять прод.
task
15.29 Конвейер записи tg_apply
✓ backend/scripts/tg_apply.py в контейнере: голосовое → расшифровка + знания + задачи во Входящие; файл → вложение в uploads + материал с оцифрованным текстом; поручение → Входящее; знание → материал; встреча → задача с пометкой «встреча», но только при однозначном времени. Разбор времени проверен на 10 формулировках: «завтра в 12», «сегодня в 15:30», «в четверг в 10:00», «05.09 в 14:00» ставятся; «завтра в первой половине дня», «часа в 3-4», «в 9:05» без дня, «на неделе», «в 25:00» уходят во Входящие. Флаги --dry и --skip-voices (расшифровка единственная платная часть). Прогон записал 8 материалов и 17 входящих.
task
15.30 Скилл telegram-sync
✓ ~/.claude/skills/telegram-sync/SKILL.md: конвейер из трёх шагов с объяснением, почему они на разных машинах, схема бизнес-процесса по типам содержимого, железные правила (голосовое по флагу voice, имя говорящего в разбор, встреча только при однозначном времени, свои реплики не поручение, поручение во Входящие а не в задачи, идемпотентность, гейт на расшифровку, латиница в серверных путях, владелец user_id 6), команды запуска, что проверять после прогона и чего конвейер не делает.
task
15.31 Оцифровано 50 файлов из склада
✓ kb_digitize.py (--list и --apply в контейнере) плюс kb_digitize_local.py (качает одним архивом, извлекает текст). Из 61 материала-файла оцифровано 50, посчитано 691 куск. Не читаются 11: шесть pdf-сканов без текстового слоя (кейсы, СНИЛС), две картинки png, одна презентация pptx, один битый pdf — им нужен OCR, его нет. Материал получает пометку, почему пусто, и повторный проход его не берёт.
task
15.32 Свои грабли на путях
✓ Дважды подряд не собирался архив для оцифровки. Первая причина: кириллица в путях через ssh портится, tar молча не находит ни файла (четвёртый раз за проект) — серверные пути теперь только латиницей. Вторая: url вложения бывает «/api/uploads/6/имя», а я вырезал только «/uploads/», из-за чего путь превращался в «/api6». Плюс docker cp оказался лишним: каталог загрузок смонтирован с хоста, файлы видны там напрямую.
task
15.33 Расшифровка голосовых переведена на локальный GigaAM
✓ Гонял голосовые через облачный Groq, хотя у владельца есть бесплатный локальный GigaAM — и в моей же памяти записано, что Groq turbo это Whisper, а он на русской разговорной речи негоден. Новый asr-local/voices_local.py переиспользует модель и нарезку по паузам из transcribe.py, но для одной дорожки: у голосового один говорящий, известный из чата. Сто секунд записи за пять секунд работы, ноль рублей. В tg_apply.py облако осталось запасным путём, если локальный шаг не запускали.
task
15.34 Сравнение GigaAM и Whisper на живых записях
✓ Прогон трёх голосовых обоими движками. GigaAM точнее в разговорной речи: «если тебе там не впадлу можешь поднарезать задачек» против whisper-овского «если те там не впадал можешь под нарезать задачи», «истина вскроется» против «истинно вскроется». Whisper лучше в терминах и пунктуации: «Tone of Voice, в его брендбуке» против «на фойсе ну в его брейнбуке», «Трэдси» против «трев треци». Вывод: берём GigaAM, пунктуация не нужна (текст идёт в разбор модели), названия чиним словарём.
task
15.35 Словарь названий после расшифровки
✓ В voices_local.py словарь замен: tone of voice, брендбук, Трэдси, СММ Агент, Фит Лид, Пульс цен, ЛидФордж, Контент Завод, nano-banana, CPA, CPP, KPI, Вордстат, Инстоплюс. Границы слова слева, чтобы не срабатывало внутри других слов. Правило кодом, а не моделью: список названий известен и меняется редко, а подсказку GigaAM не принимает. Проверено на шести формулировках из живых записей.
task
15.36 Прогон конвейера целиком на локальной расшифровке
✓ 13 голосовых расшифрованы на машине владельца бесплатно, из них 6 новых записаны: 23 знания и 4 задачи во Входящие, ноль обращений к облаку. В складе 525 материалов. Скилл telegram-sync переписан на четыре шага (собрать на cfru, оцифровать локально, расшифровать локально, записать в контейнере) с объяснением, почему они на разных машинах.
task
15.37 Свои грабли: невидимые символы от патча
✓ Патчил словарь регулярок через python-скрипт с двойным экранированием, и в файл уехало 56 символов backspace вместо «\\b» — словарь молча не срабатывал ни на одном случае, а Edit не находил строку для замены. Потом обрезка блока по первой «]» разрезала регэксп «[еи]» и сломала файл. ВПРЕДЬ: словари регулярок писать через Write целиком, а не патчить экранированием внутри heredoc.
task
15.38 Баг: Лия пять раз написала про одну встречу с Битрикса
✓ Причина найдена на живых данных портала, а не угадана. «Демо спринта» — повторяющаяся встреча (RRULE: каждые 2 недели по средам до 31.12). Битрикс отдаёт три экземпляра с ОДНИМ ID 10551 и разными DATE_FROM, у всех одинаковый PARENT_ID и одинаковый DATE_FROM_TS_UTC от первого экземпляра. Код ключевал связь по ID, а отпечаток считал по дате — поэтому каждое следующее повторение выглядело переносом того же события. ВТОРОЕ, ХУДШЕЕ СЛЕДСТВИЕ: задача одна и перезаписывалась на последнее обработанное повторение, то есть стояла на 30.09, а встреч 02.09 и 16.09 в календаре не было вообще. Синк бежит каждые 5 минут, поэтому это происходило постоянно.
task
15.39 Ключ связи по экземпляру встречи
✓ В bitrix.py добавлены repeats(), instance_key() и repeat_words(). У повторяющегося события ключ теперь «<ID>@<ДД.ММ.ГГГГ>» — дата без времени, иначе сдвиг внутри дня заводил бы новую задачу вместо переноса старой. В bitrix_sync.py синк ключует по экземпляру, поэтому каждое повторение получает свою задачу в календаре. Уведомление про серию идёт один раз, с описанием периодичности человеческими словами («каждые 2 недели по средам»), а не по одному сообщению на повторение. Проверено на живых данных портала: уникальных ключей стало 5 вместо 3, уведомлений 3 вместо 5.
task
15.40 Скрипт починки связей bitrix_repair
backend/scripts/bitrix_repair.py: переводит старые связи событий на ключи экземпляров, спрашивая у портала, какие события повторяющиеся. Ничего не создаёт — остальные повторения синк заведёт сам. Есть --dry. ЗАПУСКАТЬ ТОЛЬКО ПОСЛЕ ВЫКАТА правки: если переименовать связь при старом коде, синк не найдёт её по ID и через пять минут создаст вторую задачу.
✓ Прогнан после выката: связь 10551 переведена на 10551@30.09.2026, следующий синк завёл повторения на 02.09 и 16.09. В календаре три «Демо спринта» (02.09, 16.09, 30.09), каждое со своим ключом. Повторный прогон синка дублей не создал — проверено сравнением до и после.
task
15.41 ВЫКАТ на aitodo
✓ Выкачено по явному «да»: оценка размера задач (task_sizing + подсказка в задачах, входящих, сводке), полоса вместимости дня и семь дней в «Спланировать день», размер клавишей в «Раскидать», имя говорящего в разборе голосовых, порог поиска по доле русских букв, гибридный поиск слова+смысл, ключ экземпляра для встреч Битрикса, скрипты базы знаний и телеграм-конвейера. Перед копированием сверил серверные и локальные версии: все расхождения — только мои правки, чужого не затёрто; заменяемые файлы сохранены в /opt/TODO-New/.backup-20260902. Проверка на живом коде: поиск про договор отдаёт нужный раздел первым, подсказки размера считаются, выходные дают 0 рабочих минут, три встречи Битрикса на сегодня на месте.
task
15.42 Сборка образа была сломана до выката
✓ docker compose build backend падал не на моих правках: в requirements.txt закреплён lancedb==0.5.4, которого больше нет в PyPI. Поднять до доступной версии нельзя — от 0.14 требуется pyarrow новее закреплённого 15.0.0, pip даёт ResolutionImpossible. Решение: lancedb закомментирован, а импорт в app/services/memory/lancedb_store.py сделан мягким с понятной ошибкой при обращении. Регресса нет: эта ветка и раньше падала, но на другом — context_window_manager импортирует несуществующий app.models.conversations (проверено в старом образе). Базы .lance на сервере не было ни разу.
task
15.43 Память Лии на векторах не работает
app/services/memory/enhanced_memory_service.py не импортируется: context_window_manager тянет app.models.conversations, которого в проекте нет. Плюс lancedb больше не ставится (конфликт pyarrow). Решить одним из двух: либо завести отсутствующую модель и поднять pyarrow, либо перевести память Лии на pgvector — он в проекте уже работает и на нём живёт поиск по материалам. Второе дешевле и убирает лишнюю зависимость целиком.
task
15.44 Прогон конвейера телеграма: задачи на сегодня
✓ Сбор за 2 дня по трём папкам: 12 голосовых, 13 файлов, 41 сообщение с повесткой. Голосовые расшифрованы локально бесплатно (все 12 оказались уже в базе с прошлого прогона). Записано: 9 материалов-файлов, из них 6 оцифрованы, 3 знания, 5 входящих. В складе 547 материалов. Найдено то, ради чего просили: поручение Дениса из Пульс цен от 02.09 со словом «завтра» — три пункта в одном сообщении (аналитика за август по регистрантам, SEO-контент в блоге, результаты эксперимента по табам). Разложены на сегодня в свободные окна: 11:00, 15:45, 16:45, плюс ответ Дмитрию про созвон в 09:15. День занят 465 минут из 570.
task
15.45 Конвейер ставил встречу в прошлое
✓ Сообщение «Сегодня в 13 будет демо» от 02.09 при сборе за два дня разбиралось как 02.09 13:00 и ставилось в календарь, хотя уже 03.09. Добавлена отсечка: встречу раньше «сейчас минус 2 часа» в календарь не ставим, пишем в отчёт «встреч в прошлом». Два часа запаса — чтобы начавшуюся встречу всё же учесть.
task
15.46 Проверка дубля встречи ловила только точное время
✓ У встречи, которой сняли время руками, scheduled_start пустой, и дубль по одному времени не находился: «Демо спринта» на 02.09 оказалась без времени (владелец, видимо, перетащил её в «Без времени»), и конвейер готов был поставить рядом вторую встречу на 13:00. Теперь сверяем и время, и название в пределах дня.
task
15.47 Каналы-рассылки лезли в повестку
✓ Канал «Пульс цен I Про бизнес» с подборкой «главные деловые мероприятия сентября» дал два входящих как встречи: фильтр принял «8 сентября» за время. В tg-collect.py добавлен признак broadcast — из каналов берём только знания и файлы, повестку не берём, короткие реплики из канала пропускаем совсем. Два мусорных входящих помечены выкинутыми, исходник сохранён.
task
15.48 Первая запись в календарь Битрикса
✓ До сих пор обмен с порталом был только на чтение. По прямой просьбе владельца поставлены два блока с названием «Встреча» на 13:00-14:00 и 14:00-15:00 (события 10562 и 10563, секция календаря 126, пользователь портала 195). Название без темы намеренно: в дне владельца задачи первой работы и клиентов, их названия в календаре второй работы светить нельзя. Скрипт backend/scripts/bitrix_put_meetings.py, автоматика его не зовёт — только руками по просьбе. Права проверены заранее: scope содержит calendar, calendar.event.add доступен.
task
15.49 Записанные события сразу связаны с задачами
✓ Без связи обмен через пять минут увидел бы свои же события как чужие, завёл рядом две задачи и переименовал их в «Встреча». Поэтому после создания сразу пишем bitrix_links с ключом экземпляра и правильным отпечатком. Проверено прогоном синка: новых или перенесённых встреч 0, в дне по-прежнему «Тезисы для вебинара по ИИ» и «Перезапуск Контент-завода» со своими названиями.
task
15.50 Две встречи в расписании и разбор наложения
✓ Встречи от Ольги Вакенгут поставлены на 13:00 и 14:00, проект Пульс цен. Приёмка дашборда ПП стояла на 14:00 и уехала на 17:15 — рабочий блок идёт до 18:30. Ловушка: искал задачу для сдвига по точному названию, а в базе оно длиннее («…: сверить цифры и закрыть»), сдвиг молча не срабатывал; теперь поиск по началу названия. Встреча в 13:00 попадает на обед и сон в режиме дня — рабочих блоков там нет, владельцу это стоит знать.
task
15.51 Задачи по договору Еламы и ссылке от Алексея
✓ Две задачи поставлены с контекстом внутрь, чтобы не искать заново. Договор Еламы в ДО (04.09 11:00, 60 мин) несёт выжимку из базы знаний: альбом бизнес-процессов, запуск по шаблону, матрица согласования по видам работ вложена отдельным документом, действия «снять замечания», «организуй подписание», «размести в архив», договоры до приказа лежат в проектном офисе. Проверка ссылки (03.09 09:30, 15 мин) несёт саму ссылку. Заодно нашлось, что в бэклоге висит задача 341 «Посмотреть еламу по Фит лиду» — в описании сказано закрыть её этой, если про то же.
task
15.52 «Ссылки от кого-то там» опознаны поиском по телеграму
✓ Владелец не помнил, от кого ссылки; в складе их не было, потому что чат Алексея Энгеля вне собираемых папок. Нашёл прямым чтением чатов по имени: 31.08 06:06 Алексей Энгель прислал ссылку вида e1cib/data/Справочник.ВнутренниеДокументы?ref=... — она внутренняя для клиента 1С и в браузере не открывается, отсюда и вопрос. Важнее: документ передан владельцу на согласование 31.08 и висит третий день, а 27.08 Алексей присылал два файла по БП лидогенерации и ждал обратной связи.
task
15.53 Сборщик читал ботов: Parser Fit lead лил заявки во входящие и склад
За 15-19.09 бот дал 89 «наработок» и 20 входящих, больше, чем Нина. Папки были верные (Личные, Фитлид, Пульс цен, Клиенты), бот сидел внутри Фитлида.
✓ tg-collect.py: диалог с entity.bot пропускается целиком. Проверка: сбор за 3 дня, парсера нет, люди на месте (Нина 23, Команда 12). 18 входящих от парсера → dropped. 97 материалов от парсера в складе ждут «да» на удаление. Бэкап tg-collect.py.bak.20260920.
bug
ревьюS16 · С16 · Расшифровка на GigaAM и честный разбор8/9

Цель: Убрать Whisper как причину каши в расшифровке, перенести распознавание на машину владельца, научить разбор отличать сделанное на встрече от взятого в работу

↑ 16.1 Локальная расшифровка GigaAM на машине владельца
Whisper ломает лицо глагола: «доработаю» слышит как «доработают», отсюда задачи уезжают не на того. Проверено 31.08 на встрече 11: ни нормализация звука, ни полная large-v3, ни словарь имён не помогли, помогла только смена вендора. GigaAM (Сбер) на RTX 3050 даёт верный текст, час записи считает за 4 минуты, стоит ноль. Ставится в постоянную папку на диске E (на C всего 4,8 ГБ свободно), venv 4,6 ГБ, модель v2_rnnt 448 МБ. Нарезка по паузам silencedetect -45dB, куски до 25 секунд: модель слушает окнами по 30.
✓ Расшифровщик доведён до инструмента: asr-local/transcribe.py принимает папку встречи или пару дорожек, режет по паузам на куски до 25 секунд, отдаёт json с ролями и временем. Окружение с моделью GigaAM v2_rnnt лежит в asr-local/venv, модель 449 МБ в кеше. Проверено: час записи считается за 4 минуты, лица глаголов на месте.
task
↑ 16.2 Сервер принимает готовую расшифровку от виджета
Сейчас виджет заливает 17 МБ звука, сервер расшифровывает. После переезда на GigaAM считает виджет, на сервер уходит готовый транскрипт с таймкодами и ролями. Нужен эндпоинт приёма и запасной путь: компьютер выключен или запись со стороны — сервер расшифровывает сам.
✓ Сервер: эндпоинт POST /api/meetings/transcript принимает готовую расшифровку, звук не заливается вовсе. Общая часть разбора вынесена в digest_into_meeting и делится с прежним путём через звук. Виджет: перед отправкой пробует расшифровать локально, не вышло (нет окружения, упало, пусто) — идёт прежним путём и пишет причину файлом рядом с записью. Проверено вживую: встреча из готового текста собралась, движок записан как gigaam/v2_rnnt.
task
16.3 Кнопка «разобрать точнее» через ElevenLabs Scribe
Scribe даёт максимум: 8483 слова против 8207 у GigaAM, пунктуацию, точные термины, таймкоды по каждому слову и диаризацию. Разбор с него вышел богаче: 13 задач и 9 решений против 7 и 3. Цена 34 рубля за встречу, поэтому не по умолчанию, а кнопкой для важных встреч. Ключ есть в cz-core/.env на cfru, для AITODO нужен свой.
✓ Движок Scribe добавлен в transcription.py, ключ взят с cfru и прописан в .env aitodo. Эндпоинт POST /api/meetings/{id}/rehear принимает дорожки, переслушивает и пересобирает разбор, отметки об уехавших во Входящие задачах сохраняются. В виджете кнопка «Разобрать точнее» спрашивает второй раз и предупреждает про 34 рубля, чтобы списание не случилось с одного случайного нажатия.
task
↑ 16.4 Полный текст расшифровки отдельным файлом
Просьба владельца 31.08: рядом с саммари и синопсисом класть файл со всей расшифровкой текстом, чтобы искать по ключевым словам. Формат txt или md, с таймкодами и ролями в начале строки.
✓ Сервер отдаёт полный текст расшифровки в /meetings/{id}/docs, виджет кладёт его файлом «расшифровка.txt» рядом с саммари: время, кто говорит, что сказал. Виджет пересобран (1.1.1) и переустановлен на машине владельца 31.08, приложение запущено и работает. Файл появится при следующей записанной встрече. Для встречи 11 файл собран вручную и лежит в её папке.
task
↑ 16.5 Модель разбора: уйти с deepseek на Gemini
deepseek-v4-flash уплывает в иероглифы: на прогоне 31.08 одно окно из восьми пришлось переспрашивать по-русски, на встрече 26.08 девять задач из сорока семи пришли по-китайски. Замена на gemini-2.5-flash-lite стоит 0,69 рубля за встречу вместо 0,41, на gemini-2.5-flash 3,5 рубля.
✓ DEFAULT_MODEL = google/gemini-2.5-flash. Попутно вскрылись две вещи: фильтр provider по квантизации весов давал у Gemini 404 (теперь применяется только к открытым моделям), а включённое размышление съедало лимит ответа на длинных окнах (для google выключено). Иероглифов на прогоне больше нет.
task
↑ 16.6 Сквозная ревизия: что уже сделали прямо на встрече
Главная жалоба владельца: разбор пишет «договорились сделать X», когда X сделали прямо на встрече. Причина в архитектуре: встреча режется на окна по 8 минут, окна разбираются независимо и не знают друг о друге. Нужен проход после сборки: собранный список задач плюс сжатая лента всей встречи, один вопрос модели — что выполнено здесь же, что отменено, что переформулировано позже.
✓ revise_actions: после сборки один проход по всей встрече, у каждого пункта появилось состояние «в работу / сделали на встрече / передумали / не задача» и объяснение почему. Во «Входящие» едет только «в работу», остальное остаётся в документе отдельным разделом «Закрылось на самой встрече». На встрече 11 отсеклось 4 пункта из 16. Модель путала обещание «сделаю завтра» с исполненным — добавлена проверка кодом по словам будущего времени.
task
16.7 Склейка повторов между списками
Сейчас повторы ищутся внутри каждого списка отдельно. На встрече 31.08 выгрузка Excel вышла тремя задачами плюс двумя решениями про неё же, почта Sensai попала и в задачи, и в требующие подтверждения. Нужна склейка между задачами, решениями, подтверждениями и открытыми вопросами.
✓ Задача главнее: то, что уже есть в списке задач, убирается из требующих подтверждения и из открытых вопросов. Порог повтора решений поднят с 0.72 до 0.88 — прежний выкашивал все решения подряд.
task
16.8 Сроки задач отдельным проходом
В разборе 31.08 почти у всех задач срок пустой, хотя в разговоре звучали «завтра» и «в ближайшие дни». Вытягивать сроки отдельно по репликам вокруг задачи.
✓ Сроки вытягиваются тем же сквозным проходом: он видит всю встречу и берёт срок там, где он прозвучал, даже если это далеко от самой задачи. На встрече 11 подтянулись «завтра» и «ближайшие дни», раньше было пусто.
task
↑ 16.9 Проверка на живой встрече
После правок 31.08 записать обычную рабочую встречу и сверить пять вещей. 1) Расшифровка идёт на этой машине: в карточке встречи движок gigaam/v2_rnnt, а не groq/whisper. Если стоит whisper, значит локальный путь не сработал: смотреть файл «расшифровка-не-удалась.txt» в папке встречи. 2) Лица глаголов на месте: «доработаю», а не «доработают». 3) Сделанное прямо на встрече не висит задачей: такие пункты идут в разделе «Закрылось на самой встрече», во Входящие не едут. 4) В папке лежит «расшифровка.txt» со всей встречей текстом. 5) Сроки: «завтра», «на днях» подтянулись в задачи. Кнопку «Разобрать точнее» проверить отдельно на одной встрече: списывает около 34 рублей, спрашивает подтверждение вторым нажатием.
check
В РАБОТЕS17 · С17 · Планирование месяца и недели (скилл plan-horizon)26/35

Цель: Скилл plan-horizon: за один разговор KPI месяца и задачи недели превращаются в спринт AITODO с подзадачами, оценками, вложениями из склада и напоминаниями. Живёт над plan-day: он про «что и зачем», plan-day про «в каком часу». Решения владельца 06.09.2026: месяц = спринт проекта («Сентябрь · Фит Лид», цель = KPI); KPI владелец скидывает текстом при планировании; галка «через ИИ» на задаче отправляет её в очередь Рубки и выводит из вместимости дня; сигнал «инфа собрана» = закрытая подзадача; интервью не больше 5 вопросов на задачу, остальное допущениями; ретро по пятницам и в конец месяца; Битрикс не трогаем; пилот на задачах недели и KPI сентября Фит Лид, сквозной путь на автогенерации КП.

↑ 17.0 Экзамены спринта до кода
Скилл spec-tests. Проверки снаружи через API AITODO и по файлу скилла: после прогона планирования существует спринт с задачами, у задач оценка и дедлайн, вложения ссылками, галка «через ИИ» видна в выборке. Каждый экзамен сначала падает на ненаписанном коде. Исполнитель экзамены не правит.
✓ backend/tests/spec/plan_horizon/{exam.py,exams_17.py}: раннер без зависимостей, 12 авто + 2 медленных + 6 руками. Первый прогон до кода 06.09: красных 12 из 12. Папка tests/spec закрыта на запись правилом в CLAUDE.md репо.
task
Есть исполняемый файл проверок, по одной на каждый критерий спринта; прогон без кода красный
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.0a
acceptance
Проверки ходят в живой AITODO по API, копии логики приложения в тестах нет
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.0b
acceptance
↑ 17.1 Скилл plan-horizon: сбор фактов, интервью, каркасы декомпозиции
Файл ~/.claude/skills/plan-horizon/SKILL.md. Семь шагов: факты без вопросов → рамка горизонта (KPI месяца от владельца, неделя из данных) → интервью по крупным задачам (что есть / кто решает и от кого зависит / что считается готовым; лимит 5 вопросов) → декомпозиция по каркасу → оценка по правилу от глагола + флаг «неопределённо» + ожидание людей отдельно от минут владельца → занесение → раскладка по часам через plan-day. Каркасы: инструмент (узнать у людей → сделать → показать и правки → тест на людях → замер), контент, кампания, процесс/люди. Паспорт задачи: <Проект>-База-Знаний/задачи/<slug>.md, потом материал в складе. Триггеры «планируем месяц/неделю» забрать у plan-day. Ход 06.09: SKILL.md написан (семь шагов, каркасы, паспорт, ретро). 17.1e зелёный; 17.1d ждёт паспорт пилота; 17.1a–c руками на пилоте.
feature
«Планируем месяц» начинается с экрана «вот что я вижу»: бэклог, спринты, встречи и расшифровки за две недели, кто ждёт ответа; вопросов до этого экрана ноль
Руками. Инструкция в выводе экзаменов (раздел «Руками»): python backend/tests/spec/plan_horizon/exams_17.py --only 17.1a
acceptance
По одной крупной задаче задано не больше 5 вопросов; остальное на экране согласования помечено «принял, что …» и правится владельцем
Руками. Инструкция в выводе экзаменов (раздел «Руками»): python backend/tests/spec/plan_horizon/exams_17.py --only 17.1b
acceptance
Задача вида «сделать инструмент» разложена на стадии: узнать у людей → сделать → показать и правки → тест на людях → замер; неизвестное стало задачами «узнать у X» с дедлайном ответа
Руками. Инструкция в выводе экзаменов (раздел «Руками»): python backend/tests/spec/plan_horizon/exams_17.py --only 17.1c
acceptance
Паспорт задачи лежит в <Проект>-База-Знаний/задачи/<slug>.md и залит в склад материалом; повторный запуск скилла через месяц читает паспорт, а не спрашивает заново
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.1d
✓ Пилот 09.09.2026: паспорт по КП-агенту в FitLead-База-Знаний/задачи/kp-avtogeneratsiya.md, в складе материал 651 (источник kb:fitlead/задачи/kp-avtogeneratsiya), векторы посчитаны. Экзамен 17.1d зелёный.
acceptance
«Планируем неделю» ведёт в plan-horizon, «планируем день» в plan-day; раскладка по часам идёт через plan-day из уже созданных задач
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.1e
✓ exams_17.py 06.09.2026: ✓ plan-horizon/SKILL.md с триггерами месяца и недели, у plan-day остался день
acceptance
↑ 17.2 Занесение плана в AITODO: спринт месяца, подзадачи, оценки, вложения
POST /api/projects/{id}/sprints, задачи с sprint_id, parent_task_id, estimate_minutes, deadline, attachments [{url,filename,type}] на материалы склада и расшифровки. Проверить, что кабинет показывает вложения ссылками (страницы склада во frontend/src/app нет, найти где живут материалы). В AITODO только действия владельца плюс задачи с галкой «через ИИ».
✓ backend/scripts/plan_store.py по контракту docs/PLAN_HORIZON.md; TaskCreate/TaskUpdate приняли parent_task_id, attachments, via_ai; PATCH /api/tasks/{id} как алиас PUT; GET /api/materials/{id} и страница /materials/[id]. Экзамены 17.2a–d зелёные.
feature
После «ок» в AITODO есть спринт «Сентябрь · Фит Лид» с целью = KPI, все задачи месяца привязаны к нему
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.2a
✓ exams_17.py 06.09.2026: ✓ plan_store.py создал спринт «Экзамен · plan-horizon» с целью KPI, 5 задач, 3 подзадачи с parent_task_id
acceptance
У каждой задачи оценка в минутах и дедлайн; у задач «узнать у X» дедлайн ответа и напоминание Лии
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.2b
✓ exams_17.py 06.09.2026: ✓ у всех задач оценка и дедлайн, у «узнать у Нины» напоминание Лии «Ждём ответ: …»
acceptance
К задаче привязаны ссылки на материалы склада и расшифровки по её теме; в кабинете ссылки открываются
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.2c
✓ exams_17.py 06.09.2026: ✓ вложение ведёт на /materials/<id>, страница 200, GET /api/materials/<id> отдаёт название
acceptance
Повторный прогон занесения не плодит дубли: задача ищется по названию в бэклоге, время ставится существующей
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.2d
✓ exams_17.py 06.09.2026: ✓ два прогона подряд: 5 задач, задача из бэклога переиспользована и получила оценку 20
acceptance
↑ 17.3 Галка «через ИИ» на задаче → выборка для Рубки
Поле на задаче (булево), чекбокс в TaskForm/TaskDetailModal, фильтр GET /api/tasks?via_ai=true. Задачи с галкой исключить из вместимости в /api/day/brief. Для Рубки долгоживущий сервисный ключ (не X-User-Id: он открыт любому, кто знает id). Итог Рубки виден в задаче: строка в описании с датой и ссылкой, статус к владельцу на проверку.
✓ Task.via_ai + миграция 032 (накатана, alembic 032); фильтр ?via_ai; вместимость в brief без галки; X-Service-Key в get_current_user_flexible (ключ в .env aitodo); POST /api/tasks/{id}/result. Галка «Через ИИ» в TaskDetailModal и TaskForm. Экзамены 17.3a–d зелёные.
feature
В карточке задачи есть галка «через ИИ»; поставил, и задача появляется в выборке /api/tasks?via_ai=true
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.3a
✓ exams_17.py 06.09.2026: ✓ via_ai в ответе, PATCH ставит, ?via_ai=true/false фильтрует, галка в TaskDetailModal
acceptance
Задачи с галкой не входят во вместимость дня в /api/day/brief
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.3b
✓ exams_17.py 06.09.2026: ✓ обычная задача +59 минут в «занято минут», с галкой занятость не меняется
acceptance
Рубка ходит в AITODO долгоживущим ключом, а не 12-часовым токеном и не заголовком X-User-Id
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.3c
✓ exams_17.py 06.09.2026: ✓ X-Service-Key из .env даёт задачи владельца, неверный ключ 401
acceptance
Итог прогона Рубки виден в задаче AITODO: строка с датой и ссылкой на результат, задача возвращается владельцу на проверку
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.3d
✓ exams_17.py 06.09.2026: ✓ POST /result: строка «Итог Рубки <дата>» со ссылкой, статус completed, задача «Проверить: …» 30 мин с дедлайном и напоминанием
acceptance
🔴 17.4 Лия: напоминания снова приходят
Бриф приходит, напоминания нет. Отправка в backend/app/services/hourly_proactive_checker.py::_check_lia_reminders (окно текущего часа, is_sent, тихие часы 22-8). Сначала диагностика: логи бэкенда, строки lia_reminders (is_sent, scheduled_for в UTC или локальном), работает ли часовой чекер, конфликт токенов двух версий бота (память lia-bot-two-versions-token-conflict). Спекулятивные фиксы запрещены. Ход 06.09: Причина (по базе и коду): отправка lia_reminders жила в hourly_proactive_checker, выключенном 20.04.2026 из-за спама; последняя запись в таблице 2026-04-20 13:03 UTC; lia-v2 таблицу не читает. Плюс модель LiaReminder держала DateTime без пояса при timestamptz в базе, из-за чего время с поясом не принималось (лог: can't subtract offset-naive and offset-aware). Сделано: send_due_reminders раз в минуту + модель timezone=True, выкачено. Ждём медленные экзамены 17.4a/17.4c.
✓ Причина по базе и коду: отправка lia_reminders жила в hourly_proactive_checker._check_lia_reminders, чекер закомментирован в app/main.py «disabled by user request 2026-04-20 — всё спамит»; последняя запись в lia_reminders 2026-04-20 13:03 UTC (290 строк, все proactive/overdue/backlog самого чекера); lia-v2 таблицу не читает. Вторая причина: модель LiaReminder держала DateTime без пояса при timestamptz в базе, драйвер отказывал времени с поясом (лог 06.09: can't subtract offset-naive and offset-aware). Фикс: services/reminder_sender.send_due_reminders раз в минуту + модель timezone=True. Чекер не возвращён. Экзамены 17.4a и 17.4c зелёные.
bug
Напоминание, поставленное на «через 10 минут», приходит в телеграм от Лии; в БД is_sent = true
Экзамен backend/tests/spec/plan_horizon/exams_17.py, медленный: python backend/tests/spec/plan_horizon/exams_17.py --only 17.4a --slow
✓ exams_17.py --slow 06.09.2026: ✓ напоминание minutes_from_now=2 доставлено в телеграм, is_sent=true через 161 с
acceptance
Причина поломки записана в doneNote с доказательством из логов или БД, а не «перезапустил и заработало»
Руками. Инструкция в выводе экзаменов (раздел «Руками»): python backend/tests/spec/plan_horizon/exams_17.py --only 17.4b
✓ Причина по базе и коду: отправка lia_reminders жила в hourly_proactive_checker._check_lia_reminders, чекер закомментирован в app/main.py «disabled by user request 2026-04-20 — всё спамит»; последняя запись в lia_reminders 2026-04-20 13:03 UTC (290 строк, все proactive/overdue/backlog самого чекера); lia-v2 таблицу не читает. Вторая причина: модель LiaReminder держала DateTime без пояса при timestamptz в базе, драйвер отказывал времени с поясом (лог 06.09: can't subtract offset-naive and offset-aware). Фикс: services/reminder_sender.send_due_reminders раз в минуту + модель timezone=True. Чекер не возвращён.
acceptance
Напоминания скилла (ответ от человека, дедлайн, ретро) созданы через POST /api/reminders и доходят
Экзамен backend/tests/spec/plan_horizon/exams_17.py, медленный: python backend/tests/spec/plan_horizon/exams_17.py --only 17.4c --slow
✓ exams_17.py --slow 06.09.2026: ✓ напоминание с related_task_id через POST /api/reminders доставлено за 162 с
acceptance
17.5 Ретро недели и месяца
Напоминание Лии в пятницу и в последний рабочий день месяца «ретро». Скилл на «ретро недели»: план против факта по completed_at и deadline, перенос хвостов, где оценка промахнулась больше чем вдвое.
✓ services/reminder_sender.schedule_retro_reminders: retro на пятницу и последний рабочий день 16:00 по поясу владельца, без дублей. 17.5a зелёный; 17.5b (ретро в скилле) описан в plan-horizon/SKILL.md, проверяется руками.
feature
В пятницу и в последний рабочий день месяца приходит напоминание Лии «ретро»
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.5a
✓ exams_17.py 06.09.2026: ✓ незакрытые retro на пятницу 11.09 16:00 и на 30.09 16:00 (заводит schedule_retro_reminders на старте и в 03:10 UTC)
acceptance
«Ретро недели» показывает: закрыто в срок, перенесено, оценка промахнулась больше чем вдвое; хвосты переносятся одним подтверждением
Руками. Инструкция в выводе экзаменов (раздел «Руками»): python backend/tests/spec/plan_horizon/exams_17.py --only 17.5b
acceptance
↑ 17.6 Пилот: неделя + KPI сентября Фит Лид
Владелец скидывает задачи недели и KPI сентября. Проходим скилл вместе. Сквозной путь на автогенерации КП («агент вёрстки КП» в бэклоге): интервью → паспорт → галка → очередь Рубки → результат в задаче.
task
За один разговор из KPI и задач недели получен спринт «Сентябрь · Фит Лид» в AITODO и раскладка недели по часам
Экзамен backend/tests/spec/plan_horizon/exams_17.py: python backend/tests/spec/plan_horizon/exams_17.py --only 17.6a
✓ Пилот 09.09.2026: спринт «Сентябрь · Фит Лид» (id 18) из KPI встречи 21.08 и списка задач: 30 задач, 6 верхних, 3 стадии с галкой «через ИИ», 5 напоминаний «Ждём ответ», блоки на 09.09 и 10.09 по часам. Экзамен 17.6a зелёный.
acceptance
Автогенерация КП прошла весь путь: интервью → паспорт → галка «через ИИ» → очередь Рубки → результат в задаче AITODO
Руками. Инструкция в выводе экзаменов (раздел «Руками»): python backend/tests/spec/plan_horizon/exams_17.py --only 17.6b
acceptance
↑ 17.7 Правки по разбору ОТК (круг 2)
Второй круг ОТК: сверка со спекой отдельным подагентом (2 отсутствует, 6 частично) и критик на дифе (9 подтверждённых находок из 24, 15 отброшено без сценария отказа). Правки этой задачи закрывают находки со стороны AITODO.
✓ Сделано: ok:false не закрывает задачу и заводит «Разобраться»; вложения при повторном занесении сливаются, а не заменяются; напоминание по удалённой или закрытой задаче гасится без отправки; дедуп «Проверить» в пределах проекта; родитель проверяется на владельца и при создании; ретро месяца заводится и в сам последний рабочий день; списки задач читаются страницами по 200. Экзамены 17.7a/b/d/e зелёные, 17.7c медленный.
task
Упавший прогон (ok:false) не закрывает задачу: остаётся открытой с галкой, заводится «Разобраться: …» на 15 минут с дедлайном завтра
✓ exams_17.py 07.09.2026: ✓ статус не completed, галка на месте, «Разобраться: Экзамен упало» 15 мин, дедлайн завтра
acceptance
Повторное занесение плана не стирает вложения, добавленные владельцем в кабинете
✓ exams_17.py 07.09.2026: ✓ вложение «Прикрепил руками» пережило второй прогон, плановое на месте, дублей нет
acceptance
Напоминание по задаче, которую удалили или закрыли, не приходит
✓ exams_17.py --slow 07.09.2026: напоминание по удалённой задаче закрыто планировщиком за 163 с без отправки, is_sent=true
acceptance
Две одноимённые задачи в разных проектах получают каждая свою «Проверить: …»
✓ exams_17.py 07.09.2026: ✓ создано две проверки, project_id разошлись по двум проектам
acceptance
Родитель задачи проверяется на владельца и при создании, не только при обновлении
✓ exams_17.py 07.09.2026: ✓ создание с чужим parent_task_id отклонено 404
acceptance
ревьюS18 · С18 · Один разбор: входящие по дням и людям45/50

Цель: Входящие разбираются один раз: карточка честно говорит от кого и про что, тут же ставится проект, размер, день и исполнитель. День без часа раскладывает алгоритм по кнопке и по слову «разложи завтра». «Разобрать» остаётся для «когда-нибудь».

18.0 Экзамены спринта до кода
backend/tests/spec/single_triage/exams_18.py, по одному на критерий docs/ACCEPTANCE.md раздел Sprint 18. Каждый падает на ненаписанном коде.
✓ exams_18.py: 27 экзаменов, до кода 17 красных; после выката 27 зелёных, 5 руками
feature
18.0a Есть исполняемый файл проверок, по одной на критерий, и до кода он красный
✓ 21 критерий покрыт экзаменом, первый прогон до кода: 17 красных
acceptance
18.1 Карточка входящего честная: от кого, чат, когда сказано, исходник
Миграция 033: inbox_items.said_at, chat, hints. tg_apply пишет их в поля, а не в текст, и не повторяет заголовок в описании. API отдаёт origin (материал-расшифровка по префиксу source_ref). Экран «Раскидать» показывает шапку «от кого · чат · когда» и подсказки модели. Разовая чистка 18 задач с повтором названия в описании (с бэкапом).
✓ миграция 033 (chat, said_at, hints), origin по префиксу source_ref, описание без повтора названия, 19 живых задач вычищены с бэкапом; tg_apply.py на cfru и разбор встреч пишут поля
feature
18.1a API входящего отдаёт отдельными полями автора, чат, когда сказано и подсказки модели (срок как прозвучал, кому)
✓ POST /api/inbox/ с chat, said_at, hints → список отдал их полями, due_hint «в четверг»
acceptance
18.1b У входящего из голосового виден исходник: ссылка на материал-расшифровку и отрывок
✓ материал под «exam18:voice:…», входящее «…#задача1» → origin.material_id совпал, отрывок с текстом
acceptance
18.1c Описание задачи, рождённой из входящего, не начинается с её названия; откуда пришло — отдельной строкой
✓ описание без названия, последняя строка «Из телеграма: Экзамен Нина, 01.09 10:07 · чат …»
acceptance
18.1d У живых задач владельца повтор названия в описании убран, оригиналы сохранены в бэкапе
✓ fix_title_in_description.py: 19 задач, повторов 0, оригиналы в tasks_description_backup_20260908
acceptance
18.2 «Когда» в «Раскидать» и честное состояние «день без часа»
Плашка «Когда»: сегодня, завтра, послезавтра, выбрать день, когда-нибудь (по умолчанию). Клавиши a s d f g. to-task принимает day. «Мой день» показывает задачу с днём без часа в списке «Без времени», а не в 00:00. Сводка дня отдаёт «без часа» по дням и считает их в занятость.
✓ to-task принимает day → todo без часа; «Мой день» не ставит дату в 00:00; сводка отдаёт «без часа»
feature
18.2a Входящее превращается в задачу сразу с днём: статус todo, дата есть, часа нет
✓ day=завтра → статус todo, scheduled_date завтра, scheduled_start пуст; без day → pending
acceptance
18.2b Задача с днём без часа в «Моём дне» стоит в списке «Без времени», в неделе — в колонке своего дня, не в 00:00 таймлайна
Руками владельца: руками: владелец смотрит «Мой день» и «Неделя»
acceptance
18.2c Сводка дня показывает задачи дня без часа отдельным списком и считает их минуты в «занято»
✓ задача 45 минут без часа попала в «без часа» своего дня, «занято минут» ≥ 45
acceptance
18.3 Поручить человеку: исполнитель из «Людей», 15 минут владельца, напоминание Лии
Миграция 033: tasks.person_id → people. Действие «Поручить <имя>» в «Раскидать» и «Разобрать»: исполнитель, оценка 15 минут (постановка), напоминание Лии «спросить у <имя>: …» через 3 дня. Сводка дня показывает «кому». Карточка человека показывает, что на нём. Решение владельца 08.09.2026.
✓ tasks.person_id, сервис delegation: 15 минут владельца + напоминание Лии через 3 дня, фильтры person_id/delegated, «Люди» показывают «на нём»
feature
18.3a Задаче назначается исполнитель из «Людей»; API отдаёт person_id и имя
✓ PATCH person_id вернул person_name; чужой человек → 404
acceptance
18.3b При поручении задача получает 15 минут владельца и напоминание Лии «спросить у <имя>» через 3 дня, привязанное к задаче
✓ estimate 15, lia_reminders «Спросить у …» на +3 дня 10:00 с related_task_id
acceptance
18.3c В сводке дня у поручённой задачи видно, кому она поручена, и она занимает 15 минут владельца
✓ в сводке дня «кому» = имя, «минут» = 15 без своей оценки
acceptance
18.3d Список задач фильтруется по исполнителю, карточка человека показывает, что на нём висит
✓ /api/tasks/?person_id= отдал только задачи этого человека
acceptance
18.4 Раскладка дня по часам: алгоритм на сервере, кнопка в «Моём дне», слово в plan-day
POST /api/day/layout {day, apply}: задачи дня без часа встают в рабочие окна режима; встречи и уже поставленное не двигаются; мелочи одним блоком, крупное целиком и подальше от встреч; что не влезло — названо. Кнопка «Разложить по часам» в «Моём дне» с превью. В plan-day режим без вопросов «разложи завтра».
✓ POST /api/day/layout (services/day_layout.py), кнопка «Разложить по часам» с превью, режим «разложи завтра» в plan-day, docs/DAY_LAYOUT.md
feature
18.4a Задачи дня без часа получают время внутри рабочих окон режима дня, встречи и поставленное руками не двигаются и не перекрываются
✓ 4 задачи легли в окна режима, встреча 10:00 на месте, пересечений нет
acceptance
18.4b Дела по 15 минут стоят подряд одним блоком, двухчасовая задача стоит целиком, не порезана
✓ мелочи 06:00–06:15 и 06:15–06:30 подряд; крупное одним слотом 120 минут
acceptance
18.4c Что не влезло в день, названо отдельным списком с минутами, а не втиснуто поверх окон
✓ 720 минут при вместимости 570: «не влезло» с минутами, всё поставленное внутри окон
acceptance
18.4d Без apply ничего не пишется; с apply время записано; повторный вызов не переставляет уже поставленное
✓ превью не пишет; apply пишет; сдвинутое руками не тронуто повторным вызовом
acceptance
18.4e В «Моём дне» есть кнопка «Разложить по часам» с превью, в plan-day есть режим «разложи завтра» без вопросов
✓ в SKILL.md ручка /api/day/layout и триггер «разложи»; в бандле my-day строка «Разложить по часам»
acceptance
18.5 Пресеты в «Разобрать»: размер, день, исполнитель одним нажатием
Та же плашка, что в «Раскидать», в списке «Разобрать»: q w e r размер, a s d f g день, p поручить.
✓ кнопка «Быстро» у строк «Разобрать»: размер, день, кому копятся и применяются одним нажатием
feature
18.5a В «Разобрать» у задачи размер, день и исполнитель ставятся одним нажатием без открытия карточки
Руками владельца: руками: владелец смотрит плашку «Быстро» в «Разобрать»
acceptance
18.6 Сдача: выкат, миграция 033, чистка экзаменов, доки, ОТК
Бэкап базы, docker compose build backend frontend, alembic 033, экзамены зелёные на проде, экзаменационные записи вычищены, docs/ACCEPTANCE.md, DATABASE_SCHEMA.md, SCOPE-CUTS-LOG.md, память, dev-sync.
✓ выкачено 08.09 и 09.09: alembic 033, бэкап базы, экзамены зелёные на проде, записи вычищены, доки дописаны
feature
18.6a Выкачено на прод: миграция 033 накатилась, контейнеры подняты, экзамены зелёные на живом кабинете
✓ alembic 033, backend и frontend Up, страницы 200, дамп aitodo-20260908-triage.sql.gz (16 МБ)
acceptance
18.6b Экзаменационные задачи, входящие, люди и напоминания вычищены
✓ после чистки задачи/входящие/люди/материалы/напоминания = 0/0/0/0/0
acceptance
18.6c Доки описывают то, что работает; журнал срезанных углов дополнен; роадмап и ворклог в Atlas синхронизированы
✓ ACCEPTANCE.md с доказательствами, DATABASE_SCHEMA.md, DAY_LAYOUT.md, SCOPE-CUTS-LOG раздел 18, Atlas синхронизирован
acceptance
18.7 Найдено ОТК: поручение съедало день, дубли задач, раскладка прошлого
Два прохода ОТК на выкаченном спринте: сверка со спекой и критик на дифе. Одиннадцать находок стали критериями 18.7a-k.
✓ ОТК 09.09: два подагента нашли 21 находку, 11 стали критериями и закрыты, регресс С17 зелёный
feature
18.7a Поручение стоит владельцу 15 минут, даже когда на экране выбран размер
✓ экраны шлют 15 минут при выбранном человеке; экзамен: to-task и PATCH дают estimate 15
acceptance
18.7b Повторный to-task по разобранному входящему не рождает вторую задачу
✓ второй вызов вернул ту же задачу с полем «уже было»
acceptance
18.7c Пересекающиеся рабочие блоки режима дня не дают двух задач на один час
✓ merge() сливает окна: на 09-12 и 10-11 три задачи по часу подряд, пересечений нет
acceptance
18.7d Раскладка прошедшего дня ничего не пишет и объясняет почему
✓ apply на день −3: «записано» false, «почему» про прошедший день, часа задаче не поставили
acceptance
18.7e Когда рабочих окон на день нет вовсе, это сказано словами
✓ суббота: «на этот день в режиме дня нет рабочих блоков»
acceptance
18.7f Забрал поручение себе — навязанные 15 минут снимаются
✓ PATCH person_id null → estimate_minutes снова пуст
acceptance
18.7g Пункт встречи несёт время встречи и подсказки полями, а не прозой
✓ meetings.py пишет said_at = время встречи и hints (due_hint, owner_kind, timecode)
acceptance
18.7h Длинное сообщение: заголовок обрезан по слову, описание не с середины слова
✓ cut(): заголовок с многоточием по границе слова, описание начинается с начала сообщения
acceptance
18.7i В описании задачи нет технического пути к материалу, а есть название записи
✓ вместо «/materials/12» строка «есть расшифровка «разговор с Ниной»»
acceptance
18.7j Задача из старого бэклога, кинутая на день, видна в «Моём дне»
Руками владельца: руками: список грузится с запасом вместо сотни последних
acceptance
18.7k Подсказка «09.09» не уносит на следующий год, «31.02» и «в 9.00» днём не считаются
Руками владельца: руками: проверка чипа дня в «Раскидать»
acceptance
18.7l Задача с дедлайном на сегодня раскладывается по часам, а не считается уже стоящей
✓ Занесение плана ставит всем задачам дедлайн 18:00, и правка 18.7 про «дедлайн это занятое время» молча выводила их из кандидатов: день оставался пустым при полном списке дел. Теперь дедлайн считается занятым только у задач, которые в этот день не назначены. Доказательство: до правки раскладка четверга поставила одну задачу из десяти и показала девять блоков «18:00–18:30», после правки разложила девять задач в свободные окна.
acceptance
18.7m Задачи «через ИИ» не получают часы от раскладки и не занимают день владельца
✓ Проверено на живом кабинете: 21 задача с галкой, в сводке дня «занято 270 из 570» считает только то, что владелец делает руками. Часы, расставленные владельцем вручную в «Моём дне», раскладка не трогает.
acceptance
Виджеты 1.2.0: «Фокус» и «Встреча» значками у часов
✓ Новый модуль desktop/src/main/quickTray.ts: два отдельных значка в трее со своими GUID. Левый клик — виджет выпрыгивает над панелью развёрнутым (popWidget/togglePopWidget в windows.ts, позиция от прямоугольника значка с учётом рабочей области), повторный клик прячет. Правый клик — меню «Включить/Выключить фокус» и «Начать/Остановить запись» без открытия окна. Значок и подсказка отражают состояние: зелёное кольцо и часы фокуса, красный микрофон и часы записи. Фаза записи идёт из окна встречи по IPC meeting:phase каждую секунду, команда обратно по meeting:command в те же start/stop, что и кнопка. Проверено на живом: снимки панели, эмуляция клика по значку (виджет выпрыгнул с полем темы и кнопкой «Записать встречу»), правый клик (меню на месте). Установлено владельцу тихо, оба значка вытащены на панель через реестр.
task
Три ловушки трея на Windows 11
✓ (1) Без GUID Windows 11 склеивал все значки одного exe в одну запись NotifyIconSettings — dev-сборка показала одну запись на три Tray; после new Tray(image, guid) стало три, ключи по GUID одинаковы для dev и установленной копии. (2) Новые значки уходят за стрелку «^»; вытащены кодом через IsPromoted=1 в реестре. (3) Окно узнаёт «свёрнуто» из app:state, а не из размера — первый прогон дал пустую тёмную панель без кнопок над треем; лечится отправкой состояния окну сразу после смены collapsed в хранилище.
task
Обновление установки виджетов из песочницы
✓ Установка NSIS в aitodo-widgets/, Setup /S ставит тихо, но приложение потом не запускается: песочница гасит дерево процессов при завершении команды, Start-Process даёт ноль процессов. Рабочий путь — запуск через explorer.exe с путём к exe. Записано в память aitodo-widgets-tray-and-update.
task
18.8 «Сделал» в «Раскидать»: третий исход рядом с «выкинуть»
Решение владельца 20.09.2026: сделанное не выкидывается. Статус done у входящих, POST /api/inbox/{id}/done, кнопка «Сделал · x» в «Раскидать», для задачи-сироты completed.
✓ Выкачено 20.09: статус done во входящих, POST /api/inbox/{id}/done, restore возвращает и сделанное; в «Раскидать» кнопка «Сделал · x» зелёным рядом с «Выкинуть · 0», задача-сирота закрывается completed. Миграции нет. Бэкап серверных файлов /opt/TODO-New/.backup-20260920
feature
18.8a POST /api/inbox/{id}/done переводит в статус done с processed_at; ?status=done отдаёт, counts содержит done, в new нет; restore возвращает
✓ На проде 20.09: /done даёт status done + processed_at, ?status=done отдаёт, counts.done ≥ 1, в new нет, restore возвращает в new (экзамен 18.8a зелёный)
acceptance
18.8b Сделанное не смешано с выкинутым: после done не в dropped, после drop не в done
✓ Сделанное только в done, выкинутое только в dropped (экзамен 18.8b зелёный)
acceptance
18.8c В «Раскидать» рядом с «Выкинуть · 0» есть «Сделал · x»: входящее в done, задача-сирота в completed, в «Только что разложено» строка «сделано»
✓ В чанке /sort есть «Сделал» и completed, вызов /api/inbox/{id}/done в общем чанке 1837 (экзамен 18.8c зелёный); вид глазами за владельцем
acceptance
18.8d Доки описывают статус done (DATABASE_SCHEMA.md), критерии закрыты с доказательствами, Atlas синхронизирован
✓ DATABASE_SCHEMA.md: status = new, task, done, dropped; ACCEPTANCE.md 18.8 закрыт с доказательствами
acceptance
В РАБОТЕS19 · С19 · Тело: Лия ведёт спорт и еду17/21

Цель: Владелец не думает о еде и спорте: Лия пингует по режиму дня, считает калории и подходы, молчание = по плану. docs/BODY.md в lia-v2.

19.0 Модуль «Тело» в Лии: пинги, быстрые ответы, фото еды, карточка дня
lia-v2/backend/body/{service,store,jobs,vision,exams}.py, memory/body_plan.json, патчи telegram.py и scheduler.py. Экзамены: docker exec -w /app lia-backend python -m backend.body.exams (BODY_EXAMS_LIVE=1 для живого блока).
feature
19.1 В 06:00 приходит завтрак с блюдом и калориями из меню дня
✓ Экзамен OK; текст breakfast_text из body_plan.json
acceptance
19.2 Микроподходы 09:55/11:55/15:55/17:55 и все задания body_* в планировщике
✓ 14 заданий, пояс Asia/Yekaterinburg, лог «body jobs: 14»
acceptance
19.3 Ответ «+» создаёт тренировку «Микроподход», ответ «Подход N из 4»
✓ Экзамен 19.3 и 19.3-live против AITODO (создано и удалено)
acceptance
19.4 «съел …» создаёт приём с калориями, ответ с остатком
✓ Экзамен OK (оценка подменена); живая оценка через AITODO estimate-nutrition
acceptance
19.5 «капучино» 120 и «шоколадка» 220 без модели
✓ Экзамен OK
acceptance
19.6 Фото еды → приём и остаток; не еда → входящие
Ручная проверка: владелец шлёт фото обеда в пн, запись в AITODO meals c source=photo_recognition; скриншот → во входящих.
acceptance
19.7 Лия не пишет приёмы сама: в журнале только сказанное владельцем
✓ Решение владельца 23.09 («в 70% случаев я ем другое, приходится перезаписывать»). fill_planned → пустая заглушка, источник plan_default исчез. Экзамен 19.7 переписан, 11/11 зелёные.
acceptance
19.8 Карточка 20:30: съедено/норма, белок, подходы, серия, вес совпадают с AITODO
✓ Экзамен OK
acceptance
19.9 «93,4» пишет вес, «живот 106» пишет живот
✓ Экзамен 19.9 и 19.9-live
acceptance
19.10 Сб 10:00 список покупок, вс 11:00 готовка из плана
✓ Экзамен OK
acceptance
19.11 День без ответов: карточка «приёмов не записано», 0 из 4
✓ Переписан вместе с 19.7. Экзамен зелёный.
acceptance
19.12 После пересборки задания на месте, время Екатеринбурга
✓ docker logs: body jobs: 14; список триггеров cron hour/minute в Ekb
acceptance
19.13 Два дня без подходов → вопрос «что мешает» и один подход
✓ Экзамен OK
acceptance
19.20 С2: Apple Health → AITODO через «Команды» (вес, шаги, тренировки), быстрые ответы на часах
10.10.2026: ведётся спринтом С23 «Здоровье айфона в AITODO».
feature
19.30 С3: страница «Тело» в AITODO и виджете: калории и вес графиком, серия, меню из фото холодильника
feature
Тело: сработали ли пинги пн-ср и отвечает ли владелец
ssh aitodo "docker logs lia-backend --since 72h 2>&1 | grep -c 'Proactive message sent'"; в AITODO: /tmp/aq.sh '/api/meals/?limit=30' и /api/workouts/?limit=30 — есть ли приёмы с source=lia/photo_recognition и подходы. Нет ответов 3 дня → упростить до одного подхода и спросить владельца.
✓ 02.10, логи lia-backend за 72 ч: «Proactive message sent» 22 (7 в день: утренний брифинг 01:00 UTC + пинги тела 04:55, 08:00, 11:30, 13:00, 13:30, 15:30 UTC; body jobs: 15). Ответов владельца нет: «Processing message from 234701173» только 3, все в 03:00 UTC = сам брифинг; инструменты записи еды/подходов не вызывались (только get_*). База aitodo за 72 ч: meals 6, все source=claude (29–30.09, внесены из сессии, не через Лию), source=lia 0; workouts 0 (последний 23.09 через Лию, ходьба). /tmp/aq.sh на aitodo нет (/tmp очищен), смотрел базу напрямую. Вывод: пинги идут, владелец не отвечает 3 дня подряд. По условию проверки: упростить до одного подхода и спросить владельца, решение за ним.
⛔ Ночная смена 01-02.10.2026. Пинги идут: 21 «Proactive message sent» за 72 часа. Ответы за неделю 24.09–01.10: еда 9 записей (8 через меня в чате, 1 через Лию), подходов 0, замеров 0. Три дня подряд без ответов на подходы — по условию проверки упрощаем до одного подхода и спрашиваем тебя: оставить пинги подходов или свести к одному в день?
check
19.14 Подходы из виджета ПК (Отжимание+Пресс+Приседание одной секундой) считаются как микроподход
✓ store._sets_recent: силовые типы виджета, пачка в 5 минут = один подход. 21.09 владелец сделал 3 пачки в виджете + зарядка → карточка покажет 4 из 4. Экзамены 11/11.
feature
19.15 Убрана запись приёмов «по плану»: предложение остаётся, журнал только со слов владельца
Владелец 23.09: в 70% случаев ест другое, записи plan_default приходилось удалять руками, итог дня врал.
✓ service.py: fill_planned возвращает пустой список (комментарий со старым поведением и причиной), карточка дня показывает «Записано приёмов: N» / «Приёмов не записано», пинги обеда и ужина зовут сказать словом. Экзамены 19.7 и 19.11 переписаны, 11/11. docs/BODY.md и BODY-ACCEPTANCE.md обновлены. Выкачено в lia-backend, живой текст пинга проверен.
feature
19.16 Перекус при перерыве 5+ часов зовёт белок, а не шоколадку
✓ snack_text сначала считает unlogged_hours (long_gap_hours=5 в плане). Экзамен 19.16: пустой день → «не ел N часов… нужен белок», свежая запись → обычный текст. 13/13.
acceptance
19.17 В 18:00 по будням приходит разгрузка головы, совет меняется по дням
✓ Задание body_unload (15 заданий вместо 14), unload_options из 5 вариантов в body_plan.json, текст проверен живьём: «Стоп на пять минут… если голова гудит, это не голод». Экзамен 19.17.
acceptance
ревьюS20 · С20 · Лия пишет в склад знаний5/5

Цель: «Запиши в базу знаний» кладёт материал в склад AITODO, а не во Входящие; «что мы знаем про…» ищет по складу.

20.0 У Лии не было записи в склад: «запиши в базу данных» уходило во Входящие
22.09 владелец продиктовал Лие итоги созвона с Дмитрием по Принтфлагу и сказал «запиши в базу данных». Запись легла во входящее 743 (очередь разбора), в складе её не было: инструмента materials у Лии не существовало.
✓ backend/tools/materials.py: save_knowledge и find_knowledge, зарегистрированы в register_all. Проект разрешается по названию через /projects/resolve, вид по умолчанию «нюанс», источник «лия». Ловушка trailing slash обойдена request_raw. Экзамены materials_exams 6/6 + живой 20.live (запись, поиск, уборка в архив). Сам созвон занесён материалом 1253, задача 1245 с 5 подзадачами, входящее 743 закрыто.
bug
20.1 «Запиши в базу знаний» пишет в materials, а не в inbox
✓ Экзамен 20.1: единственный POST идёт на /materials, /inbox не вызывается.
acceptance
20.2 Текст сохраняется целиком, проект по названию, вид по умолчанию
✓ Экзамен 20.2: body без сокращений, project_id 17 из «Клиент Искра», kind «нюанс», source «лия».
acceptance
20.3 Без заголовка он берётся из первой строки, без проекта запись всё равно идёт
✓ Экзамен 20.3.
acceptance
20.5 «Что мы знаем про…» отдаёт карточки из склада
✓ Экзамен 20.5 + живой 20.live: записанный материал находится поиском.
acceptance
ревьюS21 · С21 · Встречи не теряются, запись не забывается28/35

Цель: Прошедшие встречи остаются на своих днях, встречи из Битрикса не застревают в бэклоге; виджет сам замечает звонок в Телемосте, Зуме, Телеграме или Скайпе и предлагает записать встречу с названием из дня.

↑ 21.1 Сервер: встречи остаются на своих днях
Сервер выкачен 02.10, экзамены 9/9; 21.1e частично (удалённые события).
feature
21.1a Ночной перенос не уводит встречи в бэклог: прошедшая встреча стоит на своём времени со статусом «прошла» (изменено ОТК, ждёт подтверждения владельца)
✓ exams_21.py 21.1a зелёный 02.10: встреча completed на своём времени, задача ушла в бэклог; на проде у прошедших встреч 26 completed, 0 todo
acceptance
21.1b Синхронизация возвращает встречу из Битрикса из бэклога на её дату (Планирование спринта 15.10 13:00), без уведомления
✓ 21.1b зелёный: 15.10 и 29.10 todo в 08:00 UTC, уведомления о возврате нет
acceptance
21.1c Встречи из Битрикса в бэклоге возвращены на даты; 01.10 стоят четыре встречи
✓ restore_backlogged_meetings вернул 19 встреч; 21.1c зелёный: застрявших 0, 01.10 = 11:30, 13:00, 14:00, 15:00
acceptance
21.1d Регресс: все сегодняшние встречи Битрикса стоят в дне со своим временем
✓ 21.1d зелёный, сегодня 7 встреч Битрикса на месте
acceptance
21.1e Отклонённая или удалённая в Битриксе встреча уходит из дня; выполненную не трогает (ОТК)
⛔ Удалённая в Битриксе встреча снимается, только если портал отдаёт её с DELETED=Y; проверить нельзя без записи в рабочий портал. Отклонённая снимается (экзамен зелёный).
acceptance
21.1f Прошедшие встречи не числятся просроченными (ОТК)
✓ exams_21_otk.py 21.1f зелёный: прошедших встреч в todo 0
acceptance
21.1g Отклонённая и снова принятая встреча возвращается в день (ОТК, круг 2)
✓ 21.1g зелёный: отклонённая cancelled, снова принятая todo на своём времени
acceptance
21.1h Прошедшая встреча, перенесённая на будущее, снова несделанная на новой дате (ОТК, круг 2)
✓ 21.1h зелёный
acceptance
21.1i Новая уже прошедшая встреча заводится прошедшей, а не просроченной (ОТК, круг 2)
✓ 21.1i зелёный
acceptance
↑ 21.2 Виджет: сторож звонков и окошко записи
Виджет 1.3.3 установлен, экзамены 15/15 + живой; Enter и запуск из трея — проверка руками.
feature
21.2a Звонок в Телемосте/Зуме/Телеграме/Скайпе ловится за 5 с; браузер и сам виджет не ловятся
✓ exams_21.mjs 21.2a зелёный
acceptance
21.2b Телеграм — звонок только если микрофон занят дольше 30 с
✓ 21.2b зелёный
acceptance
21.2c Окошко предлагает встречу из дня, которая идёт сейчас; две — обе на выбор; нет — поле пустое
✓ 21.2c зелёный
acceptance
21.2d Записать / Enter: запись с выбранным названием, значок у часов красный
руками на встрече; Enter работает только после щелчка по окошку (решение владельца, журнал п. 12)
acceptance
21.2e Не записывать: про этот звонок не спрашивает; идёт запись — не спрашивает
✓ 21.2e зелёный
acceptance
21.2f Окошко не отбирает фокус
✓ живой прогон зелёный 4 раза (окошко за ≤6 с); один ложный красный 02.10 — владелец сам переключил окно, журнал активного окна: окошко фокус не брало
acceptance
21.2g Конец звонка при идущей записи: окошко «Остановить и разобрать?», само не останавливает
✓ 21.2g зелёный
acceptance
21.2h Сторож читает настоящий реестр: видит Телемост на машине владельца
✓ 21.2h зелёный на живом реестре (66 записей)
acceptance
21.2i Ручная запись после незаписанного звонка не получает «звонок закончился» (ОТК)
✓ exams_21_otk.mjs зелёный (на версии до правок красный)
acceptance
21.2j Переподключение в пределах 30 с — тот же звонок, второй раз не спрашивает (ОТК)
✓ зелёный (до правок красный)
acceptance
21.2k Пустое поле в окошке — запись без названия, а не с названием прошлой (ОТК)
✓ прогон страницы окошка: пустое поле → ответ title "" → в окне встречи «без названия»; набранное обрезается
acceptance
21.2l Второй звонок во время записи спрашивается после её остановки (ОТК)
✓ зелёный (до правок красный)
acceptance
21.2m Окошко «Записать?» не пропадает от короткого разрыва микрофона (ОТК, круг 2)
✓ зелёный
acceptance
21.2n Конец записанного звонка спрашивается, даже если следом начался другой (ОТК, круг 2)
✓ зелёный
acceptance
21.2o Телеграм после переподключения — тот же звонок (ОТК, круг 2)
✓ зелёный
acceptance
21.2p Голосовое в Телеграме во время ручной записи не даёт «звонок закончился» (ОТК, круг 2)
✓ зелёный
acceptance
21.2q Следующая встреча в той же программе во время записи не дописывается молча (ОТК, круг 3)
✓ зелёный
acceptance
21.2r Ручная запись забирает звонок Телемоста/Зума/Скайпа в первые 2 минуты, Телеграм нет (ОТК, круг 3)
✓ зелёный
acceptance
21.2s Запись из меню трея не получает название прошлой встречи (ОТК, круг 3)
исправлено (название очищается при остановке), экзамена нет; проверить руками: запись из окошка с названием, потом из трея — папка без старого названия
acceptance
21.3 Проверка на настоящем звонке в Телемосте
Ждёт настоящего звонка в Телемосте (встреча 02.10 в 12:00).
feature
21.3a Настоящий звонок: окошко с названием встречи, запись пошла одним нажатием
руками, владелец
acceptance
21.4 Сдача спринта
Выкат сервера, разовый возврат, установка виджета, доки, журнал срезанных углов, Atlas.
✓ Выкачено, доки и журнал срезанных углов (17 пунктов), Atlas синхронизирован.
feature
21.4a Сервер выкачен, разовый возврат проведён, экзамены зелёные, виджет установлен
✓ сервер выкачен 02.10 (бэкапы .backup-20261002-s21, -r1, -r2, -r3), возврат 19 встреч, экзамены сервера 9/9 и виджета 15/15 + живой, виджет 1.3.3 установлен
acceptance
21.4b Доки, журнал срезанных углов, Atlas синхронизированы
✓ DESKTOP_WIDGETS.md, DAY_LAYOUT.md, SCOPE-CUTS-LOG.md (17 пунктов), Atlas спринт 21
acceptance
В РАБОТЕS22 · С22 · Linear: уведомления ботом и задачи во Входящие1/4

Цель: Ничего из Linear работодателя не теряется: назначения, упоминания и комментарии приходят ботом @fitleadmy_bot с контекстом задачи, в 10:00 сводка ждущих ответа, назначения и упоминания лежат во Входящих AITODO.

Уведомления из инбокса Linear каждые 10 минут ботом @fitleadmy_bot
Назначения, упоминания, комментарии в своих задачах. Контекст: номер, название, проект, статус, срок, текст или начало описания, ссылка на комментарий. Одна задача = один пункт, код из комментариев скрыт, комментарии в закрытых задачах не шлём. Ночью копит в одно сообщение. Код: backend/app/services/linear_digest.py, бот выбирает reminder_sender.bot_token_for.
✓ Выкачено 07.10.2026: экзамены 14/14 (backend/tests/spec/linear_inbox), сухой прогон на живом инбоксе (53 уведомления), тестовое сообщение бота дошло. Ждёт первого живого уведомления.
feature
Сводка «ждут ответа» в 10:00 Екб
Непрочитанное в инбоксе Linear старше 3 часов, по задаче один пункт, старые сверху, число открытых задач в конце. Пусто — молчит.
✓ Выкачено 07.10, задание linear_pending 05:00 UTC. Проверка 08.10 в Проверках по сроку.
feature
Назначения и упоминания из Linear во Входящие AITODO
Источник linear (метка «из Linear»), проект «Фит Лид» (LINEAR_PROJECT_TITLE), source_ref linear:<CDT-N>: пока запись не разобрана, новое по той же задаче дописывается. Первый запуск кладёт открытые задачи на владельце. В склад знаний задачи НЕ копируются (правило владельца: Linear = источник правды).
✓ Выкачено 07.10, проверка на живой базе с откатом: запись создаётся, повтор дописывается, проект подставлен.
feature
Рабочий бот: всё по Fit&Lead мимо Лии
Решение владельца 07.10: работу (Битрикс, задачи, встречи, Linear) — в @fitleadmy_bot, Лия — еда, спорт, бриф, ретро, свои проекты; Авито и ISKRA остаются в Лии. AITODO: WORK_TG_BOT_TOKEN, reminder_sender.bot_token_for (типы linear/bitrix/work + задачи проекта WORK_PROJECT_TITLE «Фит Лид»), bitrix_sync._tell. Дашборд Fit&Lead: LIA_BOT_TOKEN в .env = рабочий бот (лиды РЕКЛ БА, завод статей), без пересборки.
✓ Выкачено 07.10: экзамены 16/16 в работающем контейнере, тестовое напоминание work_check id 1662 ушло 07:56 UTC; дашборд перезапущен, в контейнере бот 8936440804, docs/DEPLOY.md обновлён. Бэкапы .backup-20261007-workbot (aitodo), .env.bak-20261007-workbot (cfru).
feature
В РАБОТЕS23 · С23 · Здоровье айфона в AITODO6/9

Цель: Данные «Здоровья» (вес с весов Zepp Life, сон, шаги, свет, пульс, тренировки) лежат в AITODO таблицами для точного сравнения по неделям и месяцам; история из экспорта 10.10 залита; команда айфона досылает свежие дни сама; месячные сводки в складе ищутся по смыслу.

↑ 23.0 Приёмник «Здоровья»: таблицы, ключ команды, залив экспорта, недельное сравнение, сводки в склад
Спека docs/HEALTH.md, критерии docs/HEALTH-ACCEPTANCE.md, экзамены backend/tests/spec/health/. Продолжение задачи 19.20 (С2 спринта «Тело»).
feature
23.1 Вся история из экспорта 10.10 в AITODO: 108 взвешиваний Zepp Life, ночи сна, шаги, 27 заплывов с рекордом 24.02.2023 1 750 м
✓ Выкачено 10.10. Залив экспорта на прод: 3 201 день (19 516 строк показателей), 878 ночей, 691 тренировка, 27 заплывов, лучший 24.02.2023 1 750 м за 45 мин; взвешиваний 114 (Zepp Life 108) = 50 дней с весом (весы писали по несколько раз в день). Счёт по экспорту и по базе совпал.
acceptance
23.2 Повторный залив того же экспорта не создаёт дублей: строк и чисел столько же
✓ Повторный залив на проде: дни created 0 / updated 0, ночи и тренировки 0 новых (перезаписаны те же 878 и 691). exam_db 23.2 зелёный.
acceptance
23.3 Команда айфона с ключом записывает вес, шаги, активные ккал, дневной свет и сон за последние дни; повтор не дублирует
✓ exam_db 23.3: вес 95,45/95,1, шаги трёх дней, активные и свет, ночь 470 мин с подъёмом 06:05, повтор не дублирует. Живой приём от команды — после сборки владельцем (23.8).
acceptance
23.4 Без ключа или с чужим ключом 401 и ничего не записано; ключ команды не открывает задачи и другие разделы
✓ exam_db 23.4 зелёный; прод: POST /api/health/ingest без ключа 401. Ключ выпущен 10.10 скриптом health_key.py, в базе только хеш.
acceptance
23.5 Присланное командой сохраняется в журнале приёма; числа и даты по-русски («95,45 кг», «10 окт. 2026 г., 6:12») разбираются
✓ exam_parse 30/30 (числа и даты по-русски, ISO, формат экспорта); exam_db 23.5: присланное лежит в health_ingest_log.
acceptance
23.6 Недельное сравнение отдаёт вес, подъём и длительность сна, шаги, свет, тренировки по неделям
✓ exam_db 23.6 зелёный; прод GET /api/health/weekly отдаёт недели с 14.09: шаги, сон 3 ночи 8,4 ч 21:30→06:36, свет, 2 заплыва 2 875 м за неделю 05.10.
acceptance
23.7 Месячные сводки в складе: поиск «как я спал в августе 2023» находит сводку августа 2023 с цифрами
⛔ Ждёт «трачу» владельца на векторы сводок (OpenAI text-embedding-3-small, меньше рубля). Сводки месяцев собираются (/api/health/month), в склад не залиты.
acceptance
23.8 Инструкция по команде по-русски на /lab, ключ только в чате; владелец собрал команду, первый приём дошёл
acceptance
ревьюS24 · С24 · Телеграм в базе целиком7/12

Цель: Каждое сообщение владельца и ему (рабочие папки + личные чаты), включая короткие, за 15 минут лежит в базе AITODO; пропуски догоняются; история с 01.09; счёт по дням для Пульса.

↑ Архив телеграма: все сообщения, догон пропусков, история с 01.09, счёт по дням
Почему: ночной tg-collect сохраняет только «ценное» (6–23% исходящих), не видит папку «Личные» (она задана правилом contacts+non_contacts), ходит раз в сутки окном 24 ч без догона. Решение: tg-archive.py на cfru каждые 10 мин по меткам (min_id) → SQLite-буфер → AITODO Postgres (миграция 035: tg_chats, tg_messages, вид tg_daily). Склад знаний (night.sh) не трогаем.
feature
24.1 Любое сообщение владельца в рабочих папках (Фитлид, Пульс цен, Клиенты), даже «ок», через ≤15 минут лежит в tg_messages AITODO: чат, папка, направление, время
Экзамен: backend/tests/spec/tg_archive/exams_24.py. Прогон: python backend/tests/spec/tg_archive/exams_24.py --only 24.1. Точка отсчёта 15.10: красный (кода нет).
⛔ Противоречие критериев: 24.1 «любое сообщение в рабочих папках», 24.5 «чужие каналы не пишутся, даже в рабочих». Канал компании @pulscenru в папке «Пульс цен»: 3 из 73 — его посты. Без канала 70/70. Решение владельца: хранить ли чужие каналы рабочих папок
acceptance
24.2 Пропуск догоняется: если прогоны не шли N часов (сервер/скрипт лежал), следующий прогон забирает всё пропущенное, дыр нет
Экзамен: backend/tests/spec/tg_archive/exams_24.py. Прогон: python backend/tests/spec/tg_archive/exams_24.py --only 24.2 --outage-minutes 25 (прогон ~35 мин, не в 01–04 Екб). Точка отсчёта 15.10: красный (кода нет).
⛔ Догон работает: простой 25 мин, после прогона 33 из 33 сообщений в охвате. 2 из 35 — посты канала @pulscenru, не пишется по 24.5. То же решение владельца, что 24.1
acceptance
24.3 Сверка с независимым полным дампом 29.09–07.10 (sbor-1007): по чатам в охвате в архиве ≥99% сообщений, включая короткие ≤5 символов
Экзамен: backend/tests/spec/tg_archive/exams_24.py. Прогон: python backend/tests/spec/tg_archive/exams_24.py --only 24.3. Точка отсчёта 15.10: красный (кода нет).
⛔ 98,07% (2289/2334), коротких 118/120: 41 сообщение группы ИСЕТЬ, из которой владелец вышел после 07.10 — недоступна. Без неё 99,83% и 100%. Решение владельца: сверять по чатам, где он остаётся
acceptance
24.4 Повторный прогон ничего не удваивает (уникальность чат+сообщение)
Экзамен: backend/tests/spec/tg_archive/exams_24.py. Прогон: python backend/tests/spec/tg_archive/exams_24.py --only 24.4. Точка отсчёта 15.10: красный (кода нет).
✓ exams_24.py --only 24.4: за два дня 1153 строк до и после --repush-days 2, дублей 0 (15.10, финальная версия)
acceptance
24.5 Охват: рабочие папки и свои каналы с текстом; личные чаты — по решению владельца (до ответа без текста); группы и боты вне папок — только кто/когда/сколько; чужие каналы и «чтиво» не пишутся
Экзамен: backend/tests/spec/tg_archive/exams_24.py. Прогон: python backend/tests/spec/tg_archive/exams_24.py --only 24.5. Точка отсчёта 15.10: красный (кода нет).
✓ 24.5: рабочих 7444 с текстом, личных 830 без текста, вне папок бот 2733/группы 573/супергруппы 4999 без текста, своих каналов 4, чужих 97 — пусто. ОТК нашёл ботов рабочих папок без текста — исправлено
acceptance
24.6 Код ничего не отправляет, не отмечает прочитанным, не удаляет (статическая проверка)
Экзамен: backend/tests/spec/tg_archive/exams_24.py. Прогон: python backend/tests/spec/tg_archive/exams_24.py --only 24.6. Точка отсчёта 15.10: красный (кода нет).
✓ 24.6: 20 запрещённых вызовов в развёрнутом tg-archive.py — ни одного; receive_updates=False
acceptance
24.7 История с 01.09 залита без FloodWait дольше минуты
Экзамен: backend/tests/spec/tg_archive/exams_24.py. Прогон: python backend/tests/spec/tg_archive/exams_24.py --only 24.7. Точка отсчёта 15.10: красный (кода нет).
✓ 24.7: 44 дня с 01.09 все с сообщениями, исходящие 32 из 32 будних, худший FloodWait 6 с; полная перечитка истории 4 мин 49 с
acceptance
24.8 Счёт по дням (tg_daily): исходящие/входящие по папкам, чатов с ответом, первое/последнее время — сходится с прямым подсчётом по tg_messages
Экзамен: backend/tests/spec/tg_archive/exams_24.py. Прогон: python backend/tests/spec/tg_archive/exams_24.py --only 24.8. Точка отсчёта 15.10: красный (кода нет).
✓ 24.8: tg_daily = прямой подсчёт, 26 строк день×папка за 7 дней (ОТК-сверка: 198 из 198 за всё время)
acceptance
24.9 Не пересекается с ночным сбором и ручными скриптами: общий замок сессии, второй ждёт или пропускает без ошибки
Экзамен: backend/tests/spec/tg_archive/exams_24.py. Прогон: python backend/tests/spec/tg_archive/exams_24.py --only 24.9. Точка отсчёта 15.10: красный (кода нет).
✓ 24.9: занятый замок → выход 0 за 1,4 с; ночь под замком и при неудаче пишет ОШИБКА; newsctl refresh-topics → tg-read.py под замком
acceptance
24.10 Отставание архива больше часа видно в утреннем брифе
Экзамен: backend/tests/spec/tg_archive/exams_24.py. Прогон: python backend/tests/spec/tg_archive/exams_24.py --only 24.10. Точка отсчёта 15.10: красный (кода нет).
✓ 24.10: бриф на подставленных данных: 2 ч 10 мин → «Архив телеграма отстаёт», 5 мин → нет; отставание считается на сервере в момент сбора
acceptance
24.11 Решение владельца: личные чаты — хранить ли текст и чьи чаты не хранить; до ответа без текста, после — догон перечитыванием только этих чатов
⛔ Ждёт ответа владельца: личные с текстом или нет, чьи чаты без текста (personal_exclude), чьи не хранить вовсе (skip_chats). Механизм готов и проверен, сейчас личные без текста
acceptance
В РАБОТЕS26 · С26 · Календари Outlook ПЦ ↔ Битрикс ↔ AITODO21/23

Цель: Встречи ПЦ из Outlook сами в AITODO, «Занят» без названий в Битрикс и в Outlook, без дублей и приглашений

↑ Документация и критерии (CALENDAR_SYNC.md, ACCEPTANCE 26)
docs/CALENDAR_SYNC.md, docs/ACCEPTANCE.md раздел Sprint 26; проба EWS 19.10 прошла
feature
↑ Экзамены С26 до кода
backend/tests/spec/calendar_sync/exams_26.py, каждый сначала красный
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
feature
↑ Outlook → AITODO: встречи ПЦ
EWS CalendarView, проект «Пульс цен», связь с уже занесёнными
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
feature
26.1 Встреча из Outlook через 15 минут в AITODO на то же время, проект «Пульс цен»
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
26.2 Перенос в Outlook двигает, отмена отменяет в AITODO
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
26.3 Занесённые руками встречи ПЦ связываются, не дублируются
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
↑ Outlook → Битрикс: «Занят»
calendar.event.add/update/delete, принять блоки 11824–11830
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
feature
26.4 Встреча Outlook = «Занят» в Битриксе без описания; перенос/отмена отражаются
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
26.11 Блоки 11824–11830 приняты как свои
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
↑ Битрикс → Outlook: «Занят» без приглашений
CalendarItem, SEND_TO_NONE
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
feature
26.5 Встреча Битрикса = «Занят» в Outlook без текста и приглашений
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
↑ Свои блоки, второй блок, названия, горизонт, повторы
таблица calendar_links, bitrix_links mirror:outlook
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
feature
26.6 Свои блоки не возвращаются; чужая встреча «Занят» обрабатывается
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
26.7 Есть встреча на интервал в целевом календаре = второй блок не ставится
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
26.8 В зеркалах нет названий и описаний
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
26.9 Не зеркалятся отменённые, «Свободен», весь день, прошедшие; горизонт вчера…+30
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
26.10 10 прогонов подряд не меняют число событий
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
↑ Пароль ПЦ: 401 → Лия, секреты, бриф
.env 600, сигнал раз в сутки, бриф при отставании > 1 ч
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
feature
26.12 401 от Outlook: Лия раз в сутки, bitrix_sync работает, догон после нового пароля
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
26.13 Пароль только в .env 600, не в логах/API/задачах
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
26.14 Бриф говорит об отставании Outlook > 1 ч
✓ Код готов локально, на прод не выкачен. exams_26.py 14/14 зелёные (до кода 14/14 красные), проверки исправлений 29/29, ОТК 3 круга завершён 19.10, экзамены не тронуты (sha256)
acceptance
↑ ОТК, выкат по «да», живая проверка
скилл otk, выкат только по «да» владельца
⛔ ОТК зелёный; выкат ждёт: закрыть дыру /api/lia/code/* (без входа, порт 8000 наружу) и «да» владельца
feature
26.15 Живая проверка на проде: тестовые встречи в обе стороны
acceptance

Ворклог (места остановки)

19.10.2026, 11:56:18 · С26 · claude

19.10 С26 «Календари Outlook ПЦ ↔ Битрикс ↔ AITODO»: проба EWS (servermail2.apress.ru, NTLM, shamrai@pulscen.ru) прошла; вручную поставлены «Занят» в Битрикс на встречи ПЦ недели (11824–11830, связи outlook-busy). Код: calendar_sync.py, outlook.py, calendar_common.py, модель calendar_links, миграция 037, задача раз в 10 мин; экзамены 14/14, ОТК 3 круга завершён, 4 пункта «не сходится» в SCOPE-CUTS-LOG. Найдена дыра вне С26: /api/lia/code/* без входа, порты 8000/3000 наружу.

→ По «да» владельца: закрыть /api/lia/code (nginx 403 + порты на 127.0.0.1), затем выкат С26 по CALENDAR_SYNC.md «Выкат», пароль ПЦ в .env 600, живая проверка 26.15 (NTLM из контейнера, день to в Битриксе, удалённый экземпляр серии).

15.10.2026, 12:05:48 · С24 · claude

С24 выкачен 15.10 по «да»: миграции 035–036, архиватор каждые 10 мин (flock -E0 -n + timeout 600), ночь и newsctl под замком, бриф видит отставание. ОТК 2 круга: два критика + сверка со спекой нашли 20+ дыр (обрыв обхода на черновике, стирание текста при переименовании папки, один чат валил прогон, ядовитая строка останавливала заливку, atlas_ro читал переписку, копии базы 644, ночь молча пропускала сбор, ссылки считались фото, «не хранить вовсе» подменено «без текста», сломанный чат выпадал навсегда) — закрыты, проверены на временной базе и подставных чатах (14/14). Экзамены на финальной версии: 7 зелёных, 24.1/24.2 красные из-за противоречия критериев (канал @pulscenru), 24.3 — вышедшая группа ИСЕТЬ. Регресс: экзамены С23 20/20.

→ Ответы владельца: (1) хранить ли чужие каналы в рабочих папках (рекомендую да → 24.1/24.2 зелёные, 24.5 уточнить); (2) 24.3 сверять по чатам, где он остаётся; (3) 24.11 текст личных + списки personal_exclude/skip_chats; (4) усилить экзамены 24.1/24.6/24.9/24.10 и добавить 24.11. Потом С25 Пульс.

15.10.2026, 10:47:23 · С24 · claude

С24 «Телеграм в базе целиком»: найдено, почему база видела 6–23% исходящих (ночной tg-collect берёт только «ценное», не видит «Личные» с флагами contacts/non_contacts, окно сутки без догона). Написан архиватор tg-archive.py (метки min_id, догон, буфер SQLite, заливка psql одной транзакцией), миграция 035 (tg_chats, tg_messages, вид tg_daily), бриф пишет «Архив телеграма отстаёт», night.sh с общим замком подготовлен. История 01.09–15.10 залита в буфер cfru: 16 622 сообщ., 169 чатов, 4 мин, FloodWait макс 5 с. Сверка с дампом 07.10: 98,07% (без вышедшей группы ИСЕТЬ 99,83%), коротких 118/120. Заливка проверена на временной pg15: идемпотентна, поймана ошибка %-форматирования. Экзамены: 24.6 и 24.10 зелёные, остальные ждут выката.

→ Ждём «да» владельца на выкат: дамп базы → миграция 035 + модель → пересборка backend → крон */10 (flock -n -E 0) → night.sh с замком → первая заливка → экзамены 24.1–24.9, 24.2 прогоном 25 мин → ОТК. Решения владельца: текст личных чатов (24.11), сверка 24.3 только по чатам, где он остаётся. Потом С25 Пульс.

10.10.2026, 12:34:08 · С23 · claude

10.10: С23 «Здоровье айфона в AITODO» выкачено по «да на прод». Таблицы health_daily/sleep/workouts/keys/ingest_log (миграция 034), ручки /api/health/ingest (ключ X-Health-Key только на приём), /daily, /weekly, /month; разбор чисел и дат по-русски, сон по часам, шаги по одному источнику. Экзамены exam_parse 30/30, exam_db 20/20 на временной базе, масштаб: вся история дважды без дублей. На проде залит экспорт 10.10: 19 516 строк, 878 ночей, 691 тренировка. Инструкция команды /lab/komanda-zdorovye/.

→ 23.7: после «трачу» запустить health_digest_store.py (сводки месяцев в склад, проект «Личные дела»). 23.8: владелец собирает команду, проверить первый приём origin=shortcut в health_ingest_log и подогнать разбор под реальный вид. Потом ОТК спринта и учёт в ретро (недельные цифры из /weekly).

07.10.2026, 07:57:38 · S22 · claude

07.10: Linear выкачен (первый запуск 07:35 UTC, 4 задачи во Входящих). Затем по просьбе владельца всё рабочее Fit&Lead развели с Лией: Битрикс-сводки, напоминания по задачам «Фит Лид», лиды РЕКЛ БА и завод статей дашборда идут @fitleadmy_bot. Авито/ISKRA остаются в Лии (решение владельца).

→ 08.10 10:00 проверка сводки Linear (Проверки по сроку). Хвосты: в дашборде Fit&Lead переименовать LIA_BOT_TOKEN в WORK_BOT_TOKEN при следующем плановом выкате; закрытие записи во Входящих при закрытии задачи в Linear.

07.10.2026, 07:26:22 · S22 · claude

07.10.2026: сводка Linear от 30.09 ни разу не работала (ключа не было) и видела только назначения. Переписана: инбокс Linear каждые 10 минут, отдельный бот @fitleadmy_bot с контекстом задачи, сводка «ждут ответа» в 10:00, назначения и упоминания во Входящие (источник linear, проект «Фит Лид»). Экзамены 14/14, сухой прогон на живом инбоксе, проверка на базе с откатом. Выкачено по «да, катим»: бэкап .backup-20261007, .env 600, пересобраны backend и frontend.

→ Дождаться первого запуска (07:35 UTC): во Входящих 4 задачи (CDT-993, 1044, 1050, 1088). 08.10 10:00 — проверка сводки (задача в Проверках по сроку). Хвосты: закрытие записи во Входящих при закрытии задачи в Linear не сделано.

02.10.2026, 05:42:11 · S21 · claude

С21 «Встречи не теряются, запись не забывается», 02.10. Причина «встреч нет в виджете»: подтягивание из Битрикса работало (раз в 5 мин), но ночной перенос 00:05 уводил прошедшие встречи в бэклог со стёртой датой (38 встреч, 21 из Битрикса). Сервер: прошедшая встреча теперь completed на своём дне; обмен возвращает встречу из бэклога, отклонённую в Битриксе снимает (cancelled + метка), снова принятую возвращает, перенесённую на будущее открывает; разово возвращено 19 встреч с 26.08. Виджет 1.3.3: сторож звонков по реестру микрофона Windows (Телемост, Зум, Скайп, Скайп для бизнеса, Телеграм после 30 с; браузер нет), окошко у часов без кражи фокуса с названием встречи из дня, «звонок закончился — остановить?». ОТК 3 круга: найдено и закрыто 13 дыр (ложное «закончился», потеря окошка при входе в звонок, Телеграм-переподключение, двойной Enter, двойной старт и др.), критерии 21.1a–i, 21.2a–s. Экзамены: сервер 9/9, виджет 15/15 + живой.

→ 1) Владелец: подтвердить 21.1a (прошедшая встреча = completed, а не todo). 2) Владелец: 17 встреч в бэклоге не из Битрикса + 2 удалённых собеседования — закрыть как прошедшие? 3) Руками на встрече: 21.3a (окошко на настоящем звонке в Телемосте), 21.2d (Записать), 21.2s (запись из трея без старого названия). 4) Проверка по сроку 09.10 (id 7f28df71): начинаются ли записи вовремя. 5) Решение по Enter без щелчка (глобальная клавиша?).

23.09.2026, 03:38:08 · С20 · claude

23.09: у Лии появились инструменты склада (save_knowledge, find_knowledge). Раньше «запиши в базу данных» уходило во Входящие, знание терялось в очереди разбора. Экзамены 6/6 + живой прогон. Созвон с Дмитрием по Принтфлагу (сайт по образцу РусФлага, лендинги по рубрикам, парсер цен, анализ конверсий) занесён материалом 1253 и задачей 1245 с пятью подзадачами.

→ Проверить на живой фразе: сказать Лие «запиши в базу знаний …» и убедиться, что материал появился. Дальше при желании: kind по смыслу (решение/факт/идея) и автоссылка материала на задачу.

23.09.2026, 03:15:21 · С19 · claude

23.09 (вторая правка дня): по слову владельца добавлены два пинга. 16:30 при перерыве в еде 5+ часов зовёт белок вместо шоколадки; 18:00 пн-пт разгрузка головы (5 вариантов, ротация по дню). Экзамены 19.16 и 19.17, всего 13/13, спека и критерии обновлены, выкачено, 15 заданий body_*.

→ Смотреть неделю: срабатывает ли разгрузка и меняется ли вечерний срыв. Ретро в пятницу по user-day-journal. 19.6 (фото еды) всё ещё не проверено живьём.

23.09.2026, 03:11:40 · С19 · claude

23.09: Лия перестала записывать еду «по плану» (решение владельца: ест другое в 70% случаев). Предложение меню осталось, в журнале только сказанное. Правка + переписанные экзамены 19.7/19.11, 11/11, спека и критерии обновлены, выкачено. Вчерашние ложные записи plan_default удалены из AITODO.

→ Владельцу предложены два пинга, ждут его слова: «не ел N часов, нужен белок» вместо перекуса в 16:30 и разгрузка в 18:00 (22.09 перегруз кончился срывом на пиццу и мыслью про виски). Проверка 24.09 по сроку.

21.09.2026, 15:10:28 · С19 · claude

21.09: первый живой день «Тела»: 5 пингов дошли, еда занесена из чата (роллы, сникерс, рёбра, кола → 1550 ккал), подходы владелец делал в виджете ПК (3 пачки) — теперь считаются. Починены два бага повторяющихся задач (время паттерна как UTC; stop без записи end_date). Встречи ПЦ на неделю в AITODO и «Встреча» в Битрикс; дубли из синка отменены.

→ Карточка дня 20:30 покажет 4 из 4. Ретро в пятницу по дневнику user-day-journal. Синк Битрикса: не тянуть наши заглушки. 19.6 фото еды всё ещё не проверено живьём.

20.09.2026, 11:38:05 · С19 · claude

20.09: спринт С19 «Тело» собран за сессию: спека docs/BODY.md, критерии BODY-ACCEPTANCE.md, 11 экзаменов + 2 живых зелёные, модуль выкачен в lia-backend, 14 заданий body_* в планировщике, быстрые пути в телеграме, фото еды через gemini-2.5-flash. Владельцу ушло вводное сообщение и пробный пинг.

→ Пн: первый живой день. 19.6 проверить по фото обеда. Проверка по сроку 24.09. Дальше С2 (Apple Health) и С3 (страница «Тело»). Ловушка: AITODO «сегодня» в UTC, день считать в +5 на стороне Лии.

20.09.2026, 09:20:41 · С17 · claude

20.09: планирование недели 21-27.09 пилотом plan-horizon: 6 планов через plan_store.py (12 новых задач, 14 обновлённых), дни и часы пн-пт через /day/layout, 3 повторяющихся блока (спорт, готовка). Попутно: сборщик телеги без ботов (С15), 97 материалов парсера удалены по «да» владельца. Страницы: /lab/sport-eda, /lab/fitlead-strategy (черновик стратегии 3 проектов).

→ Пн: владелец смотрит стратегию (1152) и гайд интервью (1155 через ИИ). Ср: стратегия Нине после «ок». Пт: ретро недели. Ловушка: время в recurrence_pattern хранится в UTC.

20.09.2026, 09:05:42 · С18 · claude

18.8 «Сделал» в «Раскидать»: третий исход рядом с «выкинуть». Статус done у входящих, POST /api/inbox/{id}/done, кнопка «Сделал · x», задача-сирота → completed. 3 экзамена зелёные на проде, выкачено 20.09.

→ Владельцу посмотреть кнопку глазами на /sort. По желанию: та же кнопка в «Разобрать» и в виджете «Входящие» на ПК (там пока только выкинуть).

20.09.2026, 08:54:12 · С15 · claude

20.09: сборщик из телеграма перестал читать ботов (Parser Fit lead давал 109 записей за неделю). 18 входящих от бота отброшены. Планирование недели 21-27.09 по plan-horizon: факты собраны, экран согласования показан владельцу.

→ Ждём «ок» на план недели → plan_store.py + дни. Ждём «да» на удаление 97 материалов от парсера из склада. Дальше: стратегия по 3 проектам страницей, план спорта и еды.

15.09.2026, 03:28:04 · · claude

Виджеты 1.2.0: «Фокус» и «Встреча» получили свои значки у часов. Клик — виджет выпрыгивает над панелью, правый клик — включить фокус или начать запись без окна, значок показывает состояние. Собрано, установлено владельцу, проверено снимками экрана и эмуляцией кликов.

→ 1) Владельцу посмотреть глазами: значки у часов, клик по микрофону и кольцу. Если значки уехали за стрелку «^» после перезагрузки — вытащить мышкой один раз, Windows запомнит. 2) Горячие клавиши на фокус и запись не делал — предложить, если значков мало. 3) Общий значок виджетов остался как был: список всех виджетов в правом клике.

15.09.2026, 03:13:37 · С17 · claude

14-15.09: второй прогон plan-horizon на неделе 14-18.09 целиком. Факты без вопросов (brief, tasks, Atlas), 5 результатов недели, сверка списка владельца с бэклогом (дубли не заведены), занесение plan_store.py в 6 спринтов (12 новых, 27 обновлённых), дни через /plan, часы через /day/layout пн-пт. Находки: блок «Без времени» на дне владелец не читает как задачи дня (заведена задача в С1); ночной откат незакрытых задач в «ждёт разбора» вычищает день целиком, наутро вчерашнее надо перепроверять руками; рекуррентная встреча ПЦ (задача 50) даёт инстанс cancelled; раскладка считает дедлайн 18:00 чужих дней 30-мин блоком по дизайну. Плюс сбор вопросов Мише из телеграма (5 голосовых расшифрованы GigaAM).

→ Планирование дня 15.09: владелец отмечает вчерашнее, накидывает новое, раскладка. Решить, что делать с ночным откатом незакрытых задач (сохранять день или спрашивать). Ретро недели в пятницу 16:00.

10.09.2026, 08:54:46 · С18 · claude

Первый живой прогон раскладки на реальном дне владельца сразу нашёл дыру во вчерашней правке: занесение плана ставит задачам дедлайн 18:00, а правка «дедлайн это занятое время» из-за этого выводила их из кандидатов, и раскладка оставляла день пустым при двух десятках дел. Починено: дедлайн считается занятым только у задач, не назначенных на этот день; то же исправлено в «Моём дне», где такая задача рисовалась блоком вместо списка «Без времени». Выкачено и проверено. В работе по кабинету: 22 задачи владельца занесены через plan_store (создано 20, четыре существующие обновлены вместо дублей), разложены по дням и часам, вычищен мусор от прогонов экзаменов (5 задач и 17 напоминаний). Знания из файла наследства маркетинга Fit&Lead занесены в склад: 15 материалов плюс полная выгрузка, поиск проверен.

→ Владелец переразложил план сам и назвал правила: срок задаёт встреча, к которой задача нужна; контент через ИИ идёт каждый день и не переносится; автоматизируемое не занимает его день; задачи одного контура делаются пачкой в день, когда по нему и так идёт разговор; сбор из телеграма доводить до текущего момента, а не до полуночи. Правила записаны в память aitodo-planning-patterns. Отсюда две доработки кабинета: повторяющиеся задачи для ежедневного контента и учёт встреч дня при выборе срока. Осталось по С18 глазами: 18.2b, 18.5a, 18.7j, 18.7k.

09.09.2026, 12:04:20 · С18 · claude

С18 «Один разбор» выкачен и принят ОТК. Разбор входящих идёт один раз: карточка несёт автора, чат, время и подсказки, исходную расшифровку, а разбор ставит проект, размер, день и исполнителя. Появились POST /api/day/layout (раскладка дня по правилам, кнопка в «Моём дне», режим «разложи завтра» в plan-day), tasks.person_id с поручением на 15 минут и напоминанием Лии, состояние «день без часа». ОТК двумя подагентами дал 21 находку: поручение съедало день целиком (экраны слали подсказку размера вместо 15 минут), двойное нажатие рождало две задачи, пересекающиеся блоки режима клали две задачи на один час, раскладка прошлого дня делала задачи просроченными, пункты встреч (246 из 300 входящих) не несли ни времени, ни подсказок. Всё это закрыто критериями 18.7a-k. Экзамены 27 из 27, регресс С17 16 из 16. Найден дрейф репо и прода: meetings.py на сервере был новее, взял серверную версию за основу.

→ Владельцу глазами: 18.2b (день без часа в «Моём дне» и неделе), 18.5a («Быстро» в «Разобрать»), 18.7j (старая задача из бэклога на день), 18.7k (подсказка дня). Первый живой разбор входящих с днями и поручением. Решить: AI Office cron падает с марта на сигнатуре run_cron_task (не трогал, починка запустит платные прогоны). Забрать серверный meeting_digest.py в репо. Пояс: раскладка берёт пояс браузера, сводка — зашитый +5, расходится только в поездке.

09.09.2026, 10:51:14 · С17 · claude

Пилот скилла plan-horizon на живых данных. Нашлась расшифровка встречи 21.08 (лежала под названием fdf без проекта, переименована и привязана к Фит Лид, копия в базе знаний). Из неё взяты KPI сентября: выручка 2 млн, 150 регистраций блогеров, 75 постов по CPA. Владелец ответил на четыре вопроса объёма. Заведён спринт «Сентябрь · Фит Лид» (18): 30 задач, 6 верхних, 3 стадии через ИИ, 5 напоминаний «Ждём ответ», вложения из склада, паспорт по КП-агенту в базе знаний и в складе (материал 651). Блоки на 09.09 и 10.09 расставлены по часам. Экзамены: 16 зелёных, 0 красных.

→ Ручные критерии 17.1a-c и 17.6b проверяются на этом же пилоте по ходу недели. Для живого круга Рубки нужен контур FitLead с папкой проекта в её настройках.