## 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** в журнале владельца сервиса есть запись об остановке с причиной