@eventmodelers/cli 1.0.25 → 1.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, Cratis, or modeling-only)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -374,6 +374,8 @@ Do not create unnecessary swimlanes. Before adding a lane, check whether an exis
374
374
 
375
375
  **Never** add a swimlane just to group things visually or because a second role appears — use the existing lane if the type matches.
376
376
 
377
+ **Exception: a second `swimlane`-type lane for another system's own events.** When an external/other-team system's events cross into this chapter as integration triggers for an automation (see `eventmodeling-identifying-outputs` Step 5b), add a second swimlane lane labeled for that system and place its trigger events there — never fold them into this chapter's own event swimlane (they are not this bounded context's domain facts) and never treat them as an informal "signal" with no EVENT node at all.
378
+
377
379
  ---
378
380
 
379
381
  ## Workshop Facilitation Guide
@@ -348,7 +348,7 @@ Does not produce commands (info-only)
348
348
 
349
349
  Instead of writing a markdown document, **place each READMODEL (and any missing AUTOMATION) on the board** using the `node:created` API. Screens are typically already placed from Step 3 (storyboarding) as one plain screen per screen state — Step 3 does not pre-split anything, so working out how many components a screen actually has is this step's job (Step 5a below), not something to re-derive from storyboarding's output. Do not re-place an existing screen unless one is clearly missing. Automations are placed here when analysis reveals a processor that reads state and issues commands but is not yet on the board.
350
350
 
351
- This step proceeds as a sequence of lettered sub-steps: identify each screen's components (5a), break multi-component screens apart into copies (5b), then design and place one read model per component (5c onward).
351
+ This step proceeds as a sequence of lettered sub-steps: identify each screen's components (5a), identify todo-list read models for automations (5b), break multi-component screens apart into copies (5c), then design and place one read model per component (5d onward).
352
352
 
353
353
  > **CRITICAL: Every READMODEL node MUST include `meta.fields` with a `mapping` on every field.** A read model without fields — or with fields that lack `mapping` — has no data lineage and cannot be traced back to its source events.
354
354
 
@@ -372,7 +372,7 @@ Automations follow:
372
372
  READ MODEL → AUTOMATION → COMMAND → EVENT
