внутренняя модель перестроена вокруг аудиозаписи

- audiorecords вместо transcribe_jobs: приложения (texts, structures,
  recognitions, record_events, topics) живут своими коллекциями, ссылки на
  исходник и на приведённую копию перестали переставляться
- рубеж называет достигнутое, отказ стал признаком остановки с причиной, а
  сторожей стало двое: число отказов и время в рубеже
- воркеры потеряли специализацию, их число задаётся [pipeline] workers, шаг
  выбирается по рубежу, а захват отдаёт идентификатор и признак захвата
This commit is contained in:
av
2026-08-14 20:20:33 +03:00
parent d079f03350
commit 1576d06735
84 changed files with 8973 additions and 2865 deletions
+24 -9
View File
@@ -72,15 +72,30 @@ Taskfile, образ — Docker, выкладка — Ansible из `pet-project-
Само имя — последняя часть ссылки `/api/files/...`, поэтому в журнал пишется
расширение, а не имя: строка журнала иначе стала бы бессрочным ключом к чужой
записи. **critical**
- **Колонки очереди правятся в четырёх местах** пакета хранилища —
`applyToRecord`, `recordToJob`, константа `acquireColumns` и структура
`acquiredRow` с её `toJob`, — плюс шаг схемы. Компилятор видит два из них.
Колонка, забытая в паре `acquireColumns`/`acquiredRow`, приезжает из захвата
нулевой, и первый же `Save` пишет этот ноль поверх сохранённого значения:
поле теряется **только у задачи, попавшей к воркеру**. **major**
- **Результат пишет только держатель захвата.** Шаг, чей захват за время работы
достался другому, завершается без записи и без ответа отправителю. Иначе два
воркера пишут в одну задачу по очереди, а отправитель получает два ответа.
- **Колонки записи правятся в двух местах** пакета хранилища —
`applyOwnedByPipeline` вместе с `applyToRecord` и `recordToAudioRecord`, —
плюс шаг схемы. Компилятор не видит ни одного: колонка, забытая в одном из
них, теряется молча — запись сохранится без поля либо приедет с нулевым.
Мест было четыре, пока захват перечислял колонки поимённо; теперь он
возвращает идентификатор и признак своего захвата, и перечень перестал расти
с моделью. Сверку держат правила `internal/archrules`. **major**
- **Рубеж объявляется одним дескриптором** — `internal/entity/stage.go`. Из него
выводятся выбор шага, отбор захвата, срок протухания захвата и предел простоя;
перечислять рубежи порознь в каждом потребителе нельзя. Рубеж, забытый в
отборе, не выдаётся ни одному воркеру никогда, а пустой прогон по инварианту
ниже не пишется в журнал и не считается в метрику: запись встанет без единого
следа. Сверку держат правила `internal/archrules`. **major**
- **Результат пишет только держатель захвата, и держатель узнаётся значением.**
Признак захвата уникален для каждого захвата, и запись результата условна по
нему, а не по занятости записи. Шаг, чей захват за время работы достался
другому — по протуханию срока или после того, как человек снял признак
остановки в панели, — завершается без записи и без ответа отправителю. Условие
по непустоте признака пропустило бы обоих: два воркера писали бы в одну запись
по очереди, а отправитель получал бы два ответа. **major**
- **Остановленная запись сообщает отправителю, какой бы ни была причина.**
Причин три — приговор шага, исчерпанные отказы, застревание. Остановленная
запись захвату не выдаётся, значит исход «пригодна к повтору» исключён.
Обязанность, записанная у одной причины, у остальных читалась бы как снятая.
**major**
## Команды