- в «Ядре» первыми стоят metadata-title-sanitize и long-title-to-review, за ними живая проверка формы ответа TheTVDB и confidence-гейт - в «Инфраструктуре» первой стала background-error-noise: единственный ready-дефект секции, решение по бэкоффу принято 2026-08-06 - infohash-identity-integrity понижен до research и сдвинут вниз: тело само не решает между change и ограничением в документе, взять его нельзя
73 lines
6.1 KiB
Markdown
73 lines
6.1 KiB
Markdown
# 🐞 Санитизировать название из метабазы перед подстановкой в план
|
||
|
||
- **Тип:** 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` дал бы пустую строку |
|
||
| `Dune<RLO>gnp.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 — регресс на нём дороже
|
||
самого дефекта.
|