373
373
  ```
374
374
 
375
- Treat any screen or automation without an incoming read model as a gap unless it provably needs no prior state at all (e.g., a blank registration form).
375
+ Treat any screen or automation without an incoming read model as a gap. A screen may be exempt if it provably needs no prior state at all (e.g., a blank registration form) — an **automation is never exempt**: every automation gets a todo-list read model, even a trivial one that opens and closes within the same slice (see Step 5b).
376
376
 
377
377
  ### Step 5a — Enumerate consumers and identify components
378
378
 
@@ -380,18 +380,46 @@ Treat any screen or automation without an incoming read model as a gap unless it
380
380
 
381
381
  Read models exist to serve the elements already on the board:
382
382
  - Every **view screen** (output/read model screen) needs at least one read model to supply its data.
383
- - Every **automation** that makes a decision based on system state needs at least one read model to read from.
383
+ - Every **automation** needs at least one read model to read from — its todo list. This applies to every automation without exception, not only ones that visibly "decide" something; see Step 5b for how to identify it.
384
384
  - Every **command/input screen** needs a read model unless it is a blank creation form with no prior state to display (this is the rare exception, not the rule).
385
385
 
386
386
  For each SCREEN node, look at its rendered layout and its `meta.fields` and identify its components — groups of fields/UI elements a user would perceive as one area: a stats tile, a list below it, a summary card, a detail panel, a status column in a table, etc. **Most screens genuinely have exactly one component — do not force a split.** A screen has more than one component only when a user would point at two separate areas and describe them as different things.
387
387
 
388
388
  A single homogeneous list/table is still one component, even when its rows draw on many different event types (e.g. a catalog whose per-row status is set by many different lifecycle events scattered across the timeline). Splitting is about visually distinct *areas* of a screen, not about how many event types feed one area — don't split a table by row or by source event. Flag this kind of component as a **roll-up component**: its read model will legitimately need wide fan-in (many `EVENT → READMODEL` connections spanning much of the timeline) because it projects current state across an entity's full lifecycle rather than from one recent slice. This is expected, not a modeling error — but treat calling it a roll-up component as an **assumption**, not a fact, and document it as one: use the orchestrating skill's "Documenting decisions inline, at any step" mechanic (a MARKDOWN note in the feedback lane, placed in the component's column) to record explicitly *why* you concluded this is a legitimate single roll-up rather than an unsplit multi-component screen — e.g. "CopyAvailabilityView treated as one roll-up component: availability is a single per-copy status derived across that copy's full lifecycle (repair, loss, reservation, return), not several screen areas bundled together." That note is what lets a later reader (or reviewer) tell a deliberate roll-up apart from a missed split, instead of re-litigating or silently re-flagging it as a god read model.
389
389
 
390
- After this step is done, **every SCREEN and every AUTOMATION on the board must be connected to at least one read model** via a `READMODEL → SCREEN` or `READMODEL → AUTOMATION` connection, and every screen identified above as having 2+ components must have been broken apart per Step 5b before any read model is placed. If a screen or automation has no incoming read model connection, it is a gap — either a read model is missing or the connection arrow is missing.
390
+ After this step is done, **every SCREEN and every AUTOMATION on the board must be connected to at least one read model** via a `READMODEL → SCREEN` or `READMODEL → AUTOMATION` connection, and every screen identified above as having 2+ components must have been broken apart per Step 5c before any read model is placed. If a screen or automation has no incoming read model connection, it is a gap — either a read model is missing or the connection arrow is missing.
391
391
 
392
392
  > **Placement rule**: A read model must be placed in a column that already contains a SCREEN or AUTOMATION it serves. Do not place read models in columns with no screen or automation — doing so creates orphaned read models that will never have a consumer.
393
393
 
394
- ### Step 5b — Break apart multi-component screens into copies
394
+ ### Step 5b — Identify todo-list read models for automations
395
+
396
+ **Every AUTOMATION needs a todo-list read model — this is not optional, and there is no "pure relay" exemption.** An automation is a processor: it reacts to events, decides what work is outstanding, and issues commands to get that work done. The read model that tells it what's outstanding is its **todo list** — a queue of pending work items, not a snapshot of current entity state.
397
+
398
+ **The pattern**: one or more events *open* an item on the todo list (something now needs doing); one or more events *close* it (the work is done — remove the item). A todo list can be opened and closed by more than one event type on either side, and the set of opening events doesn't need to match the set of closing events in count or shape — whatever the domain calls for.
399
+
400
+ **Worked example**: an automation that reacts to `CustomerRegistered` by sending a welcome notification.
401
+ - Todo list: **NotificationsToSend** — one row per pending notification.
402
+ - `CustomerRegistered` **opens** a row (a notification now needs sending).
403
+ - `NotificationSent` (the event this automation's own resulting command produces) **closes** that row (removes it — the list only ever shows outstanding work).
404
+ - The automation (`Send Welcome Notification`) reads `NotificationsToSend`, and for every open row issues `SendNotification`.
405
+
406
+ Even an automation that looks like a "pure signal relay" (e.g. translating an external system's trigger straight into a local command with no visible decision) still has a todo list — model it anyway: it documents that the automation is idempotent/complete once its own event fires, and keeps every automation consistent with the same `READMODEL → AUTOMATION → COMMAND → EVENT` pattern instead of silently exempting some as "too simple to need one." This applies without exception even when the automation's trigger comes from another team's system (Step 6 territory) whose upstream decision logic is out of scope for this model.
407
+
408
+ **There is no such thing as an invisible or informal "signal" — a trigger is always a real EVENT node, placed in a second swimlane when it belongs to another system.** Do not model an externally-triggered automation's todo list as "opened and closed by the same event" — that conflates the external trigger with this chapter's own resulting fact and produces a todo list that is never meaningfully open. Instead:
409
+ 1. Add a second `swimlane`-type lane to the chapter (`add_lane` with `type: "swimlane"`, labeled for the external system, e.g. "Reservation & Pickup System (external)") — a chapter can have more than one lane of the same type, and this lane holds that other system's own events as this chapter sees them, distinct from this chapter's own swimlane.
410
+ 2. Place one EVENT per integration trigger point in that second swimlane, in the **same column** as the AUTOMATION/COMMAND/EVENT triplet it feeds (e.g. `ReservationRequested` in the same column as the `ReserveCopy` automation/command/`CopyReserved` event). This event represents that other system's own domain fact arriving at the boundary — it is a real, first-class EVENT, not a comment or a placeholder.
411
+ 3. Wire the todo list the standard way: the external EVENT (second swimlane) **opens** the row, this chapter's own resulting EVENT (first swimlane, the same event the automation's command produces) **closes** it — the typical, expected shape for this kind of automation, matching the general open/close pattern above exactly. `EVENT → READMODEL` connections from both swimlanes are unaffected by which swimlane the event sits in.
412
+
413
+ **Fields**: a todo-list read model's fields describe the pending item — the identity it's about (e.g. `customerId`) plus enough context to act on it (e.g. `email`, `notificationType`). Do not add a `status` field to mark items done — a todo list's "open" state is *membership in the list itself* (the row exists at all), not a status flag on a row that never leaves. If the same underlying data is also useful with an explicit status column for a different consumer, that is a different read model, not this one.
414
+
415
+ **Connections and placement**: the todo-list read model goes in the interaction lane, same column as its automation (actor lane) — the same `READMODEL → AUTOMATION` placement covered in Step 5f below.
416
+ - Connect every **opening** EVENT → READMODEL.
417
+ - Connect every **closing** EVENT → READMODEL — including the automation's own resulting event, even though that event is produced by the command this same automation issues. This is not a backward arrow: `EVENT → READMODEL` connections are exempt from column ordering (see `learn-eventmodelers-api` §3) precisely because a read model is a live projection, not a frozen snapshot — a later event closing an earlier-opened item is the normal case, not an exception to reach for only when convenient.
418
+ - Connect READMODEL → AUTOMATION (the automation reads its own todo list).
419
+
420
+ After this step, every AUTOMATION on the board must have an incoming `READMODEL → AUTOMATION` connection to a todo-list read model — treat a connectionless automation exactly like a connectionless screen with no exemption: a gap to fix, not something to note and move past.
421
+
422
+ ### Step 5c — Break apart multi-component screens into copies
395
423
 
396
424
  **Do not default to a single monolithic read model that supplies an entire screen.** For every screen identified in Step 5a as having 2+ components, break it apart into one screen copy per component before designing its read models:
397
425
 
@@ -406,7 +434,7 @@ Why this matters, beyond tidiness:
406
434
 
407
435
  Before finalizing any read model, ask: "does this screen contain more than one component?" If yes and it wasn't already broken apart, do it now — don't ask whether it's worth the extra columns, it always is at this scale, since the alternative is a hidden coupling and a higher chance of a backward-arrow layout error.
408
436
 
409
- ### Step 5c — Pull field mappings from Step 3 — they are the spec, not a guess
437
+ ### Step 5d — Pull field mappings from Step 3 — they are the spec, not a guess
410
438
 
411
439
  **Do not re-derive read model needs from a screen's title or description alone, and do not rely on the orchestrator's phase-summary handoff for this** — if you arrived here via `eventmodeling-orchestrating-event-modeling`, the handoff after Step 3 is a short hand-written prose summary (`.trogonai/interviews/.../EVENTMODELING.md`), not the actual field data. It will not reliably carry the per-field mappings forward. Go back to the board itself:
412
440
 
@@ -416,7 +444,7 @@ For every SCREEN node, fetch it directly (`get_node`/`get_nodes`, never from mem
416
444
  - If a field's `mapping` names a read model that isn't `"<CommandTitle>.<fieldName>"` or `"session:..."` or `"derived:..."`, it is a read-model reference — treat it as a requirement, not a suggestion.
417
445
  - A screen with no fields, or with fields that carry no read-model-shaped mapping, is **not** evidence that it needs no read model. Re-check it against the three rules above (view screen / automation / command screen showing prior state) before concluding it's the rare blank-form exception — and say explicitly why it qualifies.
418
446
 
419
- ### Step 5d — Field data lineage — the `mapping` attribute on READMODEL fields
447
+ ### Step 5e — Field data lineage — the `mapping` attribute on READMODEL fields
420
448
 
421
449
  Every field on a READMODEL must carry a `mapping` that says exactly which event (or command) field it is projected from. Use one of these forms:
422
450
 
@@ -456,7 +484,7 @@ Read models go in the `interaction` lane — **in the same column as the SCREEN
456
484
 
457
485
  > **Timeline alignment rule**: Place the read model in the same column as its consumer screen/automation. If that column already holds a COMMAND (state-change slice occupies the interaction row), insert a new column immediately after (`{"index": N+1}`) and place both the READMODEL and any new SCREEN there. Do not append read model columns to the end of the timeline — doing so severs the visual left→right flow from data projection to UI consumption.
458
486
 
459
- ### Step 5e — Placing READMODEL and AUTOMATION nodes with `cellId` (Mandatory)
487
+ ### Step 5f — Placing READMODEL and AUTOMATION nodes with `cellId` (Mandatory)
460
488
 
461
489
  **Every `node:created` call MUST include `cellId`.** Without it the node has no cell reference and will appear stranded at position 0,0 — not in any timeline column.
462
490
 
@@ -532,7 +560,7 @@ mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<CHAPTER_ID>"
532
560
 
533
561
  > **Never call `drop` after using `cellId` in `node:created`.** The drop endpoint adds a second cell reference without removing the first. `node:created + cellId` is the only placement step needed.
534
562
 
535
- ### Step 5f — Preventing backward arrows (mandatory pre-placement check)
563
+ ### Step 5g — Preventing backward arrows (mandatory pre-placement check)
536
564
 
537
565
  The timeline must always progress left-to-right. A `READMODEL → SCREEN` connection going right-to-left is a layout error.
538
566
 
@@ -554,7 +582,7 @@ For each view screen S that queries this read model:
554
582
 
555
583
  **View screens go in the column immediately to the right of the read model they display** — either because they were placed there in Step 3, or because you move them here now.
556
584
 
557
- ### Step 5g — Wire connections after placing each READMODEL (and its SCREEN)
585
+ ### Step 5h — Wire connections after placing each READMODEL (and its SCREEN)
558
586
 
559
587
  After `place-element` returns the READMODEL node ID, create the arrows that complete the slice:
560
588
 
@@ -614,14 +642,15 @@ After `place-element` returns the READMODEL node ID, create the arrows that comp
614
642
 
615
643
  Skip a connection silently if the target cell is empty. Log each created arrow: `→ connected EVENT→READMODEL "OrderPlaced"→"OrderStatusView"`, `→ connected READMODEL→SCREEN "OrderStatusView"→"Order Status Screen"`, or `→ connected READMODEL→AUTOMATION "OrderStatusView"→"Fulfillment Processor"`.
616
644
 
617
- ### Step 5h — Mandatory per-node verification (run before declaring this step done)
645
+ ### Step 5i — Mandatory per-node verification (run before declaring this step done)
618
646
 
619
647
  Do not declare Step 5 complete on the strength of the read models you happened to design. Instead, **re-fetch every SCREEN and AUTOMATION node on the board** (`get_nodes` per type — don't rely on the list built earlier in this step, the board may have moved on) and check each one individually:
620
648
 
621
649
  1. Does it now have an incoming `READMODEL → SCREEN` or `READMODEL → AUTOMATION` connection?
622
- 2. If not — is it a provably blank creation form with no prior state? State the reason in one line (e.g. `"Register Account" screen: blank form, no prior state — exempt`).
623
- 3. If it's neither connected nor exempt, it is an **unresolved gap**. Fix it now: design the missing read model (pulling from its `meta.fields`/`mapping` as above) and wire the connection. Do not move to Step 6 with an unresolved gap silently carried forward — either fix it or explicitly flag it to the user as accepted debt.
624
- 4. Does any screen still carry more than one component undivided (a Step 5a/5b miss)? If so, break it apart now per Step 5b before counting it as resolved.
650
+ 2. If it's a SCREEN and not connected — is it a provably blank creation form with no prior state? State the reason in one line (e.g. `"Register Account" screen: blank form, no prior state — exempt`). This exemption applies to screens only.
651
+ 3. If it's an AUTOMATION and not connected, it is **never** exempt go back to Step 5b and identify its todo-list read model now.
652
+ 4. If a SCREEN is neither connected nor exempt, it is an **unresolved gap**. Fix it now: design the missing read model (pulling from its `meta.fields`/`mapping` as above) and wire the connection. Do not move to Step 6 with an unresolved gap silently carried forward — either fix it or explicitly flag it to the user as accepted debt.
653
+ 5. Does any screen still carry more than one component undivided (a Step 5a/5c miss)? If so, break it apart now per Step 5c before counting it as resolved.
625
654
 
626
655
  List the result of this pass (connected / exempt / fixed) for every screen and automation checked — this list is the evidence the orchestrator's Step 5 gate ("every screen data need is satisfied by a read model") actually holds, not just an assumption.
627
656
 
@@ -738,10 +767,11 @@ Identify UI needs without event sources:
738
767
  ### Read Model Design
739
768
  - [ ] **Typical pattern applied**: most screens follow `READ MODEL → SCREEN → COMMAND → EVENT`
740
769
  - [ ] **Every SCREEN from storyboarding is connected to at least one read model** (via `READMODEL → SCREEN`); only blank creation forms may be exempt — verified via the mandatory per-node pass above, not assumed
741
- - [ ] **Every AUTOMATION from storyboarding is connected to at least one read model** (via `READMODEL → AUTOMATION`) — same per-node verification
770
+ - [ ] **Every AUTOMATION from storyboarding is connected to at least one todo-list read model** (via `READMODEL → AUTOMATION`, Step 5b) — no exemption for automations, unlike screens; even a simple relay automation gets one
742
771
  - [ ] **No read model is placed without a connected SCREEN or AUTOMATION consumer**
743
772
  - [ ] **No read model spans more than one component** — a screen with N distinct components gets N read models and N highlighted screen copies (same screen name, one component crisp per copy), not one screen-wide read model
744
- - [ ] **Every multi-component screen was broken apart in Step 5b** — each copy keeps the original screen's name, differs only in which component is marked/highlighted
773
+ - [ ] **Every multi-component screen was broken apart in Step 5c** — each copy keeps the original screen's name, differs only in which component is marked/highlighted
774
+ - [ ] **Every automation's todo-list read model identifies its opening and closing events** (Step 5b) — including the automation's own resulting event as a closing event where applicable, not just the triggering event
745
775
  - [ ] **Roll-up components are flagged, not force-split** — a single homogeneous list/table with wide event fan-in is documented as an explicit assumption (inline MARKDOWN note, per "Documenting decisions inline"), not silently accepted or mistaken for an unsplit multi-component screen
746
776
  - [ ] Every read model has clear purpose
747
777
  - [ ] Every data field has event source
@@ -26,6 +26,9 @@ These rules govern how every element is placed on the board. Enforce them throug
26
26
  ### State-change slice (SCREEN → COMMAND → EVENT)
27
27
  - COMMAND and EVENT go in **the same column** — the command produces the event.
28
28
  - SCREEN (input/command screen) goes in the **actor row of that same column**.
29
+ - **A COMMAND never stands alone.** Every COMMAND must have exactly one issuer in the actor row of its own column: a SCREEN when a human triggers it, an AUTOMATION when a processor or external-system integration triggers it. There is no third option and no exemption — a command with an empty actor-row cell is an unresolved gap the moment it's placed, not something to leave for a later step to notice. This applies just as much to a command that only *represents* an externally-triggered integration event crossing into this chapter (Step 1/Step 6 territory) as to any other command: place an AUTOMATION for the external actor even when that actor's own decision logic is out of scope for this model — the automation node documents *that* something triggers the command, not *how* it decides to.
30
+
31
+ Every AUTOMATION placed this way still needs its own todo-list READMODEL per `eventmodeling-identifying-outputs` Step 5b — including one whose trigger is an external integration signal. There is no exemption for this either: even when the only visible trigger is the automation's own resulting event, model a todo list that opens and closes within that same slice (per Step 5b's worked pattern) rather than leaving the automation without an incoming READMODEL.
29
32
 
30
33
  ### State-view slice (EVENT → READ MODEL → SCREEN)
31
34
  - READ MODEL goes in the **interaction row** of a column that is **immediately after the primary source event's column** — never at the end of the timeline.
@@ -38,10 +41,19 @@ Placing all read models in new columns at the very end of the timeline severs th
38
41
  ### One read model per component, not one read model per screen
39
42
  A read model does not necessarily serve a whole screen — **one component in a screen resembles one read model.** Storyboarding (Step 3) only produces a plain screen per screen state; it does not decide components. That decision, and the work of breaking a multi-component screen apart into copies, happens in Step 5 (Identifying Outputs), because a component is defined by its read model.
40
43
 
41
- A screen-wide read model that has to aggregate from events scattered across many columns is the most common source of unnecessary coupling — a "god read model." A screen with a stats row and a list below it is two components: two read models and two screen copies of the *same page* (same screen name on both copies; the copies differ only in which component is marked/highlighted crisp while the other is blurred/dimmed), not one screen-wide read model. Each narrower read model then sits naturally close to its own source event, and the `EVENT → READMODEL → SCREEN` chain for each component stays short and forward. See `eventmodeling-identifying-outputs`'s "Step 5a — Enumerate consumers and identify components" and "Step 5b — Break apart multi-component screens into copies" for the mechanics — apply this during Step 5, before the placement problem exists, rather than reordering columns to patch it afterward.
44
+ A screen-wide read model that has to aggregate from events scattered across many columns is the most common source of unnecessary coupling — a "god read model." A screen with a stats row and a list below it is two components: two read models and two screen copies of the *same page* (same screen name on both copies; the copies differ only in which component is marked/highlighted crisp while the other is blurred/dimmed), not one screen-wide read model. Each narrower read model then sits naturally close to its own source event, and the `EVENT → READMODEL → SCREEN` chain for each component stays short and forward. See `eventmodeling-identifying-outputs`'s "Step 5a — Enumerate consumers and identify components" and "Step 5c — Break apart multi-component screens into copies" for the mechanics — apply this during Step 5, before the placement problem exists, rather than reordering columns to patch it afterward.
42
45
 
43
46
  Not every wide fan-in is this problem, though: a single homogeneous list/table (e.g. a catalog whose per-row status comes from many different lifecycle events) is still **one** component, and its read model legitimately needs to subscribe to many events spread across the timeline — that's a "roll-up" component, not a god read model. Treat that classification as an assumption, not a given: `eventmodeling-identifying-outputs` Step 5a records it as an inline MARKDOWN note (per "Documenting decisions inline" above) explaining why the component is one roll-up rather than several bundled ones, instead of force-splitting it or letting it pass unremarked.
44
47
 
48
+ ### The >3-events heuristic — evaluate, don't rubber-stamp
49
+
50
+ Whenever a read model ends up connected to more than 3 events, stop and actively evaluate whether it can be split — do not wave it through as "probably a roll-up" just because it's technically one visual component. Two distinct checks, both required:
51
+
52
+ 1. **Field-level minimality.** Re-derive, field by field, exactly which connected events each field actually needs. Any event connected to the read model that no field's `mapping` traces back to is a prunable connection — remove it (`set_connection` with `action: "remove"`), regardless of how the read model got wide. This is a pure hygiene check and applies even to a legitimate roll-up.
53
+ 2. **Kind-of-computation split.** Within one visual component, a field needing 1-2 simple, non-overlapping events (e.g. a monotonic counter incremented/decremented by its own dedicated events) is a fundamentally different kind of computation from a field needing wide fan-in across a whole entity's lifecycle (e.g. "is this available right now," which by construction depends on every event that can change that state). When a read model bundles both kinds, split the wide-fan-in field(s) out into their own read model and screen-copy, even if the surrounding fields stay together in a narrower one — don't let a handful of cheap counters justify leaving a genuine roll-up field un-isolated, and don't let a genuine roll-up field justify dragging cheap counters along with it.
54
+
55
+ A read model that is wide purely because it's a true single-entity roll-up (per the definition above) and has already been pruned to its minimum event set per check (1) does not need further splitting — document it and move on. The heuristic is a prompt to check every time, not a mandate to always split.
56
+
45
57
  ### No unplaced elements (0,0 nodes)
46
58
 
47
59
  After each step that creates elements (Steps 1–5), scan for any nodes that have no cell reference and are stranded at the default canvas position (0,0). These arise when `node:created` is called without `cellId`.
@@ -97,9 +109,11 @@ For each returned node, check whether it has a valid cell assignment. A node wit
97
109
  Never leave an unplaced node on the board when proceeding to the next step.
98
110
 
99
111
  ### No backward arrows
100
- The timeline must always progress left-to-right. Every connection arrow — SCREEN→COMMAND, COMMAND→EVENT, EVENTREADMODEL, READMODEL→SCREEN — must point to the right or downward (within the same column). A right-to-left arrow is always a layout error.
112
+ The timeline must always progress left-to-right — this is the goal to design toward, not just a validation check to run afterward. Every connection arrow — SCREEN→COMMAND, COMMAND→EVENT, READMODELSCREEN, READMODEL→AUTOMATION, AUTOMATION→COMMAND — must point to the right or downward (within the same column). A right-to-left arrow among these is always a layout error, full stop.
101
113
 
102
- Before wiring any connection, verify that `column(source) column(target)`. If this is violated:
114
+ **`EVENT READMODEL` is the one exception — and it stays an exception, not a second acceptable default.** Confirmed against the platform API (`learn-eventmodelers-api` §3 — `POST .../connections`): an event in a later column may legitimately connect to a read model in an earlier column, and vice versa, because a read model is a continuously-listening projection, not a point-in-time action — it can be fed by an event anywhere on its timeline, including one placed after it. Always try to place a read model so its connections read forward first; reach for this exception only when a genuine roll-up's wide fan-in makes an all-forward layout impractical (see "God read models" above), not as a default way to avoid column planning. When you do rely on it, don't "fix" the wide-fan-in read model by relocating it to sit after its last source event just to eliminate the backward arrows — that column surgery is unnecessary and, for a genuine roll-up, often impossible to do cleanly without breaking other consumers. The one real signal to watch for is a **connected event that isn't actually used by any field** on the read model — that's a prunable connection regardless of column position, not a column-ordering problem.
115
+
116
+ Before wiring any of the five forward-only pairs, verify that `column(source) ≤ column(target)`. If this is violated:
103
117
  - Move the earlier-placed element to the correct column, OR
104
118
  - Insert a new column at the right position to restore the correct order.
105
119
 
@@ -158,9 +172,7 @@ Update this file as each step completes.
158
172
 
159
173
  ## Phase Transition Protocol (Mandatory After Every Step)
160
174
 
161
- After each step completes, before invoking the next skill:
162
-
163
- ### 1. Write a phase summary to memory
175
+ After each step completes, before invoking the next skill, write a phase summary to memory.
164
176
 
165
177
  Append a summary block to `.trogonai/interviews/[project-name]/EVENTMODELING.md`:
166
178
 
@@ -173,12 +185,6 @@ Append a summary block to `.trogonai/interviews/[project-name]/EVENTMODELING.md`
173
185
 
174
186
  Also update the Interview Trail table row for this step (Status → Done, Key Output → one-line summary).
175
187
 
176
- ### 2. Compact the context
177
-
178
- After writing the summary, run `/compact` to clear the accumulated context before loading the next skill. The summary written above is the handoff — the next skill reads it from the file, not from the conversation history.
179
-
180
- This keeps each step's context lean and prevents token bloat from accumulating across all 11 steps.
181
-
182
188
  ---
183
189
 
184
190
  ## Mid-Workflow Entry
@@ -256,7 +262,7 @@ Invoke `eventmodeling-identifying-outputs`.
256
262
  **Output to carry forward**: Read model definitions — projections of events
257
263
  optimized for UI and processor queries — one per screen component, with any
258
264
  multi-component screen already broken apart into same-named, highlighted
259
- screen copies (this step's Step 5a/5b, not Step 3's job).
265
+ screen copies (this step's Step 5a/5c, not Step 3's job).
260
266
  **Gate**: Every screen data need from the storyboards is satisfied by a read
261
267
  model, and no read model spans more than one component.
262
268
 
@@ -466,4 +472,4 @@ specific needs:
466
472
  - [ ] Completeness check shows no unresolved field traceability gaps
467
473
  - [ ] Validation returns PASS or PASS WITH WARNINGS with all critical issues resolved
468
474
  - [ ] Interview trail in `.trogonai/` updated with status of each completed step
469
- - [ ] Phase summary written to memory and `/compact` run after every completed step before loading the next skill
475
+ - [ ] Phase summary written to memory after every completed step before loading the next skill
@@ -215,7 +215,7 @@ Order Entry UI
215
215
 
216
216
  ### 5. Organize Screens by Swimlane (Actor/System)
217
217
 
218
- **MANDATORY**: Use the **Role Catalog** from Step 1 (eventmodeling-brainstorming-events) as the source of swimlanes. Every human role in the catalog MUST have its own swimlane. Every system actor that has a UI or todo-list view gets a swimlane too.
218
+ **MANDATORY**: Use the **Role Catalog** from Step 1 (eventmodeling-brainstorming-events) as the source of swimlanes. Every human role in the catalog MUST have its own swimlane. Every system actor that has a UI or todo-list view gets a swimlane too — but this swimlane is narrative-only (see "Board Integration" below): system actors never get a physical actor lane of their own on the board, only human roles do.
219
219
 
220
220
  Group screens by who interacts with them:
221
221
 
@@ -254,6 +254,8 @@ Swimlane: Fulfillment System (System Actor)
254
254
 
255
255
  This shows which actors interact with which screens and helps visualize system boundaries.
256
256
 
257
+ **This grouping is not just narrative for human roles** — "Board Integration" below turns each *human role's* swimlane in this catalog into its own physical actor lane on the board, so a screen's role determines which lane it is actually placed in, not just how it is described in the report. System actor swimlanes stay narrative-only: their automations are placed in the chapter's shared default actor lane, never a lane fabricated to mimic a human role's lane (see "Placing Automations" below).
258
+
257
259
  ### 6. Show Processor "Todo List" Pattern
258
260
  For automated processors, show the todo list metaphor:
259
261
 
@@ -284,6 +286,8 @@ Success → InventoryReserved event produced + todo marked done
284
286
  Failure → InventoryFailed event produced + todo marked failed
285
287
  ```
