My Architect, część 8: Event Storming — kontrola sekwencji, a nie kolejny diagram
To ósmy artykuł serii o My Architect. Dla tych, którzy nie czytali wcześniejszych części, w skrócie: My Architect to system, w którym projekt żyje między sesjami agenta AI. Jedną stroną zwrócony jest do agenta — to on prowadzi projekt przez MCP; drugą do człowieka — wizualny interfejs pokazuje, co agent już zrobił, i cały postęp projektu. Ten artykuł dotyczy jednego konkretnego mechanizmu tej kontroli.
Witryną jest tu Forklift, średniej wielkości domena dostawy jedzenia złożona z pięciu bounded-kontekstów. Wszystkie tablice, liczby z analizatora i fragmenty DSL poniżej są prawdziwe: projekt został zasiany lokalnie i przechodzi przez realny analyzeEsSequence. Nic nie jest zmyślone.
Diagram dla samego diagramu jest bezużyteczny. Kontrola sekwencji — nie
Wszyscy mamy ten cmentarz. Folder docs/architecture, gdzie leżą ładne PNG narysowane pół roku temu, i żaden już nie odpowiada kodowi. Diagram-obrazek to zrzut czyichś dobrych intencji w chwili T. Niczego nie sprawdza. Nie wie, że zapomniałeś podłączyć gałąź anulowania. Radośnie pokaże strzałkę, której w kodzie nie ma, i przemilczy piętnaście, które są.
Dlatego kiedy mówię „agent rysuje tablicę Event Storming”, słusznie drga ci powieka. Kolejny obrazek? Nie. Różnica tkwi w jednym słowie: sekwencja.
Event Storming to nie diagram pudełek. To rozłożona w czasie historia tego, jak zdarzenie rodzi reakcję, reakcja — komendę, komenda — nowe zdarzenie. Zdarzenie domenowe („Zamówienie złożone”) ma przyczynę. Komenda („Złóż zamówienie”) ma rezultat. Polityka („Gdy tylko płatność autoryzowana → potwierdź zamówienie”) to most między czyimś zdarzeniem a twoją komendą. I właśnie ta własność — wszystko ma przyczynę i skutek — zmienia się z ładnej filozofii w maszynowo sprawdzalny inwariant.
Jeśli zdarzenie wisi bez przyczyny — to luka. Jeśli komenda nie rodzi zdarzenia — luka. Jeśli polityka niczego nie mostkuje — luka. Jeśli karta jest izolowana — ktoś naszkicował myśl i jej nie dokończył. Tych luk nie widać okiem na tablicy z czterdziestu karteczek. Ale widzi je analizator, który czyta graf sekwencji.
Witryna jest apetyczna — Forklift: on-demand food delivery, from tap to doorstep. Pięć bounded-kontekstów: Ordering, Payments, Kitchen, Dispatch, Tracking. Dokładnie ta klasa domeny, gdzie „zapomniałem podłączyć gałąź” kosztuje realne pieniądze: jedzenie ugotowane — pieniędzy nie pobrano; kuriera nie przydzielono — klient się skarży.
Kontekst Dispatch: komendy (niebieskie) → zdarzenia (pomarańczowe), polityki-mosty (liliowe), read-modele (zielone), systemy zewnętrzne (różowe), aktorzy (żółci) i otwarte pytania — hotspoty (romby) na dole.
Dlaczego daje to dźwignię właśnie agentowi
Człowiek patrzy na tablicę i czuje, że czegoś brakuje. Czasem znajdzie. Częściej — nie: uwaga się nie skaluje, przy trzydziestej karcie już nie pamiętasz, czy domknąłeś wynik komendy „Odrzuć zamówienie”.
Agent nie czuje. Agent uruchamia deterministyczne sprawdzenie grafu. analyzeEsSequence przechodzi graf przyczynowo-skutkowy tablicy i zwraca ustrukturyzowany werdykt: ok, listę gaps z typem (isolated, event-without-cause, command-without-effect, policy-not-bridging) i poziomem (warning / info), a osobno — openQuestions (karty-hotspoty).
To właśnie jest dźwignia. Agent dostaje pętlę sprzężenia zwrotnego, która nie kłamie i się nie męczy:
- Author — agent autoruje tablicę przez
create_diagram(diagramType:'event-storming', nodeId), przypinając ją do węzła hierarchii (epiku/inicjatywy). - Validate — czyta przez
get_diagram; polesequencepokazuje luki w historii. - Refine — naprawia przez
update_diagrami waliduje ponownie, ażgapszwinie się do zera. - Re-validate during implementation — w trakcie realizacji ponownie uruchamia sprawdzenie: kod rozjechał się z historią → tablica znów czerwienieje.
Agent nie próbuje być sprytny „na oko”. Opiera się na tanim deterministycznym sprawdzeniu i iteruje do zielonego — dokładnie tak, jak iteruje testy.
Pętla w akcji: Ordering, od czarnego szkicu do czystej historii
Najpierw agent naszkicował v0 kontekstu Ordering — uczciwy szkic, jaki rzuca żywy człowiek: chwycił główną nić, zaznaczył „tu wróci odpowiedź z Payments” — i nie dokończył ogona.
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)
Agent czyta get_diagram, przepuszcza przez analizator i dostaje dla 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
Dwie luki-warning (izolowana polityka powrotu z Payments i niedomknięty ogon anulowania) plus jedna notatka info („Order confirmed” bez przyczyny — rodząca komenda nie domknięta). Dalej — refine: agent podłącza rodzącą komendę, mostkuje politykę w komendę potwierdzenia, domyka ogon anulowania zdarzeniem wynikowym. Ponowna walidacja v1:
34 cards · 30 connections · 1 contexts — 0 sequence gap(s), 3 open question(s)
Luki się zwinęły. Ale — i to jest istotne — tablica nie zrobiła się pusta i nie zaczęła kłamać „wszystko rozwiązane”. Zostały dokładnie trzy karty, które agent świadomie zostawił czerwone. O nich — niżej.
Ta sama pętla na Payments: gdzie szkic jest szczególnie niebezpieczny
Payments to kontekst, w którym niedociągnięta strzałka oznacza „jedzenie ugotowane, pieniędzy nie zdjęto” albo „pieniądze zdjęto dwa razy”. Tu v0 było dziurawe, i to normalne: właśnie dlatego sprawdzenie jest potrzebne.

