внутренняя модель перестроена вокруг аудиозаписи
- audiorecords вместо transcribe_jobs: приложения (texts, structures, recognitions, record_events, topics) живут своими коллекциями, ссылки на исходник и на приведённую копию перестали переставляться - рубеж называет достигнутое, отказ стал признаком остановки с причиной, а сторожей стало двое: число отказов и время в рубеже - воркеры потеряли специализацию, их число задаётся [pipeline] workers, шаг выбирается по рубежу, а захват отдаёт идентификатор и признак захвата
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# Остановка записи — признак, а не рубеж
|
||||
|
||||
- **Дата:** 2026-08-14
|
||||
- **Источник:** openspec/changes/archive/2026-08-14-record-centric-model/design.md,
|
||||
раздел «Остановка — признак, а не рубеж»
|
||||
|
||||
## Решение
|
||||
|
||||
Прежние состояния отказа и смерти (`failed`, `dead`) схлопнуты в **признак
|
||||
остановки** с причиной: `halted_at`, `halt_reason`, `error_text`. Достигнутый
|
||||
рубеж при остановке не стирается, и снятие признака продолжает работу с того
|
||||
места, где запись встала.
|
||||
|
||||
## Почему
|
||||
|
||||
Цитата источника:
|
||||
|
||||
> **Признак** — принято: рубеж переживает остановку, продолжение идёт с места
|
||||
> остановки, массовый перезапуск после выкатки правки делается одним
|
||||
> обновлением, а различие «мы рассудили» против «мы перестали пробовать»
|
||||
> остаётся причиной, которую человек читает.
|
||||
|
||||
Отвергнуты два варианта, оба с названной ценой:
|
||||
|
||||
> **Отдельное состояние на каждую причину** — отвергнуто: перечень состояний
|
||||
> закрыт схемой, и каждая новая причина стоила бы необратимого шага.
|
||||
>
|
||||
> **Оставить как есть** — отвергнуто: именно из-за этого перезапись состояния
|
||||
> руками в панели остаётся единственным способом вернуть запись в работу, и
|
||||
> делается он наугад.
|
||||
|
||||
Прежняя модель описана решением
|
||||
[ADR-2026-08-11-queue-as-pocketbase-collection](ADR-2026-08-11-queue-as-pocketbase-collection.md):
|
||||
там состояние «мертва» заводилось взамен признака `is_error`, и довод был тот
|
||||
же — «два способа вывести задачу из выборки расходятся». Довод устоял, а
|
||||
носитель сменился: теперь единственный способ вывести запись из выборки — этот
|
||||
признак, и состояние его больше не дублирует.
|
||||
|
||||
## Последствия
|
||||
|
||||
- `+` перезапуск перестал быть догадкой: запись продолжает с сохранённого
|
||||
рубежа, а не начинает конвейер заново.
|
||||
- `+` новая причина остановки стоит значения в закрытом перечне причин, а не
|
||||
нового состояния и не нового шага схемы.
|
||||
- `+` массовый возврат в работу после выкатки правки делается одним обновлением
|
||||
колонки.
|
||||
- `−` в выборке захвата появилось четвёртое условие, и рубеж перестал быть
|
||||
единственным, что выводит запись из работы: читать состояние записи теперь
|
||||
надо двумя полями.
|
||||
- `−` перечень причин закрыт схемой, то есть новая причина всё же требует шага
|
||||
схемы — дешевле прежнего, но не бесплатно.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Ответ распознавателя хранится дословно, двоичной формой и вложением
|
||||
|
||||
- **Дата:** 2026-08-14
|
||||
- **Источник:** openspec/changes/archive/2026-08-14-record-centric-model/design.md,
|
||||
раздел «Сырой ответ провайдера хранится вложением, а не колонкой»
|
||||
|
||||
## Решение
|
||||
|
||||
Ответ SpeechKit сохраняется целиком — сообщения потока подряд, каждое своей
|
||||
двоичной записью с длиной впереди, — и лежит **вложением** коллекции попыток
|
||||
распознавания, а не колонкой.
|
||||
|
||||
## Почему
|
||||
|
||||
Цитата источника:
|
||||
|
||||
> Хранится он вообще потому, что **результат операции у провайдера не
|
||||
> переспрашивается**. Отвергнутый вариант — не хранить и разобрать на лету:
|
||||
> дешевле сегодня, но связь реплики с говорящим мы строить пока не умеем, и
|
||||
> когда научимся, архив пересчитать будет не из чего, а повторная операция стоит
|
||||
> денег за каждую запись.
|
||||
|
||||
Вложением, а не колонкой:
|
||||
|
||||
> Ответ на многочасовую запись — мегабайты. Хранилище читает запись целиком, а
|
||||
> шаг опроса читает строку попытки раз в несколько секунд: положенный колонкой,
|
||||
> ответ ехал бы в память при каждом опросе — тот же промах, что расшифровка в
|
||||
> перечне колонок захвата сегодня.
|
||||
|
||||
Двоичной формой, а не текстовой, — решение ревью кода того же изменения. Замер:
|
||||
текстовое представление собирается по нашей скомпилированной схеме и **молча
|
||||
выбрасывает поля, которых в ней нет**, а провайдер добавляет их без
|
||||
предупреждения. Двоичная форма неизвестные поля переносит: они переживают запись
|
||||
и чтение и станут читаемыми, когда схема обновится. Ради этого архив и заводился.
|
||||
|
||||
## Последствия
|
||||
|
||||
- `+` архив пересчитывается из сохранённого без единого рубля: связь реплики с
|
||||
говорящим станет доступна, когда мы научимся её читать.
|
||||
- `+` шаг опроса читает строку попытки, не поднимая мегабайты в память.
|
||||
- `−` **формат файла на диске объявлен необратимым**: сохранённое не читается
|
||||
глазами и не разбирается ничем, кроме нашего же кода, а прочесть архив без
|
||||
сервиса нельзя вовсе.
|
||||
- `−` каталог данных растёт быстрее прежнего: ответ многословнее самой
|
||||
расшифровки — несёт альтернативы, время каждого слова и разбор говорящих.
|
||||
Потолок в 256 МиБ на вложение назван строкой в `database.md`, а сколько там на
|
||||
деле у шестичасовой записи, не мерил никто.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Предел простоя остаётся часом, хотя он короче самой работы
|
||||
|
||||
- **Дата:** 2026-08-14
|
||||
- **Источник:** openspec/changes/archive/2026-08-14-record-centric-model/design.md,
|
||||
раздел «Сторожей двое, и предела времени — два числа»
|
||||
|
||||
## Решение
|
||||
|
||||
Сторож застревания ограничивает время записи в рубеже двумя числами: **час** на
|
||||
свою работу, **сутки** на ожидание чужой операции. Час меньше времени, которое
|
||||
многочасовая запись занимает на приведении, и это принято сознательно.
|
||||
|
||||
## Почему
|
||||
|
||||
Ревью дизайна показало, что число противоречит расчётному потолку записи:
|
||||
|
||||
> Расчётный потолок записи — шесть часов, приведение такой записи идёт дольше
|
||||
> часа по построению, а срок захвата шага приведения стоит сегодня восемью
|
||||
> часами. Значит длинная запись, отказавшая один раз и ждущая повтора дольше
|
||||
> часа, будет остановлена сторожем застревания вместо расшифровки.
|
||||
|
||||
Предложено было вывести предел из срока захвата — двенадцать часов на свою
|
||||
работу. Владелец решил оставить час, и довод записан цитатой:
|
||||
|
||||
> Оставляем час. Тут нужно принять, что это скорее про зависшую задачу, потому
|
||||
> что пока идёт обработка даже длинной записи мы всегда можем проверить, жив ли
|
||||
> процесс конвертера.
|
||||
|
||||
Довод держится на том, что остановка теперь **обратима**: она не стирает рубежа,
|
||||
и снятие признака возвращает запись туда, где она стояла (см.
|
||||
[ADR-2026-08-14-halt-is-a-flag-not-a-stage](ADR-2026-08-14-halt-is-a-flag-not-a-stage.md)).
|
||||
Цена ложной остановки поэтому равна одному движению владельца, а не потерянной
|
||||
записи.
|
||||
|
||||
## Последствия
|
||||
|
||||
- `+` зависшая запись обнаруживается за час, а не за восемь.
|
||||
- `+` число живёт в настройках и правится без шага схемы, если класс начнёт
|
||||
всплывать.
|
||||
- `−` длинная запись, отказавшая один раз и прождавшая повтора дольше часа,
|
||||
останавливается как застрявшая — владельцу приходится снимать признак руками.
|
||||
- `−` предел этот работает только по записи, вернувшейся в выборку. У держателя,
|
||||
погибшего жёстко, запись невидима сторожу до истечения **срока захвата** её
|
||||
рубежа, то есть восьми часов у приведения; замер и оговорка стоят строкой в
|
||||
`database.md`.
|
||||
@@ -35,6 +35,9 @@
|
||||
|
||||
| Дата | Запись | Статус |
|
||||
| --- | --- | --- |
|
||||
| 2026-08-14 | [Предел простоя остаётся часом, хотя он короче самой работы](ADR-2026-08-14-stuck-limit-stays-an-hour.md) | |
|
||||
| 2026-08-14 | [Ответ распознавателя хранится дословно, двоичной формой и вложением](ADR-2026-08-14-provider-payload-stored-verbatim.md) | |
|
||||
| 2026-08-14 | [Остановка записи — признак, а не рубеж](ADR-2026-08-14-halt-is-a-flag-not-a-stage.md) | |
|
||||
| 2026-08-14 | [Учётная запись с записями не удаляется, и это осознанный тупик](ADR-2026-08-14-account-with-records-is-not-deleted.md) | |
|
||||
| 2026-08-13 | [Намерение объявляется признаком, а не выводится из ключа доступа](ADR-2026-08-13-telegram-intent-declared-not-inferred.md) | |
|
||||
| 2026-08-13 | [Недоступность Telegram подъёму сервиса не мешает](ADR-2026-08-13-telegram-outage-does-not-block-startup.md) | |
|
||||
|
||||
Reference in New Issue
Block a user