286
288
 
289
+ **When it comes time to elaborate scenarios for this todo list (`eventmodeling-elaborating-scenarios`), reach for a storyline rather than plain GWT scenarios.** A todo list is exactly the shape a storyline is built for: the *same* read model (the todo list itself) walked through multiple states — empty → item added → item marked done/failed — which is one narrated walkthrough, not a set of isolated before/after pairs. See that skill's "Storylines" section for the data shape and posting mechanics.
290
+
287
291
  ### 7. Identify Missing Data
288
292
  Highlight where data doesn't have a clear source:
289
293
 
@@ -317,6 +321,47 @@ curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
317
321
 
318
322
  After completing the screen analysis, use the `handle-comment` skill to post a QUESTION comment on any screen node where data fields are unclear or missing sources are identified.
319
323
 
324
+ ## Resolve One Actor Lane Per Human Role (do this once, before placing any screens)
325
+
326
+ **Each human role gets its own physical lane — never place two different human roles' screens in the same actor row.** **System actors and processors are not part of this map** — they are never given a labeled lane of their own; every automation renders in the chapter's shared default actor lane instead (see "Placing Automations" below). A chapter is created with exactly one default `actor` lane, but a chapter can hold several actor-type lanes at once (`learn-eventmodelers-api` §2, `POST .../lanes`). Build a role→lane map covering human roles only, once per chapter, before the screen-placement loop, instead of resolving it screen-by-screen:
327
+
328
+ 1. Fetch the chapter and collect every row where `type === "actor"`, keyed by its `label`:
329
+
330
+ **Prefer MCP:**
331
+ ```
332
+ mcp__eventmodelers__get_node { "boardId": "$BOARD_ID", "nodeId": "$CHAPTER_ID" }
333
+ # → meta.timelineData.rows — collect every row where type === "actor" into { label → rowId }
334
+ ```
335
+
336
+ **Fallback (no MCP):**
337
+ ```bash
338
+ curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
339
+ "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$CHAPTER_ID"
340
+ ```
341
+
342
+ 2. For every **human role only** in the Role Catalog (Step 1's swimlane list above), check the map for a `label` that matches the role name (case-insensitive). If found, reuse that `rowId`. **Skip system actors/processors entirely** — do not create or look up a lane for them here; they never get an entry in this map.
343
+
344
+ 3. **If no matching lane exists, create one** — labeled with the role name, so the lane is visibly identifiable on the board:
345
+
346
+ **Prefer MCP:**
347
+ ```
348
+ mcp__eventmodelers__add_lane { "boardId": "$BOARD_ID", "timelineId": "$CHAPTER_ID", "type": "actor", "label": "<Role Name>" }
349
+ ```
350
+
351
+ **Fallback (no MCP):**
352
+ ```bash
353
+ curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/timelines/$CHAPTER_ID/lanes" \
354
+ -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: storyboarding-events" \
355
+ -H "Content-Type: application/json" \
356
+ -d '{"type": "actor", "label": "<Role Name>"}'
357
+ ```
358
+
359
+ Add the returned `rowId` to the map under that role's name. Do this once per role, not once per screen.
360
+
361
+ 4. **Leave the chapter's original default actor lane alone** — there is no rename endpoint for an existing lane, so don't try to relabel it or force the first role into it. It is fine for it to stay unused; every role, including the first one, gets a freshly labeled lane from Step 3.
362
+
363
+ The result is a `{ roleName: actorRowId }` map, covering human roles only, used by every SCREEN placed in this chapter (Step A below) — resolve it once, not per screen, and re-fetch/extend it only if a new human role appears mid-session that wasn't in the original catalog. **AUTOMATION nodes never consult this map** — they always target the chapter's default actor lane (see "Placing Automations" below).
364
+
320
365
  ## Mandatory Field Definitions on Screen Nodes
321
366
 
322
367
  > **CRITICAL: Every screen node MUST include `meta.fields` with a `mapping` on every field.** A screen without fields cannot show data lineage — it becomes impossible to verify that all displayed data has a source event or command. This applies regardless of which content type the screen renders as (HTML_SCREEN by default, or SCREEN when a sketch was explicitly requested).
@@ -398,24 +443,11 @@ A screen that only has a title and no fields is an empty placeholder — place t
398
443
 
399
444
  Every screen node requires rendered content. **HTML_SCREEN (via the `html-screen` rendering path below) is the default for every screen** — render a real HTML/CSS mockup, not a wireframe sketch. Only use the sketch path (plain SCREEN node, grid elements) when the user's request explicitly asked for a "sketch", "wireframe", or "low-fidelity mockup". The correct order for every screen is:
400
445
 
401
- **Step A — Compute the cell ID.** Screens go in the **actor lane** of their target column.
446
+ **Step A — Compute the cell ID.** This applies to SCREEN nodes (human roles only) — AUTOMATION nodes follow "Placing Automations" below instead. Screens go in **that screen's own role's actor lane** in their target column — look up `actorRowId` from the role→lane map built above, keyed by the screen's role (e.g. "Admin", "User"). Never fall back to "the" actor lane as if there were only one.
402
447
 
403
448
  1. Determine the target column (same column as the event/command, OR one column to the right of the read model).
404
- 2. Fetch the chapter to find the actor row ID.
405
-
406
- **Prefer MCP:**
407
- ```
408
- mcp__eventmodelers__get_node { "boardId": "$BOARD_ID", "nodeId": "$CHAPTER_ID" }
409
- # → meta.timelineData.rows — find the row where type === "actor"
410
- ```
411
-
412
- **Fallback (no MCP):**
413
- ```bash
414
- curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
415
- "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$CHAPTER_ID"
416
- # → timelineData.rows — find the row where type === "actor"
417
- ```
418
- 3. `cellId = actorRow.id + "-" + columnId`
449
+ 2. `actorRowId = roleLaneMap[<this screen's role>]` — the map was already resolved once for the whole chapter; do not re-fetch the chapter per screen. If this screen's role is genuinely new (wasn't in the original Role Catalog), resolve/create its lane now the same way (see above) and add it to the map before continuing.
450
+ 3. `cellId = actorRowId + "-" + columnId`
419
451
 
