Files
T
av c9b7765646 хранилище переехало с PocketBase на SQLite со своим каталогом файлов
- база своя: два пула, захват одним UPDATE ... RETURNING, шаги схемы на goose
  под файловым замком, одна миграция начальной схемы вместо семи прежних
- транспорт переписан на net/http: свои слои, свой ограничитель частоты,
  отдача файла с проверкой владельца; панель /_/ и пространство /api/ исчезли
- по находкам ревью: журнал не пишет путь под корнем приложения, ключ бюджета
  читается справа налево, узнавание известного идёт читающим пулом
2026-08-23 08:06:04 +03:00

4.4 KiB

MODIFIED Requirements

Requirement: Сырой ответ провайдера сохраняется целиком

Сервис SHALL сохранять ответ распознавателя целиком, в том виде, в каком он пришёл, и MUST хранить его отдельным файлом в каталоге данных, а не колонкой строки попытки.

Хранится он потому, что результат операции у провайдера не переспрашивается: связь реплики с говорящим сервис строить пока не умеет, и когда научится, архив пересчитается из сохранённого без повторной оплаты.

Файлом, а не колонкой, — потому что шаг опроса читает строку попытки часто, а репозиторий читает строку целиком: ответ на многочасовую запись, положенный колонкой, ехал бы в память при каждом опросе. Где именно этот файл лежит, нормирует capability storage, требование «Файл записи живёт в хранилище»: третьим файлом в подкаталоге записи, наравне с копиями аудио. Копией аудио он при этом не считается — их у записи по-прежнему две.

Чтение строки попытки шагом опроса MUST не тянуть за собой сохранённый ответ.

Сохранённый ответ — это полный текст речи, и закрыт он MUST быть наравне с самой записью. Закрытость MUST держаться проверкой владельца в обработчике сервиса: адреса, которым сохранённый ответ читают снаружи, сервис MUST не заводить вовсе, а всякий адрес, отдающий содержимое записи, MUST судить владельца связанной аудиозаписи сам, при каждом обращении. Пометка поля защищённым и правило просмотра коллекции, которыми закрытость держалась прежде, — механизмы встроенного хранилища, и их не остаётся; норма от этого не ослабла, а перестала зависеть от настройки, которую мы не писали.

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

Норму держит capability storage, требование «Содержимое записи закрыто везде, где лежит»; здесь она названа потому, что попытка распознавания — то место, куда содержимое приезжает впервые.

Scenario: Ответ сохранён и читается позже

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

Scenario: Опрос не тянет сохранённый ответ

  • GIVEN у попытки распознавания есть сохранённый ответ
  • WHEN шаг опроса читает строку попытки
  • THEN сохранённый ответ в память при этом не читается

Scenario: Адреса чтения сохранённого ответа у сервиса нет

  • GIVEN запись принята одним узнанным и прошла распознавание
  • WHEN другой узнанный ищет адрес, которым читается сохранённый ответ этой записи
  • THEN такого адреса у сервиса нет
  • AND содержимого он не получает