Files
transcriber/openspec/changes/archive/2026-08-15-remove-telegram-intake/tasks.md
T
av 8f7c3a057a удалён вход Telegram, владелец записи стал обязателен в схеме
- убраны клиент бота, транспорт обновлений, отправитель сообщений, сборка
  входа при старте, секция настроек и зависимость go-telegram-bot-api; из
  конвейера ушла доставка ответа отправителю — исход виден опросом готовности.
  Колонки адресата и значение источника остались в схеме: применённые шаги не
  переписываются
- шаг 202608140003 запрещает пустого владельца у аудиозаписи и у файла;
  существующие строки он не проверяет, и это принято сознательно — искать их
  надо запросом до выкладки
- ревью нашло два пред-существующих дефекта, оба закрыты: пустой второй ответ
  распознавателя стирал сохранённую расшифровку, а пустая расшифровка перестала
  быть заметной вместе с убранной доставкой. Попутно поднят golang.org/x/image
  до v0.45.0 — красный шаг vulns, воспроизводился и на чистом master
2026-08-15 07:24:35 +03:00

12 KiB

1. Модель записи и отображение в хранилище

  • 1.1 Убрать из entity.AudioRecord поля адресата ответа TgChatId и TgReplyMessageId
  • 1.2 Оставить константу entity.SourceTelegram и объявить её комментарием историческим значением: на неё ссылается применённый шаг схемы 202608140002, переписывать который запрещено инвариантом проекта
  • 1.3 Сделать владельца записи обычной строкой вместо ссылки, допускающей отсутствие, и провести это через applyToRecord и recordToAudioRecord
  • 1.4 Убрать колонки адресата из record_mapping.go в обоих направлениях; заведёнными в схеме они при этом остаются
  • 1.5 Завести новый шаг схемы: колонка владельца у аудиозаписи и у файла перестаёт принимать пустое значение. Откат шага возвращает необязательность
  • 1.6 Убедиться, что ни один применённый шаг схемы не изменён: task migrations отвечает нулём
  • 1.7 Проверить, что конвейер заводит приведённую копию файла с владельцем записи: без этого первый же шаг приведения упрётся в обязательность колонки

2. Служба расшифровки

  • 2.1 Убрать метод приёма записи от бота CreateJobFromTelegram
  • 2.2 Убрать из службы отправителя сообщений: поле, параметр конструктора, отправку текста, сообщение о неудаче и запись о недоставке
  • 2.3 Убрать метрику недоставленных ответов вместе с её причинами
  • 2.4 Убрать человеческие тексты отказа, которые уходили отправителю: их единственным читателем была отправка. Шаг, доводящий запись до конечного рубежа, остаётся — он двигает рубеж, — и обращений наружу не делает ни одного
  • 2.5 Убрать из internal/archrules транспорт internal/controller/tg из перечня транспортов: правило требует существования названных пакетов, и без этой правки гейт краснеет удалением каталога

3. Вход и сборка сервиса

  • 3.1 Удалить пакет internal/adapter/telegram целиком
  • 3.2 Удалить транспорт internal/controller/tg целиком
  • 3.3 Удалить telegram_build.go и telegram_build_test.go
  • 3.4 Убрать из main.go сборку входа, запуск транспорта в отдельной горутине и остановку бота при завершении
  • 3.5 Убрать из internal/contract договор об отправителе сообщений
  • 3.6 Убрать выставление метки telegram у признака поднятого входа; метка http остаётся

4. Настройки и зависимости

  • 4.1 Убрать TelegramConfig, её умолчания и проверку обязательности ключа telegram.enabled
  • 4.2 Убрать ключ server.users_while_list из структуры настроек и умолчаний. Имя написано с опечаткой — while вместо white, — и она стоит «Расхождением» в docs/conventions/config.md: удаление ключа закрывает и его
  • 4.3 Убрать секцию [telegram] из config.example.toml вместе с пояснениями. Ключа списка допущенных в образце нет — это второе записанное «Расхождение», и оно закрывается тем же удалением
  • 4.4 Прогнать go mod tidy и убедиться, что go-telegram-bot-api ушёл из go.mod и go.sum

