@eventmodelers/cli 1.0.23 → 1.0.24
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 +1 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +35 -22
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +11 -5
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +2 -9
package/package.json
CHANGED
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md
CHANGED
|
@@ -346,7 +346,9 @@ Does not produce commands (info-only)
|
|
|
346
346
|
|
|
347
347
|
## Output Format
|
|
348
348
|
|
|
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) —
|
|
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
|
+
|
|
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).
|
|
350
352
|
|
|
351
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.
|
|
352
354
|
|
|
@@ -372,31 +374,39 @@ READ MODEL → AUTOMATION → COMMAND → EVENT
|
|
|
372
374
|
|
|
373
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).
|
|
374
376
|
|
|
375
|
-
###
|
|
377
|
+
### Step 5a — Enumerate consumers and identify components
|
|
376
378
|
|
|
377
|
-
**
|
|
379
|
+
**Before designing any read model, enumerate every SCREEN and AUTOMATION already placed on the board** (from Step 3 — Storyboarding). Storyboarding hands off one plain screen per screen state and does not pre-split anything — deciding how many components a screen actually has is this step's decision, because a component is defined by its read model: **one component in a screen resembles one read model.**
|
|
378
380
|
|
|
379
|
-
|
|
380
|
-
- **
|
|
381
|
-
- **
|
|
381
|
+
Read models exist to serve the elements already on the board:
|
|
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.
|
|
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).
|
|
382
385
|
|
|
383
|
-
|
|
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.
|
|
384
387
|
|
|
385
|
-
|
|
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.
|
|
386
389
|
|
|
387
|
-
|
|
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.
|
|
388
391
|
|
|
389
|
-
**
|
|
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.
|
|
390
393
|
|
|
391
|
-
|
|
392
|
-
- Every **automation** that makes a decision based on system state needs at least one read model to read from.
|
|
393
|
-
- 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).
|
|
394
|
+
### Step 5b — Break apart multi-component screens into copies
|
|
394
395
|
|
|
395
|
-
|
|
396
|
+
**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:
|
|
396
397
|
|
|
397
|
-
|
|
398
|
+
- 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"`).
|
|
399
|
+
- Distinguish copies visually, not by name: **mark/highlight the one component each copy is about**, using the same CSS technique used throughout this workflow — de-emphasize every non-relevant component (`filter: blur(3px); opacity: 0.45; pointer-events: none;` on its wrapper) and leave the component of interest crisp, optionally with a highlight border class on it.
|
|
400
|
+
- Use the `html-screen` skill to produce each copy: pass it the original screen's markup plus which component to keep crisp. This is the skill's job — don't hand-roll the markup here.
|
|
401
|
+
- 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.
|
|
402
|
+
|
|
403
|
+
Why this matters, beyond tidiness:
|
|
404
|
+
- **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.
|
|
405
|
+
- **Components evolve independently.** A stats tile and a "recently added" list are driven by different events, change at different rates, and are typically owned by different slices in implementation. Bundling them into one read model couples their release/change cadence for no reason.
|
|
406
|
+
|
|
407
|
+
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.
|
|
398
408
|
|
|
399
|
-
### Pull field mappings from Step 3 — they are the spec, not a guess
|
|
409
|
+
### Step 5c — Pull field mappings from Step 3 — they are the spec, not a guess
|
|
400
410
|
|
|
401
411
|
**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:
|
|
402
412
|
|
|
@@ -406,7 +416,7 @@ For every SCREEN node, fetch it directly (`get_node`/`get_nodes`, never from mem
|
|
|
406
416
|
- 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.
|
|
407
417
|
- 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.
|
|
408
418
|
|
|
409
|
-
### Field data lineage — the `mapping` attribute on READMODEL fields
|
|
419
|
+
### Step 5d — Field data lineage — the `mapping` attribute on READMODEL fields
|
|
410
420
|
|
|
411
421
|
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:
|
|
412
422
|
|
|
@@ -446,7 +456,7 @@ Read models go in the `interaction` lane — **in the same column as the SCREEN
|
|
|
446
456
|
|
|
447
457
|
> **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.
|
|
448
458
|
|
|
449
|
-
### Placing READMODEL and AUTOMATION nodes with `cellId` (Mandatory)
|
|
459
|
+
### Step 5e — Placing READMODEL and AUTOMATION nodes with `cellId` (Mandatory)
|
|
450
460
|
|
|
451
461
|
**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.
|
|
452
462
|
|
|
@@ -522,7 +532,7 @@ mcp__eventmodelers__get_node { "boardId": "<BOARD_ID>", "nodeId": "<CHAPTER_ID>"
|
|
|
522
532
|
|
|
523
533
|
> **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.
|
|
524
534
|
|
|
525
|
-
### Preventing backward arrows (mandatory pre-placement check)
|
|
535
|
+
### Step 5f — Preventing backward arrows (mandatory pre-placement check)
|
|
526
536
|
|
|
527
537
|
The timeline must always progress left-to-right. A `READMODEL → SCREEN` connection going right-to-left is a layout error.
|
|
528
538
|
|
|
@@ -544,7 +554,7 @@ For each view screen S that queries this read model:
|
|
|
544
554
|
|
|
545
555
|
**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.
|
|
546
556
|
|
|
547
|
-
### Wire connections after placing each READMODEL (and its SCREEN)
|
|
557
|
+
### Step 5g — Wire connections after placing each READMODEL (and its SCREEN)
|
|
548
558
|
|
|
549
559
|
After `place-element` returns the READMODEL node ID, create the arrows that complete the slice:
|
|
550
560
|
|
|
@@ -604,13 +614,14 @@ After `place-element` returns the READMODEL node ID, create the arrows that comp
|
|
|
604
614
|
|
|
605
615
|
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"`.
|
|
606
616
|
|
|
607
|
-
### Mandatory per-node verification (run before declaring this step done)
|
|
617
|
+
### Step 5h — Mandatory per-node verification (run before declaring this step done)
|
|
608
618
|
|
|
609
619
|
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:
|
|
610
620
|
|
|
611
621
|
1. Does it now have an incoming `READMODEL → SCREEN` or `READMODEL → AUTOMATION` connection?
|
|
612
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`).
|
|
613
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.
|
|
614
625
|
|
|
615
626
|
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.
|
|
616
627
|
|
|
@@ -729,7 +740,9 @@ Identify UI needs without event sources:
|
|
|
729
740
|
- [ ] **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
|
|
730
741
|
- [ ] **Every AUTOMATION from storyboarding is connected to at least one read model** (via `READMODEL → AUTOMATION`) — same per-node verification
|
|
731
742
|
- [ ] **No read model is placed without a connected SCREEN or AUTOMATION consumer**
|
|
732
|
-
- [ ] **No read model spans more than one
|
|
743
|
+
- [ ] **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
|
|
745
|
+
- [ ] **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
|
|
733
746
|
- [ ] Every read model has clear purpose
|
|
734
747
|
- [ ] Every data field has event source
|
|
735
748
|
- [ ] Update logic for each event is explicit
|
|
@@ -35,8 +35,12 @@ These rules govern how every element is placed on the board. Enforce them throug
|
|
|
35
35
|
### Never stack read models at the end
|
|
36
36
|
Placing all read models in new columns at the very end of the timeline severs the visual connection to the events they're derived from. The board must show a coherent left-to-right narrative where each slice is self-contained.
|
|
37
37
|
|
|
38
|
-
### One read model per
|
|
39
|
-
A
|
|
38
|
+
### One read model per component, not one read model per screen
|
|
39
|
+
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
|
+
|
|
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.
|
|
42
|
+
|
|
43
|
+
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.
|
|
40
44
|
|
|
41
45
|
### No unplaced elements (0,0 nodes)
|
|
42
46
|
|
|
@@ -248,11 +252,13 @@ role or system processor.
|
|
|
248
252
|
|
|
249
253
|
Invoke `eventmodeling-identifying-outputs`.
|
|
250
254
|
|
|
251
|
-
**Input**: Event list + Commands from Step 4.
|
|
255
|
+
**Input**: Event list + Commands from Step 4 + the plain screens placed in Step 3.
|
|
252
256
|
**Output to carry forward**: Read model definitions — projections of events
|
|
253
|
-
optimized for UI and processor queries
|
|
257
|
+
optimized for UI and processor queries — one per screen component, with any
|
|
258
|
+
multi-component screen already broken apart into same-named, highlighted
|
|
259
|
+
screen copies (this step's Step 5a/5b, not Step 3's job).
|
|
254
260
|
**Gate**: Every screen data need from the storyboards is satisfied by a read
|
|
255
|
-
model.
|
|
261
|
+
model, and no read model spans more than one component.
|
|
256
262
|
|
|
257
263
|
---
|
|
258
264
|
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md
CHANGED
|
@@ -559,16 +559,9 @@ When placing screens on the board, follow these alignment rules:
|
|
|
559
559
|
|
|
560
560
|
> **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
561
|
|
|
562
|
-
###
|
|
562
|
+
### Multi-component screens are broken apart in Step 5, not here
|
|
563
563
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
- Render the **same full screen layout** once per region.
|
|
567
|
-
- In each copy, the region that copy is meant to foreground stays normal; every other region is visually de-emphasized — `filter: blur(3px); opacity: 0.45; pointer-events: none;` on the wrapper of the non-relevant region(s) reads clearly in an HTML_SCREEN render (Bulma classes still apply normally underneath the blur).
|
|
568
|
-
- Title each copy after the region, e.g. `"Librarian Dashboard — Statistics"` and `"Librarian Dashboard — Recently Added"`, not both just `"Librarian Dashboard"`.
|
|
569
|
-
- Place each copy in its own column, one column to the right of the read model that will feed it (per the table above) — this is normally a different column per copy, since each region typically has a different natural source event.
|
|
570
|
-
|
|
571
|
-
This is why the copies matter even though the underlying screen looks the same: it keeps each `READMODEL → SCREEN` connection narrow and forward (see `eventmodeling-identifying-outputs`'s "One read model per screen region" section), instead of one wide read model forced to straddle far-apart source events and pushed into a single column that can't sit correctly relative to every region's own event.
|
|
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.
|
|
572
565
|
|
|
573
566
|
### Placing Automations
|
|
574
567
|
|