Решили: у BattlePresetData появилось поле _isCarrier — «это оболочка, состав приходит снаружи». Валидатор освобождает такой пресет от требования энкаунтера и ростера и, наоборот, требует их отсутствия; второй тест следит, чтобы носитель был ровно один.

Сказано: «Завести явную роль в данных» (09.08.2026, сессия aff003ad). Выбранный вариант опросника: формулировка моя, решение Макса.

Почему: PresetMenuDuel пуст законно — бои за главным меню собираются парами в MenuBattleConfig, а пресет служит только оболочкой для запуска (_carrierPreset). Валидатор этого не знал и краснел на CI.

Отвергнутая альтернатива, которая выглядела дешевле: научить тест узнавать носителя по обратной ссылке из MenuBattleConfig. Она отвечает раннеру и молчит человеку — а именно человек открывает ассет, видит пустые поля и идёт их «дозаполнять». Вторая отвергнутая — просто выдать носителю энкаунтер: тест бы позеленел, а ассет начал бы врать, потому что состав всё равно приезжает из конфига.

Грабли, и обе про «проверь, прежде чем действовать»:

  1. Первым побуждением было дозаполнить ассет. Остановило только то, что я пошла смотреть, кто на него ссылается: по имени menu_duel — никто, и по этому признаку он выглядел мёртвым. Живым его показал поиск по guidMenuBattleConfig. Правило «ноль ссылок ещё не мёртвое» сработало ровно так, как задумано, и сэкономило сломанную механику.
  2. Консоль редактора отдаёт ИСТОРИЮ. read_console показал две ошибки компиляции, я прочла их как текущее состояние и доложила, что дерево не собирается и работа заблокирована. На деле компиляция давно прошла, ошибки были прошлым, а проверить это стоило одной попытки записать поле в ассет. Состояние редактора проверяется ДЕЙСТВИЕМ или editor_state, а не свежестью строк в логе.

Владелец правды: Data/Definitions/BattlePresetData.cs (IsCarrier и <remarks> при нём), тесты ContentValidationTests.BattlePresets_Valid и ContentValidationTests.OnlyTheMenuCarrier_IsMarkedAsCarrier.