5. Проверки

  • 5.1 Поправить тесты, опирающиеся на убранный вход: приём, владение, конвейер, метрики, недоставка, завершение работы
  • 5.2 Оставить проверку того, что запись без владельца не заводится: приём без учётной записи отвечает 403 и не заводит ни файла, ни записи
  • 5.3 Оставить проверку того, что запись без владельца не достаётся опросом: ответ тот же, что и на неизвестный идентификатор
  • 5.4 task gate зелёный целиком
  • 5.5 Поведенческая проверка на живом сервисе: подъём с файлом настроек без секции [telegram], приём записи по HTTP, опрос готовности, признак поднятого входа в метриках

6. Документы канона

  • 6.1 Паспорт: убрать потребителя «Пользователь Telegram» и сценарии 3 и 4; поправить строку об основном входе и сценарий 6 — сообщения о неудаче отправитель больше не получает, а видит исход опросом. Убранный вход записать событием с датой, как записаны прочие сдвиги границы
  • 6.2 CLAUDE.md: убрать инвариант «Бот отвечает только тем, кто в белом списке» (critical) целиком; переписать инвариант «Остановленная запись сообщает отправителю, какой бы ни была причина» (major) в терминах опроса готовности; переписать инвариант «Принятая запись не теряется молча» (major) — он требует сообщить пользователю и называет состояние failed, которого нет с прошлой задачи; снять «и без ответа отправителю» из инварианта о держателе захвата; поправить раздел «Что это» (входов больше не два), «Стек» (зависимость ушла) и запрет «Боевым токеном бота не запускаться» вместе с рецептом локального подъёма через telegram.enabled = false
  • 6.3 docs/architecture.md: поправить обзор capability поимённо — буллеты intake (признак включения входа), pipeline (недоставленный ответ), access (запись из Telegram без владельца), строку «поведение прочих узлов, включая приём из Telegram, живёт только в коде», принцип «бот, HTTP-сервер и воркеры в одном бинарнике» и строку «через него идут оба входа» в «Единых точках проекта»; docs/security.md — убрать вход из периметра; docs/database.md — сказать про колонки, оставшиеся без кода; docs/conventions/ — снять ключи бота и закрыть оба «Расхождения» про users_while_list
  • 6.4 docs/review.md: снять род узла «транспорт internal/controller/tg» и «клиент внешнего сервиса adapter/telegram» из типовых узлов, ложноположительное про запись без владельца, вопрос «через него идут оба входа», триггер метки «трогает оба входа сразу» и рецепт живого прогона через telegram.enabled = false
  • 6.5 README.md: убрать вход из описания сервиса и из настроек
  • 6.6 Проза актуальных спек, которую дельты не правят: разделы Purpose у intake, pipeline и access — дельты правят только требования, и проза иначе уедет в архив с обещаниями про бота

Критерии приёмки

Постановка пришла текстом и критериев не назвала. Ниже — предложенные; приняты они после ответа человека на чекпоинте.

  1. Ни одного упоминания входа Telegram нигде в дереве, кроме мест, где оно законно. Оракул: grep -ri telegram по всему репозиторию; законны ровно четыре места — применённые шаги схемы и константа источника, архив изменений openspec/changes/archive/, записи решений docs/adr/ и историческая часть журнала ревью. Всё прочее — находка. Оракул нарочно шире кода: прошлые удаления теряли документы именно потому, что их сверяли грепом по internal/.
  2. Применённые шаги схемы не переписаны, колонки tg_chat_id, tg_reply_message_id и значение telegram перечня источников на месте. Изменение добавляет ровно один новый шаг — обязательность владельца. Оракул: task migrations отвечает нулём, git diff по каталогу шагов показывает только добавленный файл.
  3. Запись без владельца завести нечем ни одним путём. Оракулы: тест приёма, где сессия не даёт учётной записи, — ответ 403, ни файла, ни аудиозаписи не заведено; тест хранилища — сохранение записи и файла с пустым владельцем отклоняется схемой.
  4. Отправитель узнаёт об остановке опросом готовности. Оракул: тест опроса на остановленной записи — поле рубежа несёт достигнутый рубеж, поле остановки несёт истину, машинного текста отказа в ответе нет.
  5. Сервис поднимается с файлом настроек без секции [telegram] и принимает запись по HTTP. Оракул: живой запуск по разделу команд CLAUDE.md, POST /api/audio отвечает 201, GET /api/status/:id отвечает 200.
  6. Признак поднятого входа несёт метку http и не несёт метки telegram. Оракул: чтение адреса метрик у поднятого сервиса.
  7. task gate зелёный целиком.