@eventmodelers/cli 1.0.36 → 1.0.37

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.
Files changed (69) hide show
  1. package/package.json +1 -1
  2. package/shared/skills/learn-eventmodelers-api/SKILL.md +12 -10
  3. package/stacks/modeling-kit/templates/.claude/skills/add-next-slice/SKILL.md +2 -23
  4. package/stacks/modeling-kit/templates/.claude/skills/add-next-slice/references/api-fallback.md +11 -0
  5. package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +6 -57
  6. package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/references/api-fallback.md +68 -0
  7. package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +4 -61
  8. package/stacks/modeling-kit/templates/.claude/skills/attributes/references/api-fallback.md +39 -0
  9. package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +9 -53
  10. package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/references/api-fallback.md +63 -0
  11. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +9 -319
  12. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/references/examples.md +329 -0
  13. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +23 -199
  14. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/api-fallback.md +97 -0
  15. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/examples.md +35 -0
  16. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +13 -410
  17. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/references/api-fallback.md +22 -0
  18. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/references/examples.md +397 -0
  19. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/SKILL.md +132 -0
  20. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/references/api-fallback.md +21 -0
  21. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +9 -236
  22. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/references/examples.md +257 -0
  23. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +28 -302
  24. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/references/api-fallback.md +31 -0
  25. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/references/examples.md +216 -0
  26. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +30 -343
  27. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/references/api-fallback.md +79 -0
  28. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/references/examples.md +282 -0
  29. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +51 -400
  30. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/references/api-fallback.md +67 -0
  31. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/references/examples.md +273 -0
  32. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md +45 -152
  33. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md +49 -90
  34. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/patterns.md +64 -137
  35. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +74 -65
  36. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/references/api-fallback.md +51 -0
  37. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +1 -5
  38. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/references/api-fallback.md +10 -0
  39. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +19 -36
  40. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/api-fallback.md +41 -0
  41. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/examples.md +12 -9
  42. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/patterns.md +1 -10
  43. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +26 -332
  44. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/references/api-fallback.md +77 -0
  45. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/references/examples.md +271 -0
  46. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +9 -294
  47. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/references/examples.md +306 -0
  48. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +12 -11
  49. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/references/api-fallback.md +14 -0
  50. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +6 -36
  51. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/references/api-fallback.md +14 -0
  52. package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +3 -110
  53. package/stacks/modeling-kit/templates/.claude/skills/examples/references/api-fallback.md +118 -0
  54. package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +5 -25
  55. package/stacks/modeling-kit/templates/.claude/skills/handle-comment/references/api-fallback.md +35 -0
  56. package/stacks/modeling-kit/templates/.claude/skills/html-screen/SKILL.md +9 -44
  57. package/stacks/modeling-kit/templates/.claude/skills/html-screen/references/api-fallback.md +51 -0
  58. package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +23 -183
  59. package/stacks/modeling-kit/templates/.claude/skills/place-element/references/api-fallback.md +193 -0
  60. package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +14 -81
  61. package/stacks/modeling-kit/templates/.claude/skills/storyboard/references/api-fallback.md +74 -0
  62. package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +4 -45
  63. package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/references/api-fallback.md +44 -0
  64. package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +19 -88
  65. package/stacks/modeling-kit/templates/.claude/skills/timeline/references/api-fallback.md +91 -0
  66. package/stacks/modeling-kit/templates/.claude/skills/update-prompt-status/SKILL.md +1 -9
  67. package/stacks/modeling-kit/templates/.claude/skills/update-prompt-status/references/api-fallback.md +14 -0
  68. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-integrating-legacy-systems/SKILL.md +0 -674
  69. package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md +0 -204
@@ -174,181 +174,13 @@ InventoryLevelView
174
174
 
175
175
  ## Workflow
176
176
 
