- чистка стоит на каждой точке входа значения метабазы в план — сборка матча, копия кандидата для ревью, набор закреплённых значений источника и его чтение: гарантия, поставленная только на запись, обходится данными, сохранёнными прежними версиями - название, непригодное как имя каталога (пустое или без единой буквы и цифры), не подставляется — раздача уходит в review с названной причиной - гейт подтверждения матча не сдвинут: сравнение с планом идёт по значениям провайдера, чистится только копия, уходящая дальше
158 lines
14 KiB
Markdown
158 lines
14 KiB
Markdown
## ADDED Requirements
|
|
|
|
### Requirement: Санитайзинг названий кандидатов, уходящих в ревью
|
|
|
|
Система SHALL санитизировать названия кандидата (`Title`, `OriginalTitle`) тем же
|
|
санитайзингом человекочитаемых полей плана (см. `recognition`) перед тем, как
|
|
унести их из сверки дальше: в список кандидатов для ревью, в хранилище, на экран
|
|
и в закрепляемое человеком значение. Причина та же, что у
|
|
канонического названия: выбор кандидата человеком — полноправный путь
|
|
подтверждения матча, и закреплённое им название становится именем каталога
|
|
библиотеки в тех же условиях, что и название авто-матча.
|
|
|
|
Условия подтверждения сильного матча система SHALL проверять на значениях, как их
|
|
отдал провайдер: санитайзинг кандидатов SHALL NOT влиять на эти значения. Порядок
|
|
операций требование не нормирует — нормирует исход: гейт матча этой правкой не
|
|
двигается, иначе кандидат, чьё название отличается от плана невидимым символом,
|
|
начал бы совпадать там, где прежде уходил в review. Полнота списка кандидатов
|
|
тоже SHALL остаться прежней.
|
|
|
|
Если название кандидата после санитайзинга непригодно как компонент пути (пусто
|
|
либо без единой буквы и цифры), система SHALL сохранить кандидата в списке — он
|
|
остаётся выбором человека и несёт `provider_id` и URL для внешней проверки, — но
|
|
закрепление такого названия SHALL приводить к тому же исходу, что и у
|
|
канонического: подстановки не происходит, в плане остаётся название
|
|
распознавания.
|
|
|
|
`OriginalTitle` кандидата чистится наравне с `Title`, хотя в хранилище и на экран
|
|
сегодня доходит только второе: первое уезжает в результат распознавания и в
|
|
диагностику сухого прогона, и держать в одной структуре одно чистое поле и одно
|
|
грязное — источник будущей ошибки.
|
|
|
|
#### Scenario: Название кандидата чистится перед показом и закреплением
|
|
|
|
- **GIVEN** провайдер вернул кандидата, название которого содержит zero-width
|
|
символ и кириллический двойник внутри латинского слова
|
|
- **WHEN** кандидат попадает в список для ревью
|
|
- **THEN** его название очищено тем же санитайзингом, что и поля плана
|
|
- **AND** человек, выбравший этого кандидата, закрепляет очищенное название
|
|
- **AND** в имя каталога библиотеки оно уходит в тех же условиях, что и название
|
|
авто-матча (живой папки-якоря того же тайтла нет — см. `file-layout`,
|
|
«Сходимость базы папки при подтверждённом матче»)
|
|
|
|
#### Scenario: Сравнение с планом идёт по значению провайдера
|
|
|
|
- **GIVEN** кандидат, название которого отличается от названия плана только
|
|
невидимым символом внутри слова
|
|
- **WHEN** проверяются условия подтверждения сильного матча
|
|
- **THEN** сравнение идёт по значению, как его отдал провайдер
|
|
- **AND** исход подтверждения матча тот же, что был до этого изменения
|
|
|
|
## MODIFIED Requirements
|
|
|
|
### Requirement: Подтверждение матча и каноническое имя
|
|
|
|
При единичном сильном матче система SHALL брать из записи базы официальный
|
|
`provider` (`tmdb`|`tvdb`|`tvmaze`) и `provider_id`, а также каноническое название
|
|
и год, и подменять ими соответствующие поля плана (для сериала — с учётом внешнего
|
|
тега TVDB/IMDb из `externals`, идущего в имя папки). Матч SHALL считаться
|
|
подтверждённым только при ровно одном сильном кандидате; при нуле или нескольких
|
|
кандидатах подтверждённого матча быть SHALL NOT (авто-раскладка не разрешается,
|
|
кандидаты уходят в review). Работа с базами опциональна: при выключенных базах
|
|
сверка не выполняется и подтверждённого матча нет.
|
|
|
|
Каноническое название — **недоверенное значение внешнего сервиса**, и перед
|
|
подстановкой в план система SHALL применять к нему тот же санитайзинг
|
|
человекочитаемых полей, что и к выводу LLM (см. `recognition`, требование
|
|
«Санитайзинг человекочитаемых полей плана»). Подстановка несанитизированного
|
|
значения SHALL NOT выполняться: план — источник имени каталога библиотеки, и
|
|
значение, не прошедшее чистку, уходит в путь на диске.
|
|
|
|
Если после санитайзинга каноническое название оказывается **непригодным как
|
|
компонент пути** — пустым либо вырожденным, то есть не содержащим ни одной буквы
|
|
и ни одной цифры (`.`, `..`, `-`, только пунктуация), — система SHALL сохранить в
|
|
плане прежнее название и SHALL NOT разрешать авто-раскладку: причина уходит в
|
|
перечень причин решения, раздача попадает в review. Проверка пригодности SHALL
|
|
стоять **после** санитайзинга, а не до него. Ронять распознавание или раскладку
|
|
такой матч SHALL NOT — год, провайдер и `provider_id` при этом подставляются как
|
|
обычно.
|
|
|
|
Санитайзинг, **изменивший** каноническое название, но оставивший его пригодным,
|
|
авто-раскладку SHALL NOT блокировать: в план идёт очищенное значение, и оно
|
|
предсказуемо — ради этого чистка и стоит.
|
|
|
|
При подтверждённом матче система SHALL дополнительно попытаться получить из базы
|
|
**режиссёра** (TMDB/TVDB credits) и вложить его в план (`director`) как
|
|
недоверенное косметическое значение для вывода отображаемого имени. Тот же способ
|
|
выборки режиссёра по `provider:id` SHALL быть доступен при закреплении вручную
|
|
выбранного в ревью кандидата (см. `review`), т.к. основной путь подтверждения
|
|
матча — ручной выбор, а не авто. Выборка режиссёра SHALL быть best-effort: её
|
|
недоступность, отсутствие в базе или провайдер без режиссёра (напр. TVMaze) SHALL
|
|
NOT проваливать распознавание/матч/выбор — `director` остаётся пустым, а имя
|
|
выводится без режиссёра или из более низкого слоя (сохранённый контекст). Режиссёр
|
|
из метабазы SHALL иметь приоритет над режиссёром из контекста (более проверенный
|
|
источник).
|
|
|
|
Режиссёр — недоверенное человекочитаемое поле: он SHALL NOT участвовать в
|
|
структурной валидации/гейте авто-раскладки, а его очистка (управляющие символы,
|
|
пробелы, лимит длины) применяется при рендере отображаемого имени, а не в
|
|
plan-санитайзинге.
|
|
|
|
#### Scenario: Единичный матч даёт id и каноническое имя
|
|
|
|
- **GIVEN** поиск вернул ровно одного сильного кандидата TMDB для фильма
|
|
- **WHEN** матч подтверждается
|
|
- **THEN** план получает `provider`=`tmdb`, `provider_id`, каноническое название и год
|
|
|
|
#### Scenario: Каноническое название чистится перед подстановкой
|
|
|
|
- **GIVEN** подтверждённый единичный матч, каноническое название которого содержит
|
|
zero-width символ, перевод строки или кириллический двойник внутри латинского слова
|
|
- **WHEN** каноническое название подставляется в план
|
|
- **THEN** в плане оказывается санитизированное значение
|
|
- **AND** авто-раскладка остаётся разрешённой, если прочие условия выполнены
|
|
- **AND** когда база имени папки печатается из распознавания (живой папки-якоря
|
|
того же тайтла нет — см. `file-layout`, «Сходимость базы папки при подтверждённом
|
|
матче»), в имя каталога уходит очищенное значение
|
|
|
|
#### Scenario: Название базы непригодно как компонент пути — раздача уходит в review
|
|
|
|
- **GIVEN** подтверждённый единичный матч, каноническое название которого после
|
|
санитайзинга пусто (целиком состояло из zero-width символов) либо не содержит ни
|
|
одной буквы и ни одной цифры (`.`, `...`, `-`)
|
|
- **WHEN** каноническое название подставляется в план
|
|
- **THEN** название плана остаётся прежним (подстановки не происходит)
|
|
- **AND** решение auto/review содержит причину «название из базы непригодно как имя
|
|
каталога», авто-раскладка не разрешается
|
|
- **AND** распознавание не проваливается, год и провайдер подставлены
|
|
|
|
#### Scenario: Нормальное название матча не меняется
|
|
|
|
- **GIVEN** подтверждённый единичный матч с обычным каноническим названием
|
|
- **WHEN** каноническое название подставляется в план
|
|
- **THEN** значение в плане совпадает с тем, что отдала база (санитайзинг на чистом
|
|
значении ничего не меняет)
|
|
- **AND** авто-раскладка остаётся разрешённой, если прочие условия выполнены
|
|
|
|
#### Scenario: Матч подтягивает режиссёра
|
|
|
|
- **GIVEN** подтверждённый единичный матч TMDB для фильма, у которого в credits
|
|
указан режиссёр
|
|
- **WHEN** матч подтверждается
|
|
- **THEN** в план вкладывается `director` из credits
|
|
- **AND** отображаемое имя может использовать этого режиссёра
|
|
|
|
#### Scenario: Режиссёр недоступен — матч не ломается
|
|
|
|
- **GIVEN** подтверждённый матч, для которого выборка режиссёра недоступна или
|
|
провайдер режиссёра не отдаёт
|
|
- **WHEN** матч подтверждается
|
|
- **THEN** `director` остаётся пустым
|
|
- **AND** матч подтверждён, распознавание не проваливается
|
|
|
|
#### Scenario: Несколько кандидатов — матч не подтверждён
|
|
|
|
- **GIVEN** поиск вернул более одного подходящего кандидата
|
|
- **WHEN** оценивается матч
|
|
- **THEN** подтверждённого матча нет, кандидаты собираются для выбора в review
|