## ADDED Requirements ### Requirement: Пред-парс имени релиза Перед вызовом LLM система SHALL выполнять дешёвый пред-парс имени торрента (`go-ptn`): извлекать черновые название, год, сезон, серию и качество. Результат пред-парса SHALL использоваться как вспомогательный сигнал в промпте и как сторона проверки согласованности при решении auto/review, но НЕ SHALL считаться итоговым распознаванием. #### Scenario: Пред-парс даёт черновые поля - **WHEN** на вход распознавания поступает имя релиза `Fargo.S02.2015.WEB-DL.1080p` - **THEN** пред-парс возвращает черновые `title`, `year`, `season`, `quality` - **AND** эти значения передаются в промпт LLM как подсказка ### Requirement: Разбор сигналов LLM в структурированный план Система SHALL передавать LLM недоверенные сигналы (имя торрента, дерево файлов с размерами, текстовый контекст и накопленные подсказки, пред-парс) и получать структурированный план в схеме: `type` (`movie`|`series`), `title`, `original_title`, `year`, `provider_hint`, `files[]` и `confidence`. Каждый элемент `files[]` SHALL нести `src`, `role` (`main`|`episode`|`subtitle`|`extra`|`sample`|`ignore`) и, для сериала, per-file `season`/`episode` (отдельного скалярного `season` быть SHALL NOT — так выражаются мультисезонные паки и спецвыпуски). План SHALL приниматься только если каждый `files[].src` совпадает с реальным файлом торрента. #### Scenario: План сериала с per-file нумерацией - **GIVEN** сезон-пак из 10 видеофайлов - **WHEN** LLM возвращает план - **THEN** `type` = `series`, а каждый видеофайл несёт свои `season`/`episode` #### Scenario: Несуществующий src отклоняется - **GIVEN** ответ LLM, где `files[].src` не совпадает ни с одним файлом торрента - **WHEN** план разбирается - **THEN** такой план не принимается как валидный ### Requirement: Провайдер LLM за абстракцией со структурированным выводом Доступ к LLM SHALL быть за интерфейсом с выбором реализации по полю `[llm].type` (первый тип — `openai-compat`). Система SHALL запрашивать JSON-режим (`response_format: {"type":"json_object"}`), срезать ```-ограждения и валидировать ответ в Go против схемы плана. При ошибке разбора система SHALL ретраить до `[llm].max_retries`, передавая модели саму ошибку и схему. Если после ретраев ответ не разобран, задача SHALL уходить в `review` (НЕ в `failed`) с причиной «ответ LLM не разобран». #### Scenario: Неразобранный ответ уходит в review - **GIVEN** LLM, чей ответ не проходит валидацию схемы после всех ретраев - **WHEN** завершается распознавание - **THEN** задача переходит в `review` с причиной «ответ LLM не разобран» - **AND** задача НЕ переходит в `failed` ### Requirement: Модель уверенности и решение auto/review Система SHALL раскладывать автоматически (без review) только при выполнении ВСЕГО: (1) подтверждённый единичный сильный матч в базе (`metadata-match`) с `provider_id`; (2) структурная валидация без предупреждений (фильм — ровно один основной видеофайл; сериал — число серий бьётся с базой, нумерация S·E консистентна); (3) согласованность пред-парса и LLM по типу/названию/году. Иначе задача SHALL уходить в `review` с явной причиной. Самооценку LLM (`confidence`) система SHALL учитывать лишь как вспомогательный сигнал, НЕ как единственный гейт. #### Scenario: Нет матча в базе — всегда review - **GIVEN** план без подтверждённого матча в базе (база выключена или матча нет) - **WHEN** принимается решение auto/review - **THEN** задача уходит в `review`, авто-раскладка не делается #### Scenario: Матч и чистая валидация — авто - **GIVEN** подтверждённый единичный матч, чистая структурная валидация и согласованность сигналов - **WHEN** принимается решение - **THEN** допускается авто-раскладка (при отсутствии `force_review`) ### Requirement: Роли файлов на краях раздачи Система SHALL относить семплы, «экстра» и мусор к роли `ignore` (эвристики размер/ имя + LLM), а внешние субтитры (`.srt`, `.ass`, пары VobSub `.idx`+`.sub`) — привязывать к соответствующему видео. Любую неоднозначность нумерации (дыры, дубли, спорные спецвыпуски) система SHALL эскалировать в `review`, а не разрешать молча. #### Scenario: Семпл помечается ignore - **GIVEN** раздача с файлом `sample.mkv` малого размера - **WHEN** строится план - **THEN** этот файл получает роль `ignore` и в раскладку не попадает ## REMOVED Requirements ### Requirement: Сверка с базой по нескольким названиям **Reason**: Работа с внешними базами метаданных — отдельное поведение; выделена в capability `metadata-match`. **Migration**: Требование перенесено без изменений в `metadata-match` (см. `specs/metadata-match`). ### Requirement: Локаль запроса к TMDB **Reason**: Относится к работе с метабазой (TMDB), выделенной в `metadata-match`. **Migration**: Требование перенесено без изменений в `metadata-match`. ### Requirement: Нормализация названий при сравнении **Reason**: Нормализация — часть сверки с метабазой, выделенной в `metadata-match`. **Migration**: Требование перенесено без изменений в `metadata-match`. ### Requirement: Кандидат несёт URL для внешней проверки **Reason**: Кандидат — сущность метабазы; контракт кандидата относится к `metadata-match`. **Migration**: Требование перенесено без изменений в `metadata-match`.