177
- Given commands and events, identify all outputs:
178
-
179
- ### 1. Map Event Data to UI Screens
180
- For each screen, identify source events:
181
-
182
- ```
183
- Screen: Order Status View
184
- Displays data from events:
185
- orderId ← OrderCreated event
186
- customerId ← OrderCreated event
187
- items ← OrderCreated event
188
- total ← OrderCreated event
189
- status ← OrderConfirmed event (or OrderCancelled)
190
- confirmedAt ← OrderConfirmed event
191
- paymentId ← PaymentAuthorized event
192
- shipmentId ← OrderShipped event
193
- shippedAt ← OrderShipped event
194
-
195
- This screen is a projection of these events:
196
- - OrderCreated
197
- - OrderConfirmed
198
- - PaymentAuthorized
199
- - OrderShipped
200
- ```
201
-
202
- ### 2. Define Read Models
203
- Create optimized views from event data:
204
-
205
- ```
206
- ReadModel: OrderStatusView
207
- Purpose: UI displays current order status
208
- Events subscribed: OrderCreated, OrderConfirmed, PaymentAuthorized, OrderShipped, OrderCancelled
209
- Data:
210
- {
211
- orderId: string (from OrderCreated)
212
- customerId: string (from OrderCreated)
213
- status: enum (from events: Draft → Confirmed → Authorized → Shipped → Delivered)
214
- createdAt: Date (from OrderCreated)
215
- confirmedAt: Date (from OrderConfirmed)
216
- paymentId: string (from PaymentAuthorized)
217
- shipmentId: string (from OrderShipped)
218
- shippedAt: Date (from OrderShipped)
219
- }
220
- ```
221
-
222
- ### 3. Document Event → Data Mapping
223
- Show exactly what data each event provides:
224
-
225
- ```
226
- Event: OrderCreated
227
- Provides to UI/Processors:
228
- orderId
229
- customerId
230
- items[]
231
- total
232
- shippingAddress
233
- createdAt
234
-
235
- Event: OrderConfirmed
236
- Provides to UI/Processors:
237
- orderId (link to stream)
238
- paymentMethod (user selected method)
239
- confirmedAt (timestamp)
240
- paymentId (payment system reference)
241
-
242
- Event: PaymentAuthorized
243
- Provides to UI/Processors:
244
- orderId (link to stream)
245
- paymentId
246
- authCode
247
- authorizedAt (timestamp)
248
- amount (verified amount)
249
-
250
- Event: OrderShipped
251
- Provides to UI/Processors:
252
- orderId (link to stream)
253
- shipmentId
254
- shippedAt (timestamp)
255
- carrier (shipping company)
256
- trackingNumber (for delivery tracking)
257
- ```
258
-
259
- ### 4. Create Output Catalog
260
- List all read models:
261
-
262
- ```
263
- ReadModel Catalog: Order System
264
-
265
- 1. OrderStatusReadModel
266
- Purpose: UI shows current order status
267
- Events: OrderCreated, OrderConfirmed, PaymentAuthorized, OrderShipped, OrderCancelled
268
- Data: orderId, status, createdAt, confirmedAt, paymentId, shipmentId
269
- Consumed by:
270
- - Order Status screen (UI)
271
- - Customer Dashboard (UI)
272
- - Order Processing Processor (decides if can ship)
273
-
274
- 2. OrderListReadModel
275
- Purpose: UI lists all orders for a customer
276
- Events: OrderCreated, OrderConfirmed, OrderCancelled
277
- Data: orderId, customerId, total, status, createdAt
278
- Consumed by:
279
- - Customer Order History (UI)
280
- - Order Search/Filter (UI)
281
-
282
- 3. PaymentStatusReadModel
283
- Purpose: UI shows payment status
284
- Events: OrderConfirmed, PaymentAuthorized, PaymentFailed
285
- Data: orderId, paymentId, status, authCode, failureReason, timestamp
286
- Consumed by:
287
- - Payment Status screen (UI)
288
- - Accounting Processor (reconciliation)
289
-
290
- 4. ShipmentTrackingReadModel
291
- Purpose: UI shows tracking information
292
- Events: OrderShipped, DeliveryConfirmed
293
- Data: orderId, shipmentId, trackingNumber, carrier, shippedAt, estimatedDelivery
294
- Consumed by:
295
- - Order Tracking screen (UI)
296
- - Customer notifications (Processor)
297
- ```
298
-
299
- ### 5. Identify Missing Data
300
- Check if all UI needs are covered:
301
-
302
- ```
303
- Question: What if UI needs "estimated delivery date"?
304
- Event: OrderShipped has carrier + trackingNumber
305
- Action needed: Add estimatedDelivery to OrderShipped event
306
- (or compute from carrier info)
307
-
308
- Question: What if UI needs to show "payment method" on status?
309
- Event: OrderConfirmed has paymentMethod
310
- Action needed: Include paymentMethod in relevant read models
311
-
312
- Question: What if UI needs "item descriptions"?
313
- Event: OrderCreated has items[]
314
- But: items[] only has productId
315
- Action needed: Enrich with product descriptions from catalog
316
- (via join with product service)
317
- ```
318
-
319
- ### 6. Processor Outputs
320
- Identify what processors consume:
321
-
322
- ```
323
- Processor: Inventory System
324
- Consumes from read models:
325
- - Orders in "PaymentAuthorized" status
326
- - Items and quantities needed
327
- Produces commands:
328
- - ReserveInventory
329
-
330
- Processor: Fulfillment System
331
- Consumes from read models:
332
- - Orders in "InventoryReserved" status
333
- - Items and quantities
334
- - Shipping address
335
- Produces commands:
336
- - CreateShipment
337
-
338
- Processor: Notification System
339
- Consumes from read models:
340
- - OrderCreated (sends confirmation)
341
- - OrderConfirmed (sends receipt)
342
- - OrderShipped (sends tracking)
343
- - DeliveryConfirmed (sends thank you)
344
- Does not produce commands (info-only)
345
- ```
177
+ Given commands and events, identify all outputs: for each screen, trace which events its data comes from; define a read model per component; document the event→data mapping; catalog the resulting read models; check for UI needs with no event source; and identify what processors consume. A full worked example of this reasoning (Order/Payment domain) is in `references/examples.md`.
346
178
 
347
179
  ## Output Format
348
180
 
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.
181
+ 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 only in the rare case where analysis reveals a processor that reads state and issues commands but was missed entirely in Step 4 — if that happens, immediately apply `eventmodeling-designing-automation-chains`'s rules to it (todo-list read model, translation chain if externally triggered) before continuing, rather than leaving it for Step 5i's defensive re-check to catch.
350
182
 
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).
183
+ This step proceeds as a sequence of lettered sub-steps: identify each screen's components (5a), break multi-component screens apart into copies (5c), then design and place one read model per component (5d onward). Every automation's todo-list read model and any translation chain is designed in **Step 4b** (`eventmodeling-designing-automation-chains`), immediately after Step 4 — not here. This step only ever designs screen-facing read models; Step 5i below re-checks automations defensively, not as this step's primary job.
352
184
 
