- контракт с моделью переводится на адресацию файла номером строки списка, усечение промпта снимается, лимиты уходят в конфиг - раскладка показывает все файлы раздачи, покрытие плана блокирует авто только при непокрытом видеофайле
19 KiB
MODIFIED Requirements
Requirement: Разбор сигналов LLM в структурированный план
Система SHALL передавать LLM недоверенные сигналы (имя торрента, дерево файлов с
размерами, текстовый контекст и накопленные подсказки, пред-парс) и получать
структурированный план в схеме: type (movie|series), title,
original_title, year, provider_hint, files[] и confidence. Каждый
элемент files[] SHALL адресовать файл раздачи номером строки из напечатанного
системой списка файлов, а не копией пути, и нести role
(main|episode|subtitle|extra|sample|ignore) и, для сериала,
per-file season/episode (отдельного скалярного season быть SHALL NOT — так
выражаются мультисезонные паки и спецвыпуски). Путь файла (src) SHALL
подставлять сама система резолвом номера по своему списку. Ответ, где элемент
files[] несёт путь вместо номера, система SHALL принимать как запасной формат,
проверяя совпадение пути с реальным файлом торрента. Элемент, несущий и номер, и
путь, система SHALL резолвить по номеру; несовпадение присланного пути с
резолвом номера SHALL давать причину ухода в review (сигнал сдвига адресации),
а не молчаливое затирание.
Негодный элемент files[] — номер вне диапазона списка, повторная адресация уже
адресованного файла, отсутствие и номера, и пути — система SHALL отбрасывать с
причиной ухода в review, сохраняя остальной план; при повторной адресации в
плане SHALL оставаться первый элемент. Отбраковка отдельных элементов SHALL NOT
считаться ошибкой разбора и SHALL NOT порождать повторный запрос к модели. План,
в котором после отбраковки не осталось ни одного файла, система SHALL считать
неразобранным.
Порядок списка файлов SHALL быть свойством самого распознавания, а не дисциплиной вызывающего: распознавание SHALL приводить полученный список к детерминированному порядку само, печатать промпт и резолвить номера по одному и тому же упорядоченному списку. Повторное распознавание той же раздачи SHALL давать ту же нумерацию.
План MAY дополнительно нести опциональное скалярное поле director (режиссёр).
Это поле НЕ требуется от LLM и НЕ участвует в структурной валидации или гейте
авто-раскладки; его заполняют подтверждённый матч метабазы (авто) или закреплённый
в ревью выбранный источник (через override, см. metadata-match/review) как
недоверенное косметическое значение для вывода отображаемого имени. Как недоверенное
человекочитаемое поле, director SHALL NOT входить в plan-санитайзинг (он чистит
title/original_title/provider_hint); очистка режиссёра применяется при рендере
имени. Пустой director SHALL быть штатным (режиссёр неизвестен).
Scenario: План сериала с per-file нумерацией
- GIVEN сезон-пак из 10 видеофайлов
- WHEN LLM возвращает план
- THEN
type=series, а каждый видеофайл несёт своиseason/episode
Scenario: Номер файла резолвится в путь
- GIVEN список из 180 файлов, напечатанный в промпте
- WHEN модель возвращает элемент плана с номером 13
- THEN система подставляет в
srcпуть тринадцатого файла своего списка
Scenario: Номер вне диапазона отбрасывает элемент, а не план
- GIVEN раздача из 180 файлов и ответ модели, где один элемент несёт номер 181, а остальные 179 корректны
- WHEN план разбирается
- THEN негодный элемент отброшен, остальные 179 файлов остаются в плане
- AND задача уходит в
reviewс причиной, называющей отброшенный элемент - AND повторный запрос к модели не выполняется
Scenario: Повторная адресация одного файла
- GIVEN ответ модели, где два элемента адресуют один и тот же файл
- WHEN план разбирается
- THEN в плане остаётся первый элемент, второй отброшен
- AND задача уходит в
reviewс причиной, называющей повторную адресацию
Scenario: Все элементы негодны — план не разобран
- GIVEN ответ модели, где ни один элемент
files[]не адресует реальный файл - WHEN план разбирается
- THEN план не принимается как валидный
Scenario: Путь вместо номера принимается как запасной формат
- GIVEN ответ модели, где элемент
files[]несёт путь файла вместо номера - WHEN план разбирается
- THEN разбор успешен, если путь совпадает с реальным файлом торрента
- AND correction-ретрай не выполняется
Scenario: Номер и путь одновременно — главенствует номер
- GIVEN элемент
files[], несущий и номер, и путь, которые указывают на разные файлы - WHEN план разбирается
- THEN
srcберётся резолвом номера - AND задача уходит в
reviewс причиной о несовпадении присланного пути с резолвом
Scenario: Несуществующий src отклоняется
- GIVEN ответ LLM, где
files[].srcне совпадает ни с одним файлом торрента - WHEN план разбирается
- THEN такой элемент отбрасывается с причиной, а посторонний путь в план не попадает
Scenario: Нумерация не зависит от вызывающего
- GIVEN два вызова распознавания одной раздачи, получившие список файлов в разном порядке
- WHEN собирается промпт
- THEN напечатанная нумерация в обоих вызовах одинакова
Scenario: Режиссёр не требуется от LLM и не влияет на гейт
- GIVEN ответ LLM без поля
director - WHEN план разбирается и оценивается
- THEN разбор успешен,
directorпуст - AND отсутствие режиссёра не влияет на структурную валидацию и решение auto/review
Requirement: Провайдер LLM за абстракцией со структурированным выводом
Доступ к LLM SHALL быть за интерфейсом с выбором реализации по полю [llm].type
(первый тип — openai-compat). Система SHALL запрашивать JSON-режим
(response_format: {"type":"json_object"}), срезать ```-ограждения и
валидировать ответ в Go против схемы плана. При ошибке разбора система SHALL
ретраить до [llm].max_retries, передавая модели саму ошибку и схему. Если после
ретраев ответ не разобран, задача SHALL уходить в review (НЕ в failed) с
причиной «ответ LLM не разобран».
Повторный запрос SHALL NOT переприсылать список файлов раздачи: список назван в первом сообщении диалога, и его номера сохраняют смысл на всех попытках. Размер запроса SHALL NOT расти пропорционально числу попыток.
Признак завершения генерации (finish_reason) SHALL доходить до распознавания.
Ответ, оборванный по длине, система SHALL уводить в review с отдельной
причиной «ответ модели обрезан» и SHALL NOT повторять запрос ни тем же промптом,
ни его вариантом: обрыв означает, что ответ не поместился, а не что модель
ошиблась.
Scenario: Неразобранный ответ уходит в review
- GIVEN LLM, чей ответ не проходит валидацию схемы после всех ретраев
- WHEN завершается распознавание
- THEN задача переходит в
reviewс причиной «ответ LLM не разобран» - AND задача НЕ переходит в
failed
Scenario: Повторная попытка не переприсылает список файлов
- GIVEN раздача из 180 файлов и ответ модели с ошибкой разбора
- WHEN выполняется correction-ретрай
- THEN список файлов раздачи повторно не печатается
- AND размер запроса второй попытки сопоставим с размером первой
Scenario: Обрыв по длине не ретраится
- GIVEN ответ модели с признаком обрыва генерации по длине
- WHEN завершается распознавание
- THEN задача переходит в
reviewс причиной «ответ модели обрезан» - AND повторных запросов к модели не выполняется
Requirement: Модель уверенности и решение auto/review
Система SHALL раскладывать автоматически (без review) только при выполнении
ВСЕГО: (1) подтверждённый единичный сильный матч в базе (metadata-match) с
provider_id; (2) структурная валидация без предупреждений (фильм — ровно один
основной видеофайл; сериал — число серий бьётся с базой, нумерация S·E
консистентна); (3) согласованность пред-парса и LLM по типу/названию/году. Иначе
задача SHALL уходить в review с явной причиной. Самооценку LLM (confidence)
система SHALL учитывать лишь как вспомогательный сигнал, НЕ как единственный гейт.
Список причин распознавания SHALL быть неоднородным: кроме блокирующих причин он
MAY содержать информационные строки, которые показываются человеку и сохраняются
вместе с распознаванием, но авто-раскладку НЕ отменяют — такова сводка покрытия
плана (см. «Причины по нумерации серий и покрытию плана»). Поэтому решение
auto/review система SHALL считать по блокирующим причинам, а НЕ по длине
списка причин: непустой список сам по себе SHALL NOT означать review.
Scenario: Нет матча в базе — всегда review
- GIVEN план без подтверждённого матча в базе (база выключена или матча нет)
- WHEN принимается решение auto/review
- THEN задача уходит в
review, авто-раскладка не делается
Scenario: Матч и чистая валидация — авто
- GIVEN подтверждённый единичный матч, чистая структурная валидация и согласованность сигналов
- WHEN принимается решение
- THEN допускается авто-раскладка (при отсутствии
force_review)
Scenario: Информационная причина авто не отменяет
- GIVEN подтверждённый матч и чистая валидация, но покрытие плана неполно только за счёт файлов-спутников
- WHEN принимается решение auto/review
- THEN список причин непуст — в нём сводка покрытия
- AND авто-раскладка допускается
ADDED Requirements
Requirement: Полный список файлов раздачи в промпте
Промпт распознавания SHALL включать все файлы раздачи, а не фиксированную их
часть. Предельное число файлов и предельный размер ответа модели SHALL задаваться
настройками [recognition].max_files и [recognition].max_tokens; предел числа
файлов служит предохранителем от аномальной раздачи, а не рабочим ограничением, и
его значение по умолчанию SHALL соответствовать размеру промпта, который заведомо
принимает модель. Если список всё же усечён пределом, распознавание SHALL называть
усечение отдельной причиной ухода в review. Отказ модели, вызванный размером
запроса, распознавание SHALL называть причиной о размере запроса, а не текстом
провайдера.
Scenario: Раздача на сотни файлов показана модели целиком
- GIVEN раздача из 180 файлов и
max_files= 500 - WHEN собирается промпт распознавания
- THEN в списке файлов промпта присутствуют все 180 файлов
Scenario: Усечение названо причиной
- GIVEN раздача, число файлов которой превышает
max_files - WHEN завершается распознавание
- THEN задача уходит в
review, и среди причин названо усечение списка файлов
Requirement: Причины по нумерации серий и покрытию плана компактны
Причины ухода в review, порождённые нумерацией серий, SHALL быть свёрнуты: на
сезон приходится не более одной причины, перечисляющей недостающие серии.
Распознавание SHALL называть покрытие плана — сколько файлов раздачи попало в план из общего числа, — когда покрыты не все файлы. Блокировать авто-раскладку SHALL только непокрытый видеофайл: файл, который модель не адресовала и который по расширению является видео, означает потерянную серию или фильм. Непокрытые файлы-спутники (субтитры, изображения, тексты, служебные файлы) SHALL показываться в покрытии, но SHALL NOT входить в структурную валидацию и SHALL NOT влиять на решение auto/review: модель вправе не перечислять то, что не раскладывается.
Scenario: Пропуски сезона свёрнуты в одну причину
- GIVEN план сезона, где недостают серии E05, E07 и E11
- WHEN формируются причины ухода в review
- THEN этому сезону соответствует одна причина, перечисляющая недостающие серии
Scenario: Непокрытый видеофайл блокирует авто
- GIVEN раздача, где один видеофайл не адресован ни одним элементом плана
- WHEN принимается решение auto/review
- THEN задача уходит в
reviewс причиной о непокрытом видеофайле
Scenario: Непокрытые файлы-спутники авто не блокируют
- GIVEN раздача, где не адресованы только
.nfo, скриншоты и текстовый файл, а все видеофайлы покрыты, матч подтверждён и валидация чиста - WHEN принимается решение auto/review
- THEN авто-раскладка допускается
- AND покрытие плана показано человеку, но причиной ухода в review не является