420
452
  **Step B (default) — Create the HTML_SCREEN node and render it in one atomic call.** Use `create_screen` with `contentType: "html"` — this creates the node, places it in `cellId`, and renders its pages together, so there is no window where the node exists without content:
421
453
 
@@ -554,18 +586,20 @@ When placing screens on the board, follow these alignment rules:
554
586
 
555
587
  | Screen type | Where it goes on the board |
556
588
  |-------------|---------------------------|
557
- | **Input/command screen** (triggers a command) | **Actor row, same column as the COMMAND and EVENT** it produces. The screen and command share a column — the screen sits in the actor row, the command in the interaction row, the event in the swimlane row. |
558
- | **View/output screen** (displays a read model) | **Actor row, one column to the RIGHT of the READ MODEL** it displays. The read model occupies the interaction row of the preceding column; the screen gets its own column immediately after. This column is finalised in Step 5 (Identifying Outputs) — during storyboarding, just document which read model each view screen will query. |
589
+ | **Input/command screen** (triggers a command) | **The role's own actor lane, same column as the COMMAND and EVENT** it produces. The screen and command share a column — the screen sits in that role's actor lane, the command in the interaction row, the event in the swimlane row. |
590
+ | **View/output screen** (displays a read model) | **The role's own actor lane, one column to the RIGHT of the READ MODEL** it displays. The read model occupies the interaction row of the preceding column; the screen gets its own column immediately after. This column is finalised in Step 5 (Identifying Outputs) — during storyboarding, just document which read model each view screen will query. |
559
591
 
