Files
transcriber/openspec/changes/archive/2026-08-15-app-json-contract/specs/pipeline/spec.md
T
av 3a2da3004b приём и чтение записей сведены к одному контракту приложения
- адреса приложения переехали в своё пространство `/app/`, опрос готовности
  убран целиком: рубеж и причину остановки владелец узнаёт карточкой записи,
  текст — отдельным адресом названного вида
- заведена единая точка отображения доменной ошибки и слой, приводящий к той же
  форме отказы библиотеки: тело несёт машиночитаемый код рядом с сообщением
- у записи появились имя файла отправителя, длительность и размер своими
  колонками, а у ленты владельца — свой индекс: без него страница сканировала
  весь архив сервиса
2026-08-15 13:51:23 +03:00

7.4 KiB

MODIFIED Requirements

Requirement: Число отказов ограничивает повторы шага

У аудиозаписи SHALL быть число отказов. Оно MUST расти при каждом захвате и MUST возвращаться к нулю, когда шаг завершился без отказа либо отложил работу. Рост при захвате, а не при отказе, засчитывает попытку и записи, брошенной на середине: шаг, уносящий с собой процесс, до объявления отказа не доходит никогда.

Остановка сервиса отказом не считается. Шаг, прерванный отменой по собственной остановке сервиса, MUST возвращать число отказов назад и MUST не выносить записи приговора: запись не виновата в том, что нас перезапустили, и несколько выкладок подряд иначе останавливают здоровую многочасовую запись с приговором «отказы исчерпаны». Всякая другая причина, по которой шаг не дошёл до объявления исхода, отказ тратит.

Запись, захваченная с числом отказов сверх заданного предела, MUST останавливаться признаком тем, кто её захватил, и MUST не отдаваться шагу в работу. Остановка эта видна владельцу записи карточкой записи наравне с прочими — норму держит capability archive.

Этот сторож MUST отвечать только за повторы внутри шага. Время, проведённое записью в рубеже, MUST мериться отдельным сторожем: одно число не справляется ни с одной из двух обязанностей — опрос, вернувший «ещё в работе», обнуляет его, и зависшая чужая операция опрашивается вечно, а не обнулял бы — убивал бы здоровую запись.

Scenario: Запись отказывает на каждой попытке

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

Scenario: Шаг уносит процесс, не объявив отказа

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

Scenario: Остановка сервиса отказа не тратит

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

Scenario: Прошедшая запись отказов не копит

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

Requirement: Конвейер ответа отправителю не шлёт

Шаг конвейера SHALL доводить запись до достигнутого рубежа и MUST не обращаться к отправителю вовсе — ни с готовым текстом, ни с сообщением о неудаче. Исход своей записи владелец узнаёт карточкой записи и в панели владельца сервиса; адрес карточки и содержимое ответа нормирует capability archive.

Держатель нормы сменился вместе с убранным опросом готовности: прежде исход отдавал адрес опроса, нормированный capability intake, и адреса этого больше нет. Обязанность при этом не изменилась — изменилось только то, каким адресом она исполняется.

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

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

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

Scenario: Готовый текст отправителю не уходит

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

Scenario: Остановка видна карточкой, а не сообщением

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