← Назад Harupa
2026-06-29RU EN UA BY PL

My Architect, часть 8: Event Storming — контроль последовательности, а не ещё одна диаграмма

Это восьмая статья серии про My Architect. Для тех, кто не читал предыдущие части, коротко: My Architect — система, где проект живёт между сессиями AI-агента. Одной стороной она повёрнута к агенту — он ведёт проект через MCP; другой к человеку — визуальный интерфейс показывает, что агент уже сделал, и весь прогресс по проекту. Эта статья — про один конкретный механизм такого контроля.

Витрина здесь — Forklift, средний домен доставки еды из пяти bounded-контекстов. Все доски, цифры анализатора и фрагменты DSL ниже настоящие: проект засидлен локально и проходит через реальный analyzeEsSequence. Ничего не выдумано.

Диаграмма ради диаграммы бесполезна. Контроль последовательности — нет

У всех нас есть это кладбище. Папка docs/architecture, где лежат красивые PNG, нарисованные полгода назад, и ни один уже не соответствует коду. Диаграмма-картинка — это снимок чьих-то благих намерений на момент времени T. Она ничего не проверяет. Она не знает, что вы забыли подключить ветку отмены. Она радостно покажет стрелку, которой в коде нет, и умолчит о пятнадцати, которые есть.

Поэтому когда я говорю «агент рисует Event Storming доску», у вас справедливо дёргается глаз. Ещё одна картинка? Нет. Разница в одном слове: последовательность.

Event Storming — это не диаграмма коробочек. Это разложенная во времени история того, как событие порождает реакцию, реакция — команду, команда — новое событие. У доменного события («Заказ размещён») есть причина. У команды («Разместить заказ») есть результат. Политика («Как только платёж авторизован → подтвердить заказ») — мост между чужим событием и твоей командой. И вот это свойство — всё имеет причину и следствие — превращается из красивой философии в машинно-проверяемый инвариант.

Если событие висит без причины — это брешь. Если команда не порождает события — брешь. Если политика ничего не мостит — брешь. Если карточка изолирована — кто-то набросал мысль и не довёл. Этих брешей не видно глазами на доске из сорока стикеров. Но их видно анализатору, который читает граф последовательности.

Витрина у нас аппетитная — Forklift: on-demand food delivery, from tap to doorstep. Пять bounded-контекстов: Ordering, Payments, Kitchen, Dispatch, Tracking. Ровно тот класс домена, где «забыл подключить ветку» стоит реальных денег: еда приготовлена — деньги не списаны; курьер не назначен — клиент жалуется.

Forklift — доска Dispatch / Delivery Контекст Dispatch: команды (синие) → события (оранжевые), политики-мосты (сиреневые), read-models (зелёные), внешние системы (розовые), акторы (жёлтые) и открытые вопросы — hotspot'ы (ромбы) внизу.

Почему именно агенту это даёт рычаг

Человек смотрит на доску и чувствует, что чего-то не хватает. Иногда находит. Чаще — нет: внимание не масштабируется, на тридцатой карточке вы уже не помните, свели ли исход команды «Отклонить заказ».

Агент не чувствует. Агент запускает детерминированную проверку графа. analyzeEsSequence обходит причинно-следственный граф доски и возвращает структурированный вердикт: ok, список gaps с типом (isolated, event-without-cause, command-without-effect, policy-not-bridging) и уровнем (warning / info), и отдельно — openQuestions (hotspot-карточки).

Это и есть рычаг. У агента появляется петля обратной связи, которая не врёт и не устаёт:

  1. Author — агент авторит доску через create_diagram(diagramType:'event-storming', nodeId), привязывая её к узлу иерархии (эпику/инициативе).
  2. Validate — читает через get_diagram; поле sequence показывает бреши в истории.
  3. Refine — чинит через update_diagram и валидирует снова, пока gaps не схлопнется до нуля.
  4. Re-validate during implementation — во время реализации повторно гоняет проверку: код разошёлся с историей → доска снова краснеет.