353
185
  > **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
186
 
@@ -372,7 +204,7 @@ Automations follow:
372
204
  READ MODEL → AUTOMATION → COMMAND → EVENT
373
205
  ```
374
206
 
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).
207
+ 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. For automations, that read model was already designed in **Step 4b** (`eventmodeling-designing-automation-chains`); this step's job is limited to the defensive re-check in Step 5i below.
376
208
 
377
209
  ### Step 5a — Enumerate consumers and identify components
378
210
 
@@ -380,7 +212,7 @@ Treat any screen or automation without an incoming read model as a gap. A screen
380
212
 
381
213
  Read models exist to serve the elements already on the board:
382
214
  - Every **view screen** (output/read model screen) needs at least one read model to supply its data.
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.
215
+ - 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; this was already handled in Step 4b (`eventmodeling-designing-automation-chains`) for every automation placed in Step 4.
384
216
  - 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
217
 
386
218
  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.
@@ -391,42 +223,9 @@ Once a component's fields are genuinely homogeneous (every field needs the same
391
223
 
392
224
  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.
393
225
 
394
- > **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.
395
-
396
- ### Step 5b — Identify todo-list read models for automations
397
-
398
- **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.
399
-
400
- **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.
401
-
402
- **Worked example**: an automation that reacts to `CustomerRegistered` by sending a welcome notification.
403
- - Todo list: **NotificationsToSend** — one row per pending notification.
404
- - `CustomerRegistered` **opens** a row (a notification now needs sending).
405
- - `NotificationSent` (the event this automation's own resulting command produces) **closes** that row (removes it — the list only ever shows outstanding work).
406
- - The automation (`Send Welcome Notification`) reads `NotificationsToSend`, and for every open row issues `SendNotification`.
226
+ > **Placement rule**: A read model must be placed immediately upstream of the SCREEN or AUTOMATION it serves — sharing that column when possible (a SCREEN with a free interaction row), or one column to the left when not (any AUTOMATION; a SCREEN whose column is already occupied). Do not place a read model with no screen or automation in the very next column — doing so creates an orphaned read model that will never have a consumer.
407
227
 
408
- Even an automation that looks like a "pure signal relay" 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."
409
-
410
- **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.**
411
-
412
- **An automation can only ever be directly triggered by an internal event — never by another system's event.** A "trigger" arriving from a second swimlane is not itself the thing that drives your domain's work; it first has to be *translated* into an internal event. Do not model this as one automation whose todo list is opened by the external EVENT and that also does the real work (e.g. an automation reading a todo list opened by `ReservationRequested` from another system's swimlane and directly issuing `ReserveCopy`) — that lets an external system trigger domain work with no translation step, which this model doesn't allow. **Apply this now, in Step 5** — Conway's Law (Step 6) only confirms the boundary, it doesn't introduce the chain. When an integration trigger comes from another team's system, model it as **two chained automations**, never one:
413
-
414
- 1. **Translation automation** — converts the external fact into an internal one; the other system's own decision logic is out of scope. Its todo list is opened by the external EVENT and closed by the internal EVENT its own command produces — the one and only place an external EVENT may open a todo list.
415
- - **Three separate columns**, left to right: `[external EVENT] → [todo-list READMODEL] → [AUTOMATION + COMMAND + internal EVENT]`. Never crammed into one or two — the "one EVENT per column" rule applies here too.
416
- - **Name the internal EVENT for its business meaning, not the transport** — usually the same name as the external EVENT (e.g. external `CopyReserved` → internal `CopyReserved`; the swimlane already shows which is which), never a mechanical `<X>SignalReceived`/`<X>RequestReceived` suffix. Same for the automation/command: `Record Reservation`/`RecordReservation`, not `Record Reservation Signal`/`RecordReservationSignal`.
417
- - Its command and event carry no business decision — they only exist to produce the internal fact the next automation needs.
418
- 2. **Worker automation** — the one that does the actual work (the domain reaction the process is really about, e.g. `ReserveCopy`). Its todo list is opened **only** by the internal EVENT the translation automation produced (this chapter's own swimlane) — never by the external EVENT directly — and closed by whatever event marks that work done.
419
-
420
- Wire the todo lists the standard way for each automation separately: for the translation automation, the external EVENT (second swimlane) **opens** the row and its own resulting internal EVENT **closes** it; for the worker automation, that same internal EVENT **opens** its row and its own resulting EVENT **closes** it. `EVENT → READMODEL` connections from both swimlanes are unaffected by which swimlane the event sits in.
421
-
422
- **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.
423
-
424
- **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.
425
- - Connect READMODEL → AUTOMATION **first** (the automation reads its own todo list) — the closing connection below is only accepted once this edge exists.
426
- - Connect every **opening** EVENT → READMODEL.
427
- - 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 when the read model already feeds an AUTOMATION (see `learn-eventmodelers-api` §3) — this todo-list read model qualifies because of the `READMODEL → AUTOMATION` edge above. A read model in this shape 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.
428
-
429
- 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.
228
+ > **Automation todo-list read models are designed in Step 4b, not here.** The full patternevery automation's todo-list read model, the "no invisible signal" rule, and the two-chained-automation translation requirement for externally-triggered automations now lives in `eventmodeling-designing-automation-chains` (Step 4b), which runs immediately after Step 4, before this step. If Step 4b ran, every automation already on the board has its todo-list read model wired; Step 5i below only re-checks this defensively. The rare exception is an automation discovered only now, during output analysis (see "Output Format" above) — if that happens, apply `eventmodeling-designing-automation-chains`'s rules to it directly rather than re-deriving them here.
430
229
 
431
230
  ### Step 5c — Break apart multi-component screens into copies
432
231
 
@@ -435,7 +234,7 @@ After this step, every AUTOMATION on the board must have an incoming `READMODEL
435
234
  - Each copy is the **same page**, so it **keeps the same screen name/title** — do not rename copies after their component (e.g. don't title one copy `"Librarian Dashboard — Statistics"` and another `"Librarian Dashboard — Recently Added"`; both stay `"Librarian Dashboard"`).
436
235
  - Distinguish copies visually, not by name: **mark/highlight the one component each copy is about**, using the `html-screen` skill's native Marks feature — see that skill's "Marks" section for the full mechanism. In short: the component of interest gets `data-em-mark-id`/`em-mark em-mark-<colorhex>` baked onto it in the page HTML, paired with a matching `meta.marks` entry (`{id, color, pageIndex, blurOutside: true}`) that blurs every other top-level section. Never hand-roll this with inline `filter`/`outline`/`opacity` CSS — that does not match how the app itself renders a mark.
437
236
  - Use the `html-screen` skill to produce each copy: pass it the original screen's markup, explicitly asking it to mark/highlight the one component to keep crisp and blur the rest (this satisfies `html-screen`'s "only when the user explicitly asks for one" condition for its Marks feature — the ask comes from this step). This is the skill's job — don't hand-roll the markup here.
