recognize: название из метабазы санитизируется перед попаданием в план
- чистка стоит на каждой точке входа значения метабазы в план — сборка матча, копия кандидата для ревью, набор закреплённых значений источника и его чтение: гарантия, поставленная только на запись, обходится данными, сохранёнными прежними версиями - название, непригодное как имя каталога (пустое или без единой буквы и цифры), не подставляется — раздача уходит в review с названной причиной - гейт подтверждения матча не сдвинут: сравнение с планом идёт по значениям провайдера, чистится только копия, уходящая дальше
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
## 1. Код
|
||||
|
||||
- [x] 1.1 В `internal/recognize/recognize.go` прогнать `match.Title` через
|
||||
`sanitizeTitle` перед подстановкой в `plan.Title`; год, режиссёр и провайдер
|
||||
оставить как есть
|
||||
- [x] 1.2 Непригодный результат чистки (пусто либо ни одной буквы и цифры):
|
||||
подстановку не выполнять, прежнее название сохранить, причину передать **в**
|
||||
`decide`, а не дописывать к готовому решению (см. design, Решение 4)
|
||||
- [x] 1.3 Логировать на `Debug`, когда чистка реально изменила каноническое
|
||||
название — тем же способом, что `sanitizeField` (названия не секреты)
|
||||
- [x] 1.4 Чистить `Title`/`OriginalTitle` кандидата на **копии**, в момент
|
||||
`append` в `candidates` (`internal/recognize/metadata.go`). Место накопления не
|
||||
двигать — оно стоит до `if match != nil { continue }`, и перенос обеднил бы
|
||||
список кандидатов при подтверждённом матче с заблокированным авто. Срез `cands`
|
||||
не мутировать: `for _, c := range cands` даёт копию структуры (все поля
|
||||
`metadata.Candidate` скалярные), поэтому сравнение остаётся на значениях
|
||||
провайдера и гейт матча не сдвигается
|
||||
- [x] 1.5 Закрепление кандидата с непригодным названием (`chooseCandidateLocked`,
|
||||
`internal/worker/review.go`): пин названия не ставится, в плане остаётся
|
||||
название распознавания — тот же исход, что у канонического названия
|
||||
|
||||
## 2. Тесты
|
||||
|
||||
- [x] 2.1 Табличный тест на четыре входа из «Воспроизведения» задачи: три ZWSP
|
||||
(`U+200B`), `Dune<RLO>gnp.mkv` (`U+202E`), `Dune\nHACK`, `Dunа` с кириллической
|
||||
`а` — проверяет `plan.Title` и `Decision.Auto`
|
||||
- [x] 2.2 Граничные случаи непригодного названия: три ZWSP (пусто после чистки) и
|
||||
вырожденные `"."`, `"..."`, `"-"`, `" . "` — план сохраняет прежнее название,
|
||||
`Auto=false`, причина названа, год и провайдер подставлены
|
||||
- [x] 2.5 Идемпотентность: `sanitizeTitle(sanitizeTitle(x)) == sanitizeTitle(x)`
|
||||
по тому же набору входов, что и 2.1
|
||||
- [x] 2.6 Кандидаты, уходящие в ревью, очищены: те же четыре входа в названии
|
||||
кандидата — в `Result.Candidates` значения санитизированы
|
||||
- [x] 2.7 Гейт матча не сдвинулся: кандидат, отличающийся от плана только
|
||||
zero-width внутри слова, по-прежнему **не** даёт подтверждённого матча
|
||||
(сравнение идёт по значению провайдера)
|
||||
- [x] 2.8 Список кандидатов не обеднел: при подтверждённом матче от первого
|
||||
провайдера кандидаты остальных провайдеров того же ключа по-прежнему в списке
|
||||
- [x] 2.9 Закрепление кандидата с названием `-`: пин названия не поставлен, в
|
||||
плане остаётся название распознавания, каталог с мусорным именем не строится
|
||||
- [x] 2.3 Нормальное название матча: значение в плане совпадает с ответом базы,
|
||||
`Auto=true` при прочих чистых условиях
|
||||
- [x] 2.4 Прогнать существующие тесты `internal/recognize` и `internal/metadata`
|
||||
**без правки ожиданий** — регресс на TMDB виден сразу
|
||||
|
||||
## 3. Гейт и спеки
|
||||
|
||||
- [x] 3.1 `task gate` зелёный
|
||||
- [x] 3.2 `openspec validate --strict metadata-title-sanitize`
|
||||
|
||||
## Критерии приёмки задачи
|
||||
|
||||
Приходят из постановки `tasks/items/metadata-title-sanitize.md`, здесь — дословно.
|
||||
|
||||
- [x] A1 Все четыре входа из «Воспроизведения» дают либо санитизированный
|
||||
`plan.Title`, либо уход в review — но не авто-раскладку с исходным значением.
|
||||
**Оракул:** тот самый падающий тест из отчёта триажа, перенесённый в дерево
|
||||
- [x] A2 Название, схлопывающееся санитизацией в пустую строку, не порождает
|
||||
каталог с пустым именем и не роняет раскладку. **Оракул:** табличный тест на
|
||||
границе, случай «три ZWSP»
|
||||
- [x] A3 Поведение TMDB на нормальных названиях не изменилось. **Оракул:**
|
||||
существующие тесты `internal/recognize` и `internal/metadata` зелёные без правок
|
||||
ожиданий
|
||||
- [x] A4 Место санитизации названо требованием спеки, а не только кодом.
|
||||
**Оракул:** `openspec validate --strict` на дельте
|
||||
|
||||
## 4. Правки по ревью кода
|
||||
|
||||
- [x] 4.1 Санитайзинг канонического названия перенесён в `buildMatch` —
|
||||
единственную точку сборки `Match`; `recognize.go` и `decide` читают уже чистое
|
||||
значение и не пересчитывают условие каждый по-своему
|
||||
- [x] 4.2 Чистка и проверка пригодности названия источника перенесены в
|
||||
`sourcePins` — общий дом набора пинов, через который идут и превью, и
|
||||
закрепление; «превью = применение» держится конструкцией
|
||||
- [x] 4.3 Кандидаты, сохранённые прежней версией, чистятся на закреплении:
|
||||
гарантия не держится на времени записи строки
|
||||
- [x] 4.4 Отказ закрепить непригодное название виден в журнале — атрибут
|
||||
`title_pinned` у существующей записи `review candidate chosen`
|
||||
- [x] 4.5 Дельта `review` — требование «Подтверждение матча обновляет
|
||||
отображаемое имя» дополнено санитайзингом на закреплении и свойством
|
||||
«превью = применение»
|
||||
- [x] 4.6 Тесты: `TestChooseCandidate_DirtyLegacyTitleSanitized`,
|
||||
`TestBuildSources_PreviewMatchesApply` (оба падают без правки)
|
||||
- [x] 4.7 Чистка названия и на **чтении** пина (`applyOverrides`): пин,
|
||||
закреплённый прежней версией, обычным «Применить» не переписывается, и без
|
||||
этого доезжал до имени каталога дословно (находка эксплуатационного прохода)
|
||||
- [x] 4.8 `naming.sanitize` снимает категорию Cf: дельта `recognition`
|
||||
обосновывает отказ чистить `director` в плане тем, что его чистит рендер, — а
|
||||
рендер снимал только C0, и RLO из credits разворачивал карточку Telegram
|
||||
(находка триажа)
|
||||
Reference in New Issue
Block a user