{
  "version": "1.0.0",
  "taskId": "TASK-PRIME-006",
  "date": "2026-09-27",
  "start": "O00",
  "status": "contract-and-memory-only-explorer",
  "roles": [
    {
      "id": "owner",
      "name": "Владелец",
      "scope": "Организация и филиалы; найм, доступ, политики, финансы. Только подтверждённое владение."
    },
    {
      "id": "barber",
      "name": "Барбер",
      "scope": "Свои смены и назначенные визиты; доступ к пожеланиям и фото только в рабочем контексте."
    },
    {
      "id": "guest",
      "name": "Гость",
      "scope": "Анонимный просмотр, поиск, локальный черновик; без чужих визитов, токенов карт и staff API."
    },
    {
      "id": "client",
      "name": "Клиент",
      "scope": "Свои записи, способы оплаты, согласия, паспорт и клуб. Не получает staff-права через вход."
    }
  ],
  "phases": [
    "Настройка",
    "Команда",
    "Выбор",
    "Запись и оплата",
    "До визита",
    "Визит",
    "Результат и расчёт",
    "После визита",
    "Управление",
    "Повтор"
  ],
  "nodes": [
    {
      "id": "O00",
      "title": "Подтвердить владение",
      "role": "owner",
      "phase": 0,
      "layer": "front",
      "domain": "operations",
      "frontend": "Войти и подтвердить право управлять PRIME.",
      "backend": "Проверить предварительно выданное право создания организации или существующий owner grant и step-up. Публичный OAuth не выдаёт роль owner.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-01"
      ],
      "commandIds": [
        "CMD-ORG"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O01",
      "title": "Создать организацию",
      "role": "owner",
      "phase": 0,
      "layer": "back",
      "domain": "operations",
      "frontend": "Показать черновик организации и ответственного.",
      "backend": "Создать organization с owner membership в транзакции; аудит, unique legal identity после проверки.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-01"
      ],
      "commandIds": [
        "CMD-ORG"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O02",
      "title": "Настроить филиал",
      "role": "owner",
      "phase": 0,
      "layer": "front",
      "domain": "operations",
      "frontend": "Адрес, часовой пояс, часы, кресла и контакты.",
      "backend": "Версионировать Branch и Resource; проверить зоны и интервалы, не переносить hosts МАУ.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-BRANCH"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O03",
      "title": "Услуги и длительность",
      "role": "owner",
      "phase": 0,
      "layer": "front",
      "domain": "operations",
      "frontend": "Услуги, навыки, длительность, перерывы, цена.",
      "backend": "ServiceVersion: integer minor units/RUB, skill requirements, equipment, duration и buffer.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-CATALOG"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O04",
      "title": "Правила сервиса",
      "role": "owner",
      "phase": 0,
      "layer": "front",
      "domain": "operations",
      "frontend": "Предоплата, отмена, опоздание, возврат, клуб — с явным статусом решения.",
      "backend": "PolicyVersion; ничего не удерживать по неутверждённым правилам. Снимок условий в каждом заказе.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-03"
      ],
      "commandIds": [
        "CMD-POLICY"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O05",
      "title": "Подключить ЮKassa",
      "role": "owner",
      "phase": 0,
      "layer": "back",
      "domain": "operations",
      "frontend": "Статус тестового/боевого магазина и фискализации.",
      "backend": "Секреты только серверу; shopId, webhook, сверка, способ выдачи чека. Sandbox smoke до включения продаж.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-11"
      ],
      "commandIds": [
        "CMD-MERCHANT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O06",
      "title": "Открыть набор барберов",
      "role": "owner",
      "phase": 1,
      "layer": "front",
      "domain": "operations",
      "frontend": "Описать навыки, загрузку, условия и этапы отбора.",
      "backend": "Vacancy/candidate consent; не публиковать персональные данные кандидата в клиентский каталог.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-HIRING"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O07",
      "title": "Рассмотреть кандидата",
      "role": "owner",
      "phase": 1,
      "layer": "front",
      "domain": "operations",
      "frontend": "Портфолио, интервью, доступность; согласовать пробную смену.",
      "backend": "RecruitmentCase с ограниченным доступом; отклонение и retention отдельно от клиентского аккаунта.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-CANDIDATE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O08",
      "title": "Пробная смена",
      "role": "owner",
      "phase": 1,
      "layer": "front",
      "domain": "operations",
      "frontend": "Оценить навыки и дать обратную связь.",
      "backend": "Trial shift не даёт доступа к всей базе; отметка результата и решение владельца.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-CANDIDATE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O09",
      "title": "Предложить условия",
      "role": "owner",
      "phase": 1,
      "layer": "front",
      "domain": "operations",
      "frontend": "Ставка/процент, услуги, филиал, права и дата старта.",
      "backend": "Versioned offer; модель занятости и расчётов требует утверждения, принятие фиксируется отдельно.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-02"
      ],
      "commandIds": [
        "CMD-CANDIDATE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O10",
      "title": "Пригласить в команду",
      "role": "owner",
      "phase": 1,
      "layer": "back",
      "domain": "operations",
      "frontend": "Показать одноразовое приглашение и его срок.",
      "backend": "Хеш invite-token, expiry, intended scope; доставка после согласия получателя, повтор инвалидирует старый token.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-INVITE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O11",
      "title": "Отказ в найме",
      "role": "owner",
      "phase": 1,
      "layer": "front",
      "domain": "operations",
      "frontend": "Закрыть кандидатуру с корректной обратной связью.",
      "backend": "Закрыть case, отозвать trial-доступ, применить retention; не создавать membership.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-CANDIDATE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O12",
      "title": "Опубликовать запись",
      "role": "owner",
      "phase": 2,
      "layer": "back",
      "domain": "operations",
      "frontend": "Проверить готовность мастеров, цен и расписания.",
      "backend": "Открыть каталог только при active staff, shifts, policies и выбранном режиме оплаты; outbox catalog.published.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PUBLISH"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O13",
      "title": "Операционный день",
      "role": "owner",
      "phase": 5,
      "layer": "front",
      "domain": "operations",
      "frontend": "Нагрузка, исключения, обращения, незакрытые оплаты.",
      "backend": "Read model по филиалу; только разрешённые персональные данные. Нет подмены банковского статуса.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-OPERATIONS"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O14",
      "title": "Смены и отпуска",
      "role": "owner",
      "phase": 2,
      "layer": "front",
      "domain": "operations",
      "frontend": "Одобрить график, отпуск, замену, блокировку кресла.",
      "backend": "Revision + resource constraints; изменение смены не удаляет существующие записи.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SHIFT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O15",
      "title": "Мастер недоступен",
      "role": "owner",
      "phase": 4,
      "layer": "back",
      "domain": "operations",
      "frontend": "Показать затронутые визиты и варианты замены.",
      "backend": "Freeze affected slots; incident batch с индивидуальным решением по каждому booking, дедупликация сообщений.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-REASSIGN"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O16",
      "title": "Согласовать замену",
      "role": "owner",
      "phase": 4,
      "layer": "front",
      "domain": "operations",
      "frontend": "Предложить другого барбера/время или отмену.",
      "backend": "Никакой тихой замены: consent клиента, новая quote при изменении цены, transfer booking атомарно.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-REASSIGN"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O17",
      "title": "Уволить или приостановить",
      "role": "owner",
      "phase": 8,
      "layer": "front",
      "domain": "operations",
      "frontend": "Дата окончания, будущие визиты, расчёт и отзыв прав.",
      "backend": "Membership.revoking; закрыть новые слоты, подготовить перенос, revoke sessions, сохранить audit.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-16"
      ],
      "commandIds": [
        "CMD-OFFBOARD"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O18",
      "title": "Доступ сотрудника отозван",
      "role": "owner",
      "phase": 8,
      "layer": "back",
      "domain": "operations",
      "frontend": "Показать завершённую процедуру и оставшиеся обязательства.",
      "backend": "Отмена membership немедленно на API; общие паспорта остаются у клиента, staff media cache истекает.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-OFFBOARD"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O19",
      "title": "Закрытие филиала / авария",
      "role": "owner",
      "phase": 4,
      "layer": "front",
      "domain": "operations",
      "frontend": "Отключение воды, света, оборудования, погода: приостановить запись.",
      "backend": "Branch incident; затронутые визиты → предложение/возврат, запрет новых hold, владельцу список незавершённых компенсаций.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-16"
      ],
      "commandIds": [
        "CMD-BRANCH"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O20",
      "title": "Разобрать претензию",
      "role": "owner",
      "phase": 7,
      "layer": "front",
      "domain": "operations",
      "frontend": "Услышать клиента, предложить исправление/возврат/объяснение.",
      "backend": "Case, факты и сроки; не стирать отзыв за компенсацию, решение с audit и независимым возвратом.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-CASE-RESOLVE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O21",
      "title": "Расчёт с барбером",
      "role": "owner",
      "phase": 8,
      "layer": "front",
      "domain": "operations",
      "frontend": "Выручка, возвраты, чаевые отдельно, начисление по версии договора.",
      "backend": "Payroll ledger и период; ЮKassa merchant settlement не является зарплатой. Выплата отдельным подтверждённым каналом.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-02"
      ],
      "commandIds": [
        "CMD-PAYROLL"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O22",
      "title": "Сверка выручки",
      "role": "owner",
      "phase": 8,
      "layer": "back",
      "domain": "operations",
      "frontend": "Платежи, касса, возвраты, чеки и банковские поступления раздельно.",
      "backend": "Reconciliation job; сумма заказа ≠ выручка после возвратов ≠ merchant settlement; расхождение → case.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-11"
      ],
      "commandIds": [
        "CMD-RECONCILE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O23",
      "title": "Отчёт и новые решения",
      "role": "owner",
      "phase": 9,
      "layer": "front",
      "domain": "operations",
      "frontend": "Конверсия, загрузка, повторы, отмены, качество без рейтинговой гонки.",
      "backend": "Агрегаты из событий, исключить технические дубли, cohort attribution; новые правила только следующей версией.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-OPERATIONS"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "O24",
      "title": "Передача владения",
      "role": "owner",
      "phase": 8,
      "layer": "front",
      "domain": "operations",
      "frontend": "Усиленная проверка обеих сторон и подтверждение передачи.",
      "backend": "Не оставлять организацию без владельца; атомарная замена grant, аудит, отзыв старых полномочий.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-01",
        "POL-16"
      ],
      "commandIds": [
        "CMD-TRANSFER"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B00",
      "title": "Получить приглашение",
      "role": "barber",
      "phase": 1,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Увидеть PRIME, филиал, автора и условия.",
      "backend": "GET invite проверяет hash/expiry/revoked; не раскрывать чужие данные до аутентификации.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-INVITE-ACCEPT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B01",
      "title": "Приглашение истекло",
      "role": "barber",
      "phase": 1,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Запросить новое или отказаться.",
      "backend": "Не восстанавливать старый token; только владелец выдаёт новую версию.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-INVITE-ACCEPT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B02",
      "title": "Войти как приглашённый",
      "role": "barber",
      "phase": 1,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Подтвердить свою идентичность, затем прочитать условия.",
      "backend": "Связать invitation с verified identity; membership ещё pending, claim не принимает role из клиента.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-INVITE-ACCEPT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B03",
      "title": "Принять приглашение",
      "role": "barber",
      "phase": 1,
      "layer": "back",
      "domain": "workforce",
      "frontend": "Подтвердить конкретную версию условий.",
      "backend": "Одноразовый claim в транзакции, membership onboarding, аудит и уведомление владельцу.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-INVITE-ACCEPT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B04",
      "title": "Пройти вводный этап",
      "role": "barber",
      "phase": 1,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Профиль, навыки, правила фото, расписание и подтверждение готовности.",
      "backend": "Минимальные права; owner подтверждает навыки и старт, клиентский профиль скрыт до публикации.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-ONBOARD"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B05",
      "title": "Готов к записи",
      "role": "barber",
      "phase": 2,
      "layer": "back",
      "domain": "workforce",
      "frontend": "Проверить публичный профиль и смену.",
      "backend": "Active membership + approved skills + published shift; availability пересчитывается.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-ONBOARD"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B06",
      "title": "Открыть свой день",
      "role": "barber",
      "phase": 5,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Предстоящие визиты, перерывы, свободные окна, незакрытые задачи.",
      "backend": "Scoped read model; server now и timezone филиала, запрет чужого расписания вне scope.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-DAY"
      ],
      "screenIds": [
        "SCR-018"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B07",
      "title": "Попросить отпуск",
      "role": "barber",
      "phase": 2,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Выбрать даты и предложить смену.",
      "backend": "LeaveRequest; до решения владельца существующие записи сохранены, новые временно ограничиваются политикой.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SHIFT-REQUEST"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B08",
      "title": "Сообщить о болезни",
      "role": "barber",
      "phase": 4,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Одним действием сообщить недоступность без диагноза.",
      "backend": "Absence incident + blocked availability; минимизация данных о здоровье, owner получает очередь замен.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-ABSENCE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": [
        "болезнь",
        "заболел",
        "болею"
      ]
    },
    {
      "id": "B09",
      "title": "Сообщить об опоздании",
      "role": "barber",
      "phase": 4,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Ожидаемое прибытие и затронутые визиты.",
      "backend": "Recompute delay impact; клиенты получают выбор, никаких молчаливых сдвигов всего дня.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-06"
      ],
      "commandIds": [
        "CMD-ABSENCE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": [
        "опоздание",
        "опоздал",
        "задержка"
      ]
    },
    {
      "id": "B10",
      "title": "Карточка клиента",
      "role": "barber",
      "phase": 5,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Пожелания, разрешённый паспорт, ограничения и время.",
      "backend": "Проверить assignment и consent на каждый media URL; audit доступа, signed URL ограничен временем.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-DAY"
      ],
      "screenIds": [
        "SCR-019"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B11",
      "title": "Отметить прибытие",
      "role": "barber",
      "phase": 5,
      "layer": "back",
      "domain": "workforce",
      "frontend": "Сверить клиента и услугу, отметить check-in.",
      "backend": "Booking confirmed → arrived; серверная отметка, повтор check-in идемпотентен.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-ARRIVE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B12",
      "title": "Согласовать результат",
      "role": "barber",
      "phase": 5,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Обсудить форму, тишину, чувствительность и цену до начала.",
      "backend": "Consultation snapshot; consent на изменение состава и цены, фото отдельным согласием.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SCOPE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B13",
      "title": "Начать работу",
      "role": "barber",
      "phase": 5,
      "layer": "back",
      "domain": "workforce",
      "frontend": "Показать активный визит, время и согласованные услуги.",
      "backend": "arrived → in_service, assignment/version guard; запрет параллельных визитов одного кресла.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SERVICE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B14",
      "title": "Нужно больше времени",
      "role": "barber",
      "phase": 5,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Запросить дополнение, цену и длительность.",
      "backend": "Проверить следующий booking и ресурсы; approve клиента; при конфликте сократить согласованный scope или отдельный визит.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SCOPE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B15",
      "title": "Прервать услугу",
      "role": "barber",
      "phase": 5,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Зафиксировать причину, оказанную часть и помощь.",
      "backend": "Service incident; безопасность, стоимость только фактически согласованного; спор/возврат в отдельном case.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SERVICE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B16",
      "title": "Показать результат",
      "role": "barber",
      "phase": 6,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Сверить ожидания; можно поправить сразу.",
      "backend": "Result reviewed клиентом; фото не обязательны для закрытия услуги.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B17",
      "title": "Записать Cut Passport",
      "role": "barber",
      "phase": 6,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Параметры, продукт, совет, фото при согласии.",
      "backend": "Passport revision, author, visitId; клиент владеет приватностью. Публикация портфолио отдельным разрешением.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PASSPORT"
      ],
      "screenIds": [
        "SCR-020"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B18",
      "title": "Закончить услугу",
      "role": "barber",
      "phase": 6,
      "layer": "back",
      "domain": "workforce",
      "frontend": "Отдельно показать готовность результата и статус оплаты.",
      "backend": "in_service → service_completed; не помечать paid автоматически, invoice balance проверяется отдельно.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SERVICE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B19",
      "title": "Закрыть свою смену",
      "role": "barber",
      "phase": 8,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Проверить незавершённые паспорта, визиты и оборудование.",
      "backend": "Shift close допускает явную передачу unresolved cases владельцу; аудит, часы и перерывы.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SHIFT-CLOSE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B20",
      "title": "Проверить начисление",
      "role": "barber",
      "phase": 8,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Свои услуги, возвраты, чаевые и расчёт периода.",
      "backend": "Scoped earnings view; acknowledge либо dispute, staff не видит чужие начисления.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-02"
      ],
      "commandIds": [
        "CMD-EARNINGS"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B21",
      "title": "Отказаться от условий",
      "role": "barber",
      "phase": 1,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Отклонить предложение или обсудить новую версию.",
      "backend": "Decline invite/offer; доступ не активируется, будущая версия требует нового принятия.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-INVITE-ACCEPT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B22",
      "title": "Уйти из команды",
      "role": "barber",
      "phase": 8,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Сообщить дату и передать будущие визиты.",
      "backend": "Exit request не удаляет историю и не забирает клиентские фото; owner завершает offboarding.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SHIFT-REQUEST"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "B23",
      "title": "Клиент ведёт себя опасно",
      "role": "barber",
      "phase": 5,
      "layer": "front",
      "domain": "workforce",
      "frontend": "Остановить визит и позвать владельца; экстренная помощь вне приложения.",
      "backend": "Safety case с ограниченным доступом, остановка услуги; санкции только после review и возможности обращения.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-INCIDENT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G00",
      "title": "Открыть PRIME",
      "role": "guest",
      "phase": 2,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Посмотреть концепцию, филиал и цены без регистрации.",
      "backend": "Публичный каталог без PII, rate limits; аналитика без присвоения клиентской личности.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PUBLIC-CATALOG"
      ],
      "screenIds": [
        "SCR-001"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G01",
      "title": "Выбрать образ",
      "role": "guest",
      "phase": 2,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Смотреть разрешённое портфолио и сохранять локальный интерес.",
      "backend": "Показывать только опубликованные работы с действующим consent, фильтры услуги/длины.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PUBLIC-CATALOG"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G02",
      "title": "Выбрать мастера",
      "role": "guest",
      "phase": 2,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Навыки, работы и ближайшее окно; без выдуманных отзывов.",
      "backend": "Публичная версия профиля, только active membership и service skills.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PUBLIC-CATALOG"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G03",
      "title": "Найти время",
      "role": "guest",
      "phase": 2,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Первый свободный или любимый мастер, другой день/филиал.",
      "backend": "Availability read — подсказка, не бронь; timezone филиала, revision и validUntil.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-AVAILABILITY"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G04",
      "title": "Выбрать филиал",
      "role": "guest",
      "phase": 2,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Адрес, доступность входа, карта и часы.",
      "backend": "Branch active; геолокация необязательна, адрес доступен текстом.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PUBLIC-CATALOG"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G05",
      "title": "Собрать черновик",
      "role": "guest",
      "phase": 3,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Услуги, мастер, время и ориентировочная сумма.",
      "backend": "Локальный draft без реального hold; цена проверяется сервером перед подтверждением.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G06",
      "title": "Продолжить с аккаунтом",
      "role": "guest",
      "phase": 3,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Объяснить, зачем вход для управления визитом, сохранить черновик.",
      "backend": "Сохранить scoped continuation, без role escalation и без доверия старой цене/слоту.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G07",
      "title": "Уйти без записи",
      "role": "guest",
      "phase": 9,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Закрыть сценарий без рассылок и скрытого заказа.",
      "backend": "Никаких payment/booking effects; локальный draft удаляется по политике.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": true,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G08",
      "title": "Связаться с филиалом",
      "role": "guest",
      "phase": 3,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Телефон, маршрут, часы; помощь без аккаунта.",
      "backend": "Контакт филиала из актуального каталога, не обещать состоявшийся звонок.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PUBLIC-CATALOG"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G09",
      "title": "Прийти без записи",
      "role": "guest",
      "phase": 5,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Уточнить наличие окна на месте.",
      "backend": "Walk-in оформляет сотрудник с проверкой ресурса и согласием; не блокировать обслуживание отсутствием приложения.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-AVAILABILITY"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G10",
      "title": "Получить приглашение в клуб",
      "role": "guest",
      "phase": 2,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Условия гостевого визита, срок и отправитель.",
      "backend": "GuestPass token без раскрытия истории дарителя; согласие получателя обязательно.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-12"
      ],
      "commandIds": [
        "CMD-GUEST-PASS"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "G11",
      "title": "Вернуться по ссылке",
      "role": "guest",
      "phase": 2,
      "layer": "front",
      "domain": "discovery",
      "frontend": "Восстановить публичный путь; просроченная ссылка объяснена.",
      "backend": "Allowlisted deep link, проверить объект и срок; чужие/private данные только после auth.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A00",
      "title": "Выбрать способ входа",
      "role": "guest",
      "phase": 3,
      "layer": "front",
      "domain": "identity",
      "frontend": "Telegram, Яндекс; MAX при готовом канале. Отказ не удаляет черновик.",
      "backend": "AuthTransaction с state/expiry/continuation. Ни один provider не задаёт роль сотрудника.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-14"
      ],
      "commandIds": [
        "CMD-AUTH"
      ],
      "screenIds": [
        "SCR-002"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A01",
      "title": "Войти через Telegram",
      "role": "guest",
      "phase": 3,
      "layer": "front",
      "domain": "identity",
      "frontend": "Открыть системный браузер или проверенный native flow.",
      "backend": "OIDC authorization code + PKCE S256; client secret только backend, проверить iss/aud/exp/signature и привязку state.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-14"
      ],
      "commandIds": [
        "CMD-AUTH-CALLBACK"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A02",
      "title": "Войти через Яндекс",
      "role": "guest",
      "phase": 3,
      "layer": "front",
      "domain": "identity",
      "frontend": "Запросить минимальный набор данных.",
      "backend": "Authorization code + PKCE S256, state и точный redirect URI; server exchange и user identity API.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-14"
      ],
      "commandIds": [
        "CMD-AUTH-CALLBACK"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A03",
      "title": "Подтвердиться через MAX",
      "role": "guest",
      "phase": 3,
      "layer": "front",
      "domain": "identity",
      "frontend": "Открыть mini-app, подтвердить связку, вернуться в PRIME.",
      "backend": "Условный адаптер: проверить initData HMAC/auth_date и одноразовый challenge; standalone OIDC не предполагается. Feature gate до end-to-end spike.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-14"
      ],
      "commandIds": [
        "CMD-AUTH-CALLBACK"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A04",
      "title": "Проверить ответ провайдера",
      "role": "guest",
      "phase": 3,
      "layer": "back",
      "domain": "identity",
      "frontend": "Ожидать завершения, не показывать вход раньше сервера.",
      "backend": "Consume state один раз, токены на сервере/защищённом хранилище; stale/replay/issuer mismatch отвергнуть.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-AUTH",
        "CMD-AUTH-CALLBACK"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A05",
      "title": "Вход отменён или недоступен",
      "role": "guest",
      "phase": 3,
      "layer": "front",
      "domain": "identity",
      "frontend": "Повторить, выбрать другой способ или продолжить гостем.",
      "backend": "Закрыть AuthTransaction, не создавать пустой дубликат аккаунта.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A06",
      "title": "Завершить профиль",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "identity",
      "frontend": "Имя и доступный подтверждённый контакт; условия и маркетинг отдельно.",
      "backend": "Account по provider+subject; обязательные условия versioned, promo consent optional и по каналам.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PROFILE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A07",
      "title": "Аккаунт готов",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "identity",
      "frontend": "Вернуться к сохранённой цели и показать доступные роли.",
      "backend": "Server session; переоценить draft, quote, slot. Membership проверяется отдельно от client identity.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SESSION"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A08",
      "title": "Связать второй вход",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "identity",
      "frontend": "Повторно подтвердить текущий аккаунт и новый provider.",
      "backend": "Two-sided proof; unique provider subject. Email/телефон по совпадению не повод автоматически объединять аккаунты.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-IDENTITY-LINK"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A09",
      "title": "Обнаружен другой аккаунт",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "identity",
      "frontend": "Объяснить коллизию; безопасное восстановление без потери визитов.",
      "backend": "Не объединять по PII; controlled recovery case и доказательство владения обеими identities.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-IDENTITY-LINK"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A10",
      "title": "Восстановить доступ",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "identity",
      "frontend": "Другой связанный вход или обращение; сохранить request ID.",
      "backend": "Rate limit, recovery audit, проверка владения; саппорт не просит CVV/пароль мессенджера.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-RECOVERY"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A11",
      "title": "Сменить роль",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "identity",
      "frontend": "Выбрать один из разрешённых рабочих контекстов.",
      "backend": "Server проверяет active membership при каждом запросе; client/barber/owner могут принадлежать одному person.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-01"
      ],
      "commandIds": [
        "CMD-SESSION"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A12",
      "title": "Выйти со всех устройств",
      "role": "client",
      "phase": 8,
      "layer": "back",
      "domain": "identity",
      "frontend": "Подтвердить завершение сессий.",
      "backend": "Revoke refresh sessions, очистить sensitive cache; оплаченные визиты и компенсации продолжаются на сервере.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-LOGOUT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "A13",
      "title": "Нет доступа",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "identity",
      "frontend": "Объяснить отзыв роли, показать допустимый аккаунт и помощь.",
      "backend": "403 без чужих данных, токен не заменяет active grant; audit access denial.",
      "sourceIds": [
        "OWNER-BRIEF",
        "TG-LOGIN",
        "YANDEX-ID",
        "MAX-VALIDATION"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-01"
      ],
      "commandIds": [
        "CMD-SESSION"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C00",
      "title": "Главная клиента",
      "role": "client",
      "phase": 2,
      "layer": "front",
      "domain": "booking",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SESSION"
      ],
      "screenIds": [
        "SCR-003"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C01",
      "title": "Выбрать новый образ",
      "role": "client",
      "phase": 2,
      "layer": "front",
      "domain": "booking",
      "frontend": "Портфолио, вариант следующей формы и пожелания.",
      "backend": "Style reference связан с доступными услугами, не обещать гарантированный результат по фото.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PUBLIC-CATALOG"
      ],
      "screenIds": [
        "SCR-011"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C02",
      "title": "Выбрать барбера",
      "role": "client",
      "phase": 2,
      "layer": "front",
      "domain": "booking",
      "frontend": "Навыки, ближайшее время или первый свободный.",
      "backend": "Service skills, branch, active membership; retired stylist → альтернативы без автоматической замены.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PUBLIC-CATALOG"
      ],
      "screenIds": [
        "SCR-005"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C03",
      "title": "Собрать услуги",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "booking",
      "frontend": "Длительность и сумма меняются вместе; дополнительные пожелания.",
      "backend": "Server quote по ServiceVersion, скидки/клуб валидируются сервером; zero/negative duration запрещены.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PUBLIC-CATALOG"
      ],
      "screenIds": [
        "SCR-004"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C04",
      "title": "Выбрать окно",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "booking",
      "frontend": "Умные слоты, другой день/филиал, лист ожидания.",
      "backend": "Availability с креслом, навыком, сменой, буфером и существующими hold; время сервера.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-AVAILABILITY"
      ],
      "screenIds": [
        "SCR-006"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C05",
      "title": "Повторить прошлый образ",
      "role": "client",
      "phase": 2,
      "layer": "front",
      "domain": "booking",
      "frontend": "Открыть прошлый паспорт и уточнить изменения.",
      "backend": "Reference to passport version; проверить доступность мастера, актуальные услуги и цену, не копировать старую оплату.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PASSPORT-READ"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C06",
      "title": "Получить расчёт",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "booking",
      "frontend": "Показать полную цену, предоплату/оплату на месте и правила.",
      "backend": "Immutable Quote: price/duration/policyVersion/currency/expiresAt; stale quote требует нового подтверждения.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-03"
      ],
      "commandIds": [
        "CMD-QUOTE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C07",
      "title": "Временно удержать слот",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "booking",
      "frontend": "Показать оставшееся время; не объявлять бронь окончательной.",
      "backend": "Atomic hold с уникальным ресурсным интервалом, TTL, revision; срок не продлевается бесконечно.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-04"
      ],
      "commandIds": [
        "CMD-HOLD"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C08",
      "title": "Слот уже занят",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "booking",
      "frontend": "Сохранить услуги и предложить соседние окна.",
      "backend": "409 conflict → свежая availability; не создавать второй charge и не удалять существующий визит.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-AVAILABILITY"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C09",
      "title": "Проверить визит",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "booking",
      "frontend": "Мастер, филиал, дата, цена, контакт, условия и способ оплаты.",
      "backend": "Guard quote/hold/policy/consent/contact; business command только после явного подтверждения.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [
        "SCR-007"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C10",
      "title": "Подтвердить запись",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "booking",
      "frontend": "Показать один pending запрос и его статус.",
      "backend": "Idempotent BookingSaga; validate hold/revision/payment policy. Деньги и слот — отдельные агрегаты.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-BOOK"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C11",
      "title": "Результат неизвестен",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "booking",
      "frontend": "Не нажимать повторную оплату; показать сверку и request ID.",
      "backend": "GET operation by id, bounded reconciliation, ни failure ни success не выводятся из timeout.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C12",
      "title": "Визит подтверждён",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "booking",
      "frontend": "Подтверждённый booking ID, адрес, календарь, подготовка.",
      "backend": "Только authoritative confirmed; outbox reminders; оплачено/к оплате показывается отдельно.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [
        "SCR-008"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C13",
      "title": "Лист ожидания",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "booking",
      "frontend": "Дни, мастер, диапазон времени, допустимый контакт и срок.",
      "backend": "Waitlist request с expiry/consent; без удержания средств и без гарантии места.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-08"
      ],
      "commandIds": [
        "CMD-WAITLIST"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C14",
      "title": "Предложено окно",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "booking",
      "frontend": "Принять до указанного срока или отказаться.",
      "backend": "Временное предложение одному кандидату или атомарный first-claim; offer ≠ confirmed booking.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-08"
      ],
      "commandIds": [
        "CMD-AVAILABILITY",
        "CMD-WAITLIST-OFFER",
        "CMD-WAITLIST-CLAIM"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C15",
      "title": "Предложение истекло",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "booking",
      "frontend": "Остаться в листе, изменить пожелания или выйти.",
      "backend": "Release offer/hold once; fairness и dedupe, не слать одно окно бесконечно.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-08"
      ],
      "commandIds": [
        "CMD-AVAILABILITY",
        "CMD-WAITLIST-OFFER"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C16",
      "title": "Передумать до записи",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "booking",
      "frontend": "Вернуться или закрыть; показать реальные незавершённые операции.",
      "backend": "Если платежа нет — release hold; если payment pending — отмена intent + reconcile, не забывать платеж.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-04"
      ],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C17",
      "title": "Подготовиться к визиту",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "booking",
      "frontend": "Референс, что сохранить, тишина/общение и доступность.",
      "backend": "Visit preferences versioned, минимальные данные; отсутствие референса не блокирует услугу.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [
        "SCR-010"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C18",
      "title": "Добавить фото",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "booking",
      "frontend": "Выбор камеры/галереи и отдельное согласие на хранение.",
      "backend": "Scoped upload session, content limits, metadata stripping, private media; photo consent не равно portfolio consent.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-10"
      ],
      "commandIds": [
        "CMD-MEDIA"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C19",
      "title": "Отказать в фото",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "booking",
      "frontend": "Продолжить текстом без наказания за отказ.",
      "backend": "Не читать камеру/галерею, не создавать media; разрешение ОС и согласие хранения независимы.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-10"
      ],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C20",
      "title": "Фото не загрузилось",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "booking",
      "frontend": "Сохранить локальный черновик, повторить или удалить.",
      "backend": "Идемпотентный upload finalize; orphan cleanup по TTL, отказ не отменяет booking.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-MEDIA"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C21",
      "title": "Управлять визитом",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "booking",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [
        "SCR-009"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C22",
      "title": "Перенести визит",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "booking",
      "frontend": "Выбрать новый слот и увидеть разницу цены/условий.",
      "backend": "Исходный визит остаётся подтверждённым до атомарной замены; new quote при изменении состава.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-05"
      ],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C23",
      "title": "Подтвердить перенос",
      "role": "client",
      "phase": 4,
      "layer": "back",
      "domain": "booking",
      "frontend": "Показать новое время после ответа сервера.",
      "backend": "Atomic move hold→booking and release old; компенсировать разницу платежа отдельной saga; cancel старых reminders.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-MOVE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C24",
      "title": "Проверить отмену",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "booking",
      "frontend": "Ясно показать сумму возврата/обязательства и причины без обязательного диагноза.",
      "backend": "Cancellation quote по policy snapshot; версия+auth; штрафы не включать без утверждённого правила.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-05"
      ],
      "commandIds": [
        "CMD-REFUND-QUOTE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C25",
      "title": "Визит отменён",
      "role": "client",
      "phase": 4,
      "layer": "back",
      "domain": "booking",
      "frontend": "Статус отмены и отдельно ход возврата.",
      "backend": "Cancel booking, release resource, outbox waitlist, cancel reminders; refund pending не объявлять refunded.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-CANCEL"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C26",
      "title": "Клиент заболел",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "booking",
      "frontend": "Быстро перенести/отменить; пожелать восстановления, не требовать медицинских данных.",
      "backend": "Reason category optional, empathetic exception policy review; не начислять автоматический штраф.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-05"
      ],
      "commandIds": [
        "CMD-LATE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": [
        "болезнь",
        "заболел",
        "болею"
      ]
    },
    {
      "id": "C27",
      "title": "Клиент опаздывает",
      "role": "client",
      "phase": 5,
      "layer": "front",
      "domain": "booking",
      "frontend": "Сообщить примерное прибытие, увидеть варианты.",
      "backend": "Сравнить remaining service+buffer с next boundary; мастер/владелец подтверждает возможный scope.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-06"
      ],
      "commandIds": [
        "CMD-LATE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": [
        "опоздание",
        "опоздал",
        "задержка"
      ]
    },
    {
      "id": "C28",
      "title": "Клиент не пришёл",
      "role": "client",
      "phase": 5,
      "layer": "back",
      "domain": "booking",
      "frontend": "Показать пропущенный визит и путь к человеку, без обвинительного текста.",
      "backend": "После grace и проверки check-in открыть no-show case; не списывать карту по одному таймеру.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-05"
      ],
      "commandIds": [
        "CMD-NOSHOW"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": [
        "забывчивость",
        "забыл",
        "неявка",
        "no-show"
      ]
    },
    {
      "id": "C29",
      "title": "Прибыть в филиал",
      "role": "client",
      "phase": 5,
      "layer": "front",
      "domain": "booking",
      "frontend": "Показать визит, сообщить о прибытии; QR не обязателен.",
      "backend": "Проверить location/booking status, check-in сотрудником; геолокация не является доказательством услуги.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C30",
      "title": "Прийти раньше",
      "role": "client",
      "phase": 5,
      "layer": "front",
      "domain": "booking",
      "frontend": "Показать ожидание или согласованное раннее начало.",
      "backend": "Не занимать чужой интервал; early start только если ресурсы свободны и мастер согласен.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-LATE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C31",
      "title": "Прийти не туда",
      "role": "client",
      "phase": 5,
      "layer": "front",
      "domain": "booking",
      "frontend": "Показать правильный адрес и связаться с филиалом.",
      "backend": "Новый branch требует согласования ресурсов/цены; не подтверждать по GPS автоматически.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-LATE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C32",
      "title": "Получить услугу",
      "role": "client",
      "phase": 5,
      "layer": "front",
      "domain": "booking",
      "frontend": "Видеть согласованный состав и возможность задать вопрос.",
      "backend": "in_service authoritative; аппликация может быть закрыта, состояние живёт на сервере.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C33",
      "title": "Попросить изменить результат",
      "role": "client",
      "phase": 6,
      "layer": "front",
      "domain": "booking",
      "frontend": "Описать несовпадение; исправить сейчас или открыть обращение.",
      "backend": "Согласованный scope corrective work, availability и стоимость; не подменять первоначальный паспорт.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SCOPE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C34",
      "title": "Завершить визит",
      "role": "client",
      "phase": 6,
      "layer": "front",
      "domain": "booking",
      "frontend": "Результат, остаток к оплате, чек и паспорт отдельно.",
      "backend": "service_completed и payment_settled — разные условия; closed только при разрешённых исключениях/передаче долга.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-VISIT-CLOSE"
      ],
      "screenIds": [
        "SCR-012"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C35",
      "title": "Оставить отзыв",
      "role": "client",
      "phase": 7,
      "layer": "front",
      "domain": "booking",
      "frontend": "Честный отзыв, приватный feedback или пропуск.",
      "backend": "Один отзыв на завершённый визит с редакциями; moderation ≠ скрытие негатива; без требования положительного рейтинга.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-15"
      ],
      "commandIds": [
        "CMD-REVIEW"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C36",
      "title": "Подать претензию",
      "role": "client",
      "phase": 7,
      "layer": "front",
      "domain": "booking",
      "frontend": "Текст, доступные фото по желанию и ожидаемый результат.",
      "backend": "Case ID, срок ответа, escalation; не требовать публикации фото и не блокировать возврат за отзыв.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-REVIEW"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C37",
      "title": "Поблагодарить барбера",
      "role": "client",
      "phase": 7,
      "layer": "front",
      "domain": "booking",
      "frontend": "Спасибо, чаевые по желанию, поделиться ссылкой.",
      "backend": "Чаевые отдельная операция/ledger при включённом канале; отказ не меняет качество обслуживания.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-15"
      ],
      "commandIds": [
        "CMD-PAY",
        "CMD-REVIEW"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C38",
      "title": "Открыть Cut Passport",
      "role": "client",
      "phase": 7,
      "layer": "front",
      "domain": "booking",
      "frontend": "Параметры и разрешённые до/после; исправление заметок.",
      "backend": "Immutable revisions и ownership; revoked media скрываются, технические параметры можно хранить отдельно.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PASSPORT-READ"
      ],
      "screenIds": [
        "SCR-013"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C39",
      "title": "Выбрать следующий образ",
      "role": "client",
      "phase": 9,
      "layer": "front",
      "domain": "booking",
      "frontend": "Повторить точно или изменить детали с барбером.",
      "backend": "Новый draft из версии паспорта; новый quote, без фонового списания.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PASSPORT-READ"
      ],
      "screenIds": [
        "SCR-014"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C40",
      "title": "Записаться снова",
      "role": "client",
      "phase": 9,
      "layer": "front",
      "domain": "booking",
      "frontend": "Предложить подходящий интервал, дату выбирает человек.",
      "backend": "New booking intent, связи previousVisitId/cohort; никакого авто-бронирования из напоминания.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PASSPORT-READ"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C41",
      "title": "Взять паузу",
      "role": "client",
      "phase": 9,
      "layer": "front",
      "domain": "booking",
      "frontend": "Отложить уход за формой: поездка, болезнь, смена планов.",
      "backend": "Pause recommendation jobs до выбранной даты; сервисные сообщения о реальных обязательствах остаются отдельно.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": [
        "болезнь",
        "отпуск",
        "переезд",
        "усталость"
      ]
    },
    {
      "id": "C42",
      "title": "Настроить уведомления",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "booking",
      "frontend": "Каналы, время, сервисные события и маркетинг раздельно.",
      "backend": "Consent ledger + permission state; revoke действует на pending jobs, inbox сохраняет статус визита.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-07"
      ],
      "commandIds": [
        "CMD-CONSENT",
        "CMD-REMINDER"
      ],
      "screenIds": [
        "SCR-015"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C43",
      "title": "Помощь человеку",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "booking",
      "frontend": "Открыть обращение, контакт филиала и номер операции.",
      "backend": "Support case без раскрытия чужой PII; SLA и escalation, разрешение требует audit.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-13"
      ],
      "commandIds": [
        "CMD-CASE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "C44",
      "title": "Особые пожелания",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "booking",
      "frontend": "Тишина, доступность, сопровождающий, аллергия по желанию.",
      "backend": "Минимизация чувствительных данных, ограниченный срок и scope; подтвердить доступность услуги у филиала.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PROFILE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": [
        "аллергия",
        "инвалидность",
        "тишина",
        "доступность"
      ]
    },
    {
      "id": "C45",
      "title": "Записать другого человека",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "booking",
      "frontend": "Разделить плательщика и получателя, пригласить получателя.",
      "backend": "Recipient consent/age policy; не открывать паспорт другого человека плательщику. Подтверждение получателя до private data.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-12"
      ],
      "commandIds": [
        "CMD-PROFILE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P00",
      "title": "Выбрать оплату",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "payments",
      "frontend": "Новая/сохранённая карта, доступный клубный зачёт или на месте.",
      "backend": "Allowed methods по merchant/policy/amount; payer и recipient раздельны; сумма только из quote.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-03"
      ],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P01",
      "title": "Ввести карту у провайдера",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "payments",
      "frontend": "Открыть защищённую форму ЮKassa.",
      "backend": "PAN/CVV не проходят через PRIME, не логируются; клиент получает confirmation flow, secret остаётся на сервере.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-SAVE",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P02",
      "title": "Разрешить сохранение карты",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "payments",
      "frontend": "Отдельный необязательный выбор и понятная цель.",
      "backend": "Сохранить consent version, только тогда save_payment_method=true; не равняется согласию на автоплатёж.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-SAVE",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P03",
      "title": "Сохранённый способ оплаты",
      "role": "client",
      "phase": 6,
      "layer": "back",
      "domain": "payments",
      "frontend": "Бренд и последние цифры; не обещать сохранение до ответа.",
      "backend": "Только при payment_method.saved=true сохранить provider ID, owner, masked metadata. CVV/PAN не хранить.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-SAVE",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-METHODS"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P04",
      "title": "Использовать сохранённую карту",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "payments",
      "frontend": "Выбрать свою карту и подтвердить конкретную сумму.",
      "backend": "Ownership token + explicit current payment intent; возможен новый challenge, declined token не означает потерю booking.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-SAVE",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-METHODS"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P05",
      "title": "Отвязать карту",
      "role": "client",
      "phase": 8,
      "layer": "back",
      "domain": "payments",
      "frontend": "Показать, что будущие списания отключены; объяснить активные обязательства.",
      "backend": "Revoke local authorization, cancel renewal jobs; unlink не отменяет прошлый payment/refund. Действия provider по поддерживаемому API отдельно.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-SAVE",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-UNLINK-CARD"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P06",
      "title": "Создать платёж",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "payments",
      "frontend": "Показать pending и ссылку провайдера.",
      "backend": "POST payment с persisted operationId/idempotence key и quote; purpose booking/deposit/club/tip раздельный, серверная сумма.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-11"
      ],
      "commandIds": [
        "CMD-PAY"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P07",
      "title": "Подтвердить в банке",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "payments",
      "frontend": "3DS/redirect, можно вернуться или отказаться.",
      "backend": "Return URL — только навигация; не источник succeeded. State связан с payment intent.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P08",
      "title": "Ожидать статус оплаты",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "payments",
      "frontend": "Ожидание, номер операции и безопасный выход из приложения.",
      "backend": "Webhook inbox + authenticated GET verify object/shop/amount/currency; dedupe; stale notification не понижает состояние.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-WEBHOOK"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P09",
      "title": "Средства авторизованы",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "payments",
      "frontend": "Различать блокировку и окончательное списание.",
      "backend": "waiting_for_capture; expires_at провайдера, capture/cancel только при согласованном основании. Не держать авторизацию до далёкого визита.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PAYMENT-CAPTURE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P10",
      "title": "Платёж успешен",
      "role": "client",
      "phase": 6,
      "layer": "back",
      "domain": "payments",
      "frontend": "Показать успешную операцию, затем проверенный статус заказа.",
      "backend": "succeeded immutable; ledger once, booking saga/club/tip continuation по purpose, outbox receipt.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-PAYMENT-CAPTURE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P11",
      "title": "Платёж отклонён / отменён",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "payments",
      "frontend": "Причина без обвинения; другой метод, повтор новым намерением или выход.",
      "backend": "canceled final; release obsolete hold, новый payment только после проверки старого. Дубликат callback не создаёт новый.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P12",
      "title": "Оплата неизвестна",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "payments",
      "frontend": "Сверяем, не платите второй раз; можно оставить обращение.",
      "backend": "Сетевой timeout не равен отказу; persist operation, reconcile before retry, ключ ЮKassa имеет ограниченный срок.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P13",
      "title": "Сверить платёж",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "payments",
      "frontend": "Обновить результат из сервера.",
      "backend": "GET provider + local operation/ledger, compare order amount; after idempotency window не повторять create вслепую.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-RECONCILE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P14",
      "title": "Оплатить на месте",
      "role": "client",
      "phase": 6,
      "layer": "front",
      "domain": "payments",
      "frontend": "Показать остаток к оплате: наличные или терминал.",
      "backend": "Booking can be confirmed as payment_due по политике; cashier confirms amount and method, без фиктивного YooKassa payment.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-CASH"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P15",
      "title": "Подтвердить оплату на месте",
      "role": "barber",
      "phase": 6,
      "layer": "back",
      "domain": "payments",
      "frontend": "Уполномоченный сотрудник подтверждает приём и чек.",
      "backend": "Separate cashier capability; audit, unique settlement, external terminal reference; если нет права — владелец.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-CASH"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P16",
      "title": "Запросить возврат",
      "role": "client",
      "phase": 7,
      "layer": "front",
      "domain": "payments",
      "frontend": "Сумма, основание и статус рассмотрения.",
      "backend": "Refund entitlement/order version; сумма ≤ captured − successful/pending refunds. Не объявлять деньги возвращёнными при создании.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-REFUND-QUOTE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P17",
      "title": "Возврат выполняется",
      "role": "client",
      "phase": 7,
      "layer": "back",
      "domain": "payments",
      "frontend": "Показать pending и идентификатор, без обещанного срока банка.",
      "backend": "Idempotent refund object; webhook/GET reconciliation, cash возврат через отдельный audited процесс.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-REFUND"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P18",
      "title": "Возврат завершён",
      "role": "client",
      "phase": 7,
      "layer": "back",
      "domain": "payments",
      "frontend": "Обновить статус возврата и чек.",
      "backend": "Refund succeeded → ledger once, сумма заказа/клуб/начисление мастера корректируются связанными записями.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P19",
      "title": "Возврат требует внимания",
      "role": "owner",
      "phase": 7,
      "layer": "front",
      "domain": "payments",
      "frontend": "Повторить сверку/передать финансовому ответственному.",
      "backend": "Timeout не считать failed; terminal canceled допускает исправленную новую операцию, SLA escalation и audit.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-13"
      ],
      "commandIds": [
        "CMD-RECONCILE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P20",
      "title": "Выдать чек",
      "role": "client",
      "phase": 6,
      "layer": "back",
      "domain": "payments",
      "frontend": "Показать чек или состояние его подготовки.",
      "backend": "Фискализация по выбранной схеме, отдельные события предоплаты/зачёта/возврата; accounting mapping утверждается до live.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-11"
      ],
      "commandIds": [
        "CMD-RECEIPT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P21",
      "title": "Чек ещё не готов",
      "role": "owner",
      "phase": 6,
      "layer": "front",
      "domain": "payments",
      "frontend": "Деньги уже учтены; показать очередь исправления.",
      "backend": "Receipt retry bounded + reconciliation; не списывать повторно и не менять succeeded на failed.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-11"
      ],
      "commandIds": [
        "CMD-RECONCILE",
        "CMD-RECEIPT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P22",
      "title": "Спор по списанию",
      "role": "owner",
      "phase": 7,
      "layer": "front",
      "domain": "payments",
      "frontend": "Показать факты и маршрут финансового разбирательства.",
      "backend": "Dispute/chargeback отдельно от обычного refund; заморозить спорное начисление, audit evidence, human review.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-CASE-RESOLVE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P23",
      "title": "Доплата / частичный возврат",
      "role": "client",
      "phase": 6,
      "layer": "front",
      "domain": "payments",
      "frontend": "Показать согласованную разницу за изменённую услугу.",
      "backend": "Новая price revision, explicit consent; остаток pay/refund saga. Нельзя незаметно увеличить исходный charge.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SCOPE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P24",
      "title": "Зачесть клубный визит",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "payments",
      "frontend": "Показать списываемую привилегию и остаток к доплате.",
      "backend": "Reserve entitlement атомарно; commit при политике оказания услуги, release при отмене; не считать клуб фиктивным cash wallet.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09"
      ],
      "commandIds": [
        "CMD-ENTITLEMENT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "P25",
      "title": "Деньги пришли после потери слота",
      "role": "owner",
      "phase": 3,
      "layer": "back",
      "domain": "payments",
      "frontend": "Объяснить ситуацию, предложить согласованное окно или возврат.",
      "backend": "Paid-unallocated saga; никогда не double-book. Refund обязательной компенсацией при невозможности подтвердить услугу.",
      "sourceIds": [
        "OWNER-BRIEF",
        "YOOKASSA-PROCESS",
        "YOOKASSA-WEBHOOKS"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-04"
      ],
      "commandIds": [
        "CMD-RECONCILE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "N00",
      "title": "Запланировать напоминания",
      "role": "client",
      "phase": 4,
      "layer": "back",
      "domain": "notifications",
      "frontend": "Показать выбранные каналы и локальное время.",
      "backend": "Outbox по booking version; job id=booking/type/version/channel, server timezone, отмена при переносе.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-07"
      ],
      "commandIds": [
        "CMD-NOTIFICATION"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "N01",
      "title": "Разрешить канал",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "notifications",
      "frontend": "Push permission в контексте пользы; отказ оставляет inbox.",
      "backend": "OS permission отдельно от channel consent; device tokens и messenger bot-access не равны promo consent.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-REMINDER"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "N02",
      "title": "Доставить уведомление",
      "role": "client",
      "phase": 4,
      "layer": "back",
      "domain": "notifications",
      "frontend": "Короткое сообщение без чувствительных деталей на lock screen.",
      "backend": "Channel adapter с retries/backoff, consent recheck, validity window; accepted provider ≠ seen человеком.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-07"
      ],
      "commandIds": [
        "CMD-NOTIFICATION"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "N03",
      "title": "Не доставлено",
      "role": "client",
      "phase": 4,
      "layer": "back",
      "domain": "notifications",
      "frontend": "Показать актуальное событие внутри приложения.",
      "backend": "Недействительный token удалить, fallback только при согласии; не спамить всеми каналами.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-07"
      ],
      "commandIds": [
        "CMD-NOTIFICATION"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": [
        "уведомления",
        "недоставка"
      ]
    },
    {
      "id": "N04",
      "title": "Прочитать напоминание",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "notifications",
      "frontend": "Открыть текущий визит, маршрут или перенос.",
      "backend": "Deep link перепроверяет auth/ownership/revision; read receipt не является согласием на услугу.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-REMINDER"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "N05",
      "title": "Забыть или пропустить",
      "role": "client",
      "phase": 5,
      "layer": "back",
      "domain": "notifications",
      "frontend": "Оставить возможность восстановиться, связаться и перенести.",
      "backend": "Нет прочтения ≠ no-show; только реальный start/grace/check-in может открыть missed case.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": [
        "забывчивость",
        "забыл",
        "неявка"
      ]
    },
    {
      "id": "N06",
      "title": "Напомнить позже",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "notifications",
      "frontend": "Выбрать один перенос напоминания.",
      "backend": "Snooze с max count/deadline, не после начала услуги; не меняет booking time.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-REMINDER"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "N07",
      "title": "Отключить рассылку",
      "role": "client",
      "phase": 8,
      "layer": "back",
      "domain": "notifications",
      "frontend": "Сразу подтвердить отказ от маркетинга.",
      "backend": "Revoke channel consent и pending campaign jobs; важные обязательства доступны в inbox, без обхода отказа.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-REMINDER"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "N08",
      "title": "Разрешённый запасной канал",
      "role": "client",
      "phase": 4,
      "layer": "back",
      "domain": "notifications",
      "frontend": "Одна понятная попытка уведомления.",
      "backend": "Проверить подтверждённый адрес/контакт, consent и dedupe across channels; затем задача человеку при критичности.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-07"
      ],
      "commandIds": [
        "CMD-NOTIFICATION"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "N09",
      "title": "Ссылка устарела",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "notifications",
      "frontend": "Показать новое время/отмену и актуальные действия.",
      "backend": "Не воскрешать canceled booking по старой ссылке; no private content до auth.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L00",
      "title": "Посмотреть PRIME CLUB",
      "role": "client",
      "phase": 7,
      "layer": "front",
      "domain": "club",
      "frontend": "Понятные привилегии, стоимость, срок, пауза и отмена.",
      "backend": "Только published ClubPlanVersion; примеры маркетолога не являются утверждёнными тарифами.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09"
      ],
      "commandIds": [],
      "screenIds": [
        "SCR-016"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L01",
      "title": "Принять условия клуба",
      "role": "client",
      "phase": 7,
      "layer": "front",
      "domain": "club",
      "frontend": "Выбрать разовую покупку или явно разрешённое продление.",
      "backend": "Plan/consent snapshot; recurrence отдельный mandate с amount/cadence/change notice.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09"
      ],
      "commandIds": [
        "CMD-CLUB"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L02",
      "title": "Членство активно",
      "role": "client",
      "phase": 7,
      "layer": "back",
      "domain": "club",
      "frontend": "Показать период и доступные услуги/привилегии.",
      "backend": "Только settled purchase → immutable entitlement ledger; duplicate webhook не удваивает баланс.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09"
      ],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L03",
      "title": "Применить привилегию",
      "role": "client",
      "phase": 3,
      "layer": "front",
      "domain": "club",
      "frontend": "Выбрать подходящий визит и увидеть остаток.",
      "backend": "Eligibility service/branch/period; concurrent redeem защищён unique reservation.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09"
      ],
      "commandIds": [
        "CMD-ENTITLEMENT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L04",
      "title": "Продлить членство",
      "role": "client",
      "phase": 9,
      "layer": "back",
      "domain": "club",
      "frontend": "Предупредить о новом периоде и сумме; можно отказаться.",
      "backend": "Scheduler only with active mandate/token; одна operation на период, не скрывать изменение цены.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09"
      ],
      "commandIds": [
        "CMD-MEMBERSHIP",
        "CMD-RENEWAL"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L05",
      "title": "Продление не прошло",
      "role": "client",
      "phase": 9,
      "layer": "front",
      "domain": "club",
      "frontend": "Обновить способ оплаты, оплатить вручную или завершить членство.",
      "backend": "Limited retry policy and grace draft; не накапливать бесконечные списания/долги.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09"
      ],
      "commandIds": [
        "CMD-RENEWAL"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L06",
      "title": "Пауза или отмена клуба",
      "role": "client",
      "phase": 9,
      "layer": "front",
      "domain": "club",
      "frontend": "Показать дату прекращения, остаток и судьбу будущих записей.",
      "backend": "Cancel renewal atomically; refund/unused entitlement по утверждённым правилам, визиты не исчезают.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09"
      ],
      "commandIds": [
        "CMD-MEMBERSHIP"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L07",
      "title": "Период завершён",
      "role": "client",
      "phase": 9,
      "layer": "back",
      "domain": "club",
      "frontend": "Показать обычные условия, доступ к истории сохраняется.",
      "backend": "Expire benefits, release invalid reserves with explicit customer resolution; паспорт не заложник членства.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09"
      ],
      "commandIds": [
        "CMD-RENEWAL"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L08",
      "title": "Подарить гостевой визит",
      "role": "client",
      "phase": 7,
      "layer": "front",
      "domain": "club",
      "frontend": "Выбрать доступную привилегию и ссылку без чужих данных.",
      "backend": "Reserve GuestPass, expiry, one-use claim; recipient identity independent from payer.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09"
      ],
      "commandIds": [
        "CMD-GUEST-PASS"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L09",
      "title": "Принять гостевой визит",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "club",
      "frontend": "Подтвердить условия, выбрать услуги и время.",
      "backend": "Claim once после auth и consent, entitlement получателю; запрет self-abuse по опубликованной политике.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-09",
        "POL-12"
      ],
      "commandIds": [
        "CMD-GUEST-CLAIM"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L10",
      "title": "Пригласить друга",
      "role": "client",
      "phase": 9,
      "layer": "front",
      "domain": "club",
      "frontend": "Добровольно поделиться ссылкой, без импорта адресной книги.",
      "backend": "Referral code attribution; не отправлять сообщение за человека; никаких скрытых reward promises.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-15"
      ],
      "commandIds": [
        "CMD-REFERRAL"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "L11",
      "title": "Учесть рекомендацию",
      "role": "client",
      "phase": 9,
      "layer": "back",
      "domain": "club",
      "frontend": "Прозрачно показать результат после выполненного условия.",
      "backend": "Reward after eligible completed settled visit, one per rule, fraud review и reversal ledger при refund.",
      "sourceIds": [
        "MARKETING-V2",
        "MARKETING-V3",
        "MARKETING-20"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-15"
      ],
      "commandIds": [
        "CMD-REFERRAL"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "R00",
      "title": "Приватность и аккаунт",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "privacy",
      "frontend": "Фото, каналы, связанные входы, карты, выгрузка и удаление.",
      "backend": "Capabilities per owner of data; отдельные consent records, activity/audit view.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [
        "SCR-017"
      ],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "R01",
      "title": "Разрешить портфолио",
      "role": "client",
      "phase": 7,
      "layer": "front",
      "domain": "privacy",
      "frontend": "Предпросмотр конкретных фото и каналов публикации.",
      "backend": "Granular revocable consent; private passport не публикуется автоматически, отказ не влияет на услугу.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-10"
      ],
      "commandIds": [
        "CMD-MEDIA"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "R02",
      "title": "Отозвать фото",
      "role": "client",
      "phase": 8,
      "layer": "back",
      "domain": "privacy",
      "frontend": "Убрать фото из приложения и портфолио; показать ход удаления.",
      "backend": "Revoke signed URLs, purge derivatives/CDN, provenance downstream; retention exceptions документируются и ограничивают доступ.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-10"
      ],
      "commandIds": [
        "CMD-CONSENT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "R03",
      "title": "Выгрузить свои данные",
      "role": "client",
      "phase": 8,
      "layer": "back",
      "domain": "privacy",
      "frontend": "Подтверждение личности и готовность защищённой выгрузки.",
      "backend": "Async export с expiry, доступ только владельцу, exclude third-party private notes, audit.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-EXPORT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "R04",
      "title": "Удалить аккаунт",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "privacy",
      "frontend": "Показать будущие визиты, возвраты и последствия.",
      "backend": "Deletion intent с reauth, revoke sessions; не терять финансовые обязательства и открытые cases.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-01",
        "POL-10",
        "POL-16"
      ],
      "commandIds": [
        "CMD-DELETE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "R05",
      "title": "Завершить обязательства",
      "role": "client",
      "phase": 8,
      "layer": "back",
      "domain": "privacy",
      "frontend": "Отмена/перенос будущих визитов и статус возвратов.",
      "backend": "Saga cancellation/refund; сроки хранения по утверждённой матрице, минимальные финансовые записи отделены от профиля.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-16"
      ],
      "commandIds": [
        "CMD-DELETE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "R06",
      "title": "Профиль удалён",
      "role": "client",
      "phase": 9,
      "layer": "back",
      "domain": "privacy",
      "frontend": "Подтвердить удаление доступных данных и явно назвать сохранённые обязательные записи.",
      "backend": "Tombstone/anonymize, no marketing, erase media jobs reconciled; повторный вход не восстанавливает старые данные автоматически.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": true,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "R07",
      "title": "Потерян телефон",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "privacy",
      "frontend": "Другой вход, завершить сессии и восстановить доступ.",
      "backend": "Risk review и revoke device; PAN/CVV не используются как доказательство личности.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-RECOVERY"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": [
        "кража",
        "потерял телефон"
      ]
    },
    {
      "id": "R08",
      "title": "Доступность интерфейса",
      "role": "client",
      "phase": 8,
      "layer": "front",
      "domain": "privacy",
      "frontend": "Крупный шрифт, screen reader, тишина, reduced motion, текстовые альтернативы.",
      "backend": "Настройки не снижают право на запись; sensitive preference не уходит в общую аналитику.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "S00",
      "title": "Зафиксировать запись",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "reliability",
      "frontend": "Подтверждение только после commit.",
      "backend": "Atomic capacity claim/booking unique constraints; payment prerequisite зависит от policy; outbox commit с записью.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-BOOK"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "S01",
      "title": "Проверить свободный ресурс",
      "role": "client",
      "phase": 3,
      "layer": "back",
      "domain": "reliability",
      "frontend": "Показать актуальные подходящие окна.",
      "backend": "Availability = shift ∩ skill ∩ equipment − bookings − holds − breaks; interval arithmetic, no overlap.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-HOLD",
        "CMD-AVAILABILITY"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "S02",
      "title": "Нет сети / приложение закрыто",
      "role": "client",
      "phase": 4,
      "layer": "front",
      "domain": "reliability",
      "frontend": "Локальный draft, последнее состояние и понятный offline status.",
      "backend": "Не ставить финансовые commands в слепую очередь; server operations продолжаются независимо от клиента.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "S03",
      "title": "Восстановить состояние",
      "role": "client",
      "phase": 4,
      "layer": "back",
      "domain": "reliability",
      "frontend": "Сначала сверить актуальный статус, затем продолжить.",
      "backend": "Fetch operations/bookings revision, apply monotonic state, dedupe pending commands, refresh auth если истекла.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SESSION"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "S04",
      "title": "Разобрать конфликт изменений",
      "role": "owner",
      "phase": 5,
      "layer": "front",
      "domain": "reliability",
      "frontend": "Показать обе версии и актуальное состояние.",
      "backend": "Optimistic concurrency/409; не last-write-wins для денег, места, consent и прав.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-SHIFT"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "S05",
      "title": "Операционная очередь",
      "role": "owner",
      "phase": 7,
      "layer": "back",
      "domain": "reliability",
      "frontend": "Видимые unresolved cases, ответственный и срок.",
      "backend": "Retry budget exhausted → durable manual case, escalation, audit; не терять message в DLQ без владельца.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-13",
        "POL-16"
      ],
      "commandIds": [
        "CMD-CASE",
        "CMD-CASE-RESOLVE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "S06",
      "title": "Закрыть обращение",
      "role": "owner",
      "phase": 8,
      "layer": "front",
      "domain": "reliability",
      "frontend": "Показать решение и подтверждённые компенсации.",
      "backend": "Resolution reason + linked authoritative outcomes; unresolved payment/refund не закрывается кнопкой оператора.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [
        "POL-13"
      ],
      "commandIds": [
        "CMD-CASE-RESOLVE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    },
    {
      "id": "S07",
      "title": "Закрыть визит в учёте",
      "role": "client",
      "phase": 7,
      "layer": "back",
      "domain": "reliability",
      "frontend": "Услуга, расчёт, чек и результат отражены отдельно.",
      "backend": "Booking closed when service/payment obligations resolved or explicit audited receivable; immutable history, outbox retention.",
      "sourceIds": [
        "OWNER-BRIEF"
      ],
      "status": "contract",
      "terminal": false,
      "policyIds": [],
      "commandIds": [
        "CMD-VISIT-CLOSE"
      ],
      "screenIds": [],
      "implementationStatus": "contract-only; atlas exploration implemented",
      "keywords": []
    }
  ],
  "edges": [
    {
      "id": "O00-O01",
      "source": "O00",
      "target": "O01",
      "label": "Создать организацию",
      "kind": "happy",
      "actor": "owner",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "operations.o00_o01",
      "frontend": "Показать черновик организации и ответственного.",
      "backend": "Создать organization с owner membership в транзакции; аудит, unique legal identity после проверки."
    },
    {
      "id": "O01-O02",
      "source": "O01",
      "target": "O02",
      "label": "Настроить филиал",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "operations.o01_o02",
      "frontend": "Адрес, часовой пояс, часы, кресла и контакты.",
      "backend": "Версионировать Branch и Resource; проверить зоны и интервалы, не переносить hosts МАУ."
    },
    {
      "id": "O02-O03",
      "source": "O02",
      "target": "O03",
      "label": "Услуги и длительность",
      "kind": "happy",
      "actor": "owner",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "operations.o02_o03",
      "frontend": "Услуги, навыки, длительность, перерывы, цена.",
      "backend": "ServiceVersion: integer minor units/RUB, skill requirements, equipment, duration и buffer."
    },
    {
      "id": "O03-O04",
      "source": "O03",
      "target": "O04",
      "label": "Правила сервиса",
      "kind": "happy",
      "actor": "owner",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "operations.o03_o04",
      "frontend": "Предоплата, отмена, опоздание, возврат, клуб — с явным статусом решения.",
      "backend": "PolicyVersion; ничего не удерживать по неутверждённым правилам. Снимок условий в каждом заказе."
    },
    {
      "id": "O04-O05",
      "source": "O04",
      "target": "O05",
      "label": "Подключить ЮKassa",
      "kind": "happy",
      "actor": "owner",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "operations.o04_o05",
      "frontend": "Статус тестового/боевого магазина и фискализации.",
      "backend": "Секреты только серверу; shopId, webhook, сверка, способ выдачи чека. Sandbox smoke до включения продаж."
    },
    {
      "id": "O05-O06",
      "source": "O05",
      "target": "O06",
      "label": "Открыть набор барберов",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "operations.o05_o06",
      "frontend": "Описать навыки, загрузку, условия и этапы отбора.",
      "backend": "Vacancy/candidate consent; не публиковать персональные данные кандидата в клиентский каталог."
    },
    {
      "id": "O06-O07",
      "source": "O06",
      "target": "O07",
      "label": "Рассмотреть кандидата",
      "kind": "happy",
      "actor": "owner",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "operations.o06_o07",
      "frontend": "Портфолио, интервью, доступность; согласовать пробную смену.",
      "backend": "RecruitmentCase с ограниченным доступом; отклонение и retention отдельно от клиентского аккаунта."
    },
    {
      "id": "O07-O08",
      "source": "O07",
      "target": "O08",
      "label": "Пробная смена",
      "kind": "happy",
      "actor": "owner",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "operations.o07_o08",
      "frontend": "Оценить навыки и дать обратную связь.",
      "backend": "Trial shift не даёт доступа к всей базе; отметка результата и решение владельца."
    },
    {
      "id": "O08-O09",
      "source": "O08",
      "target": "O09",
      "label": "Предложить условия",
      "kind": "happy",
      "actor": "owner",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "operations.o08_o09",
      "frontend": "Ставка/процент, услуги, филиал, права и дата старта.",
      "backend": "Versioned offer; модель занятости и расчётов требует утверждения, принятие фиксируется отдельно."
    },
    {
      "id": "O09-O10",
      "source": "O09",
      "target": "O10",
      "label": "Пригласить в команду",
      "kind": "happy",
      "actor": "owner",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "operations.o09_o10",
      "frontend": "Показать одноразовое приглашение и его срок.",
      "backend": "Хеш invite-token, expiry, intended scope; доставка после согласия получателя, повтор инвалидирует старый token."
    },
    {
      "id": "O10-B00",
      "source": "O10",
      "target": "B00",
      "label": "Получить приглашение",
      "kind": "happy",
      "actor": "system",
      "guard": "Доставка согласованного приглашения; это межролевой handoff, не переключение owner session в barber.",
      "handoff": true,
      "event": "operations.o10_b00",
      "frontend": "Увидеть PRIME, филиал, автора и условия.",
      "backend": "GET invite проверяет hash/expiry/revoked; не раскрывать чужие данные до аутентификации."
    },
    {
      "id": "B00-B02",
      "source": "B00",
      "target": "B02",
      "label": "Войти как приглашённый",
      "kind": "happy",
      "actor": "barber",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "workforce.b00_b02",
      "frontend": "Подтвердить свою идентичность, затем прочитать условия.",
      "backend": "Связать invitation с verified identity; membership ещё pending, claim не принимает role из клиента."
    },
    {
      "id": "B02-B03",
      "source": "B02",
      "target": "B03",
      "label": "Принять приглашение",
      "kind": "happy",
      "actor": "barber",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "workforce.b02_b03",
      "frontend": "Подтвердить конкретную версию условий.",
      "backend": "Одноразовый claim в транзакции, membership onboarding, аудит и уведомление владельцу."
    },
    {
      "id": "B03-B04",
      "source": "B03",
      "target": "B04",
      "label": "Пройти вводный этап",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "workforce.b03_b04",
      "frontend": "Профиль, навыки, правила фото, расписание и подтверждение готовности.",
      "backend": "Минимальные права; owner подтверждает навыки и старт, клиентский профиль скрыт до публикации."
    },
    {
      "id": "B04-B05",
      "source": "B04",
      "target": "B05",
      "label": "Готов к записи",
      "kind": "happy",
      "actor": "barber",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "workforce.b04_b05",
      "frontend": "Проверить публичный профиль и смену.",
      "backend": "Active membership + approved skills + published shift; availability пересчитывается."
    },
    {
      "id": "B05-O12",
      "source": "B05",
      "target": "O12",
      "label": "Опубликовать запись",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": true,
      "event": "workforce.b05_o12",
      "frontend": "Проверить готовность мастеров, цен и расписания.",
      "backend": "Открыть каталог только при active staff, shifts, policies и выбранном режиме оплаты; outbox catalog.published."
    },
    {
      "id": "O12-G00",
      "source": "O12",
      "target": "G00",
      "label": "Открыть PRIME",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": true,
      "event": "operations.o12_g00",
      "frontend": "Посмотреть концепцию, филиал и цены без регистрации.",
      "backend": "Публичный каталог без PII, rate limits; аналитика без присвоения клиентской личности."
    },
    {
      "id": "G00-G04",
      "source": "G00",
      "target": "G04",
      "label": "Выбрать филиал",
      "kind": "happy",
      "actor": "guest",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "discovery.g00_g04",
      "frontend": "Адрес, доступность входа, карта и часы.",
      "backend": "Branch active; геолокация необязательна, адрес доступен текстом."
    },
    {
      "id": "G04-G01",
      "source": "G04",
      "target": "G01",
      "label": "Выбрать образ",
      "kind": "happy",
      "actor": "guest",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "discovery.g04_g01",
      "frontend": "Смотреть разрешённое портфолио и сохранять локальный интерес.",
      "backend": "Показывать только опубликованные работы с действующим consent, фильтры услуги/длины."
    },
    {
      "id": "G01-G02",
      "source": "G01",
      "target": "G02",
      "label": "Выбрать мастера",
      "kind": "happy",
      "actor": "guest",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "discovery.g01_g02",
      "frontend": "Навыки, работы и ближайшее окно; без выдуманных отзывов.",
      "backend": "Публичная версия профиля, только active membership и service skills."
    },
    {
      "id": "G02-G03",
      "source": "G02",
      "target": "G03",
      "label": "Найти время",
      "kind": "happy",
      "actor": "guest",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "discovery.g02_g03",
      "frontend": "Первый свободный или любимый мастер, другой день/филиал.",
      "backend": "Availability read — подсказка, не бронь; timezone филиала, revision и validUntil."
    },
    {
      "id": "G03-G05",
      "source": "G03",
      "target": "G05",
      "label": "Собрать черновик",
      "kind": "happy",
      "actor": "guest",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "discovery.g03_g05",
      "frontend": "Услуги, мастер, время и ориентировочная сумма.",
      "backend": "Локальный draft без реального hold; цена проверяется сервером перед подтверждением."
    },
    {
      "id": "G05-G06",
      "source": "G05",
      "target": "G06",
      "label": "Продолжить с аккаунтом",
      "kind": "happy",
      "actor": "guest",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "discovery.g05_g06",
      "frontend": "Объяснить, зачем вход для управления визитом, сохранить черновик.",
      "backend": "Сохранить scoped continuation, без role escalation и без доверия старой цене/слоту."
    },
    {
      "id": "G06-A00",
      "source": "G06",
      "target": "A00",
      "label": "Выбрать способ входа",
      "kind": "happy",
      "actor": "guest",
      "guard": "Сохранить anonymous draft; binding к identity только после успешного auth и новой quote.",
      "handoff": false,
      "event": "discovery.g06_a00",
      "frontend": "Telegram, Яндекс; MAX при готовом канале. Отказ не удаляет черновик.",
      "backend": "AuthTransaction с state/expiry/continuation. Ни один provider не задаёт роль сотрудника."
    },
    {
      "id": "A00-A01",
      "source": "A00",
      "target": "A01",
      "label": "Войти через Telegram",
      "kind": "happy",
      "actor": "guest",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "identity.a00_a01",
      "frontend": "Открыть системный браузер или проверенный native flow.",
      "backend": "OIDC authorization code + PKCE S256; client secret только backend, проверить iss/aud/exp/signature и привязку state."
    },
    {
      "id": "A01-A04",
      "source": "A01",
      "target": "A04",
      "label": "Проверить ответ провайдера",
      "kind": "happy",
      "actor": "guest",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "identity.a01_a04",
      "frontend": "Ожидать завершения, не показывать вход раньше сервера.",
      "backend": "Consume state один раз, токены на сервере/защищённом хранилище; stale/replay/issuer mismatch отвергнуть."
    },
    {
      "id": "A04-A06",
      "source": "A04",
      "target": "A06",
      "label": "Завершить профиль",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": true,
      "event": "identity.a04_a06",
      "frontend": "Имя и доступный подтверждённый контакт; условия и маркетинг отдельно.",
      "backend": "Account по provider+subject; обязательные условия versioned, promo consent optional и по каналам."
    },
    {
      "id": "A06-A07",
      "source": "A06",
      "target": "A07",
      "label": "Аккаунт готов",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "identity.a06_a07",
      "frontend": "Вернуться к сохранённой цели и показать доступные роли.",
      "backend": "Server session; переоценить draft, quote, slot. Membership проверяется отдельно от client identity."
    },
    {
      "id": "A07-C00",
      "source": "A07",
      "target": "C00",
      "label": "Главная клиента",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "identity.a07_c00",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache."
    },
    {
      "id": "C00-C03",
      "source": "C00",
      "target": "C03",
      "label": "Собрать услуги",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c00_c03",
      "frontend": "Длительность и сумма меняются вместе; дополнительные пожелания.",
      "backend": "Server quote по ServiceVersion, скидки/клуб валидируются сервером; zero/negative duration запрещены."
    },
    {
      "id": "C03-C02",
      "source": "C03",
      "target": "C02",
      "label": "Выбрать барбера",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c03_c02",
      "frontend": "Навыки, ближайшее время или первый свободный.",
      "backend": "Service skills, branch, active membership; retired stylist → альтернативы без автоматической замены."
    },
    {
      "id": "C02-C04",
      "source": "C02",
      "target": "C04",
      "label": "Выбрать окно",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c02_c04",
      "frontend": "Умные слоты, другой день/филиал, лист ожидания.",
      "backend": "Availability с креслом, навыком, сменой, буфером и существующими hold; время сервера."
    },
    {
      "id": "C04-S01",
      "source": "C04",
      "target": "S01",
      "label": "Проверить свободный ресурс",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c04_s01",
      "frontend": "Показать актуальные подходящие окна.",
      "backend": "Availability = shift ∩ skill ∩ equipment − bookings − holds − breaks; interval arithmetic, no overlap."
    },
    {
      "id": "S01-C06",
      "source": "S01",
      "target": "C06",
      "label": "Получить расчёт",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "reliability.s01_c06",
      "frontend": "Показать полную цену, предоплату/оплату на месте и правила.",
      "backend": "Immutable Quote: price/duration/policyVersion/currency/expiresAt; stale quote требует нового подтверждения."
    },
    {
      "id": "C06-C07",
      "source": "C06",
      "target": "C07",
      "label": "Временно удержать слот",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c06_c07",
      "frontend": "Показать оставшееся время; не объявлять бронь окончательной.",
      "backend": "Atomic hold с уникальным ресурсным интервалом, TTL, revision; срок не продлевается бесконечно."
    },
    {
      "id": "C07-C09",
      "source": "C07",
      "target": "C09",
      "label": "Проверить визит",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c07_c09",
      "frontend": "Мастер, филиал, дата, цена, контакт, условия и способ оплаты.",
      "backend": "Guard quote/hold/policy/consent/contact; business command только после явного подтверждения."
    },
    {
      "id": "C09-P00",
      "source": "C09",
      "target": "P00",
      "label": "Выбрать оплату",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c09_p00",
      "frontend": "Новая/сохранённая карта, доступный клубный зачёт или на месте.",
      "backend": "Allowed methods по merchant/policy/amount; payer и recipient раздельны; сумма только из quote."
    },
    {
      "id": "P00-P01",
      "source": "P00",
      "target": "P01",
      "label": "Ввести карту у провайдера",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "payments.p00_p01",
      "frontend": "Открыть защищённую форму ЮKassa.",
      "backend": "PAN/CVV не проходят через PRIME, не логируются; клиент получает confirmation flow, secret остаётся на сервере."
    },
    {
      "id": "P01-P06",
      "source": "P01",
      "target": "P06",
      "label": "Создать платёж",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "payments.p01_p06",
      "frontend": "Показать pending и ссылку провайдера.",
      "backend": "POST payment с persisted operationId/idempotence key и quote; purpose booking/deposit/club/tip раздельный, серверная сумма."
    },
    {
      "id": "P06-P07",
      "source": "P06",
      "target": "P07",
      "label": "Подтвердить в банке",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "payments.p06_p07",
      "frontend": "3DS/redirect, можно вернуться или отказаться.",
      "backend": "Return URL — только навигация; не источник succeeded. State связан с payment intent."
    },
    {
      "id": "P07-P08",
      "source": "P07",
      "target": "P08",
      "label": "Ожидать статус оплаты",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "payments.p07_p08",
      "frontend": "Ожидание, номер операции и безопасный выход из приложения.",
      "backend": "Webhook inbox + authenticated GET verify object/shop/amount/currency; dedupe; stale notification не понижает состояние."
    },
    {
      "id": "P08-P10",
      "source": "P08",
      "target": "P10",
      "label": "Платёж успешен",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "payments.p08_p10",
      "frontend": "Показать успешную операцию, затем проверенный статус заказа.",
      "backend": "succeeded immutable; ledger once, booking saga/club/tip continuation по purpose, outbox receipt."
    },
    {
      "id": "P10-C10",
      "source": "P10",
      "target": "C10",
      "label": "Подтвердить запись",
      "kind": "happy",
      "actor": "system",
      "guard": "purpose=booking/deposit, quote accepted; payment succeeded не означает confirmed booking до S00.",
      "handoff": false,
      "event": "payments.p10_c10",
      "frontend": "Показать один pending запрос и его статус.",
      "backend": "Idempotent BookingSaga; validate hold/revision/payment policy. Деньги и слот — отдельные агрегаты."
    },
    {
      "id": "C10-S00",
      "source": "C10",
      "target": "S00",
      "label": "Зафиксировать запись",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c10_s00",
      "frontend": "Подтверждение только после commit.",
      "backend": "Atomic capacity claim/booking unique constraints; payment prerequisite зависит от policy; outbox commit с записью."
    },
    {
      "id": "S00-C12",
      "source": "S00",
      "target": "C12",
      "label": "Визит подтверждён",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "reliability.s00_c12",
      "frontend": "Подтверждённый booking ID, адрес, календарь, подготовка.",
      "backend": "Только authoritative confirmed; outbox reminders; оплачено/к оплате показывается отдельно."
    },
    {
      "id": "C12-N00",
      "source": "C12",
      "target": "N00",
      "label": "Запланировать напоминания",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c12_n00",
      "frontend": "Показать выбранные каналы и локальное время.",
      "backend": "Outbox по booking version; job id=booking/type/version/channel, server timezone, отмена при переносе."
    },
    {
      "id": "N00-N01",
      "source": "N00",
      "target": "N01",
      "label": "Разрешить канал",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "notifications.n00_n01",
      "frontend": "Push permission в контексте пользы; отказ оставляет inbox.",
      "backend": "OS permission отдельно от channel consent; device tokens и messenger bot-access не равны promo consent."
    },
    {
      "id": "N01-N02",
      "source": "N01",
      "target": "N02",
      "label": "Доставить уведомление",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "notifications.n01_n02",
      "frontend": "Короткое сообщение без чувствительных деталей на lock screen.",
      "backend": "Channel adapter с retries/backoff, consent recheck, validity window; accepted provider ≠ seen человеком."
    },
    {
      "id": "N02-N04",
      "source": "N02",
      "target": "N04",
      "label": "Прочитать напоминание",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "notifications.n02_n04",
      "frontend": "Открыть текущий визит, маршрут или перенос.",
      "backend": "Deep link перепроверяет auth/ownership/revision; read receipt не является согласием на услугу."
    },
    {
      "id": "N04-C21",
      "source": "N04",
      "target": "C21",
      "label": "Управлять визитом",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "notifications.n04_c21",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние."
    },
    {
      "id": "C21-C17",
      "source": "C21",
      "target": "C17",
      "label": "Подготовиться к визиту",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c21_c17",
      "frontend": "Референс, что сохранить, тишина/общение и доступность.",
      "backend": "Visit preferences versioned, минимальные данные; отсутствие референса не блокирует услугу."
    },
    {
      "id": "C17-C29",
      "source": "C17",
      "target": "C29",
      "label": "Прибыть в филиал",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c17_c29",
      "frontend": "Показать визит, сообщить о прибытии; QR не обязателен.",
      "backend": "Проверить location/booking status, check-in сотрудником; геолокация не является доказательством услуги."
    },
    {
      "id": "C29-B11",
      "source": "C29",
      "target": "B11",
      "label": "Отметить прибытие",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": true,
      "event": "booking.c29_b11",
      "frontend": "Сверить клиента и услугу, отметить check-in.",
      "backend": "Booking confirmed → arrived; серверная отметка, повтор check-in идемпотентен."
    },
    {
      "id": "B11-B10",
      "source": "B11",
      "target": "B10",
      "label": "Карточка клиента",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "workforce.b11_b10",
      "frontend": "Пожелания, разрешённый паспорт, ограничения и время.",
      "backend": "Проверить assignment и consent на каждый media URL; audit доступа, signed URL ограничен временем."
    },
    {
      "id": "B10-B12",
      "source": "B10",
      "target": "B12",
      "label": "Согласовать результат",
      "kind": "happy",
      "actor": "barber",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "workforce.b10_b12",
      "frontend": "Обсудить форму, тишину, чувствительность и цену до начала.",
      "backend": "Consultation snapshot; consent на изменение состава и цены, фото отдельным согласием."
    },
    {
      "id": "B12-B13",
      "source": "B12",
      "target": "B13",
      "label": "Начать работу",
      "kind": "happy",
      "actor": "barber",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "workforce.b12_b13",
      "frontend": "Показать активный визит, время и согласованные услуги.",
      "backend": "arrived → in_service, assignment/version guard; запрет параллельных визитов одного кресла."
    },
    {
      "id": "B13-C32",
      "source": "B13",
      "target": "C32",
      "label": "Получить услугу",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": true,
      "event": "workforce.b13_c32",
      "frontend": "Видеть согласованный состав и возможность задать вопрос.",
      "backend": "in_service authoritative; аппликация может быть закрыта, состояние живёт на сервере."
    },
    {
      "id": "C32-B16",
      "source": "C32",
      "target": "B16",
      "label": "Показать результат",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": true,
      "event": "booking.c32_b16",
      "frontend": "Сверить ожидания; можно поправить сразу.",
      "backend": "Result reviewed клиентом; фото не обязательны для закрытия услуги."
    },
    {
      "id": "B16-B17",
      "source": "B16",
      "target": "B17",
      "label": "Записать Cut Passport",
      "kind": "happy",
      "actor": "barber",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "workforce.b16_b17",
      "frontend": "Параметры, продукт, совет, фото при согласии.",
      "backend": "Passport revision, author, visitId; клиент владеет приватностью. Публикация портфолио отдельным разрешением."
    },
    {
      "id": "B17-B18",
      "source": "B17",
      "target": "B18",
      "label": "Закончить услугу",
      "kind": "happy",
      "actor": "barber",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "workforce.b17_b18",
      "frontend": "Отдельно показать готовность результата и статус оплаты.",
      "backend": "in_service → service_completed; не помечать paid автоматически, invoice balance проверяется отдельно."
    },
    {
      "id": "B18-C34",
      "source": "B18",
      "target": "C34",
      "label": "Завершить визит",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": true,
      "event": "workforce.b18_c34",
      "frontend": "Результат, остаток к оплате, чек и паспорт отдельно.",
      "backend": "service_completed и payment_settled — разные условия; closed только при разрешённых исключениях/передаче долга."
    },
    {
      "id": "C34-S07",
      "source": "C34",
      "target": "S07",
      "label": "Закрыть визит в учёте",
      "kind": "happy",
      "actor": "client",
      "guard": "Услуга завершена, remaining balance=0 или явный audited receivable; чек/возврат имеют отдельные состояния.",
      "handoff": false,
      "event": "booking.c34_s07",
      "frontend": "Услуга, расчёт, чек и результат отражены отдельно.",
      "backend": "Booking closed when service/payment obligations resolved or explicit audited receivable; immutable history, outbox retention."
    },
    {
      "id": "S07-C38",
      "source": "S07",
      "target": "C38",
      "label": "Открыть Cut Passport",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "reliability.s07_c38",
      "frontend": "Параметры и разрешённые до/после; исправление заметок.",
      "backend": "Immutable revisions и ownership; revoked media скрываются, технические параметры можно хранить отдельно."
    },
    {
      "id": "C38-C39",
      "source": "C38",
      "target": "C39",
      "label": "Выбрать следующий образ",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c38_c39",
      "frontend": "Повторить точно или изменить детали с барбером.",
      "backend": "Новый draft из версии паспорта; новый quote, без фонового списания."
    },
    {
      "id": "C39-C40",
      "source": "C39",
      "target": "C40",
      "label": "Записаться снова",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c39_c40",
      "frontend": "Предложить подходящий интервал, дату выбирает человек.",
      "backend": "New booking intent, связи previousVisitId/cohort; никакого авто-бронирования из напоминания."
    },
    {
      "id": "C40-C05",
      "source": "C40",
      "target": "C05",
      "label": "Повторить прошлый образ",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c40_c05",
      "frontend": "Открыть прошлый паспорт и уточнить изменения.",
      "backend": "Reference to passport version; проверить доступность мастера, актуальные услуги и цену, не копировать старую оплату."
    },
    {
      "id": "C05-C03",
      "source": "C05",
      "target": "C03",
      "label": "Собрать услуги",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить актуальное состояние, полномочия и версию объекта.",
      "handoff": false,
      "event": "booking.c05_c03",
      "frontend": "Длительность и сумма меняются вместе; дополнительные пожелания.",
      "backend": "Server quote по ServiceVersion, скидки/клуб валидируются сервером; zero/negative duration запрещены."
    },
    {
      "id": "O00-A00",
      "source": "O00",
      "target": "A00",
      "label": "Подтвердить личность",
      "kind": "recovery",
      "actor": "owner",
      "guard": "Continuation owner_setup; grant владельца уже существует вне публичной регистрации.",
      "handoff": true,
      "event": "operations.o00_a00",
      "frontend": "Telegram, Яндекс; MAX при готовом канале. Отказ не удаляет черновик.",
      "backend": "AuthTransaction с state/expiry/continuation. Ни один provider не задаёт роль сотрудника."
    },
    {
      "id": "A07-O01",
      "source": "A07",
      "target": "O01",
      "label": "Продолжить настройку владельца",
      "kind": "happy",
      "actor": "system",
      "guard": "Только verified owner grant + step-up; auth не создаёт owner grant.",
      "handoff": true,
      "event": "identity.a07_o01",
      "frontend": "Показать черновик организации и ответственного.",
      "backend": "Создать organization с owner membership в транзакции; аудит, unique legal identity после проверки."
    },
    {
      "id": "A07-B03",
      "source": "A07",
      "target": "B03",
      "label": "Принять приглашение сотрудника",
      "kind": "happy",
      "actor": "system",
      "guard": "Только pending invite, совпадающая подтверждённая identity и принятие текущих условий.",
      "handoff": true,
      "event": "identity.a07_b03",
      "frontend": "Подтвердить конкретную версию условий.",
      "backend": "Одноразовый claim в транзакции, membership onboarding, аудит и уведомление владельцу."
    },
    {
      "id": "B02-A00",
      "source": "B02",
      "target": "A00",
      "label": "Выбрать провайдера",
      "kind": "happy",
      "actor": "barber",
      "guard": "Сохранить invite continuation с expiry, роль не берётся из клиента.",
      "handoff": true,
      "event": "workforce.b02_a00",
      "frontend": "Telegram, Яндекс; MAX при готовом канале. Отказ не удаляет черновик.",
      "backend": "AuthTransaction с state/expiry/continuation. Ни один provider не задаёт роль сотрудника."
    },
    {
      "id": "G00-G01",
      "source": "G00",
      "target": "G01",
      "label": "Начать с образа",
      "kind": "happy",
      "actor": "guest",
      "guard": "Портфолио опубликовано и consent действителен.",
      "handoff": false,
      "event": "discovery.g00_g01",
      "frontend": "Смотреть разрешённое портфолио и сохранять локальный интерес.",
      "backend": "Показывать только опубликованные работы с действующим consent, фильтры услуги/длины."
    },
    {
      "id": "G00-G02",
      "source": "G00",
      "target": "G02",
      "label": "Начать с мастера",
      "kind": "happy",
      "actor": "guest",
      "guard": "Публичные active профили.",
      "handoff": false,
      "event": "discovery.g00_g02",
      "frontend": "Навыки, работы и ближайшее окно; без выдуманных отзывов.",
      "backend": "Публичная версия профиля, только active membership и service skills."
    },
    {
      "id": "G00-G03",
      "source": "G00",
      "target": "G03",
      "label": "Начать со времени",
      "kind": "happy",
      "actor": "guest",
      "guard": "Availability read без гарантии hold.",
      "handoff": false,
      "event": "discovery.g00_g03",
      "frontend": "Первый свободный или любимый мастер, другой день/филиал.",
      "backend": "Availability read — подсказка, не бронь; timezone филиала, revision и validUntil."
    },
    {
      "id": "G00-G08",
      "source": "G00",
      "target": "G08",
      "label": "Позвонить или узнать адрес",
      "kind": "happy",
      "actor": "guest",
      "guard": "Актуальный публичный контакт.",
      "handoff": false,
      "event": "discovery.g00_g08",
      "frontend": "Телефон, маршрут, часы; помощь без аккаунта.",
      "backend": "Контакт филиала из актуального каталога, не обещать состоявшийся звонок."
    },
    {
      "id": "G00-G07",
      "source": "G00",
      "target": "G07",
      "label": "Уйти",
      "kind": "exit",
      "actor": "guest",
      "guard": "Нет созданных бизнес-операций.",
      "handoff": false,
      "event": "discovery.g00_g07",
      "frontend": "Закрыть сценарий без рассылок и скрытого заказа.",
      "backend": "Никаких payment/booking effects; локальный draft удаляется по политике."
    },
    {
      "id": "G00-G10",
      "source": "G00",
      "target": "G10",
      "label": "Открыть гостевое приглашение",
      "kind": "happy",
      "actor": "guest",
      "guard": "Есть входящая ссылка GuestPass; не маркетинговая рассылка без согласия.",
      "handoff": false,
      "event": "discovery.g00_g10",
      "frontend": "Условия гостевого визита, срок и отправитель.",
      "backend": "GuestPass token без раскрытия истории дарителя; согласие получателя обязательно."
    },
    {
      "id": "G08-G09",
      "source": "G08",
      "target": "G09",
      "label": "Прийти лично",
      "kind": "happy",
      "actor": "guest",
      "guard": "Филиал открыт; walk-in ещё не запись.",
      "handoff": false,
      "event": "discovery.g08_g09",
      "frontend": "Уточнить наличие окна на месте.",
      "backend": "Walk-in оформляет сотрудник с проверкой ресурса и согласием; не блокировать обслуживание отсутствием приложения."
    },
    {
      "id": "G09-C03",
      "source": "G09",
      "target": "C03",
      "label": "Оформить визит на месте",
      "kind": "happy",
      "actor": "guest",
      "guard": "Сотрудник с booking.create capability и согласие получателя; ephemeral client без обязательного приложения.",
      "handoff": true,
      "event": "discovery.g09_c03",
      "frontend": "Длительность и сумма меняются вместе; дополнительные пожелания.",
      "backend": "Server quote по ServiceVersion, скидки/клуб валидируются сервером; zero/negative duration запрещены."
    },
    {
      "id": "G09-G08",
      "source": "G09",
      "target": "G08",
      "label": "Нет места — оставить контакт филиала",
      "kind": "recovery",
      "actor": "guest",
      "guard": "Не собирать личные данные без цели.",
      "handoff": false,
      "event": "discovery.g09_g08",
      "frontend": "Телефон, маршрут, часы; помощь без аккаунта.",
      "backend": "Контакт филиала из актуального каталога, не обещать состоявшийся звонок."
    },
    {
      "id": "G11-G00",
      "source": "G11",
      "target": "G00",
      "label": "Открыть актуальный каталог",
      "kind": "recovery",
      "actor": "guest",
      "guard": "Ссылка публичная и allowlisted.",
      "handoff": false,
      "event": "discovery.g11_g00",
      "frontend": "Посмотреть концепцию, филиал и цены без регистрации.",
      "backend": "Публичный каталог без PII, rate limits; аналитика без присвоения клиентской личности."
    },
    {
      "id": "G10-A00",
      "source": "G10",
      "target": "A00",
      "label": "Принять гостевой визит",
      "kind": "happy",
      "actor": "guest",
      "guard": "Подтвердить identity, сохранить one-use claim continuation.",
      "handoff": false,
      "event": "discovery.g10_a00",
      "frontend": "Telegram, Яндекс; MAX при готовом канале. Отказ не удаляет черновик.",
      "backend": "AuthTransaction с state/expiry/continuation. Ни один provider не задаёт роль сотрудника."
    },
    {
      "id": "A07-L09",
      "source": "A07",
      "target": "L09",
      "label": "Активировать приглашение гостя",
      "kind": "happy",
      "actor": "system",
      "guard": "Valid GuestPass, consent получателя, claim once; не owner/staff grant.",
      "handoff": false,
      "event": "identity.a07_l09",
      "frontend": "Подтвердить условия, выбрать услуги и время.",
      "backend": "Claim once после auth и consent, entitlement получателю; запрет self-abuse по опубликованной политике."
    },
    {
      "id": "O07-O11",
      "source": "O07",
      "target": "O11",
      "label": "Кандидат не подошёл",
      "kind": "exception",
      "actor": "owner",
      "guard": "Решение владельца с reason и ограниченным retention.",
      "handoff": false,
      "event": "operations.o07_o11",
      "frontend": "Закрыть кандидатуру с корректной обратной связью.",
      "backend": "Закрыть case, отозвать trial-доступ, применить retention; не создавать membership."
    },
    {
      "id": "O08-O11",
      "source": "O08",
      "target": "O11",
      "label": "Пробная смена не пройдена",
      "kind": "exception",
      "actor": "owner",
      "guard": "Нет активного membership.",
      "handoff": false,
      "event": "operations.o08_o11",
      "frontend": "Закрыть кандидатуру с корректной обратной связью.",
      "backend": "Закрыть case, отозвать trial-доступ, применить retention; не создавать membership."
    },
    {
      "id": "O11-O06",
      "source": "O11",
      "target": "O06",
      "label": "Продолжить поиск",
      "kind": "recovery",
      "actor": "owner",
      "guard": "Новое vacancy/candidate действие, без восстановления старого доступа.",
      "handoff": false,
      "event": "operations.o11_o06",
      "frontend": "Описать навыки, загрузку, условия и этапы отбора.",
      "backend": "Vacancy/candidate consent; не публиковать персональные данные кандидата в клиентский каталог."
    },
    {
      "id": "B00-B01",
      "source": "B00",
      "target": "B01",
      "label": "Ссылка просрочена или отозвана",
      "kind": "exception",
      "actor": "barber",
      "guard": "expiry/revoked/consumed проверяет сервер.",
      "handoff": false,
      "event": "workforce.b00_b01",
      "frontend": "Запросить новое или отказаться.",
      "backend": "Не восстанавливать старый token; только владелец выдаёт новую версию."
    },
    {
      "id": "B01-O10",
      "source": "B01",
      "target": "O10",
      "label": "Попросить новое приглашение",
      "kind": "recovery",
      "actor": "barber",
      "guard": "Владелец подтверждает, новый token инвалидирует старый.",
      "handoff": true,
      "event": "workforce.b01_o10",
      "frontend": "Показать одноразовое приглашение и его срок.",
      "backend": "Хеш invite-token, expiry, intended scope; доставка после согласия получателя, повтор инвалидирует старый token."
    },
    {
      "id": "B00-B21",
      "source": "B00",
      "target": "B21",
      "label": "Отказаться от предложения",
      "kind": "exit",
      "actor": "barber",
      "guard": "Отказ не активирует доступ.",
      "handoff": false,
      "event": "workforce.b00_b21",
      "frontend": "Отклонить предложение или обсудить новую версию.",
      "backend": "Decline invite/offer; доступ не активируется, будущая версия требует нового принятия."
    },
    {
      "id": "B21-O09",
      "source": "B21",
      "target": "O09",
      "label": "Обсудить другие условия",
      "kind": "recovery",
      "actor": "barber",
      "guard": "Новая offer version требует нового принятия.",
      "handoff": true,
      "event": "workforce.b21_o09",
      "frontend": "Ставка/процент, услуги, филиал, права и дата старта.",
      "backend": "Versioned offer; модель занятости и расчётов требует утверждения, принятие фиксируется отдельно."
    },
    {
      "id": "B21-O11",
      "source": "B21",
      "target": "O11",
      "label": "Завершить найм",
      "kind": "exit",
      "actor": "barber",
      "guard": "Закрыть кандидатуру, отозвать trial capability.",
      "handoff": true,
      "event": "workforce.b21_o11",
      "frontend": "Закрыть кандидатуру с корректной обратной связью.",
      "backend": "Закрыть case, отозвать trial-доступ, применить retention; не создавать membership."
    },
    {
      "id": "B05-B06",
      "source": "B05",
      "target": "B06",
      "label": "Начать смену",
      "kind": "happy",
      "actor": "system",
      "guard": "Membership и shift active.",
      "handoff": false,
      "event": "workforce.b05_b06",
      "frontend": "Предстоящие визиты, перерывы, свободные окна, незакрытые задачи.",
      "backend": "Scoped read model; server now и timezone филиала, запрет чужого расписания вне scope."
    },
    {
      "id": "O12-O13",
      "source": "O12",
      "target": "O13",
      "label": "Открыть операционный день",
      "kind": "happy",
      "actor": "system",
      "guard": "Владельцу свой branch scope.",
      "handoff": false,
      "event": "operations.o12_o13",
      "frontend": "Нагрузка, исключения, обращения, незакрытые оплаты.",
      "backend": "Read model по филиалу; только разрешённые персональные данные. Нет подмены банковского статуса."
    },
    {
      "id": "O13-O14",
      "source": "O13",
      "target": "O14",
      "label": "Изменить смены",
      "kind": "happy",
      "actor": "owner",
      "guard": "Version check; существующие визиты не исчезают.",
      "handoff": false,
      "event": "operations.o13_o14",
      "frontend": "Одобрить график, отпуск, замену, блокировку кресла.",
      "backend": "Revision + resource constraints; изменение смены не удаляет существующие записи."
    },
    {
      "id": "O14-B06",
      "source": "O14",
      "target": "B06",
      "label": "Опубликовать согласованный график",
      "kind": "happy",
      "actor": "owner",
      "guard": "Нет конфликтов с визитами и ресурсами.",
      "handoff": true,
      "event": "operations.o14_b06",
      "frontend": "Предстоящие визиты, перерывы, свободные окна, незакрытые задачи.",
      "backend": "Scoped read model; server now и timezone филиала, запрет чужого расписания вне scope."
    },
    {
      "id": "B06-B07",
      "source": "B06",
      "target": "B07",
      "label": "Запросить отпуск",
      "kind": "happy",
      "actor": "barber",
      "guard": "Своя membership, корректные даты.",
      "handoff": false,
      "event": "workforce.b06_b07",
      "frontend": "Выбрать даты и предложить смену.",
      "backend": "LeaveRequest; до решения владельца существующие записи сохранены, новые временно ограничиваются политикой."
    },
    {
      "id": "B07-O14",
      "source": "B07",
      "target": "O14",
      "label": "Рассмотреть отпуск",
      "kind": "async",
      "actor": "barber",
      "guard": "Владелец решает и уведомляет сотрудника.",
      "handoff": true,
      "event": "workforce.b07_o14",
      "frontend": "Одобрить график, отпуск, замену, блокировку кресла.",
      "backend": "Revision + resource constraints; изменение смены не удаляет существующие записи."
    },
    {
      "id": "B06-B08",
      "source": "B06",
      "target": "B08",
      "label": "Я заболел",
      "kind": "exception",
      "actor": "barber",
      "guard": "Не требовать диагноз; быстро заморозить новые слоты.",
      "handoff": false,
      "event": "workforce.b06_b08",
      "frontend": "Одним действием сообщить недоступность без диагноза.",
      "backend": "Absence incident + blocked availability; минимизация данных о здоровье, owner получает очередь замен."
    },
    {
      "id": "B06-B09",
      "source": "B06",
      "target": "B09",
      "label": "Я опаздываю",
      "kind": "exception",
      "actor": "barber",
      "guard": "ETA и затронутые визиты, без тихого сдвига.",
      "handoff": false,
      "event": "workforce.b06_b09",
      "frontend": "Ожидаемое прибытие и затронутые визиты.",
      "backend": "Recompute delay impact; клиенты получают выбор, никаких молчаливых сдвигов всего дня."
    },
    {
      "id": "B08-O15",
      "source": "B08",
      "target": "O15",
      "label": "Разобрать смену",
      "kind": "async",
      "actor": "barber",
      "guard": "Incident с дедупликацией затронутых booking.",
      "handoff": true,
      "event": "workforce.b08_o15",
      "frontend": "Показать затронутые визиты и варианты замены.",
      "backend": "Freeze affected slots; incident batch с индивидуальным решением по каждому booking, дедупликация сообщений."
    },
    {
      "id": "B09-O15",
      "source": "B09",
      "target": "O15",
      "label": "Рассчитать задержку",
      "kind": "async",
      "actor": "barber",
      "guard": "Не сокращать услугу клиента без согласия.",
      "handoff": true,
      "event": "workforce.b09_o15",
      "frontend": "Показать затронутые визиты и варианты замены.",
      "backend": "Freeze affected slots; incident batch с индивидуальным решением по каждому booking, дедупликация сообщений."
    },
    {
      "id": "O13-O19",
      "source": "O13",
      "target": "O19",
      "label": "В филиале авария",
      "kind": "exception",
      "actor": "owner",
      "guard": "Пауза новых бронирований, известный период недоступности.",
      "handoff": false,
      "event": "operations.o13_o19",
      "frontend": "Отключение воды, света, оборудования, погода: приостановить запись.",
      "backend": "Branch incident; затронутые визиты → предложение/возврат, запрет новых hold, владельцу список незавершённых компенсаций."
    },
    {
      "id": "O19-O15",
      "source": "O19",
      "target": "O15",
      "label": "Разобрать затронутые визиты",
      "kind": "async",
      "actor": "owner",
      "guard": "Каждый booking получает отдельное решение/компенсацию.",
      "handoff": false,
      "event": "operations.o19_o15",
      "frontend": "Показать затронутые визиты и варианты замены.",
      "backend": "Freeze affected slots; incident batch с индивидуальным решением по каждому booking, дедупликация сообщений."
    },
    {
      "id": "O15-O16",
      "source": "O15",
      "target": "O16",
      "label": "Предложить замену",
      "kind": "recovery",
      "actor": "system",
      "guard": "Есть подходящий барбер и ресурс.",
      "handoff": false,
      "event": "operations.o15_o16",
      "frontend": "Предложить другого барбера/время или отмену.",
      "backend": "Никакой тихой замены: consent клиента, новая quote при изменении цены, transfer booking атомарно."
    },
    {
      "id": "O15-C24",
      "source": "O15",
      "target": "C24",
      "label": "Нет замены — предложить отмену",
      "kind": "recovery",
      "actor": "system",
      "guard": "Инициатор салон; refund по опубликованной политике, клиент информирован.",
      "handoff": true,
      "event": "operations.o15_c24",
      "frontend": "Ясно показать сумму возврата/обязательства и причины без обязательного диагноза.",
      "backend": "Cancellation quote по policy snapshot; версия+auth; штрафы не включать без утверждённого правила."
    },
    {
      "id": "O16-C22",
      "source": "O16",
      "target": "C22",
      "label": "Клиент выбирает перенос",
      "kind": "handoff",
      "actor": "owner",
      "guard": "Согласие клиента, подходящий навык/ресурс; новое ценовое предложение при разнице.",
      "handoff": true,
      "event": "operations.o16_c22",
      "frontend": "Выбрать новый слот и увидеть разницу цены/условий.",
      "backend": "Исходный визит остаётся подтверждённым до атомарной замены; new quote при изменении состава."
    },
    {
      "id": "O16-C24",
      "source": "O16",
      "target": "C24",
      "label": "Клиент отказался",
      "kind": "recovery",
      "actor": "owner",
      "guard": "Нельзя заменить барбера без согласия.",
      "handoff": true,
      "event": "operations.o16_c24",
      "frontend": "Ясно показать сумму возврата/обязательства и причины без обязательного диагноза.",
      "backend": "Cancellation quote по policy snapshot; версия+auth; штрафы не включать без утверждённого правила."
    },
    {
      "id": "O13-O17",
      "source": "O13",
      "target": "O17",
      "label": "Завершить работу с мастером",
      "kind": "happy",
      "actor": "owner",
      "guard": "Owner step-up, scope и план будущих визитов.",
      "handoff": false,
      "event": "operations.o13_o17",
      "frontend": "Дата окончания, будущие визиты, расчёт и отзыв прав.",
      "backend": "Membership.revoking; закрыть новые слоты, подготовить перенос, revoke sessions, сохранить audit."
    },
    {
      "id": "B06-B22",
      "source": "B06",
      "target": "B22",
      "label": "Сообщить об уходе",
      "kind": "happy",
      "actor": "barber",
      "guard": "Свой membership, дата и handover.",
      "handoff": false,
      "event": "workforce.b06_b22",
      "frontend": "Сообщить дату и передать будущие визиты.",
      "backend": "Exit request не удаляет историю и не забирает клиентские фото; owner завершает offboarding."
    },
    {
      "id": "B22-O17",
      "source": "B22",
      "target": "O17",
      "label": "Начать завершение сотрудничества",
      "kind": "handoff",
      "actor": "barber",
      "guard": "Владелец видит запрос, не автоматическое удаление.",
      "handoff": true,
      "event": "workforce.b22_o17",
      "frontend": "Дата окончания, будущие визиты, расчёт и отзыв прав.",
      "backend": "Membership.revoking; закрыть новые слоты, подготовить перенос, revoke sessions, сохранить audit."
    },
    {
      "id": "O17-O15",
      "source": "O17",
      "target": "O15",
      "label": "Передать будущие визиты",
      "kind": "async",
      "actor": "owner",
      "guard": "Все неоказанные визиты включены в batch.",
      "handoff": false,
      "event": "operations.o17_o15",
      "frontend": "Показать затронутые визиты и варианты замены.",
      "backend": "Freeze affected slots; incident batch с индивидуальным решением по каждому booking, дедупликация сообщений."
    },
    {
      "id": "O17-O18",
      "source": "O17",
      "target": "O18",
      "label": "Отозвать доступ",
      "kind": "happy",
      "actor": "owner",
      "guard": "Немедленно при риске, иначе по дате; обязательства остаются в incident queue.",
      "handoff": false,
      "event": "operations.o17_o18",
      "frontend": "Показать завершённую процедуру и оставшиеся обязательства.",
      "backend": "Отмена membership немедленно на API; общие паспорта остаются у клиента, staff media cache истекает."
    },
    {
      "id": "O18-O21",
      "source": "O18",
      "target": "O21",
      "label": "Сверить окончательный расчёт",
      "kind": "happy",
      "actor": "system",
      "guard": "Нет потери ledger и возвратов.",
      "handoff": false,
      "event": "operations.o18_o21",
      "frontend": "Выручка, возвраты, чаевые отдельно, начисление по версии договора.",
      "backend": "Payroll ledger и период; ЮKassa merchant settlement не является зарплатой. Выплата отдельным подтверждённым каналом."
    },
    {
      "id": "O18-O06",
      "source": "O18",
      "target": "O06",
      "label": "Нанять замену",
      "kind": "happy",
      "actor": "system",
      "guard": "Новая вакансия, не перенос credentials старого мастера.",
      "handoff": false,
      "event": "operations.o18_o06",
      "frontend": "Описать навыки, загрузку, условия и этапы отбора.",
      "backend": "Vacancy/candidate consent; не публиковать персональные данные кандидата в клиентский каталог."
    },
    {
      "id": "O13-O22",
      "source": "O13",
      "target": "O22",
      "label": "Сверить деньги",
      "kind": "happy",
      "actor": "owner",
      "guard": "Owner finance capability.",
      "handoff": false,
      "event": "operations.o13_o22",
      "frontend": "Платежи, касса, возвраты, чеки и банковские поступления раздельно.",
      "backend": "Reconciliation job; сумма заказа ≠ выручка после возвратов ≠ merchant settlement; расхождение → case."
    },
    {
      "id": "O22-O21",
      "source": "O22",
      "target": "O21",
      "label": "Подготовить начисления",
      "kind": "happy",
      "actor": "system",
      "guard": "Учтены settled/refunded операции, правила договора имеют версию.",
      "handoff": false,
      "event": "operations.o22_o21",
      "frontend": "Выручка, возвраты, чаевые отдельно, начисление по версии договора.",
      "backend": "Payroll ledger и период; ЮKassa merchant settlement не является зарплатой. Выплата отдельным подтверждённым каналом."
    },
    {
      "id": "O21-B20",
      "source": "O21",
      "target": "B20",
      "label": "Проверить свой расчёт",
      "kind": "handoff",
      "actor": "owner",
      "guard": "Только свой statement, без чужих персональных данных.",
      "handoff": true,
      "event": "operations.o21_b20",
      "frontend": "Свои услуги, возвраты, чаевые и расчёт периода.",
      "backend": "Scoped earnings view; acknowledge либо dispute, staff не видит чужие начисления."
    },
    {
      "id": "B20-O22",
      "source": "B20",
      "target": "O22",
      "label": "Есть расхождение",
      "kind": "exception",
      "actor": "barber",
      "guard": "Dispute с evidence, исходный ledger не редактируется задним числом.",
      "handoff": true,
      "event": "workforce.b20_o22",
      "frontend": "Платежи, касса, возвраты, чеки и банковские поступления раздельно.",
      "backend": "Reconciliation job; сумма заказа ≠ выручка после возвратов ≠ merchant settlement; расхождение → case."
    },
    {
      "id": "B20-O23",
      "source": "B20",
      "target": "O23",
      "label": "Подтвердить расчёт",
      "kind": "happy",
      "actor": "barber",
      "guard": "Подтверждение statement не является банковской выплатой.",
      "handoff": true,
      "event": "workforce.b20_o23",
      "frontend": "Конверсия, загрузка, повторы, отмены, качество без рейтинговой гонки.",
      "backend": "Агрегаты из событий, исключить технические дубли, cohort attribution; новые правила только следующей версией."
    },
    {
      "id": "O23-O03",
      "source": "O23",
      "target": "O03",
      "label": "Улучшить услуги",
      "kind": "happy",
      "actor": "owner",
      "guard": "Новая версия не меняет старые quote/заказы.",
      "handoff": false,
      "event": "operations.o23_o03",
      "frontend": "Услуги, навыки, длительность, перерывы, цена.",
      "backend": "ServiceVersion: integer minor units/RUB, skill requirements, equipment, duration и buffer."
    },
    {
      "id": "O23-O06",
      "source": "O23",
      "target": "O06",
      "label": "Расширить команду",
      "kind": "happy",
      "actor": "owner",
      "guard": "Новая потребность в найме.",
      "handoff": false,
      "event": "operations.o23_o06",
      "frontend": "Описать навыки, загрузку, условия и этапы отбора.",
      "backend": "Vacancy/candidate consent; не публиковать персональные данные кандидата в клиентский каталог."
    },
    {
      "id": "O13-O24",
      "source": "O13",
      "target": "O24",
      "label": "Передать владение",
      "kind": "happy",
      "actor": "owner",
      "guard": "Двойное подтверждение identity и прав, MFA.",
      "handoff": false,
      "event": "operations.o13_o24",
      "frontend": "Усиленная проверка обеих сторон и подтверждение передачи.",
      "backend": "Не оставлять организацию без владельца; атомарная замена grant, аудит, отзыв старых полномочий."
    },
    {
      "id": "O24-O13",
      "source": "O24",
      "target": "O13",
      "label": "Завершить передачу",
      "kind": "happy",
      "actor": "owner",
      "guard": "Новый owner grant записан атомарно, старые сессии отозваны.",
      "handoff": false,
      "event": "operations.o24_o13",
      "frontend": "Нагрузка, исключения, обращения, незакрытые оплаты.",
      "backend": "Read model по филиалу; только разрешённые персональные данные. Нет подмены банковского статуса."
    },
    {
      "id": "A00-A02",
      "source": "A00",
      "target": "A02",
      "label": "Выбрать Яндекс",
      "kind": "happy",
      "actor": "guest",
      "guard": "Registered redirect URI, state и PKCE.",
      "handoff": false,
      "event": "identity.a00_a02",
      "frontend": "Запросить минимальный набор данных.",
      "backend": "Authorization code + PKCE S256, state и точный redirect URI; server exchange и user identity API."
    },
    {
      "id": "A00-A03",
      "source": "A00",
      "target": "A03",
      "label": "Выбрать MAX",
      "kind": "happy",
      "actor": "guest",
      "guard": "Только если integration gate пройден; mini-app + trusted one-use handoff.",
      "handoff": false,
      "event": "identity.a00_a03",
      "frontend": "Открыть mini-app, подтвердить связку, вернуться в PRIME.",
      "backend": "Условный адаптер: проверить initData HMAC/auth_date и одноразовый challenge; standalone OIDC не предполагается. Feature gate до end-to-end spike."
    },
    {
      "id": "A02-A04",
      "source": "A02",
      "target": "A04",
      "label": "Вернуться из Яндекса",
      "kind": "async",
      "actor": "guest",
      "guard": "Exchange code сервером, связать state/PKCE.",
      "handoff": false,
      "event": "identity.a02_a04",
      "frontend": "Ожидать завершения, не показывать вход раньше сервера.",
      "backend": "Consume state один раз, токены на сервере/защищённом хранилище; stale/replay/issuer mismatch отвергнуть."
    },
    {
      "id": "A03-A04",
      "source": "A03",
      "target": "A04",
      "label": "Вернуться из MAX",
      "kind": "async",
      "actor": "guest",
      "guard": "Backend validated initData + freshness + challenge; не доверять initDataUnsafe.",
      "handoff": false,
      "event": "identity.a03_a04",
      "frontend": "Ожидать завершения, не показывать вход раньше сервера.",
      "backend": "Consume state один раз, токены на сервере/защищённом хранилище; stale/replay/issuer mismatch отвергнуть."
    },
    {
      "id": "A01-A05",
      "source": "A01",
      "target": "A05",
      "label": "Отменить или не получить ответ",
      "kind": "exception",
      "actor": "guest",
      "guard": "Не создавать account/session без проверки.",
      "handoff": false,
      "event": "identity.a01_a05",
      "frontend": "Повторить, выбрать другой способ или продолжить гостем.",
      "backend": "Закрыть AuthTransaction, не создавать пустой дубликат аккаунта."
    },
    {
      "id": "A02-A05",
      "source": "A02",
      "target": "A05",
      "label": "Отказать Яндексу",
      "kind": "exception",
      "actor": "guest",
      "guard": "Закрыть transaction, сохранить безопасный draft.",
      "handoff": false,
      "event": "identity.a02_a05",
      "frontend": "Повторить, выбрать другой способ или продолжить гостем.",
      "backend": "Закрыть AuthTransaction, не создавать пустой дубликат аккаунта."
    },
    {
      "id": "A03-A05",
      "source": "A03",
      "target": "A05",
      "label": "MAX недоступен",
      "kind": "exception",
      "actor": "guest",
      "guard": "Feature gate/нет приложения/невалидная подпись → другой способ.",
      "handoff": false,
      "event": "identity.a03_a05",
      "frontend": "Повторить, выбрать другой способ или продолжить гостем.",
      "backend": "Закрыть AuthTransaction, не создавать пустой дубликат аккаунта."
    },
    {
      "id": "A04-A05",
      "source": "A04",
      "target": "A05",
      "label": "Ответ не прошёл проверку",
      "kind": "exception",
      "actor": "system",
      "guard": "Replay, expiry, state mismatch, недоступный provider; не утекать деталями identity.",
      "handoff": false,
      "event": "identity.a04_a05",
      "frontend": "Повторить, выбрать другой способ или продолжить гостем.",
      "backend": "Закрыть AuthTransaction, не создавать пустой дубликат аккаунта."
    },
    {
      "id": "A05-A00",
      "source": "A05",
      "target": "A00",
      "label": "Выбрать другой способ",
      "kind": "recovery",
      "actor": "guest",
      "guard": "Новая auth transaction; один принятый callback.",
      "handoff": false,
      "event": "identity.a05_a00",
      "frontend": "Telegram, Яндекс; MAX при готовом канале. Отказ не удаляет черновик.",
      "backend": "AuthTransaction с state/expiry/continuation. Ни один provider не задаёт роль сотрудника."
    },
    {
      "id": "A05-G00",
      "source": "A05",
      "target": "G00",
      "label": "Остаться гостем",
      "kind": "exit",
      "actor": "guest",
      "guard": "Никаких staff или private client данных.",
      "handoff": false,
      "event": "identity.a05_g00",
      "frontend": "Посмотреть концепцию, филиал и цены без регистрации.",
      "backend": "Публичный каталог без PII, rate limits; аналитика без присвоения клиентской личности."
    },
    {
      "id": "A06-G00",
      "source": "A06",
      "target": "G00",
      "label": "Не принимать обязательные условия",
      "kind": "exit",
      "actor": "client",
      "guard": "Не активировать account; draft не создаёт заказ.",
      "handoff": true,
      "event": "identity.a06_g00",
      "frontend": "Посмотреть концепцию, филиал и цены без регистрации.",
      "backend": "Публичный каталог без PII, rate limits; аналитика без присвоения клиентской личности."
    },
    {
      "id": "A07-C09",
      "source": "A07",
      "target": "C09",
      "label": "Продолжить сохранённую запись",
      "kind": "happy",
      "actor": "system",
      "guard": "Draft complete; quote/hold предварительно переоценены, иначе к C03.",
      "handoff": false,
      "event": "identity.a07_c09",
      "frontend": "Мастер, филиал, дата, цена, контакт, условия и способ оплаты.",
      "backend": "Guard quote/hold/policy/consent/contact; business command только после явного подтверждения."
    },
    {
      "id": "C00-C01",
      "source": "C00",
      "target": "C01",
      "label": "Искать образ",
      "kind": "happy",
      "actor": "client",
      "guard": "Consent для public portfolio.",
      "handoff": false,
      "event": "booking.c00_c01",
      "frontend": "Портфолио, вариант следующей формы и пожелания.",
      "backend": "Style reference связан с доступными услугами, не обещать гарантированный результат по фото."
    },
    {
      "id": "C01-C03",
      "source": "C01",
      "target": "C03",
      "label": "Выбрать услуги образа",
      "kind": "happy",
      "actor": "client",
      "guard": "Референс — пожелание, услуги согласуются.",
      "handoff": false,
      "event": "booking.c01_c03",
      "frontend": "Длительность и сумма меняются вместе; дополнительные пожелания.",
      "backend": "Server quote по ServiceVersion, скидки/клуб валидируются сервером; zero/negative duration запрещены."
    },
    {
      "id": "C00-C02",
      "source": "C00",
      "target": "C02",
      "label": "Сначала мастер",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверка актуальности профиля.",
      "handoff": false,
      "event": "booking.c00_c02",
      "frontend": "Навыки, ближайшее время или первый свободный.",
      "backend": "Service skills, branch, active membership; retired stylist → альтернативы без автоматической замены."
    },
    {
      "id": "C00-C04",
      "source": "C00",
      "target": "C04",
      "label": "Сначала время",
      "kind": "happy",
      "actor": "client",
      "guard": "Для финального расчёта обязательны услуги и ресурс.",
      "handoff": false,
      "event": "booking.c00_c04",
      "frontend": "Умные слоты, другой день/филиал, лист ожидания.",
      "backend": "Availability с креслом, навыком, сменой, буфером и существующими hold; время сервера."
    },
    {
      "id": "C00-C05",
      "source": "C00",
      "target": "C05",
      "label": "Повторить результат",
      "kind": "happy",
      "actor": "client",
      "guard": "Есть доступный свой паспорт; иначе новый подбор.",
      "handoff": false,
      "event": "booking.c00_c05",
      "frontend": "Открыть прошлый паспорт и уточнить изменения.",
      "backend": "Reference to passport version; проверить доступность мастера, актуальные услуги и цену, не копировать старую оплату."
    },
    {
      "id": "C04-C13",
      "source": "C04",
      "target": "C13",
      "label": "Нет удобного окна",
      "kind": "recovery",
      "actor": "client",
      "guard": "Consent на ограниченные уведомления waitlist.",
      "handoff": false,
      "event": "booking.c04_c13",
      "frontend": "Дни, мастер, диапазон времени, допустимый контакт и срок.",
      "backend": "Waitlist request с expiry/consent; без удержания средств и без гарантии места."
    },
    {
      "id": "C13-C14",
      "source": "C13",
      "target": "C14",
      "label": "Освободился подходящий слот",
      "kind": "async",
      "actor": "client",
      "guard": "Matching criteria, fairness, offer expiry; не auto-book.",
      "handoff": false,
      "event": "booking.c13_c14",
      "frontend": "Принять до указанного срока или отказаться.",
      "backend": "Временное предложение одному кандидату или атомарный first-claim; offer ≠ confirmed booking."
    },
    {
      "id": "C13-C00",
      "source": "C13",
      "target": "C00",
      "label": "Выйти из листа",
      "kind": "exit",
      "actor": "client",
      "guard": "Отменить waitlist и pending offers.",
      "handoff": false,
      "event": "booking.c13_c00",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache."
    },
    {
      "id": "C14-C06",
      "source": "C14",
      "target": "C06",
      "label": "Принять окно",
      "kind": "happy",
      "actor": "client",
      "guard": "Offer ещё действителен; новая quote и atomic hold.",
      "handoff": false,
      "event": "booking.c14_c06",
      "frontend": "Показать полную цену, предоплату/оплату на месте и правила.",
      "backend": "Immutable Quote: price/duration/policyVersion/currency/expiresAt; stale quote требует нового подтверждения."
    },
    {
      "id": "C14-C15",
      "source": "C14",
      "target": "C15",
      "label": "Не ответить вовремя",
      "kind": "exception",
      "actor": "client",
      "guard": "Server deadline, освободить offer exactly once.",
      "handoff": false,
      "event": "booking.c14_c15",
      "frontend": "Остаться в листе, изменить пожелания или выйти.",
      "backend": "Release offer/hold once; fairness и dedupe, не слать одно окно бесконечно."
    },
    {
      "id": "C14-C13",
      "source": "C14",
      "target": "C13",
      "label": "Отказаться и ждать дальше",
      "kind": "recovery",
      "actor": "client",
      "guard": "Rate limit уведомлений, обновить критерии по желанию.",
      "handoff": false,
      "event": "booking.c14_c13",
      "frontend": "Дни, мастер, диапазон времени, допустимый контакт и срок.",
      "backend": "Waitlist request с expiry/consent; без удержания средств и без гарантии места."
    },
    {
      "id": "C15-C13",
      "source": "C15",
      "target": "C13",
      "label": "Продолжить ожидание",
      "kind": "recovery",
      "actor": "client",
      "guard": "Request ещё действителен, максимум повторов ограничен.",
      "handoff": false,
      "event": "booking.c15_c13",
      "frontend": "Дни, мастер, диапазон времени, допустимый контакт и срок.",
      "backend": "Waitlist request с expiry/consent; без удержания средств и без гарантии места."
    },
    {
      "id": "C15-C00",
      "source": "C15",
      "target": "C00",
      "label": "Закончить ожидание",
      "kind": "exit",
      "actor": "client",
      "guard": "Нет held capacity и pending payment.",
      "handoff": false,
      "event": "booking.c15_c00",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache."
    },
    {
      "id": "S01-C08",
      "source": "S01",
      "target": "C08",
      "label": "Ресурс недоступен",
      "kind": "exception",
      "actor": "system",
      "guard": "Conflict authoritative, старый quote не подтверждается.",
      "handoff": false,
      "event": "reliability.s01_c08",
      "frontend": "Сохранить услуги и предложить соседние окна.",
      "backend": "409 conflict → свежая availability; не создавать второй charge и не удалять существующий визит."
    },
    {
      "id": "C07-C08",
      "source": "C07",
      "target": "C08",
      "label": "Не удалось удержать",
      "kind": "exception",
      "actor": "system",
      "guard": "Atomic claim проиграл гонку; средства не списывать.",
      "handoff": false,
      "event": "booking.c07_c08",
      "frontend": "Сохранить услуги и предложить соседние окна.",
      "backend": "409 conflict → свежая availability; не создавать второй charge и не удалять существующий визит."
    },
    {
      "id": "C07-C16",
      "source": "C07",
      "target": "C16",
      "label": "Время выбора истекло",
      "kind": "exception",
      "actor": "system",
      "guard": "Release hold by TTL; начатый платёж отправляется на reconciliation.",
      "handoff": false,
      "event": "booking.c07_c16",
      "frontend": "Вернуться или закрыть; показать реальные незавершённые операции.",
      "backend": "Если платежа нет — release hold; если payment pending — отмена intent + reconcile, не забывать платеж."
    },
    {
      "id": "C08-C04",
      "source": "C08",
      "target": "C04",
      "label": "Выбрать другое окно",
      "kind": "recovery",
      "actor": "client",
      "guard": "Сохранить service/master intent, обновить availability.",
      "handoff": false,
      "event": "booking.c08_c04",
      "frontend": "Умные слоты, другой день/филиал, лист ожидания.",
      "backend": "Availability с креслом, навыком, сменой, буфером и существующими hold; время сервера."
    },
    {
      "id": "C09-C03",
      "source": "C09",
      "target": "C03",
      "label": "Изменить услуги",
      "kind": "recovery",
      "actor": "client",
      "guard": "Отпустить hold, новая длительность/quote.",
      "handoff": false,
      "event": "booking.c09_c03",
      "frontend": "Длительность и сумма меняются вместе; дополнительные пожелания.",
      "backend": "Server quote по ServiceVersion, скидки/клуб валидируются сервером; zero/negative duration запрещены."
    },
    {
      "id": "C09-C16",
      "source": "C09",
      "target": "C16",
      "label": "Отказаться до подтверждения",
      "kind": "exit",
      "actor": "client",
      "guard": "Не отменять уже состоявшийся payment молча.",
      "handoff": false,
      "event": "booking.c09_c16",
      "frontend": "Вернуться или закрыть; показать реальные незавершённые операции.",
      "backend": "Если платежа нет — release hold; если payment pending — отмена intent + reconcile, не забывать платеж."
    },
    {
      "id": "C16-C00",
      "source": "C16",
      "target": "C00",
      "label": "Завершить без операции",
      "kind": "exit",
      "actor": "client",
      "guard": "Нет pending payment; hold released.",
      "handoff": false,
      "event": "booking.c16_c00",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache."
    },
    {
      "id": "C16-P13",
      "source": "C16",
      "target": "P13",
      "label": "Сверить уже начатую оплату",
      "kind": "recovery",
      "actor": "client",
      "guard": "Persisted operation exists; cancellation intent сохранён.",
      "handoff": false,
      "event": "booking.c16_p13",
      "frontend": "Обновить результат из сервера.",
      "backend": "GET provider + local operation/ledger, compare order amount; after idempotency window не повторять create вслепую."
    },
    {
      "id": "C10-C11",
      "source": "C10",
      "target": "C11",
      "label": "Ответ сервера потерян",
      "kind": "exception",
      "actor": "system",
      "guard": "Сохраняется operationId; запрещён новый create наугад.",
      "handoff": false,
      "event": "booking.c10_c11",
      "frontend": "Не нажимать повторную оплату; показать сверку и request ID.",
      "backend": "GET operation by id, bounded reconciliation, ни failure ни success не выводятся из timeout."
    },
    {
      "id": "C11-S03",
      "source": "C11",
      "target": "S03",
      "label": "Узнать результат",
      "kind": "recovery",
      "actor": "client",
      "guard": "GET operationId, не повторять charge с новым ключом.",
      "handoff": false,
      "event": "booking.c11_s03",
      "frontend": "Сначала сверить актуальный статус, затем продолжить.",
      "backend": "Fetch operations/bookings revision, apply monotonic state, dedupe pending commands, refresh auth если истекла."
    },
    {
      "id": "S00-C08",
      "source": "S00",
      "target": "C08",
      "label": "Запись конфликтует",
      "kind": "exception",
      "actor": "system",
      "guard": "Нет successful payment; release resources/entitlement.",
      "handoff": false,
      "event": "reliability.s00_c08",
      "frontend": "Сохранить услуги и предложить соседние окна.",
      "backend": "409 conflict → свежая availability; не создавать второй charge и не удалять существующий визит."
    },
    {
      "id": "S00-P25",
      "source": "S00",
      "target": "P25",
      "label": "Оплачено, а слота нет",
      "kind": "exception",
      "actor": "system",
      "guard": "Оплата подтверждена, booking commit невозможен → compensation saga.",
      "handoff": true,
      "event": "reliability.s00_p25",
      "frontend": "Объяснить ситуацию, предложить согласованное окно или возврат.",
      "backend": "Paid-unallocated saga; никогда не double-book. Refund обязательной компенсацией при невозможности подтвердить услугу."
    },
    {
      "id": "C12-C21",
      "source": "C12",
      "target": "C21",
      "label": "Управлять записью",
      "kind": "happy",
      "actor": "client",
      "guard": "Own confirmed booking.",
      "handoff": false,
      "event": "booking.c12_c21",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние."
    },
    {
      "id": "C12-C44",
      "source": "C12",
      "target": "C44",
      "label": "Добавить важные пожелания",
      "kind": "happy",
      "actor": "client",
      "guard": "Добровольно, scope и retention.",
      "handoff": false,
      "event": "booking.c12_c44",
      "frontend": "Тишина, доступность, сопровождающий, аллергия по желанию.",
      "backend": "Минимизация чувствительных данных, ограниченный срок и scope; подтвердить доступность услуги у филиала."
    },
    {
      "id": "C44-C17",
      "source": "C44",
      "target": "C17",
      "label": "Сохранить пожелания",
      "kind": "happy",
      "actor": "client",
      "guard": "Реальная доступность услуги подтверждается сотрудником.",
      "handoff": false,
      "event": "booking.c44_c17",
      "frontend": "Референс, что сохранить, тишина/общение и доступность.",
      "backend": "Visit preferences versioned, минимальные данные; отсутствие референса не блокирует услугу."
    },
    {
      "id": "C17-C18",
      "source": "C17",
      "target": "C18",
      "label": "Добавить референс",
      "kind": "happy",
      "actor": "client",
      "guard": "Разрешение ОС и consent на private storage.",
      "handoff": false,
      "event": "booking.c17_c18",
      "frontend": "Выбор камеры/галереи и отдельное согласие на хранение.",
      "backend": "Scoped upload session, content limits, metadata stripping, private media; photo consent не равно portfolio consent."
    },
    {
      "id": "C17-C19",
      "source": "C17",
      "target": "C19",
      "label": "Обойтись без фото",
      "kind": "happy",
      "actor": "client",
      "guard": "Текстовый путь равноценен.",
      "handoff": false,
      "event": "booking.c17_c19",
      "frontend": "Продолжить текстом без наказания за отказ.",
      "backend": "Не читать камеру/галерею, не создавать media; разрешение ОС и согласие хранения независимы."
    },
    {
      "id": "C18-C20",
      "source": "C18",
      "target": "C20",
      "label": "Ошибка загрузки",
      "kind": "exception",
      "actor": "client",
      "guard": "Draft остаётся локально, отсутствие фото не отменяет booking.",
      "handoff": false,
      "event": "booking.c18_c20",
      "frontend": "Сохранить локальный черновик, повторить или удалить.",
      "backend": "Идемпотентный upload finalize; orphan cleanup по TTL, отказ не отменяет booking."
    },
    {
      "id": "C18-C21",
      "source": "C18",
      "target": "C21",
      "label": "Фото сохранено",
      "kind": "happy",
      "actor": "client",
      "guard": "Server finalize confirmed, private object assigned to booking.",
      "handoff": false,
      "event": "booking.c18_c21",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние."
    },
    {
      "id": "C19-C21",
      "source": "C19",
      "target": "C21",
      "label": "Продолжить без фото",
      "kind": "happy",
      "actor": "client",
      "guard": "No media effects.",
      "handoff": false,
      "event": "booking.c19_c21",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние."
    },
    {
      "id": "C20-C18",
      "source": "C20",
      "target": "C18",
      "label": "Повторить загрузку",
      "kind": "recovery",
      "actor": "client",
      "guard": "Тот же upload intent, без дублирования файлов.",
      "handoff": false,
      "event": "booking.c20_c18",
      "frontend": "Выбор камеры/галереи и отдельное согласие на хранение.",
      "backend": "Scoped upload session, content limits, metadata stripping, private media; photo consent не равно portfolio consent."
    },
    {
      "id": "C20-C19",
      "source": "C20",
      "target": "C19",
      "label": "Удалить черновик фото",
      "kind": "exit",
      "actor": "client",
      "guard": "Delete local draft + revoke orphan upload.",
      "handoff": false,
      "event": "booking.c20_c19",
      "frontend": "Продолжить текстом без наказания за отказ.",
      "backend": "Не читать камеру/галерею, не создавать media; разрешение ОС и согласие хранения независимы."
    },
    {
      "id": "C21-C22",
      "source": "C21",
      "target": "C22",
      "label": "Перенести",
      "kind": "happy",
      "actor": "client",
      "guard": "Booking movable, показать policy snapshot.",
      "handoff": false,
      "event": "booking.c21_c22",
      "frontend": "Выбрать новый слот и увидеть разницу цены/условий.",
      "backend": "Исходный визит остаётся подтверждённым до атомарной замены; new quote при изменении состава."
    },
    {
      "id": "C22-C23",
      "source": "C22",
      "target": "C23",
      "label": "Выбрать новый слот",
      "kind": "happy",
      "actor": "client",
      "guard": "New hold valid, old booking сохранён до commit.",
      "handoff": false,
      "event": "booking.c22_c23",
      "frontend": "Показать новое время после ответа сервера.",
      "backend": "Atomic move hold→booking and release old; компенсировать разницу платежа отдельной saga; cancel старых reminders."
    },
    {
      "id": "C23-C12",
      "source": "C23",
      "target": "C12",
      "label": "Перенос подтверждён",
      "kind": "happy",
      "actor": "system",
      "guard": "Atomic move, reminders replaced, payment delta tracked.",
      "handoff": false,
      "event": "booking.c23_c12",
      "frontend": "Подтверждённый booking ID, адрес, календарь, подготовка.",
      "backend": "Только authoritative confirmed; outbox reminders; оплачено/к оплате показывается отдельно."
    },
    {
      "id": "C23-C08",
      "source": "C23",
      "target": "C08",
      "label": "Новое окно заняли",
      "kind": "exception",
      "actor": "system",
      "guard": "Исходный booking сохранён; показать его рядом с альтернативами.",
      "handoff": false,
      "event": "booking.c23_c08",
      "frontend": "Сохранить услуги и предложить соседние окна.",
      "backend": "409 conflict → свежая availability; не создавать второй charge и не удалять существующий визит."
    },
    {
      "id": "C22-C21",
      "source": "C22",
      "target": "C21",
      "label": "Передумать переносить",
      "kind": "exit",
      "actor": "client",
      "guard": "Release new hold, оставить исходный booking.",
      "handoff": false,
      "event": "booking.c22_c21",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние."
    },
    {
      "id": "C21-C24",
      "source": "C21",
      "target": "C24",
      "label": "Отменить",
      "kind": "happy",
      "actor": "client",
      "guard": "Cancellation quote актуален.",
      "handoff": false,
      "event": "booking.c21_c24",
      "frontend": "Ясно показать сумму возврата/обязательства и причины без обязательного диагноза.",
      "backend": "Cancellation quote по policy snapshot; версия+auth; штрафы не включать без утверждённого правила."
    },
    {
      "id": "C24-C25",
      "source": "C24",
      "target": "C25",
      "label": "Подтвердить отмену",
      "kind": "happy",
      "actor": "client",
      "guard": "Version guard, принятое cancellation intent.",
      "handoff": false,
      "event": "booking.c24_c25",
      "frontend": "Статус отмены и отдельно ход возврата.",
      "backend": "Cancel booking, release resource, outbox waitlist, cancel reminders; refund pending не объявлять refunded."
    },
    {
      "id": "C24-C21",
      "source": "C24",
      "target": "C21",
      "label": "Сохранить визит",
      "kind": "exit",
      "actor": "client",
      "guard": "Никакой отмены до подтверждения.",
      "handoff": false,
      "event": "booking.c24_c21",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние."
    },
    {
      "id": "C25-P16",
      "source": "C25",
      "target": "P16",
      "label": "Вернуть предоплату",
      "kind": "async",
      "actor": "system",
      "guard": "Есть entitlement на refund и captured amount; cash/club отдельные ledger.",
      "handoff": false,
      "event": "booking.c25_p16",
      "frontend": "Сумма, основание и статус рассмотрения.",
      "backend": "Refund entitlement/order version; сумма ≤ captured − successful/pending refunds. Не объявлять деньги возвращёнными при создании."
    },
    {
      "id": "C25-C40",
      "source": "C25",
      "target": "C40",
      "label": "Выбрать другой день",
      "kind": "happy",
      "actor": "system",
      "guard": "Отмена confirmed, возврат может продолжаться независимо.",
      "handoff": false,
      "event": "booking.c25_c40",
      "frontend": "Предложить подходящий интервал, дату выбирает человек.",
      "backend": "New booking intent, связи previousVisitId/cohort; никакого авто-бронирования из напоминания."
    },
    {
      "id": "C25-C13",
      "source": "C25",
      "target": "C13",
      "label": "Предложить освободившееся окно",
      "kind": "async",
      "actor": "system",
      "guard": "Waitlist event; получатель другой клиент, права не передаются.",
      "handoff": false,
      "event": "booking.c25_c13",
      "frontend": "Дни, мастер, диапазон времени, допустимый контакт и срок.",
      "backend": "Waitlist request с expiry/consent; без удержания средств и без гарантии места."
    },
    {
      "id": "C21-C26",
      "source": "C21",
      "target": "C26",
      "label": "Я заболел",
      "kind": "exception",
      "actor": "client",
      "guard": "Без обязательного диагноза и автоматического штрафа.",
      "handoff": false,
      "event": "booking.c21_c26",
      "frontend": "Быстро перенести/отменить; пожелать восстановления, не требовать медицинских данных.",
      "backend": "Reason category optional, empathetic exception policy review; не начислять автоматический штраф."
    },
    {
      "id": "C26-C22",
      "source": "C26",
      "target": "C22",
      "label": "Выздороветь и перенести",
      "kind": "recovery",
      "actor": "client",
      "guard": "Показать доступные даты и условия.",
      "handoff": false,
      "event": "booking.c26_c22",
      "frontend": "Выбрать новый слот и увидеть разницу цены/условий.",
      "backend": "Исходный визит остаётся подтверждённым до атомарной замены; new quote при изменении состава."
    },
    {
      "id": "C26-C24",
      "source": "C26",
      "target": "C24",
      "label": "Отменить визит",
      "kind": "recovery",
      "actor": "client",
      "guard": "Причина optional, empathetic exception policy.",
      "handoff": false,
      "event": "booking.c26_c24",
      "frontend": "Ясно показать сумму возврата/обязательства и причины без обязательного диагноза.",
      "backend": "Cancellation quote по policy snapshot; версия+auth; штрафы не включать без утверждённого правила."
    },
    {
      "id": "C21-C27",
      "source": "C21",
      "target": "C27",
      "label": "Я опаздываю",
      "kind": "exception",
      "actor": "client",
      "guard": "ETA, следующий визит не сдвигается молча.",
      "handoff": false,
      "event": "booking.c21_c27",
      "frontend": "Сообщить примерное прибытие, увидеть варианты.",
      "backend": "Сравнить remaining service+buffer с next boundary; мастер/владелец подтверждает возможный scope."
    },
    {
      "id": "C27-B12",
      "source": "C27",
      "target": "B12",
      "label": "Мастер может принять",
      "kind": "handoff",
      "actor": "client",
      "guard": "Длительности хватает; scope и цена согласованы обеими сторонами.",
      "handoff": true,
      "event": "booking.c27_b12",
      "frontend": "Обсудить форму, тишину, чувствительность и цену до начала.",
      "backend": "Consultation snapshot; consent на изменение состава и цены, фото отдельным согласием."
    },
    {
      "id": "C27-C22",
      "source": "C27",
      "target": "C22",
      "label": "Не успеваем — перенести",
      "kind": "recovery",
      "actor": "client",
      "guard": "Старое окно освобождается только по accepted move/cancel.",
      "handoff": false,
      "event": "booking.c27_c22",
      "frontend": "Выбрать новый слот и увидеть разницу цены/условий.",
      "backend": "Исходный визит остаётся подтверждённым до атомарной замены; new quote при изменении состава."
    },
    {
      "id": "C27-C24",
      "source": "C27",
      "target": "C24",
      "label": "Не успеваем — отменить",
      "kind": "recovery",
      "actor": "client",
      "guard": "Показать cancellation quote; никаких silent charges.",
      "handoff": false,
      "event": "booking.c27_c24",
      "frontend": "Ясно показать сумму возврата/обязательства и причины без обязательного диагноза.",
      "backend": "Cancellation quote по policy snapshot; версия+auth; штрафы не включать без утверждённого правила."
    },
    {
      "id": "C21-C29",
      "source": "C21",
      "target": "C29",
      "label": "Я на месте",
      "kind": "happy",
      "actor": "client",
      "guard": "Правильный филиал и актуальная дата.",
      "handoff": false,
      "event": "booking.c21_c29",
      "frontend": "Показать визит, сообщить о прибытии; QR не обязателен.",
      "backend": "Проверить location/booking status, check-in сотрудником; геолокация не является доказательством услуги."
    },
    {
      "id": "C29-C30",
      "source": "C29",
      "target": "C30",
      "label": "Пришёл раньше",
      "kind": "happy",
      "actor": "client",
      "guard": "Без требования немедленного обслуживания.",
      "handoff": false,
      "event": "booking.c29_c30",
      "frontend": "Показать ожидание или согласованное раннее начало.",
      "backend": "Не занимать чужой интервал; early start только если ресурсы свободны и мастер согласен."
    },
    {
      "id": "C30-B11",
      "source": "C30",
      "target": "B11",
      "label": "Мастер готов раньше",
      "kind": "handoff",
      "actor": "client",
      "guard": "Ресурсы свободны, согласие обеих сторон.",
      "handoff": true,
      "event": "booking.c30_b11",
      "frontend": "Сверить клиента и услугу, отметить check-in.",
      "backend": "Booking confirmed → arrived; серверная отметка, повтор check-in идемпотентен."
    },
    {
      "id": "C30-C21",
      "source": "C30",
      "target": "C21",
      "label": "Подождать назначенного времени",
      "kind": "happy",
      "actor": "client",
      "guard": "Booking time не изменяется.",
      "handoff": false,
      "event": "booking.c30_c21",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние."
    },
    {
      "id": "C29-C31",
      "source": "C29",
      "target": "C31",
      "label": "Другой филиал / адрес",
      "kind": "exception",
      "actor": "client",
      "guard": "Проверить назначенный branch.",
      "handoff": false,
      "event": "booking.c29_c31",
      "frontend": "Показать правильный адрес и связаться с филиалом.",
      "backend": "Новый branch требует согласования ресурсов/цены; не подтверждать по GPS автоматически."
    },
    {
      "id": "C31-G08",
      "source": "C31",
      "target": "G08",
      "label": "Уточнить маршрут",
      "kind": "recovery",
      "actor": "client",
      "guard": "Публичный адрес нужного филиала.",
      "handoff": true,
      "event": "booking.c31_g08",
      "frontend": "Телефон, маршрут, часы; помощь без аккаунта.",
      "backend": "Контакт филиала из актуального каталога, не обещать состоявшийся звонок."
    },
    {
      "id": "C31-C27",
      "source": "C31",
      "target": "C27",
      "label": "Сообщить задержку",
      "kind": "recovery",
      "actor": "client",
      "guard": "Связаться с назначенным филиалом.",
      "handoff": false,
      "event": "booking.c31_c27",
      "frontend": "Сообщить примерное прибытие, увидеть варианты.",
      "backend": "Сравнить remaining service+buffer с next boundary; мастер/владелец подтверждает возможный scope."
    },
    {
      "id": "B06-B10",
      "source": "B06",
      "target": "B10",
      "label": "Открыть следующий визит",
      "kind": "happy",
      "actor": "barber",
      "guard": "Своя назначенная запись.",
      "handoff": false,
      "event": "workforce.b06_b10",
      "frontend": "Пожелания, разрешённый паспорт, ограничения и время.",
      "backend": "Проверить assignment и consent на каждый media URL; audit доступа, signed URL ограничен временем."
    },
    {
      "id": "B12-C24",
      "source": "B12",
      "target": "C24",
      "label": "Услуга не подходит",
      "kind": "exception",
      "actor": "barber",
      "guard": "До начала согласовать отмену и деньги.",
      "handoff": true,
      "event": "workforce.b12_c24",
      "frontend": "Ясно показать сумму возврата/обязательства и причины без обязательного диагноза.",
      "backend": "Cancellation quote по policy snapshot; версия+auth; штрафы не включать без утверждённого правила."
    },
    {
      "id": "B13-B14",
      "source": "B13",
      "target": "B14",
      "label": "Расширить услугу",
      "kind": "happy",
      "actor": "system",
      "guard": "Есть желание клиента; проверка времени и цены.",
      "handoff": false,
      "event": "workforce.b13_b14",
      "frontend": "Запросить дополнение, цену и длительность.",
      "backend": "Проверить следующий booking и ресурсы; approve клиента; при конфликте сократить согласованный scope или отдельный визит."
    },
    {
      "id": "B14-P23",
      "source": "B14",
      "target": "P23",
      "label": "Согласовать доплату",
      "kind": "happy",
      "actor": "barber",
      "guard": "Explicit consent, новая quote; нельзя списать старый token без intent.",
      "handoff": true,
      "event": "workforce.b14_p23",
      "frontend": "Показать согласованную разницу за изменённую услугу.",
      "backend": "Новая price revision, explicit consent; остаток pay/refund saga. Нельзя незаметно увеличить исходный charge."
    },
    {
      "id": "B14-C32",
      "source": "B14",
      "target": "C32",
      "label": "Продолжить прежний объём",
      "kind": "recovery",
      "actor": "barber",
      "guard": "Следующее окно защищено; additions отклонены без ухудшения исходной услуги.",
      "handoff": true,
      "event": "workforce.b14_c32",
      "frontend": "Видеть согласованный состав и возможность задать вопрос.",
      "backend": "in_service authoritative; аппликация может быть закрыта, состояние живёт на сервере."
    },
    {
      "id": "B13-B15",
      "source": "B13",
      "target": "B15",
      "label": "Остановить услугу",
      "kind": "exception",
      "actor": "system",
      "guard": "Безопасность, самочувствие, поломка; зафиксировать факт без лишних medical данных.",
      "handoff": false,
      "event": "workforce.b13_b15",
      "frontend": "Зафиксировать причину, оказанную часть и помощь.",
      "backend": "Service incident; безопасность, стоимость только фактически согласованного; спор/возврат в отдельном case."
    },
    {
      "id": "B15-O20",
      "source": "B15",
      "target": "O20",
      "label": "Разобрать последствия",
      "kind": "handoff",
      "actor": "barber",
      "guard": "Не закрывать деньги до согласованного решения.",
      "handoff": true,
      "event": "workforce.b15_o20",
      "frontend": "Услышать клиента, предложить исправление/возврат/объяснение.",
      "backend": "Case, факты и сроки; не стирать отзыв за компенсацию, решение с audit и независимым возвратом."
    },
    {
      "id": "B13-B23",
      "source": "B13",
      "target": "B23",
      "label": "Угроза или конфликт",
      "kind": "exception",
      "actor": "system",
      "guard": "Приоритет безопасности; приложение не заменяет экстренные службы.",
      "handoff": false,
      "event": "workforce.b13_b23",
      "frontend": "Остановить визит и позвать владельца; экстренная помощь вне приложения.",
      "backend": "Safety case с ограниченным доступом, остановка услуги; санкции только после review и возможности обращения."
    },
    {
      "id": "B23-B15",
      "source": "B23",
      "target": "B15",
      "label": "Безопасно прервать",
      "kind": "recovery",
      "actor": "barber",
      "guard": "Инцидент владельцу и ясный статус визита.",
      "handoff": false,
      "event": "workforce.b23_b15",
      "frontend": "Зафиксировать причину, оказанную часть и помощь.",
      "backend": "Service incident; безопасность, стоимость только фактически согласованного; спор/возврат в отдельном case."
    },
    {
      "id": "B16-C33",
      "source": "B16",
      "target": "C33",
      "label": "Результат не устраивает",
      "kind": "exception",
      "actor": "barber",
      "guard": "Обратная связь добровольна, без давления.",
      "handoff": true,
      "event": "workforce.b16_c33",
      "frontend": "Описать несовпадение; исправить сейчас или открыть обращение.",
      "backend": "Согласованный scope corrective work, availability и стоимость; не подменять первоначальный паспорт."
    },
    {
      "id": "C33-B12",
      "source": "C33",
      "target": "B12",
      "label": "Согласовать исправление",
      "kind": "recovery",
      "actor": "client",
      "guard": "Новый scope, ресурсы и время; исходная версия результата сохранена.",
      "handoff": true,
      "event": "booking.c33_b12",
      "frontend": "Обсудить форму, тишину, чувствительность и цену до начала.",
      "backend": "Consultation snapshot; consent на изменение состава и цены, фото отдельным согласием."
    },
    {
      "id": "C33-C36",
      "source": "C33",
      "target": "C36",
      "label": "Обратиться после визита",
      "kind": "recovery",
      "actor": "client",
      "guard": "Case доступен и без положительного отзыва.",
      "handoff": false,
      "event": "booking.c33_c36",
      "frontend": "Текст, доступные фото по желанию и ожидаемый результат.",
      "backend": "Case ID, срок ответа, escalation; не требовать публикации фото и не блокировать возврат за отзыв."
    },
    {
      "id": "B17-C19",
      "source": "B17",
      "target": "C19",
      "label": "Клиент не хочет фото",
      "kind": "happy",
      "actor": "barber",
      "guard": "Параметры можно сохранить без фотографий.",
      "handoff": true,
      "event": "workforce.b17_c19",
      "frontend": "Продолжить текстом без наказания за отказ.",
      "backend": "Не читать камеру/галерею, не создавать media; разрешение ОС и согласие хранения независимы."
    },
    {
      "id": "B18-B19",
      "source": "B18",
      "target": "B19",
      "label": "Закрыть рабочую смену",
      "kind": "happy",
      "actor": "system",
      "guard": "Незавершённые cases переданы, не потеряны.",
      "handoff": false,
      "event": "workforce.b18_b19",
      "frontend": "Проверить незавершённые паспорта, визиты и оборудование.",
      "backend": "Shift close допускает явную передачу unresolved cases владельцу; аудит, часы и перерывы."
    },
    {
      "id": "B19-B20",
      "source": "B19",
      "target": "B20",
      "label": "Посмотреть начисление",
      "kind": "happy",
      "actor": "barber",
      "guard": "Опубликован statement для периода.",
      "handoff": false,
      "event": "workforce.b19_b20",
      "frontend": "Свои услуги, возвраты, чаевые и расчёт периода.",
      "backend": "Scoped earnings view; acknowledge либо dispute, staff не видит чужие начисления."
    },
    {
      "id": "B19-B06",
      "source": "B19",
      "target": "B06",
      "label": "Следующая смена",
      "kind": "happy",
      "actor": "barber",
      "guard": "Новые server date/shift и active membership.",
      "handoff": false,
      "event": "workforce.b19_b06",
      "frontend": "Предстоящие визиты, перерывы, свободные окна, незакрытые задачи.",
      "backend": "Scoped read model; server now и timezone филиала, запрет чужого расписания вне scope."
    },
    {
      "id": "C34-P14",
      "source": "C34",
      "target": "P14",
      "label": "Оплатить остаток на месте",
      "kind": "happy",
      "actor": "client",
      "guard": "Payment_due > 0, разрешённый метод.",
      "handoff": false,
      "event": "booking.c34_p14",
      "frontend": "Показать остаток к оплате: наличные или терминал.",
      "backend": "Booking can be confirmed as payment_due по политике; cashier confirms amount and method, без фиктивного YooKassa payment."
    },
    {
      "id": "C34-P00",
      "source": "C34",
      "target": "P00",
      "label": "Оплатить остаток онлайн",
      "kind": "happy",
      "actor": "client",
      "guard": "Новая payment intent только на remaining balance.",
      "handoff": false,
      "event": "booking.c34_p00",
      "frontend": "Новая/сохранённая карта, доступный клубный зачёт или на месте.",
      "backend": "Allowed methods по merchant/policy/amount; payer и recipient раздельны; сумма только из quote."
    },
    {
      "id": "C34-C36",
      "source": "C34",
      "target": "C36",
      "label": "Открыть спор",
      "kind": "exception",
      "actor": "client",
      "guard": "Service completion не блокирует complaint.",
      "handoff": false,
      "event": "booking.c34_c36",
      "frontend": "Текст, доступные фото по желанию и ожидаемый результат.",
      "backend": "Case ID, срок ответа, escalation; не требовать публикации фото и не блокировать возврат за отзыв."
    },
    {
      "id": "S07-C35",
      "source": "S07",
      "target": "C35",
      "label": "Оценить визит",
      "kind": "happy",
      "actor": "system",
      "guard": "Отзыв необязателен, без reward за положительную оценку.",
      "handoff": false,
      "event": "reliability.s07_c35",
      "frontend": "Честный отзыв, приватный feedback или пропуск.",
      "backend": "Один отзыв на завершённый визит с редакциями; moderation ≠ скрытие негатива; без требования положительного рейтинга."
    },
    {
      "id": "C35-C37",
      "source": "C35",
      "target": "C37",
      "label": "Сказать спасибо",
      "kind": "happy",
      "actor": "client",
      "guard": "Любой выбор рейтинга либо пропуск.",
      "handoff": false,
      "event": "booking.c35_c37",
      "frontend": "Спасибо, чаевые по желанию, поделиться ссылкой.",
      "backend": "Чаевые отдельная операция/ledger при включённом канале; отказ не меняет качество обслуживания."
    },
    {
      "id": "C35-C36",
      "source": "C35",
      "target": "C36",
      "label": "Рассказать о проблеме",
      "kind": "exception",
      "actor": "client",
      "guard": "Негатив не прячется за обращением.",
      "handoff": false,
      "event": "booking.c35_c36",
      "frontend": "Текст, доступные фото по желанию и ожидаемый результат.",
      "backend": "Case ID, срок ответа, escalation; не требовать публикации фото и не блокировать возврат за отзыв."
    },
    {
      "id": "C35-C38",
      "source": "C35",
      "target": "C38",
      "label": "Пропустить отзыв",
      "kind": "exit",
      "actor": "client",
      "guard": "Доступ к паспорту не зависит от рейтинга.",
      "handoff": false,
      "event": "booking.c35_c38",
      "frontend": "Параметры и разрешённые до/после; исправление заметок.",
      "backend": "Immutable revisions и ownership; revoked media скрываются, технические параметры можно хранить отдельно."
    },
    {
      "id": "C37-C38",
      "source": "C37",
      "target": "C38",
      "label": "Открыть результат",
      "kind": "happy",
      "actor": "client",
      "guard": "Чаевые не обязательны.",
      "handoff": false,
      "event": "booking.c37_c38",
      "frontend": "Параметры и разрешённые до/после; исправление заметок.",
      "backend": "Immutable revisions и ownership; revoked media скрываются, технические параметры можно хранить отдельно."
    },
    {
      "id": "C37-P00",
      "source": "C37",
      "target": "P00",
      "label": "Оставить чаевые",
      "kind": "happy",
      "actor": "client",
      "guard": "Tip feature enabled, отдельный purpose/recipient и сумма; не invoice balance.",
      "handoff": false,
      "event": "booking.c37_p00",
      "frontend": "Новая/сохранённая карта, доступный клубный зачёт или на месте.",
      "backend": "Allowed methods по merchant/policy/amount; payer и recipient раздельны; сумма только из quote."
    },
    {
      "id": "C36-O20",
      "source": "C36",
      "target": "O20",
      "label": "Передать владельцу",
      "kind": "handoff",
      "actor": "client",
      "guard": "Case SLA, доступ к согласованным материалам.",
      "handoff": true,
      "event": "booking.c36_o20",
      "frontend": "Услышать клиента, предложить исправление/возврат/объяснение.",
      "backend": "Case, факты и сроки; не стирать отзыв за компенсацию, решение с audit и независимым возвратом."
    },
    {
      "id": "O20-P16",
      "source": "O20",
      "target": "P16",
      "label": "Одобрить возврат",
      "kind": "happy",
      "actor": "owner",
      "guard": "Refund entitlement/amount подтверждены и записаны.",
      "handoff": true,
      "event": "operations.o20_p16",
      "frontend": "Сумма, основание и статус рассмотрения.",
      "backend": "Refund entitlement/order version; сумма ≤ captured − successful/pending refunds. Не объявлять деньги возвращёнными при создании."
    },
    {
      "id": "O20-C22",
      "source": "O20",
      "target": "C22",
      "label": "Предложить исправление в другой день",
      "kind": "recovery",
      "actor": "owner",
      "guard": "Клиент согласен, стоимость и scope ясны.",
      "handoff": true,
      "event": "operations.o20_c22",
      "frontend": "Выбрать новый слот и увидеть разницу цены/условий.",
      "backend": "Исходный визит остаётся подтверждённым до атомарной замены; new quote при изменении состава."
    },
    {
      "id": "O20-S06",
      "source": "O20",
      "target": "S06",
      "label": "Объяснить решение",
      "kind": "happy",
      "actor": "owner",
      "guard": "Все обещанные действия имеют authoritative результат; можно обжаловать.",
      "handoff": false,
      "event": "operations.o20_s06",
      "frontend": "Показать решение и подтверждённые компенсации.",
      "backend": "Resolution reason + linked authoritative outcomes; unresolved payment/refund не закрывается кнопкой оператора."
    },
    {
      "id": "C38-R01",
      "source": "C38",
      "target": "R01",
      "label": "Разрешить публикацию работы",
      "kind": "happy",
      "actor": "client",
      "guard": "Preview конкретных фото; private passport отдельно.",
      "handoff": false,
      "event": "booking.c38_r01",
      "frontend": "Предпросмотр конкретных фото и каналов публикации.",
      "backend": "Granular revocable consent; private passport не публикуется автоматически, отказ не влияет на услугу."
    },
    {
      "id": "C38-L00",
      "source": "C38",
      "target": "L00",
      "label": "Посмотреть клуб",
      "kind": "happy",
      "actor": "client",
      "guard": "Не блокировать паспорт предложением клуба.",
      "handoff": false,
      "event": "booking.c38_l00",
      "frontend": "Понятные привилегии, стоимость, срок, пауза и отмена.",
      "backend": "Только published ClubPlanVersion; примеры маркетолога не являются утверждёнными тарифами."
    },
    {
      "id": "C39-C01",
      "source": "C39",
      "target": "C01",
      "label": "Изменить образ",
      "kind": "happy",
      "actor": "client",
      "guard": "Новый draft, не менять прошлый passport.",
      "handoff": false,
      "event": "booking.c39_c01",
      "frontend": "Портфолио, вариант следующей формы и пожелания.",
      "backend": "Style reference связан с доступными услугами, не обещать гарантированный результат по фото."
    },
    {
      "id": "C39-C41",
      "source": "C39",
      "target": "C41",
      "label": "Пока не записываться",
      "kind": "exit",
      "actor": "client",
      "guard": "Остановить recommendation cadence по выбору, без давления.",
      "handoff": false,
      "event": "booking.c39_c41",
      "frontend": "Отложить уход за формой: поездка, болезнь, смена планов.",
      "backend": "Pause recommendation jobs до выбранной даты; сервисные сообщения о реальных обязательствах остаются отдельно."
    },
    {
      "id": "C41-C00",
      "source": "C41",
      "target": "C00",
      "label": "Вернуться когда удобно",
      "kind": "recovery",
      "actor": "client",
      "guard": "Сохранённые права и история согласно consent.",
      "handoff": false,
      "event": "booking.c41_c00",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache."
    },
    {
      "id": "C40-C04",
      "source": "C40",
      "target": "C04",
      "label": "Найти новое окно",
      "kind": "happy",
      "actor": "client",
      "guard": "Новый quote/hold, не auto-book.",
      "handoff": false,
      "event": "booking.c40_c04",
      "frontend": "Умные слоты, другой день/филиал, лист ожидания.",
      "backend": "Availability с креслом, навыком, сменой, буфером и существующими hold; время сервера."
    },
    {
      "id": "C00-C45",
      "source": "C00",
      "target": "C45",
      "label": "Записать близкого",
      "kind": "happy",
      "actor": "client",
      "guard": "Плательщик не получает доступ к чужой истории.",
      "handoff": false,
      "event": "booking.c00_c45",
      "frontend": "Разделить плательщика и получателя, пригласить получателя.",
      "backend": "Recipient consent/age policy; не открывать паспорт другого человека плательщику. Подтверждение получателя до private data."
    },
    {
      "id": "C45-G10",
      "source": "C45",
      "target": "G10",
      "label": "Передать приглашение получателю",
      "kind": "handoff",
      "actor": "client",
      "guard": "Отдельный recipient consent; minor policy обязательна до активации.",
      "handoff": true,
      "event": "booking.c45_g10",
      "frontend": "Условия гостевого визита, срок и отправитель.",
      "backend": "GuestPass token без раскрытия истории дарителя; согласие получателя обязательно."
    },
    {
      "id": "C00-R00",
      "source": "C00",
      "target": "R00",
      "label": "Открыть настройки",
      "kind": "happy",
      "actor": "client",
      "guard": "Own identity.",
      "handoff": false,
      "event": "booking.c00_r00",
      "frontend": "Фото, каналы, связанные входы, карты, выгрузка и удаление.",
      "backend": "Capabilities per owner of data; отдельные consent records, activity/audit view."
    },
    {
      "id": "C00-C43",
      "source": "C00",
      "target": "C43",
      "label": "Нужна помощь",
      "kind": "happy",
      "actor": "client",
      "guard": "Понятный case ID, без передачи чужих PII.",
      "handoff": false,
      "event": "booking.c00_c43",
      "frontend": "Открыть обращение, контакт филиала и номер операции.",
      "backend": "Support case без раскрытия чужой PII; SLA и escalation, разрешение требует audit."
    },
    {
      "id": "P00-P02",
      "source": "P00",
      "target": "P02",
      "label": "Хочу сохранить карту",
      "kind": "happy",
      "actor": "client",
      "guard": "Необязательное отдельное согласие, не предвыбранное.",
      "handoff": false,
      "event": "payments.p00_p02",
      "frontend": "Отдельный необязательный выбор и понятная цель.",
      "backend": "Сохранить consent version, только тогда save_payment_method=true; не равняется согласию на автоплатёж."
    },
    {
      "id": "P02-P01",
      "source": "P02",
      "target": "P01",
      "label": "Перейти в платёжную форму",
      "kind": "happy",
      "actor": "client",
      "guard": "Consent recorded, save_payment_method flag.",
      "handoff": false,
      "event": "payments.p02_p01",
      "frontend": "Открыть защищённую форму ЮKassa.",
      "backend": "PAN/CVV не проходят через PRIME, не логируются; клиент получает confirmation flow, secret остаётся на сервере."
    },
    {
      "id": "P00-P04",
      "source": "P00",
      "target": "P04",
      "label": "Выбрать сохранённую карту",
      "kind": "happy",
      "actor": "client",
      "guard": "Active token belongs to payer.",
      "handoff": false,
      "event": "payments.p00_p04",
      "frontend": "Выбрать свою карту и подтвердить конкретную сумму.",
      "backend": "Ownership token + explicit current payment intent; возможен новый challenge, declined token не означает потерю booking."
    },
    {
      "id": "P04-P06",
      "source": "P04",
      "target": "P06",
      "label": "Подтвердить сумму",
      "kind": "happy",
      "actor": "client",
      "guard": "One explicit intent, quote и method owner проверены.",
      "handoff": false,
      "event": "payments.p04_p06",
      "frontend": "Показать pending и ссылку провайдера.",
      "backend": "POST payment с persisted operationId/idempotence key и quote; purpose booking/deposit/club/tip раздельный, серверная сумма."
    },
    {
      "id": "P00-P14",
      "source": "P00",
      "target": "P14",
      "label": "Выбрать оплату на месте",
      "kind": "happy",
      "actor": "client",
      "guard": "Политика допускает payment_due booking; нулевая предоплата не online paid.",
      "handoff": false,
      "event": "payments.p00_p14",
      "frontend": "Показать остаток к оплате: наличные или терминал.",
      "backend": "Booking can be confirmed as payment_due по политике; cashier confirms amount and method, без фиктивного YooKassa payment."
    },
    {
      "id": "P14-C10",
      "source": "P14",
      "target": "C10",
      "label": "Подтвердить запись с оплатой позже",
      "kind": "happy",
      "actor": "client",
      "guard": "Service ещё не оказана; policy permits pay-on-site.",
      "handoff": false,
      "event": "payments.p14_c10",
      "frontend": "Показать один pending запрос и его статус.",
      "backend": "Idempotent BookingSaga; validate hold/revision/payment policy. Деньги и слот — отдельные агрегаты."
    },
    {
      "id": "P14-P15",
      "source": "P14",
      "target": "P15",
      "label": "Принять оплату после услуги",
      "kind": "handoff",
      "actor": "client",
      "guard": "Service complete, сотрудник имеет cashier capability, сумма реальна.",
      "handoff": true,
      "event": "payments.p14_p15",
      "frontend": "Уполномоченный сотрудник подтверждает приём и чек.",
      "backend": "Separate cashier capability; audit, unique settlement, external terminal reference; если нет права — владелец."
    },
    {
      "id": "P15-P20",
      "source": "P15",
      "target": "P20",
      "label": "Выдать кассовый чек",
      "kind": "async",
      "actor": "system",
      "guard": "Метод и сумма подтверждены, нет дублирования settlement.",
      "handoff": true,
      "event": "payments.p15_p20",
      "frontend": "Показать чек или состояние его подготовки.",
      "backend": "Фискализация по выбранной схеме, отдельные события предоплаты/зачёта/возврата; accounting mapping утверждается до live."
    },
    {
      "id": "P06-P12",
      "source": "P06",
      "target": "P12",
      "label": "Ответ create потерян",
      "kind": "exception",
      "actor": "system",
      "guard": "Persisted operation key, нельзя создавать новый платёж наугад.",
      "handoff": false,
      "event": "payments.p06_p12",
      "frontend": "Сверяем, не платите второй раз; можно оставить обращение.",
      "backend": "Сетевой timeout не равен отказу; persist operation, reconcile before retry, ключ ЮKassa имеет ограниченный срок."
    },
    {
      "id": "P06-P11",
      "source": "P06",
      "target": "P11",
      "label": "Провайдер отказал",
      "kind": "exception",
      "actor": "system",
      "guard": "Только authoritative canceled/validation rejection без accepted charge.",
      "handoff": false,
      "event": "payments.p06_p11",
      "frontend": "Причина без обвинения; другой метод, повтор новым намерением или выход.",
      "backend": "canceled final; release obsolete hold, новый payment только после проверки старого. Дубликат callback не создаёт новый."
    },
    {
      "id": "P07-P12",
      "source": "P07",
      "target": "P12",
      "label": "Закрыть приложение после банка",
      "kind": "exception",
      "actor": "client",
      "guard": "Возврат в приложение не требуется для server reconciliation.",
      "handoff": false,
      "event": "payments.p07_p12",
      "frontend": "Сверяем, не платите второй раз; можно оставить обращение.",
      "backend": "Сетевой timeout не равен отказу; persist operation, reconcile before retry, ключ ЮKassa имеет ограниченный срок."
    },
    {
      "id": "P07-P11",
      "source": "P07",
      "target": "P11",
      "label": "Отказаться в форме банка",
      "kind": "exception",
      "actor": "client",
      "guard": "Проверить provider status, пока pending — идти в reconcile.",
      "handoff": false,
      "event": "payments.p07_p11",
      "frontend": "Причина без обвинения; другой метод, повтор новым намерением или выход.",
      "backend": "canceled final; release obsolete hold, новый payment только после проверки старого. Дубликат callback не создаёт новый."
    },
    {
      "id": "P08-P09",
      "source": "P08",
      "target": "P09",
      "label": "Банк авторизовал средства",
      "kind": "async",
      "actor": "system",
      "guard": "waiting_for_capture verified, expires_at сохранён.",
      "handoff": false,
      "event": "payments.p08_p09",
      "frontend": "Различать блокировку и окончательное списание.",
      "backend": "waiting_for_capture; expires_at провайдера, capture/cancel только при согласованном основании. Не держать авторизацию до далёкого визита."
    },
    {
      "id": "P09-P10",
      "source": "P09",
      "target": "P10",
      "label": "Подтвердить списание",
      "kind": "async",
      "actor": "system",
      "guard": "Ресурс гарантирован и policy intent допускает capture; provider succeeded verified.",
      "handoff": false,
      "event": "payments.p09_p10",
      "frontend": "Показать успешную операцию, затем проверенный статус заказа.",
      "backend": "succeeded immutable; ledger once, booking saga/club/tip continuation по purpose, outbox receipt."
    },
    {
      "id": "P09-P11",
      "source": "P09",
      "target": "P11",
      "label": "Отменить авторизацию",
      "kind": "recovery",
      "actor": "system",
      "guard": "Booking не может состояться либо user cancel; cancel verified, не refund succeeded payment.",
      "handoff": false,
      "event": "payments.p09_p11",
      "frontend": "Причина без обвинения; другой метод, повтор новым намерением или выход.",
      "backend": "canceled final; release obsolete hold, новый payment только после проверки старого. Дубликат callback не создаёт новый."
    },
    {
      "id": "P08-P12",
      "source": "P08",
      "target": "P12",
      "label": "Webhook не пришёл",
      "kind": "exception",
      "actor": "system",
      "guard": "Bounded polling/reconciliation, не optimistic paid.",
      "handoff": false,
      "event": "payments.p08_p12",
      "frontend": "Сверяем, не платите второй раз; можно оставить обращение.",
      "backend": "Сетевой timeout не равен отказу; persist operation, reconcile before retry, ключ ЮKassa имеет ограниченный срок."
    },
    {
      "id": "P08-P11",
      "source": "P08",
      "target": "P11",
      "label": "Получен canceled",
      "kind": "async",
      "actor": "system",
      "guard": "Authentic GET status, сумма и merchant совпадают.",
      "handoff": false,
      "event": "payments.p08_p11",
      "frontend": "Причина без обвинения; другой метод, повтор новым намерением или выход.",
      "backend": "canceled final; release obsolete hold, новый payment только после проверки старого. Дубликат callback не создаёт новый."
    },
    {
      "id": "P10-P03",
      "source": "P10",
      "target": "P03",
      "label": "Сохранение карты подтверждено",
      "kind": "async",
      "actor": "system",
      "guard": "Только payment_method.saved=true и предшествующий consent.",
      "handoff": false,
      "event": "payments.p10_p03",
      "frontend": "Бренд и последние цифры; не обещать сохранение до ответа.",
      "backend": "Только при payment_method.saved=true сохранить provider ID, owner, masked metadata. CVV/PAN не хранить."
    },
    {
      "id": "P03-C12",
      "source": "P03",
      "target": "C12",
      "label": "Продолжить визит",
      "kind": "happy",
      "actor": "system",
      "guard": "Booking уже confirmed; иначе C10/S00 сначала. Payment method activation не создаёт booking.",
      "handoff": false,
      "event": "payments.p03_c12",
      "frontend": "Подтверждённый booking ID, адрес, календарь, подготовка.",
      "backend": "Только authoritative confirmed; outbox reminders; оплачено/к оплате показывается отдельно."
    },
    {
      "id": "P10-P20",
      "source": "P10",
      "target": "P20",
      "label": "Сформировать чек оплаты",
      "kind": "async",
      "actor": "system",
      "guard": "Provider succeeded, fiscalization scheme учитывает предоплату.",
      "handoff": false,
      "event": "payments.p10_p20",
      "frontend": "Показать чек или состояние его подготовки.",
      "backend": "Фискализация по выбранной схеме, отдельные события предоплаты/зачёта/возврата; accounting mapping утверждается до live."
    },
    {
      "id": "P10-P25",
      "source": "P10",
      "target": "P25",
      "label": "Удержание слота истекло",
      "kind": "exception",
      "actor": "system",
      "guard": "Booking не committed, средства реально captured.",
      "handoff": true,
      "event": "payments.p10_p25",
      "frontend": "Объяснить ситуацию, предложить согласованное окно или возврат.",
      "backend": "Paid-unallocated saga; никогда не double-book. Refund обязательной компенсацией при невозможности подтвердить услугу."
    },
    {
      "id": "P10-L02",
      "source": "P10",
      "target": "L02",
      "label": "Активировать покупку клуба",
      "kind": "async",
      "actor": "system",
      "guard": "purpose=club, unique entitlement grant per payment.",
      "handoff": false,
      "event": "payments.p10_l02",
      "frontend": "Показать период и доступные услуги/привилегии.",
      "backend": "Только settled purchase → immutable entitlement ledger; duplicate webhook не удваивает баланс."
    },
    {
      "id": "P10-C37",
      "source": "P10",
      "target": "C37",
      "label": "Учесть чаевые",
      "kind": "async",
      "actor": "system",
      "guard": "purpose=tip, отдельный ledger; не повторять booking creation.",
      "handoff": false,
      "event": "payments.p10_c37",
      "frontend": "Спасибо, чаевые по желанию, поделиться ссылкой.",
      "backend": "Чаевые отдельная операция/ledger при включённом канале; отказ не меняет качество обслуживания."
    },
    {
      "id": "P11-P00",
      "source": "P11",
      "target": "P00",
      "label": "Попробовать другой метод",
      "kind": "recovery",
      "actor": "client",
      "guard": "Старый платёж terminal, новая явная intent и свежая quote.",
      "handoff": false,
      "event": "payments.p11_p00",
      "frontend": "Новая/сохранённая карта, доступный клубный зачёт или на месте.",
      "backend": "Allowed methods по merchant/policy/amount; payer и recipient раздельны; сумма только из quote."
    },
    {
      "id": "P11-C16",
      "source": "P11",
      "target": "C16",
      "label": "Закончить попытку",
      "kind": "exit",
      "actor": "client",
      "guard": "Нет неразрешённого pending payment.",
      "handoff": false,
      "event": "payments.p11_c16",
      "frontend": "Вернуться или закрыть; показать реальные незавершённые операции.",
      "backend": "Если платежа нет — release hold; если payment pending — отмена intent + reconcile, не забывать платеж."
    },
    {
      "id": "P12-P13",
      "source": "P12",
      "target": "P13",
      "label": "Начать сверку",
      "kind": "recovery",
      "actor": "client",
      "guard": "GET/local operation first, сохранённый idempotency key.",
      "handoff": false,
      "event": "payments.p12_p13",
      "frontend": "Обновить результат из сервера.",
      "backend": "GET provider + local operation/ledger, compare order amount; after idempotency window не повторять create вслепую."
    },
    {
      "id": "P13-P10",
      "source": "P13",
      "target": "P10",
      "label": "Подтверждено succeeded",
      "kind": "recovery",
      "actor": "system",
      "guard": "Merchant, amount, currency, purpose и ledger проверены.",
      "handoff": false,
      "event": "payments.p13_p10",
      "frontend": "Показать успешную операцию, затем проверенный статус заказа.",
      "backend": "succeeded immutable; ledger once, booking saga/club/tip continuation по purpose, outbox receipt."
    },
    {
      "id": "P13-P11",
      "source": "P13",
      "target": "P11",
      "label": "Подтверждено canceled",
      "kind": "recovery",
      "actor": "system",
      "guard": "Provider final state.",
      "handoff": false,
      "event": "payments.p13_p11",
      "frontend": "Причина без обвинения; другой метод, повтор новым намерением или выход.",
      "backend": "canceled final; release obsolete hold, новый payment только после проверки старого. Дубликат callback не создаёт новый."
    },
    {
      "id": "P13-S05",
      "source": "P13",
      "target": "S05",
      "label": "Статус не разрешился",
      "kind": "exception",
      "actor": "system",
      "guard": "Retry budget исчерпан; durable case с ответственным, никаких повторных charges.",
      "handoff": true,
      "event": "payments.p13_s05",
      "frontend": "Видимые unresolved cases, ответственный и срок.",
      "backend": "Retry budget exhausted → durable manual case, escalation, audit; не терять message в DLQ без владельца."
    },
    {
      "id": "P03-P05",
      "source": "P03",
      "target": "P05",
      "label": "Удалить сохранённый способ",
      "kind": "happy",
      "actor": "system",
      "guard": "Reauth, active mandates показаны отдельно.",
      "handoff": false,
      "event": "payments.p03_p05",
      "frontend": "Показать, что будущие списания отключены; объяснить активные обязательства.",
      "backend": "Revoke local authorization, cancel renewal jobs; unlink не отменяет прошлый payment/refund. Действия provider по поддерживаемому API отдельно."
    },
    {
      "id": "P05-R00",
      "source": "P05",
      "target": "R00",
      "label": "Способ отключён",
      "kind": "happy",
      "actor": "system",
      "guard": "Future local charges blocked; past refund still traceable.",
      "handoff": false,
      "event": "payments.p05_r00",
      "frontend": "Фото, каналы, связанные входы, карты, выгрузка и удаление.",
      "backend": "Capabilities per owner of data; отдельные consent records, activity/audit view."
    },
    {
      "id": "P16-P17",
      "source": "P16",
      "target": "P17",
      "label": "Создать согласованный возврат",
      "kind": "happy",
      "actor": "client",
      "guard": "Authorised entitlement; amount bounded including pending refunds, idempotency key.",
      "handoff": false,
      "event": "payments.p16_p17",
      "frontend": "Показать pending и идентификатор, без обещанного срока банка.",
      "backend": "Idempotent refund object; webhook/GET reconciliation, cash возврат через отдельный audited процесс."
    },
    {
      "id": "P16-O20",
      "source": "P16",
      "target": "O20",
      "label": "Условия требуют рассмотрения",
      "kind": "exception",
      "actor": "client",
      "guard": "Не выдавать автоматическое решение при споре.",
      "handoff": true,
      "event": "payments.p16_o20",
      "frontend": "Услышать клиента, предложить исправление/возврат/объяснение.",
      "backend": "Case, факты и сроки; не стирать отзыв за компенсацию, решение с audit и независимым возвратом."
    },
    {
      "id": "P17-P18",
      "source": "P17",
      "target": "P18",
      "label": "Провайдер подтвердил возврат",
      "kind": "async",
      "actor": "system",
      "guard": "Refund succeeded verified, ledger once.",
      "handoff": false,
      "event": "payments.p17_p18",
      "frontend": "Обновить статус возврата и чек.",
      "backend": "Refund succeeded → ledger once, сумма заказа/клуб/начисление мастера корректируются связанными записями."
    },
    {
      "id": "P17-P19",
      "source": "P17",
      "target": "P19",
      "label": "Возврат не разрешён вовремя",
      "kind": "exception",
      "actor": "system",
      "guard": "Unknown остаётся unknown; финальный canceled отличается от timeout.",
      "handoff": true,
      "event": "payments.p17_p19",
      "frontend": "Повторить сверку/передать финансовому ответственному.",
      "backend": "Timeout не считать failed; terminal canceled допускает исправленную новую операцию, SLA escalation и audit."
    },
    {
      "id": "P19-P17",
      "source": "P19",
      "target": "P17",
      "label": "Исправить и повторить безопасно",
      "kind": "recovery",
      "actor": "owner",
      "guard": "Сначала сверка предыдущего refund; новый intent только после terminal canceled.",
      "handoff": true,
      "event": "payments.p19_p17",
      "frontend": "Показать pending и идентификатор, без обещанного срока банка.",
      "backend": "Idempotent refund object; webhook/GET reconciliation, cash возврат через отдельный audited процесс."
    },
    {
      "id": "P19-S05",
      "source": "P19",
      "target": "S05",
      "label": "Передать финансовому ответственному",
      "kind": "handoff",
      "actor": "owner",
      "guard": "SLA и evidence, обязательство не закрыто.",
      "handoff": false,
      "event": "payments.p19_s05",
      "frontend": "Видимые unresolved cases, ответственный и срок.",
      "backend": "Retry budget exhausted → durable manual case, escalation, audit; не терять message в DLQ без владельца."
    },
    {
      "id": "P18-P20",
      "source": "P18",
      "target": "P20",
      "label": "Чек возврата",
      "kind": "async",
      "actor": "system",
      "guard": "Связать исходный receipt и сумму, исключить дубли.",
      "handoff": false,
      "event": "payments.p18_p20",
      "frontend": "Показать чек или состояние его подготовки.",
      "backend": "Фискализация по выбранной схеме, отдельные события предоплаты/зачёта/возврата; accounting mapping утверждается до live."
    },
    {
      "id": "P18-C40",
      "source": "P18",
      "target": "C40",
      "label": "Вернуться к записи",
      "kind": "happy",
      "actor": "system",
      "guard": "Возврат отражён, новый визит доброволен.",
      "handoff": false,
      "event": "payments.p18_c40",
      "frontend": "Предложить подходящий интервал, дату выбирает человек.",
      "backend": "New booking intent, связи previousVisitId/cohort; никакого авто-бронирования из напоминания."
    },
    {
      "id": "P20-P21",
      "source": "P20",
      "target": "P21",
      "label": "Фискализация задержалась",
      "kind": "exception",
      "actor": "system",
      "guard": "Payment succeeded не меняется; receipt_pending отдельное состояние.",
      "handoff": true,
      "event": "payments.p20_p21",
      "frontend": "Деньги уже учтены; показать очередь исправления.",
      "backend": "Receipt retry bounded + reconciliation; не списывать повторно и не менять succeeded на failed."
    },
    {
      "id": "P20-S07",
      "source": "P20",
      "target": "S07",
      "label": "Учесть готовый чек",
      "kind": "happy",
      "actor": "system",
      "guard": "Услуга завершена и remaining balance разрешён; чек предоплаты сам по себе не закрывает будущий визит.",
      "handoff": false,
      "event": "payments.p20_s07",
      "frontend": "Услуга, расчёт, чек и результат отражены отдельно.",
      "backend": "Booking closed when service/payment obligations resolved or explicit audited receivable; immutable history, outbox retention."
    },
    {
      "id": "P21-P20",
      "source": "P21",
      "target": "P20",
      "label": "Повторить выдачу чека",
      "kind": "recovery",
      "actor": "owner",
      "guard": "Idempotent receipt request, retry budget.",
      "handoff": true,
      "event": "payments.p21_p20",
      "frontend": "Показать чек или состояние его подготовки.",
      "backend": "Фискализация по выбранной схеме, отдельные события предоплаты/зачёта/возврата; accounting mapping утверждается до live."
    },
    {
      "id": "P21-S05",
      "source": "P21",
      "target": "S05",
      "label": "Нужна ручная коррекция",
      "kind": "handoff",
      "actor": "owner",
      "guard": "Responsible finance owner, статус денег не переписывается.",
      "handoff": false,
      "event": "payments.p21_s05",
      "frontend": "Видимые unresolved cases, ответственный и срок.",
      "backend": "Retry budget exhausted → durable manual case, escalation, audit; не терять message в DLQ без владельца."
    },
    {
      "id": "O13-P22",
      "source": "O13",
      "target": "P22",
      "label": "Поступил банковский спор",
      "kind": "exception",
      "actor": "owner",
      "guard": "Есть реальное уведомление/acquirer case, сверить объект.",
      "handoff": false,
      "event": "operations.o13_p22",
      "frontend": "Показать факты и маршрут финансового разбирательства.",
      "backend": "Dispute/chargeback отдельно от обычного refund; заморозить спорное начисление, audit evidence, human review."
    },
    {
      "id": "P22-O20",
      "source": "P22",
      "target": "O20",
      "label": "Исследовать обстоятельства",
      "kind": "recovery",
      "actor": "owner",
      "guard": "Refund и dispute координируются, исключить двойную компенсацию.",
      "handoff": false,
      "event": "payments.p22_o20",
      "frontend": "Услышать клиента, предложить исправление/возврат/объяснение.",
      "backend": "Case, факты и сроки; не стирать отзыв за компенсацию, решение с audit и независимым возвратом."
    },
    {
      "id": "P23-P06",
      "source": "P23",
      "target": "P06",
      "label": "Оплатить согласованную разницу",
      "kind": "happy",
      "actor": "client",
      "guard": "delta > 0 и новый explicit consent, purpose=adjustment.",
      "handoff": false,
      "event": "payments.p23_p06",
      "frontend": "Показать pending и ссылку провайдера.",
      "backend": "POST payment с persisted operationId/idempotence key и quote; purpose booking/deposit/club/tip раздельный, серверная сумма."
    },
    {
      "id": "P23-P16",
      "source": "P23",
      "target": "P16",
      "label": "Вернуть разницу",
      "kind": "happy",
      "actor": "client",
      "guard": "delta < 0, captured/refund bounds.",
      "handoff": false,
      "event": "payments.p23_p16",
      "frontend": "Сумма, основание и статус рассмотрения.",
      "backend": "Refund entitlement/order version; сумма ≤ captured − successful/pending refunds. Не объявлять деньги возвращёнными при создании."
    },
    {
      "id": "P23-C32",
      "source": "P23",
      "target": "C32",
      "label": "Оставить исходный состав",
      "kind": "exit",
      "actor": "client",
      "guard": "Нет нового согласия; никакого увеличения суммы.",
      "handoff": false,
      "event": "payments.p23_c32",
      "frontend": "Видеть согласованный состав и возможность задать вопрос.",
      "backend": "in_service authoritative; аппликация может быть закрыта, состояние живёт на сервере."
    },
    {
      "id": "P00-P24",
      "source": "P00",
      "target": "P24",
      "label": "Применить клубный баланс услуг",
      "kind": "happy",
      "actor": "client",
      "guard": "Entitlement active and eligible; не денежный кошелёк.",
      "handoff": false,
      "event": "payments.p00_p24",
      "frontend": "Показать списываемую привилегию и остаток к доплате.",
      "backend": "Reserve entitlement атомарно; commit при политике оказания услуги, release при отмене; не считать клуб фиктивным cash wallet."
    },
    {
      "id": "P24-C10",
      "source": "P24",
      "target": "C10",
      "label": "Привилегии достаточно",
      "kind": "happy",
      "actor": "system",
      "guard": "Reserved entitlement; booking commit сохраняет reservation, consumption только по policy.",
      "handoff": false,
      "event": "payments.p24_c10",
      "frontend": "Показать один pending запрос и его статус.",
      "backend": "Idempotent BookingSaga; validate hold/revision/payment policy. Деньги и слот — отдельные агрегаты."
    },
    {
      "id": "P24-P06",
      "source": "P24",
      "target": "P06",
      "label": "Осталась доплата",
      "kind": "happy",
      "actor": "system",
      "guard": "Amount равен непокрытому остатку, entitlement reservation связан с order.",
      "handoff": false,
      "event": "payments.p24_p06",
      "frontend": "Показать pending и ссылку провайдера.",
      "backend": "POST payment с persisted operationId/idempotence key и quote; purpose booking/deposit/club/tip раздельный, серверная сумма."
    },
    {
      "id": "P25-O16",
      "source": "P25",
      "target": "O16",
      "label": "Найти согласованную альтернативу",
      "kind": "recovery",
      "actor": "system",
      "guard": "Никогда не занимать чужое время, согласие клиента на новый вариант.",
      "handoff": false,
      "event": "payments.p25_o16",
      "frontend": "Предложить другого барбера/время или отмену.",
      "backend": "Никакой тихой замены: consent клиента, новая quote при изменении цены, transfer booking атомарно."
    },
    {
      "id": "P25-P16",
      "source": "P25",
      "target": "P16",
      "label": "Компенсировать потерю слота",
      "kind": "recovery",
      "actor": "system",
      "guard": "Captured деньги + нет подтверждённой услуги → refund entitlement.",
      "handoff": true,
      "event": "payments.p25_p16",
      "frontend": "Сумма, основание и статус рассмотрения.",
      "backend": "Refund entitlement/order version; сумма ≤ captured − successful/pending refunds. Не объявлять деньги возвращёнными при создании."
    },
    {
      "id": "N00-N02",
      "source": "N00",
      "target": "N02",
      "label": "Канал уже разрешён",
      "kind": "async",
      "actor": "system",
      "guard": "Consent и token active, deadline/version актуальны.",
      "handoff": false,
      "event": "notifications.n00_n02",
      "frontend": "Короткое сообщение без чувствительных деталей на lock screen.",
      "backend": "Channel adapter с retries/backoff, consent recheck, validity window; accepted provider ≠ seen человеком."
    },
    {
      "id": "N01-N03",
      "source": "N01",
      "target": "N03",
      "label": "Не разрешать push",
      "kind": "exit",
      "actor": "client",
      "guard": "Без скрытого fallback; inbox остаётся доступен.",
      "handoff": false,
      "event": "notifications.n01_n03",
      "frontend": "Показать актуальное событие внутри приложения.",
      "backend": "Недействительный token удалить, fallback только при согласии; не спамить всеми каналами."
    },
    {
      "id": "N02-N03",
      "source": "N02",
      "target": "N03",
      "label": "Канал не доставил",
      "kind": "exception",
      "actor": "system",
      "guard": "Provider rejection/token invalid/TTL; не трактовать как отказ клиента.",
      "handoff": false,
      "event": "notifications.n02_n03",
      "frontend": "Показать актуальное событие внутри приложения.",
      "backend": "Недействительный token удалить, fallback только при согласии; не спамить всеми каналами."
    },
    {
      "id": "N02-N05",
      "source": "N02",
      "target": "N05",
      "label": "Человек не прочитал",
      "kind": "exception",
      "actor": "system",
      "guard": "Доставка не равна прочтению и не даёт основания штрафовать.",
      "handoff": false,
      "event": "notifications.n02_n05",
      "frontend": "Оставить возможность восстановиться, связаться и перенести.",
      "backend": "Нет прочтения ≠ no-show; только реальный start/grace/check-in может открыть missed case."
    },
    {
      "id": "N03-N08",
      "source": "N03",
      "target": "N08",
      "label": "Попробовать согласованный канал",
      "kind": "recovery",
      "actor": "system",
      "guard": "Есть отдельный consent и verified contact; cross-channel dedupe.",
      "handoff": false,
      "event": "notifications.n03_n08",
      "frontend": "Одна понятная попытка уведомления.",
      "backend": "Проверить подтверждённый адрес/контакт, consent и dedupe across channels; затем задача человеку при критичности."
    },
    {
      "id": "N03-C21",
      "source": "N03",
      "target": "C21",
      "label": "Посмотреть внутри приложения",
      "kind": "recovery",
      "actor": "system",
      "guard": "In-app current status доступен независимо от push.",
      "handoff": false,
      "event": "notifications.n03_c21",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние."
    },
    {
      "id": "N08-N04",
      "source": "N08",
      "target": "N04",
      "label": "Открыть сообщение",
      "kind": "happy",
      "actor": "system",
      "guard": "Auth и актуальность ссылки проверяются.",
      "handoff": false,
      "event": "notifications.n08_n04",
      "frontend": "Открыть текущий визит, маршрут или перенос.",
      "backend": "Deep link перепроверяет auth/ownership/revision; read receipt не является согласием на услугу."
    },
    {
      "id": "N08-S05",
      "source": "N08",
      "target": "S05",
      "label": "Связаться вручную при критичном изменении",
      "kind": "handoff",
      "actor": "system",
      "guard": "Нет успешной доставки; owner task с допустимым контактом.",
      "handoff": true,
      "event": "notifications.n08_s05",
      "frontend": "Видимые unresolved cases, ответственный и срок.",
      "backend": "Retry budget exhausted → durable manual case, escalation, audit; не терять message в DLQ без владельца."
    },
    {
      "id": "N04-N06",
      "source": "N04",
      "target": "N06",
      "label": "Напомнить позже",
      "kind": "happy",
      "actor": "client",
      "guard": "До начала визита, snooze budget.",
      "handoff": false,
      "event": "notifications.n04_n06",
      "frontend": "Выбрать один перенос напоминания.",
      "backend": "Snooze с max count/deadline, не после начала услуги; не меняет booking time."
    },
    {
      "id": "N06-N00",
      "source": "N06",
      "target": "N00",
      "label": "Поставить одно напоминание",
      "kind": "async",
      "actor": "client",
      "guard": "Новый job с тем же смыслом, supersede предыдущий.",
      "handoff": false,
      "event": "notifications.n06_n00",
      "frontend": "Показать выбранные каналы и локальное время.",
      "backend": "Outbox по booking version; job id=booking/type/version/channel, server timezone, отмена при переносе."
    },
    {
      "id": "N04-N09",
      "source": "N04",
      "target": "N09",
      "label": "Открыть старую ссылку",
      "kind": "exception",
      "actor": "client",
      "guard": "Version stale/canceled, не показывать старое подтверждение.",
      "handoff": false,
      "event": "notifications.n04_n09",
      "frontend": "Показать новое время/отмену и актуальные действия.",
      "backend": "Не воскрешать canceled booking по старой ссылке; no private content до auth."
    },
    {
      "id": "N09-C21",
      "source": "N09",
      "target": "C21",
      "label": "Перейти к актуальному визиту",
      "kind": "recovery",
      "actor": "client",
      "guard": "Current booking accessible and owned.",
      "handoff": false,
      "event": "notifications.n09_c21",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние."
    },
    {
      "id": "N05-C28",
      "source": "N05",
      "target": "C28",
      "label": "Время прошло, клиента нет",
      "kind": "async",
      "actor": "system",
      "guard": "start + grace, staff проверил check-in/контакт; не по отсутствию read receipt.",
      "handoff": false,
      "event": "notifications.n05_c28",
      "frontend": "Показать пропущенный визит и путь к человеку, без обвинительного текста.",
      "backend": "После grace и проверки check-in открыть no-show case; не списывать карту по одному таймеру."
    },
    {
      "id": "N05-C27",
      "source": "N05",
      "target": "C27",
      "label": "Клиент вспомнил и опаздывает",
      "kind": "recovery",
      "actor": "system",
      "guard": "Можно сообщить ETA и согласовать решение.",
      "handoff": false,
      "event": "notifications.n05_c27",
      "frontend": "Сообщить примерное прибытие, увидеть варианты.",
      "backend": "Сравнить remaining service+buffer с next boundary; мастер/владелец подтверждает возможный scope."
    },
    {
      "id": "C28-C43",
      "source": "C28",
      "target": "C43",
      "label": "Объяснить обстоятельства",
      "kind": "recovery",
      "actor": "system",
      "guard": "Human review, штраф не автоматический, можно оспорить no-show.",
      "handoff": false,
      "event": "booking.c28_c43",
      "frontend": "Открыть обращение, контакт филиала и номер операции.",
      "backend": "Support case без раскрытия чужой PII; SLA и escalation, разрешение требует audit."
    },
    {
      "id": "C28-C40",
      "source": "C28",
      "target": "C40",
      "label": "Записаться заново",
      "kind": "recovery",
      "actor": "system",
      "guard": "Только после разрешения ограничений по опубликованной политике, новые условия видимы.",
      "handoff": false,
      "event": "booking.c28_c40",
      "frontend": "Предложить подходящий интервал, дату выбирает человек.",
      "backend": "New booking intent, связи previousVisitId/cohort; никакого авто-бронирования из напоминания."
    },
    {
      "id": "C42-N07",
      "source": "C42",
      "target": "N07",
      "label": "Отключить маркетинг",
      "kind": "happy",
      "actor": "client",
      "guard": "Отзыв действует немедленно для новых/pending кампаний.",
      "handoff": false,
      "event": "booking.c42_n07",
      "frontend": "Сразу подтвердить отказ от маркетинга.",
      "backend": "Revoke channel consent и pending campaign jobs; важные обязательства доступны в inbox, без обхода отказа."
    },
    {
      "id": "C42-N01",
      "source": "C42",
      "target": "N01",
      "label": "Изменить сервисный канал",
      "kind": "happy",
      "actor": "client",
      "guard": "Показать ограничения доставки и inbox fallback.",
      "handoff": false,
      "event": "booking.c42_n01",
      "frontend": "Push permission в контексте пользы; отказ оставляет inbox.",
      "backend": "OS permission отдельно от channel consent; device tokens и messenger bot-access не равны promo consent."
    },
    {
      "id": "N07-R00",
      "source": "N07",
      "target": "R00",
      "label": "Сохранить настройки",
      "kind": "happy",
      "actor": "system",
      "guard": "Не обходить отказ другим каналом.",
      "handoff": false,
      "event": "notifications.n07_r00",
      "frontend": "Фото, каналы, связанные входы, карты, выгрузка и удаление.",
      "backend": "Capabilities per owner of data; отдельные consent records, activity/audit view."
    },
    {
      "id": "C00-C42",
      "source": "C00",
      "target": "C42",
      "label": "Управлять уведомлениями",
      "kind": "happy",
      "actor": "client",
      "guard": "Own preferences.",
      "handoff": false,
      "event": "booking.c00_c42",
      "frontend": "Каналы, время, сервисные события и маркетинг раздельно.",
      "backend": "Consent ledger + permission state; revoke действует на pending jobs, inbox сохраняет статус визита."
    },
    {
      "id": "L00-L01",
      "source": "L00",
      "target": "L01",
      "label": "Выбрать план",
      "kind": "happy",
      "actor": "client",
      "guard": "Есть утверждённые terms/price/renewal/cancellation, иначе блокировать purchase.",
      "handoff": false,
      "event": "club.l00_l01",
      "frontend": "Выбрать разовую покупку или явно разрешённое продление.",
      "backend": "Plan/consent snapshot; recurrence отдельный mandate с amount/cadence/change notice."
    },
    {
      "id": "L00-C00",
      "source": "L00",
      "target": "C00",
      "label": "Не вступать",
      "kind": "exit",
      "actor": "client",
      "guard": "Обычная запись доступна.",
      "handoff": false,
      "event": "club.l00_c00",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache."
    },
    {
      "id": "L01-P00",
      "source": "L01",
      "target": "P00",
      "label": "Оплатить клуб",
      "kind": "happy",
      "actor": "client",
      "guard": "purpose=club, planVersion, явный purchase consent; автопродление отдельное.",
      "handoff": false,
      "event": "club.l01_p00",
      "frontend": "Новая/сохранённая карта, доступный клубный зачёт или на месте.",
      "backend": "Allowed methods по merchant/policy/amount; payer и recipient раздельны; сумма только из quote."
    },
    {
      "id": "L02-L03",
      "source": "L02",
      "target": "L03",
      "label": "Использовать доступную услугу",
      "kind": "happy",
      "actor": "system",
      "guard": "Current period and eligibility.",
      "handoff": false,
      "event": "club.l02_l03",
      "frontend": "Выбрать подходящий визит и увидеть остаток.",
      "backend": "Eligibility service/branch/period; concurrent redeem защищён unique reservation."
    },
    {
      "id": "L03-C03",
      "source": "L03",
      "target": "C03",
      "label": "Собрать клубный визит",
      "kind": "happy",
      "actor": "client",
      "guard": "Quote покажет entitlement и любую доплату.",
      "handoff": false,
      "event": "club.l03_c03",
      "frontend": "Длительность и сумма меняются вместе; дополнительные пожелания.",
      "backend": "Server quote по ServiceVersion, скидки/клуб валидируются сервером; zero/negative duration запрещены."
    },
    {
      "id": "L02-L04",
      "source": "L02",
      "target": "L04",
      "label": "Наступил срок продления",
      "kind": "async",
      "actor": "system",
      "guard": "Active recurrence mandate/token, notice delivered according to approved policy.",
      "handoff": false,
      "event": "club.l02_l04",
      "frontend": "Предупредить о новом периоде и сумме; можно отказаться.",
      "backend": "Scheduler only with active mandate/token; одна operation на период, не скрывать изменение цены."
    },
    {
      "id": "L04-P06",
      "source": "L04",
      "target": "P06",
      "label": "Создать платёж за период",
      "kind": "async",
      "actor": "system",
      "guard": "Один ключ на membership+period, amount disclosed, mandate active.",
      "handoff": false,
      "event": "club.l04_p06",
      "frontend": "Показать pending и ссылку провайдера.",
      "backend": "POST payment с persisted operationId/idempotence key и quote; purpose booking/deposit/club/tip раздельный, серверная сумма."
    },
    {
      "id": "L04-L05",
      "source": "L04",
      "target": "L05",
      "label": "Нет действующего способа / отказ",
      "kind": "exception",
      "actor": "system",
      "guard": "Не списывать новым token без consent, retry bounded.",
      "handoff": false,
      "event": "club.l04_l05",
      "frontend": "Обновить способ оплаты, оплатить вручную или завершить членство.",
      "backend": "Limited retry policy and grace draft; не накапливать бесконечные списания/долги."
    },
    {
      "id": "L05-P00",
      "source": "L05",
      "target": "P00",
      "label": "Продлить вручную",
      "kind": "recovery",
      "actor": "client",
      "guard": "Explicit intent; сверить предыдущий renewal payment first.",
      "handoff": false,
      "event": "club.l05_p00",
      "frontend": "Новая/сохранённая карта, доступный клубный зачёт или на месте.",
      "backend": "Allowed methods по merchant/policy/amount; payer и recipient раздельны; сумма только из quote."
    },
    {
      "id": "L05-L07",
      "source": "L05",
      "target": "L07",
      "label": "Не продлевать",
      "kind": "exit",
      "actor": "client",
      "guard": "Показать срок оставшихся benefits и будущих booking.",
      "handoff": false,
      "event": "club.l05_l07",
      "frontend": "Показать обычные условия, доступ к истории сохраняется.",
      "backend": "Expire benefits, release invalid reserves with explicit customer resolution; паспорт не заложник членства."
    },
    {
      "id": "L02-L06",
      "source": "L02",
      "target": "L06",
      "label": "Пауза / отмена",
      "kind": "happy",
      "actor": "system",
      "guard": "Owner of membership, видимая дата прекращения.",
      "handoff": false,
      "event": "club.l02_l06",
      "frontend": "Показать дату прекращения, остаток и судьбу будущих записей.",
      "backend": "Cancel renewal atomically; refund/unused entitlement по утверждённым правилам, визиты не исчезают."
    },
    {
      "id": "L06-L07",
      "source": "L06",
      "target": "L07",
      "label": "Период закончился",
      "kind": "async",
      "actor": "client",
      "guard": "Mandate cancelled; старые финансовые обязательства не исчезают.",
      "handoff": false,
      "event": "club.l06_l07",
      "frontend": "Показать обычные условия, доступ к истории сохраняется.",
      "backend": "Expire benefits, release invalid reserves with explicit customer resolution; паспорт не заложник членства."
    },
    {
      "id": "L06-P16",
      "source": "L06",
      "target": "P16",
      "label": "Вернуть неиспользованную часть",
      "kind": "happy",
      "actor": "client",
      "guard": "Только утверждённые terms и entitlement; сумма расчёта прозрачна.",
      "handoff": false,
      "event": "club.l06_p16",
      "frontend": "Сумма, основание и статус рассмотрения.",
      "backend": "Refund entitlement/order version; сумма ≤ captured − successful/pending refunds. Не объявлять деньги возвращёнными при создании."
    },
    {
      "id": "L07-C00",
      "source": "L07",
      "target": "C00",
      "label": "Продолжить без клуба",
      "kind": "happy",
      "actor": "system",
      "guard": "История и паспорт сохраняются по consent.",
      "handoff": false,
      "event": "club.l07_c00",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache."
    },
    {
      "id": "L02-L08",
      "source": "L02",
      "target": "L08",
      "label": "Подарить гостевой визит",
      "kind": "happy",
      "actor": "system",
      "guard": "Правила плана допускают transferable entitlement.",
      "handoff": false,
      "event": "club.l02_l08",
      "frontend": "Выбрать доступную привилегию и ссылку без чужих данных.",
      "backend": "Reserve GuestPass, expiry, one-use claim; recipient identity independent from payer."
    },
    {
      "id": "L08-G10",
      "source": "L08",
      "target": "G10",
      "label": "Получатель открывает ссылку",
      "kind": "handoff",
      "actor": "client",
      "guard": "Claim token без PII дарителя, пользователь сам делится ссылкой.",
      "handoff": true,
      "event": "club.l08_g10",
      "frontend": "Условия гостевого визита, срок и отправитель.",
      "backend": "GuestPass token без раскрытия истории дарителя; согласие получателя обязательно."
    },
    {
      "id": "L09-C03",
      "source": "L09",
      "target": "C03",
      "label": "Выбрать гостевой визит",
      "kind": "happy",
      "actor": "system",
      "guard": "После успешного одноразового claim; услуги и срок ограничены terms.",
      "handoff": false,
      "event": "club.l09_c03",
      "frontend": "Длительность и сумма меняются вместе; дополнительные пожелания.",
      "backend": "Server quote по ServiceVersion, скидки/клуб валидируются сервером; zero/negative duration запрещены."
    },
    {
      "id": "C38-L10",
      "source": "C38",
      "target": "L10",
      "label": "Рекомендовать другу",
      "kind": "happy",
      "actor": "client",
      "guard": "Добровольная ссылка, без автоматической отправки.",
      "handoff": false,
      "event": "booking.c38_l10",
      "frontend": "Добровольно поделиться ссылкой, без импорта адресной книги.",
      "backend": "Referral code attribution; не отправлять сообщение за человека; никаких скрытых reward promises."
    },
    {
      "id": "L10-G11",
      "source": "L10",
      "target": "G11",
      "label": "Друг перешёл по ссылке",
      "kind": "handoff",
      "actor": "client",
      "guard": "Attribution не авторизация, не раскрывает данные пригласившего.",
      "handoff": true,
      "event": "club.l10_g11",
      "frontend": "Восстановить публичный путь; просроченная ссылка объяснена.",
      "backend": "Allowlisted deep link, проверить объект и срок; чужие/private данные только после auth."
    },
    {
      "id": "S07-L11",
      "source": "S07",
      "target": "L11",
      "label": "Выполнено условие рекомендации",
      "kind": "async",
      "actor": "system",
      "guard": "Only eligible referred visit, no self-referral, unique reward ledger.",
      "handoff": false,
      "event": "reliability.s07_l11",
      "frontend": "Прозрачно показать результат после выполненного условия.",
      "backend": "Reward after eligible completed settled visit, one per rule, fraud review и reversal ledger при refund."
    },
    {
      "id": "L11-C00",
      "source": "L11",
      "target": "C00",
      "label": "Показать начисление привилегии",
      "kind": "happy",
      "actor": "system",
      "guard": "Terms опубликованы; не выдумывать cash reward.",
      "handoff": false,
      "event": "club.l11_c00",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache."
    },
    {
      "id": "R00-A08",
      "source": "R00",
      "target": "A08",
      "label": "Добавить способ входа",
      "kind": "happy",
      "actor": "client",
      "guard": "Reauth текущей сессии.",
      "handoff": false,
      "event": "privacy.r00_a08",
      "frontend": "Повторно подтвердить текущий аккаунт и новый provider.",
      "backend": "Two-sided proof; unique provider subject. Email/телефон по совпадению не повод автоматически объединять аккаунты."
    },
    {
      "id": "A08-A09",
      "source": "A08",
      "target": "A09",
      "label": "Provider уже связан с другим аккаунтом",
      "kind": "exception",
      "actor": "client",
      "guard": "Не объединять автоматически по совпавшему телефону/email.",
      "handoff": false,
      "event": "identity.a08_a09",
      "frontend": "Объяснить коллизию; безопасное восстановление без потери визитов.",
      "backend": "Не объединять по PII; controlled recovery case и доказательство владения обеими identities."
    },
    {
      "id": "A08-R00",
      "source": "A08",
      "target": "R00",
      "label": "Связка подтверждена",
      "kind": "happy",
      "actor": "client",
      "guard": "Proof обеих identities, unique provider-subject.",
      "handoff": false,
      "event": "identity.a08_r00",
      "frontend": "Фото, каналы, связанные входы, карты, выгрузка и удаление.",
      "backend": "Capabilities per owner of data; отдельные consent records, activity/audit view."
    },
    {
      "id": "A09-A10",
      "source": "A09",
      "target": "A10",
      "label": "Восстановить корректную связку",
      "kind": "recovery",
      "actor": "client",
      "guard": "Controlled identity recovery, audit и rate limit.",
      "handoff": false,
      "event": "identity.a09_a10",
      "frontend": "Другой связанный вход или обращение; сохранить request ID.",
      "backend": "Rate limit, recovery audit, проверка владения; саппорт не просит CVV/пароль мессенджера."
    },
    {
      "id": "A10-A00",
      "source": "A10",
      "target": "A00",
      "label": "Войти подтверждённым способом",
      "kind": "recovery",
      "actor": "client",
      "guard": "Новая transaction, не bypass provider.",
      "handoff": true,
      "event": "identity.a10_a00",
      "frontend": "Telegram, Яндекс; MAX при готовом канале. Отказ не удаляет черновик.",
      "backend": "AuthTransaction с state/expiry/continuation. Ни один provider не задаёт роль сотрудника."
    },
    {
      "id": "R00-P05",
      "source": "R00",
      "target": "P05",
      "label": "Отключить сохранённую карту",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверить active mandates и pending operations.",
      "handoff": false,
      "event": "privacy.r00_p05",
      "frontend": "Показать, что будущие списания отключены; объяснить активные обязательства.",
      "backend": "Revoke local authorization, cancel renewal jobs; unlink не отменяет прошлый payment/refund. Действия provider по поддерживаемому API отдельно."
    },
    {
      "id": "R00-R02",
      "source": "R00",
      "target": "R02",
      "label": "Отозвать фотографии",
      "kind": "happy",
      "actor": "client",
      "guard": "Own media; финансовые документы не удалять через media API.",
      "handoff": false,
      "event": "privacy.r00_r02",
      "frontend": "Убрать фото из приложения и портфолио; показать ход удаления.",
      "backend": "Revoke signed URLs, purge derivatives/CDN, provenance downstream; retention exceptions документируются и ограничивают доступ."
    },
    {
      "id": "R01-C38",
      "source": "R01",
      "target": "C38",
      "label": "Опубликовать согласованный материал",
      "kind": "happy",
      "actor": "client",
      "guard": "Только перечисленные media/channel, действующий consent.",
      "handoff": false,
      "event": "privacy.r01_c38",
      "frontend": "Параметры и разрешённые до/после; исправление заметок.",
      "backend": "Immutable revisions и ownership; revoked media скрываются, технические параметры можно хранить отдельно."
    },
    {
      "id": "R01-R02",
      "source": "R01",
      "target": "R02",
      "label": "Передумать публиковать",
      "kind": "recovery",
      "actor": "client",
      "guard": "Отзыв consent и derivatives purge.",
      "handoff": false,
      "event": "privacy.r01_r02",
      "frontend": "Убрать фото из приложения и портфолио; показать ход удаления.",
      "backend": "Revoke signed URLs, purge derivatives/CDN, provenance downstream; retention exceptions документируются и ограничивают доступ."
    },
    {
      "id": "R02-R00",
      "source": "R02",
      "target": "R00",
      "label": "Удаление медиа подтверждено",
      "kind": "happy",
      "actor": "system",
      "guard": "Проверен object/CDN/pending jobs status; partial failure в S05.",
      "handoff": false,
      "event": "privacy.r02_r00",
      "frontend": "Фото, каналы, связанные входы, карты, выгрузка и удаление.",
      "backend": "Capabilities per owner of data; отдельные consent records, activity/audit view."
    },
    {
      "id": "R02-S05",
      "source": "R02",
      "target": "S05",
      "label": "Не всё удалилось",
      "kind": "exception",
      "actor": "system",
      "guard": "Durable purge task, limited retry, ответственный и статус клиенту.",
      "handoff": true,
      "event": "privacy.r02_s05",
      "frontend": "Видимые unresolved cases, ответственный и срок.",
      "backend": "Retry budget exhausted → durable manual case, escalation, audit; не терять message в DLQ без владельца."
    },
    {
      "id": "R00-R03",
      "source": "R00",
      "target": "R03",
      "label": "Запросить выгрузку",
      "kind": "happy",
      "actor": "client",
      "guard": "Reauth, request scope и защищённая delivery.",
      "handoff": false,
      "event": "privacy.r00_r03",
      "frontend": "Подтверждение личности и готовность защищённой выгрузки.",
      "backend": "Async export с expiry, доступ только владельцу, exclude third-party private notes, audit."
    },
    {
      "id": "R03-R00",
      "source": "R03",
      "target": "R00",
      "label": "Выгрузка готова",
      "kind": "async",
      "actor": "system",
      "guard": "Expiring link после повторной identity check, не публичный URL.",
      "handoff": false,
      "event": "privacy.r03_r00",
      "frontend": "Фото, каналы, связанные входы, карты, выгрузка и удаление.",
      "backend": "Capabilities per owner of data; отдельные consent records, activity/audit view."
    },
    {
      "id": "R00-R04",
      "source": "R00",
      "target": "R04",
      "label": "Удалить аккаунт",
      "kind": "happy",
      "actor": "client",
      "guard": "Reauth, показать последствия и obligations.",
      "handoff": false,
      "event": "privacy.r00_r04",
      "frontend": "Показать будущие визиты, возвраты и последствия.",
      "backend": "Deletion intent с reauth, revoke sessions; не терять финансовые обязательства и открытые cases."
    },
    {
      "id": "R04-R05",
      "source": "R04",
      "target": "R05",
      "label": "Подтвердить удаление",
      "kind": "happy",
      "actor": "client",
      "guard": "Проверены step-up и отсутствие последнего owner grant. Сохранить минимальные обязательства по отдельной retention policy.",
      "handoff": false,
      "event": "privacy.r04_r05",
      "frontend": "Отмена/перенос будущих визитов и статус возвратов.",
      "backend": "Saga cancellation/refund; сроки хранения по утверждённой матрице, минимальные финансовые записи отделены от профиля."
    },
    {
      "id": "R04-R00",
      "source": "R04",
      "target": "R00",
      "label": "Отменить до исполнения",
      "kind": "exit",
      "actor": "client",
      "guard": "Если job ещё обратим; consumed deletion не отменять обещанием.",
      "handoff": false,
      "event": "privacy.r04_r00",
      "frontend": "Фото, каналы, связанные входы, карты, выгрузка и удаление.",
      "backend": "Capabilities per owner of data; отдельные consent records, activity/audit view."
    },
    {
      "id": "R05-P16",
      "source": "R05",
      "target": "P16",
      "label": "Есть незавершённый возврат",
      "kind": "async",
      "actor": "system",
      "guard": "Deletion не уничтожает payment mapping; limited-purpose records.",
      "handoff": false,
      "event": "privacy.r05_p16",
      "frontend": "Сумма, основание и статус рассмотрения.",
      "backend": "Refund entitlement/order version; сумма ≤ captured − successful/pending refunds. Не объявлять деньги возвращёнными при создании."
    },
    {
      "id": "R05-R06",
      "source": "R05",
      "target": "R06",
      "label": "Завершить удаление профиля",
      "kind": "happy",
      "actor": "system",
      "guard": "Media erased, no active auth; unresolved finance вынесено в ограниченный case и явно сообщено.",
      "handoff": false,
      "event": "privacy.r05_r06",
      "frontend": "Подтвердить удаление доступных данных и явно назвать сохранённые обязательные записи.",
      "backend": "Tombstone/anonymize, no marketing, erase media jobs reconciled; повторный вход не восстанавливает старые данные автоматически."
    },
    {
      "id": "R00-R07",
      "source": "R00",
      "target": "R07",
      "label": "Телефон потерян",
      "kind": "exception",
      "actor": "client",
      "guard": "Другой trusted канал, identity verification.",
      "handoff": false,
      "event": "privacy.r00_r07",
      "frontend": "Другой вход, завершить сессии и восстановить доступ.",
      "backend": "Risk review и revoke device; PAN/CVV не используются как доказательство личности."
    },
    {
      "id": "R07-A12",
      "source": "R07",
      "target": "A12",
      "label": "Отозвать сессии устройств",
      "kind": "recovery",
      "actor": "client",
      "guard": "Подтверждено владение аккаунтом.",
      "handoff": false,
      "event": "privacy.r07_a12",
      "frontend": "Подтвердить завершение сессий.",
      "backend": "Revoke refresh sessions, очистить sensitive cache; оплаченные визиты и компенсации продолжаются на сервере."
    },
    {
      "id": "R07-A10",
      "source": "R07",
      "target": "A10",
      "label": "Нет другого входа",
      "kind": "recovery",
      "actor": "client",
      "guard": "Human recovery без обхода доказательств личности.",
      "handoff": false,
      "event": "privacy.r07_a10",
      "frontend": "Другой связанный вход или обращение; сохранить request ID.",
      "backend": "Rate limit, recovery audit, проверка владения; саппорт не просит CVV/пароль мессенджера."
    },
    {
      "id": "R00-A12",
      "source": "R00",
      "target": "A12",
      "label": "Выйти со всех устройств",
      "kind": "happy",
      "actor": "client",
      "guard": "Own session, reauth для sensitive action.",
      "handoff": false,
      "event": "privacy.r00_a12",
      "frontend": "Подтвердить завершение сессий.",
      "backend": "Revoke refresh sessions, очистить sensitive cache; оплаченные визиты и компенсации продолжаются на сервере."
    },
    {
      "id": "A12-G00",
      "source": "A12",
      "target": "G00",
      "label": "Вернуться в гостевой режим",
      "kind": "exit",
      "actor": "system",
      "guard": "Local private cache очищен; серверные операции продолжаются.",
      "handoff": true,
      "event": "identity.a12_g00",
      "frontend": "Посмотреть концепцию, филиал и цены без регистрации.",
      "backend": "Публичный каталог без PII, rate limits; аналитика без присвоения клиентской личности."
    },
    {
      "id": "R00-A11",
      "source": "R00",
      "target": "A11",
      "label": "Выбрать рабочий контекст",
      "kind": "happy",
      "actor": "client",
      "guard": "Только memberships, возвращённые сервером.",
      "handoff": false,
      "event": "privacy.r00_a11",
      "frontend": "Выбрать один из разрешённых рабочих контекстов.",
      "backend": "Server проверяет active membership при каждом запросе; client/barber/owner могут принадлежать одному person."
    },
    {
      "id": "A11-O13",
      "source": "A11",
      "target": "O13",
      "label": "Режим владельца",
      "kind": "happy",
      "actor": "client",
      "guard": "Server owner scope и active grant.",
      "handoff": true,
      "event": "identity.a11_o13",
      "frontend": "Нагрузка, исключения, обращения, незакрытые оплаты.",
      "backend": "Read model по филиалу; только разрешённые персональные данные. Нет подмены банковского статуса."
    },
    {
      "id": "A11-B06",
      "source": "A11",
      "target": "B06",
      "label": "Режим барбера",
      "kind": "happy",
      "actor": "client",
      "guard": "Server active staff membership для филиала.",
      "handoff": true,
      "event": "identity.a11_b06",
      "frontend": "Предстоящие визиты, перерывы, свободные окна, незакрытые задачи.",
      "backend": "Scoped read model; server now и timezone филиала, запрет чужого расписания вне scope."
    },
    {
      "id": "A11-C00",
      "source": "A11",
      "target": "C00",
      "label": "Режим клиента",
      "kind": "happy",
      "actor": "client",
      "guard": "Own customer context, без staff impersonation.",
      "handoff": false,
      "event": "identity.a11_c00",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache."
    },
    {
      "id": "B10-A13",
      "source": "B10",
      "target": "A13",
      "label": "Доступ к визиту отозван",
      "kind": "exception",
      "actor": "barber",
      "guard": "Membership/assignment/consent больше не позволяет чтение.",
      "handoff": true,
      "event": "workforce.b10_a13",
      "frontend": "Объяснить отзыв роли, показать допустимый аккаунт и помощь.",
      "backend": "403 без чужих данных, токен не заменяет active grant; audit access denial."
    },
    {
      "id": "A13-A11",
      "source": "A13",
      "target": "A11",
      "label": "Перейти в разрешённый контекст",
      "kind": "recovery",
      "actor": "client",
      "guard": "Не использовать stale role cache.",
      "handoff": false,
      "event": "identity.a13_a11",
      "frontend": "Выбрать один из разрешённых рабочих контекстов.",
      "backend": "Server проверяет active membership при каждом запросе; client/barber/owner могут принадлежать одному person."
    },
    {
      "id": "R00-R08",
      "source": "R00",
      "target": "R08",
      "label": "Настроить доступность",
      "kind": "happy",
      "actor": "client",
      "guard": "Настройки не влияют на права/цены.",
      "handoff": false,
      "event": "privacy.r00_r08",
      "frontend": "Крупный шрифт, screen reader, тишина, reduced motion, текстовые альтернативы.",
      "backend": "Настройки не снижают право на запись; sensitive preference не уходит в общую аналитику."
    },
    {
      "id": "R08-C00",
      "source": "R08",
      "target": "C00",
      "label": "Продолжить с настройками",
      "kind": "happy",
      "actor": "client",
      "guard": "Font scale, reader, reduced motion остаются рабочими.",
      "handoff": false,
      "event": "privacy.r08_c00",
      "frontend": "Ближайший визит, образ, мастер, время и повтор.",
      "backend": "Агрегировать только свой контекст; skeleton/error/empty, нет фальшивого confirmed при stale cache."
    },
    {
      "id": "C21-S02",
      "source": "C21",
      "target": "S02",
      "label": "Пропала сеть",
      "kind": "exception",
      "actor": "client",
      "guard": "Последний snapshot помечен stale, никакой новой автоматической оплаты.",
      "handoff": false,
      "event": "booking.c21_s02",
      "frontend": "Локальный draft, последнее состояние и понятный offline status.",
      "backend": "Не ставить финансовые commands в слепую очередь; server operations продолжаются независимо от клиента."
    },
    {
      "id": "B13-S02",
      "source": "B13",
      "target": "S02",
      "label": "Закрылось приложение мастера",
      "kind": "exception",
      "actor": "system",
      "guard": "Service state сохраняется сервером, не завершается таймером UI.",
      "handoff": true,
      "event": "workforce.b13_s02",
      "frontend": "Локальный draft, последнее состояние и понятный offline status.",
      "backend": "Не ставить финансовые commands в слепую очередь; server operations продолжаются независимо от клиента."
    },
    {
      "id": "S02-S03",
      "source": "S02",
      "target": "S03",
      "label": "Сеть восстановилась",
      "kind": "recovery",
      "actor": "client",
      "guard": "Сначала authoritative fetch, затем reconcile pending intents.",
      "handoff": false,
      "event": "reliability.s02_s03",
      "frontend": "Сначала сверить актуальный статус, затем продолжить.",
      "backend": "Fetch operations/bookings revision, apply monotonic state, dedupe pending commands, refresh auth если истекла."
    },
    {
      "id": "S03-C12",
      "source": "S03",
      "target": "C12",
      "label": "Подтверждение найдено",
      "kind": "recovery",
      "actor": "system",
      "guard": "booking=confirmed и owner identity matches; не по cached success.",
      "handoff": false,
      "event": "reliability.s03_c12",
      "frontend": "Подтверждённый booking ID, адрес, календарь, подготовка.",
      "backend": "Только authoritative confirmed; outbox reminders; оплачено/к оплате показывается отдельно."
    },
    {
      "id": "S03-C08",
      "source": "S03",
      "target": "C08",
      "label": "Подтверждения нет, слот утрачен",
      "kind": "recovery",
      "actor": "system",
      "guard": "Payment reconciliation завершена или отдельно tracked.",
      "handoff": false,
      "event": "reliability.s03_c08",
      "frontend": "Сохранить услуги и предложить соседние окна.",
      "backend": "409 conflict → свежая availability; не создавать второй charge и не удалять существующий визит."
    },
    {
      "id": "S03-B06",
      "source": "S03",
      "target": "B06",
      "label": "Восстановить рабочий день",
      "kind": "recovery",
      "actor": "system",
      "guard": "Continuation staff, active grant; scope не берётся из localStorage.",
      "handoff": true,
      "event": "reliability.s03_b06",
      "frontend": "Предстоящие визиты, перерывы, свободные окна, незакрытые задачи.",
      "backend": "Scoped read model; server now и timezone филиала, запрет чужого расписания вне scope."
    },
    {
      "id": "S03-A00",
      "source": "S03",
      "target": "A00",
      "label": "Сессия истекла",
      "kind": "recovery",
      "actor": "system",
      "guard": "Сохранить только безопасный continuation, повторный auth.",
      "handoff": true,
      "event": "reliability.s03_a00",
      "frontend": "Telegram, Яндекс; MAX при готовом канале. Отказ не удаляет черновик.",
      "backend": "AuthTransaction с state/expiry/continuation. Ни один provider не задаёт роль сотрудника."
    },
    {
      "id": "O14-S04",
      "source": "O14",
      "target": "S04",
      "label": "Кто-то изменил график раньше",
      "kind": "exception",
      "actor": "owner",
      "guard": "Revision mismatch, никакого silent overwrite.",
      "handoff": false,
      "event": "operations.o14_s04",
      "frontend": "Показать обе версии и актуальное состояние.",
      "backend": "Optimistic concurrency/409; не last-write-wins для денег, места, consent и прав."
    },
    {
      "id": "C23-S04",
      "source": "C23",
      "target": "S04",
      "label": "Перенос конфликтует с отменой",
      "kind": "exception",
      "actor": "system",
      "guard": "Одна операция выигрывает atomic transition, другой client получает новое состояние.",
      "handoff": true,
      "event": "booking.c23_s04",
      "frontend": "Показать обе версии и актуальное состояние.",
      "backend": "Optimistic concurrency/409; не last-write-wins для денег, места, consent и прав."
    },
    {
      "id": "S04-O13",
      "source": "S04",
      "target": "O13",
      "label": "Пересмотреть актуальное состояние",
      "kind": "recovery",
      "actor": "owner",
      "guard": "Owner scope; пользовательский конфликт дополнительно сообщает текущий booking клиенту.",
      "handoff": false,
      "event": "reliability.s04_o13",
      "frontend": "Нагрузка, исключения, обращения, незакрытые оплаты.",
      "backend": "Read model по филиалу; только разрешённые персональные данные. Нет подмены банковского статуса."
    },
    {
      "id": "C43-S05",
      "source": "C43",
      "target": "S05",
      "label": "Создать обращение",
      "kind": "async",
      "actor": "client",
      "guard": "Case сохранён с SLA и owner; система не обещает мгновенный ответ.",
      "handoff": true,
      "event": "booking.c43_s05",
      "frontend": "Видимые unresolved cases, ответственный и срок.",
      "backend": "Retry budget exhausted → durable manual case, escalation, audit; не терять message в DLQ без владельца."
    },
    {
      "id": "S05-O13",
      "source": "S05",
      "target": "O13",
      "label": "Назначить ответственного",
      "kind": "handoff",
      "actor": "system",
      "guard": "Claim once, SLA timer, escalation если нет реакции.",
      "handoff": false,
      "event": "reliability.s05_o13",
      "frontend": "Нагрузка, исключения, обращения, незакрытые оплаты.",
      "backend": "Read model по филиалу; только разрешённые персональные данные. Нет подмены банковского статуса."
    },
    {
      "id": "O13-S06",
      "source": "O13",
      "target": "S06",
      "label": "Зафиксировать решение обращения",
      "kind": "happy",
      "actor": "owner",
      "guard": "Resolved downstream operations verified, audit и notice.",
      "handoff": false,
      "event": "operations.o13_s06",
      "frontend": "Показать решение и подтверждённые компенсации.",
      "backend": "Resolution reason + linked authoritative outcomes; unresolved payment/refund не закрывается кнопкой оператора."
    },
    {
      "id": "S06-C21",
      "source": "S06",
      "target": "C21",
      "label": "Сообщить результат по визиту",
      "kind": "handoff",
      "actor": "owner",
      "guard": "Own booking, актуальный статус, privacy.",
      "handoff": true,
      "event": "reliability.s06_c21",
      "frontend": "Маршрут, календарь, написать, перенести, отменить.",
      "backend": "Booking revision + policy snapshot; устаревшие ссылки пересматривают текущее состояние."
    },
    {
      "id": "S06-O23",
      "source": "S06",
      "target": "O23",
      "label": "Учесть причины в отчёте",
      "kind": "happy",
      "actor": "owner",
      "guard": "Агрегированные обезличенные причины, не medical free text.",
      "handoff": false,
      "event": "reliability.s06_o23",
      "frontend": "Конверсия, загрузка, повторы, отмены, качество без рейтинговой гонки.",
      "backend": "Агрегаты из событий, исключить технические дубли, cohort attribution; новые правила только следующей версией."
    },
    {
      "id": "C19-B18",
      "source": "C19",
      "target": "B18",
      "label": "Завершить услугу без фото",
      "kind": "happy",
      "actor": "barber",
      "guard": "Контекст — завершение текущей услуги; отказ касается только фото, assignment и in_service проверены.",
      "handoff": true,
      "event": "privacy.photo_declined_service_complete",
      "frontend": "Закончить услугу без сохранения фото.",
      "backend": "Service completion отдельно от media consent и settlement."
    },
    {
      "id": "R04-O24",
      "source": "R04",
      "target": "O24",
      "label": "Сначала передать управление",
      "kind": "recovery",
      "actor": "owner",
      "guard": "Текущая identity является последним владельцем; переход доступен только по уже существующему owner grant и после step-up.",
      "handoff": true,
      "event": "privacy.r04_o24",
      "frontend": "Усиленная проверка обеих сторон и подтверждение передачи.",
      "backend": "Не оставлять организацию без владельца; атомарная замена grant, аудит, отзыв старых полномочий."
    },
    {
      "id": "O24-R04",
      "source": "O24",
      "target": "R04",
      "label": "Вернуться к удалению аккаунта",
      "kind": "recovery",
      "actor": "owner",
      "guard": "Новый владелец принял управление, транзакция завершена. Вернуться к исходному deletion intent той же identity с повторной проверкой полномочий.",
      "handoff": true,
      "event": "privacy.o24_r04",
      "frontend": "Показать будущие визиты, возвраты и последствия.",
      "backend": "Deletion intent с reauth, revoke sessions; не терять финансовые обязательства и открытые cases."
    }
  ],
  "scenarios": [
    {
      "id": "J01",
      "name": "Владелец: от найма до открытия",
      "group": "Запуск",
      "nodeIds": [
        "O00",
        "O01",
        "O02",
        "O03",
        "O04",
        "O05",
        "O06",
        "O07",
        "O08",
        "O09",
        "O10",
        "B00",
        "B02",
        "B03",
        "B04",
        "B05",
        "O12"
      ],
      "edgeIds": [
        "O00-O01",
        "O01-O02",
        "O02-O03",
        "O03-O04",
        "O04-O05",
        "O05-O06",
        "O06-O07",
        "O07-O08",
        "O08-O09",
        "O09-O10",
        "O10-B00",
        "B00-B02",
        "B02-B03",
        "B03-B04",
        "B04-B05",
        "B05-O12"
      ],
      "goal": "Создать действующую команду и опубликовать запись только после проверки готовности."
    },
    {
      "id": "J02",
      "name": "Гость → первый оплаченный визит",
      "group": "Привлечение",
      "nodeIds": [
        "O12",
        "G00",
        "G01",
        "G02",
        "G03",
        "G05",
        "G06",
        "A00",
        "A01",
        "A04",
        "A06",
        "A07",
        "C00",
        "C03",
        "C02",
        "C04",
        "S01",
        "C06",
        "C07",
        "C09",
        "P00",
        "P01",
        "P06",
        "P07",
        "P08",
        "P10",
        "C10",
        "S00",
        "C12"
      ],
      "edgeIds": [
        "O12-G00",
        "G00-G01",
        "G01-G02",
        "G02-G03",
        "G03-G05",
        "G05-G06",
        "G06-A00",
        "A00-A01",
        "A01-A04",
        "A04-A06",
        "A06-A07",
        "A07-C00",
        "C00-C03",
        "C03-C02",
        "C02-C04",
        "C04-S01",
        "S01-C06",
        "C06-C07",
        "C07-C09",
        "C09-P00",
        "P00-P01",
        "P01-P06",
        "P06-P07",
        "P07-P08",
        "P08-P10",
        "P10-C10",
        "C10-S00",
        "S00-C12"
      ],
      "goal": "Три входа маркетолога сходятся в подтверждённой записи; платёж отделён от места."
    },
    {
      "id": "J03",
      "name": "Визит → паспорт → повтор",
      "group": "Возвращение",
      "nodeIds": [
        "C12",
        "C21",
        "C17",
        "C29",
        "B11",
        "B10",
        "B12",
        "B13",
        "C32",
        "B16",
        "B17",
        "B18",
        "C34",
        "S07",
        "C38",
        "C39",
        "C40",
        "C05",
        "C03"
      ],
      "edgeIds": [
        "C12-C21",
        "C21-C17",
        "C17-C29",
        "C29-B11",
        "B11-B10",
        "B10-B12",
        "B12-B13",
        "B13-C32",
        "C32-B16",
        "B16-B17",
        "B17-B18",
        "B18-C34",
        "C34-S07",
        "S07-C38",
        "C38-C39",
        "C39-C40",
        "C40-C05",
        "C05-C03"
      ],
      "goal": "Замкнуть память о результате в новую, добровольную запись."
    },
    {
      "id": "J04",
      "name": "Барбер заболел — замена",
      "group": "Исключения",
      "nodeIds": [
        "B06",
        "B08",
        "O15",
        "O16",
        "C22",
        "C23",
        "C12"
      ],
      "edgeIds": [
        "B06-B08",
        "B08-O15",
        "O15-O16",
        "O16-C22",
        "C22-C23",
        "C23-C12"
      ],
      "goal": "Не потерять визиты и не менять мастера без согласия клиента."
    },
    {
      "id": "J05",
      "name": "Клиент заболел — возврат",
      "group": "Исключения",
      "nodeIds": [
        "C21",
        "C26",
        "C24",
        "C25",
        "P16",
        "P17",
        "P18",
        "C40"
      ],
      "edgeIds": [
        "C21-C26",
        "C26-C24",
        "C24-C25",
        "C25-P16",
        "P16-P17",
        "P17-P18",
        "P18-C40"
      ],
      "goal": "Отменить визит и отдельно довести денежную компенсацию до результата."
    },
    {
      "id": "J06",
      "name": "Клиент опаздывает",
      "group": "Исключения",
      "nodeIds": [
        "C21",
        "C27",
        "B12",
        "B13",
        "C32",
        "B16",
        "B17",
        "B18",
        "C34"
      ],
      "edgeIds": [
        "C21-C27",
        "C27-B12",
        "B12-B13",
        "B13-C32",
        "C32-B16",
        "B16-B17",
        "B17-B18",
        "B18-C34"
      ],
      "goal": "Успеть обслужить только в согласованном scope без ущерба следующему клиенту."
    },
    {
      "id": "J07",
      "name": "Забыл, не пришёл, восстановился",
      "group": "Исключения",
      "nodeIds": [
        "N00",
        "N02",
        "N05",
        "C28",
        "C43",
        "S05",
        "O13",
        "S06",
        "C21"
      ],
      "edgeIds": [
        "N00-N02",
        "N02-N05",
        "N05-C28",
        "C28-C43",
        "C43-S05",
        "S05-O13",
        "O13-S06",
        "S06-C21"
      ],
      "goal": "No-show после проверки факта; человеческий разбор и ясный выход."
    },
    {
      "id": "J08",
      "name": "Напоминание не доставлено",
      "group": "Уведомления",
      "nodeIds": [
        "N00",
        "N02",
        "N03",
        "N08",
        "N04",
        "N06",
        "N00"
      ],
      "edgeIds": [
        "N00-N02",
        "N02-N03",
        "N03-N08",
        "N08-N04",
        "N04-N06",
        "N06-N00"
      ],
      "goal": "Fallback только с согласием; доставка не равна прочтению."
    },
    {
      "id": "J09",
      "name": "Оплата прошла, ответ потерян",
      "group": "Оплата",
      "nodeIds": [
        "P06",
        "P12",
        "P13",
        "P10",
        "C10",
        "S00",
        "C12"
      ],
      "edgeIds": [
        "P06-P12",
        "P12-P13",
        "P13-P10",
        "P10-C10",
        "C10-S00",
        "S00-C12"
      ],
      "goal": "Сверить одну операцию без повторного списания."
    },
    {
      "id": "J10",
      "name": "Оплачено, но слот утрачен",
      "group": "Оплата",
      "nodeIds": [
        "P08",
        "P10",
        "P25",
        "P16",
        "P17",
        "P18",
        "C40"
      ],
      "edgeIds": [
        "P08-P10",
        "P10-P25",
        "P25-P16",
        "P16-P17",
        "P17-P18",
        "P18-C40"
      ],
      "goal": "Компенсация paid-unallocated вместо двойного бронирования."
    },
    {
      "id": "J11",
      "name": "Сохранить и отвязать карту",
      "group": "Оплата",
      "nodeIds": [
        "P00",
        "P02",
        "P01",
        "P06",
        "P07",
        "P08",
        "P10",
        "P03",
        "P05",
        "R00"
      ],
      "edgeIds": [
        "P00-P02",
        "P02-P01",
        "P01-P06",
        "P06-P07",
        "P07-P08",
        "P08-P10",
        "P10-P03",
        "P03-P05",
        "P05-R00"
      ],
      "goal": "Consent, provider token, затем запрет будущих списаний без разрушения истории."
    },
    {
      "id": "J12",
      "name": "Наличные / терминал после услуги",
      "group": "Оплата",
      "nodeIds": [
        "C34",
        "P14",
        "P15",
        "P20",
        "S07",
        "C38"
      ],
      "edgeIds": [
        "C34-P14",
        "P14-P15",
        "P15-P20",
        "P20-S07",
        "S07-C38"
      ],
      "goal": "Учесть оплату на месте без фиктивного банковского callback."
    },
    {
      "id": "J13",
      "name": "PRIME CLUB и гостевой визит",
      "group": "Клуб",
      "nodeIds": [
        "L00",
        "L01",
        "P00",
        "P01",
        "P06",
        "P07",
        "P08",
        "P10",
        "L02",
        "L08",
        "G10",
        "A00",
        "A02",
        "A04",
        "A06",
        "A07",
        "L09",
        "C03"
      ],
      "edgeIds": [
        "L00-L01",
        "L01-P00",
        "P00-P01",
        "P01-P06",
        "P06-P07",
        "P07-P08",
        "P08-P10",
        "P10-L02",
        "L02-L08",
        "L08-G10",
        "G10-A00",
        "A00-A02",
        "A02-A04",
        "A04-A06",
        "A06-A07",
        "A07-L09",
        "L09-C03"
      ],
      "goal": "Плательщик и получатель раздельны; одноразовая привилегия."
    },
    {
      "id": "J14",
      "name": "Продление клуба не прошло",
      "group": "Клуб",
      "nodeIds": [
        "L02",
        "L04",
        "L05",
        "L07",
        "C00"
      ],
      "edgeIds": [
        "L02-L04",
        "L04-L05",
        "L05-L07",
        "L07-C00"
      ],
      "goal": "Ограничить повторы и сохранить историю без принудительного членства."
    },
    {
      "id": "J15",
      "name": "Недовольство → исправление",
      "group": "Качество",
      "nodeIds": [
        "B16",
        "C33",
        "C36",
        "O20",
        "C22",
        "C23",
        "C12"
      ],
      "edgeIds": [
        "B16-C33",
        "C33-C36",
        "C36-O20",
        "O20-C22",
        "C22-C23",
        "C23-C12"
      ],
      "goal": "Дать человеку выбор исправления; не принуждать к хорошему отзыву."
    },
    {
      "id": "J16",
      "name": "Потеря телефона и доступа",
      "group": "Приватность",
      "nodeIds": [
        "R00",
        "R07",
        "A10",
        "A00",
        "A02",
        "A04",
        "A06",
        "A07",
        "C00"
      ],
      "edgeIds": [
        "R00-R07",
        "R07-A10",
        "A10-A00",
        "A00-A02",
        "A02-A04",
        "A04-A06",
        "A06-A07",
        "A07-C00"
      ],
      "goal": "Восстановление с доказательством владения без слияния по совпавшему email."
    },
    {
      "id": "J17",
      "name": "Удаление профиля и обязательства",
      "group": "Приватность",
      "nodeIds": [
        "R00",
        "R04",
        "R05",
        "R06"
      ],
      "edgeIds": [
        "R00-R04",
        "R04-R05",
        "R05-R06"
      ],
      "goal": "Отозвать доступ, удалить допустимые данные, явно отделить ограниченные финансовые записи."
    },
    {
      "id": "J18",
      "name": "Мастер уходит из команды",
      "group": "Команда",
      "nodeIds": [
        "B06",
        "B22",
        "O17",
        "O18",
        "O21",
        "B20",
        "O23",
        "O06"
      ],
      "edgeIds": [
        "B06-B22",
        "B22-O17",
        "O17-O18",
        "O18-O21",
        "O21-B20",
        "B20-O23",
        "O23-O06"
      ],
      "goal": "Отозвать права, сверить расчёт, не потерять будущие визиты и клиентские паспорта."
    },
    {
      "id": "J19",
      "name": "Пауза в визитах и возвращение",
      "group": "Возвращение",
      "nodeIds": [
        "C38",
        "C39",
        "C41",
        "C00",
        "C05",
        "C03"
      ],
      "edgeIds": [
        "C38-C39",
        "C39-C41",
        "C41-C00",
        "C00-C05",
        "C05-C03"
      ],
      "goal": "Поездка, усталость или болезнь не повод для бесконечных напоминаний."
    },
    {
      "id": "J20",
      "name": "MAX недоступен — другой вход",
      "group": "Регистрация",
      "nodeIds": [
        "A00",
        "A03",
        "A05",
        "A00",
        "A02",
        "A04",
        "A06",
        "A07",
        "C00"
      ],
      "edgeIds": [
        "A00-A03",
        "A03-A05",
        "A05-A00",
        "A00-A02",
        "A02-A04",
        "A04-A06",
        "A06-A07",
        "A07-C00"
      ],
      "goal": "MAX условен до проверенной интеграции; нет тупика регистрации."
    },
    {
      "id": "J21",
      "name": "Перенос вместо отмены",
      "group": "Запись",
      "nodeIds": [
        "C21",
        "C22",
        "C23",
        "C12",
        "C21"
      ],
      "edgeIds": [
        "C21-C22",
        "C22-C23",
        "C23-C12",
        "C12-C21"
      ],
      "goal": "Исходный визит сохраняется до атомарной замены."
    },
    {
      "id": "J22",
      "name": "Лист ожидания",
      "group": "Запись",
      "nodeIds": [
        "C04",
        "C13",
        "C14",
        "C15",
        "C13",
        "C14",
        "C06",
        "C07",
        "C09"
      ],
      "edgeIds": [
        "C04-C13",
        "C13-C14",
        "C14-C15",
        "C15-C13",
        "C13-C14",
        "C14-C06",
        "C06-C07",
        "C07-C09"
      ],
      "goal": "Место становится визитом только после явного принятия и final commit."
    },
    {
      "id": "J23",
      "name": "Авария в филиале",
      "group": "Исключения",
      "nodeIds": [
        "O13",
        "O19",
        "O15",
        "C24",
        "C25",
        "P16",
        "P17",
        "P18"
      ],
      "edgeIds": [
        "O13-O19",
        "O19-O15",
        "O15-C24",
        "C24-C25",
        "C25-P16",
        "P16-P17",
        "P17-P18"
      ],
      "goal": "Каждый затронутый клиент получает понятное решение и компенсацию."
    },
    {
      "id": "J24",
      "name": "Положительный опыт → рекомендация",
      "group": "Возвращение",
      "nodeIds": [
        "S07",
        "C35",
        "C37",
        "C38",
        "L10",
        "G11",
        "G00"
      ],
      "edgeIds": [
        "S07-C35",
        "C35-C37",
        "C37-C38",
        "C38-L10",
        "L10-G11",
        "G11-G00"
      ],
      "goal": "Рекомендация добровольна, ссылка не раскрывает личные данные."
    },
    {
      "id": "J25",
      "name": "Чек задержался",
      "group": "Оплата",
      "nodeIds": [
        "P10",
        "P20",
        "P21",
        "S05",
        "O13",
        "S06",
        "O23"
      ],
      "edgeIds": [
        "P10-P20",
        "P20-P21",
        "P21-S05",
        "S05-O13",
        "O13-S06",
        "S06-O23"
      ],
      "goal": "Не списывать повторно из-за сбоя фискализации; видимый владелец проблемы."
    },
    {
      "id": "J26",
      "name": "Перерыв сети во время услуги",
      "group": "Надёжность",
      "nodeIds": [
        "B13",
        "S02",
        "S03",
        "B06",
        "B10"
      ],
      "edgeIds": [
        "B13-S02",
        "S02-S03",
        "S03-B06",
        "B06-B10"
      ],
      "goal": "Восстановить серверное состояние и разрешённый рабочий контекст."
    },
    {
      "id": "J27",
      "name": "Согласие и отказ от фотографий",
      "group": "Приватность",
      "nodeIds": [
        "C17",
        "C18",
        "C20",
        "C19",
        "C21"
      ],
      "edgeIds": [
        "C17-C18",
        "C18-C20",
        "C20-C19",
        "C19-C21"
      ],
      "goal": "Обслужить без фото; черновик и orphan upload не превращаются в публичное медиа."
    },
    {
      "id": "J28",
      "name": "Отбор кандидата и отказ",
      "group": "Команда",
      "nodeIds": [
        "O06",
        "O07",
        "O08",
        "O11",
        "O06"
      ],
      "edgeIds": [
        "O06-O07",
        "O07-O08",
        "O08-O11",
        "O11-O06"
      ],
      "goal": "Отказ закрывает временный доступ и возвращает владельца к поиску."
    }
  ],
  "closure": {
    "safeEnds": [
      "G07",
      "R06"
    ],
    "returnAnchors": [
      "O13",
      "B06",
      "C00",
      "C12",
      "C40",
      "G00"
    ],
    "meaning": "Обязательства замыкаются транзакцией, компенсацией или ответственным case; это граф совместной работы акторов, не одна сессия с правами всех ролей."
  },
  "policies": [
    {
      "id": "POL-01",
      "title": "Организация и роли",
      "proposal": "Одна организация PRIME с возможностью нескольких филиалов. Владелец может быть барбером и клиентом, но active context и API scope раздельны. Первого владельца заводит подтверждённая bootstrap-процедура.",
      "decisionOwner": "owner",
      "nodeIds": [
        "A11",
        "A13",
        "O00",
        "O01",
        "O24",
        "R04"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-02",
      "title": "Занятость и расчёт барбера",
      "proposal": "Тип договора, ставка, процент, база начисления, чаевые и правила перерасчёта не утверждены. В графе versioned offer и отдельный payroll ledger; приём оплаты клиента не выплачивает зарплату.",
      "decisionOwner": "owner",
      "nodeIds": [
        "O09",
        "O21",
        "B20"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-03",
      "title": "Предоплата",
      "proposal": "Проектная рекомендация: по умолчанию оплата на месте; предоплату включать по опубликованной политике услуги/клуба. Ставка configurable в basis points, default 0, не утверждённый тариф.",
      "decisionOwner": "owner",
      "nodeIds": [
        "O04",
        "C06",
        "P00"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-04",
      "title": "Удержание окна",
      "proposal": "Демо-значение hold TTL 5 минут. Серверное время, ограниченные продления; expiry не забывает уже начатый платёж. Не совпадает с банковской авторизацией.",
      "decisionOwner": "owner",
      "nodeIds": [
        "C07",
        "C16",
        "P25"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-05",
      "title": "Перенос и отмена",
      "proposal": "Версия правил фиксируется в заказе. Автоматические штрафы и списание за no-show выключены. Любое удержание требует заранее принятых условий и отдельного решения о правомерности; причина болезни без диагноза.",
      "decisionOwner": "owner",
      "nodeIds": [
        "C22",
        "C24",
        "C26",
        "C28"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-06",
      "title": "Опоздание",
      "proposal": "Для демо grace 10 минут, не гарантия обслуживания. Решение: оставшееся время ≥ согласованная длительность + buffer и есть согласие мастера/клиента. Иначе перенос/отмена; следующий визит защищён.",
      "decisionOwner": "owner",
      "nodeIds": [
        "C27",
        "B09"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-07",
      "title": "Уведомления",
      "proposal": "Демо cadence 24 часа и 2 часа до визита, если ещё актуально; snooze ограничен. Канал opt-in, quiet hours и timezone; критичное изменение уходит в очередь владельца при недоставке. Маркетинг отдельно.",
      "decisionOwner": "client",
      "nodeIds": [
        "N00",
        "N02",
        "N03",
        "N08",
        "C42"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-08",
      "title": "Лист ожидания",
      "proposal": "Демо offer TTL 15 минут. Справедливое согласованное правило очереди, atomic claim, без auto-book; предложенное окно может истечь.",
      "decisionOwner": "owner",
      "nodeIds": [
        "C13",
        "C14",
        "C15"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-09",
      "title": "PRIME CLUB",
      "proposal": "Тарифы и остатки маркетолога — гипотеза. До утверждения плана purchase disabled. Раздельные entitlement, guest pass, mandate продления; неизменяемый ledger, не самодельный денежный кошелёк.",
      "decisionOwner": "owner",
      "nodeIds": [
        "L00",
        "L01",
        "L02",
        "L03",
        "L04",
        "L05",
        "L06",
        "L07",
        "L08",
        "L09",
        "P24"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-10",
      "title": "Фото и чувствительные пожелания",
      "proposal": "Private passport по умолчанию, фото необязательны. Фото/портфолио/камера/маркетинг — разные разрешения. Retention, экспорт и удаление требуют конкретной матрицы до production; диагноз не собирать.",
      "decisionOwner": "client",
      "nodeIds": [
        "C18",
        "C19",
        "R01",
        "R02",
        "R04"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-11",
      "title": "ЮKassa и чеки",
      "proposal": "Один merchant по исходной модели; multi-merchant/split выплат не предполагать. Режим оплаты, фискальная схема, ставки/предмет расчёта и возвраты утверждаются с ответственными до live.",
      "decisionOwner": "owner",
      "nodeIds": [
        "O05",
        "P06",
        "P20",
        "P21",
        "O22"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-12",
      "title": "Покупка для другого человека",
      "proposal": "Payer ≠ recipient. Нельзя передавать историю по оплате. Возраст/законный представитель/согласия — открытое решение; сценарий несовершеннолетнего блокируется до конкретной политики.",
      "decisionOwner": "owner",
      "nodeIds": [
        "C45",
        "G10",
        "L09"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-13",
      "title": "Сроки и ручная поддержка",
      "proposal": "Демо: unresolved финансовая операция после ограниченного retry budget создаёт urgent case; целевой первый ответ 30 минут в рабочее время, не обещанный SLA. После рабочего времени показать реальное время ответа.",
      "decisionOwner": "owner",
      "nodeIds": [
        "S05",
        "S06",
        "P19",
        "C43"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-14",
      "title": "Вход и платформы",
      "proposal": "Telegram/Яндекс — документированные flows, MAX — conditional handoff. Нужны зарегистрированные apps и secrets до интеграции; iOS alternative login/Apple guideline отдельно. Кнопки схемы не выполняют вход.",
      "decisionOwner": "owner",
      "nodeIds": [
        "A00",
        "A01",
        "A02",
        "A03"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-15",
      "title": "Рекомендации и чаевые",
      "proposal": "Добровольный отзыв/рекомендация/чаевые. Rewards и tip provider включаются только после опубликованных правил и отдельного финансового потока; не награждать исключительно положительные отзывы.",
      "decisionOwner": "owner",
      "nodeIds": [
        "C35",
        "C37",
        "L10",
        "L11"
      ],
      "status": "proposal-needs-owner-decision"
    },
    {
      "id": "POL-16",
      "title": "Закрытие и сохранность обязательств",
      "proposal": "Закрытие филиала, уход сотрудника и удаление аккаунта не уничтожают payment/refund mappings. Ответственный case остаётся до authoritative решения; техническая очередь не считается завершённым возвратом.",
      "decisionOwner": "owner",
      "nodeIds": [
        "O17",
        "O19",
        "O24",
        "R04",
        "R05",
        "S05"
      ],
      "status": "proposal-needs-owner-decision"
    }
  ],
  "providers": [
    {
      "id": "TG-LOGIN",
      "name": "Telegram",
      "status": "documented-not-connected",
      "url": "https://core.telegram.org/bots/telegram-login",
      "checked": "2026-09-27",
      "decision": "OIDC authorization code + PKCE S256. Backend проверяет подпись, iss/aud/exp и state; phone и bot_access запрашиваются только по необходимости. Вход и разрешение на сообщения разделены."
    },
    {
      "id": "YANDEX-ID",
      "name": "Яндекс ID",
      "status": "documented-not-connected",
      "url": "https://yandex.ru/dev/id/doc/ru/codes/code-url",
      "checked": "2026-09-27",
      "decision": "Authorization code + PKCE S256 и state; токен обменивается сервером, redirect URI зарегистрирован. Минимальные scopes и доказанная identity вместо слияния по email."
    },
    {
      "id": "MAX-VALIDATION",
      "name": "MAX",
      "status": "conditional-spike-required",
      "url": "https://dev.max.ru/docs/webapps/validation",
      "checked": "2026-09-27",
      "decision": "Документирован mini-app initData с HMAC-SHA256 и auth_date. Для native PRIME нужен проверенный одноразовый handoff между mini-app и приложением. Самостоятельный MAX OIDC здесь не подтверждён; кнопку включать только после интеграционного spike, fallback Telegram/Яндекс."
    },
    {
      "id": "YOOKASSA-PROCESS",
      "name": "ЮKassa: состояния платежа",
      "status": "documented-not-connected",
      "url": "https://yookassa.ru/developers/payment-acceptance/getting-started/payment-process",
      "checked": "2026-09-27",
      "decision": "pending → waiting_for_capture/succeeded/canceled. succeeded и canceled финальны. expires_at авторизации берётся у провайдера; длинную запись нельзя обеспечивать бессрочным банковским hold. Возврат отдельным объектом."
    },
    {
      "id": "YOOKASSA-SAVE",
      "name": "ЮKassa: сохранение карты",
      "status": "documented-not-connected",
      "url": "https://yookassa.ru/developers/payment-acceptance/scenario-extensions/recurring-payments/save-payment-method/save-during-payment",
      "checked": "2026-09-27",
      "decision": "После отдельного согласия передать save_payment_method; сохранить идентификатор только при payment_method.saved=true. В PRIME — provider ID и маска, PAN/CVV не принимать. Первичная привязка в этой модели происходит при платеже; отдельная нулевая привязка требует проверки доступности магазина."
    },
    {
      "id": "YOOKASSA-WEBHOOKS",
      "name": "ЮKassa: уведомления",
      "status": "documented-not-connected",
      "url": "https://yookassa.ru/developers/using-api/webhooks",
      "checked": "2026-09-27",
      "decision": "Входящий webhook — сигнал для обработки. Архитектурное решение PRIME: durable inbox, проверка актуального объекта authenticated GET, суммы/валюты/магазина, дедупликация и монотонное состояние. Browser return URL не подтверждает оплату."
    },
    {
      "id": "YOOKASSA-IDEMPOTENCY",
      "name": "ЮKassa: идемпотентность",
      "status": "documented-not-connected",
      "url": "https://yookassa.ru/developers/using-api/interaction-format",
      "checked": "2026-09-27",
      "decision": "Idempotence-Key повторяет одну операцию с теми же параметрами; гарантия провайдера ограничена 24 часами. PRIME хранит собственную operation identity дольше; после окна сначала сверка, не слепой повтор POST."
    },
    {
      "id": "YOOKASSA-RECEIPTS",
      "name": "ЮKassa: чеки",
      "status": "merchant-configuration-required",
      "url": "https://yookassa.ru/developers/payment-acceptance/receipts/54fz/other-services/basics",
      "checked": "2026-09-27",
      "decision": "Фискальный сценарий выбирается с бухгалтерией и настройками магазина. В модели отдельные состояния чека оплаты, предоплаты/зачёта и возврата; сбой чека не запускает второй платёж."
    },
    {
      "id": "APPLE-LOGIN",
      "name": "Apple: Login Services",
      "status": "release-decision-required",
      "url": "https://developer.apple.com/app-store/review/guidelines/#login-services",
      "checked": "2026-09-27",
      "decision": "Перед iOS release проверить применимость 4.8 при сторонних способах входа и добавить подходящий равноценный вариант, например Sign in with Apple. Выбор провайдеров в графе не подтверждает готовность к App Review."
    }
  ],
  "apiContracts": [
    {
      "id": "CMD-AUTH",
      "route": "POST /v1/auth/transactions",
      "role": "guest",
      "aggregate": "Identity",
      "consistency": "state + PKCE; callback consume once",
      "nodeIds": [
        "A00",
        "A04"
      ],
      "payload": "state, expiresAt, provider, continuation",
      "failures": [
        "unauthorized",
        "expired",
        "replay",
        "provider_unavailable"
      ],
      "events": [
        "AuthVerified",
        "AuthRejected"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-INVITE",
      "route": "POST /v1/organizations/{org}/staff-invites",
      "role": "owner",
      "aggregate": "Invitation",
      "consistency": "Idempotency-Key + organization revision",
      "nodeIds": [
        "O10"
      ],
      "payload": "candidateId, intendedScope, offerVersion, expiry; token generated on server, hash at rest",
      "failures": [
        "forbidden",
        "version_conflict",
        "consumed",
        "revoked"
      ],
      "events": [
        "StaffInvited"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-SHIFT",
      "route": "PUT /v1/branches/{branch}/shifts/{id}",
      "role": "owner",
      "aggregate": "Shift",
      "consistency": "If-Match + audit reason",
      "nodeIds": [
        "O14",
        "S04"
      ],
      "payload": "interval, skills, resources, affectedBookings",
      "failures": [
        "forbidden",
        "overlap",
        "version_conflict"
      ],
      "events": [
        "ShiftChanged",
        "AvailabilityInvalidated"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-QUOTE",
      "route": "POST /v1/quotes",
      "role": "client",
      "aggregate": "Quote",
      "consistency": "Deterministic quote inputs + expiry",
      "nodeIds": [
        "C06"
      ],
      "payload": "services, recipient, branch, currency, policyVersion",
      "failures": [
        "stale_catalog",
        "invalid_entitlement",
        "missing_contact"
      ],
      "events": [
        "QuoteCreated"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-HOLD",
      "route": "POST /v1/slot-holds",
      "role": "client",
      "aggregate": "SlotHold",
      "consistency": "Idempotency-Key + resource exclusion constraint",
      "nodeIds": [
        "C07",
        "S01"
      ],
      "payload": "start/end UTC, timezone, quoteId, expiresAt",
      "failures": [
        "slot_conflict",
        "expired",
        "resource_unavailable"
      ],
      "events": [
        "SlotHeld",
        "SlotReleased"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-BOOK",
      "route": "POST /v1/bookings",
      "role": "client",
      "aggregate": "BookingSaga",
      "consistency": "Idempotency-Key + If-Match quote/hold",
      "nodeIds": [
        "C10",
        "S00"
      ],
      "payload": "quoteId, holdId, paymentIntentId, policyAcceptance",
      "failures": [
        "unknown",
        "conflict",
        "expired",
        "payment_unresolved"
      ],
      "events": [
        "BookingConfirmed",
        "CompensationRequired"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-MOVE",
      "route": "POST /v1/bookings/{id}/move",
      "role": "client",
      "aggregate": "Booking",
      "consistency": "Idempotency-Key + expectedRevision; old stays until commit",
      "nodeIds": [
        "C23"
      ],
      "payload": "newHoldId, quoteId, acceptedDelta",
      "failures": [
        "conflict",
        "stale_revision",
        "delta_unpaid"
      ],
      "events": [
        "BookingMoved",
        "PaymentAdjustmentRequested"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-CANCEL",
      "route": "POST /v1/bookings/{id}/cancel",
      "role": "client",
      "aggregate": "Booking",
      "consistency": "Idempotency-Key + expectedRevision + cancelQuote",
      "nodeIds": [
        "C25"
      ],
      "payload": "reason optional, cancellationQuoteId",
      "failures": [
        "in_service",
        "stale_quote",
        "stale_revision"
      ],
      "events": [
        "BookingCanceled",
        "RefundRequested",
        "WaitlistSlotOpened"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-PAY",
      "route": "POST /v1/payment-intents",
      "role": "client",
      "aggregate": "Payment",
      "consistency": "Unique operation + persisted provider idempotence key; tips require an enabled verified recipient channel and separate quote/ledger",
      "nodeIds": [
        "P06",
        "C37"
      ],
      "payload": "purpose, quoteId, ownedMethodId optional, saveConsent",
      "failures": [
        "unknown",
        "declined",
        "duplicate",
        "amount_changed",
        "tip_channel_unavailable"
      ],
      "events": [
        "PaymentPending",
        "PaymentSucceeded",
        "PaymentCanceled"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-WEBHOOK",
      "route": "POST /v1/integrations/yookassa/events",
      "role": "system",
      "aggregate": "ProviderInbox",
      "consistency": "Dedupe object id+type+state; verify authenticated GET before mutation",
      "nodeIds": [
        "P08"
      ],
      "payload": "provider object reference, verified shop/amount/currency",
      "failures": [
        "invalid_object",
        "mismatched_merchant",
        "unavailable"
      ],
      "events": [
        "ProviderStateReconciled"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Verified service identity only; never exposed as a client command."
    },
    {
      "id": "CMD-REFUND",
      "route": "POST /v1/orders/{id}/refunds",
      "role": "owner",
      "aggregate": "Refund",
      "consistency": "Idempotency-Key, authorized entitlement, bounded pending+successful amount",
      "nodeIds": [
        "P17"
      ],
      "payload": "paymentId, amountMinor, reason, orderRevision",
      "failures": [
        "over_refund",
        "unknown",
        "already_pending"
      ],
      "events": [
        "RefundPending",
        "RefundSucceeded",
        "RefundAttentionRequired"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-ARRIVE",
      "route": "POST /v1/bookings/{id}/arrive",
      "role": "barber",
      "aggregate": "Booking",
      "consistency": "Assignment/cashier scope as appropriate + revision",
      "nodeIds": [
        "B11"
      ],
      "payload": "observed arrival, server timestamp",
      "failures": [
        "forbidden",
        "canceled",
        "wrong_branch"
      ],
      "events": [
        "ClientArrived"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-SERVICE",
      "route": "POST /v1/bookings/{id}/service-events",
      "role": "barber",
      "aggregate": "VisitSession",
      "consistency": "Idempotency-Key + expected state/revision",
      "nodeIds": [
        "B13",
        "B15",
        "B18"
      ],
      "payload": "start, acceptedScope, complete, interruption reason",
      "failures": [
        "forbidden",
        "invalid_state",
        "price_unaccepted"
      ],
      "events": [
        "ServiceStarted",
        "ServiceCompleted"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-PASSPORT",
      "route": "POST /v1/visits/{id}/passport-revisions",
      "role": "barber",
      "aggregate": "Passport",
      "consistency": "Assignment + consent + expectedRevision",
      "nodeIds": [
        "B17"
      ],
      "payload": "parameters, privateMediaIds, author",
      "failures": [
        "consent_revoked",
        "media_not_ready",
        "revision_conflict"
      ],
      "events": [
        "PassportSaved"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-CONSENT",
      "route": "PUT /v1/me/consents/{purpose}",
      "role": "client",
      "aggregate": "Consent",
      "consistency": "Idempotency-Key + version; revoke propagates",
      "nodeIds": [
        "C42",
        "R02"
      ],
      "payload": "purpose, channel/media scope, version, accepted",
      "failures": [
        "invalid_scope",
        "stale_version"
      ],
      "events": [
        "ConsentChanged",
        "MediaPurgeRequested"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-CLUB",
      "route": "POST /v1/club/memberships",
      "role": "client",
      "aggregate": "Membership/Entitlement",
      "consistency": "Versioned plan, mandate, immutable ledger and unique period key",
      "nodeIds": [
        "L01"
      ],
      "payload": "planVersion, acceptedTerms, renewalConsent; activation only after verified settlement",
      "failures": [
        "plan_unpublished",
        "mandate_revoked",
        "entitlement_used"
      ],
      "events": [
        "MembershipPending",
        "MembershipActivated"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-CASE",
      "route": "POST /v1/support/cases",
      "role": "client",
      "aggregate": "SupportCase",
      "consistency": "Idempotency-Key + accessible references",
      "nodeIds": [
        "C43",
        "S05"
      ],
      "payload": "category, operationId, contact consent, description",
      "failures": [
        "forbidden_reference",
        "duplicate"
      ],
      "events": [
        "CaseOpened",
        "CaseEscalated"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-DELETE",
      "route": "POST /v1/me/deletion-requests",
      "role": "client",
      "aggregate": "DeletionSaga",
      "consistency": "Step-up auth + operation identity",
      "nodeIds": [
        "R04",
        "R05"
      ],
      "payload": "accepted consequences, pending obligations",
      "failures": [
        "reauth_required",
        "active_operation",
        "last_owner"
      ],
      "events": [
        "DeletionRequested",
        "ErasureCompleted"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-ABSENCE",
      "route": "POST /v1/staff/me/absence-incidents",
      "role": "barber",
      "aggregate": "AbsenceIncident",
      "consistency": "Idempotency-Key + active membership",
      "nodeIds": [
        "B08",
        "B09"
      ],
      "payload": "time interval, category without diagnosis",
      "failures": [
        "forbidden",
        "invalid_interval"
      ],
      "events": [
        "AvailabilityBlocked",
        "ReassignmentRequired"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-OFFBOARD",
      "route": "POST /v1/staff/{id}/offboarding",
      "role": "owner",
      "aggregate": "Membership",
      "consistency": "Step-up, expectedRevision, dependent booking handover",
      "nodeIds": [
        "O17",
        "O18"
      ],
      "payload": "effectiveAt, capabilities, affectedBookingIds",
      "failures": [
        "last_owner",
        "forbidden",
        "stale_revision"
      ],
      "events": [
        "MembershipRevoked",
        "SessionsRevoked"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-ORG",
      "route": "POST /v1/organizations",
      "role": "owner",
      "aggregate": "Organization",
      "consistency": "Provisioning entitlement + step-up; public identity cannot self-grant owner",
      "nodeIds": [
        "O00",
        "O01"
      ],
      "payload": "legalDisplayName, provisionToken; no payment secrets",
      "failures": [
        "forbidden",
        "duplicate"
      ],
      "events": [
        "OrganizationProvisioned"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-BRANCH",
      "route": "PUT /v1/organizations/{org}/branches/{id}",
      "role": "owner",
      "aggregate": "Branch",
      "consistency": "Tenant scope, If-Match, audit; closure schedules compensation before publication",
      "nodeIds": [
        "O02",
        "O19"
      ],
      "payload": "address, timezone IANA, openingHours, resources, closure interval/reason",
      "failures": [
        "forbidden",
        "version_conflict",
        "affected_bookings"
      ],
      "events": [
        "BranchChanged",
        "BranchClosurePlanned"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-CATALOG",
      "route": "PUT /v1/branches/{branch}/catalog/{id}",
      "role": "owner",
      "aggregate": "ServiceCatalog",
      "consistency": "Versioned catalog; issued quotes immutable until expiry",
      "nodeIds": [
        "O03"
      ],
      "payload": "name, durationMinutes, bufferMinutes, priceMinor, staffSkills, publication",
      "failures": [
        "invalid_price",
        "invalid_duration",
        "version_conflict"
      ],
      "events": [
        "CatalogVersionPublished"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-POLICY",
      "route": "POST /v1/organizations/{org}/policy-versions",
      "role": "owner",
      "aggregate": "ServicePolicy",
      "consistency": "Append-only publication; financial changes require owner approval and effectiveAt",
      "nodeIds": [
        "O04"
      ],
      "payload": "cancellation, deposit, grace, noShow, waitlist, notifications, club terms",
      "failures": [
        "incomplete_policy",
        "version_conflict"
      ],
      "events": [
        "PolicyVersionPublished"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-MERCHANT",
      "route": "POST /v1/organizations/{org}/merchant-connections",
      "role": "owner",
      "aggregate": "MerchantConnection",
      "consistency": "Step-up, tenant secret vault reference; sandbox/live mode explicit; no credentials in graph or logs",
      "nodeIds": [
        "O05"
      ],
      "payload": "merchantReference, environment, authorized vault reference, fiscal configuration",
      "failures": [
        "credentials_invalid",
        "merchant_mismatch",
        "fiscal_not_ready"
      ],
      "events": [
        "MerchantVerified"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-HIRING",
      "route": "POST /v1/organizations/{org}/vacancies",
      "role": "owner",
      "aggregate": "Vacancy",
      "consistency": "Scoped owner, versioned job conditions, applicant consent and retention",
      "nodeIds": [
        "O06"
      ],
      "payload": "skills, branch, capacity, offerVersion",
      "failures": [
        "forbidden",
        "invalid_terms"
      ],
      "events": [
        "VacancyOpened"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-CANDIDATE",
      "route": "POST /v1/vacancies/{id}/candidate-events",
      "role": "owner",
      "aggregate": "Candidate",
      "consistency": "Revision + consent; trial is explicitly supervised, no client-data access by default",
      "nodeIds": [
        "O07",
        "O08",
        "O09",
        "O11"
      ],
      "payload": "consider, trial, offer, reject; reason, termsVersion, permitted contact",
      "failures": [
        "consent_missing",
        "invalid_transition",
        "version_conflict"
      ],
      "events": [
        "CandidateReviewed",
        "TrialScheduled",
        "OfferIssued",
        "CandidateRejected"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-INVITE-ACCEPT",
      "route": "POST /v1/staff-invites/{token}/accept",
      "role": "authenticated",
      "aggregate": "StaffMembership",
      "consistency": "Token hashed, expiry/single-use, intended identity and scope, accepted offer version; atomic grant",
      "nodeIds": [
        "B00",
        "B01",
        "B02",
        "B03",
        "B21"
      ],
      "payload": "authenticated identity, offerVersion, acceptance; no caller role field",
      "failures": [
        "expired",
        "revoked",
        "already_consumed",
        "identity_mismatch",
        "offer_changed"
      ],
      "events": [
        "StaffJoined",
        "InviteRejected"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-ONBOARD",
      "route": "PUT /v1/staff/me/onboarding",
      "role": "barber",
      "aggregate": "StaffOnboarding",
      "consistency": "Current membership; owner verifies required skills before bookable=true",
      "nodeIds": [
        "B04",
        "B05"
      ],
      "payload": "profile, skills evidence, accepted policies, onboarding progress",
      "failures": [
        "forbidden",
        "requirements_missing"
      ],
      "events": [
        "OnboardingSubmitted",
        "StaffReady"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-PUBLISH",
      "route": "POST /v1/branches/{branch}/publication",
      "role": "owner",
      "aggregate": "Bookability",
      "consistency": "Atomic readiness check of services, staff, shifts, policy and payment configuration",
      "nodeIds": [
        "O12"
      ],
      "payload": "expected configuration versions, publish flag",
      "failures": [
        "staff_missing",
        "no_shifts",
        "policy_unapproved",
        "payment_not_ready"
      ],
      "events": [
        "BookingOpened"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-OPERATIONS",
      "route": "GET /v1/branches/{branch}/operations",
      "role": "owner",
      "aggregate": "OperationsReadModel",
      "consistency": "Server scope + redaction; pagination, asOf/version, no merchant status inferred from UI",
      "nodeIds": [
        "O13",
        "O23"
      ],
      "payload": "branch, range UTC, cursor",
      "failures": [
        "forbidden",
        "unavailable"
      ],
      "events": [],
      "status": "target-contract-not-implemented",
      "response": "Scoped read projection with asOf, revision and pagination when applicable; no state mutation.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-SHIFT-REQUEST",
      "route": "POST /v1/staff/me/shift-requests",
      "role": "barber",
      "aggregate": "ShiftRequest",
      "consistency": "Membership, expected schedule revision; request does not silently drop assigned bookings",
      "nodeIds": [
        "B07",
        "B22"
      ],
      "payload": "leave/resignation, interval, reason optional",
      "failures": [
        "forbidden",
        "invalid_interval"
      ],
      "events": [
        "ShiftChangeRequested"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-REASSIGN",
      "route": "POST /v1/absence-incidents/{id}/reassignments",
      "role": "owner",
      "aggregate": "ReassignmentSaga",
      "consistency": "Reserve compatible resource; client acceptance for material change; old booking retained until commit",
      "nodeIds": [
        "O15",
        "O16"
      ],
      "payload": "affectedBookingIds, alternative holds, contact status",
      "failures": [
        "conflict",
        "consent_pending",
        "no_alternative"
      ],
      "events": [
        "AlternativeOffered",
        "BookingReassigned",
        "CompensationRequired"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-DAY",
      "route": "GET /v1/staff/me/day",
      "role": "barber",
      "aggregate": "StaffDayReadModel",
      "consistency": "Assignment and branch scopes, privacy-redacted projection, no public client directory",
      "nodeIds": [
        "B06",
        "B10"
      ],
      "payload": "localDate, branchId, revision",
      "failures": [
        "forbidden",
        "unavailable"
      ],
      "events": [],
      "status": "target-contract-not-implemented",
      "response": "Scoped read projection with asOf, revision and pagination when applicable; no state mutation.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-SCOPE",
      "route": "POST /v1/visits/{id}/scope-quotes",
      "role": "barber",
      "aggregate": "VisitScopeQuote",
      "consistency": "Expected visit revision; next booking protected; client accepts new price/time before mutation",
      "nodeIds": [
        "B12",
        "B14",
        "C33",
        "P23"
      ],
      "payload": "requested change, estimated duration; separate clientAcceptance token",
      "failures": [
        "next_booking_conflict",
        "price_not_accepted",
        "revision_conflict"
      ],
      "events": [
        "ScopeQuoted",
        "ScopeAccepted"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-INCIDENT",
      "route": "POST /v1/visits/{id}/incidents",
      "role": "barber",
      "aggregate": "SafetyIncident",
      "consistency": "Assignment, minimally necessary facts, audited escalation; safety precedes payment workflow",
      "nodeIds": [
        "B23"
      ],
      "payload": "category, pauseService, immediate assistance action",
      "failures": [
        "forbidden",
        "invalid_visit"
      ],
      "events": [
        "ServicePaused",
        "IncidentEscalated"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-SHIFT-CLOSE",
      "route": "POST /v1/shifts/{id}/close",
      "role": "barber",
      "aggregate": "ShiftClose",
      "consistency": "Own shift, exception queue retained; never implies all payments captured",
      "nodeIds": [
        "B19"
      ],
      "payload": "expectedRevision, unresolvedVisitIds",
      "failures": [
        "forbidden",
        "active_visit"
      ],
      "events": [
        "ShiftClosed",
        "ShiftExceptionRecorded"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-PAYROLL",
      "route": "POST /v1/organizations/{org}/payroll-periods/{id}/close",
      "role": "owner",
      "aggregate": "BarberSettlement",
      "consistency": "Versioned remuneration terms + immutable ledger; actual transfer is separate explicit operation",
      "nodeIds": [
        "O21"
      ],
      "payload": "period, verified earningLines, adjustments with reasons",
      "failures": [
        "unresolved_dispute",
        "incomplete_period",
        "version_conflict"
      ],
      "events": [
        "SettlementCalculated",
        "SettlementApproved"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-EARNINGS",
      "route": "GET /v1/staff/me/earnings",
      "role": "barber",
      "aggregate": "EarningsReadModel",
      "consistency": "Own staff identity; correction as append-only dispute, no editing ledger",
      "nodeIds": [
        "B20"
      ],
      "payload": "period, cursor",
      "failures": [
        "forbidden",
        "unavailable"
      ],
      "events": [],
      "status": "target-contract-not-implemented",
      "response": "Scoped read projection with asOf, revision and pagination when applicable; no state mutation.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-RECONCILE",
      "route": "POST /internal/jobs/settlement-reconciliation",
      "role": "system",
      "aggregate": "Settlement",
      "consistency": "Service identity, durable operation identity; provider GET and outbox retries; no public caller",
      "nodeIds": [
        "O22",
        "P13",
        "P19",
        "P21",
        "P25"
      ],
      "payload": "operationId, provider object IDs, cursor",
      "failures": [
        "provider_unavailable",
        "mismatch",
        "unknown"
      ],
      "events": [
        "SettlementReconciled",
        "ReconciliationAttentionRequired"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Verified service identity only; never exposed as a client command."
    },
    {
      "id": "CMD-TRANSFER",
      "route": "POST /v1/organizations/{org}/ownership-transfers",
      "role": "owner",
      "aggregate": "OwnershipTransfer",
      "consistency": "Step-up on both parties, intended recipient acceptance, two-party transaction; at least one owner at commit",
      "nodeIds": [
        "O24"
      ],
      "payload": "recipientIdentity, expectedRevision, acceptanceProof",
      "failures": [
        "last_owner",
        "recipient_unverified",
        "forbidden",
        "version_conflict"
      ],
      "events": [
        "OwnershipTransferred",
        "SessionsRevoked"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-PUBLIC-CATALOG",
      "route": "GET /v1/public/branches/{branch}/catalog",
      "role": "guest",
      "aggregate": "PublicCatalog",
      "consistency": "Published, non-personal data only; no candidate/staff private fields",
      "nodeIds": [
        "G00",
        "G01",
        "G02",
        "G04",
        "G08",
        "C01",
        "C02",
        "C03"
      ],
      "payload": "branch, language, cursor",
      "failures": [
        "not_found",
        "unpublished",
        "unavailable"
      ],
      "events": [],
      "status": "target-contract-not-implemented",
      "response": "Scoped read projection with asOf, revision and pagination when applicable; no state mutation.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-AVAILABILITY",
      "route": "GET /v1/public/availability",
      "role": "guest",
      "aggregate": "AvailabilityProjection",
      "consistency": "UTC interval + branch timezone; projection is indicative, authoritative exclusion at hold commit",
      "nodeIds": [
        "G03",
        "G09",
        "C04",
        "C08",
        "C14",
        "C15",
        "S01"
      ],
      "payload": "branchId, serviceIds, barber preference, date",
      "failures": [
        "no_capacity",
        "stale_catalog",
        "unavailable"
      ],
      "events": [],
      "status": "target-contract-not-implemented",
      "response": "Scoped read projection with asOf, revision and pagination when applicable; no state mutation.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-AUTH-CALLBACK",
      "route": "POST /v1/auth/transactions/{id}/complete",
      "role": "guest",
      "aggregate": "AuthTransaction",
      "consistency": "Consume state once, code+PKCE backend exchange, issuer/audience/expiry checks; MAX gated until spike",
      "nodeIds": [
        "A01",
        "A02",
        "A03",
        "A04"
      ],
      "payload": "provider response, transactionId; no trusted client role or email merge",
      "failures": [
        "expired",
        "replay",
        "invalid_signature",
        "provider_unavailable",
        "feature_disabled"
      ],
      "events": [
        "IdentityVerified",
        "SessionIssued"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-PROFILE",
      "route": "PUT /v1/me/profile",
      "role": "authenticated",
      "aggregate": "Profile",
      "consistency": "If-Match, field minimization, contact verification; recipient consent distinct from purchaser identity",
      "nodeIds": [
        "A06",
        "C44",
        "C45"
      ],
      "payload": "name, verified contact, accessibility preferences, recipient relationship",
      "failures": [
        "unverified_contact",
        "forbidden_field",
        "version_conflict"
      ],
      "events": [
        "ProfileUpdated"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-SESSION",
      "route": "GET /v1/me/context",
      "role": "authenticated",
      "aggregate": "SessionContext",
      "consistency": "Server grants + scope + revision; role switch only selects existing capability",
      "nodeIds": [
        "A07",
        "A11",
        "A13",
        "C00",
        "S03"
      ],
      "payload": "organization context, sinceVersion",
      "failures": [
        "unauthorized",
        "forbidden",
        "revoked"
      ],
      "events": [],
      "status": "target-contract-not-implemented",
      "response": "Scoped read projection with asOf, revision and pagination when applicable; no state mutation.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-IDENTITY-LINK",
      "route": "POST /v1/me/identity-links",
      "role": "authenticated",
      "aggregate": "IdentityLink",
      "consistency": "Recent reauth + verified second provider; never merge by display name or unverified email/phone",
      "nodeIds": [
        "A08",
        "A09"
      ],
      "payload": "new provider transaction proof",
      "failures": [
        "identity_already_linked",
        "reauth_required",
        "conflict"
      ],
      "events": [
        "IdentityLinked",
        "IdentityLinkConflict"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-RECOVERY",
      "route": "POST /v1/auth/recovery-cases",
      "role": "guest",
      "aggregate": "IdentityRecovery",
      "consistency": "Rate limits, minimum proof, revoke lost session; no public account-existence leak",
      "nodeIds": [
        "A10",
        "R07"
      ],
      "payload": "provider proof or recovery case, safe contact",
      "failures": [
        "invalid_proof",
        "rate_limited",
        "manual_review"
      ],
      "events": [
        "RecoveryStarted",
        "SessionsRevoked"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-LOGOUT",
      "route": "POST /v1/me/sessions/revoke",
      "role": "authenticated",
      "aggregate": "Session",
      "consistency": "Current verified identity, per-session/all scope; invalidate refresh family and push device association",
      "nodeIds": [
        "A12"
      ],
      "payload": "sessionIds or all; current session last",
      "failures": [
        "unauthorized"
      ],
      "events": [
        "SessionsRevoked"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-WAITLIST",
      "route": "POST /v1/waitlist-entries",
      "role": "client",
      "aggregate": "WaitlistEntry",
      "consistency": "Deduplicate client preference; expires/cancelable, opt-in channel; no slot promised",
      "nodeIds": [
        "C13"
      ],
      "payload": "branch/services/time windows/barber preference, notification consent",
      "failures": [
        "consent_missing",
        "invalid_window"
      ],
      "events": [
        "WaitlistJoined"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-WAITLIST-OFFER",
      "route": "POST /internal/jobs/waitlist-offers",
      "role": "system",
      "aggregate": "WaitlistOffer",
      "consistency": "Atomic ordered claim, offer expiry from server; capacity hold exclusive; expire once then offer next",
      "nodeIds": [
        "C14",
        "C15"
      ],
      "payload": "vacated resource interval, policyVersion, queue cursor",
      "failures": [
        "no_capacity",
        "expired",
        "already_claimed"
      ],
      "events": [
        "WaitlistOffered",
        "WaitlistOfferExpired"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Verified service identity only; never exposed as a client command."
    },
    {
      "id": "CMD-WAITLIST-CLAIM",
      "route": "POST /v1/waitlist-offers/{id}/claim",
      "role": "client",
      "aggregate": "WaitlistOffer",
      "consistency": "Owner of entry, current server expiry, atomic claim to hold; booking still requires quote acceptance",
      "nodeIds": [
        "C14"
      ],
      "payload": "expected offer version",
      "failures": [
        "expired",
        "already_claimed",
        "forbidden"
      ],
      "events": [
        "WaitlistOfferClaimed"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-MEDIA",
      "route": "POST /v1/me/media-uploads",
      "role": "client",
      "aggregate": "PrivateMedia",
      "consistency": "Purpose-scoped consent; private short-lived upload URL; type/size scan, checksum, ACL, deletion propagation",
      "nodeIds": [
        "C18",
        "C20",
        "R01"
      ],
      "payload": "purpose, contentType, byteLength, digest; no public URL",
      "failures": [
        "consent_missing",
        "too_large",
        "unsupported_type",
        "scan_failed"
      ],
      "events": [
        "PrivateMediaReady",
        "MediaRejected"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-LATE",
      "route": "POST /v1/bookings/{id}/arrival-updates",
      "role": "client",
      "aggregate": "ArrivalEstimate",
      "consistency": "Own booking + revision; no automatic repricing or shortening without agreement",
      "nodeIds": [
        "C26",
        "C27",
        "C30",
        "C31"
      ],
      "payload": "estimated arrival, reason category optional; no diagnosis",
      "failures": [
        "canceled",
        "stale_revision",
        "wrong_branch"
      ],
      "events": [
        "ArrivalEstimateChanged",
        "AssistanceRequested"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-NOSHOW",
      "route": "POST /v1/bookings/{id}/no-show-reviews",
      "role": "barber",
      "aggregate": "AttendanceReview",
      "consistency": "Assigned staff/owner, server grace elapsed, manual confirmation and audit; disputed arrival preserved",
      "nodeIds": [
        "C28"
      ],
      "payload": "observed absence, contact attempts, expectedRevision",
      "failures": [
        "grace_not_elapsed",
        "arrived",
        "version_conflict"
      ],
      "events": [
        "NoShowRecorded",
        "NoShowDisputed"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-CASH",
      "route": "POST /v1/orders/{id}/counter-payments",
      "role": "barber",
      "aggregate": "CounterPayment",
      "consistency": "Explicit cashier capability, expected amount/version, idempotency; assigned barber alone insufficient",
      "nodeIds": [
        "P14",
        "P15"
      ],
      "payload": "amountMinor, cash/external_terminal, receipt reference",
      "failures": [
        "cashier_scope_required",
        "amount_mismatch",
        "duplicate"
      ],
      "events": [
        "CounterPaymentRecorded",
        "ReceiptRequested"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-METHODS",
      "route": "GET /v1/me/payment-methods",
      "role": "client",
      "aggregate": "SavedPaymentMethod",
      "consistency": "Identity owns token; masked details only, no PAN/CVV; reusable only if provider.saved=true",
      "nodeIds": [
        "P03",
        "P04"
      ],
      "payload": "cursor",
      "failures": [
        "unauthorized",
        "unavailable"
      ],
      "events": [],
      "status": "target-contract-not-implemented",
      "response": "Scoped read projection with asOf, revision and pagination when applicable; no state mutation.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-UNLINK-CARD",
      "route": "DELETE /v1/me/payment-methods/{id}",
      "role": "client",
      "aggregate": "SavedPaymentMethod",
      "consistency": "Ownership + reauth where needed; disable local future use, cancel dependent renewal mandate, audit",
      "nodeIds": [
        "P05"
      ],
      "payload": "expectedRevision, acknowledge affected mandates",
      "failures": [
        "forbidden",
        "active_charge",
        "version_conflict"
      ],
      "events": [
        "PaymentMethodDisabled",
        "RenewalMandateRevoked"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-REFUND-QUOTE",
      "route": "POST /v1/bookings/{id}/cancellation-quotes",
      "role": "client",
      "aggregate": "CancellationQuote",
      "consistency": "Versioned policy captured at booking; exact refund bound, pending adjustments included",
      "nodeIds": [
        "C24",
        "P16"
      ],
      "payload": "bookingRevision, reason optional",
      "failures": [
        "in_service",
        "stale_revision",
        "unavailable"
      ],
      "events": [
        "CancellationQuoted"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-PAYMENT-CAPTURE",
      "route": "POST /internal/jobs/payment-settlements",
      "role": "system",
      "aggregate": "PaymentSettlement",
      "consistency": "Authenticated worker, reservation allocation confirmed, provider current state/expiry, persisted idempotence key",
      "nodeIds": [
        "P09",
        "P10"
      ],
      "payload": "authorized paymentId, capture amount or cancellation decision",
      "failures": [
        "expired",
        "canceled",
        "amount_exceeded",
        "unknown"
      ],
      "events": [
        "PaymentCaptured",
        "AuthorizationCanceled"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Verified service identity only; never exposed as a client command."
    },
    {
      "id": "CMD-RECEIPT",
      "route": "GET /v1/me/orders/{id}/receipts",
      "role": "client",
      "aggregate": "FiscalReceipt",
      "consistency": "Owned order; receipt pending/ready/failed distinct from successful payment",
      "nodeIds": [
        "P20",
        "P21"
      ],
      "payload": "orderId",
      "failures": [
        "forbidden",
        "pending",
        "unavailable"
      ],
      "events": [],
      "status": "target-contract-not-implemented",
      "response": "Scoped read projection with asOf, revision and pagination when applicable; no state mutation.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-NOTIFICATION",
      "route": "POST /internal/jobs/notification-deliveries",
      "role": "system",
      "aggregate": "NotificationDelivery",
      "consistency": "Outbox+dedupe booking/version/channel; current schedule and consent, quiet hours; no mass fallback without consent",
      "nodeIds": [
        "N00",
        "N02",
        "N03",
        "N08"
      ],
      "payload": "templateVersion, minimal payload, recipient reference",
      "failures": [
        "channel_denied",
        "unreachable",
        "stale_booking",
        "retry_exhausted"
      ],
      "events": [
        "NotificationDelivered",
        "NotificationFailed"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Verified service identity only; never exposed as a client command."
    },
    {
      "id": "CMD-REMINDER",
      "route": "PUT /v1/me/bookings/{id}/reminders",
      "role": "client",
      "aggregate": "ReminderPreference",
      "consistency": "Own booking; preferences distinct from OS permission and actual delivery",
      "nodeIds": [
        "N01",
        "N04",
        "N06",
        "N07",
        "C42"
      ],
      "payload": "channel, snoozeUntil, disabled, read event",
      "failures": [
        "forbidden",
        "invalid_time",
        "channel_unavailable"
      ],
      "events": [
        "ReminderPreferenceChanged"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-MEMBERSHIP",
      "route": "PUT /v1/me/club/membership",
      "role": "client",
      "aggregate": "ClubMembership",
      "consistency": "Versioned plan and separate renewal mandate; respect paid period and reserved credits",
      "nodeIds": [
        "L04",
        "L06"
      ],
      "payload": "autoRenew consent, pause/cancel effective date",
      "failures": [
        "plan_changed",
        "active_entitlement_conflict"
      ],
      "events": [
        "RenewalMandateChanged",
        "MembershipPaused"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-RENEWAL",
      "route": "POST /internal/jobs/club-renewals",
      "role": "system",
      "aggregate": "RenewalAttempt",
      "consistency": "One attempt per membership/period; valid current mandate; no overlap/charge after revocation, bounded retries",
      "nodeIds": [
        "L04",
        "L05",
        "L07"
      ],
      "payload": "membershipId, periodKey",
      "failures": [
        "mandate_revoked",
        "payment_failed",
        "unknown"
      ],
      "events": [
        "RenewalSucceeded",
        "RenewalFailed",
        "MembershipExpired"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Verified service identity only; never exposed as a client command."
    },
    {
      "id": "CMD-ENTITLEMENT",
      "route": "POST /v1/club/entitlement-reservations",
      "role": "client",
      "aggregate": "EntitlementLedger",
      "consistency": "Atomic reserve one usable credit per booking; consume only once at completed service; release on cancel",
      "nodeIds": [
        "L03",
        "P24"
      ],
      "payload": "entitlementId, bookingId, expectedRevision",
      "failures": [
        "exhausted",
        "expired",
        "already_reserved"
      ],
      "events": [
        "EntitlementReserved",
        "EntitlementConsumed",
        "EntitlementReleased"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-GUEST-PASS",
      "route": "POST /v1/club/guest-passes",
      "role": "client",
      "aggregate": "GuestPass",
      "consistency": "Eligible membership, quota, server-generated single-use token, expiry; no friend contact uploaded without consent",
      "nodeIds": [
        "L08",
        "G10"
      ],
      "payload": "entitlementId, optional display message",
      "failures": [
        "quota_exceeded",
        "expired"
      ],
      "events": [
        "GuestPassIssued"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-GUEST-CLAIM",
      "route": "POST /v1/club/guest-passes/{token}/claim",
      "role": "client",
      "aggregate": "GuestPass",
      "consistency": "Authenticated intended beneficiary, atomic single claim, expiry; not a transferable identity token",
      "nodeIds": [
        "L09"
      ],
      "payload": "verified identity, guest eligibility",
      "failures": [
        "expired",
        "already_claimed",
        "ineligible"
      ],
      "events": [
        "GuestPassClaimed"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-REFERRAL",
      "route": "POST /v1/me/referrals",
      "role": "client",
      "aggregate": "Referral",
      "consistency": "Unique attribution, anti-self-referral; reward only after eligible completed non-refunded visit",
      "nodeIds": [
        "L10",
        "L11"
      ],
      "payload": "referralCode, qualifyingVisitId",
      "failures": [
        "self_referral",
        "duplicate",
        "ineligible",
        "refunded"
      ],
      "events": [
        "ReferralAttributed",
        "RewardGranted",
        "RewardReversed"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-REVIEW",
      "route": "POST /v1/visits/{id}/feedback",
      "role": "client",
      "aggregate": "VisitFeedback",
      "consistency": "Own completed visit, one revisable review; visibility choice, no public photo by default",
      "nodeIds": [
        "C35",
        "C36",
        "C37"
      ],
      "payload": "score, text, private/public choice, category",
      "failures": [
        "visit_not_completed",
        "forbidden",
        "version_conflict"
      ],
      "events": [
        "FeedbackSubmitted",
        "CaseOpened"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-PASSPORT-READ",
      "route": "GET /v1/me/passports/{id}",
      "role": "client",
      "aggregate": "PassportReadModel",
      "consistency": "Own immutable revision history; photos consent/expiry checked, suggestions optional",
      "nodeIds": [
        "C05",
        "C38",
        "C39",
        "C40"
      ],
      "payload": "revision, cursor",
      "failures": [
        "forbidden",
        "deleted",
        "media_unavailable"
      ],
      "events": [],
      "status": "target-contract-not-implemented",
      "response": "Scoped read projection with asOf, revision and pagination when applicable; no state mutation.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-EXPORT",
      "route": "POST /v1/me/data-exports",
      "role": "authenticated",
      "aggregate": "DataExport",
      "consistency": "Step-up, asynchronous immutable snapshot, expiring authenticated download, audit",
      "nodeIds": [
        "R03"
      ],
      "payload": "format, scope",
      "failures": [
        "reauth_required",
        "already_running"
      ],
      "events": [
        "DataExportReady"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-CASE-RESOLVE",
      "route": "POST /v1/support/cases/{id}/resolution",
      "role": "owner",
      "aggregate": "SupportCase",
      "consistency": "Authorized case scope, expected revision; escalation deadline, independent payment refund authority",
      "nodeIds": [
        "O20",
        "S05",
        "S06",
        "P22"
      ],
      "payload": "resolution, next action owner, dueAt, linked operationIds",
      "failures": [
        "forbidden",
        "unresolved_payment",
        "stale_revision"
      ],
      "events": [
        "CaseResolved",
        "CaseEscalated"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Backend verifies identity, capability and resource scope on every request; graph role is descriptive, never authority."
    },
    {
      "id": "CMD-VISIT-CLOSE",
      "route": "POST /internal/jobs/visit-close",
      "role": "system",
      "aggregate": "VisitClosure",
      "consistency": "Service complete + final balanced settlement + entitlement ledger; unknown payments stay pending, outbox atomic",
      "nodeIds": [
        "C34",
        "S07"
      ],
      "payload": "visitId, expected revisions",
      "failures": [
        "payment_unresolved",
        "service_active",
        "ledger_mismatch"
      ],
      "events": [
        "VisitClosed",
        "RepeatSuggestionEligible"
      ],
      "status": "target-contract-not-implemented",
      "response": "Current aggregate state and revision; operationId for asynchronous commands; safe code + retryable + correlationId on failure.",
      "authorization": "Verified service identity only; never exposed as a client command."
    }
  ]
}
