- чистка стоит на каждой точке входа значения метабазы в план — сборка матча, копия кандидата для ревью, набор закреплённых значений источника и его чтение: гарантия, поставленная только на запись, обходится данными, сохранёнными прежними версиями - название, непригодное как имя каталога (пустое или без единой буквы и цифры), не подставляется — раздача уходит в review с названной причиной - гейт подтверждения матча не сдвинут: сравнение с планом идёт по значениям провайдера, чистится только копия, уходящая дальше
7.2 KiB
Значение метабазы чистится на каждой точке входа в план, а три санитайзера не сводятся в один
- Дата: 2026-08-10
- Источник:
openspec/changes/archive/2026-08-10-metadata-title-sanitize/design.md,
разделы
Decisions(Решения 1, 1a, 3) иNon-Goals
Контекст
Название, приходящее из TMDB/TVDB/TVMaze, попадает в имя каталога библиотеки Jellyfin. Выход LLM мы чистим и считаем недоверенным; название из метабазы того же обращения не получало, хотя приходит так же — из-за периметра. Наблюдаемый исход: каталог из невидимых символов выглядит пустым, кириллическая буква внутри латинского слова даёт вторую папку, неотличимую от первой, и авто-раскладка это пропускала.
Разбор показал, что точка входа не одна. Их четыре, и каждая ведёт в имя каталога: сборка подтверждённого матча, копия кандидата, уходящая на экран ревью и в хранилище, набор закреплённых значений выбранного человеком источника и чтение уже закреплённого значения.
Решение
Чистка стоит на каждой из четырёх точек, а не в одной «правильной».
Цитата из design.md, Решение 1a:
Закрываются обе одной и той же чисткой, но в трёх местах — по одному на каждую точку, где значение метабазы входит в домен.
Плюс четвёртая, добавленная по находке эксплуатационного прохода: чистка на чтении закреплённого значения. Гарантия чистоты не может держаться на времени записи строки — кандидаты и закреплённые значения, сохранённые прежними версиями, обходят её, а обычное «Применить» ничего не перезаписывает. Санитайзинг идемпотентен, поэтому лишние точки на уже чистом значении не делают ничего; это же свойство сделано нормативным и покрыто тестом.
Отдельно: гейт подтверждения матча чистка не двигает. Сравнение кандидата с
планом идёт по значениям провайдера, чистится только копия, уходящая дальше.
Причина в том, что normalize и санитайзинг не эквивалентны: невидимый символ
внутри слова normalize превращает в пробел, а санитайзинг удаляет — чистка до
сравнения превратила бы часть нынешних «в review» в «авто».
Рассмотренные варианты
- Свести три санитайзера проекта в один. Отвергнуто: у них разный предмет —
recognize.SanitizeTitleчистит значение,layout.sanitizeComponent— компонент пути под требования файловой системы,naming.sanitize— отображаемый ярлык. Свёртка гомоглифов — визуально неотличимых букв из разных алфавитов — внутриsanitizeComponentсломала бы правило сходимости базы папки: она гоняется и по имени, прочитанному с диска. - Закрыть только авто-путь, ручной отдать отдельной задаче. Отвергнуто на
чекпоинте: спека
metadata-matchсама называет ручной выбор основным путём подтверждения матча — починка коснулась бы менее употребимой половины, а спека утверждала бы свойство, которого нет. - Чистить в клиентах метабаз. Отвергнуто: пришлось бы повторять в трёх клиентах и в каждом следующем, а проверка «в плане нет грязных полей» перестала бы читаться в одном месте.
- Разовая правка данных вместо чистки на чтении. Отвергнута как более дорогая и не закрывающая следующего читателя.
- Полная нормализация Unicode (NFC/NFKC плюс полная таблица визуально совпадающих символов Unicode) — Non-Goal. Цель — предсказуемое и сверяемое значение, а не исчерпывающая защита от визуального совпадения; курируемая кирилло-латинская таблица закрывает реальный случай.
Что осталось нерешённым намеренно
Каталог с невидимым символом, уже созданный в библиотеке, кодом не лечится. Правило сходимости базы папки наследует имя от живой папки-якоря, и очистка извлечённой базы напечатала бы рядом вторую, чистую папку — то есть ровно тот исход с двумя каталогами, против которого затевалось изменение. Лечение — переименовать папку руками, после чего сходимость подхватит новое имя. Изменение закрывает появление новых таких каталогов, а не существующие.
Цена
Точек чистки четыре вместо одной, и правило «значение метабазы чистится на
входе в домен» держится на ревью, а не на линтере. Взамен свойство «показанное
на экране совпадает с тем, что ляжет на диск» держится устройством кода: чистка
стоит в sourcePins — общем доме набора закреплённых значений, через который
идут и предпросмотр, и закрепление.