Аудит дублирования (xhigh, 4 параллельных аудитора + ручная верификация чтением кода). _bidding_strategy.py — 5547 строк, второй по размеру файл проекта; здесь сосредоточен крупнейший пласт копипасты.
Находки
1. 4 копии _build_*_custom_period_budget (~95% идентичны)
_bidding_strategy.py:1381,3475,4435,5087 — _build_text_search_, _build_text_network_, _build_unified_network_, _build_unified_search_.
Сверил text-search (1381) и unified-search (5087) построчно: тела возврата, проверка missing, asserts идентичны. Отличия только в:
- префиксе флага (
--text-search- vs --unified-search-);
- слове в тексте ошибки (
TextCampaign vs UnifiedCampaign).
→ Одна функция _build_custom_period_budget(flag_prefix, campaign_label, spend_limit, start_date, end_date, auto_continue). Экономия ~120 строк, логика CustomPeriodBudget в одном месте.
2. 4 копии _build_*_exploration_budget — со СКРЫТЫМ поведенческим расхождением ⚠️
_bidding_strategy.py:1419,3511,4472,5126.
text-search требует is_custom == "YES" (строки 1446–1450, по public-docs constraint #388), а unified-search принимает и YES, и NO (строки 5156–5158, по cached WSDL). Это намеренная разница, но сейчас она «спрятана» в двух из четырёх почти одинаковых копий — при ручной правке одной копии легко занести регрессию.
→ Параметризовать (flag_prefix, label, exploration_yes_only: bool). Дубль уходит, а единственное реальное отличие становится явным аргументом.
3. 6 пар build_*_search_strategy / build_*_network_strategy (70–90% совпадения)
- text_campaign:
1747 ↔ 3540
- dynamic_text:
2417 ↔ 2134
- smart_campaign:
3057 ↔ 3958
- unified_campaign:
5225 ↔ 4574
- mobile_app:
775 ↔ 975
Каждая пара дублирует весь пайплайн: setup field_support dict, валидация detail-флагов, CPA-обработка, сборка budget-блоков. _TextStrategyConfig(NamedTuple) (1457) — уже начатый правильный путь, но применён только к TextCampaign.
→ Распространить config-объект (search/network как параметр) на остальные типы кампаний. Самый объёмный пласт файла.
4. 3 копии _assemble_*_strategy_block
_bidding_strategy.py:2046,2946,4501 (dynamic/smart/unified) — собирают CustomPeriodBudget/ExplorationBudget по budget-type тремя слегка разными способами. → Общий _assemble_strategy_block с таблицей builder'ов.
Не дефект (проверено)
Приёмка
Аудит дублирования (xhigh, 4 параллельных аудитора + ручная верификация чтением кода).
_bidding_strategy.py— 5547 строк, второй по размеру файл проекта; здесь сосредоточен крупнейший пласт копипасты.Находки
1. 4 копии
_build_*_custom_period_budget(~95% идентичны)_bidding_strategy.py:1381,3475,4435,5087—_build_text_search_,_build_text_network_,_build_unified_network_,_build_unified_search_.Сверил text-search (1381) и unified-search (5087) построчно: тела возврата, проверка
missing, asserts идентичны. Отличия только в:--text-search-vs--unified-search-);TextCampaignvsUnifiedCampaign).→ Одна функция
_build_custom_period_budget(flag_prefix, campaign_label, spend_limit, start_date, end_date, auto_continue). Экономия ~120 строк, логика CustomPeriodBudget в одном месте.2. 4 копии⚠️
_build_*_exploration_budget— со СКРЫТЫМ поведенческим расхождением_bidding_strategy.py:1419,3511,4472,5126.text-search требует
is_custom == "YES"(строки 1446–1450, по public-docs constraint #388), а unified-search принимает и YES, и NO (строки 5156–5158, по cached WSDL). Это намеренная разница, но сейчас она «спрятана» в двух из четырёх почти одинаковых копий — при ручной правке одной копии легко занести регрессию.→ Параметризовать
(flag_prefix, label, exploration_yes_only: bool). Дубль уходит, а единственное реальное отличие становится явным аргументом.3. 6 пар
build_*_search_strategy/build_*_network_strategy(70–90% совпадения)1747↔35402417↔21343057↔39585225↔4574775↔975Каждая пара дублирует весь пайплайн: setup
field_supportdict, валидация detail-флагов, CPA-обработка, сборка budget-блоков._TextStrategyConfig(NamedTuple)(1457) — уже начатый правильный путь, но применён только к TextCampaign.→ Распространить config-объект (search/network как параметр) на остальные типы кампаний. Самый объёмный пласт файла.
4. 3 копии
_assemble_*_strategy_block_bidding_strategy.py:2046,2946,4501(dynamic/smart/unified) — собираютCustomPeriodBudget/ExplorationBudgetпо budget-type тремя слегка разными способами. → Общий_assemble_strategy_blockс таблицей builder'ов.Не дефект (проверено)
CAMPAIGN_TYPE_BUILDERSреестр — это намеренная точка расширения для leaf-PR (campaigns bidding strategies: TextCampaign search branch #361–369), а не «недозаполненный» дубль (см. docstring модуля).Приёмка
pytestзелёный (особенноtest_dry_run.py,test_wsdl_parity_gate.py).--dry-runпаритет: payload идентичен до/после для всех затронутых типов кампаний.