@@ -1,7 +1,7 @@
# Ревью: настройка и журнал
Проектная часть конвейера ревью: чем jellybit отличается от абстрактного
Go-сервиса и что здесь уже проскакивало. Устройство самого конвейера (профил и,
Go-сервиса и что здесь уже проскакивало. Устройство самого конвейера (метк и,
стадии, контракт находок) живёт в скилле, а не здесь.
## Как настроен конвейер
@@ -93,126 +93,142 @@ Go-сервиса и что здесь уже проскакивало. Устр
`original_title` заполняется всегда и при неуверенности дублирует `title` —
это контракт capability `recognition` , а не недосмотр.
### Вопросы к проход ам
### Вопросы по тем ам
Форма: `<имя проход а >: <вопрос> (<провенанс>)` . Журнал дефектов пока пуст,
поэтому провенанс у всех пунктов — инвариант или ADR, а не пойманный случай;
по мере накопления журнала список должен смещаться в сторону реальных промахов .
Форма: `<тем а >: <вопрос> (<провенанс>)` . Адресуется теме, а не имени прохода:
проход переезжает между метками и упраздняется, тема переезд переживает. Задаёт
вопрос тот, кто закрывает тему на текущем прогоне .
- `adversar y` : можно ли, управляя только именами файлов в раздаче и текстом
- `securit y` : можно ли, управляя только именами файлов в раздаче и текстом
контекста, добиться целевого пути вне `paths.movies` /`series` — включая путь
через юникод, длину сверх лимита ФС и коллизию после нормализации?
(инвариант «целевой путь строго под библиотекой», [security.md ](security.md ))
- `adversar y` : есть ли последовательность команд, после которой снимается
- `securit y` : есть ли последовательность команд, после которой снимается
**последняя ** копия данных — с учётом `superseded` -ссылок и гонки со сверкой?
(инвариант «источник неприкосновенен»)
- `adversar y` : что даёт крафт-магнет с чужим или подставным инфохэшем —
- `securit y` : что даёт крафт-магнет с чужим или подставным инфохэшем —
присоединение к чужой активной загрузке, отравление владения?
(открытая задача про идентичность инфохэшей)
- `adversar y` : где признак «это наше» снимается с одной сущности, а действие
- `securit y` : где признак «это наше» снимается с одной сущности, а действие
применяется к другой — присутствие раздачи в qBittorrent против байтов на
диске, запись в БД против файла, инфохэш против содержимого? (журнал,
2026-08-06: уборка своего торрента сносила чужие файлы)
- `ops` : что делает эта ветка, когда qBittorrent недоступен несколько минут
подряд — сколько ERROR-строк в секунду и меняется ли состояние задач?
- `operation s` : что делает эта ветка, когда qBittorrent недоступен несколько
минут подряд — сколько ERROR-строк в секунду и меняется ли состояние задач?
(задача про ERROR-шторм фоновых циклов)
- `ops` : как это ведёт себя при сотне загрузок в базе и десятках тысяч
- `operation s` : как это ведёт себя при сотне загрузок в базе и десятках тысяч
`file_link` — есть ли запрос без индекса и полный проход по таблице?
(задача про масштаб 100/1000, [database.md ](database.md ) → «Настройки»)
- `ops` : что остаётся на диске и в базе, если процесс убит посреди раскладки
батча? (состояние `linking` и его восстановление)
- `code ` : логирующий чекпоинт один на операцию — или ошибка залогирована и
возвращена вверх, где залогирована снова?
- `operation s` : что остаётся на диске и в базе, если процесс убит посреди
раскладки батча? (состояние `linking` и его восстановление)
- `conventions ` : логирующий чекпоинт один на операцию — или ошибка залогирована
и возвращена вверх, где залогирована снова?
([conventions/logging.md ](conventions/logging.md ))
- `code ` : новое поле конфига появилось в `config.example.toml` с описанием
назначения, диапазона и единиц? ([ conventions/config.md ]( conventions/config.md ))
- `specs` : не завелось ли поведение, которого спека не заказывала — тихий
- `conventions ` : новое поле конфига появилось в `config.example.toml` с
описанием назначения, диапазона и единиц?
([conventions/config.md ](conventions/config.md ))
- `requirements` : не завелось ли поведение, которого спека не заказывала — тихий
дефолт, проглоченная ошибка, ретрай «на всякий случай», отброшенное поле?
- `architecture` : не появился ли второй способ делать то, что уже делается —
второе место, где генерится время или id, второй парсер источника, вторая
логика целевых имён мимо `naming` ?
([architecture.md ](architecture.md ) → «Единые точки проекта»)
### Триггеры профиля
### Триггеры метки
Уточняет умолчания конвейера, не отменяет их. Рабочее умолчание — `standard ` ;
миграция схемы и публичный контракт ступень **не ** поднимают: их проверяют
проходы, которые в `standard ` и так есть.
Уточняет умолчания конвейера, не отменяет их. Рабочее умолчание — `medium ` ;
миграция схемы и публичный контракт метку **не ** поднимают: их проверяют
проходы, которые в `medium ` и так есть. Списка три: два поднимают до `large` ,
по одному на ось, третий опускает до `small` .
**Новым понятием или структурной единицей здесь считается ** (→ `wide` ): новый
пакет `internal/*` ; новая capability в `openspec/specs/` ; новый транспорт приёма
или уведомлений рядом с REST, веб-UI, ботом и CLI; новый провайдер метабазы за
существующим интерфейсом; новое состояние в графе переходов загрузки; перенос
ответственности между `worker` , `recognition` , `layout` и `store` .
**Крупное здесь ** — про объём, сколько узлов и слоёв трогает изменение:
**Правила идентичности, слияния и разбора живут здесь ** (→ `deep` ): владение
раздачей по инфохэшу и сверка с qBittorrent ( `ident` , `internal/store` ,
`state-reconciliation` ); построение целевых пу тей и санитизация имён
(`internal/layout` , `naming` ); разбор недоверенного входа — bencode, magnet,
текст контекста, ответ LLM (`internal/torrent` , `internal/magnet` ,
`internal/tgbot/parse.go` , разбор ответа модели); выбор кандидата метабазы и
слияние его полей с догадкой LLM (`internal/metadata` , `metadata-match` );
merge-раскладка при повторном добавлении раздачи.
- перенос ответственности между `worker` , `recognition` , `layout` и `store` ;
- новое состояние в графе переходов загрузки: оно тянет за собой воркер, спеку ,
отображение в веб-UI и бо те и восстановление после рестарта;
- правка, идущая насквозь по цепочке приём → распознавание → раскладка;
- новый провайдер метабазы за существующим интерфейсом: клиент, поле конфига с
образцом, слияние полей кандидата, ветка «провайдера нет».
**Незнакомое здесь ** — про форму решения, которую предстоит нащупать по ходу:
- новый пакет `internal/*` или новая capability в `openspec/specs/` ;
- новый транспорт приёма или уведомлений рядом с REST, веб-UI, ботом и CLI;
- заводится или меняется **правило идентичности, слияния или разбора ** : ключ
владения раздачей и сверка с qBittorrent (`ident` , `internal/store` ,
`state-reconciliation` ); построение целевых путей и санитизация имён
(`internal/layout` , `naming` ); новый вид входа или новая ветка неоднозначности
у разбора недоверенного — bencode, magnet, текст контекста, ответ LLM
(`internal/torrent` , `internal/magnet` , `internal/tgbot/parse.go` ); новый
источник или новый победитель при конфликте в слиянии кандидата метабазы
(`internal/metadata` , `metadata-match` ); merge-раскладка при повторном
добавлении раздачи.
- «Поведение, видимое снаружи» здесь включает **тексты и карточки Telegram ** —
для единственного пользователя это и есть интерфейс.
**Место из списка ступень не поднимает — поднимает правило. ** Перечни выше
отвечают «здесь такие правила водятся», а не «любая правка здесь идёт в `deep` ».
Ступень поднимает то, что даёт работу новому проходу: заводится ключ сравнения
или меняется его состав; у разбора появляется новый вид входа или новая ветка
неоднозначности; в слияние добавляется источник или меняется победитель при
конфликте.
**Место из перечня метку не поднимает — поднимает правило. ** Перечни выше
отвечают «здесь такие правила водятся», а не «любая правка здесь идёт в
`large` ». Метку поднимает то, что даёт работу новому проходу: заводится ключ
сравнения или меняется его состав; у разбора появляется новый вид входа или
новая ветка неоднозначности; в слияние добавляется источник или меняется
победитель при конфликте.
**Отсекающие условия — проверяются до выбора профиля, любое сработавшее держи т
ступень внизу.** Перечень закрытый, каждый пункт проверяется взглядом на дифф и
дельта-спек у :
**Мелкое здесь ** — опускает до `small` . Перечень закрытый, каждый пунк т
проверяется взглядом на дифф и дельта-спеку, любое сработавшее держит метку
вниз у :
- **дельта-спека называет исход поимённо. ** Независимая реализация окупается
выбором, которого спека не сделала. Если сценарий уже говорит, что даёт
вырожденный вход, реализация повторит спеку, и дифф покажет расхождение в
форме, а не в решении;
- **дельта-спека называет исход поимённо** — сценарий уже говорит, что даёт
вырожденный вход, и решать в коде нечего;
- **новых сценариев в дельта-спеке нет** — изменение уточняет уже описанное
поведение, а не заказывает новое;
- **правка сообщения, комментария, записи журнала, имени или теста** в узле из
перечня ;
перечней выше ;
- **сужение уже существующей нормализации** без нового вида входа: вход остался
тот же, изменился исход на одном его значении.
**Ориентир частоты. ** `standard` закрывает большинство задач, `wide` — редки й
случай, `deep` — исключение на крупной функциональности, а не на уборке. Задача
типа `chore` или `bugfix` , собранная из нитей прошлого ревью, идёт в `quick` или
`standard` , даже когда трогает файл из перечня `deep` . Верхняя ступень чаще одной
задачи на сп ринт означает ошибку в критерии, а не спринт из сложных задач.
Отрицательный тест поверх перечня: что после мерджа не откатывается обратно й
правкой — миграция, формат на диске, публичный контракт, имя, — **не ** `small` ,
каким бы маленьким ни был дифф.
**О рие нтир частоты. ** `medium` закрывает большинство задач, `large` рассчитана
на 5–10% и приходится на крупную функциональность, а не на уборку: задача типа
`chore` или `fix` , собранная из нитей прошлого ревью, идёт в `small` или
`medium` , даже когда трогает файл из перечней выше. `large` чаще одной задачи на
спринт означает ошибку в критерии, а не спринт из сложных задач.
### Недоступно проверке
**Не проверит ни один проход ** — принципиальная граница, по факту промаха не
пересматривается.
- И стория инцидентов на umbar и то, что уже ломалось в проде.
- П оведение таблицы SQLite под реальным объёмом и профилем нагрузки: реального
профиля нет ни у кого, кроме сервера.
- З авязка внешних потребителей (Jellyfin, закладки, чужие ссылки) на текущее
поведение.
- Качество распознавания как таковое: правильно ли LLM определил фильм — вопрос
тюнинга модели и промпта, а не ревью кода. Размеченный корпус, по которому это
можно было бы судить числом, решено не собирать (`tasks/REJECTED.md` ,
2026-08-06).
- Суждение «этой функциональности не должно существовать» .
- `operations` : и стория инцидентов на umbar и то, что уже ломалось в проде.
- `operations` : п оведение таблицы SQLite под реальным объёмом и профилем
нагрузки — реального профиля нет ни у кого, кроме сервера.
- `architecture` : з авязка внешних потребителей (Jellyfin, закладки, чужие
ссылки) на текущее поведение.
- `architecture` : суждение «этой функциональности не должно существовать».
- `requirements` : качество распознавания как таковое — правильно ли LLM
определил фильм. Это вопрос тюнинга модели и промпта, а не ревью кода;
размеченный корпус, по которому это можно было бы судить числом, решено не
собирать ( `tasks/REJECTED.md` , 2026-08-06) .
**Перестали проверять сознательно ** — пересматривается первым, как только
что-то проскочило.
- **И диоматичность Go — с 2026-08-04.** Проектный проход `idiom` (поимённая
сверка с положениями Effective Go, Go Code Review Comments, стайлгайдов Uber
и Google) у дал ён вместе с проектными копиями агентов при переезде на плагин
`av-dev-pipeline` , который этот проход упразднил. Способные части переселены:
эксперимент про тив поведения библиотеки и драйвера — в `ops` , «не изобретаем
ли то, что уже есть в библиотеке» — в `architecture` . **Различение
«идиоматично против распространено» теперь не спрашивает никто.** Класс
обратимый: портит форму кода, не данные. Пересмотр — задача
`quality-review-agents` .
- `conventions` : **и диоматичность Go — с 2026-08-04. ** Проектный проход `idiom`
(поимённая сверка с положениями Effective Go, Go Code Review Comments,
стайлгайдов Uber и Google) у праздн ён вместе с переездом конвейера в плагин
([ADR-2026-08-04-review-pipeline-to-plugin ](adr/ADR-2026-08-04-review-pipeline-to-plugin.md ));
способные час ти переселены — в тему `operations` (эксперимент против
поведения библиотеки и драйвера) и в `architecture` («не изобретаем ли то,
что уже есть в библиотеке»). **Различение «идиоматично против
распространено» теперь не спрашивает никто.** Класс обратимый: портит форму
кода, не данные. Пересмотр — задача `quality-review-agents` .
- `security` , `operations` , `architecture` : на метках `small` и `medium` не
проверяется ничто, требующее запуска, — построенных путей атаки, замеров и
эксплуатационного постмортема там нет по устройству конвейера. Их даёт только
`large` , а она приходится на 5–10% задач.
## Журнал дефектов
@@ -272,7 +288,7 @@ merge-раскладка при повторном добавлении разд
проход не спрашивал про **асимметрию признака владения ** — признак снимается
с одной сущности (запись в qBittorrent), а действие применяется к другой
(байты на диске). Враждебный проход до этой задачи на данном коде не гонялся.
- **Что меняем:** вопрос `adversary` в разде ле выше дополнен пунктом про
- **Что меняем:** в «В опросы по темам» добав лен вопрос темы `security` про
асимметрию признака владения. Сам дефект — задачей в беклоге, кандидат
`critical` ; спека `state-reconciliation` в том же изменении перестала
утверждать, что уборка «данных пользователя не касается».
@@ -296,7 +312,7 @@ merge-раскладка при повторном добавлении разд
В дереве остался табличный `TestParseNoNameSentinelDropped` .
- **Почему не поймали раньше:** ловить было нечему — дефект внесён этим же
изменением и пойман тем же прогоном. Отмечено потому, что это **эвал-сет
наоборот**: случай, где верхняя ступень окупилась. Три прохода из семи
наоборот**: случай, где старшая метка окупилась. Три прохода из семи
(`specs` , `adversary` , `reimpl` ) нашли его независимо, и двое принесли оракул;
проход `code` (конвенции) и гейт его не видели — порядок двух операций внутри
функции не выражается ни правилом линтера, ни конвенцией.