"""Матрица сценариев /recipes — id для привязки тестов и guard в ui_contract.""" from __future__ import annotations from dataclasses import dataclass from typing import List, Literal Layer = Literal["api", "dual", "e2e"] @dataclass(frozen=True) class RecipeScenario: id: str layer: Layer description: str SCENARIOS: List[RecipeScenario] = [ RecipeScenario("HAPPY_ONE_RECIPE_MOVE", "api", "move up/down одного рейса в периоде"), RecipeScenario("EDGE_EMPTY_PERIOD_TRANSFER", "api", "transfer в пустой период index 0"), RecipeScenario("EDGE_MAX_RECIPES_ORDER", "api", "много рейсов — move крайних позиций"), RecipeScenario("TRANSFER_ENQUEUE_SOURCE_DELETE", "api", "sync delete исходного period_recipes"), RecipeScenario("TRANSFER_REPEAT_A_B_A", "api", "повторный transfer A→B→A"), RecipeScenario("DUAL_UNLINK_BOTH_TERMINALS", "dual", "unlink period → A и B"), RecipeScenario("DUAL_TRANSFER_BOTH_TERMINALS", "dual", "transfer period → A и B"), RecipeScenario("DUAL_TRANSFER_THEN_REORDER", "dual", "transfer + reorder на B"), RecipeScenario("DUAL_OFFLINE_CATCHUP_TRANSFER", "dual", "B offline, transfer, догон"), RecipeScenario("DUAL_LATE_JOIN_AFTER_TRANSFER", "dual", "late join после transfer"), RecipeScenario("DUAL_REORDER_AND_NEW_GROUP", "dual", "reorder ингредиентов + новая группа → A и B"), RecipeScenario("DUAL_ADD_GROUP_UPDATES_EXISTING", "dual", "60/40 группы на peer, не 140%"), RecipeScenario("CALCULATE_FROM_DRY_MATTER", "api", "POST /api/recipes/calculate с calculateFromDryMatter"), RecipeScenario("SAVE_DRY_MATTER_LOCKED", "api", "сохранение рецепта с dry_matter_locked пересчитывает веса"), RecipeScenario("DUAL_PUSH_ROUNDTRIP", "dual", "terminal A push → server → B"), RecipeScenario("DUAL_CONCURRENT_RECIPE", "dual", "устаревший push не перезаписывает master"), RecipeScenario("DUAL_REPORTS_SYNC", "dual", "loading_report на обоих терминалах"), RecipeScenario("DUAL_OFFLINE_CATCHUP_GROUPS", "dual", "offline B догоняет reorder + группу"), RecipeScenario("E2E_DRAG_REORDER", "e2e", "DnD ручкой — порядок + API"), RecipeScenario("E2E_MOVE_RECIPE_UP", "e2e", "кнопка move-recipe-up меняет order"), RecipeScenario("E2E_REORDER_THEN_TRANSFER", "e2e", "reorder затем transfer"), RecipeScenario("E2E_TRANSFER_THEN_REORDER", "e2e", "transfer затем reorder на B"), RecipeScenario("E2E_TRANSFER_REPEAT", "e2e", "transfer A→B→A"), RecipeScenario("E2E_TRANSFER_ESCAPE", "e2e", "Escape отменяет transfer"), RecipeScenario("E2E_HEADS_RECALC", "e2e", "смена голов пересчитывает вес группы heads"), RecipeScenario("DUAL_E2E_DND_SYNC", "e2e", "DnD на A → sync → B видит order"), RecipeScenario("DUAL_E2E_TRANSFER_REORDER", "e2e", "transfer на A → sync → B видит рейс"), RecipeScenario("E2E_EDITOR_UNLOADING_GROUP", "e2e", "add/remove unloading group + save"), RecipeScenario("E2E_EDITOR_CANCEL", "e2e", "show-recipe-edit-off без save"), RecipeScenario("JOURNEY_MORNING_ROUTINE", "e2e", "полный еблан: save→reorder→copy→paste→unlink"), RecipeScenario("JOURNEY_TRANSFER_REPEAT_SLOTS", "e2e", "полный еблан: transfer со слотом A↔B"), RecipeScenario("JOURNEY_ESCAPE_REORDER_MIX", "e2e", "полный еблан: escape transfer → reorder"), RecipeScenario("JOURNEY_MILL_CREATE_DELETE", "e2e", "полный еблан: mill create/save/delete global"), RecipeScenario("JOURNEY_SETTINGS_LOGOUT", "e2e", "полный еблан: settings → logout"), RecipeScenario("JOURNEY_EMPTY_THEN_FULL", "e2e", "полный еблан: пустой period → create → delete all"), RecipeScenario("JOURNEY_MOBILE_FLIP", "e2e", "полный еблан: mobile шаги + back + кнопки reorder"), RecipeScenario("JOURNEY_EDITOR_CANCEL_REOPEN", "e2e", "полный еблан: cancel → другой рейс → save"), RecipeScenario("JOURNEY_MOVE_BUTTONS_YOYO", "e2e", "полный еблан: up/down спам кнопками"), RecipeScenario("JOURNEY_DOUBLE_COPY_PASTE", "e2e", "полный еблан: два paste одного copy в period B"), RecipeScenario("JOURNEY_MILL_DISPENSER_PINGPONG", "e2e", "полный еблан: mill↔dispenser переключения"), RecipeScenario("JOURNEY_DISTRACTED_UI", "e2e", "полный еблан: help/settings отвлечение → transfer"), RecipeScenario("JOURNEY_MEGA_MIX", "e2e", "полный еблан: мега-смесь всех операций подряд"), ] SCENARIO_IDS = [s.id for s in SCENARIOS]