560
592
  > **Do not create standalone screen columns that are disconnected from commands or read models.** Every screen must either share its column with the command it submits, or be placed one column to the right of the read model it displays.
561
593
 
562
594
  ### Multi-component screens are broken apart in Step 5, not here
563
595
 
564
- Storyboarding renders **one plain screen per screen state** — do not pre-split a screen into per-component copies here. Deciding how many components a view screen actually has, and breaking it apart into one highlighted copy per component, is `eventmodeling-identifying-outputs`'s job (its "Step 5a — Enumerate consumers and identify components" and "Step 5b — Break apart multi-component screens into copies"), because a component is defined by its read model and read models aren't designed until Step 5. During storyboarding, just place the single screen one column to the right of where its read model will end up (per the table above); document which read model it will query even before that read model exists.
596
+ Storyboarding renders **one plain screen per screen state** — do not pre-split a screen into per-component copies here. Deciding how many components a view screen actually has, and breaking it apart into one highlighted copy per component, is `eventmodeling-identifying-outputs`'s job (its "Step 5a — Enumerate consumers and identify components" and "Step 5c — Break apart multi-component screens into copies"), because a component is defined by its read model and read models aren't designed until Step 5. During storyboarding, just place the single screen one column to the right of where its read model will end up (per the table above); document which read model it will query even before that read model exists.
565
597
 
