# Opus Questions + Answers — 2026-07-31 ## A. Единый executor (operations/executor.py) **A1. Граница executor: до /run включительно, без поллинга.** Executor делает все шаги: POST /instances → POST /instanceOperations → send_params_terraform → /run. Возвращает `{instance_uid, op_uid, display_name}`. Поллинг — забота вызывающего (api_test.py: async thread, scenario.py: sync while). **A2. Ошибки: dict `{ok, error, failed_step}`.** Не исключения. `failed_step` = "instances" | "instanceOperations" | "params" | "run". Оба вызывающих конвертируют в свой формат (jsonify / RuntimeError). **A3. Трекер: да, вызывать tracker_add внутри executor для всех create.** Сценарные инстансы — такие же реальные инстансы в облаке, должны быть в трекере. Единообразие. **A4. _finish_op: оставить в api_test.py.** Но вынести цикл поллинга в общий хелпер `poll_until_done(client, op_uid, timeout=1800)` в `operations/poll.py`, который используют и _finish_op (async), и run_scenario (sync). ## B. Гибкие ссылки на инстансы **B5. Приоритет: да. instance_uid > instance_ref > новый create.** **B6. Хранение output→uid: и в памяти, и в БД.** В памяти — словарь для быстрого резолвинга во время выполнения. В БД — `scenario_runs.instance_bindings` обновляется после каждого create-шага. При падении воркера видно что создалось. Но runner не зависит от БД для резолвинга (только память). **B7. Валидация: да на всё.** `_validate_steps()` проверяет: (a) instance_ref ссылается на output из предыдущих шагов, (b) output уникален в пределах сценария, (c) для не-create шага обязателен один из instance_ref/instance_uid. **B8. Обратная совместимость: поддерживать оба формата, без миграции.** Если шаг без output/instance_ref/instance_uid → fallback на старый instance_map[service_id]. Seed dummy_test работает как есть. Новые сценарии используют новый формат. ## C. Схема БД **C9. Да, без изменений схемы.** Только новые опциональные ключи в JSONB-объектах шагов. **C10. Да, использовать instance_bindings.** После create: `bindings[output_name] = instance_uid`. Сохранять в БД после каждого шага. ## D. UI редактора сценариев **D11. Модальное окно на весь экран.** Параметры с dataDescriptor (map-fixed) — много вложенных полей, inline в scenario-body слишком тесно. **D12. Да, вынести рендер параметров в общий модуль.** `static/js/params-render.js`: `renderParamRow()`, `renderMapFixedRow()`, `collectParams()`. Используется и в operations.js, и в scenario-form.js. **D13. Pre-fill: авто при смене операции.** Показывать ВСЕ параметры с defaults, пользователь удаляет лишние или меняет значения. Кнопка «Сбросить на defaults». **D14. Символические имена в БД.** `{"durationMs": "5000"}` — человекочитаемо, стабильно. Резолвинг в numeric ID — в runtime. ## E. Оптимизация **E15. Да, вынести в `api/utils.py`.** Обе реализации (_find_uid, _uid_from_location) унифицировать. **E16. Да, startup check.** При старте: `UPDATE scenario_runs SET status='TIMEOUT', error_log='worker restart' WHERE status='RUNNING' AND created_at < NOW() - INTERVAL '1 hour'`. Просто, без доп. инфраструктуры. **E17. Оставить lock_check.** Один сценарий за раз — безопасно. Можно ослабить позже. **E18. Не в scope.** fallback на API работает, потеря stages — minor. Отдельная задача. **E19. Порядок: бэкенд → UI.** 1. `operations/executor.py` + `operations/poll.py` + `api/utils.py` 2. Формат шагов (output/instance_ref) + валидация + резолвинг 3. Минимальные правки api_test.py и scenario.py (вызов executor) 4. UI редактор (модал + общий рендер параметров)