@eventmodelers/cli 1.0.36 → 1.0.38
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/shared/skills/learn-eventmodelers-api/SKILL.md +22 -13
- package/stacks/modeling-kit/templates/.claude/skills/add-next-slice/SKILL.md +2 -23
- package/stacks/modeling-kit/templates/.claude/skills/add-next-slice/references/api-fallback.md +11 -0
- package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +6 -57
- package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/references/api-fallback.md +68 -0
- package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +4 -61
- package/stacks/modeling-kit/templates/.claude/skills/attributes/references/api-fallback.md +39 -0
- package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/SKILL.md +9 -53
- package/stacks/modeling-kit/templates/.claude/skills/discover-storyboard/references/api-fallback.md +63 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/SKILL.md +12 -380
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-applying-conways-law/references/examples.md +329 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/SKILL.md +45 -290
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/api-fallback.md +97 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-brainstorming-events/references/examples.md +35 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/SKILL.md +15 -410
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/references/api-fallback.md +22 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-checking-completeness/references/examples.md +397 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-core-rules/SKILL.md +182 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/SKILL.md +148 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-automation-chains/references/api-fallback.md +21 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/SKILL.md +48 -448
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-designing-event-models/references/examples.md +167 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +31 -380
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/references/api-fallback.md +31 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/references/examples.md +216 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/SKILL.md +33 -393
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/references/api-fallback.md +79 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-inputs/references/examples.md +282 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/SKILL.md +54 -454
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/references/api-fallback.md +67 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-identifying-outputs/references/examples.md +273 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-interview-protocol/SKILL.md +31 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/SKILL.md +37 -184
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/domain-patterns.md +58 -99
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/patterns.md +82 -163
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/SKILL.md +86 -78
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-orchestrating-event-modeling/references/api-fallback.md +51 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/SKILL.md +5 -5
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-plotting-events/references/api-fallback.md +10 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/SKILL.md +22 -51
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/api-fallback.md +41 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/examples.md +12 -9
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-slicing-event-models/references/patterns.md +1 -10
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/SKILL.md +29 -382
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/references/api-fallback.md +77 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-storyboarding-events/references/examples.md +271 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/SKILL.md +12 -349
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-translating-external-events/references/examples.md +306 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md +69 -107
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/references/api-fallback.md +14 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/SKILL.md +75 -160
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models-checklist/references/api-fallback.md +14 -0
- package/stacks/modeling-kit/templates/.claude/skills/examples/SKILL.md +3 -110
- package/stacks/modeling-kit/templates/.claude/skills/examples/references/api-fallback.md +118 -0
- package/stacks/modeling-kit/templates/.claude/skills/handle-comment/SKILL.md +5 -25
- package/stacks/modeling-kit/templates/.claude/skills/handle-comment/references/api-fallback.md +35 -0
- package/stacks/modeling-kit/templates/.claude/skills/html-screen/SKILL.md +9 -44
- package/stacks/modeling-kit/templates/.claude/skills/html-screen/references/api-fallback.md +51 -0
- package/stacks/modeling-kit/templates/.claude/skills/place-element/SKILL.md +34 -180
- package/stacks/modeling-kit/templates/.claude/skills/place-element/references/api-fallback.md +203 -0
- package/stacks/modeling-kit/templates/.claude/skills/storyboard/SKILL.md +14 -81
- package/stacks/modeling-kit/templates/.claude/skills/storyboard/references/api-fallback.md +74 -0
- package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/SKILL.md +4 -45
- package/stacks/modeling-kit/templates/.claude/skills/storyboard-screen/references/api-fallback.md +44 -0
- package/stacks/modeling-kit/templates/.claude/skills/timeline/SKILL.md +19 -88
- package/stacks/modeling-kit/templates/.claude/skills/timeline/references/api-fallback.md +91 -0
- package/stacks/modeling-kit/templates/.claude/skills/update-prompt-status/SKILL.md +1 -9
- package/stacks/modeling-kit/templates/.claude/skills/update-prompt-status/references/api-fallback.md +14 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-integrating-legacy-systems/SKILL.md +0 -674
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-optimizing-stream-design/references/snapshotting.md +0 -204
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# Translating External Events — Worked Examples
|
|
2
|
+
|
|
3
|
+
These are conceptual worked examples of the translation reasoning this skill applies — useful for understanding the reasoning, but the actual mechanics are the numbered Workflow steps in the main SKILL.md.
|
|
4
|
+
|
|
5
|
+
## 1. Identify External Event Sources
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
External System: Payment Gateway (Stripe)
|
|
9
|
+
|
|
10
|
+
Events received:
|
|
11
|
+
- charge.succeeded
|
|
12
|
+
- charge.failed
|
|
13
|
+
- charge.refunded
|
|
14
|
+
- charge.dispute.created
|
|
15
|
+
|
|
16
|
+
Example payload: charge.succeeded
|
|
17
|
+
{
|
|
18
|
+
"id": "ch_1234567890",
|
|
19
|
+
"amount": 15000,
|
|
20
|
+
"currency": "usd",
|
|
21
|
+
"customer": "cus_9876543210",
|
|
22
|
+
"status": "succeeded",
|
|
23
|
+
"created": 1640995200
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
External System: GPS Location Service (Google Maps)
|
|
27
|
+
|
|
28
|
+
Events received:
|
|
29
|
+
- location_update
|
|
30
|
+
- geofence_enter
|
|
31
|
+
- geofence_exit
|
|
32
|
+
|
|
33
|
+
Example payload: geofence_exit
|
|
34
|
+
{
|
|
35
|
+
"userId": "user-123",
|
|
36
|
+
"geoFenceId": "hotel-front-entrance",
|
|
37
|
+
"timestamp": 1640995200,
|
|
38
|
+
"latitude": 40.7128,
|
|
39
|
+
"longitude": -74.0060
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 2. Analyze Technical Representation
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
External Event: charge.succeeded (Stripe)
|
|
47
|
+
|
|
48
|
+
Technical fields:
|
|
49
|
+
- id: UUID of charge in Stripe (not meaningful to us)
|
|
50
|
+
- amount: Integer cents (15000 = $150.00)
|
|
51
|
+
- currency: ISO code ("usd")
|
|
52
|
+
- customer: Stripe customer ID (not our customer ID)
|
|
53
|
+
- status: String indicating success
|
|
54
|
+
- created: Unix timestamp
|
|
55
|
+
|
|
56
|
+
Problems with using directly:
|
|
57
|
+
We don't use Stripe customer IDs (we have our own customer IDs)
|
|
58
|
+
Currency and amount require interpretation
|
|
59
|
+
Status is one field in their model, we care about the fact it succeeded
|
|
60
|
+
Stripe charge ID isn't the same as our order ID
|
|
61
|
+
We need to correlate back to our Order stream
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 3. Define Domain Translation Rules
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Translation: External charge.succeeded → Domain PaymentAuthorized
|
|
68
|
+
|
|
69
|
+
Mapping rules:
|
|
70
|
+
charge.id (Stripe) → paymentGatewayRef (store for reconciliation, don't use as primary)
|
|
71
|
+
charge.customer (Stripe) → Look up: Which of OUR customers has this Stripe ID?
|
|
72
|
+
charge.amount → paymentAmount (convert from cents)
|
|
73
|
+
charge.currency → paymentCurrency
|
|
74
|
+
created → timestamp
|
|
75
|
+
[NEED TO FIND] → orderId (Stripe doesn't tell us! This is critical—how do we know which order?)
|
|
76
|
+
|
|
77
|
+
Problem identified:
|
|
78
|
+
Stripe webhook comes with charge details but NOT our order ID.
|
|
79
|
+
|
|
80
|
+
Solutions:
|
|
81
|
+
A. Store Stripe charge ID in our Order when we initiate payment
|
|
82
|
+
When webhook arrives: charge.id → Look up in OrderPaymentReference
|
|
83
|
+
Find orderId → Create PaymentAuthorized event
|
|
84
|
+
|
|
85
|
+
B. Store custom metadata in Stripe charge
|
|
86
|
+
When creating charge: Include our orderId in metadata
|
|
87
|
+
When webhook arrives: Extract orderId from metadata
|
|
88
|
+
|
|
89
|
+
Choose A or B based on Stripe integration approach.
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 4. Handle Correlation
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
Pattern: Correlation via Reference Tracking
|
|
96
|
+
|
|
97
|
+
Our system flow:
|
|
98
|
+
1. Order created in our system: order-123
|
|
99
|
+
2. We initiate payment with Stripe:
|
|
100
|
+
- Send amount, customer info
|
|
101
|
+
- Receive charge ID: ch_1234567890
|
|
102
|
+
- Store reference: OrderPaymentReference { orderId: order-123, stripeChargeId: ch_1234567890 }
|
|
103
|
+
|
|
104
|
+
When webhook arrives:
|
|
105
|
+
1. Webhook: charge.succeeded { id: ch_1234567890, amount: 15000, ... }
|
|
106
|
+
2. Look up: Find OrderPaymentReference where stripeChargeId = ch_1234567890
|
|
107
|
+
3. Get orderId from reference
|
|
108
|
+
4. Create PaymentAuthorized event: { orderId: order-123, amount: 150.00, ... }
|
|
109
|
+
|
|
110
|
+
Key insight: You must create the correlation bridge when initiating external action.
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 5. Define Translation Scenarios
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
External Event: charge.succeeded
|
|
117
|
+
Trigger: Stripe webhook arrives with charge details
|
|
118
|
+
Precondition: OrderPaymentReference exists for this charge ID
|
|
119
|
+
Translation logic:
|
|
120
|
+
1. Extract charge.id from webhook
|
|
121
|
+
2. Look up OrderPaymentReference.orderId
|
|
122
|
+
3. Validate order exists and is in Confirmed state
|
|
123
|
+
4. Create domain event: PaymentAuthorized { orderId, amount, timestamp, ... }
|
|
124
|
+
Success: Domain event produced
|
|
125
|
+
Failure scenarios:
|
|
126
|
+
- Charge ID not found in references → Log error, don't produce event (manual review)
|
|
127
|
+
- Order not in Confirmed state → Log error, don't produce event
|
|
128
|
+
- Duplicate webhook → Idempotent handling (check if event already exists)
|
|
129
|
+
|
|
130
|
+
--- External Event: geofence_exit
|
|
131
|
+
Trigger: Guest leaves hotel area (GPS geofence)
|
|
132
|
+
Precondition: Guest has opted in to location tracking
|
|
133
|
+
Translation logic:
|
|
134
|
+
1. Extract userId and geoFenceId from webhook
|
|
135
|
+
2. Validate guest is currently in hotel
|
|
136
|
+
3. Check geofence_exit is "hotel-front-entrance" (not just any geofence)
|
|
137
|
+
4. Create domain event: GuestLeftHotel { guestId: userId, timestamp, ... }
|
|
138
|
+
Success: Domain event produced
|
|
139
|
+
Failure scenarios:
|
|
140
|
+
- Guest hasn't opted in → Don't produce event (respect privacy)
|
|
141
|
+
- Guest not checked in → Don't produce event (shouldn't be in geofence)
|
|
142
|
+
- Unknown geofence → Log error, don't produce event
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## 6. Handle Duplicates and Ordering
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Problem: Stripe retries charge.succeeded webhook
|
|
149
|
+
Webhook 1: charge.succeeded { id: ch_123 } → Arrives at 10:00 AM
|
|
150
|
+
Webhook 2: charge.succeeded { id: ch_123 } → Arrives at 10:05 AM (retry)
|
|
151
|
+
|
|
152
|
+
Solution: Idempotent translation
|
|
153
|
+
|
|
154
|
+
Check before creating event:
|
|
155
|
+
1. Extract external ID: ch_123
|
|
156
|
+
2. Query: Does PaymentAuthorized event exist with paymentGatewayRef = ch_123?
|
|
157
|
+
3. If yes: Do nothing (already processed)
|
|
158
|
+
4. If no: Create event
|
|
159
|
+
|
|
160
|
+
This requires storing the external ID in the event:
|
|
161
|
+
PaymentAuthorized event {
|
|
162
|
+
orderId: order-123,
|
|
163
|
+
amount: 150.00,
|
|
164
|
+
paymentGatewayRef: ch_123, ← Store external ID for deduplication
|
|
165
|
+
...
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## 7. Handle Partial or Missing Information
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
External Event: geofence_exit
|
|
173
|
+
|
|
174
|
+
Available data:
|
|
175
|
+
- userId
|
|
176
|
+
- geoFenceId
|
|
177
|
+
- timestamp
|
|
178
|
+
- latitude, longitude (raw GPS)
|
|
179
|
+
|
|
180
|
+
Missing data:
|
|
181
|
+
- Guest name (not in webhook payload)
|
|
182
|
+
- Reason for leaving (not tracked)
|
|
183
|
+
- Expected return time (not available)
|
|
184
|
+
|
|
185
|
+
Handling strategy:
|
|
186
|
+
A. Translation enriches from our system:
|
|
187
|
+
Domain event: GuestLeftHotel {
|
|
188
|
+
guestId: userId, ← From webhook
|
|
189
|
+
timestamp: ..., ← From webhook
|
|
190
|
+
guestName: "John Smith", ← Looked up from guest stream
|
|
191
|
+
roomNumber: "502", ← Looked up from guest stream
|
|
192
|
+
geoFenceId: "front-entrance" ← From webhook
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
B. Some data we don't need:
|
|
196
|
+
We ignore: latitude, longitude (we just care that guest left)
|
|
197
|
+
|
|
198
|
+
C. Some data we can infer:
|
|
199
|
+
We can assume: Guest is now outside hotel
|
|
200
|
+
Cleaning crew can visit room
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Legacy markdown structure (superseded — kept for reference only)
|
|
204
|
+
|
|
205
|
+
Older versions of this skill wrote the translation analysis as a standalone markdown document. The actual output mechanism today is placing each translated domain event on the board (see "Output Format" in the main SKILL.md) — this template is kept only so the shape of the information (what a complete translation write-up covers) stays documented somewhere.
|
|
206
|
+
|
|
207
|
+
````markdown
|
|
208
|
+
# External Event Translation: [Domain Name]
|
|
209
|
+
|
|
210
|
+
## External Systems & Events
|
|
211
|
+
|
|
212
|
+
### System: [External System Name]
|
|
213
|
+
|
|
214
|
+
**Connection Type**: [Webhook/API polling/WebSocket/Streaming]
|
|
215
|
+
|
|
216
|
+
**Events Received**:
|
|
217
|
+
- event1_name
|
|
218
|
+
- event2_name
|
|
219
|
+
- event3_name
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Translation Rules
|
|
224
|
+
|
|
225
|
+
### External Event: [Event Name]
|
|
226
|
+
|
|
227
|
+
**Source System**: [System name]
|
|
228
|
+
|
|
229
|
+
**Technical Representation**:
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"field1": "value",
|
|
233
|
+
"field2": "value"
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Domain Translation**:
|
|
238
|
+
| External Field | Our Field | Mapping | Notes |
|
|
239
|
+
|---|---|---|---|
|
|
240
|
+
| externalId | n/a | Stored for deduplication | Reference only |
|
|
241
|
+
| customer | [lookup] | Look up our customer ID | Must correlate |
|
|
242
|
+
|
|
243
|
+
**Correlation Method**:
|
|
244
|
+
[How do we link back to our domain entities?]
|
|
245
|
+
|
|
246
|
+
**Domain Event Produced**:
|
|
247
|
+
- Event Name: [EventName]
|
|
248
|
+
- Fields: [List with sources]
|
|
249
|
+
|
|
250
|
+
**Translation Logic**:
|
|
251
|
+
```
|
|
252
|
+
1. Extract from webhook
|
|
253
|
+
2. Validate preconditions
|
|
254
|
+
3. Enrich from our system
|
|
255
|
+
4. Create domain event
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Success Scenario**:
|
|
259
|
+
[What success looks like]
|
|
260
|
+
|
|
261
|
+
**Failure Scenarios**:
|
|
262
|
+
- Scenario 1: Consequence
|
|
263
|
+
- Scenario 2: Consequence
|
|
264
|
+
|
|
265
|
+
**Duplicate Handling**: [Idempotent strategy]
|
|
266
|
+
|
|
267
|
+
--- [Repeat for each external event]
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Correlation Reference
|
|
272
|
+
|
|
273
|
+
Track how external IDs map to our domain:
|
|
274
|
+
|
|
275
|
+
| Our Entity | External System | External ID Field | Storage | Lookup |
|
|
276
|
+
|---|---|---|---|---|
|
|
277
|
+
| Order | Stripe | charge.id | OrderPaymentReference | By charge ID |
|
|
278
|
+
| Guest | GPS Service | userId | Guest stream | By userId |
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Failure & Recovery
|
|
283
|
+
|
|
284
|
+
### Webhook Arrives for Non-existent Order
|
|
285
|
+
**Symptom**: Stripe sends charge.succeeded for unknown order
|
|
286
|
+
**Cause**: Race condition or data inconsistency
|
|
287
|
+
**Detection**: OrderPaymentReference lookup returns nothing
|
|
288
|
+
**Recovery**: Log error, queue for manual review
|
|
289
|
+
|
|
290
|
+
### Duplicate Webhooks
|
|
291
|
+
**Symptom**: Same webhook received multiple times
|
|
292
|
+
**Cause**: Stripe retry mechanism or network duplication
|
|
293
|
+
**Detection**: Domain event already exists with same externalRef
|
|
294
|
+
**Recovery**: Idempotent check prevents duplicate event creation
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Testing Recommendations
|
|
299
|
+
|
|
300
|
+
- [ ] Test happy path: External event → Correct domain event
|
|
301
|
+
- [ ] Test missing correlation: External event arrives before our order created
|
|
302
|
+
- [ ] Test duplicate: Same webhook processed twice
|
|
303
|
+
- [ ] Test invalid data: Webhook with missing required fields
|
|
304
|
+
- [ ] Test partial data: Webhook with some fields missing
|
|
305
|
+
- [ ] Test ordering: Multiple webhooks arrive out of order
|
|
306
|
+
````
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-validating-event-models/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: eventmodeling-validating-event-models
|
|
3
|
-
description: "Step 9 of Event Modeling - Validate
|
|
3
|
+
description: "Step 9 of Event Modeling - Validate the model for completeness and consistency. Ensures events are immutable facts, read models are deterministic projections, and commands are traceable decisions. Identifies gaps before the model is declared done. Use when reviewing a model before it's considered final. Do not use for: the structured 12-check checklist (use eventmodeling-validating-event-models-checklist) or field-level completeness verification (use eventmodeling-checking-completeness)."
|
|
4
4
|
allowed-tools:
|
|
5
5
|
- Write
|
|
6
6
|
- Bash
|
|
@@ -10,6 +10,8 @@ allowed-tools:
|
|
|
10
10
|
|
|
11
11
|
> **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until it has completed. Consult `learn-eventmodelers-api` only if you need to look up a specific endpoint or field this file doesn't cover — don't load it eagerly.
|
|
12
12
|
|
|
13
|
+
This step applies the shared element rules in **`eventmodeling-core-rules`** — read it once per session if you haven't already; it defines what a COMMAND/EVENT/READMODEL/SCREEN/AUTOMATION is, how each is named, and the anti-patterns to reject, so this step doesn't restate them.
|
|
14
|
+
|
|
13
15
|
Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the curl blocks below are the fallback for sessions without MCP connected.
|
|
14
16
|
|
|
15
17
|
For validation you treat the Event Model as read only. The only thing you are allowed to change is comments.
|
|
@@ -33,32 +35,34 @@ mcp__eventmodelers__get_nodes { "boardId": "$BOARD_ID", "type": "COMMAND" }
|
|
|
33
35
|
mcp__eventmodelers__get_nodes { "boardId": "$BOARD_ID", "type": "READMODEL" }
|
|
34
36
|
```
|
|
35
37
|
|
|
36
|
-
**Fallback (no MCP):**
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
40
|
-
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=EVENT"
|
|
41
|
-
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
42
|
-
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=COMMAND"
|
|
43
|
-
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
44
|
-
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=READMODEL"
|
|
45
|
-
```
|
|
38
|
+
**Fallback (no MCP):** see `references/api-fallback.md` — "Board Context".
|
|
46
39
|
|
|
47
40
|
After validation, use the `handle-comment` skill to post findings on the relevant nodes — `TASK` for critical violations that must be fixed, `QUESTION` for warnings and recommendations. (That skill already handles the `add_comment` MCP-vs-curl choice internally — no separate rewrite needed here.)
|
|
48
41
|
|
|
49
42
|
## Purpose
|
|
50
|
-
|
|
43
|
+
|
|
44
|
+
Ensures the event model is complete, correct, and internally consistent.
|
|
51
45
|
|
|
52
46
|
## Workflow
|
|
53
47
|
|
|
54
48
|
When given an event model, perform comprehensive validation:
|
|
55
49
|
|
|
56
|
-
###
|
|
50
|
+
### 0. Automated structural pass — run `validate_model` first
|
|
51
|
+
|
|
52
|
+
Before the manual checks below, run the server-side checklist once per chapter:
|
|
57
53
|
|
|
58
|
-
|
|
54
|
+
```
|
|
55
|
+
mcp__eventmodelers__validate_model { "boardId": "$BOARD_ID", "chapterId": "<chapterId>" }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
It returns a compact `findings` list (no node dumps) covering: unplaced nodes, backward arrows among the forward-only pairs (with the todo-list `EVENT → READMODEL` exception already applied), COMMANDs with zero or multiple issuers, READMODELs with no inbound EVENT, columns with more than one screen, and COMMAND/READMODEL columns with no SCENARIO. This replaces the per-type `get_nodes` scans and the `get_node` `projection: "edges"` spot-checks those manual checks would otherwise need — start from its `findings`, then use the sections below for the semantic checks it can't make (naming, immutability, field-source traceability, scenario coverage depth). A `verdict` of `PASS` on `validate_model` is necessary but not sufficient — still do the semantic pass.
|
|
59
|
+
|
|
60
|
+
### 1. Entity/Timeline Completeness Check
|
|
61
|
+
|
|
62
|
+
Verify each entity's timeline has:
|
|
59
63
|
- Clear name (identity)
|
|
60
64
|
- At least one event type
|
|
61
|
-
-
|
|
65
|
+
- An initial event (what starts the entity's story)
|
|
62
66
|
- State transitions documented
|
|
63
67
|
|
|
64
68
|
**For each event:**
|
|
@@ -67,142 +71,115 @@ Verify each swimlane has:
|
|
|
67
71
|
- All data is **immutable**
|
|
68
72
|
- Unique semantics (no duplicates)
|
|
69
73
|
|
|
70
|
-
**For each
|
|
71
|
-
- Can be deterministically
|
|
72
|
-
-
|
|
74
|
+
**For each read model:**
|
|
75
|
+
- Can be deterministically derived from events
|
|
76
|
+
- No side effects in how it's built
|
|
73
77
|
|
|
74
78
|
**For each command:**
|
|
75
79
|
- Clear input parameters
|
|
76
|
-
-
|
|
80
|
+
- Preconditions defined in scenarios
|
|
77
81
|
- Resulting events specified (or rejection reason)
|
|
78
|
-
- Pure logic (no side effects except event appending)
|
|
79
82
|
|
|
80
83
|
### 2. Consistency Checks
|
|
81
84
|
|
|
82
|
-
- [ ] **Event-
|
|
85
|
+
- [ ] **Event-Entity Mapping**: Every event belongs to exactly one lane/entity
|
|
83
86
|
- [ ] **Single Command Issuer**: Every command is issued by exactly one SCREEN or AUTOMATION — never two. Check each COMMAND node's inbound edges; more than one SCREEN/AUTOMATION wired into the same command is a CRITICAL violation (commonly an auto-connect artifact — see `place-element` Step 7c)
|
|
84
|
-
- [ ] **Command Outcomes**: Every command produces events OR documents rejection
|
|
85
|
-
- [ ] **Deterministic
|
|
86
|
-
- [ ] **No Side Effects in Projections**: Pure state reconstruction logic
|
|
87
|
+
- [ ] **Command Outcomes**: Every command produces events OR documents a rejection
|
|
88
|
+
- [ ] **Deterministic Read Models**: A read model can only be derived one way from its events
|
|
87
89
|
- [ ] **Event Immutability**: No event data is ever modified
|
|
88
90
|
- [ ] **Naming Consistency**: Are naming patterns consistent?
|
|
89
|
-
- Commands:
|
|
90
|
-
- Events:
|
|
91
|
-
|
|
92
|
-
### 3. Event Sourcing Principles Compliance
|
|
91
|
+
- Commands: present-tense verb (CreateOrder, ConfirmPayment)
|
|
92
|
+
- Events: past-tense verb (OrderCreated, PaymentConfirmed)
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
### 3. Event Modeling Principles Compliance
|
|
95
95
|
|
|
96
|
-
- [ ] **Events are Facts**:
|
|
96
|
+
- [ ] **Events are Facts**: describe what happened, not potential futures
|
|
97
97
|
- "OrderMayBeConfirmed" → "OrderConfirmed"
|
|
98
|
-
- "PaymentPending" (
|
|
98
|
+
- "PaymentPending" (as an event) → "PaymentInitiated", "PaymentAuthorized"
|
|
99
99
|
|
|
100
|
-
- [ ] **Events are Immutable**:
|
|
100
|
+
- [ ] **Events are Immutable**: no modification of event data
|
|
101
101
|
- "Update OrderCreated event with new total" → "Append OrderTotalCorrected event"
|
|
102
102
|
|
|
103
|
-
- [ ] **Complete Event Data**:
|
|
104
|
-
- Event
|
|
103
|
+
- [ ] **Complete Event Data**: events contain all facts a read model needs to project them
|
|
104
|
+
- Event "OrderConfirmed" missing paymentId → Event includes paymentId
|
|
105
105
|
|
|
106
|
-
- [ ] **No Computed Fields in Events**:
|
|
107
|
-
- OrderCreated includes "totalTax" (computed) → Includes items + amounts
|
|
106
|
+
- [ ] **No Computed Fields in Events**: only raw captured facts
|
|
107
|
+
- OrderCreated includes "totalTax" (computed) → Includes items + amounts; tax computed in the read model
|
|
108
108
|
|
|
109
|
-
- [ ] **Deterministic
|
|
110
|
-
- Projection uses: for each event, do X
|
|
111
|
-
- Projection uses: external API call during replay
|
|
112
|
-
|
|
113
|
-
- [ ] **State is Derived**: Current state always comes from replaying events
|
|
114
|
-
- "Load state: replay all events for Order:123"
|
|
115
|
-
- "Load state: query database Orders table"
|
|
109
|
+
- [ ] **Deterministic Read Models**: replaying the same events always produces the same read model
|
|
116
110
|
|
|
117
111
|
### 4. Event Flow Validation
|
|
118
112
|
|
|
119
|
-
- [ ] **Command → Event Mapping**:
|
|
120
|
-
- [ ] **No Zombie Commands**:
|
|
113
|
+
- [ ] **Command → Event Mapping**: clear what each command produces
|
|
114
|
+
- [ ] **No Zombie Commands**: commands that never produce events (read-only commands are fine if documented as such)
|
|
121
115
|
|
|
122
116
|
### 5. Role & Actor Attribution Validation
|
|
123
117
|
|
|
124
118
|
Verify that every command has explicit actor attribution from the Role Catalog:
|
|
125
119
|
|
|
126
|
-
- [ ] **Role Catalog exists**:
|
|
127
|
-
- CRITICAL:
|
|
120
|
+
- [ ] **Role Catalog exists**: a Role Catalog was defined in Step 1 (eventmodeling-brainstorming-events)
|
|
121
|
+
- CRITICAL: no Role Catalog found — commands have no actor attribution
|
|
128
122
|
- PASS: Role Catalog with human roles and system actors defined
|
|
129
123
|
|
|
130
|
-
- [ ] **Every command has actor attribution**:
|
|
124
|
+
- [ ] **Every command has actor attribution**: no command uses generic "User"
|
|
131
125
|
- CRITICAL: `CreateOrder` attributed to "User" (which user? Customer? Admin? Seller?)
|
|
132
126
|
- PASS: `CreateOrder` attributed to "Customer" (specific role from catalog)
|
|
133
127
|
|
|
134
|
-
### 6. Command
|
|
135
|
-
|
|
136
|
-
**This is the PRIMARY validation gate. Violations are CRITICAL and must be fixed before approval.** Validate that **command state read models** are **minimal and command-specific**, not bundled like DDD aggregates.
|
|
137
|
-
|
|
138
|
-
### 7. Command & State Validation
|
|
128
|
+
### 6. Command Validation
|
|
139
129
|
|
|
140
|
-
- [ ] **
|
|
141
|
-
-
|
|
130
|
+
- [ ] **Preconditions Clear**: when can each command execute?
|
|
131
|
+
- "Can only confirm if state is Draft"
|
|
132
|
+
- "Can sometimes confirm"
|
|
133
|
+
- [ ] **Rejection Handling**: what happens if a precondition fails?
|
|
134
|
+
- "Reject, no events appended"
|
|
135
|
+
- "Append a rejection/failure event and continue" (if that's the modeled outcome)
|
|
136
|
+
- [ ] **Valid State Transitions**: document what state changes are allowed
|
|
142
137
|
```text
|
|
143
138
|
Draft → Confirmed (ConfirmOrder)
|
|
144
139
|
Draft → Cancelled (CancelOrder)
|
|
145
140
|
Confirmed → Shipped (ShipOrder)
|
|
146
141
|
Confirmed ↛ Draft (invalid)
|
|
147
142
|
```
|
|
148
|
-
- [ ] **Preconditions Clear**: When can each command execute?
|
|
149
|
-
- "Can only confirm if state is Draft"
|
|
150
|
-
- "Can sometimes confirm"
|
|
151
|
-
- [ ] **Error Handling**: What happens if validation fails?
|
|
152
|
-
- "Reject with ValidationError, no events appended"
|
|
153
|
-
- "Append ErrorEvent and continue"
|
|
154
143
|
|
|
155
|
-
###
|
|
144
|
+
### 7. Read Model Validation
|
|
156
145
|
|
|
157
|
-
- [ ] **Read Models**:
|
|
158
|
-
- [ ] **Read Models Optional**:
|
|
159
|
-
- [ ] **Regenerable**:
|
|
146
|
+
- [ ] **Read Models**: are rich projections shaped for their query
|
|
147
|
+
- [ ] **Read Models Optional**: are they needed, or just convenience?
|
|
148
|
+
- [ ] **Regenerable**: could be rebuilt from events at any time
|
|
160
149
|
|
|
161
|
-
###
|
|
150
|
+
### 8. Issues & Recommendations Report
|
|
162
151
|
|
|
163
152
|
Format findings as comments:
|
|
164
153
|
|
|
165
154
|
```markdown
|
|
166
|
-
|
|
167
155
|
## Validation Summary
|
|
168
156
|
|
|
169
157
|
**Overall Status**: Ready with recommendations
|
|
170
158
|
|
|
171
|
-
**Blockers
|
|
159
|
+
**Blockers**: 0 critical issues
|
|
172
160
|
|
|
173
161
|
**Recommended Fixes**:
|
|
174
162
|
1. Add missing OrderCancelled event
|
|
175
|
-
2.
|
|
176
|
-
3. Document all implicit invariants explicitly
|
|
177
|
-
|
|
178
|
-
**Ready for Code Generation**: Yes, after implementing recommendations
|
|
163
|
+
2. Document all implicit preconditions explicitly
|
|
179
164
|
|
|
180
165
|
## Next Steps
|
|
181
166
|
1. Review recommendations with domain expert
|
|
182
167
|
2. Update model with critical fixes
|
|
183
|
-
3. Proceed to code generation
|
|
184
168
|
```
|
|
185
169
|
|
|
186
170
|
## Common Issues to Flag
|
|
187
171
|
|
|
188
172
|
| Issue | Pattern | Fix |
|
|
189
173
|
|-------|---------|-----|
|
|
190
|
-
| Missing cancellation flows | No "Cancelled" events | Add
|
|
191
|
-
| Implicit
|
|
192
|
-
|
|
|
193
|
-
|
|
|
194
|
-
| No read models | Commands reading query/read models for validation | Add separate query read models; keep command state minimal |
|
|
195
|
-
| Circular dependencies | Projection A depends on B, B on A | Redesign stream boundaries |
|
|
174
|
+
| Missing cancellation flows | No "Cancelled" events | Add the missing outcome slices |
|
|
175
|
+
| Implicit preconditions | "Obviously can't do X" | Make preconditions explicit |
|
|
176
|
+
| Orphaned events | Events no one reads | Link to a read model or command |
|
|
177
|
+
| No read models | Commands validated against raw event replay with no documented read model | Add a read model documenting what the command actually reads |
|
|
196
178
|
| Command issued by multiple things | COMMAND node has 2+ inbound SCREEN/AUTOMATION edges | Keep the deliberate same-column issuer, remove the rest via `set_connection` (`action: "remove"`) — see `place-element` Step 7c |
|
|
197
179
|
|
|
198
|
-
## Key Principles
|
|
180
|
+
## Key Principles
|
|
199
181
|
|
|
200
|
-
|
|
201
|
-
2. **Immutable event log**: Events never change, only appended
|
|
202
|
-
3. **State is a projection**: Current state is built by replaying events
|
|
203
|
-
4. **Commands are pure decisions**: Validate against state, produce events or reject
|
|
204
|
-
5. **Projections are optional**: Can be rebuilt at any time
|
|
205
|
-
6. **Stream per entity**: Each entity has one append-only event stream
|
|
182
|
+
See `eventmodeling-core-rules` for the element definitions this validation checks against (events as immutable facts, read models as optional projections, commands as decisions against documented preconditions).
|
|
206
183
|
|
|
207
184
|
## Success Criteria
|
|
208
185
|
|
|
@@ -210,39 +187,24 @@ Your event model validation is successful when:
|
|
|
210
187
|
|
|
211
188
|
- All requirements are captured in events
|
|
212
189
|
- Commands clearly trigger events
|
|
213
|
-
-
|
|
214
|
-
-
|
|
215
|
-
- Read models serve actual query needs (not used by commands)
|
|
216
|
-
- Command state is minimal and command-specific (not shared across multiple commands)
|
|
190
|
+
- Business rules are explicit preconditions (not hidden assumptions)
|
|
191
|
+
- Read models serve actual query needs
|
|
217
192
|
- Events are immutable facts (past tense, no computed fields)
|
|
218
|
-
- State can be deterministically rebuilt from events
|
|
219
193
|
- All command-to-event mappings are documented
|
|
220
194
|
- Critical issues are resolved or documented as known limitations
|
|
221
|
-
|
|
222
|
-
A model is **ready for code generation** if:
|
|
223
|
-
- No critical issues remain
|
|
224
|
-
- All command state follows naming convention (e.g., `[CommandName]State`)
|
|
225
|
-
- No state is shared between different commands
|
|
226
|
-
- All events are immutable facts
|
|
227
|
-
- All business rules are explicit
|
|
228
|
-
- A Role Catalog exists with all human roles and system actors
|
|
229
|
-
- Every command has explicit actor attribution from the Role Catalog
|
|
195
|
+
- A Role Catalog exists with all human roles and system actors, and every command has explicit actor attribution
|
|
230
196
|
|
|
231
197
|
## Quality Checklist
|
|
232
198
|
|
|
233
199
|
- [ ] All events are immutable facts (past tense)
|
|
234
200
|
- [ ] No computed fields stored in events
|
|
235
|
-
- [ ]
|
|
236
|
-
- [ ] Commands
|
|
201
|
+
- [ ] Read models are derived deterministically from events
|
|
202
|
+
- [ ] Commands are checked against documented preconditions
|
|
237
203
|
- [ ] Each command either produces events or rejects (no silent failures)
|
|
238
204
|
- [ ] **No command has more than one inbound SCREEN/AUTOMATION edge (a command is never issued by more than one thing)**
|
|
239
205
|
- [ ] Event causality/command-event mapping is clear
|
|
240
206
|
- [ ] State transitions are documented
|
|
241
|
-
- [ ]
|
|
242
|
-
- [ ] Projections serve specific query needs (or are removed)
|
|
243
|
-
- [ ] Everything can be rebuilt from the event stream
|
|
244
|
-
- [ ] No state is shared between different commands
|
|
245
|
-
- [ ] All command state is minimal (only fields needed for validation)
|
|
207
|
+
- [ ] Read models serve specific query needs (or are removed)
|
|
246
208
|
- [ ] **Role Catalog exists with human roles and system actors**
|
|
247
209
|
- [ ] **Every command attributed to a specific role/actor (no generic "User")**
|
|
248
210
|
- [ ] **Every human role has at least one command and one read model**
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Validating Event Models — curl Fallback Calls
|
|
2
|
+
|
|
3
|
+
Only needed when MCP is not connected. Every call below has an MCP equivalent in the main SKILL.md — always prefer that.
|
|
4
|
+
|
|
5
|
+
## Board Context
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
9
|
+
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=EVENT"
|
|
10
|
+
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
11
|
+
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=COMMAND"
|
|
12
|
+
curl -s -H "x-token: $TOKEN" -H "x-board-id: $BOARD_ID" \
|
|
13
|
+
"$BASE_URL/api/org/$ORG_ID/boards/$BOARD_ID/nodes?type=READMODEL"
|
|
14
|
+
```
|