@eventmodelers/cli 1.0.31 → 1.0.33

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.31",
3
+ "version": "1.0.33",
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": {
@@ -652,6 +652,17 @@ After `place-element` returns the READMODEL node ID, create the arrows that comp
652
652
 
653
653
  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"`.
654
654
 
655
+ 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.
656
+
657
+ Example body:
658
+ ```markdown
659
+ ## Event → field reasoning — OrderStatusView
660
+
661
+ - **OrderPlaced** → sets `orderId`, `status: "placed"`, `items[]` — the read model's creation event; the order doesn't exist before it.
662
+ - **OrderShipped** → updates `status: "shipped"`, `trackingNumber` — the only event carrying a tracking number.
663
+ - **OrderCancelled** → updates `status: "cancelled"` — terminal state, no further events expected after this.
664
+ ```
665
+
655
666
  ### Step 5i — Mandatory per-node verification (run before declaring this step done)
656
667
 
657
668
  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:
@@ -662,6 +673,7 @@ Do not declare Step 5 complete on the strength of the read models you happened t
662
673
  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.
663
674
  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.
664
675
  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.
676
+ 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.
665
677
 
666
678
  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.
667
679
 
@@ -785,6 +797,7 @@ Identify UI needs without event sources:
785
797
  - [ ] **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
786
798
  - [ ] **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
787
799
  - [ ] **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
800
+ - [ ] **Every read model has an event-reasoning MARKDOWN note** (Step 5h.4) covering every connected event and which field(s) it sets or updates
788
801
  - [ ] Every read model has clear purpose
789
802
  - [ ] Every data field has event source
790
803
  - [ ] Update logic for each event is explicit
@@ -56,6 +56,16 @@ Two distinct checks, both required, and neither is satisfied by having done it o
56
56
 
57
57
  After both checks, a read model may still be wide because one or more of its fields have irreducible, genuinely-single-field fan-in — that is an outcome you document (per "Documenting decisions inline" above, naming the specific field and why), not a category ("roll-up component") you assign to the node up front and stop checking. Re-run this evaluation on every read model at every step that touches it, including ones a prior step already looked at — a field added or a screen re-scoped later can introduce exactly the bundling problem this heuristic exists to catch.
58
58
 
59
+ ### Recognizing a dedicated business event behind a derived condition
60
+
61
+ This is a **business-modeling decision, not a technical one** — it is not triggered by a read model's fan-in count and is not a fix for anything the >3-events heuristic flags. A read model landing on wide fan-in is at most a symptom that might prompt you to ask the question below; it is never the reason to answer it one way or the other, and the question is worth asking regardless of how many events are involved.
62
+
63
+ The question to ask is simply: **is this fact worth a new event?** A derived condition — "is this available right now," "has this moved to its next stage," etc. — is worth its own event when it's a fact a domain expert would recognize and name in its own right (not just "some field I compute"), and when that fact is valuable to a later step in the process — another automation would react to it, a different bounded context would want to subscribe to it, some downstream process needs to trigger off of it. If both hold, it deserves to exist as its own dedicated event — e.g. "the copy was marked available" — not just as derived read-model logic recomputed from several other events.
64
+
65
+ When that's the case, model it as its own event, produced via the same todo-list + automation translation pattern Step 5b uses for external integrations, but triggered internally by whichever raw events can produce that outcome. If the condition is purely for display, with nothing downstream that would ever act on it, it stays a plain read-model projection — no new event needed, no matter how many raw events feed it or how wide the resulting fan-in looks.
66
+
67
+ **Only fold together causes that are genuinely redundant for the same outcome — never causes that carry distinct business meaning.** A derived condition's causes typically split into two groups: several distinct events that all mean the *same* thing from the business's point of view (e.g. `CopyReservationReleased`, `CopyReturned`, and `CopyReturnedFromRepair` all mean "the copy is available again"), and several distinct events that each mean something the business still wants told apart (e.g. `CopyReserved` → Reserved, `CopyCheckedOut` → CheckedOut, `CopySentForRepair` → UnderRepair, `CopyReportedLost` → Lost, `CopyWithdrawn` → Withdrawn). Only the first group is safe to consolidate — a dedicated event like `CopyMarkedAvailable` collapses "N different reasons, same outcome" into one reusable signal without losing information. Collapsing the second group into something like a generic `CopyMarkedUnavailable` would erase the *why*, which some downstream consumer may actually need — leave those as separate events and direct connections, even though the read model's fan-in then stays wider than the fully-consolidated ideal. That remaining fan-in is not a failure of anything — it means those events are each individually meaningful, not synonymous with each other, and collapsing them would have been the actual modeling mistake.
68
+
59
69
  ### No unplaced elements (0,0 nodes)
60
70
 
61
71
  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`.