From 6d801ed03ba7e67bcd0b2e092bec9a5de218a7f7 Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Tue, 7 Jul 2026 14:55:53 +0300 Subject: [PATCH] =?UTF-8?q?=D0=91=D0=B5=D0=BA=D0=BB=D0=BE=D0=B3:=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D0=BD=D0=BE=D1=81=20=D0=B2=20Tududi=20=D0=BA?= =?UTF-8?q?=D0=B0=D0=BA=20=D0=B5=D0=B4=D0=B8=D0=BD=D1=81=D1=82=D0=B2=D0=B5?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=B8=D1=81=D1=82=D0=BE=D1=87=D0=BD?= =?UTF-8?q?=D0=B8=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Задачи беклога перенесены в Tududi (проект jellybit) с приоритетами и описанием. Файл docs/backlog.md удалён; CLAUDE.md указывает на Tududi как единственный источник. Живые ссылки в спеках на backlog.md переписаны на отсылку к задаче в беклоге (Tududi). Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 14 + docs/backlog.md | 484 ---------------------------------- docs/specs/architecture.md | 3 +- docs/specs/jellyfin-layout.md | 2 +- docs/specs/recognition.md | 7 +- docs/specs/review-ux.md | 4 +- 6 files changed, 23 insertions(+), 491 deletions(-) delete mode 100644 docs/backlog.md diff --git a/CLAUDE.md b/CLAUDE.md index 2a975d1..643f6fa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -91,6 +91,20 @@ OpenSpec (пилот — `ingest`). До переноса источник ис - `docs/drafts/` — черновики: планы, идеи, ещё не принятые решения. Не источник истины. +## Задачи и беклог + +- **Единственный источник беклога — Tududi**, проект `jellybit` (MCP-сервер + `tududi`, project_id 14). Там задачи с приоритетами (высокий/средний/ + низкий) и описанием (контекст, принятые решения, ссылки на спеки/ADR/ + черновики в теле задачи). Ищи, заводи и закрывай задачи через + MCP-инструменты `tududi` (`list_tasks`, `create_task`, `update_task`, + `complete_task`, `search`). +- Спекулятивные задачи (ещё без решения «делаем») помечены префиксом + `[идея]` в названии — их сперва прорабатываем. +- Отдельного файла-беклога в репозитории больше нет: `docs/backlog.md` + перенесён в Tududi. Старая версия при необходимости доступна в истории + git. + ## Язык - Документация, комментарии, сообщения коммитов — **русский**. diff --git a/docs/backlog.md b/docs/backlog.md deleted file mode 100644 index 237656e..0000000 --- a/docs/backlog.md +++ /dev/null @@ -1,484 +0,0 @@ -# Беклог - -Единый список будущих задач по проекту: то, что уже решили сделать, и -идеи, которые ещё надо обдумать. Это не план реализации (он — в -[drafts/roadmap.md](drafts/roadmap.md)) и не источник истины: принятое и -реализованное переезжает в `docs/specs`/`docs/adr`. - -Приоритет — грубая оценка «ценность / стоимость», не обязательство к -порядку. Спекулятивные пункты (ещё без решения «делаем») помечены -_(идея)_ — их сперва надо проработать. - -## Высокий - -### Проблема второго сезона - -Если первый сезон сериала уже разложен, а мы добавляем второй/третий/…, -новый сезон должен лечь в **ту же** папку сериала, а не завести рядом почти -одинаковую вторую. Разбор ([drafts/logical-title-model.md](drafts/logical-title-model.md)) -показал: проблема не в группировке, а в **сходимости папки** — папка каждый -раз печатается заново из выхода LLM, и совпадение `provider_id` не -гарантирует совпадение строки («Fargo» vs «Фарго», год сезона vs год -сериала). Отдельная сущность «тайтл» **не вводится**; решение — правило -сходимости при построении плана: при подтверждённом матче наследовать базу -папки от живых `file_link`'ов загрузок с тем же `(provider, provider_id)`, -игнорируя LLM-выход; якоря нет — папка из распознавания, как сейчас (первая -загрузка «печатает» имя). - -- [ ] lookup живых ссылок по `(provider, provider_id)` через current recognition -- [ ] наследование базы папки (имя + год) при построении плана раскладки -- [ ] рассинхрон (несколько живых папок с одним матчем) → review, не молча -- [ ] тесты: сходимость, отсутствие якоря (свежая папка), смена провайдера - -Связано: [drafts/logical-title-model.md](drafts/logical-title-model.md) §5.2, -[recognition.md](specs/recognition.md) (модель уверенности, -матч в базе), [jellyfin-layout.md](specs/jellyfin-layout.md) (папка -сериала с провайдер-id). - -### Раздачи с докачиванием (слияние при повторном добавлении) - -Свежий сериал раздают по мере выхода: торрент содержит 5 эпизодов из 10, -позже его перезаливают целиком, и пользователь добавляет раздачу повторно. -Решение проработано ([drafts/logical-title-model.md](drafts/logical-title-model.md) -§6.2): новая загрузка приходит в ту же папку за счёт правила сходимости, а -раскладка становится **merge** — доложить только недостающее. Существующие -пути не трогаем (never-overwrite, владение остаётся у старой загрузки), -новые кладём (владеет новая). Split-ownership сезона (серии поделены между -загрузками) принят как норма per-path модели; обе раздачи сидируют -независимо. - -- [ ] в плане раскладки отличать «путь занят живой ссылкой того же матча» - (→ пропустить) от настоящей коллизии (→ review, как сейчас) -- [ ] merge-раскладка: существующее пропустить, недостающее доложить -- [ ] показать итог в карточке: сколько доложено, сколько уже было -- [ ] решить «слияние загрузок» при перезаливе той же вещи (одна строка - `download` + новый infohash vs новая загрузка) — открытый вопрос - черновика §10 - -Зависит от правила сходимости ([«Проблема второго -сезона»](#проблема-второго-сезона)) и выигрывает от ULID-идентичности. - -Связано: [jellyfin-layout.md](specs/jellyfin-layout.md) (раскладка, -идемпотентность), [workflow.md](specs/workflow.md) (повторный прогон -загрузки). - -### Удаление средствами jellybit («единое окно», path 2) - -Распознавание **ручного** удаления (источник из qBittorrent / цель из -Jellyfin) и пометка рассинхрона уже сделаны: фоновая сверка по матрице -«источник × цель» → состояния `target_missing`/`orphaned`/`deleted`, -безопасный `undo` (не снимает последнюю копию, `nlink <= 1`), синхронный -preflight перед действиями. См. `openspec/specs/state-reconciliation/`, -[workflow.md](specs/workflow.md) → «Сверка с реальностью». - -Осталось (path 2) — продолжение «единого окна»: удалять просмотренное -**из самого jellybit**, не идя руками в qBittorrent/Jellyfin. Решения из -разбора ([drafts/logical-title-model.md](drafts/logical-title-model.md) -§5.3, §6.4): «тайтл» — вычисляемая группа загрузок по -`(provider, provider_id)` / общей папке, без новой сущности; удаление -целиком — обход загрузок группы штатным undo; удаление раздачи из -qBittorrent — осознанный выход за инвариант «источник неприкосновенен», -только по явному подтверждению (не случайному клику). - -- [ ] удаление одной загрузки: снять её живые хардлинки (штатный undo, - `superseded` пропускаем, `nlink`-гард) + опц. удалить раздачу из - qBittorrent с файлами — с осознанным подтверждением -- [ ] вычисляемая группа «тайтл» в UI: состав сериала/фильма (загрузки, - сезоны, файлы) одним экраном -- [ ] удаление тайтла целиком: обход загрузок группы + опц. снос - опустевшей папки -- [ ] после полного удаления память о тайтле не остаётся (линза без - содержимого не нужна) - -Связано: [drafts/logical-title-model.md](drafts/logical-title-model.md), -[ADR-2026-06-13-hardlinks](adr/ADR-2026-06-13-hardlinks.md), -[architecture.md](specs/architecture.md) → «Раскладка файлов», -[workflow.md](specs/workflow.md). - -### Ретеншн и очистка БД - -Терминальные задачи (`done`/`cancelled`/`failed`/`reverted`), их попытки -`recognition` с сырыми ответами LLM и `metadata_candidate` копятся вечно — -со временем БД и список загрузок распухают и становятся нечитаемыми. Нужна -авточистка старше N дней (с настройкой в `[storage]` или `[worker]`) и/или -ручное удаление. Маленькая задача, но без неё интерфейс деградирует по мере -эксплуатации. - -Связано: [architecture.md](specs/architecture.md) → «Хранилище» (таблицы -`download`/`recognition`/`metadata_candidate`/`file_link`), пакет `store`. - -### Eval-харнес распознавания (корпус кейсов + метрика точности) - -Распознавание — ядро продукта, но смена модели или правка промпта сейчас -вслепую: регрессий не видно. Нужен корпус размеченных кейсов (русские -релизы, аниме, сезон-паки, репаки, спецвыпуски) и прогон распознавания по -нему с метрикой точности (тип/название/год/нумерация). Тогда можно -сравнивать LLM-провайдеры и версии промпта по числам, а не на ощупь. -Прогон — отдельной командой (`jellybit eval` или тестом), на фикстурах, без -реального qBittorrent. - -Связано: [recognition.md](specs/recognition.md) (конвейер, модель -уверенности), пакет `recognize`. - -### НФТ: масштаб до 100 одновременных загрузок (потолок — 1000) - -Сейчас потолок по нагрузке нигде не зафиксирован: воркер, поллинг -qBittorrent, пул LLM-вызовов и запись в SQLite спроектированы «на глаз». -Записать в **нефункциональные требования** целевой ориентир — архитектура -держит до **100 одновременных загрузок** в работе (приём → распознавание → -раскладка), план-максимум — **1000**. Сама запись требования дешева и -высокоценна: она задаёт рамку для решений ниже по списку. Отдельно (уже -дороже) — аудит узких мест под эту цифру: одиночное соединение SQLite и -сериализация записи, конкурентность воркера и лимит параллельных -распознаваний, частота/стоимость поллинга и дедуп при наплыве. - -Связано: [architecture.md](specs/architecture.md) → «Отслеживание -загрузки»/«Хранилище», пакеты `worker`, `store`, `qbt`, `llm`. - -## Средний - -### Словарь единого языка (ubiquitous language) - -Свести термины домена в один глоссарий, чтобы пользователь, документация, -код и агент говорили на одном языке: загрузка, раздача, распознавание, матч, -кандидат, раскладка, источник/цель, хардлинк, ревью, переход состояния и -т.д. — русский термин, английский идентификатор в коде, краткое определение. -Сейчас наименования расходятся между спеками, UI и кодом, и в диалоге с -агентом приходится каждый раз сверять понятия. Глоссарий — источник истины -по именам; на нём же строится агент-ревьювер наименований (см. -[«Агенты-ревьюверы качества»](#агенты-ревьюверы-качества-наименования-архитектура-конвенции-стиль)). - -Связано: [docs/conventions](conventions/README.md) (кросс-каттинг), -[architecture.md](specs/architecture.md) (домен), новый файл-глоссарий. - -### Агенты-ревьюверы качества (наименования, архитектура, конвенции, стиль) - -Набор узких сабагентов-ревьюверов поверх ревью-процесса из `CLAUDE.md`, -каждый со своей оптикой: соответствие наименований словарю единого языка, -соблюдение архитектурных границ (единое ядро/тонкие транспорты, инварианты -безопасности данных), конвенций (ошибки, логирование, конфиг, TZ), стиля -кода на высоком уровне и поиск дублирования. Запускаются как чекпоинт перед -`archive`/коммитом. Развивает ревью-процесс OpenSpec в сторону -воспроизводимых автоматических проверок, не заменяя человеческое ревью. - -Связано: `CLAUDE.md` (ревью-процесс, конвенции), -[docs/conventions](conventions/README.md), -[«Словарь единого языка»](#словарь-единого-языка-ubiquitous-language). - -### Сила совпадения кандидата и пересмотр распознавания/матчинга _(идея)_ - -Сейчас у кандидата метабазы нет метрики силы совпадения (`metadata_candidate` -хранит provider/id/title/year/url), а решение «авто vs review» — по правилу -«единственный сильный матч + валидация», не по числовой уверенности. Для -ревью это значит: список кандидатов нечем отсортировать/подсветить по -уверенности — берём порядок сбора. Идея — ввести на этапе матча **силу -совпадения кандидата** (точное совпадение названия+года vs частичное) для -сортировки и подсказки в UI. Шире — отдельно продумать **сам процесс -распознавания и матчинга**: границы «разбор LLM / поиск в базе / сверка», -что храним у кандидата, как считаем и показываем уверенность. Требует -проработки перед реализацией. - -Связано: [recognition.md](specs/recognition.md) (модель уверенности), -[ADR-2026-06-13-auto-link-requires-db-match](adr/ADR-2026-06-13-auto-link-requires-db-match.md), -[review-ux.md](specs/review-ux.md) (выбор источника в ревью, реализовано), -[«Пересмотр набора capabilities»](#пересмотр-набора-capabilities-и-рефакторинг-спек). - -### История переходов загрузки - -Сохранять полную историю переходов состояний загрузки (что/когда/почему/кто -инициировал — воркер, человек, сверка), а не только текущее состояние. -Сейчас по задаче виден лишь актуальный статус, а разбор «как мы сюда попали» -идёт по логам сервера. Отдельная таблица истории даёт лог переходов в -карточке/расширенной информации и фундамент для метрик длительности стадий. -Естественно ложится на собственный идентификатор загрузки. - -Связано: детальный экран загрузки (`/download/{id}`) уже реализован — лог -переходов ложится в него; -[drafts/logical-title-model.md](drafts/logical-title-model.md) §5.4 (схема -`state_transition`, actor `worker|human|reconcile`), -[workflow.md](specs/workflow.md) (граф состояний), -[database.md](specs/database.md), пакеты `worker`, `store`. - -### Машина состояний на go-библиотеке - -Сейчас FSM реализована вручную в `worker`. Выбрать подходящую go-библиотеку -для описания воркфлоу/машины состояний и перевести переходы на неё — ради -декларативности, проверяемости переходов и единого места правды. Кандидаты -для оценки: `looplab/fsm`, `qmuntal/stateless` (и аналоги). Граф и переходы -уже формализованы — переносим один в один. - -Связано: [workflow.md](specs/workflow.md) (текущий граф состояний). - -### Привязка уведомлений к источнику в ботах (мульти-бот) - -Уведомления и запросы подтверждения должен получать тот, кто прислал -загрузку: автор сообщения о новой раздаче — адресат пингов и ревью по ней. -Транспортов-ботов может быть несколько (Telegram, в перспективе Matrix и -др.); каждый адресует «своему» отправителю. Веб-интерфейс остаётся -**единым для всех** и точкой правды по функциональности (боты — тонкие -адаптеры над тем же ядром). Нужно: хранить у загрузки источник/транспорт и -идентификатор отправителя, маршрутизировать пинги по нему. - -Связано: [review-ux.md](specs/review-ux.md) (разделение труда транспортов, -веб = точные правки), [architecture.md](specs/architecture.md) → -«Транспорты». - -### Улучшения UI: показывать матч с записью метабазы - -Web-сторона реализована: страница загрузки `/download/{id}` и экран ревью -показывают, **с какой именно записью** метабазы (TMDB/TVDB/IMDb) сматчилась -загрузка — провайдер, id и ссылку на запись. Осталось довести то же в -**Telegram**: в уведомлениях/подтверждениях показывать запись матча (название, -год, провайдер-id, ссылку), чтобы ошибочную привязку было видно и из бота. -Полный выбор источника в вебе уже реализован — см. -[review-ux.md](specs/review-ux.md). - -Связано: [review-ux.md](specs/review-ux.md), [recognition.md](specs/recognition.md) -(матч в базе), [architecture.md](specs/architecture.md) → «Транспорты». - -### Сложные сериальные раздачи: все сезоны разом, паки, спецраскладки _(идея)_ - -Обычный случай сериальной раздачи — один сезон (его номер надо сразу видеть -глазами и сверять на ревью — под это сделана сводка сезонов в инфо-части, см. -`openspec/specs/review`). Но в редких заказах раздача бывает сложнее: **все -сезоны сериала разом**, **пак нескольких сезонов**, смешанная нумерация, вложенные -папки сезонов, разнобойные имена файлов. Сейчас `PlanFile.Season` задаётся на -каждом файле (мультисезон в принципе выразим), но целостно эти сценарии не -проработаны: как надёжно распознать многосезонную раздачу, как показать её на -ревью (сводка — лишь страховка, не полноценный разбор по сезонам), как разложить -и как это стыкуется со сходимостью папки и merge-докачиванием. Проработать -крайние случаи и решить, что поддерживаем явно, а что уводим в ревью как «сложную -раскладку». - -Связано: [recognition.md](specs/recognition.md) (сезон-паки, нумерация), -[jellyfin-layout.md](specs/jellyfin-layout.md) (раскладка сезонов), -[review-ux.md](specs/review-ux.md) (крайние сценарии, сводка сезонов), -[«Проблема второго сезона»](#проблема-второго-сезона), -[«Раздачи с докачиванием»](#раздачи-с-докачиванием-слияние-при-повторном-добавлении). - -### Аниме с абсолютной нумерацией - -Релизы аниме часто нумеруют серии сквозным числом (`#137`) без сезонов, а -Jellyfin ждёт `SxxEyy`. Нужен пересчёт абсолютной нумерации в сезон/серию — -надёжнее всего через TVDB (там есть absolute order). Отдельный крайний -случай распознавания; на стороне ревью — веб-хелпер «absolute → S·E». - -Связано: [recognition.md](specs/recognition.md) (конвейер, сезон-паки), -[jellyfin-layout.md](specs/jellyfin-layout.md) (нумерация серий), -[review-ux.md](specs/review-ux.md) (крайние сценарии). - -### Добавление торрентов файлом/ссылкой — «единое окно» - -Поддержать источники помимо magnet: `.torrent`-файл и URL (отдаём их в -qBittorrent, без исходящих запросов на пользовательский URL — SSRF -исключён). Идеал — одно поле «единого окна»: кидаем туда текст или файл, а -сервис сам разбирает, что это (magnet / ссылка / .torrent / сообщение -бота), и заводит загрузку. - -Связано: [architecture.md](specs/architecture.md) → «Транспорты» -(`source_type = magnet|torrent|url` уже в схеме), пакет `ingest` (сейчас -поддержан только magnet). - -### Бэкап SQLite - -`architecture.md` требует «бекапить data-том», но *как* — не описано. Без -понятной стратегии сбой или редеплой стирают всё in-flight состояние. -Зафиксировать решение и реализовать: периодический `VACUUM INTO` в -`/data/backups` по расписанию (с ротацией) либо потоковая репликация -(litestream). Лучше сделать, пока БД маленькая. - -Связано: [architecture.md](specs/architecture.md) → «Деплой» (data-том, -«бекапить-и-не-терять»), пакет `store`. - -### Глубокий healthcheck и статус зависимостей - -`/healthz` проверяет только сам сервис. Если qBittorrent, LLM или метабаза -недоступны — узнаёшь лишь по застрявшим задачам. Нужна readiness-проверка -ключевых зависимостей и отражение их состояния в UI (бейдж «qBittorrent -недоступен»), чтобы причина простоя была видна сразу. - -Связано: [architecture.md](specs/architecture.md) → «Деплой» (healthcheck), -пакеты `qbt`, `llm`, `metadata`, `httpapi`. - -### Обучение на правках человека (few-shot из прошлых ревью) - -Когда человек поправил матч, тип или нумерацию — сохранять это как пример и -подмешивать похожие в будущие промпты. Системно повышает точность на «твоих» -трекерах и форматах имён без смены модели. Развитие идеи многоступенчатой -верификации, но дешевле: учимся на уже собранных `hint`/`override`. - -Связано: [recognition.md](specs/recognition.md) (конвейер, промпт), -[«Многоступенчатая верификация»](#многоступенчатая-верификация-привязки-идея), -[architecture.md](specs/architecture.md) → «Хранилище» (`hint`, `override`). - -### Гейт авто-раскладки по `confidence`: спека vs код - -Аудит спек↔код (2026-07-03) нашёл расхождение в модели уверенности. -Спека `recognition` (унаследовано из `recognition.md`) утверждает, что -самооценка LLM `confidence` — **вспомогательный сигнал, НЕ единственный гейт**: -при подтверждённом матче в базе + чистой структурной валидации + согласованности -сигналов авто-раскладка допускается. Код же (`internal/recognize/validate.go`, -`confidence < AutoThreshold`, дефолт 0.85) делает `confidence` **жёстким -блокирующим условием**: план с матчем и чистой валидацией, но `confidence` 0.5 -уйдёт в review вопреки сценарию спеки. Нужно определиться, что правда: либо -признать порог `AutoThreshold` в спеке как легитимный гейт (скорее так — код его -осознанно ввёл конфигом), либо ослабить код. Заодно `AutoThreshold` как -конфигурируемый гейт спекой не описан. - -Связано: `openspec/specs/recognition` (требование «Модель уверенности и решение -auto/review»), -[ADR-2026-06-13-auto-link-requires-db-match](adr/ADR-2026-06-13-auto-link-requires-db-match.md), -пакет `recognize`. - -### Привязка внешних субтитров к серии (сериалы) - -Аудит спек↔код (2026-07-03): спека `recognition` требует «внешние субтитры SHALL -привязываться к соответствующему видео». Для **фильма** это работает — раскладка -именует субтитр по базе видеофайла. Для **сериала** связь субтитр→конкретная -серия не выражена: в `PlanFile` (`internal/recognize`) нет поля привязки, и нет -логики спаривания VobSub `.idx`+`.sub`. Нужно смоделировать привязку субтитра к -эпизоду (поле на `PlanFile` или роль с указанием `season`/`episode`) и спаривание -`.idx`+`.sub`, либо — если поддержку откладываем — сузить формулировку спеки до -реального поведения. - -Связано: `openspec/specs/recognition` (требование «Роли файлов на краях»), -[jellyfin-layout.md](specs/jellyfin-layout.md) (имена субтитров), пакеты -`recognize`, `layout`. - -### Раздачи-копии диска (DVD/BluRay: VIDEO_TS/BDMV) - -Иногда для очень редких фильмов скачивается не один видеофайл, а **полная копия -диска** — структура `VIDEO_TS/` (DVD: `VIDEO_TS.IFO`, `VTS_01_1.VOB`…) или -`BDMV/` (BluRay: `BDMV/STREAM/*.m2ts`, `index.bdmv`). Сейчас распознавание и -раскладка заточены под пофайловый разбор (один main-видеофайл фильма / серии -сериала), а тут «фильм» — это **каталог целиком**. Jellyfin такие раскладки -поддерживает (папка фильма с вложенным `VIDEO_TS`/`BDMV`), нам нужно: распознать, -что раздача — это образ диска (по наличию `VIDEO_TS`/`BDMV`), не пытаться -разбирать её по отдельным VOB/m2ts как серии, и разложить весь каталог диска -хардлинками в папку фильма Jellyfin (`Название (Год)/VIDEO_TS/…`). Крайний, но -реальный случай для редких изданий; частота низкая, поэтому в «Среднем». - -Связано: [recognition.md](specs/recognition.md) (роли файлов, что игнорируем), -[jellyfin-layout.md](specs/jellyfin-layout.md) (раскладка фильма, крайние -случаи), пакеты `recognize`, `layout`. - -## Низкий - -### Панель действий ревью вне htmx-свопа блока источника - -При выборе источника одним кликом обновляется только блок источника -(`#source-block`) htmx-свопом, а нижняя панель действий (кнопка «Применить», -завязанная на `HasLinks`) — вне блока и не обновляется до полной перезагрузки. -Практически не мешает (хардлинки только по явному «Применить», -`Apply` без плана вернёт ошибку), но в краевом случае (источник с пустым -предпросмотром из-за коллизии) кнопка «Применить» может остаться/пропасть не -синхронно. Решение намечено в дизайне `review-unified-source-block` -(Risks/Trade-offs): обновлять панель `hx-swap-oob` из того же партиала. - -Связано: `openspec/specs/review`, `openspec/specs/web-ui`, пакет `httpapi`. - -### Мгновенные обновления через SSE - -Живые обновления прогресса сейчас на htmx-поллинге (фаза 2 веб-UI) — просто -и работает, но с задержкой в интервал опроса и холостыми запросами. -Перевести динамический контент (прогресс загрузки, смена статуса, раздача) -на Server-Sent Events, чтобы обновления приходили почти мгновенно и без -лишнего поллинга. Поллинг работает, поэтому это улучшение, а не блокер; SSE — -один долгоживущий ответ на соединение, ложится на server-rendered UI без -тяжёлого фронтенда. - -Связано: [architecture.md](specs/architecture.md) → «Транспорты», -[review-ux.md](specs/review-ux.md), пакет `httpapi`. - -### Версии/качество одного тайтла (репаки, апгрейд 1080p → 2160p) - -По калибровке болей (2026-07-02, -[drafts/logical-title-model.md](drafts/logical-title-model.md) §6.3) — -**не боль**, из приоритета выпало. Сосуществование версий доступно уже -сейчас (Jellyfin multi-version, другой целевой путь), коллизия на тот же -путь штатно уходит в review. Явный replace (undo старого хардлинка → lay -нового → супересид владения путём) — отдельный change, если/когда станет -болью. - -Связано: [«Раздачи с докачиванием»](#раздачи-с-докачиванием-слияние-при-повторном-добавлении), -[jellyfin-layout.md](specs/jellyfin-layout.md) (never-overwrite, коллизия). - -### Многоступенчатая верификация привязки _(идея)_ - -Несколько раз извлекать данные из раздачи и контекста разными промптами, -искать в метабазах, затем сводить результаты в общий вердикт -(голосование/консенсус) — выше точность ценой нескольких вызовов LLM и -запросов к базам. Требует проработки: когда включать, как мерджить -расхождения, стоимость/латентность. - -Связано: [recognition.md](specs/recognition.md) (конвейер и модель -уверенности). - -### Выбор из нескольких находок метабазы в Telegram - -Когда распознавание даёт несколько подходящих кандидатов в метабазе, -предлагать их в Telegram списком (кнопки) для ручного выбора, а не молча -брать первый/лучший. Веб остаётся точкой точных правок (полный выбор -источника уже реализован — см. [review-ux.md](specs/review-ux.md)), бот — -быстрый выбор из готового короткого списка. - -Связано: [review-ux.md](specs/review-ux.md) (боты — быстрые действия, веб — -точные правки), [recognition.md](specs/recognition.md) (кандидаты матча). - -### Проверка свободного места перед copy-fallback - -Когда хардлинк невозможен (`EXDEV`/`ENOTSUP`/…), `layout` копирует файл, -дублируя место на диске. На забитом диске это упрётся в полку посреди -раскладки. Перед копированием проверять доступное место и при нехватке -внятно уходить в `failed` с понятной причиной, а не падать на полпути. - -Связано: [architecture.md](specs/architecture.md) → «Раскладка файлов» -(фолбэк-копирование), пакет `layout`. - -### Кэш метабаз (и опционально LLM) - -Повторные и ретраящиеся прогоны распознавания бьют TMDB/TVDB/TVMaze одним и -тем же запросом. Кэш ответов с TTL экономит лимиты API и ускоряет «Распознать -заново»/«Уточнить». При желании — кэш ответов LLM по хешу входа (но он менее -полезен, т.к. вход меняется подсказками). - -Связано: [recognition.md](specs/recognition.md) (сверка с базой), пакеты -`metadata`, `llm`. - -### guessit как сервис-спутник _(идея)_ - -`go-ptn` слабее питоновского `guessit`. Если точности пред-парса не -хватит — завернуть `guessit` в крошечный HTTP-сервис (один файл, -поставляется рядом с бинарём jellybit) и спрашивать его на шаге -пред-парса. Сохраняет «доставку копированием»: два файла вместо одного. - -Связано: [recognition.md](specs/recognition.md) → «На будущее» (пред-парс). - -### Завершение загрузки через webhook _(идея)_ - -Сейчас завершение ловим поллингом qBittorrent раз в несколько секунд. -Альтернатива: «Run external program on torrent completion» в qBittorrent -дёргает эндпоинт jellybit. Реагирует быстрее, но связывает нас с конфигом -qBittorrent. Решим по опыту эксплуатации. - -Связано: [architecture.md](specs/architecture.md) → «Отслеживание загрузки», -пакет `worker`. - -### Авторизация веб-UI (на будущее) - -Решено для v1: без авторизации в доверенной LAN, опц. allowlist подсетей -(`http.trusted_subnets`) — как умеет qBittorrent. Если понадобится защита: -токен/Basic в самом приложении или вынос за reverse-proxy с -аутентификацией. - -Связано: [architecture.md](specs/architecture.md) → «Транспорты» (доступ к -веб-UI), пакет `httpapi`. - -### Современный Web-UI как PWA - -Переделать веб-интерфейс в современное PWA-приложение (устанавливаемое, -отзывчивое, удобное с телефона). Текущий server-rendered UI функционален, -поэтому это улучшение, а не блокер; большой объём работы. - -Связано: [review-ux.md](specs/review-ux.md) (веб = точные правки), -пакет `httpapi`. diff --git a/docs/specs/architecture.md b/docs/specs/architecture.md index be7db30..b92c096 100644 --- a/docs/specs/architecture.md +++ b/docs/specs/architecture.md @@ -61,7 +61,8 @@ reject / defer / undo) — команды к `worker`: (server-rendered). В v1 **без авторизации** (доверенная LAN). Поле `http.trusted_subnets` зарезервировано, но **пока не применяется**: деплой только в локальную сеть без доступа из интернета, поэтому - allowlist-middleware и авторизацию отложили — [backlog.md](../backlog.md#авторизация-веб-ui-на-будущее). + allowlist-middleware и авторизацию отложили — задача «Авторизация + веб-UI» в беклоге (Tududi, проект «jellybit»). - **Telegram-бот** — переслать magnet/сообщение бота; текст становится контекстом. Доступ — по `telegram.allowed_user_ids` (пусто = запрет всем, fail-closed). Бот же шлёт **пинги** о входе в review/готовности. diff --git a/docs/specs/jellyfin-layout.md b/docs/specs/jellyfin-layout.md index 791a8f9..ddf048e 100644 --- a/docs/specs/jellyfin-layout.md +++ b/docs/specs/jellyfin-layout.md @@ -99,4 +99,4 @@ inode общий — диск не дублируется. сезонам. - **Несколько аудиодорожек** — обычно внутри mkv, не наша забота. - **Аниме с абсолютной нумерацией** — пересчёт в S·E, отдельная проработка - ([backlog.md](../backlog.md#аниме-с-абсолютной-нумерацией)). + (задача в беклоге — Tududi, проект «jellybit»). diff --git a/docs/specs/recognition.md b/docs/specs/recognition.md index 086ce8a..430f577 100644 --- a/docs/specs/recognition.md +++ b/docs/specs/recognition.md @@ -133,11 +133,12 @@ notes пояснения, неоднозначности - Сезон-паки разбираем по сериям; смешанные паки, спецвыпуски (`Season 00`), двойные серии (`SxxEyy-Eyy`) — через per-file season/episode; любая неоднозначность → review. -- Аниме с абсолютной нумерацией — отдельный крайний случай, см. - [backlog.md](../backlog.md#аниме-с-абсолютной-нумерацией). +- Аниме с абсолютной нумерацией — отдельный крайний случай, задача + в беклоге (Tududi, проект «jellybit»). ## На будущее `go-ptn` слабее питоновского `guessit`. Если точности пред-парса не хватит — завернуть `guessit` лёгким сервисом-спутником (один файл рядом с -бинарём). См. [backlog.md](../backlog.md#guessit-как-сервис-спутник-идея). +бинарём). Задача «guessit как сервис-спутник» в беклоге (Tududi, проект +«jellybit»). diff --git a/docs/specs/review-ux.md b/docs/specs/review-ux.md index 5175cbf..d8141f1 100644 --- a/docs/specs/review-ux.md +++ b/docs/specs/review-ux.md @@ -119,8 +119,8 @@ Telegram = одобрить / подсказать / выбрать кандид - **База неоднозначна** → выбор кандидата (часто чинит всё разом: пиннит provider-id и каноническое имя). - **База пустая (рус/аниме)** → «без базы» или ручной id/url. Аниме с - абсолютной нумерацией → веб-хелпер «absolute → S·E» (см. - [backlog.md](../backlog.md#аниме-с-абсолютной-нумерацией)). + абсолютной нумерацией → веб-хелпер «absolute → S·E» (задача + «Аниме с абсолютной нумерацией» в беклоге — Tududi, проект «jellybit»). - **Не тот тип (movie↔series)** → переключатель пересобирает форму плана. - **Мусор (sample/extra/дубли дорожек)** → роль «игнор». - **Полный провал** (LLM ничего не вытащил) → веб-«ручной режим»: выбрать