438
- - Place each copy in its own column, one column to the right of the read model that will feed it — this is normally a different column per copy, since each component typically has a different natural source event.
237
+ - Place each copy in its own column, the **same column** as the read model that will feed it (insert a new column immediately before if that copy's column is already occupied) — this is normally a different column per copy, since each component typically has a different natural source event.
439
238
 
440
239
  Why this matters, beyond tidiness:
441
240
  - **It prevents backward arrows.** A single screen-wide read model is forced to aggregate from whatever events each of its components needs, which often means reaching back across many columns to events scattered throughout the timeline — and the read model can only sit in one column, so some of those connections end up spanning a wide gap or, worse, pushing the read model's column later than some of its screen's other consumers require. Splitting by component lets each narrower read model sit close to its own natural source event(s), keeping every `EVENT → READMODEL` arrow short and forward.
@@ -489,9 +288,9 @@ Every field must also set `"cardinality"` — use `"Single"` unless the field ge
489
288
  }
490
289
  ```
491
290
 
492
- Read models go in the `interaction` lane **in the same column as the SCREEN or AUTOMATION they serve** (READMODEL in interaction row, SCREEN in actor row of the same column).
291
+ Read models go in the `interaction` lane. For a **SCREEN**, the primary read model shares the SCREEN's column (READMODEL in interaction row, SCREEN in actor row of the same column) — unless that column's interaction row is already occupied (e.g. a command/input screen, where the COMMAND already sits there), in which case the read model goes one column to the left instead. For an **AUTOMATION**, the read model always goes one column to the left, never the same column — an automation's own column already holds the COMMAND it issues. If a consumer needs more than one read model, only the primary one gets this placement; every additional read model goes further left still.
493
292
 
494
- > **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.
293
+ > **Timeline alignment rule**: Place the read model in the same column as its consumer screen when that column is free, or one column before its consumer (screen or automation) when it isn't. Insert the new column immediately **before** the consumer's column (`{"index": consumerColumnIndex}`, shifting the consumer right) rather than after the read model must sit upstream of (to the left of) the element it feeds. 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.
495
294
 
496
295
  ### Step 5f — Placing READMODEL and AUTOMATION nodes with `cellId` (Mandatory)
497
296
 
@@ -499,14 +298,16 @@ Read models go in the `interaction` lane — **in the same column as the SCREEN
499
298
 
500
299
  **For a READMODEL** (interaction lane):
501
300
 
502
- **Prefer MCP** — `place_element` collapses finding/creating the empty interaction cell (including inserting a new column when the target column is already occupied by a COMMAND) and creating the node into one call:
301
+ **Prefer MCP** — `place_element` collapses finding/creating the empty interaction cell and creating the node into one call, but it does **not** resolve an occupied target column for you: passing an already-occupied `columnIndex` fails outright rather than auto-inserting a column before it (it only auto-extends when `columnIndex` is *past* the current column count — a different situation). **Target column depends on the consumer type**:
302
+ - **SCREEN**: target the screen's own column index. First check whether that column's interaction row is already occupied (e.g. a command/input screen) — `get_node` with `projection: "cells"` on the chapter. If it is, insert a new column immediately before the screen first (`add_column` with `beforeNodeId` set to the screen's own node id), then pass *that* new column's index to `place_element` instead of the screen's original one.
303
+ - **AUTOMATION**: target `consumerColumnIndex - 1` (one column to the *left* of the automation) — never the automation's own column index, since it already holds the COMMAND the automation issues.
503
304
  ```
504
305
  mcp__eventmodelers__place_element {
505
306
  "boardId": "<BOARD_ID>",
506
307
  "timelineId": "<CHAPTER_ID>",
507
308
  "elementType": "READMODEL",
508
309
  "title": "ActiveReservationView",
509
- "columnIndex": <consumerScreenOrAutomationColumnIndex>
310
+ "columnIndex": <consumerScreenColumnIndex> // or <automationColumnIndex - 1> for an AUTOMATION consumer
510
311
  }
