recognize: название из метабазы санитизируется перед попаданием в план

- чистка стоит на каждой точке входа значения метабазы в план — сборка матча,
  копия кандидата для ревью, набор закреплённых значений источника и его
  чтение: гарантия, поставленная только на запись, обходится данными,
  сохранёнными прежними версиями
- название, непригодное как имя каталога (пустое или без единой буквы и
  цифры), не подставляется — раздача уходит в review с названной причиной
- гейт подтверждения матча не сдвинут: сравнение с планом идёт по значениям
  провайдера, чистится только копия, уходящая дальше
This commit is contained in:
av
2026-08-10 10:41:16 +03:00
parent bb278e8744
commit 9aecf757e0
26 changed files with 1653 additions and 53 deletions
+22
View File
@@ -158,3 +158,25 @@ func TestDeriveNameNilProviderUsesFallback(t *testing.T) {
t.Errorf("DeriveName() = %q (ожидался фолбек без LLM)", got)
}
}
// Значения ярлыка приходят снаружи — из credits метабазы и из сохранённого
// контекста. Категория Cf (zero-width, BOM, RLO) обязана сниматься здесь:
// требование metadata-match не чистит режиссёра в плане именно потому, что его
// чистит рендер. RLO в карточке Telegram переворачивает отображение имени.
func TestSanitize_StripsFormatChars(t *testing.T) {
cases := []struct{ in, want string }{
{"Denis\u202eVilleneuve", "DenisVilleneuve"},
{"Denis\u200bVilleneuve", "DenisVilleneuve"},
{"Denis\ufeffVilleneuve", "DenisVilleneuve"},
{"Denis\nVilleneuve", "Denis Villeneuve"},
{"Дени Вильнёв", "Дени Вильнёв"},
}
for _, c := range cases {
if got := sanitize(c.in); got != c.want {
t.Errorf("sanitize(%q) = %q, want %q", c.in, got, c.want)
}
}
if got := Label("Dune", "Denis\u202eVilleneuve", 2021, ""); got != "Dune (DenisVilleneuve, 2021)" {
t.Errorf("Label = %q", got)
}
}