Werdykt analizatora dla 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 — мост к отмене брошен на шве
Po refine agent domyka ścieżkę zwrotu (Evaluate refund → Issue refund → Refund issued), domyka obsługę chargebacku i dobudowuje most polityki decline w Cancel order. Werdykt dla v1:
39 cards · 27 connections · 1 contexts — 0 sequence gap(s), 3 open question(s)
I znów — trzy karty zostają czerwone celowo (capture-vs-reject race, atrybucja winy przy zwrocie, właściciel liability przy chargebacku).
Pozostałe trzy konteksty: ten sam wzorzec
Pętla wszędzie jest ta sama. Co złapał analizator w v0 — i do czego zwinęło się w v1:
| Kontekst | v0 (luki) | v1 | Co było zepsute w v0 |
|---|---|---|---|
| Ordering | 2 → | 0 | izolowana polityka powrotu; niedomknięty ogon anulowania |
| Payments | 3 → | 0 | urwana ścieżka zwrotu; zapomniany chargeback; most decline na szwie |
| Kitchen | 5 → | 0 | Reject order/Order rejected osierocone; polityka szacowania czasu bez triggera; Start cooking bez zdarzenia; Cooking started izolowany |
| Dispatch | 4 → | 0 | Notify ops bez wyniku; polityka trackingu-sierota; Courier arrived/Delivery failed bez przyczyny |
| Tracking | 3 → | 0 | polityka powiadomień bez triggera; Recalculate ETA izolowana; polityka prośby o ocenę nie domknięta |
Łącznie w projekcie: 17 mechanicznych luk złapanych i zamkniętych, 15 otwartych pytań świadomie zostawionych na widoku. Ani jednej zmyślonej liczby — to wynik realnego analyzeEsSequence po zasianych tablicach.
Co zostaje otwartymi pytaniami — i dlaczego to feature, a nie bug
Oto główna myśl. Kiedy gaps zwinęły się do zera, naiwny system uległby pokusie powiedzieć „architektura gotowa”. To byłoby kłamstwo. Różnica między luką a otwartym pytaniem jest fundamentalna:
- Luka to mechaniczne niedociągnięcie. Strzałka, której zapomniano poprowadzić. Naprawia się w DSL w minutę. Nie wymaga decyzji — wymaga staranności. To właśnie analizator jest zobowiązany łapać i żądać naprawy.
- Otwarte pytanie (hotspot) to nierozwiązana decyzja biznesowa. Nie da się jej „naprawić” poprowadzeniem strzałki, bo nie wybrano jeszcze, którą strzałkę poprowadzić. Zamaskować ją „zielonym” znaczy po cichu podjąć decyzję za product ownera. Najgorsze, co architektura może zrobić.
Dlatego hotspoty to pełnoprawni obywatele tablicy. Przechodzą walidację (ok=true), ale zostają na widoku jako openQuestions. Tablica uczciwie mówi: „mechanicznie jestem spójna, ale te rozwidlenia czekają na człowieka”.
I najpiękniejsze: jedno pytanie biznesowe wypływa hotspotem z różnych stron szwu — to samo pytanie widać z kilku kontekstów naraz. To nie duplikacja, lecz mapa tego, kogo dotknie decyzja, gdy product owner ją w końcu podejmie:
- Dostępność kuriera (SLA). „Po N retry / T minutach bez kuriera — przytrzymać gotowanie, podnieść stawkę kurierowi, czy auto-anulowanie + zwrot?” Widoczne w Dispatch (
No courier available), Ordering (Hold or auto-cancel) i Payments (gałąź refund) jednocześnie. - Wyścig capture-vs-reject. „Jeśli odmowa restauracji przyszła po obciążeniu — to void holda czy już RefundIssued?” Wisi w Payments, Kitchen i Ordering. Jeden race condition, którego nikt jeszcze nie rozstrzygnął — i tablica nie pozwala o nim zapomnieć.
- Atrybucja winy przy zwrocie po gotowaniu (customer / courier / restaurant-fault) — hotspot w Payments, Dispatch i Tracking naraz, bo próg manual-review nie został jeszcze ustawiony.
- Fallback powiadomień (co robić, gdy padnie bramka Push/SMS/Email) i przeterminowanie ETA — uczciwe otwarte pytania Tracking, których analizator nie maskuje.
Zielony analizator nie oznacza „decyzje podjęte”. Oznacza „historia jest mechanicznie spójna, a wszystkie nierozwiązane rozwidlenia są jawnie wyniesione na powierzchnię, a nie utopione w milczeniu”. To dokładnie ta granica, której chcesz między tym, co agent ma prawo dobudować sam, a tym, gdzie jest zobowiązany zawołać człowieka.
Artefakt: to nie obrazki, to działający projekt
Wszystko powyżej to nie makieta w edytorze graficznym. To zasiany projekt, który otwiera się w produkcie:
- Forklift — inicjatywa i 5 epików (po jednym na bounded-kontekst), każdy epik posiada własną tablicę Event Storming.
- 178 kart, 142 połączenia na pięciu tablicach; każda tablica przechodzi
analyzeEsSequencez zerem warningów i trzemaopenQuestions. - Tablice są przypięte do węzłów hierarchii — czyli „v0 → v1” to nie jednorazowe sprzątanie, lecz żywa kontrola: gdy kod rozjedzie się z historią, tablica znów poczerwienieje.

