Files
transcriber/openspec/specs/intake/spec.md
T
av 6c04c801c9 http: тесты приёма переписаны на подставные адаптеры
- проверки больше не зовут ffprobe и не меняют рабочий каталог процесса;
  добавлены случаи на отказ чтения метаданных и на отсутствие поля audio
- заведена спека intake на приём по HTTP, ADR о подставных адаптерах,
  запись в журнал ревью о проверке, которая не могла упасть
- go test снят из объявленных долгов CLAUDE.md, послабление errcheck
  для _test.go в .golangci.yml убрано
2026-08-11 08:35:11 +03:00

6.6 KiB
Raw Blame History

intake Specification

Purpose

Приём записи и опрос готовности задачи расшифровки: что считается принятой записью, что уезжает в ответ и что происходит, когда запись не удалось прочитать.

Описан пока только приём по HTTP — тот, что нормируют проверки. Приём из Telegram делит с ним общий шаг заведения задачи, но требований на него нет: требование, написанное без проверки, — предположение, а не норма. Первая задача, которая трогает поведение приёма из Telegram, дописывает его сюда.

Requirements

Requirement: Приём записи по HTTP

Сервис SHALL принимать запись от внешней программы запросом POST /api/audio с телом multipart/form-data и полем audio. Принятая запись MUST быть сохранена и получить заведённую под неё задачу расшифровки в состоянии created; ответ MUST нести идентификатор задачи полем job_id и её состояние полем status.

Имена полей ответа нормативны: контракт HTTP API объявлен проектом необратимым, и переименование поля ломает внешнюю программу молча.

Приём не судит о годности записи сам: расширение он берёт из имени файла, а пригодность содержимого узнаёт у источника метаданных.

Scenario: Запись принята

  • GIVEN источник метаданных читает запись и отдаёт её длительность
  • WHEN программа шлёт POST /api/audio с полем audio
  • THEN ответ имеет код 201, а в теле лежат непустой job_id и status со значением created
  • AND содержимое записи целиком лежит в каталоге хранения одним файлом

Scenario: Поля с записью нет

  • WHEN программа шлёт POST /api/audio без поля audio
  • THEN ответ имеет код 400 и сообщение об отсутствии записи
  • AND ни файла, ни задачи не заводится

Scenario: Размеру записи приём не судья

  • GIVEN источник метаданных читает запись и отдаёт её длительность
  • WHEN программа шлёт запись нулевой длины
  • THEN ответ имеет код 201: собственного порога по размеру у приёма нет

Requirement: Имя файла в хранилище

Сервис SHALL сохранять принятую запись под собственным именем — идентификатором, к которому приписано расширение из имени файла отправителя. Имя, данное отправителем, MUST не попадать в хранилище: оно приходит извне и содержимым своим приёму не подконтрольно.

Расширения в присланном имени нет — сервис MUST подставить .audio, чтобы у файла на диске расширение было всегда.

Scenario: Расширение взято из имени отправителя

  • WHEN программа шлёт запись с именем test.mp3
  • THEN файл в каталоге хранения имеет расширение .mp3

Scenario: Имени без расширения назначено своё

  • WHEN программа шлёт запись с именем test без расширения
  • THEN файл в каталоге хранения имеет расширение .audio

Requirement: Отказ чтения метаданных

Сервис SHALL отвечать отказом, когда источник метаданных не смог прочитать принятую запись. Ответ MUST иметь код 500, а причина отказа MUST не попадать в тело ответа: она принадлежит журналу, а не отправителю.

Scenario: Источник метаданных вернул ошибку

  • GIVEN источник метаданных не может прочитать запись
  • WHEN программа шлёт POST /api/audio с этой записью
  • THEN ответ имеет код 500
  • AND задача расшифровки не заводится

Requirement: Опрос готовности задачи

Сервис SHALL отдавать состояние задачи расшифровки по запросу GET /api/status/:id. Ответ MUST нести идентификатор полем job_id, состояние полем status и время заведения полем created_at, а текст расшифровки полем transcription_text, и это поле MUST отсутствовать в ответе, пока текста нет: пустая строка на месте отсутствующего текста читается как «расшифровка пуста».

Scenario: Задача найдена

  • WHEN программа спрашивает состояние заведённой задачи
  • THEN ответ имеет код 200 и несёт job_id, status и created_at

Scenario: Расшифровки ещё нет

  • WHEN программа спрашивает состояние задачи, которая ещё не дошла до текста
  • THEN поля transcription_text в ответе нет вовсе

Scenario: Задачи с таким идентификатором нет

  • WHEN программа спрашивает состояние по неизвестному идентификатору
  • THEN ответ имеет код 404 и сообщение о ненайденной задаче