# 🐞 Убирать записанный файл, когда приём отказал на середине - **Тип:** fix - **Категория:** Очередь — Осиротевший файл — тот же отказ на середине, и чинится тем же местом приёма. - **Зачем:** Отказ чтения метаданных и отказ записи на диск оставляют файл в каталоге хранения без задачи и без учёта: сопоставить его не с чем, удалять приходится руками. - **Теги:** review-2026-08-11 Приём пишет файл на диск, потом спрашивает у источника метаданных длительность, потом заводит запись в учёте и задачу. Уборка при отказе есть **только на последнем шаге**: отказ `fileRepo.Create` зовёт `os.Remove`, а отказы записи на диск и чтения метаданных возвращают ошибку, оставляя файл лежать. Сопоставить такой файл не с чем: записи в `files` под него нет, задачи нет, имя — случайный идентификатор. На сервере это `data/files`, где лежат голосовые сообщения живых людей, а проект по паспорту «не хранит записи как архив». Найдено проходом `review-specs` ревью дизайна change `2026-08-11-fix-http-handler-tests`; отчёт триажа — `openspec/changes/archive/2026-08-11-fix-http-handler-tests/review/triage.md`. Вынесено сюда решением человека на контрольной точке. ## Воспроизведение Асимметрия видна в самом коде: ``` sed -n '110,160p' internal/service/transcribe.go ``` Ветка `fileRepo.Create` (строки 152–157) содержит `os.Remove(storageFilePath)` с комментарием «Удаляем файл если не удалось создать запись в БД». Ветки `io.Copy`, `dst.Close` и `metaviewer.GetInfo` (строки 116–133) возвращают ошибку без уборки, хотя файл к этому моменту уже создан. Прогоном: `TestCreateTranscribeJob_MetaViewerFailure` в `internal/controller/http/transcribe_test.go` доводит приём до этой ветки — после него в каталоге хранения лежит файл, а `countJobs` равен нулю. ## Затрагивает - `internal/service/transcribe.go`, функция `createTranscribeJob` — три ветки отказа между созданием файла и заведением записи в учёте; - `internal/controller/http/transcribe_test.go` — случай отказа метаданных получает проверку на отсутствие файла; - раскладка `data/files` не меняется: имена и формат прежние. ## Критерии приёмки - Отказ чтения метаданных не оставляет файла в каталоге хранения. Оракул — тест на подставном источнике, возвращающем ошибку: каталог пуст после запроса. - Отказ записи на диск на середине не оставляет частично записанного файла. Оракул — тест с источником данных, обрывающимся на середине чтения. - Уборка сама не заслоняет исходную ошибку: отправитель по-прежнему получает отказ, а причина уезжает в журнал. Оракул — тот же тест, код ответа и запись в перехваченном журнале. ## Рамки Уборка файлов, осиротевших **до** этой правки, сюда не входит: их надо найти сверкой каталога с учётом, и это отдельная работа с боевыми данными.