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. Ровно тот класс домена, где «забыл подключить ветку» стоит реальных денег: еда приготовлена — деньги не списаны; курьер не назначен — клиент жалуется.
Контекст Dispatch: команды (синие) → события (оранжевые), политики-мосты (сиреневые), read-models (зелёные), внешние системы (розовые), акторы (жёлтые) и открытые вопросы — hotspot'ы (ромбы) внизу.
Почему именно агенту это даёт рычаг
Человек смотрит на доску и чувствует, что чего-то не хватает. Иногда находит. Чаще — нет: внимание не масштабируется, на тридцатой карточке вы уже не помните, свели ли исход команды «Отклонить заказ».
Агент не чувствует. Агент запускает детерминированную проверку графа. analyzeEsSequence обходит причинно-следственный граф доски и возвращает структурированный вердикт: ok, список gaps с типом (isolated, event-without-cause, command-without-effect, policy-not-bridging) и уровнем (warning / info), и отдельно — openQuestions (hotspot-карточки).
Это и есть рычаг. У агента появляется петля обратной связи, которая не врёт и не устаёт:
- Author — агент авторит доску через
create_diagram(diagramType:'event-storming', nodeId), привязывая её к узлу иерархии (эпику/инициативе). - Validate — читает через
get_diagram; полеsequenceпоказывает бреши в истории. - Refine — чинит через
update_diagramи валидирует снова, покаgapsне схлопнется до нуля. - 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 был дырявым, и это нормально: именно поэтому проверка и нужна.

Вердикт анализатора по 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 |
|---|---|---|---|
| Ordering | 2 → | 0 | изолированная политика возврата; недозамкнутый хвост отмены |
| Payments | 3 → | 0 | оборванный путь возврата; забытый чарджбэк; мост decline на шве |
| Kitchen | 5 → | 0 | Reject order/Order rejected осиротели; политика оценки времени без триггера; Start cooking без события; Cooking started изолирован |
| Dispatch | 4 → | 0 | Notify ops без исхода; политика трекинга-сирота; Courier arrived/Delivery failed без причины |
| Tracking | 3 → | 0 | политика нотификации без триггера; Recalculate ETA изолирована; политика запроса рейтинга не сведена |
Итого по проекту: 17 механических брешей поймано и закрыто, 15 открытых вопросов сознательно оставлено на виду. Ни одной выдуманной цифры — это вывод реального analyzeEsSequence по засидленным доскам.
Что остаётся открытыми вопросами — и почему это фича, а не баг
Вот главная мысль. Когда gaps схлопнулись до нуля, у наивной системы возник бы соблазн сказать «архитектура готова». Это была бы ложь. Разница между брешью и открытым вопросом фундаментальна:
- Брешь — механическая недоведённость. Стрелку забыли провести. Чинится в DSL за минуту. Не требует решения — требует аккуратности. Именно это анализатор обязан ловить и требовать починки.
- Открытый вопрос (hotspot) — нерешённое бизнес-решение. Его нельзя «починить» проводкой стрелки, потому что ещё не выбрано, какую стрелку проводить. Замаскировать его «зелёным» — значит молча принять решение за продакт-оунера. Худшее, что может сделать архитектура.
Поэтому hotspot'ы — первоклассные граждане доски. Они проходят валидацию (ok=true), но остаются на виду как openQuestions. Доска честно говорит: «механически я связна, но вот эти развилки ждут человека».
И самое красивое: один бизнес-вопрос всплывает hotspot'ом с разных сторон шва — один и тот же вопрос виден из нескольких контекстов сразу. Это не дублирование, а карта того, кого затронет решение, когда продакт его наконец примет:
- Доступность курьера (SLA). «После N ретраев / T минут без курьера — придержать готовку, поднять оплату курьеру, или авто-отмена + возврат?» Виден в Dispatch (
No courier available), Ordering (Hold or auto-cancel) и Payments (refund-ветка) одновременно. - Гонка capture-vs-reject. «Если отказ ресторана пришёл после списания — это void холда или уже RefundIssued?» Висит в Payments, Kitchen и Ordering. Один race condition, который никто пока не разрешил — и доска не даёт о нём забыть.
- Атрибуция вины при возврате после готовки (customer / courier / restaurant-fault) — hotspot в Payments, Dispatch и Tracking сразу, потому что порог manual-review ещё не задан.
- Fallback нотификаций (что делать, когда падает Push/SMS/Email-шлюз) и протухание ETA — честные открытые вопросы Tracking, которые анализатор не маскирует.
Зелёный анализатор не означает «решения приняты». Он означает «история механически связна, и все нерешённые развилки явно подняты на поверхность, а не утоплены в молчании». Это ровно та граница, которую вы хотите между тем, что агент вправе достроить сам, и тем, где он обязан позвать человека.
Артефакт: это не картинки, это работающий проект
Всё выше — не мокап в графическом редакторе. Это засидленный проект, который открывается в продукте:
- Forklift — инициатива и 5 эпиков (по одному на bounded-контекст), каждый эпик владеет своей Event Storming доской.
- 178 карточек, 142 связи на пяти досках; каждая доска проходит
analyzeEsSequenceс нулём warning'ов и тремяopenQuestions. - Доски привязаны к узлам иерархии — значит «v0 → v1» это не разовая чистка, а живой контроль: когда код разойдётся с историей, доска снова покраснеет.