511
312
  ```
512
313
  Then set `meta.fields` (with `mapping`/`generated`/`cardinality`) on the returned node id:
@@ -520,45 +321,17 @@ mcp__eventmodelers__submit_node_events {
520
321
  }]
521
322
  }
522
323
  ```
523
- To determine the consumer's column index beforehand, or to check whether a specific interaction cell is already occupied (there is no `cellId` filter on `get_nodes` — see the note under "Wire connections" below), fetch the chapter and read its cell map:
324
+ To determine the consumer's column index beforehand, or to check whether a specific interaction cell is already occupied (there is no `cellId` filter on `get_nodes` — see the note under "Wire connections" below), fetch the chapter and read its cell map — `projection: "cells"` returns just `{rows, columns, cells}`, not the whole chapter node:
524
325
  ```
525
- mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<CHAPTER_ID>" }
526
- # → meta.timelineData.rows (find "interaction"/"actor" rows) and meta.timelineData.cells (sparse; absent id = empty)
326
+ mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<CHAPTER_ID>", "projection": "cells" }
327
+ # → rows (find "interaction"/"actor" rows) and cells (sparse; absent id = empty)
527
328
  ```
528
329
 
529
- **Fallback (no MCP)**the full manual sequence:
330
+ **Fallback (no MCP):** see `references/api-fallback.md` "Step 5f — Placing a READMODEL node (full manual sequence)".
530
331
 
531
- 1. Find the column where the consumer SCREEN or AUTOMATION lives. Fetch the timeline to get the interaction row ID:
532
- ```bash
533
- curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
534
- "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/$CHAPTER_ID"
535
- # → timelineData.rows — find the row where type === "interaction"
536
- ```
537
- 2. Check if the interaction cell is already occupied (existing COMMAND):
538
- ```bash
539
- curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=<interactionRowId>-<columnId>" \
540
- -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID"
541
- ```
542
- If a COMMAND occupies that cell, insert a new column immediately after (`{"index": currentIndex + 1}`) and use that column's ID instead.
543
- 3. `cellId = interactionRow.id + "-" + columnId`
544
- 4. Create the READMODEL:
545
- ```bash
546
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes/events" \
547
- -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: identifying-outputs" \
548
- -H "Content-Type: application/json" \
549
- -d '[{
550
- "id": "<event-uuid>",
551
- "eventType": "node:created",
552
- "nodeId": "<node-uuid>",
553
- "boardId": "<BOARD_ID>",
554
- "timestamp": 1234567890,
555
- "chapterId": "<CHAPTER_ID>",
556
- "cellId": "<interactionRowId>-<columnId>",
557
- "meta": {"type": "READMODEL", "title": "ActiveReservationView", "fields": [...]}
558
- }]'
559
- ```
332
+ **Pass `autoConnect: false` on every `place_element` / `node:created` call in this step.** Output read-model columns are inserted right next to automation-chain and command columns whose events are *not* the read model's sources — the default auto-connect would wire the new READMODEL to the nearest event on its left, which is exactly the stray-edge cleanup this step has repeatedly generated. Suppress it here and wire every `EVENT → READMODEL` / `READMODEL → SCREEN` / `READMODEL → AUTOMATION` edge explicitly in Step 5h's `set_connections` batch. After the batch, run `validate_model` (`{boardId, chapterId}`) — its `backward-arrows` and `readmodel-sources` findings confirm the wiring is what you intended and no stray edge slipped in.
560
333
 
561
- **For an AUTOMATION** (actor lane, same column as its READMODEL):
334
+ **For an AUTOMATION** (actor lane) its READMODEL always goes **one column to its left**, never the same column: the automation's own column already holds the COMMAND it issues (interaction row), so the read model can't also live there.
562
335
 
563
336
  **Prefer MCP** — same `place_element` call with `"elementType": "AUTOMATION"`, then `submit_node_events` for fields, as above.
564
337
 
@@ -571,27 +344,26 @@ mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<CHAPTER_ID>"
571
344
 
572
345
  ### Step 5g — Preventing backward arrows (mandatory pre-placement check)
573
346
 
574
- The timeline must always progress left-to-right. A `READMODEL → SCREEN` connection going right-to-left is a layout error.
347
+ The timeline must always progress left-to-right, or downward within the same column. A `READMODEL → SCREEN` connection going right-to-left is a layout error.
575
348
 
576
- The correct layout is: **READMODEL in column N, SCREEN in column N+1** (the screen is always one column to the right of its read model). Before placing each read model, find the view screen it serves and verify the column order:
349
+ The correct layout is: **READMODEL and its (primary) view SCREEN share the same column** — READMODEL in the interaction row, SCREEN in the actor row, a downward connection. The read model only sits in a separate column, immediately **before** the screen's, when the screen's column is already unavailable to it (its interaction row is occupied by something else, e.g. a COMMAND on a command/input screen). If a screen displays more than one read model, only the primary read model shares the screen's column — every additional read model goes further left, never to the right. Before placing each read model, find the view screen it serves and verify the column order:
577
350
 
