@milehimikey/em 1.8.0 → 1.9.0
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/.claude/skills/event-modeling/SKILL.md +58 -404
- package/.claude/skills/event-modeling-conform/SKILL.md +77 -0
- package/.claude/skills/{event-modeling → event-modeling-conform}/reference/conform.md +39 -13
- package/.claude/skills/event-modeling-design/SKILL.md +139 -0
- package/.claude/skills/event-modeling-discover/SKILL.md +89 -0
- package/.claude/skills/{event-modeling → event-modeling-discover}/reference/extract.md +3 -2
- package/.claude/skills/event-modeling-implement/SKILL.md +40 -0
- package/.claude/skills/{event-modeling → event-modeling-implement}/reference/implement.md +3 -2
- package/.claude/skills/event-modeling-review/SKILL.md +58 -0
- package/.claude/skills/{event-modeling → event-modeling-shared}/reference/em-dsl.md +128 -84
- package/.claude/skills/{event-modeling → event-modeling-shared}/reference/methodology.md +6 -5
- package/.claude/skills/event-modeling-shared/reference/operating-principles.md +147 -0
- package/.claude/skills/{event-modeling → event-modeling-shared}/templates/model-readme.md +2 -2
- package/.claude/skills/{event-modeling → event-modeling-shared}/templates/slice.md +51 -8
- package/README.md +24 -4
- package/dist/catalog/build.js +9 -0
- package/dist/catalog/build.js.map +1 -1
- package/dist/catalog/docJoin.d.ts +15 -0
- package/dist/catalog/docJoin.js +8 -0
- package/dist/catalog/docJoin.js.map +1 -1
- package/dist/catalog/modelCollisionValidate.d.ts +22 -0
- package/dist/catalog/modelCollisionValidate.js +67 -0
- package/dist/catalog/modelCollisionValidate.js.map +1 -0
- package/dist/catalog/orphanedSliceDocValidate.d.ts +11 -0
- package/dist/catalog/orphanedSliceDocValidate.js +98 -0
- package/dist/catalog/orphanedSliceDocValidate.js.map +1 -0
- package/dist/catalog/sliceDoc.d.ts +15 -0
- package/dist/catalog/sliceDoc.js +18 -0
- package/dist/catalog/sliceDoc.js.map +1 -1
- package/dist/cli/changelogBuild.d.ts +12 -0
- package/dist/cli/changelogBuild.js +89 -0
- package/dist/cli/changelogBuild.js.map +1 -0
- package/dist/cli/ciInit.d.ts +42 -0
- package/dist/cli/ciInit.js +298 -0
- package/dist/cli/ciInit.js.map +1 -0
- package/dist/cli/conformSupersede.d.ts +32 -0
- package/dist/cli/conformSupersede.js +102 -0
- package/dist/cli/conformSupersede.js.map +1 -0
- package/dist/cli/coverage.d.ts +17 -10
- package/dist/cli/coverage.js +61 -16
- package/dist/cli/coverage.js.map +1 -1
- package/dist/cli/frontmatterSurgery.d.ts +28 -0
- package/dist/cli/frontmatterSurgery.js +66 -0
- package/dist/cli/frontmatterSurgery.js.map +1 -0
- package/dist/cli/markImplemented.js +6 -45
- package/dist/cli/markImplemented.js.map +1 -1
- package/dist/cli/ratify.d.ts +41 -0
- package/dist/cli/ratify.js +151 -0
- package/dist/cli/ratify.js.map +1 -0
- package/dist/cli/reratify.d.ts +33 -0
- package/dist/cli/reratify.js +137 -0
- package/dist/cli/reratify.js.map +1 -0
- package/dist/cli/skillCheck.d.ts +6 -0
- package/dist/cli/skillCheck.js +46 -0
- package/dist/cli/skillCheck.js.map +1 -1
- package/dist/cli/skillDirs.d.ts +15 -0
- package/dist/cli/skillDirs.js +34 -0
- package/dist/cli/skillDirs.js.map +1 -0
- package/dist/cli/skillSync.d.ts +10 -0
- package/dist/cli/skillSync.js +15 -0
- package/dist/cli/skillSync.js.map +1 -1
- package/dist/cli/sliceIndex.d.ts +3 -0
- package/dist/cli/sliceIndex.js +6 -2
- package/dist/cli/sliceIndex.js.map +1 -1
- package/dist/cli/sliceLink.d.ts +52 -0
- package/dist/cli/sliceLink.js +152 -0
- package/dist/cli/sliceLink.js.map +1 -0
- package/dist/cli/status.d.ts +261 -0
- package/dist/cli/status.js +536 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/usageLog.d.ts +75 -0
- package/dist/cli/usageLog.js +193 -0
- package/dist/cli/usageLog.js.map +1 -0
- package/dist/cli.js +501 -130
- package/dist/cli.js.map +1 -1
- package/dist/emit/diffJson.d.ts +9 -1
- package/dist/emit/diffJson.js +44 -1
- package/dist/emit/diffJson.js.map +1 -1
- package/dist/emit/freshnessJson.d.ts +6 -0
- package/dist/emit/freshnessJson.js +24 -0
- package/dist/emit/freshnessJson.js.map +1 -0
- package/dist/emit/json.d.ts +67 -8
- package/dist/emit/json.js +19 -3
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/statusJson.d.ts +7 -0
- package/dist/emit/statusJson.js +39 -0
- package/dist/emit/statusJson.js.map +1 -0
- package/dist/emit/typespec.d.ts +26 -0
- package/dist/emit/typespec.js +356 -0
- package/dist/emit/typespec.js.map +1 -0
- package/dist/emit/usageReportJson.d.ts +3 -0
- package/dist/emit/usageReportJson.js +23 -0
- package/dist/emit/usageReportJson.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +301 -11
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/rules.d.ts +13 -0
- package/dist/model/rules.js +20 -0
- package/dist/model/rules.js.map +1 -1
- package/dist/model/validate.js +9 -1
- package/dist/model/validate.js.map +1 -1
- package/dist/parser/ast.d.ts +6 -0
- package/dist/parser/parser.js +20 -6
- package/dist/parser/parser.js.map +1 -1
- package/dist/render/drawNotes.d.ts +11 -1
- package/dist/render/drawNotes.js +20 -2
- package/dist/render/drawNotes.js.map +1 -1
- package/dist/render/render.js +31 -6
- package/dist/render/render.js.map +1 -1
- package/dist/render/serve.js +4 -0
- package/dist/render/serve.js.map +1 -1
- package/dist/render/sliceOverlay.d.ts +7 -2
- package/dist/render/sliceOverlay.js +19 -7
- package/dist/render/sliceOverlay.js.map +1 -1
- package/dist/render/sliceStatus.d.ts +7 -3
- package/dist/render/sliceStatus.js +21 -14
- package/dist/render/sliceStatus.js.map +1 -1
- package/dist/render/viewerHtml.js +1 -1
- package/dist/render/viewerHtml.js.map +1 -1
- package/dist/templates.d.ts +2 -2
- package/dist/templates.js +5 -5
- package/dist/util/markers.d.ts +16 -4
- package/dist/util/markers.js +23 -10
- package/dist/util/markers.js.map +1 -1
- package/package.json +2 -1
- /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/conformance-report.md +0 -0
- /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/state.md +0 -0
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
Read this **before doing any conform work**. It governs the `conform` phase: checking a
|
|
4
4
|
**ratified** model (and its slice docs) against the codebase that is supposed to implement it,
|
|
5
5
|
and reporting where they've drifted apart. Conform reuses `extract`'s sourcing/mode rules
|
|
6
|
-
(`reference/extract.md`) for reading the target codebase
|
|
6
|
+
(the `event-modeling-discover` skill's `reference/extract.md`) for reading the target codebase
|
|
7
|
+
rather than duplicating them — the
|
|
7
8
|
difference is what you do with what you find: extract *builds* a model from the code; conform
|
|
8
9
|
*compares* code evidence against a model that already exists.
|
|
9
10
|
|
|
@@ -33,7 +34,7 @@ difference is what you do with what you find: extract *builds* a model from the
|
|
|
33
34
|
## Preconditions
|
|
34
35
|
|
|
35
36
|
1. A canonical `.em` model with a state file (`.event-modeling.md`), reachable the same way the
|
|
36
|
-
|
|
37
|
+
shared preconditions locate it — see `../../event-modeling-shared/reference/operating-principles.md`.
|
|
37
38
|
2. The slices you're about to check should be **implemented** — docs at `status: implemented`
|
|
38
39
|
(or the status the user says corresponds to shipped code) for whichever slices are in scope.
|
|
39
40
|
Checking a `draft` or `ready-to-implement` slice against code is a wasted walk — ratified or
|
|
@@ -57,11 +58,19 @@ named invariants, Given/When/Then scenarios). Conform checks all three surfaces
|
|
|
57
58
|
|---|---|---|---|
|
|
58
59
|
| **Structural** — `.em` ↔ code | slices/elements/fields/flow | `em` (deterministic) | `em diff --json` on canonical vs. an as-is scratch model |
|
|
59
60
|
| **Spec** — slice doc ↔ code | field rules not enforced, named invariants (`INV-*`) without enforcement/test sites, GWT scenarios without test sites | you (judgment) | per-slice evidence walk: each checkable claim in the doc mapped to a code/test site by name (`INV-CHK-4` → its enforcement site + its test) |
|
|
60
|
-
| **Internal** — slice doc ↔ `.em` | the doc's frontmatter
|
|
61
|
-
|
|
62
|
-
The internal surface is deterministically
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
| **Internal** — slice doc ↔ `.em` | the doc's frontmatter `pattern:` or its Command/Event/Read Model sections and field tables disagreeing with the model's own elements/fields | `em` (deterministic) | `em validate`'s `doc-model-*` diagnostics, unconditionally in the default list |
|
|
62
|
+
|
|
63
|
+
The internal surface is deterministically checked by `em validate` itself (MIL-124) — four
|
|
64
|
+
diagnostics, always on, no flag needed: `doc-model-pattern-mismatch` (frontmatter `pattern:` vs.
|
|
65
|
+
the model's own classification), `doc-model-element-not-in-model` / `doc-model-element-not-in-doc`
|
|
66
|
+
(the doc's Command/Event/Read Model markers vs. the slice's actual elements, each direction), and
|
|
67
|
+
`doc-model-field-mismatch` (a matched Command/Event's field table vs. the model's `{ fields }`
|
|
68
|
+
block). Run `em validate <model-name>.em --json` and read each entry's `code`/`refs`/`message`
|
|
69
|
+
(`docs/validation.md#doc-model-consistency` documents exactly what each one checks and
|
|
70
|
+
when it stays silent — every rule is declare-gated, so a thin/draft doc doesn't nag); consume it
|
|
71
|
+
the same way step 3 below consumes `em diff --json` — parse the structured findings, don't
|
|
72
|
+
re-derive them by eye. Fold any that fire for an in-scope slice into that slice's internal-surface
|
|
73
|
+
findings for step 4's classification, citing the diagnostic directly as the evidence.
|
|
65
74
|
|
|
66
75
|
**Internal inconsistency is its own class, not drift.** When a doc and the `.em` disagree with
|
|
67
76
|
each other, neither one is "the code" — you don't know which is stale. Report it as internal
|
|
@@ -171,11 +180,13 @@ For each slice in scope:
|
|
|
171
180
|
granularity than the `.em` declares — e.g. event fields documented only in a slice doc's
|
|
172
181
|
table — are checked on the **spec surface** against the doc, not smuggled into the
|
|
173
182
|
structural diff.
|
|
174
|
-
4.
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
183
|
+
4. Read the in-scope slice's `doc-model-*` findings straight off the `em validate --json` run
|
|
184
|
+
from precondition 4 (or re-run it here) — no code evidence needed, `em` already did the
|
|
185
|
+
doc-vs-`.em` comparison for frontmatter `pattern:` and the Command/Event/Read Model rosters
|
|
186
|
+
and field tables. The only judgment left on this surface is narrative sections `em validate`
|
|
187
|
+
can't parse (Intent, Open Questions, notes): count a contradiction here too when it's
|
|
188
|
+
unambiguous — a stale sentence that flatly contradicts the `.em` is an internal
|
|
189
|
+
inconsistency; a vague or interpretable one is not a finding.
|
|
179
190
|
|
|
180
191
|
Do this for every in-scope slice before moving on to diffing. The evidence you record here is
|
|
181
192
|
what every finding in the report will cite — file paths, not vibes.
|
|
@@ -229,7 +240,7 @@ structural findings) — a finding with no citation isn't ready to report.
|
|
|
229
240
|
### 5. Report + proposals
|
|
230
241
|
|
|
231
242
|
Write `conformance/<YYYY-MM-DD>-report.md` in the model directory, from
|
|
232
|
-
|
|
243
|
+
`../../event-modeling-shared/templates/conformance-report.md`. For a real-drift or model-gap finding, propose a
|
|
233
244
|
ready-to-apply red note — `issue "conformance: <text>"` on the right element, written out in
|
|
234
245
|
the report exactly as it should be pasted into the `.em` — when a model-side marker is the
|
|
235
246
|
right fix; when the fix is purely doc wording (or the finding is an internal inconsistency
|
|
@@ -253,6 +264,21 @@ the marker (nobody ratified the outcome), so the next run re-walks the same span
|
|
|
253
264
|
`docs/ci.md`. If any proposals were ratified and applied, log a Decisions entry noting what
|
|
254
265
|
changed and why.
|
|
255
266
|
|
|
267
|
+
**Superseding the report you just walked (MIL-164).** Once the user has ruled on this run's
|
|
268
|
+
findings, also run:
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
em conform-supersede <model-name>.em conformance/YYYY-MM-DD-report.md --as-of <target-repo revision> --findings <spec>
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
— stamping the report with a "superseded as of `<rev>`" banner so a later reader who finds it
|
|
275
|
+
(a search hit, a bookmark, a link from an old PR description) sees immediately that its
|
|
276
|
+
file:line citations describe an ancestor of the current model, not its current state. This is
|
|
277
|
+
what keeps a superseded report an honest piece of history rather than a silently-misleading
|
|
278
|
+
current view. `<spec>` names the finding number(s) this run's ruling covers (e.g. `"1-3"`); if
|
|
279
|
+
only some findings were ruled on this session, run it again later with the remaining numbers —
|
|
280
|
+
each call adds its own stamp rather than overwriting the last.
|
|
281
|
+
|
|
256
282
|
## Conventions
|
|
257
283
|
|
|
258
284
|
- **Scratch model:** `<model-name>-asis.em`, written **next to** the canonical model (same
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: event-modeling-design
|
|
3
|
+
em-version: 1.9.0
|
|
4
|
+
description: >-
|
|
5
|
+
Use when structuring a draft event model into swimlanes and the four patterns (State Change,
|
|
6
|
+
State View, Automation, Translation), evaluating a model's structural completeness, or writing
|
|
7
|
+
implementation-ready deep slice documents (field tables, invariants, Given/When/Then scenarios,
|
|
8
|
+
error flows) for a model that already has its happy-path spine. Drives `em`'s model and slice
|
|
9
|
+
phases — the core modeling work between discovery and implementation.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Event Modeling — model & slice
|
|
13
|
+
|
|
14
|
+
You are facilitating the core modeling work: turning a draft happy-path spine into a
|
|
15
|
+
structurally complete, validated model, and then a deep implementation-ready spec per slice.
|
|
16
|
+
Your job is to **extract an accurate model from the user through Socratic questioning** — never
|
|
17
|
+
to invent the domain. You drive the `em` CLI to render the model live, and you produce
|
|
18
|
+
implementation-ready slice docs.
|
|
19
|
+
|
|
20
|
+
Read `../event-modeling-shared/reference/operating-principles.md` (preconditions, project
|
|
21
|
+
layout, the Socratic/validation discipline every phase follows) and
|
|
22
|
+
`../event-modeling-shared/reference/methodology.md` (the 7 steps + 4 patterns) before doing real
|
|
23
|
+
work — they are the source of truth. Run the preconditions there first: this phase expects a
|
|
24
|
+
draft model already exists (from `event-modeling-discover`'s `discover` or `extract` phase).
|
|
25
|
+
|
|
26
|
+
## Phase: `model` — steps 5-7
|
|
27
|
+
|
|
28
|
+
Goal: a structurally complete, **validated** model with correct patterns and swimlanes.
|
|
29
|
+
|
|
30
|
+
1. **Swimlanes & patterns (step 5).** Group events into **contexts** (bounded contexts /
|
|
31
|
+
aggregates) — ask which events share a consistency boundary and who owns them. Classify each
|
|
32
|
+
slice as one of the 4 patterns. **Share the slice between every automation or translation and
|
|
33
|
+
the command it triggers** (the reaction — processor/translation — together with the command
|
|
34
|
+
and event it produces; the read model it watches, if any, stays in the slice before). A
|
|
35
|
+
translation or automation is a reaction: it **triggers a command and never records an event
|
|
36
|
+
directly**. Add `translation` slices for external inputs (externally triggered: external →
|
|
37
|
+
translation → command → event, no slice before) and for the system reacting to its own state
|
|
38
|
+
(internally triggered: read model in the slice before → translation → command → event).
|
|
39
|
+
2. **Elaborate scenarios — first pass (step 6).** For each slice, capture the happy-path
|
|
40
|
+
Given/When/Then and the obvious invariants as short notes. (The full spec is the `slice` phase
|
|
41
|
+
below.)
|
|
42
|
+
3. **Evaluate completeness (step 7).** Walk the model: every slice is a **complete** pattern, not a
|
|
43
|
+
half-slice — **every command has something that triggers it**, every command emits an event,
|
|
44
|
+
**every event is read by a read model**, **every read model has a consumer**, every view has a
|
|
45
|
+
source, every UI is reachable, every connection is
|
|
46
|
+
one of the six legal pairs, and every automation **and** translation triggers a command (none
|
|
47
|
+
wired straight to an event, none with no command at all). Run `em validate` and resolve all
|
|
48
|
+
errors and warnings — it catches a reaction wired straight to an event too now (see
|
|
49
|
+
`../event-modeling-shared/reference/em-dsl.md`), so a clean run covers this case.
|
|
50
|
+
For an unread event, don't just bolt on a view to silence the warning: ask the user who looks at
|
|
51
|
+
this fact and what they do with it. The honest answers are "here's the read model we missed" or
|
|
52
|
+
"nobody — so why are we recording it", and both improve the model.
|
|
53
|
+
|
|
54
|
+
End of phase: render, update state (`em state set-phase slice`), continue with the `slice` phase
|
|
55
|
+
below to write implementation specs.
|
|
56
|
+
|
|
57
|
+
## Phase: `slice` — deep slice documents
|
|
58
|
+
|
|
59
|
+
Goal: implementation-ready specs. Go slice by slice (let the user pick order, or follow the
|
|
60
|
+
timeline). Check `README.md`'s Slices table for what's already done (run `em slice index
|
|
61
|
+
<model-name>.em` first if it looks stale).
|
|
62
|
+
|
|
63
|
+
This is also where **branch / unhappy-path events** are discovered and added to the model — as a
|
|
64
|
+
slice's alternate/error flows surface (a rejection, removal, cancellation, decline, expiry), add
|
|
65
|
+
the corresponding event/slice to the `.em` and re-render. The happy-path spine from earlier
|
|
66
|
+
phases is the starting point, not the finished event set. **Every new event needs its reader too**
|
|
67
|
+
— a rejection or cancellation that nothing projects will warn, and usually the missing piece is
|
|
68
|
+
real (someone has to see that the request was declined).
|
|
69
|
+
|
|
70
|
+
For each slice:
|
|
71
|
+
0. **Check for re-ratification first.** If `slices/<slice-name>.md` already exists with
|
|
72
|
+
`status: implemented`, this is a re-ratification, not fresh authoring: hold a Socratic
|
|
73
|
+
deep-dive on what changed (same rigor as step 1, scoped to the delta), update whichever
|
|
74
|
+
sections actually changed, then express the change as the `## Delta` section — fixed heading,
|
|
75
|
+
`### Added`/`Modified`/`Removed`/`Renamed` Requirement blocks each carrying its own scenarios
|
|
76
|
+
(see `../event-modeling-shared/templates/slice.md` and
|
|
77
|
+
`docs/slice-doc-schema.md#delta-section-grammar-and-lifecycle`)
|
|
78
|
+
— **overwriting** whatever the section held before, never appending to it. Then continue at
|
|
79
|
+
step 2 to bump `version` and flip `status` back to `ready-to-implement`, leaving
|
|
80
|
+
`implementedIn` naming the prior version's PR (intended drift signal, not a bug — see the
|
|
81
|
+
schema doc). Otherwise, this is first-time authoring: continue at step 1.
|
|
82
|
+
1. Hold a Socratic deep-dive to fill every section of `../event-modeling-shared/templates/slice.md`:
|
|
83
|
+
intent, trigger/actor,
|
|
84
|
+
command + field table (types & rules), event(s) + payload (mark immutable facts), invariants
|
|
85
|
+
(give each a stable ID), Given/When/Then scenarios (happy path + rule boundaries + edge cases),
|
|
86
|
+
alternate/error flows (retries, idempotency, compensations), non-functional requirements
|
|
87
|
+
(security/authz, PII/compliance, performance/SLA), read models affected, open questions. Park
|
|
88
|
+
anything unresolved rather than guessing. If the slice lives in an existing codebase, Grep/Read
|
|
89
|
+
adjacent real sources (OpenAPI specs, DB migrations, existing DTOs/event classes in sibling
|
|
90
|
+
contexts) before finalizing field names/types or invariants — don't guess a shape that's
|
|
91
|
+
already defined elsewhere.
|
|
92
|
+
2. **First-time authoring:** scaffold the doc mechanically rather than hand-writing the
|
|
93
|
+
frontmatter — `em slice new "<slice name>" --pattern <state-change|state-view|automation|
|
|
94
|
+
translation> --swimlane "<Persona> → <Context>" --wire <model>.em` writes `slices/<slice-name>.md`
|
|
95
|
+
(kebab-cased to match, via the same slugging `em` uses everywhere else) with the canonical
|
|
96
|
+
`schemaVersion`/`pattern`/`swimlane`/`status: draft`/`version: 1` frontmatter — exactly the
|
|
97
|
+
five keys `em export` and the readiness gate require, no more — and the `# Slice:` heading +
|
|
98
|
+
diagram-image stub already in place. `--wire` also inserts the `note
|
|
99
|
+
"slices/<slice-name>.md"` line straight into the `.em`, onto the slice's primary element (the
|
|
100
|
+
command for State Change, the view for State View, the processor for Automation, the
|
|
101
|
+
translation for Translation), matched by export key — see step 4 for when it refuses instead.
|
|
102
|
+
Both `--pattern` and `--swimlane` are required; an invalid `--pattern` is refused with the
|
|
103
|
+
valid choices listed. Never hand-type this block, and never fall back to a placeholder
|
|
104
|
+
pattern/swimlane to dodge the flags. Then fill in every judgment section below the stub from
|
|
105
|
+
step 1 (Intent, Command, Event(s), Invariants, Scenarios, ...) — the doc's prose is still
|
|
106
|
+
entirely hand-authored, only the frontmatter/heading scaffold and the `.em` wiring are
|
|
107
|
+
mechanized. Record the originating need (ticket/conversation link) in the Intent section when
|
|
108
|
+
one exists. When this doc exists because of a split, merge, or rename, add the matching
|
|
109
|
+
lineage key(s) by hand (`split-from`/`merged-from`/`superseded-by`, `<slice-key>@v<N>` grammar
|
|
110
|
+
— see `docs/slice-doc-schema.md` for the full schema; `em validate` catches a malformed one
|
|
111
|
+
after the fact, see the `lineage-*` rules below).
|
|
112
|
+
**Re-ratification (step 0):** the doc already exists, so `em slice new` doesn't apply here
|
|
113
|
+
(it refuses to overwrite an existing file without `--force`, and forcing would blow away the
|
|
114
|
+
doc's authored body) — run `em slice reratify <model>.em <slice-key>` instead: it bumps
|
|
115
|
+
`version` and flips `status` back to `ready-to-implement` in the existing frontmatter,
|
|
116
|
+
clearing any stale `ratifiedBy:`/`ratifiedOn:` from the prior version so a follow-up
|
|
117
|
+
`em slice ratify --by <name>` (if the team records that) applies cleanly.
|
|
118
|
+
3. Render the slice's own diagram: `em render <model>.em --slice "<slice name>" -o
|
|
119
|
+
slices/<slice-name>.svg` (kebab-case, matching the doc's filename and the `![Diagram]` stub
|
|
120
|
+
`em slice new` already wrote) — redraws just this slice in its own canonical pattern shape.
|
|
121
|
+
4. Confirm it's wired into the `.em`: `em slice new --wire` (step 2) already inserted the `note
|
|
122
|
+
"slices/<slice-name>.md"` line onto the slice's primary element's own declaration line — it
|
|
123
|
+
only ever edits that one line, and only when doing so is unambiguous, so it refuses (writing
|
|
124
|
+
NEITHER the doc nor the `.em` edit) rather than guess when the slice has zero or more than one
|
|
125
|
+
candidate element of the primary kind, or when that line already carries a `note` clause. On a
|
|
126
|
+
refusal, re-run step 2 without `--wire` — it prints the exact line to add, paste it onto the
|
|
127
|
+
slice's primary element by hand.
|
|
128
|
+
5. Run `em slice index <model-name>.em` to regenerate `README.md`'s Slices table — the one
|
|
129
|
+
canonical slice index — from the model and the doc frontmatter you just wrote (status,
|
|
130
|
+
`implementedIn` once shipped). Never hand-edit the table; it's a generated block.
|
|
131
|
+
6. Re-render and `em validate`.
|
|
132
|
+
|
|
133
|
+
When a slice is **ratified** — a human flips its `status` to `ready-to-implement` with every
|
|
134
|
+
open question resolved — it's ready to hand to an implementer. Confirm with
|
|
135
|
+
`em validate <model>.em --slice-ready <key>`, and point whoever (or whatever) implements it
|
|
136
|
+
at the `event-modeling-implement` skill.
|
|
137
|
+
|
|
138
|
+
End of phase: every slice that should exist has a doc, `README.md`'s Slices table is current,
|
|
139
|
+
and the model validates clean. Suggest `event-modeling-implement` for each ratified slice.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: event-modeling-discover
|
|
3
|
+
em-version: 1.9.0
|
|
4
|
+
description: >-
|
|
5
|
+
Use when starting a brand-new event model from scratch — greenfield discovery: brainstorming
|
|
6
|
+
past-tense events, storyboarding the happy path, finding the commands and read models — or when
|
|
7
|
+
extracting a current-state model from an EXISTING codebase or system (event-driven or
|
|
8
|
+
procedural). Drives `em`'s discover and extract phases; produces a draft or as-is `.em` model
|
|
9
|
+
ready for the model/slice phases (`event-modeling-design`).
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Event Modeling — discover & extract
|
|
13
|
+
|
|
14
|
+
You are facilitating the start of an Event Modeling session. Your job is to **extract an
|
|
15
|
+
accurate model from the user through Socratic questioning** — never to invent the domain. You
|
|
16
|
+
drive the `em` CLI to render the model live.
|
|
17
|
+
|
|
18
|
+
Read `../event-modeling-shared/reference/operating-principles.md` (preconditions, project
|
|
19
|
+
layout, the Socratic/validation discipline every phase follows) and
|
|
20
|
+
`../event-modeling-shared/reference/methodology.md` (the 7 steps + 4 patterns) before doing real
|
|
21
|
+
work — they are the source of truth. Run the preconditions there first.
|
|
22
|
+
|
|
23
|
+
**Existing system?** Use the `extract` phase below. **New feature inside an existing codebase,
|
|
24
|
+
not a whole-system extraction?** Stay in `discover`, but before locking in command/event names,
|
|
25
|
+
Grep/Read adjacent real sources (OpenAPI specs, DB migrations, existing DTOs/event classes in
|
|
26
|
+
sibling contexts) rather than guessing conventions — same check the `slice` phase applies to
|
|
27
|
+
field tables (`event-modeling-design`).
|
|
28
|
+
|
|
29
|
+
## Phase: `discover` — steps 1-4
|
|
30
|
+
|
|
31
|
+
Goal: a draft model of events, storyboard, commands, and views. Loose is OK; structure comes next.
|
|
32
|
+
|
|
33
|
+
1. **Brainstorm events (step 1).** Ask the user to name everything that happens, as past-tense
|
|
34
|
+
facts. Probe for missed state changes. For each candidate, apply the **"is it an event?"
|
|
35
|
+
test** (`methodology.md` step 1 — the "would this wake the CEO at 3am" heuristic):
|
|
36
|
+
reject derived values (belong in a read model) and telemetry/activity (not business state).
|
|
37
|
+
Don't silently drop rejections — park them in the state file's Decisions log with why, so
|
|
38
|
+
they aren't re-proposed later. Capture the survivors as a flat list.
|
|
39
|
+
2. **Plot / storyboard (step 2).** Order the events into the narrative. Identify **personas**
|
|
40
|
+
(actors) and the **UI** screens at each step. Add `persona` declarations and `ui` elements.
|
|
41
|
+
In a **headless/API** model there are no human personas or screens — identify the external
|
|
42
|
+
**callers** at each step instead; declare one persona per caller/role, and its `ui` boxes are
|
|
43
|
+
the API calls (see `methodology.md`).
|
|
44
|
+
3. **Inputs (step 3).** For each event, find the **command** that causes it (imperative name).
|
|
45
|
+
Form `command → event` slices (State Change pattern). Every command needs a **trigger** in the
|
|
46
|
+
same breath: the screen the user issues it from (a `ui` in the slice), or — for the Automation
|
|
47
|
+
and Translation patterns — the reaction that triggers it, also in this slice. A command
|
|
48
|
+
nothing points at is a write nobody can start. *"Who does this, and where are they when they
|
|
49
|
+
do it?"*
|
|
50
|
+
4. **Outputs (step 4).** Identify the **read models / views** consumers need and wire them with
|
|
51
|
+
`from "Event"` (State View pattern), each with the screen (or reaction) that consumes it — a
|
|
52
|
+
read model nothing displays is information dropped on the floor. In a **headless/API** model
|
|
53
|
+
the consumer is the caller persona's `ui` (the API query) — same as any screen. Read models are
|
|
54
|
+
**repeated** in each slice where they're read (use `view X again` after the first, each instance
|
|
55
|
+
with its own consumer) so the timeline flows (see `methodology.md`).
|
|
56
|
+
**Close the loop before leaving this step:** every event from step 3 must be read by at least one
|
|
57
|
+
read model. Walk the event list and ask, for each one, *"who looks at this, and what do they do
|
|
58
|
+
with it?"* An event with no answer is either missing its read model or shouldn't be recorded —
|
|
59
|
+
both are worth raising with the user rather than leaving dangling.
|
|
60
|
+
|
|
61
|
+
End of phase: write/refresh the `.em`, render it, update `.event-modeling.md` (steps done,
|
|
62
|
+
decisions, open questions — run `em state set-phase model` rather than hand-editing `Current
|
|
63
|
+
phase:`), and run `em slice index <model-name>.em` to seed `README.md`'s Slices table (every
|
|
64
|
+
slice already reads "no doc yet" — no slice docs exist until the `slice` phase writes them).
|
|
65
|
+
Tell the user they can stop here and resume with `/event-modeling` (or invoke
|
|
66
|
+
`event-modeling-design` directly).
|
|
67
|
+
|
|
68
|
+
## Phase: `extract` — current-state model of an existing system
|
|
69
|
+
|
|
70
|
+
Goal: a faithful **current-state** model extracted from an existing system — the as-is sibling
|
|
71
|
+
of `discover` (it replaces discover; the model then proceeds to `model` as usual, in
|
|
72
|
+
`event-modeling-design`).
|
|
73
|
+
|
|
74
|
+
**Read `reference/extract.md` before doing any extract work** — it carries a stance override
|
|
75
|
+
that inverts methodology step 1 (capture how the system behaves *today*; never model desired
|
|
76
|
+
state).
|
|
77
|
+
|
|
78
|
+
- Two source modes, detected from the system itself and confirmed with the user:
|
|
79
|
+
**event-driven** (an event vocabulary already exists — schemas, topics, handlers) and
|
|
80
|
+
**procedural/monolith** (no event vocabulary — synthesize candidate events from behavior
|
|
81
|
+
and docs).
|
|
82
|
+
- Converge via a ~7-round confirm-and-clarify loop (one concern per round; render from round 2,
|
|
83
|
+
validate from round 4 — see the playbook).
|
|
84
|
+
- **Current-state-only:** park unknowns as `# TBD` comments in the `.em`, mirrored in the state
|
|
85
|
+
file's Open Questions — never guess intended design.
|
|
86
|
+
|
|
87
|
+
End of phase: validated as-is model; state file updated (source mode, rounds, decisions; `em
|
|
88
|
+
state set-phase model` for `Current phase:`); run `em slice index <model-name>.em` to seed
|
|
89
|
+
`README.md`'s Slices table; then hand off to `event-modeling-design` (steps 5-7).
|
|
@@ -23,8 +23,9 @@ reaction-shares-a-slice-with-its-command shape — still applies.
|
|
|
23
23
|
|
|
24
24
|
## Setup
|
|
25
25
|
|
|
26
|
-
1. Run the
|
|
27
|
-
|
|
26
|
+
1. Run the shared preconditions (tool check, model location) — see
|
|
27
|
+
`../../event-modeling-shared/reference/operating-principles.md`. If no model exists yet, run
|
|
28
|
+
`em scaffold <model-name>` (see that doc's "Project layout this skill creates").
|
|
28
29
|
2. **Agree the scope line first**: which system, which part, what's out of bounds. Write it to
|
|
29
30
|
the state file's Session inputs.
|
|
30
31
|
3. Record in the state file: `Source mode` (after detection, below) and
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: event-modeling-implement
|
|
3
|
+
em-version: 1.9.0
|
|
4
|
+
description: >-
|
|
5
|
+
Use when building a single ratified event-modeling slice (status: ready-to-implement) into
|
|
6
|
+
merged, tested code — the one phase where the agent builds rather than facilitates. Gates on
|
|
7
|
+
readiness, treats the slice doc as the read-only spec, surfaces gaps instead of deciding them
|
|
8
|
+
silently, and requires tests traceable to the doc's invariants and scenarios.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Event Modeling — implement
|
|
12
|
+
|
|
13
|
+
Goal: turn a single `ready-to-implement` slice into merged, verified code — the one phase where
|
|
14
|
+
the agent builds rather than facilitates.
|
|
15
|
+
|
|
16
|
+
**Read `reference/implement.md` before doing any implement work and follow it as the
|
|
17
|
+
contract.** In short: gate on `em validate <model>.em --slice-ready <key>` (stop and hand
|
|
18
|
+
back if it fails — never edit the doc to make the gate pass); treat the slice doc as the
|
|
19
|
+
spec (read-only, except the merge-time `status`/`implementedIn` flip); surface every gap to
|
|
20
|
+
the user instead of deciding it silently; cover every `INV-<MNEMONIC>-n` and every scenario with
|
|
21
|
+
tests; in spec-kit projects, allocate via em-sdd-bridge (redirect mode) and never run
|
|
22
|
+
`/speckit.specify`.
|
|
23
|
+
|
|
24
|
+
That contract applies to any implementing agent, whether or not the session started from
|
|
25
|
+
`/event-modeling` — `em contract` prints it to stdout with no `.claude/` awareness required, for
|
|
26
|
+
an agent that can run a shell but isn't Claude Code.
|
|
27
|
+
|
|
28
|
+
If the project ships pattern-specific implementation skills (for example an Axon/DCB skill set
|
|
29
|
+
keyed on a slice doc's `pattern:` frontmatter), route by the slice's pattern and follow those —
|
|
30
|
+
`reference/implement.md` §2 explains where that hand-off happens.
|
|
31
|
+
|
|
32
|
+
Preconditions (tool check, model location) are the same as every other phase — see
|
|
33
|
+
`../event-modeling-shared/reference/operating-principles.md` — but this phase additionally
|
|
34
|
+
requires the target slice to already be ratified; if it isn't, stop and say so rather than
|
|
35
|
+
starting on unratified work.
|
|
36
|
+
|
|
37
|
+
End of phase: PR merged, slice doc flipped to `status: implemented` with `implementedIn`
|
|
38
|
+
filled, `em slice index <model-name>.em` run to refresh `README.md`'s Slices table. Implement
|
|
39
|
+
doesn't chain to another phase — run it once per ratified slice; `event-modeling-conform`'s
|
|
40
|
+
`conform` phase later checks the result against the model.
|
|
@@ -126,7 +126,7 @@ resolves the doc via the same note-binding join `--slice-ready` uses, is idempot
|
|
|
126
126
|
with the same URL, and refuses (never silently overwrites) if the doc is already `implemented`
|
|
127
127
|
with a different URL. Prefer it over hand-editing the doc's frontmatter.
|
|
128
128
|
|
|
129
|
-
Then, if the project keeps a model README (from
|
|
129
|
+
Then, if the project keeps a model README (from `../../event-modeling-shared/templates/model-readme.md`), run
|
|
130
130
|
`em slice index <model-name>.em` so its generated Slices table reflects the new status and
|
|
131
131
|
link — never hand-edit that table. The `implementedIn` link is what the `conform` phase later
|
|
132
132
|
uses to anchor drift-checking — leaving it empty blinds the loop.
|
|
@@ -179,6 +179,7 @@ everything a spec holds. Don't introduce an intermediate spec document of your o
|
|
|
179
179
|
|
|
180
180
|
Implementation isn't the end of the slice's story. On a cadence — or whenever someone asks —
|
|
181
181
|
the `conform` phase checks implemented slices against the code, using the `implementedIn` link
|
|
182
|
-
you recorded, and reports drift for humans to rule on (see `
|
|
182
|
+
you recorded, and reports drift for humans to rule on (see the `event-modeling-conform` skill's
|
|
183
|
+
`reference/conform.md`). Your two
|
|
183
184
|
duties to that future loop are already behind you if you followed this doc: an accurate
|
|
184
185
|
lifecycle flip, and zero silent decisions.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: event-modeling-review
|
|
3
|
+
em-version: 1.9.0
|
|
4
|
+
description: >-
|
|
5
|
+
Use when starting em's live browser viewer (`em watch --serve`) so a team can watch a model
|
|
6
|
+
update in real time, or facilitating a SCHEDULED stakeholder walkthrough that steps through
|
|
7
|
+
slices one at a time in Review mode, capturing anything the room raises live as `issue "..."`
|
|
8
|
+
red notes. Drives `em`'s watch and review phases.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Event Modeling — watch & review
|
|
12
|
+
|
|
13
|
+
## Phase: `watch` — live team view
|
|
14
|
+
|
|
15
|
+
Start the watcher with `--serve` in the background:
|
|
16
|
+
`em watch <model-name>.em -o <model-name>.svg --serve` (run_in_background). It re-renders on every
|
|
17
|
+
save and pushes an instant reload to the browser over Server-Sent Events. Tell the user to open the
|
|
18
|
+
URL it prints (e.g. `http://localhost:5173/?svg=<model-name>.svg`) and share their screen — updates
|
|
19
|
+
appear the moment you save, with no polling and no idle churn between edits.
|
|
20
|
+
|
|
21
|
+
The viewer navigates like a map — drag to pan, scroll/pinch to zoom, **Fit** to reset — and its
|
|
22
|
+
**Review mode** steps through slices one at a time (see the `review` phase below). A save that
|
|
23
|
+
fails to render never blanks the shared screen: the last good diagram stays up, an error banner
|
|
24
|
+
explains what went wrong, and the viewer recovers on its own at the next successful render.
|
|
25
|
+
|
|
26
|
+
## Phase: `review` — stakeholder walkthrough
|
|
27
|
+
|
|
28
|
+
Goal: step a real stakeholder review session through the model slice by slice, one slice
|
|
29
|
+
spotlighted at a time, with any open questions the room raises captured live as `issue "..."`
|
|
30
|
+
red notes.
|
|
31
|
+
|
|
32
|
+
**Trigger: a real stakeholder review session is on the calendar — a scheduled use, not
|
|
33
|
+
speculation.** Don't propose this phase proactively; it exists for facilitated reviews with
|
|
34
|
+
non-engineer stakeholders in the room, not routine model editing.
|
|
35
|
+
|
|
36
|
+
Start the same live server as `watch`: `em watch <model-name>.em -o <model-name>.svg --serve`
|
|
37
|
+
(run_in_background). Open the printed URL, click **Review mode** in the header, and share the
|
|
38
|
+
screen. Use Prev/Next (or the left/right arrow keys) to step through slices in declaration
|
|
39
|
+
order — each one pans/zooms into view with everything else dimmed, so the room's attention
|
|
40
|
+
tracks one slice at a time.
|
|
41
|
+
|
|
42
|
+
**Live capture:** when a stakeholder raises something unresolved, add `issue "..."` to the
|
|
43
|
+
relevant element in the `.em` file and save — exactly the same mechanism `event-modeling-conform`
|
|
44
|
+
uses for any other issue. The browser updates over the existing SSE push within moments, without
|
|
45
|
+
losing the current slice or resetting review mode.
|
|
46
|
+
|
|
47
|
+
Wrap-up: run `em validate --list-issues` to sweep everything captured during the session and
|
|
48
|
+
walk each one with the user, same as any open issue. Update the state file's Participants
|
|
49
|
+
section with who attended, and run `em state set-review <date>` to set the `Last stakeholder
|
|
50
|
+
review:` marker (mirrors `Last conformance:`).
|
|
51
|
+
|
|
52
|
+
End of phase: state file's `Last stakeholder review:` marker updated, every issue captured
|
|
53
|
+
live triaged (resolved on the spot, moved to Open questions / parking lot, or left open on
|
|
54
|
+
purpose). Review doesn't chain to another phase — it's a recurring, scheduled activity like
|
|
55
|
+
`conform`, not a step in the discover → model → slice sequence.
|
|
56
|
+
|
|
57
|
+
Preconditions (tool check, model location) are the same as every other phase — see
|
|
58
|
+
`../event-modeling-shared/reference/operating-principles.md`.
|