Агент не пытается быть умным «на глаз». Он опирается на дешёвую детерминированную проверку и итерирует до зелёного — ровно так, как итерирует тесты.

Петля в действии: Ordering, от чёрного черновика до чистой истории

Сначала агент набросал v0 контекста Ordering — честный черновик, какой набрасывает живой человек: схватил основную нить, пометил «сюда вернётся ответ из Payments» — и не довёл хвост.

event-storming
# фрагмент: показана только основная нить Ordering, на доске карточек больше

group "Ordering"
  [command] "Place order"
  [event]   "Order placed"
  [policy]  "Whenever Payment authorized → Confirm order"
  [command] "Confirm order"
  [event]   "Order confirmed"
  [command] "Cancel order"

connect "Place order" -> "Order placed"
# "Whenever Payment authorized → Confirm order" — ни к чему не подключена  (isolated policy)
# "Cancel order" — ни входящего, ни исходящего                            (isolated command)
# "Order confirmed" — без входящей причины                                (event-without-cause, info)

Агент читает get_diagram, прогоняет анализатор и получает по v0:

27 cards · 19 connections · 1 contexts — 2 sequence gap(s), 0 open question(s)
gaps:
  • "Whenever Payment authorized → Confirm order" (policy) is not connected to anything
  • "Cancel order" (command) is not connected to anything

Две бреши-warning (изолированная политика возврата из Payments и недозамкнутый хвост отмены) плюс одна info-пометка («Order confirmed» без причины — порождающая команда не сведена). Дальше — refine: агент подключает порождающую команду, мостит политику в команду подтверждения, замыкает хвост отмены результирующим событием. Повторная валидация v1:

34 cards · 30 connections · 1 contexts — 0 sequence gap(s), 3 open question(s)

Бреши схлопнулись. Но — и это важно — доска не стала пустой и не стала врать «всё решено». Осталось ровно три карточки, которые агент сознательно оставил красными. О них — ниже.

Та же петля на Payments: где черновик особенно опасен

Payments — контекст, где недопроведённая стрелка означает «еда приготовлена, деньги не сняты» или «деньги сняты дважды». Здесь v0 был дырявым, и это нормально: именно поэтому проверка и нужна.

Forklift — доска Payments

Вердикт анализатора по v0 Payments:

25 cards · 15 connections · 1 contexts — 3 sequence gap(s), 0 open question(s)
gaps:
  • "Issue refund" (command) is not connected to anything        — путь возврата нарисован наполовину
  • "Chargeback opened" (event) is not connected to anything     — забытая ветка отказа
  • "On decline cancel order" (policy) missing outgoing command  — мост к отмене брошен на шве

После refine агент замыкает путь возврата (Evaluate refund → Issue refund → Refund issued), сводит обработку чарджбэка и достраивает мост политики decline в Cancel order. Вердикт по v1:

39 cards · 27 connections · 1 contexts — 0 sequence gap(s), 3 open question(s)

И снова — три карточки остаются красными намеренно (capture-vs-reject race, атрибуция вины при возврате, владелец liability по чарджбэку).

Остальные три контекста: тот же паттерн

Петля везде одна и та же. Что поймал анализатор в v0 — и до чего схлопнулось в v1:

Контекстv0 (бреши)v1Что было сломано в v0
Ordering2 →0изолированная политика возврата; недозамкнутый хвост отмены
Payments3 →0оборванный путь возврата; забытый чарджбэк; мост decline на шве
Kitchen5 →0Reject order/Order rejected осиротели; политика оценки времени без триггера; Start cooking без события; Cooking started изолирован
Dispatch4 →0Notify ops без исхода; политика трекинга-сирота; Courier arrived/Delivery failed без причины
Tracking3 →0политика нотификации без триггера; Recalculate ETA изолирована; политика запроса рейтинга не сведена