566
598
  ### Placing Automations
567
599
 
568
- When a processor or system actor reacts to events automatically (no human interaction), place an **AUTOMATION** node in the actor row instead of a SCREEN. Automations go in the same column as the COMMAND they trigger and the READMODEL that feeds them.
600
+ When a processor or system actor reacts to events automatically (no human interaction), place an **AUTOMATION** node in the chapter's **default actor lane** instead of a SCREEN — never create, reuse, or look up a per-system-actor lane for it, and never resolve it through the human role→lane map above. Automations go in the same column as the COMMAND they trigger and the READMODEL that feeds them.
601
+
602
+ **Do not design automation actor lanes to mimic human ones.** A "Payment Processor" or "Inventory System" swimlane in the narrative report (Step 5 above) is a documentation grouping only — it must never be materialized as its own labeled `actor`-type lane on the board. Only human roles get a physical lane; every automation, regardless of which system actor it narratively belongs to, renders in the same shared default actor lane.
569
603
 
570
604
  A column is an automation column (not a screen column) when:
571
605
  - The action is triggered by the system, not a user gesture
@@ -577,7 +611,7 @@ Examples:
577
611
  - Inventory check fires after payment authorized → AUTOMATION "Reserve Inventory"
578
612
  - Notification service sends an email → AUTOMATION "Send Confirmation Email"