Как попробовать самому — уже можно
Это не «когда-нибудь зарелизим». Весь тулчейн обновлён и доступен прямо сейчас:
- Приложение — тип
event-stormingраскатан на my-architect.app: доски рендерятся, раскладываются по причинному графу (ELK), создаются прямо из иерархии (узел → «+» → Event Storming). - MCP —
@my-architect/mcp@1.6.1опубликован в npm: инструментыcreate_diagram(diagramType:'event-storming', nodeId),get_diagram(возвращает полеsequenceс брешами) иupdate_diagram(refine + пере-анализ). - Скилл —
my-architectv1.11.0 в маркетплейсе: несёт правило «для эпика/инициативы по умолчанию проводи Event Storming суб-задачей и ре-валидируй последовательность во время реализации».
Установка в Claude Code:
- Заведи аккаунт на my-architect.app, возьми токен на странице API Keys и экспортируй его в той же сессии, где запускаешь Claude Code:
``bash export MCP_API_KEY=mcp_ВАШ_ТОКЕН ``
- Добавь маркетплейс и поставь плагин (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 ``
- Дай агенту эпик или инициативу и попроси разложить Event Storming — он сам пройдёт петлю
create_diagram → get_diagram (sequence) → update_diagramдо зелёного, оставив открытые вопросы hotspot'ами.
Уже стоит плагин? Обнови до свежих инструментов и правила: /plugin marketplace update my-architect-marketplace → /plugin update my-architect.
Вывод: практика для команд
Если убрать весь Forklift и оставить суть — рабочий рецепт:
- Перестаньте относиться к диаграммам как к картинкам. Берите формат с проверяемым инвариантом. У Event Storming он встроен: всё имеет причину и следствие.
- Сделайте проверку последовательности дешёвой и детерминированной.
analyzeEsSequenceповерх доски — это линтер для архитектуры. Бреши (isolated,event-without-cause,command-without-effect,policy-not-bridging) — это ошибки компиляции вашей истории. - Дайте петлю агенту, а не разовый прогон.
create_diagram→get_diagram(validate) →update_diagram(refine) → re-validate во время реализации. Агент итерирует до зелёного так же, как до зелёных тестов — без усталости и без «вроде всё подключил». - Жёстко разделяйте брешь и открытый вопрос. Брешь чинит агент. Открытый вопрос держится hotspot'ом на виду и ждёт человека. Система, маскирующая второе под первое, молча принимает бизнес-решения за вас — худший вид техдолга.
- Привязывайте доску к узлу иерархии (эпику/инициативе), а не к воздуху.
Самое ценное здесь даже не то, что агент чинит бреши. А то, что он точно знает, где чинить нельзя — и оставляет эти места красными, подписанными и видимыми. Архитектура, которая честно говорит «вот этого я ещё не знаю», стоит дороже любой красивой диаграммы, которая делает вид, что знает всё.