Follow-up по #581 / эпик #584 (находка #3 из аудита).
Три копии _assemble_*_strategy_block собирают CustomPeriodBudget/ExplorationBudget по budget-type тремя слегка разными способами:
_assemble_dynamic_text_strategy_block (~88 строк, сырые параметры)
_assemble_smart_strategy_block (~111 строк, + flag_prefix/is_update)
_assemble_unified_strategy_block (~73 строки, уже рефакторена — принимает готовые dict-блоки)
Привести dynamic/smart к уже-рефакторенному паттерну _assemble_unified_strategy_block (общий _assemble_strategy_block с таблицей builder'ов; принимает собранные блоки, а не сырые параметры).
Инварианты: --dry-run payload и тексты ошибок байт-идентичны до/после для всех затронутых типов кампаний. Эталоны до/после. Гейты: test_dry_run.py, test_wsdl_parity_gate.py, test_cli_contract.py.
Follow-up по #581 / эпик #584 (находка #3 из аудита).
Три копии
_assemble_*_strategy_blockсобираютCustomPeriodBudget/ExplorationBudgetпо budget-type тремя слегка разными способами:_assemble_dynamic_text_strategy_block(~88 строк, сырые параметры)_assemble_smart_strategy_block(~111 строк, + flag_prefix/is_update)_assemble_unified_strategy_block(~73 строки, уже рефакторена — принимает готовые dict-блоки)Привести dynamic/smart к уже-рефакторенному паттерну
_assemble_unified_strategy_block(общий_assemble_strategy_blockс таблицей builder'ов; принимает собранные блоки, а не сырые параметры).Инварианты:
--dry-runpayload и тексты ошибок байт-идентичны до/после для всех затронутых типов кампаний. Эталоны до/после. Гейты:test_dry_run.py,test_wsdl_parity_gate.py,test_cli_contract.py.