579
613
 
580
- Human roles get SCREEN nodes. System actors and processors get AUTOMATION nodes. Place both types during storyboarding — do not defer automations to a later step.
614
+ Human roles get SCREEN nodes placed in their own labeled actor lane. System actors and processors get AUTOMATION nodes placed in the shared default actor lane. Place both types during storyboarding — do not defer automations to a later step.
581
615
 
582
616
  ### One Screen Per Column (Hard Rule)
583
617
 
@@ -612,6 +646,8 @@ Present as:
612
646
 
613
647
  ### System Actor Swimlanes
614
648
 
649
+ _(Narrative grouping only — these are not physical board lanes. Every automation below renders in the chapter's shared default actor lane; see "Placing Automations".)_
650
+
615
651
  #### Payment Processor Swimlane
616
652
  - Screen 1: Payment Verification (automated)
617
653
  - [Shows what UI/views the processor interacts with]
@@ -696,8 +732,10 @@ Failure produces: [Event]
696
732
  - [ ] Alternative states are shown
697
733
  - [ ] Error states are shown
698
734
  - [ ] **Every human role from the Role Catalog has at least one swimlane**
699
- - [ ] **Every swimlane is labeled with the role/actor name from the catalog**
700
- - [ ] **Swimlanes organized by actor/system**
735
+ - [ ] **Every human-role swimlane is labeled with the role name from the catalog**
736
+ - [ ] **Swimlanes organized by actor/system in the narrative report**
737
+ - [ ] **Every human role's swimlane is a real, distinct `actor`-type lane on the board (`meta.timelineData.rows`), not just a grouping in the markdown report** — no two different human roles share the same `actorRowId`
738
+ - [ ] **No system actor / processor has been given its own labeled actor lane** — every AUTOMATION node sits in the chapter's default actor lane, never a lane fabricated to mimic a human role's
701
739
  - [ ] **Human role screens clearly separated from processor screens**
702
740
  - [ ] **Processor todo list pattern shown for automated systems**
703
741
  - [ ] **System boundaries visible through swimlane organization**
@@ -68,7 +68,7 @@ Guidelines:
68
68
 
69
69
  ### Marks — only when the user explicitly asks for one
70
70
 
71
- The canvas has a native "Marks" feature (outline highlight, plus an optional "blur outside" or "white outside" spotlight) for calling out part of a screen — confirmed against the app's own source (`HtmlEditorModal.tsx`, `canvas/nodes/markHtml.ts`, `markBlur.ts`, `markStyles.ts`, `canvas/nodes/HtmlScreenNode.tsx`). **Do not add marks by default.** Only apply marks when the request explicitly asks to highlight/mark/call out/circle/spotlight, or blur/obscure/white-out part of the screen (e.g. "highlight the submit button", "blur everything except the email field", "white out everything but the header"), or when another skill's own instructions ask for a component to be marked/highlighted (e.g. `eventmodeling-identifying-outputs` Step 5b, which explicitly requests a mark per screen copy — that counts as an explicit ask). An ordinary "design a screen" request gets no marks.
71
+ The canvas has a native "Marks" feature (outline highlight, plus an optional "blur outside" or "white outside" spotlight) for calling out part of a screen — confirmed against the app's own source (`HtmlEditorModal.tsx`, `canvas/nodes/markHtml.ts`, `markBlur.ts`, `markStyles.ts`, `canvas/nodes/HtmlScreenNode.tsx`). **Do not add marks by default.** Only apply marks when the request explicitly asks to highlight/mark/call out/circle/spotlight, or blur/obscure/white-out part of the screen (e.g. "highlight the submit button", "blur everything except the email field", "white out everything but the header"), or when another skill's own instructions ask for a component to be marked/highlighted (e.g. `eventmodeling-identifying-outputs` Step 5c, which explicitly requests a mark per screen copy — that counts as an explicit ask). An ordinary "design a screen" request gets no marks.
72
72
 
73
73
  **Never fake this with hand-written inline CSS** (`filter:blur(...)`, `outline:...`, `opacity:...`, `pointer-events:...` on page elements) — that is not how the native feature works and won't match how the app itself renders a mark. A real mark has **two halves that must both be set together**, in the same page/meta update:
74
74