Итого по проекту: 17 механических брешей поймано и закрыто, 15 открытых вопросов сознательно оставлено на виду. Ни одной выдуманной цифры — это вывод реального analyzeEsSequence по засидленным доскам.

Что остаётся открытыми вопросами — и почему это фича, а не баг

Вот главная мысль. Когда gaps схлопнулись до нуля, у наивной системы возник бы соблазн сказать «архитектура готова». Это была бы ложь. Разница между брешью и открытым вопросом фундаментальна:

Поэтому hotspot'ы — первоклассные граждане доски. Они проходят валидацию (ok=true), но остаются на виду как openQuestions. Доска честно говорит: «механически я связна, но вот эти развилки ждут человека».

И самое красивое: один бизнес-вопрос всплывает hotspot'ом с разных сторон шва — один и тот же вопрос виден из нескольких контекстов сразу. Это не дублирование, а карта того, кого затронет решение, когда продакт его наконец примет:

Зелёный анализатор не означает «решения приняты». Он означает «история механически связна, и все нерешённые развилки явно подняты на поверхность, а не утоплены в молчании». Это ровно та граница, которую вы хотите между тем, что агент вправе достроить сам, и тем, где он обязан позвать человека.

Артефакт: это не картинки, это работающий проект

Всё выше — не мокап в графическом редакторе. Это засидленный проект, который открывается в продукте:

Forklift — доска Ordering

Как попробовать самому — уже можно

Это не «когда-нибудь зарелизим». Весь тулчейн обновлён и доступен прямо сейчас:

Установка в Claude Code:

  1. Заведи аккаунт на my-architect.app, возьми токен на странице API Keys и экспортируй его в той же сессии, где запускаешь Claude Code:

``bash export MCP_API_KEY=mcp_ВАШ_ТОКЕН ``

  1. Добавь маркетплейс и поставь плагин (MCP-сервер подключится сам — npx -y @my-architect/mcp@latest, MA_API_URL=https://my-architect.app):

`` /plugin marketplace add d7561985/my-architect-marketplace /plugin install my-architect@my-architect-marketplace ``

  1. Дай агенту эпик или инициативу и попроси разложить Event Storming — он сам пройдёт петлю create_diagram → get_diagram (sequence) → update_diagram до зелёного, оставив открытые вопросы hotspot'ами.

Уже стоит плагин? Обнови до свежих инструментов и правила: /plugin marketplace update my-architect-marketplace/plugin update my-architect.

Вывод: практика для команд

Если убрать весь Forklift и оставить суть — рабочий рецепт:

  1. Перестаньте относиться к диаграммам как к картинкам. Берите формат с проверяемым инвариантом. У Event Storming он встроен: всё имеет причину и следствие.
  2. Сделайте проверку последовательности дешёвой и детерминированной. analyzeEsSequence поверх доски — это линтер для архитектуры. Бреши (isolated, event-without-cause, command-without-effect, policy-not-bridging) — это ошибки компиляции вашей истории.
  3. Дайте петлю агенту, а не разовый прогон. create_diagramget_diagram (validate) → update_diagram (refine) → re-validate во время реализации. Агент итерирует до зелёного так же, как до зелёных тестов — без усталости и без «вроде всё подключил».
  4. Жёстко разделяйте брешь и открытый вопрос. Брешь чинит агент. Открытый вопрос держится hotspot'ом на виду и ждёт человека. Система, маскирующая второе под первое, молча принимает бизнес-решения за вас — худший вид техдолга.
  5. Привязывайте доску к узлу иерархии (эпику/инициативе), а не к воздуху.

Самое ценное здесь даже не то, что агент чинит бреши. А то, что он точно знает, где чинить нельзя — и оставляет эти места красными, подписанными и видимыми. Архитектура, которая честно говорит «вот этого я ещё не знаю», стоит дороже любой красивой диаграммы, которая делает вид, что знает всё.