Files
jellybit/openspec/changes/archive/2026-08-10-metadata-title-sanitize/specs/recognition/spec.md
T
av 9aecf757e0 recognize: название из метабазы санитизируется перед попаданием в план
- чистка стоит на каждой точке входа значения метабазы в план — сборка матча,
  копия кандидата для ревью, набор закреплённых значений источника и его
  чтение: гарантия, поставленная только на запись, обходится данными,
  сохранёнными прежними версиями
- название, непригодное как имя каталога (пустое или без единой буквы и
  цифры), не подставляется — раздача уходит в review с названной причиной
- гейт подтверждения матча не сдвинут: сравнение с планом идёт по значениям
  провайдера, чистится только копия, уходящая дальше
2026-08-10 10:41:16 +03:00

8.9 KiB
Raw Blame History

MODIFIED Requirements

Requirement: Санитайзинг человекочитаемых полей плана

Перед структурной валидацией плана и сверкой с базами система SHALL санитизировать человекочитаемые поля плана — title, original_title, provider_hint — как недоверенный вывод LLM. Санитайзинг SHALL: (1) удалять управляющие и zero-width символы (C0/C1, U+200B и родственные, BOM U+FEFF); (2) сводить внутренние последовательности пробельных к одиночному пробелу и обрезать края; (3) сворачивать кирилло-латинские homoglyph-двойники (см. ниже).

Санитайзинг SHALL быть общим для обоих источников названия — вывода LLM и записи метабазы. Значение, пришедшее из метабазы и заменяющее поле плана при подтверждённом матче, SHALL проходить тот же санитайзинг перед подстановкой (см. metadata-match, требование «Подтверждение матча и каноническое имя»). Второго способа чистить названия плана система SHALL NOT заводить: одна реализация обслуживает оба источника. Речь только о полях плана — очистка компонента пути под требования файловой системы (layout) и очистка отображаемого ярлыка (naming) остаются своими, отдельными и законными.

Санитайзинг SHALL быть идемпотентным: повторное применение к уже санитизированному значению SHALL NOT изменять его. На этом свойстве стоит утверждение, что правка не меняет путей на диске для раздач с нормальным названием, и оно проверяется тестом, а не подразумевается.

Следствие, на которое опирается раскладка: к моменту, когда план уходит в решение auto/review, каждое из полей title, original_title, provider_hint совпадает с тем, что дал бы санитайзинг этого значения — независимо от того, пришло оно от LLM или из метабазы.

Свёртка двойников SHALL работать потокенно (по словам, разделённым не-буквенными символами): токен, все буквы которого принадлежат одному скрипту, система SHALL оставлять без изменений (билингвальность реальна — кириллические названия неприкосновенны); в токене смешанного скрипта система SHALL определять доминирующий скрипт по числу буквенных рун и заменять буквы-меньшинство их визуальными двойниками из доминирующего скрипта по курируемой таблице. При отсутствии доминирующего скрипта (равенство) токен SHALL оставаться без изменений.

Санитайзинг SHALL применяться ТОЛЬКО к перечисленным человекочитаемым полям плана. Применение того же санитайзинга к значениям, пришедшим из метабазы — каноническому названию и названиям кандидатов, — заказано отдельно, см. metadata-match. files[].src система SHALL NOT санитизировать — эти значения обязаны совпадать с реальными файлами торрента, и расхождение (в т.ч. homoglyph) SHALL оставаться основанием отклонить план, а не поводом «чинить» путь. director система SHALL NOT санитизировать в плане — он не участвует в пути на диске, и его очистка применяется при рендере отображаемого имени (см. metadata-match).

Когда санитайзинг реально изменил значение поля, система SHALL логировать это на уровне Debug (названия не относятся к секретам).

Scenario: Кириллический двойник в англоязычном названии сворачивается

  • GIVEN план, где title = Hаrold and the Purple Crayon (буква а в первом слове — кириллическая U+0430)
  • WHEN план санитизируется
  • THEN первое слово становится Harold (все буквы латинские)
  • AND в запрос к базе и в сравнение уходит латинское название

Scenario: Честное кириллическое название не трогается

  • GIVEN план российского фильма с title = Тёмный рыцарь, где все буквы каждого слова кириллические
  • WHEN план санитизируется
  • THEN название остаётся кириллическим без замены букв

Scenario: Токен без доминирующего скрипта не трогается

  • GIVEN план, где короткий токен содержит поровну латинских и кириллических букв (доминирующего скрипта нет)
  • WHEN план санитизируется
  • THEN этот токен остаётся без замены букв (осознанный trade-off: двухбуквенный homoglyph-typo не сворачивается)

Scenario: Zero-width и лишние пробелы вычищаются

  • GIVEN план, где title содержит zero-width символ и сдвоенные пробелы
  • WHEN план санитизируется
  • THEN zero-width удалён, внутренние пробелы сведены к одиночным, края обрезаны

Scenario: files[].src не санитизируется

  • GIVEN ответ LLM, где files[].src содержит символ-двойник и не совпадает ни с одним реальным файлом торрента
  • WHEN план обрабатывается
  • THEN files[].src НЕ изменяется санитайзингом
  • AND несовпадение src приводит к отклонению плана (эскалация в review), а не к «починке» пути

Scenario: Название из метабазы чистится тем же санитайзингом

  • GIVEN подтверждённый единичный матч, каноническое название которого содержит zero-width символ и кириллический двойник внутри латинского слова
  • WHEN каноническое название подставляется в план
  • THEN в плане оказывается значение, прошедшее тот же санитайзинг, что и вывод LLM

Scenario: После сверки с базой несанитизированных полей в плане не остаётся

  • GIVEN план после подтверждённого матча с базой
  • WHEN оценивается решение auto/review
  • THEN каждое из полей title, original_title, provider_hint совпадает с тем, что дал бы санитайзинг этого значения
  • AND director под это требование не подпадает: он чистится при рендере отображаемого имени

Scenario: Повторный санитайзинг ничего не меняет

  • GIVEN значение, уже прошедшее санитайзинг
  • WHEN санитайзинг применяется к нему второй раз
  • THEN значение не изменяется