Jak wypróbować samemu — już można
To nie „kiedyś zreleasujemy”. Cały toolchain jest zaktualizowany i dostępny od ręki:
- Aplikacja — typ
event-stormingrozwinięty na my-architect.app: tablice się renderują, układają według grafu przyczynowego (ELK), tworzą się prosto z hierarchii (węzeł → „+” → Event Storming). - MCP —
@my-architect/mcp@1.6.1opublikowany w npm: narzędziacreate_diagram(diagramType:'event-storming', nodeId),get_diagram(zwraca polesequencez lukami) iupdate_diagram(refine + ponowna analiza). - Skill —
my-architectv1.11.0 w marketplace: niesie regułę „dla epiku/inicjatywy domyślnie przeprowadź Event Storming jako sub-zadanie i re-waliduj sekwencję podczas realizacji”.
Instalacja w Claude Code:
- Załóż konto na my-architect.app, weź token na stronie API Keys i wyeksportuj go w tej samej sesji, w której uruchamiasz Claude Code:
``bash export MCP_API_KEY=mcp_TWÓJ_TOKEN ``
- Dodaj marketplace i postaw plugin (serwer MCP podłączy się sam —
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 ``
- Daj agentowi epik albo inicjatywę i poproś o rozłożenie Event Storming — sam przejdzie pętlę
create_diagram → get_diagram (sequence) → update_diagramdo zielonego, zostawiając otwarte pytania jako hotspoty.
Masz już plugin? Zaktualizuj do świeżych narzędzi i reguły: /plugin marketplace update my-architect-marketplace → /plugin update my-architect.
Wniosek: praktyka dla zespołów
Jeśli usunąć cały Forklift i zostawić sedno — działający przepis:
- Przestańcie traktować diagramy jak obrazki. Bierzcie format ze sprawdzalnym inwariantem. Event Storming ma go wbudowany: wszystko ma przyczynę i skutek.
- Zróbcie sprawdzanie sekwencji tanim i deterministycznym.
analyzeEsSequencena tablicy to linter dla architektury. Luki (isolated,event-without-cause,command-without-effect,policy-not-bridging) to błędy kompilacji waszej historii. - Dajcie agentowi pętlę, a nie jednorazowy przebieg.
create_diagram→get_diagram(validate) →update_diagram(refine) → re-validate podczas realizacji. Agent iteruje do zielonego tak samo, jak do zielonych testów — bez zmęczenia i bez „chyba wszystko podłączyłem”. - Twardo oddzielajcie lukę od otwartego pytania. Lukę naprawia agent. Otwarte pytanie trzyma się hotspotem na widoku i czeka na człowieka. System maskujący to drugie jako pierwsze po cichu podejmuje decyzje biznesowe za was — najgorszy rodzaj długu technicznego.
- Przypinajcie tablicę do węzła hierarchii (epiku/inicjatywy), a nie do powietrza.
Najcenniejsze jest tu nawet nie to, że agent naprawia luki. Lecz to, że dokładnie wie, gdzie naprawiać nie wolno — i zostawia te miejsca czerwone, podpisane i widoczne. Architektura, która uczciwie mówi „tego jeszcze nie wiem”, jest warta więcej niż jakikolwiek ładny diagram udający, że wie wszystko.