хранилище переехало с PocketBase на SQLite со своим каталогом файлов
- база своя: два пула, захват одним UPDATE ... RETURNING, шаги схемы на goose под файловым замком, одна миграция начальной схемы вместо семи прежних - транспорт переписан на net/http: свои слои, свой ограничитель частоты, отдача файла с проверкой владельца; панель /_/ и пространство /api/ исчезли - по находкам ревью: журнал не пишет путь под корнем приложения, ключ бюджета читается справа налево, узнавание известного идёт читающим пулом
This commit is contained in:
@@ -1,8 +1,19 @@
|
||||
# recognition Specification
|
||||
|
||||
## Purpose
|
||||
TBD - created by archiving change record-centric-model. Update Purpose after archive.
|
||||
|
||||
Что принадлежит внешнему распознавателю и как это лежит у нас: попытка
|
||||
распознавания отдельной строкой, сырой ответ провайдера целиком, структура
|
||||
реплик, построенная из сохранённого ответа, и граница, за которую разбор чужого
|
||||
формата не выходит.
|
||||
|
||||
Движение записи по рубежам нормирует `pipeline`, хранение текста и структуры —
|
||||
`storage`, закрытость содержимого — `storage` же.
|
||||
|
||||
Сознательно не описан формат ответа конкретного провайдера: он живёт в адаптере
|
||||
и в записках разведки, а не в норме поведения.
|
||||
## Requirements
|
||||
|
||||
### Requirement: Попытка распознавания хранится отдельно от записи
|
||||
|
||||
Сервис SHALL держать всё, что принадлежит внешнему распознавателю, отдельной
|
||||
@@ -39,24 +50,37 @@ TBD - created by archiving change record-centric-model. Update Purpose after arc
|
||||
### Requirement: Сырой ответ провайдера сохраняется целиком
|
||||
|
||||
Сервис SHALL сохранять ответ распознавателя целиком, в том виде, в каком он
|
||||
пришёл, и MUST хранить его вложением, а не колонкой строки попытки.
|
||||
пришёл, и MUST хранить его **отдельным файлом в каталоге данных**, а не колонкой
|
||||
строки попытки.
|
||||
|
||||
Хранится он потому, что **результат операции у провайдера не переспрашивается**:
|
||||
связь реплики с говорящим сервис строить пока не умеет, и когда научится, архив
|
||||
пересчитается из сохранённого без повторной оплаты.
|
||||
|
||||
Вложением, а не колонкой, — потому что шаг опроса читает строку попытки часто, а
|
||||
хранилище читает запись целиком: ответ на многочасовую запись, положенный
|
||||
колонкой, ехал бы в память при каждом опросе.
|
||||
Файлом, а не колонкой, — потому что шаг опроса читает строку попытки часто, а
|
||||
репозиторий читает строку целиком: ответ на многочасовую запись, положенный
|
||||
колонкой, ехал бы в память при каждом опросе. Где именно этот файл лежит,
|
||||
нормирует capability `storage`, требование «Файл записи живёт в хранилище»:
|
||||
третьим файлом в подкаталоге записи, наравне с копиями аудио. Копией аудио он при
|
||||
этом не считается — их у записи по-прежнему две.
|
||||
|
||||
Чтение строки попытки шагом опроса MUST не тянуть за собой сохранённый ответ.
|
||||
|
||||
Сохранённый ответ — это полный текст речи, и закрыт он MUST быть наравне с самой
|
||||
записью: поле вложения помечено защищённым, правило просмотра пускает только
|
||||
владельца связанной записи, ссылка не попадает ни в журнал, ни в метку метрики.
|
||||
Норму держит capability `storage`, требование «Содержимое записи закрыто во всех
|
||||
коллекциях, где лежит»; здесь она названа потому, что коллекция попыток — то
|
||||
место, куда содержимое приезжает впервые.
|
||||
записью. Закрытость MUST держаться **проверкой владельца в обработчике сервиса**:
|
||||
адреса, которым сохранённый ответ читают снаружи, сервис MUST не заводить вовсе, а
|
||||
всякий адрес, отдающий содержимое записи, MUST судить владельца связанной
|
||||
аудиозаписи сам, при каждом обращении. Пометка поля защищённым и правило
|
||||
просмотра коллекции, которыми закрытость держалась прежде, — механизмы
|
||||
встроенного хранилища, и их не остаётся; норма от этого не ослабла, а перестала
|
||||
зависеть от настройки, которую мы не писали.
|
||||
|
||||
Путь к файлу сохранённого ответа MUST не попадать ни в журнал, ни в метку
|
||||
метрики, ни в ответ отправителю.
|
||||
|
||||
Норму держит capability `storage`, требование «Содержимое записи закрыто везде,
|
||||
где лежит»; здесь она названа потому, что попытка распознавания — то место, куда
|
||||
содержимое приезжает впервые.
|
||||
|
||||
#### Scenario: Ответ сохранён и читается позже
|
||||
|
||||
@@ -70,6 +94,14 @@ TBD - created by archiving change record-centric-model. Update Purpose after arc
|
||||
- **WHEN** шаг опроса читает строку попытки
|
||||
- **THEN** сохранённый ответ в память при этом не читается
|
||||
|
||||
#### Scenario: Адреса чтения сохранённого ответа у сервиса нет
|
||||
|
||||
- **GIVEN** запись принята одним узнанным и прошла распознавание
|
||||
- **WHEN** другой узнанный ищет адрес, которым читается сохранённый ответ этой
|
||||
записи
|
||||
- **THEN** такого адреса у сервиса нет
|
||||
- **AND** содержимого он не получает
|
||||
|
||||
### Requirement: Структура реплик строится из сохранённого ответа
|
||||
|
||||
Сервис SHALL строить структуру реплик записи из сохранённого ответа провайдера и
|
||||
@@ -148,4 +180,3 @@ MUST не обращаться к провайдеру повторно ради
|
||||
- **WHEN** провайдер отвечает идентификатором операции
|
||||
- **THEN** идентификатор сохраняется в строке попытки
|
||||
- **AND** повторная отправка той же записи не заводится
|
||||
|
||||
|
||||
Reference in New Issue
Block a user