## MODIFIED Requirements

### Requirement: Сверка с базой по нескольким названиям

При сверке плана с включёнными базами метаданных система SHALL искать по
нескольким названиям в порядке убывания силы ключа: сначала по
`original_title`, затем по локализованному `title`, затем по `provider_hint`.
Этот перебор названий SHALL выполняться в рамках каждого прохода сверки — проходы
(с годом и безгодовой fallback) определяет требование «Безгодовой второй проход
сверки как fallback». Поиск SHALL останавливаться, как только очередной запрос
дал единичный сильный матч (ровно один кандидат с совпадением названия и года);
ранняя остановка действует в пределах прохода. Запрос с названием, нормализованно
совпадающим с уже выполненным, система SHALL пропускать, чтобы не обращаться к
базе повторно с тем же ключом.

Кандидаты для ручного выбора в review система SHALL собирать из всех выполненных
заходов обоих проходов с дедупликацией по `provider:id` и общим потолком.

#### Scenario: Иностранный фильм находится по оригинальному названию

- **GIVEN** план с `title` «Тёмный рыцарь», `original_title` «The Dark Knight», год 2008
- **WHEN** выполняется сверка с базой
- **THEN** первый запрос идёт по «The Dark Knight»
- **AND** при единичном сильном матче дальнейшие запросы (по `title`, `provider_hint`) не выполняются

#### Scenario: Фолбэк на локализованное название

- **GIVEN** план, для которого запрос по `original_title` не дал единичного сильного матча
- **WHEN** продолжается сверка
- **THEN** выполняется запрос по локализованному `title`
- **AND** при отсутствии матча и там — запрос по `provider_hint`

#### Scenario: Дублирующий запрос пропускается

- **GIVEN** план, у которого `original_title` нормализованно совпадает с `title`
- **WHEN** выполняется сверка
- **THEN** база запрашивается этим названием один раз, повторный заход по `title` не делается

### Requirement: Нормализация названий при сравнении

Нормализация названий для гейта сильного матча SHALL сводить букву `ё` к `е`,
чтобы написания, различающиеся только `ё`/`е`, считались одним названием.

Нормализация SHALL дополнительно сворачивать кирилло-латинские homoglyph-двойники
по той же курируемой таблице, что применяется при санитайзинге плана
(capability `recognition`), чтобы визуально совпадающие название плана и кандидата
базы, различающиеся лишь скриптом отдельных букв, считались одним названием. Это
defense-in-depth на случай двойников со стороны кандидата: гейт — точка
безопасно-критичного решения об авто-матче и SHALL быть устойчив к двойникам
независимо от предшествующего санитайзинга.

#### Scenario: «Тёмный» и «Темный» совпадают

- **GIVEN** план с названием «Тёмный рыцарь» и кандидат базы «Темный рыцарь»
- **WHEN** сравниваются нормализованные названия
- **THEN** они считаются совпадающими

#### Scenario: Двойник у кандидата не мешает матчу

- **GIVEN** план с латинским названием `Harold` и кандидат базы, где то же слово
  содержит кириллический символ-двойник
- **WHEN** сравниваются нормализованные названия
- **THEN** они считаются совпадающими

## ADDED Requirements

### Requirement: Безгодовой второй проход сверки как fallback

Система SHALL выполнять второй проход сверки без года как fallback: когда поиск с
годом не дал подтверждённого единичного сильного матча, а год плана известен
(`year > 0`), выполняется тот же перебор названий (в порядке `original_title` →
`title` → `provider_hint`) и провайдеров, но с запросом БЕЗ года. Второй проход
SHALL выполняться только как
fallback: если первый проход подтвердил матч или год плана неизвестен, второго
прохода быть SHALL NOT.

Гейт сильного матча (нормализованное совпадение названия и год кандидата в пределах
±1, ровно один кандидат) при этом SHALL оставаться неизменным — безгодовой проход
расширяет только выдачу запроса, но не ослабляет условие подтверждения, поэтому
инвариант «авто-раскладка только при подтверждённом единичном сильном матче» не
затрагивается. Дополнительно в безгодовом проходе система SHALL требовать
известный год кандидата: запись с неизвестным годом (год подтвердить нечем) во
втором проходе подтверждённым матчем быть SHALL NOT и уходит кандидатом в review
(в первом, с-годом, проходе прежняя leniency к неизвестному году сохраняется).
Кандидаты для ручного выбора в review система SHALL собирать из обоих проходов с
той же дедупликацией по `provider:id` и общим потолком.

#### Scenario: Год плана off-by-one — авто-матч восстанавливается без года

- **GIVEN** запись есть в базе, но год плана отличается от её года ровно на 1
  (жёсткий exact-year фильтр запроса отсёк её в первом проходе)
- **WHEN** первый проход (с годом) не дал сильного матча
- **THEN** выполняется второй проход без года
- **AND** единичный кандидат проходит гейт (название совпадает, год бьётся ±1) —
  матч подтверждается

#### Scenario: Год плана расходится больше чем на 1 — кандидат только в review

- **GIVEN** запись есть в базе, но год плана отличается от её года больше чем на 1
- **WHEN** второй проход без года возвращает эту запись единственным кандидатом
- **THEN** гейт отклоняет её по году (расхождение больше ±1) — подтверждённого
  матча нет
- **AND** кандидат собирается для выбора в review (человек получает кандидата
  вместо пустого списка)

#### Scenario: Первый проход подтвердил матч — второго нет

- **GIVEN** первый проход (с годом) дал единичный сильный матч
- **WHEN** завершается сверка
- **THEN** второй (безгодовой) проход не выполняется

#### Scenario: Год неизвестен — второго прохода нет

- **GIVEN** план без года (`year` = 0)
- **WHEN** первый проход не дал матча
- **THEN** второй проход не выполняется (он был бы идентичен первому)

#### Scenario: Кандидат с неизвестным годом в безгодовом проходе — только review

- **GIVEN** год плана известен, а pass 1 (с годом) не дал матча
- **WHEN** безгодовой проход возвращает единственного кандидата с совпадающим
  названием, но неизвестным годом
- **THEN** подтверждённого матча нет (год кандидата не подтверждён) — авто-раскладка
  не делается
- **AND** кандидат собирается для выбора в review

#### Scenario: Несколько кандидатов из безгодового прохода — матч не подтверждён

- **GIVEN** безгодовой проход вернул более одного кандидата, проходящего гейт
- **WHEN** оценивается матч
- **THEN** подтверждённого матча нет, кандидаты собираются для выбора в review
