@eventmodelers/cli 1.0.32 → 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.32",
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": {
@@ -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`.