diff --git a/tasks/BACKLOG.md b/tasks/BACKLOG.md index 2a3ff83..8cbc3fb 100644 --- a/tasks/BACKLOG.md +++ b/tasks/BACKLOG.md @@ -13,7 +13,6 @@ ## Ядро продукта -- [🐞 Санитизировать название из метабазы перед подстановкой в план](items/metadata-title-sanitize.md) — plan.Title = match.Title подставляется ПОСЛЕ sanitizePlan — название из TMDB/TVDB уезжает в имя каталога Jellyfin дословно, с невидимыми символами и гомоглифами, и авто-раскладка это пропускает - [🐞 Отправлять на ревью раздачу с непомещающимся именем вместо отказа](items/long-title-to-review.md) — название длиннее ~237 байт роняет раскладку в failed с текстом системной ошибки: пользователь видит «file name too long» вместо карточки ревью, где это чинится подсказкой - [🔬 Форма ответа поиска TheTVDB и семантика параметра language](items/tvdb-search-response-live-check.md) — форма ответа поиска TheTVDB принята по swagger 4.7.10 и живым прогоном не подтверждена — при иной форме разбор молча уходит в фолбэк, гейт зелёный, локализованное название не работает - [✨ Узаконить confidence-гейт авто-раскладки в спеке и сделать его выключаемым (дефолт 0.7)](items/auto-link-confidence-gate.md) — Решено (B): гейт оставляем как доп. проверку на ревью — выключаемый порог, дефолт 0.85→0.7, записать в спеку diff --git a/tasks/items/metadata-title-sanitize.md b/tasks/items/metadata-title-sanitize.md deleted file mode 100644 index 9bb197a..0000000 --- a/tasks/items/metadata-title-sanitize.md +++ /dev/null @@ -1,72 +0,0 @@ -# 🐞 Санитизировать название из метабазы перед подстановкой в план - -- **Тип:** fix -- **Категория:** Ядро продукта — дефект major: название из метабазы уезжает в имя каталога Jellyfin мимо санитизации, авто-раскладка это пропускает; оракул добыт триажом, а internal/recognize тронут tvdb-title-locale неделю назад — окно открыто -- **Зачем:** plan.Title = match.Title подставляется ПОСЛЕ sanitizePlan — название из TMDB/TVDB уезжает в имя каталога Jellyfin дословно, с невидимыми символами и гомоглифами, и авто-раскладка это пропускает - -Название, пришедшее из метабазы, подставляется в план **после** того, как план -прошёл санитизацию: `plan.Title = match.Title` стоит ниже `sanitizePlan`. -Значение уезжает в имя каталога библиотеки, не сверенное ни с чем — гейт -авто-раскладки сверяет `normalize(c.Title) || normalize(c.OriginalTitle)` и -проходит по второму полю, а в путь идёт первое. - -`layout.sanitizeComponent` ниже по потоку снимает `/\:*?"<>|` и байты `< 0x20`, -но категорию Cf (невидимые управляющие) не трогает и гомоглифы не сворачивает. -Итог — два визуально неотличимых каталога в медиатеке. - -**Класс пре-существующий, и это важно для рамок:** тот же путь у TMDB, задача -`tvdb-title-locale` его только распространила на второго провайдера. Инвариант -«целевой путь строго под библиотекой» **держится** — проверено на `Dune/../../etc`, -`" .. "`, `"..."` и на 400 символах, выхода из песочницы нет. Поэтому `major`, -а не `critical`. - -Провенанс: ревью изменения `tvdb-title-locale`, находка 2 — -[отчёт триажа](../../openspec/changes/archive/2026-08-07-tvdb-title-locale/review/report.md). - -## Воспроизведение - -Падающий тест на реальном `Recognizer` (оракул добыт триажом, не рассуждением). -Подать кандидата метабазы с названием и посмотреть на `plan.Title` и решение -гейта: - -| Вход | Что происходит | -| --- | --- | -| три символа ZWSP (`U+200B`) | `auto=true`, в план уезжают невидимки; `sanitizeTitle` дал бы пустую строку | -| `Dunegnp.mkv` (`U+202E`) | `auto=true`, имя каталога переворачивается при отображении | -| `Dune\nHACK` | `auto=true`, перевод строки доезжает до плана | -| `Dunа` с кириллической `а` | `auto=true`, каталог визуально неотличим от латинского `Dune` | - -Во всех четырёх случаях значение в плане отличается от того, что дал бы -санитайзер, и ни одно не остановлено гейтом. - -## Затрагивает - -- `internal/recognize/recognize.go` — порядок подстановки `match.Title` и - `match.OriginalTitle` относительно `sanitizePlan`; -- `internal/layout` — состав `sanitizeComponent`, если решим закрывать категорию - Cf и гомоглифы здесь, а не на подстановке (выбор места — часть задачи); -- поведение **обоих** провайдеров, TMDB и TVDB: правка меняет уже работающий - TMDB, и это её главный риск; -- `openspec/specs/metadata-match/spec.md` либо `file-layout` — чьим требованием - станет «название из метабазы санитизируется перед попаданием в путь». - -## Критерии приёмки - -- Все четыре входа из «Воспроизведения» дают либо санитизированный `plan.Title`, - либо уход в review — но не авто-раскладку с исходным значением. **Оракул:** - тот самый падающий тест из отчёта триажа, перенесённый в дерево. -- Название, схлопывающееся санитизацией в пустую строку, не порождает каталог с - пустым именем и не роняет раскладку. **Оракул:** табличный тест на границе, - случай «три ZWSP». -- Поведение TMDB на нормальных названиях не изменилось. **Оракул:** существующие - тесты `internal/recognize` и `internal/metadata` зелёные без правок ожиданий. -- Место санитизации названо требованием спеки, а не только кодом. **Оракул:** - `openspec validate --strict` на дельте. - -## Рамки - -Гомоглифы сворачивать не обязательно — достаточно сделать значение в пути -предсказуемым и сверяемым; полноценная нормализация Unicode это отдельный -разговор. Инвариант «целевой путь строго под библиотекой» уже держится, ломать -его правкой нельзя. Правка задевает работающий TMDB — регресс на нём дороже -самого дефекта.