578
351
  ```
579
- For each view screen S that queries this read model:
580
- If column(S) <= intended column(READMODEL):
581
- The screen is not to the right of the read model. Fix before placing.
582
- Option A: Insert a new column immediately after the read model's column
583
- and move screen S there.
584
- Use POST /timelines/:tl/columns {"index": N} to insert,
585
- then node:changed to update the screen node's cell.
586
- If column(S) == intended column(READMODEL) + 1:
587
- Screen is already in the correct column directly to the right. No adjustment needed.
588
- If column(S) > intended column(READMODEL) + 1:
589
- → Gap between read model and screen. Move the read model to column(S) - 1, or move the screen to column(READMODEL) + 1.
352
+ For each view screen S that queries this read model as its primary read model:
353
+ If column(S)'s interaction row is free:
354
+ Place the READMODEL in column(S) itself (same column as S). No adjustment needed.
355
+ If column(S)'s interaction row is already occupied:
356
+ Insert a new column immediately before column(S) and place the READMODEL there instead.
357
+ mcp__eventmodelers__add_column { "boardId": "<BOARD_ID>", "timelineId": "<TL>", "beforeNodeId": "<S's node id>" }
358
+ (fallback, no MCP: POST /timelines/:tl/columns {"index": N} with N computed by hand),
359
+ then node:changed to update any node whose cell needs to move.
360
+ If the read model ends up more than one column away from S with nothing in between:
361
+ Gap between read model and screen. Close it: move the read model into column(S) (if free) or column(S) - 1.
590
362
  ```
591
363
 
