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'ом на видноті і чекає на людину. Система, що маскує друге під перше, мовчки приймає бізнес-рішення за вас — найгірший вид техборгу.
- Прив'язуйте дошку до вузла ієрархії (епіку/ініціативі), а не до повітря.
Найцінніше тут навіть не те, що агент лагодить проломи. А те, що він точно знає, де лагодити не можна — і лишає ці місця червоними, підписаними і видимими. Архітектура, яка чесно каже «ось цього я ще не знаю», коштує дорожче за будь-яку гарну діаграму, яка вдає, що знає все.