@eventmodelers/cli 1.0.150 → 1.0.151
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 +8 -0
- package/stacks/axon/templates/.claude/skills/build-automation/SKILL.md +2 -0
- package/stacks/axon/templates/.claude/skills/build-state-change/SKILL.md +2 -0
- package/stacks/axon/templates/.claude/skills/build-state-view/SKILL.md +2 -0
- package/stacks/classic/templates/.claude/skills/build-automation/SKILL.md +2 -0
- package/stacks/classic/templates/.claude/skills/build-state-change/SKILL.md +2 -0
- package/stacks/classic/templates/.claude/skills/build-state-view/SKILL.md +2 -0
- package/stacks/kurrent/templates/.claude/skills/build-automation/SKILL.md +2 -0
- package/stacks/kurrent/templates/.claude/skills/build-state-change/SKILL.md +2 -0
- package/stacks/kurrent/templates/.claude/skills/build-state-view/SKILL.md +2 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +18 -0
- package/stacks/node/templates/.claude/skills/build-automation/SKILL.md +2 -0
- package/stacks/node/templates/.claude/skills/build-state-change/SKILL.md +2 -0
- package/stacks/node/templates/.claude/skills/build-state-view/SKILL.md +2 -0
- package/stacks/opencqrs/templates/.claude/skills/build-automation/SKILL.md +2 -0
- package/stacks/opencqrs/templates/.claude/skills/build-state-change/SKILL.md +2 -0
- package/stacks/opencqrs/templates/.claude/skills/build-state-view/SKILL.md +2 -0
- package/stacks/supabase/templates/.claude/skills/build-state-change/SKILL.md +2 -0
- package/stacks/supabase/templates/.claude/skills/build-state-view/SKILL.md +2 -0
- package/stacks/umadb/templates/.claude/skills/build-automation/SKILL.md +2 -0
- package/stacks/umadb/templates/.claude/skills/build-state-change/SKILL.md +2 -0
- package/stacks/umadb/templates/.claude/skills/build-state-view/SKILL.md +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventmodelers/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.151",
|
|
4
4
|
"description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, OpenCQRS, UmaDB, Kurrent, or modeling-only)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -696,6 +696,8 @@ Append Given-When-Then scenario(s) to a column's spec node — the node is creat
|
|
|
696
696
|
title: string
|
|
697
697
|
vertical?: boolean
|
|
698
698
|
examples?: unknown[]
|
|
699
|
+
context?: SpecStep[] // READMODELs the command decides against
|
|
700
|
+
contextNote?: string // markdown background — ONLY what events, commands and read models can't express
|
|
699
701
|
given?: SpecStep[] // EVENTs from this timeline
|
|
700
702
|
when?: SpecStep[] // at most one COMMAND, or one inline QUERY object; empty if then has a READMODEL
|
|
701
703
|
then?: SpecStep[] // EVENTs only OR exactly one READMODEL (not mixed)
|
|
@@ -711,6 +713,7 @@ A step given as `{title, type}` is resolved server-side, so the names you alread
|
|
|
711
713
|
|
|
712
714
|
**Validation rules**:
|
|
713
715
|
- `context`: only READMODELs (the state the command decides against)
|
|
716
|
+
- `contextNote`: free markdown, last resort. State belongs in `given` events (or `context` read models), inputs in the `when` command's fields, outcomes in `then` — a note never replaces or repeats any of them. Use it only for background no element can carry: an external condition ("the payment provider is in maintenance"), a business assumption, the reason a case matters. Blank notes are dropped. Exported as `contextNote` on the scenario in slice data
|
|
714
717
|
- `given`: only EVENTs from same timeline
|
|
715
718
|
- `when`: max one COMMAND; must be empty when `then` contains a READMODEL (use an inline QUERY item for a state-view)
|
|
716
719
|
- `then`: all EVENTs OR exactly one READMODEL — never mixed
|
|
@@ -765,8 +768,13 @@ Append one or more storylines to a column's spec node. The spec node is auto-cre
|
|
|
765
768
|
examples?: unknown[]
|
|
766
769
|
}>
|
|
767
770
|
}
|
|
771
|
+
|
|
772
|
+
// A note beat — free markdown anywhere in the sequence, referencing no element:
|
|
773
|
+
{ instanceId: 'uuid', refId: '', type: 'STORYLINE_NOTE', title: 'Note', note: 'markdown' }
|
|
768
774
|
```
|
|
769
775
|
|
|
776
|
+
A note beat is the storyline's `contextNote`: only for what the beats themselves can't express (an external condition, an assumption, a time gap like "two weeks later"). Never use one to stand in for an event, command or read model that should be a beat — model the element instead. It is exported as an element `{id: instanceId, type: 'STORYLINE_NOTE', description: note}`; an empty note is rejected (`STORYLINE_NOTE_EMPTY`).
|
|
777
|
+
|
|
770
778
|
A beat is addressed either way, like a scenario step:
|
|
771
779
|
```typescript
|
|
772
780
|
{ refId: 'node-uuid' } // a board node — always wins, never re-resolved
|
|
@@ -396,6 +396,8 @@ class {AutomationName}ProcessorTest {
|
|
|
396
396
|
|
|
397
397
|
### Storyline-Derived Tests (Optional)
|
|
398
398
|
|
|
399
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
400
|
+
|
|
399
401
|
`slice.json` may also carry a `storylines[]` array — narrated walkthroughs with an ordered
|
|
400
402
|
`elements[]` "beats" sequence (EVENT/COMMAND/READMODEL/...). This is a secondary, supplementary
|
|
401
403
|
source; `specifications[]` above stays the primary and default source of test cases. Most slices
|
|
@@ -405,6 +405,8 @@ see [references/axon-test-fixture-patterns.md](references/axon-test-fixture-patt
|
|
|
405
405
|
|
|
406
406
|
## Step 7b: Storyline-Derived Tests (Optional)
|
|
407
407
|
|
|
408
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
409
|
+
|
|
408
410
|
`slice.json` may carry a `storylines[]` array alongside `specifications[]` — narrated walkthroughs
|
|
409
411
|
where an ordered sequence of `elements[]` "beats" (EVENT/COMMAND/READMODEL/...) shows one use case
|
|
410
412
|
end to end. This is a secondary, supplementary source — `specifications[]` (Step 7) stays the
|
|
@@ -210,6 +210,8 @@ Do not design your own test cases unless specifically instructed to do so.
|
|
|
210
210
|
|
|
211
211
|
## Step 4b: Storyline-Derived Tests (Optional)
|
|
212
212
|
|
|
213
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
214
|
+
|
|
213
215
|
`slice.json` may also carry a `storylines[]` array — narrated walkthroughs where the *same* read
|
|
214
216
|
model appears as multiple ordered "beats" across one flow (see `elements[]` on each storyline).
|
|
215
217
|
This is a secondary, supplementary source: `specifications[]` (Step 4) remains the primary and
|
|
@@ -39,6 +39,8 @@ Follow `/build-state-change` for this slice's command and events — all of its
|
|
|
39
39
|
|
|
40
40
|
### Storyline-derived tests
|
|
41
41
|
|
|
42
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
43
|
+
|
|
42
44
|
If `storylines[]` includes a beat sequence running through this automation's trigger → this slice's command, the command test for that segment is already covered by build-state-change's own "Storyline-derived tests" step.
|
|
43
45
|
|
|
44
46
|
## Step 3 — Find the trigger point
|
|
@@ -77,6 +77,8 @@ Name each test after the specification title so it can be traced back to the boa
|
|
|
77
77
|
|
|
78
78
|
### Storyline-derived tests (optional)
|
|
79
79
|
|
|
80
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
81
|
+
|
|
80
82
|
`storylines[]` in slice.json (optional — only present when the board author built an explicit walkthrough) can supply additional tests. A storyline embedded in this slice's slice.json already belongs entirely to this slice — no need to match beats against `commands[]` by id/title. Scan each storyline's ordered `elements` for a `type: COMMAND` beat followed by its EVENT beat(s):
|
|
81
83
|
|
|
82
84
|
- `given` — the cumulative ordered events from the start of the storyline up to (not including) the command beat, set up as state as above
|
|
@@ -80,6 +80,8 @@ Name each test after the specification title.
|
|
|
80
80
|
|
|
81
81
|
### Storyline-derived tests (optional)
|
|
82
82
|
|
|
83
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
84
|
+
|
|
83
85
|
`storylines[]` in slice.json is optional — present only when the board author explicitly built a walkthrough for this flow. When present, mine it for **additional** tests, on top of (never instead of) the specification tests.
|
|
84
86
|
|
|
85
87
|
A storyline is `{ id, title, elements: [...] }`, where `elements` is an ordered list of beats — the same element can repeat to show its state at different points in the flow. A storyline embedded in this slice's slice.json already belongs entirely to this slice — no need to match beats against `readmodels[]` by id/title. Scan for a pair of adjacent beats that are both `type: READMODEL`, with only EVENT beat(s) between them and no COMMAND beat in that run. That pair is one self-contained test:
|
|
@@ -384,6 +384,8 @@ class {AutomationName}HandlingTest {
|
|
|
384
384
|
|
|
385
385
|
### Storyline-Derived Tests (Optional)
|
|
386
386
|
|
|
387
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
388
|
+
|
|
387
389
|
`slice.json` may also carry a `storylines[]` array — narrated walkthroughs with an ordered
|
|
388
390
|
`elements[]` "beats" sequence (EVENT/COMMAND/READMODEL/...). This is a secondary, supplementary
|
|
389
391
|
source; `specifications[]` above stays the primary and default source of test cases. Most slices
|
|
@@ -376,6 +376,8 @@ the same reconstruction path production uses.
|
|
|
376
376
|
|
|
377
377
|
## Step 6b: Storyline-Derived Tests (Optional)
|
|
378
378
|
|
|
379
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
380
|
+
|
|
379
381
|
`slice.json` may carry a `storylines[]` array alongside `specifications[]` — narrated walkthroughs
|
|
380
382
|
where an ordered sequence of `elements[]` "beats" (EVENT/COMMAND/READMODEL/...) shows one use case
|
|
381
383
|
end to end. This is a secondary, supplementary source — `specifications[]` (Step 7) stays the
|
|
@@ -341,6 +341,8 @@ package — which it already does, following this stack's convention (`{SliceNam
|
|
|
341
341
|
|
|
342
342
|
## Step 5b: Storyline-Derived Tests (Optional)
|
|
343
343
|
|
|
344
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
345
|
+
|
|
344
346
|
`slice.json` may also carry a `storylines[]` array — narrated walkthroughs where the *same* read
|
|
345
347
|
model appears as multiple ordered "beats" across one flow (see `elements[]` on each storyline).
|
|
346
348
|
This is a secondary, supplementary source: `specifications[]` (Step 4) remains the primary and
|
package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md
CHANGED
|
@@ -50,6 +50,21 @@ narrated lifecycle, GWT covers everything else about that read model.
|
|
|
50
50
|
A storyline threads all three beats into one walkthrough; three separate GWTs could each assert one
|
|
51
51
|
transition but not the lifecycle.
|
|
52
52
|
|
|
53
|
+
## Notes — Last Resort Only
|
|
54
|
+
|
|
55
|
+
A scenario can carry a `contextNote` (markdown), and a storyline can hold note beats
|
|
56
|
+
(`{type: "STORYLINE_NOTE", refId: "", note: "…"}`). **Notes are only for what cannot be expressed
|
|
57
|
+
with events and the other elements.** Before writing one, ask: could this be a `given` event, a
|
|
58
|
+
`context` read model, a field example on the command, or a `then` outcome? If yes, model it that
|
|
59
|
+
way — a scenario that tells its story in a note instead of in events is incomplete, and code
|
|
60
|
+
generated from it can't test what's only in prose.
|
|
61
|
+
|
|
62
|
+
Legit uses: a condition outside the system ("the payment provider is in maintenance"), a business
|
|
63
|
+
assumption or regulation behind the case, why the case matters, a time gap between storyline beats
|
|
64
|
+
("14 days later"). Not legit: "the customer has already ordered twice" (→ `given` events), "the
|
|
65
|
+
cart total is 120 €" (→ field examples), "an email is sent" (→ a `then` event), restating the
|
|
66
|
+
title. Most scenarios need no note; keep any note to a few lines.
|
|
67
|
+
|
|
53
68
|
### Storyline data shape
|
|
54
69
|
|
|
55
70
|
```json
|
|
@@ -77,6 +92,8 @@ transition but not the lifecycle.
|
|
|
77
92
|
READMODEL. Beats are only READMODEL or EVENT — no COMMAND, SCREEN or other types. Every `refId`
|
|
78
93
|
must be on the same timeline.
|
|
79
94
|
- `isError` marks a beat as an alternate/error branch off the previous beat.
|
|
95
|
+
- A note beat (`type: "STORYLINE_NOTE"`, `refId: ""`, markdown in `note`) may sit anywhere and is
|
|
96
|
+
skipped by the order rules — see "Notes — Last Resort Only" above before adding one.
|
|
80
97
|
- `fields`, `expectEmptyList`, `exampleMode`, `examples` mirror the same fields GWT scenario steps
|
|
81
98
|
use, letting a beat show concrete example data the same way a "then" readmodel step does.
|
|
82
99
|
|
|
@@ -494,6 +511,7 @@ After posting, tell the user:
|
|
|
494
511
|
**No command has only 2 scenarios unless all other types were reviewed and found inapplicable.**
|
|
495
512
|
|
|
496
513
|
**Per read model — this is a separate, equally mandatory pass, not an afterthought of the command pass above:**
|
|
514
|
+
- [ ] **Notes carry nothing an element could** — every `contextNote` and note beat holds only background no event, command field or read model can express; anything else is moved into `given`/`when`/`then`/`context` and the note removed
|
|
497
515
|
- [ ] **Every READMODEL on the board has at least one view scenario** — GWT (`given`: source EVENTs, `when`: empty, `then`: the READMODEL) or a storyline. A model with dozens of command scenarios and 0 read-model scenarios is not a complete Step 7 — it's easy to walk away thinking coverage is thorough because the command side looks exhaustive, so check the read-model side explicitly before reporting this step done.
|
|
498
516
|
- [ ] **Population scenario** — the view shows correct data after its source event(s)
|
|
499
517
|
- [ ] **Removal/update scenario, where applicable** — a row disappears or changes (`expectEmptyList: true` for list-type views) after an event that supersedes it (expiry, return, archival, withdrawal, status change, etc.). `EVENT → READMODEL` is exempt from column ordering **only when the read model already feeds an AUTOMATION** (`READMODEL → AUTOMATION` edge; see `learn-eventmodelers-api` §3 and `eventmodeling-orchestrating-event-modeling`'s "No backward arrows") — a later event connecting back to an earlier-placed todo-list read model is normal for that accumulator shape, so add the connection if it's missing rather than assuming the scenario is impossible. If the read model has no automation to feed, the backward connection is rejected — by Step 5 this should already have been modeled the forward way (see `eventmodeling-identifying-outputs` Step 5g's copy pattern: a new read model + screen copy in the later event's column, never a link back). If it wasn't, write the scenario against that forward-placed copy rather than the original. Only skip this scenario, with a documented gap (TASK comment), when the superseding event genuinely lives in a different chapter.
|
|
@@ -64,6 +64,8 @@ Refer to the build-state-change skill for the full command handler structure.
|
|
|
64
64
|
|
|
65
65
|
### Storyline-derived tests
|
|
66
66
|
|
|
67
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
68
|
+
|
|
67
69
|
If `storylines[]` includes a beat sequence running through this automation's trigger event → this slice's command, the command-handler test for that segment is already covered by build-state-change's own "Storyline-derived tests" step — it runs as part of following that skill above. This skill has no separate reactor-test format: the processor's event-to-command field mapping is exercised only indirectly, through that command-handler test, never by a dedicated `processor.test.ts`.
|
|
68
70
|
|
|
69
71
|
---
|
|
@@ -230,6 +230,8 @@ Add one test per specification in the slice.json. If the spec has no preconditio
|
|
|
230
230
|
|
|
231
231
|
### Storyline-derived tests (optional)
|
|
232
232
|
|
|
233
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
234
|
+
|
|
233
235
|
`storylines[]` in slice.json (optional — only present when the board author built an explicit walkthrough) can also supply command-handler tests, in addition to the specifications-derived ones above. A storyline embedded in this slice's slice.json already belongs entirely to this slice — no need to match beats against `commands[]` by id/title. Just scan each storyline's ordered `elements` for a `type: COMMAND` beat, followed by its emitted EVENT beat(s):
|
|
234
236
|
|
|
235
237
|
- `given` — the cumulative ordered events from the start of the storyline up to (not including) the command beat
|
|
@@ -327,6 +327,8 @@ Write one `it` block per specification in the slice.json. Use `given([events]).w
|
|
|
327
327
|
|
|
328
328
|
### Storyline-derived tests (optional)
|
|
329
329
|
|
|
330
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
331
|
+
|
|
330
332
|
`storylines[]` in slice.json is optional — present only when the board author explicitly built a walkthrough for this flow; most slices have none. When present, mine it for **additional** read-model-chain tests, on top of (never instead of) the specifications-derived tests above.
|
|
331
333
|
|
|
332
334
|
A storyline is `{ id, title, elements: [...] }`, where `elements` is an ordered list of beats — the same element can repeat to show its state at different points in the flow. A storyline embedded in this slice's slice.json already belongs entirely to this slice — no need to match beats against `readmodels[]` by id/title. Just scan for a pair of adjacent beats that are both `type: READMODEL`, with only EVENT beat(s) between them and no COMMAND beat in that run. That pair is one self-contained projection test:
|
|
@@ -394,6 +394,8 @@ class {AutomationName}ProcessorTest {
|
|
|
394
394
|
|
|
395
395
|
### Storyline-Derived Tests (Optional)
|
|
396
396
|
|
|
397
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
398
|
+
|
|
397
399
|
`slice.json` may also carry a `storylines[]` array — narrated walkthroughs with an ordered
|
|
398
400
|
`elements[]` "beats" sequence (EVENT/COMMAND/READMODEL/...). This is a secondary, supplementary
|
|
399
401
|
source; `specifications[]` above stays the primary and default source of test cases. Most slices
|
|
@@ -368,6 +368,8 @@ Full fluent-API cheat sheet: see
|
|
|
368
368
|
|
|
369
369
|
## Step 7b: Storyline-Derived Tests (Optional)
|
|
370
370
|
|
|
371
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
372
|
+
|
|
371
373
|
`slice.json` may carry a `storylines[]` array alongside `specifications[]` — narrated walkthroughs
|
|
372
374
|
where an ordered sequence of `elements[]` "beats" (EVENT/COMMAND/READMODEL/...) shows one use case
|
|
373
375
|
end to end. This is a secondary, supplementary source — `specifications[]` (Step 7) stays the
|
|
@@ -300,6 +300,8 @@ class {SliceName}ProjectorTest {
|
|
|
300
300
|
|
|
301
301
|
## Step 4b: Storyline-Derived Tests (Optional)
|
|
302
302
|
|
|
303
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
304
|
+
|
|
303
305
|
`slice.json` may also carry a `storylines[]` array — narrated walkthroughs where the *same* read
|
|
304
306
|
model appears as multiple ordered "beats" across one flow (see `elements[]` on each storyline).
|
|
305
307
|
This is a secondary, supplementary source: `specifications[]` (Step 3) remains the primary and
|
|
@@ -232,6 +232,8 @@ Add one test per specification in the slice.json. If the spec has no preconditio
|
|
|
232
232
|
|
|
233
233
|
## Step 4b — Storyline-derived tests (optional)
|
|
234
234
|
|
|
235
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
236
|
+
|
|
235
237
|
Some slices also have a `storylines[]` array in slice.json — narrated walkthroughs of one use case as an ordered sequence of beats (`elements[]`). Most slices have no storylines; skip this step silently when `storylines[]` is empty or absent.
|
|
236
238
|
|
|
237
239
|
A storyline embedded in this slice's slice.json already belongs entirely to this slice — no need to match beats against `commands[]` by id/title. For each storyline, find a `type: COMMAND` beat directly followed by its EVENT beat(s). That pair is a command-handler test — the same shape as the specifications-derived tests above:
|
|
@@ -309,6 +309,8 @@ Write one `it` block per specification in the slice.json. Use `given([events]).w
|
|
|
309
309
|
|
|
310
310
|
## Step 5b — Storyline-derived tests (optional)
|
|
311
311
|
|
|
312
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
313
|
+
|
|
312
314
|
Some slices also have a `storylines[]` array in slice.json — narrated walkthroughs where the *same* read model repeats across several beats in one ordered `elements[]` list, showing its state at different points in a single flow. Most slices have no storylines; skip this step silently when `storylines[]` is empty or absent.
|
|
313
315
|
|
|
314
316
|
A storyline embedded in this slice's slice.json already belongs entirely to this slice — no need to match beats against `readmodels[]` by id/title. For each storyline, scan `elements[]` for pairs of adjacent `type: 'READMODEL'` beats with only EVENT beat(s) in between. Each such pair is a clean, self-contained projection test — the same shape as the specifications-derived tests above:
|
|
@@ -282,6 +282,8 @@ verifyNoMoreInteractions(targetCommandHandler);
|
|
|
282
282
|
|
|
283
283
|
### Storyline-Derived Tests (Optional)
|
|
284
284
|
|
|
285
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
286
|
+
|
|
285
287
|
`slice.json` may also carry a `storylines[]` array — narrated walkthroughs with an ordered
|
|
286
288
|
`elements[]` "beats" sequence (EVENT/COMMAND/READMODEL/...). This is a secondary, supplementary
|
|
287
289
|
source; `specifications[]` above stays the primary and default source of test cases. Most slices
|
|
@@ -344,6 +344,8 @@ behaviour, why `subscribe()` isn't faked: see
|
|
|
344
344
|
|
|
345
345
|
## Step 7b: Storyline-Derived Tests (Optional)
|
|
346
346
|
|
|
347
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
348
|
+
|
|
347
349
|
`slice.json` may carry a `storylines[]` array alongside `specifications[]` — narrated walkthroughs
|
|
348
350
|
where an ordered sequence of `elements[]` "beats" (EVENT/COMMAND/READMODEL/...) shows one use case
|
|
349
351
|
end to end. This is a secondary, supplementary source — `specifications[]` (Step 7) stays the
|
|
@@ -286,6 +286,8 @@ Add a `com.h2database:h2` test-scope dependency once, project-wide, if it isn't
|
|
|
286
286
|
|
|
287
287
|
## Step 4b: Storyline-Derived Tests (Optional)
|
|
288
288
|
|
|
289
|
+
> **Note beats**: an entry with `type: STORYLINE_NOTE` is a note the board author placed in the walkthrough — its `description` is markdown context (an assumption, an external condition, a time gap), and its `id` is not a board node. Read it as background for the beats around it, but it is never a step: skip it when looking for COMMAND/EVENT/READMODEL beats or judging which beats are adjacent, and never turn it into test setup or an assertion on its own.
|
|
290
|
+
|
|
289
291
|
`slice.json` may also carry a `storylines[]` array — narrated walkthroughs where the *same* read
|
|
290
292
|
model appears as multiple ordered "beats" across one flow. This is a secondary, supplementary
|
|
291
293
|
source: `specifications[]` (Step 4) remains the primary and default source of test cases. Most
|