592
- **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.
364
+ **View screens normally share the column of the (primary) read model they display** — either because they were placed there in Step 3, or because the read model was placed into the screen's own column just now (per the check above). A screen's own position is never moved to resolve a read model placement conflict — when the shared column isn't available, the **read model** gets a new column immediately before the screen's, not the other way around (this preserves the screen's narrative order from Step 3).
593
365
 
594
- **The same rule applies to `EVENT → READMODEL`.** If a later event needs to update data a read model already feeds to a SCREEN, do not connect that later event back into the existing read model — the platform only accepts an `EVENT → READMODEL` backward connection when the read model already has a `READMODEL → AUTOMATION` edge (the todo-list pattern from Step 5b). For any read model feeding a SCREEN, resolve the update the same way Step 5c resolves multi-component screens: place a **new copy of the read model** in (or immediately after) the later event's column, connect the later event forward into that copy, and place a matching copy of the same screen there — same title, updated data, optionally re-marked/highlighted via `html-screen`'s Marks feature. Never link the new copy back to the earlier read model instance.
366
+ **The same rule applies to `EVENT → READMODEL`.** If a later event needs to update data a read model already feeds to a SCREEN, do not connect that later event back into the existing read model — the platform only accepts an `EVENT → READMODEL` backward connection when the read model already has a `READMODEL → AUTOMATION` edge (the todo-list pattern from Step 4b, `eventmodeling-designing-automation-chains`). For any read model feeding a SCREEN, resolve the update the same way Step 5c resolves multi-component screens: place a **new copy of the read model** in (or immediately after) the later event's column, connect the later event forward into that copy, and place a matching copy of the same screen there — same title, updated data, optionally re-marked/highlighted via `html-screen`'s Marks feature. Never link the new copy back to the earlier read model instance.
595
367
 
596
368
  ### Step 5h — Wire connections after placing each READMODEL (and its SCREEN)
597
369
 
@@ -599,43 +371,26 @@ After `place-element` returns the READMODEL node ID, create the arrows that comp
599
371
 
600
372
  1. **EVENT → READMODEL** — find the primary source EVENT node in the swimlane row of the same column.
601
373
 
602
- **Prefer MCP** — `get_nodes` has no `cellId` filter (only `type`); look up occupancy via the chapter's cell map instead, then connect with the type-checked edge tool (auto-corrects direction, skips duplicates):
374
+ **Prefer MCP** — `get_nodes` has no `cellId` filter (only `type`); look up occupancy via the chapter's cell map instead (`projection: "cells"`), then connect with the type-checked edge tool (auto-corrects direction, skips duplicates):
603
375
  ```
604
- mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<CHAPTER_ID>" }
605
- # → read meta.timelineData.cells["<swimlaneRowId>-<columnId>"] for the occupying node id
376
+ mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<CHAPTER_ID>", "projection": "cells" }
377
+ # → read cells["<swimlaneRowId>-<columnId>"] for the occupying node id
606
378
  mcp__eventmodelers__set_connection { "boardId": "<BOARD_ID>", "source": "<eventNodeId>", "target": "<readmodelNodeId>", "action": "connect" }
607
379
  ```
608
380
 
609
- **Fallback (no MCP):**
610
- ```bash
611
- curl -s "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?cellId=<swimlaneRowId>-<columnId>" \
612
- -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs"
613
- ```
614
- Connect it:
615
- ```bash
616
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/connections" \
617
- -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs" \
618
- -H "Content-Type: application/json" \
619
- -d '{"source":"<eventNodeId>","target":"<readmodelNodeId>"}'
620
- ```
381
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 5h.1 — Wire EVENT → READMODEL".
621
382
 
622
- 2. **READMODEL → SCREEN** — connect to the existing SCREEN node in the actor row of the next column (screens are typically already placed from Step 3).
383
+ 2. **READMODEL → SCREEN** — connect to the existing SCREEN node in the actor row of the same column (or the column immediately after, only when that column wasn't available to the read model — screens are typically already placed from Step 3).
623
384
 
624
385
  **Prefer MCP:**
625
386
  ```
626
387
  mcp__eventmodelers__set_connection { "boardId": "<BOARD_ID>", "source": "<readmodelNodeId>", "target": "<screenNodeId>", "action": "connect" }
627
388
  ```
628
389
 
629
- **Fallback (no MCP):**
630
- ```bash
631
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/connections" \
632
- -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs" \
633
- -H "Content-Type: application/json" \
634
- -d '{"source":"<readmodelNodeId>","target":"<screenNodeId>"}'
635
- ```
390
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 5h.2 — Wire READMODEL → SCREEN".
636
391
 
637
392
  3. **READMODEL → AUTOMATION** — if the read model is consumed by an automatic process (scheduler, background job, external trigger), place the AUTOMATION node and connect it:
638
- - Place the AUTOMATION in the automation lane, in the column immediately to the right of its read model (same rule as screens).
393
+ - Place the AUTOMATION in the automation lane, in the column immediately to the right of its read model unlike a view screen, this is unconditional for automations: the automation's own column always holds the COMMAND it issues, so its read model never shares that column.
639
394
  - Then connect:
640
395
 
641
396
  **Prefer MCP:**
@@ -643,16 +398,12 @@ After `place-element` returns the READMODEL node ID, create the arrows that comp
643
398
  mcp__eventmodelers__set_connection { "boardId": "<BOARD_ID>", "source": "<readmodelNodeId>", "target": "<automationNodeId>", "action": "connect" }
644
399
  ```
645
400
 
646
- **Fallback (no MCP):**
647
- ```bash
648
- curl -s -X POST "$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/connections" \
649
- -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" -H "x-user-id: eventmodeling-identifying-outputs" \
650
- -H "Content-Type: application/json" \
651
- -d '{"source":"<readmodelNodeId>","target":"<automationNodeId>"}'
652
- ```
401
+ **Fallback (no MCP):** see `references/api-fallback.md` — "Step 5h.3 — Wire READMODEL → AUTOMATION".
653
402
 
654
403
  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"`.
655
404
 
405
+ If this step is processing more than one read model in the same pass, collect every connection resolved above (across all of them) into one `set_connections` call instead of one `set_connection` per pair — this was the single largest source of individual tool calls in this step. Pass `compact: true` on that call: with `autoConnect: false` set at placement, every edge here is one you're deliberately creating, so a `{connected, existed, removed, notFound, failed, errors}` tally is all you need back — not a row per edge.
406
+
656
407
  4. **Document the reasoning for each connected event** — for every EVENT → READMODEL edge wired in step 1 (including any added later, e.g. via Step 5g's backward-connection exemption or a Step 5c/copy pattern), record why that event feeds this read model: which field(s) it sets or updates, and why. Use one MARKDOWN note per read model, in that read model's own column (same feedback-lane + MARKDOWN mechanics as `eventmodeling-orchestrating-event-modeling`'s "Documenting decisions inline, at any step" / Step 11 — add the chapter's feedback lane first if it doesn't already exist, then place the note at `cellId = "<feedbackLaneId>-<readModelColumnId>"`). Extend the existing note (don't create a second one) when the read model later gains another connected event.
657
408
 
658
409
  Example body:
@@ -670,133 +421,33 @@ Do not declare Step 5 complete on the strength of the read models you happened t
670
421
 
671
422
  1. Does it now have an incoming `READMODEL → SCREEN` or `READMODEL → AUTOMATION` connection?
672
423
  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.
673
- 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.
424
+ 3. If it's an AUTOMATION and not connected, it is **never** exempt — this should already be resolved by Step 4b (`eventmodeling-designing-automation-chains`); if it isn't, apply that skill's rules now to identify its todo-list read model.
674
425
  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.
675
426
  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.
676
427
  6. **Re-fetch every READMODEL too** and run the >3-events heuristic (`eventmodeling-orchestrating-event-modeling`) on each one field by field — including read models a MARKDOWN note already justified as a roll-up. A prior note documents one field's irreducible fan-in; it does not exempt the rest of that node's fields from this check. The failure mode this catches: a wide-fan-in field (e.g. live per-copy availability) bundled together with a cheap, low-fan-in identity/fact field (e.g. a title set by 1-2 events) that has nothing to do with the roll-up — that pairing is always two read models, never one, no matter how the note reads.
677
428
  7. **Every READMODEL has its event-reasoning MARKDOWN note (Step 5h.4)**, and that note accounts for *every* inbound `EVENT → READMODEL` edge on the node — not just the one from when it was first placed. If a read model gained a connected event later and the note wasn't extended, fix it now rather than carrying the gap forward.
678
429
 
430
+ Run `validate_model` (`{boardId, chapterId}`) once as the mechanical half of this pass — its `readmodel-sources` findings list every READMODEL with no inbound EVENT, `screen-collisions` flags any column that ended up with two screens, and `backward-arrows` catches a `READMODEL → SCREEN` that points left. Then do the judgement checks above (blank-form exemptions, the >3-events heuristic, note completeness) that the tool can't make.
431
+
679
432
  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.
680
433
 
681
434
  After all read models, screens, automations, and connections are in place, present the Read Model Catalog summary as text to the user.
682
435
 
683
436
  ---
684
437
 
685
- For reference, the full markdown structure is:
686
-
687
- ```markdown
688
- # Outputs: [Domain Name]
689
-
690
- ## Read Models Summary
691
-
692
- | ReadModel | Purpose | Events | Consumed By |
693
- |-----------|---------|--------|-------------|
694
- | OrderStatus | Show order state | OrderCreated, OrderConfirmed | UI, Processor |
695
- | OrderList | List orders | OrderCreated, OrderCancelled | UI |
696
- | PaymentStatus | Payment info | OrderConfirmed, PaymentAuthorized | UI, Accounting |
697
- | Shipment Tracking | Track delivery | OrderShipped, DeliveryConfirmed | UI, Notifications |
698
-
699
- ---
700
-
701
- ## Detailed Read Models
702
-
703
- ### ReadModel: OrderStatusView
704
-
705
- **Purpose**: Order Status screen displays current order state
706
-
707
- **Events subscribed**:
708
- - OrderCreated
709
- - OrderConfirmed
710
- - PaymentAuthorized
711
- - OrderShipped
712
- - OrderCancelled
713
- - DeliveryConfirmed
714
-
715
- **Data**:
716
- ```
717
- {
718
- orderId: string
719
- customerId: string
720
- status: 'Draft' | 'Confirmed' | 'Authorized' | 'Shipped' | 'Delivered' | 'Cancelled'
721
- items: Array<{productId, quantity, unitPrice}>
722
- total: number
723
- shippingAddress: Address
724
-
725
- createdAt: Date
726
- confirmedAt: Date
727
- paymentId: string
728
- paymentMethod: 'card' | 'transfer'
729
- authorizedAt: Date
730
-
731
- shipmentId: string
732
- carrier: string
733
- trackingNumber: string
734
- shippedAt: Date
735
- estimatedDelivery: Date
736
- }
737
- ```
738
-
739
- **Update Logic**:
740
- - OrderCreated: Insert with status='Draft'
741
- - OrderConfirmed: Update status='Confirmed'
742
- - PaymentAuthorized: Update status='Authorized', set paymentId
743
- - OrderShipped: Update status='Shipped', set shipmentId, carrier, trackingNumber
744
- - DeliveryConfirmed: Update status='Delivered'
745
- - OrderCancelled: Update status='Cancelled'
746
-
747
- **Consumed By**:
748
- - Order Status Screen (displays)
749
- - Order Processing Processor (checks status)
750
- - Notification System (sends updates)
751
-
752
- --- [Repeat for each read model]
753
-
754
- ---
755
-
756
- ## Data Completeness Check
757
-
758
- ### Events → UI Needs
759
-
760
- Verify all UI needs have event sources:
761
-
762
- | UI Need | Event Source | Status |
763
- |---------|-------------|--------|
764
- | Order status | OrderConfirmed, OrderShipped | |
765
- | Tracking number | OrderShipped | |
766
- | Order items | OrderCreated | |
767
- | Estimated delivery | OrderShipped | |
768
- | Cancellation reason | OrderCancelled | |
769
-
770
- ### Missing Data
771
-
772
- Identify UI needs without event sources:
773
- - None identified
774
-
775
- ---
776
-
777
- ## Processor Consumption
778
-
779
- ### Processors and their reads:
780
-
781
- | Processor | Reads From | Writes Commands |
782
- |-----------|-----------|-----------------|
783
- | Inventory | OrderStatusView (Authorized) | ReserveInventory |
784
- | Fulfillment | OrderStatusView (InventoryReserved) | CreateShipment |
785
- | Notification | OrderStatusView (all) | None (info-only) |
786
- | Accounting | PaymentStatusView | None (reporting) |
787
- ```
438
+ Older versions of this skill wrote the read model catalog as a markdown document rather than placing nodes on the board — that legacy template is kept in `references/examples.md` for reference only; it is not the actual output mechanism.
788
439
 
789
440
  ## Quality Checklist
790
441
 
791
442
  ### Read Model Design
792
443
  - [ ] **Typical pattern applied**: most screens follow `READ MODEL → SCREEN → COMMAND → EVENT`
793
444
  - [ ] **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
794
- - [ ] **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
795
- - [ ] **No automation's todo list is opened directly by another system's (second-swimlane) EVENT unless that automation is itself the translation automation** (Step 5b) — an automation doing the actual domain work is only ever opened by an internal event; a second-swimlane EVENT feeding straight into a work automation's todo list is a missing translation automation
445
+ - [ ] **Every AUTOMATION from storyboarding is connected to at least one todo-list read model** (via `READMODEL → AUTOMATION`, Step 4b) — no exemption for automations, unlike screens; even a simple relay automation gets one
446
+ - [ ] **No automation's todo list is opened directly by another system's (second-swimlane) EVENT unless that automation is itself the translation automation** (Step 4b) — an automation doing the actual domain work is only ever opened by an internal event; a second-swimlane EVENT feeding straight into a work automation's todo list is a missing translation automation
796
447
  - [ ] **No read model is placed without a connected SCREEN or AUTOMATION consumer**
797
448
  - [ ] **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
798
449
  - [ ] **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
799
- - [ ] **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
450
+ - [ ] **Every automation's todo-list read model identifies its opening and closing events** (Step 4b) — including the automation's own resulting event as a closing event where applicable, not just the triggering event
800
451
  - [ ] **A field's genuinely irreducible wide fan-in is documented per-field** (inline MARKDOWN note, per "Documenting decisions inline") — and that note is never treated as clearing every other field on the same read model from the >3-events check; a cheap identity/fact field bundled alongside a wide roll-up field is always split out, never excused by the roll-up's own note
801
452
  - [ ] **Every read model has an event-reasoning MARKDOWN note** (Step 5h.4) covering every connected event and which field(s) it sets or updates
802
453
  - [ ] Every read model has clear purpose