@milehimikey/em 1.7.2 → 1.8.1

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.
Files changed (119) hide show
  1. package/.claude/skills/event-modeling/SKILL.md +92 -65
  2. package/.claude/skills/event-modeling/reference/conform.md +45 -20
  3. package/.claude/skills/event-modeling/reference/em-dsl.md +132 -55
  4. package/.claude/skills/event-modeling/reference/extract.md +5 -4
  5. package/.claude/skills/event-modeling/reference/implement.md +34 -22
  6. package/.claude/skills/event-modeling/templates/model-readme.md +8 -5
  7. package/.claude/skills/event-modeling/templates/slice.md +19 -5
  8. package/README.md +6 -4
  9. package/dist/catalog/docJoin.d.ts +28 -3
  10. package/dist/catalog/docJoin.js +82 -13
  11. package/dist/catalog/docJoin.js.map +1 -1
  12. package/dist/catalog/docModelConsistencyValidate.d.ts +8 -0
  13. package/dist/catalog/docModelConsistencyValidate.js +335 -0
  14. package/dist/catalog/docModelConsistencyValidate.js.map +1 -0
  15. package/dist/catalog/noteBindingValidate.d.ts +8 -0
  16. package/dist/catalog/noteBindingValidate.js +133 -0
  17. package/dist/catalog/noteBindingValidate.js.map +1 -0
  18. package/dist/catalog/pages.js +3 -3
  19. package/dist/catalog/pages.js.map +1 -1
  20. package/dist/catalog/sliceDoc.d.ts +14 -0
  21. package/dist/catalog/sliceDoc.js +22 -0
  22. package/dist/catalog/sliceDoc.js.map +1 -1
  23. package/dist/catalog/sliceReadyValidate.d.ts +18 -0
  24. package/dist/catalog/sliceReadyValidate.js +25 -1
  25. package/dist/catalog/sliceReadyValidate.js.map +1 -1
  26. package/dist/cli/agentsMd.d.ts +15 -0
  27. package/dist/cli/agentsMd.js +72 -0
  28. package/dist/cli/agentsMd.js.map +1 -0
  29. package/dist/cli/conformScope.d.ts +86 -0
  30. package/dist/cli/conformScope.js +156 -0
  31. package/dist/cli/conformScope.js.map +1 -0
  32. package/dist/cli/contract.d.ts +7 -0
  33. package/dist/cli/contract.js +27 -0
  34. package/dist/cli/contract.js.map +1 -0
  35. package/dist/cli/coverage.d.ts +71 -0
  36. package/dist/cli/coverage.js +177 -0
  37. package/dist/cli/coverage.js.map +1 -0
  38. package/dist/cli/markImplemented.d.ts +34 -0
  39. package/dist/cli/markImplemented.js +180 -0
  40. package/dist/cli/markImplemented.js.map +1 -0
  41. package/dist/cli/migrateReactionShape.d.ts +62 -0
  42. package/dist/cli/migrateReactionShape.js +283 -0
  43. package/dist/cli/migrateReactionShape.js.map +1 -0
  44. package/dist/cli/sliceIndex.d.ts +49 -0
  45. package/dist/cli/sliceIndex.js +115 -0
  46. package/dist/cli/sliceIndex.js.map +1 -0
  47. package/dist/cli/sliceNew.d.ts +18 -0
  48. package/dist/cli/sliceNew.js +53 -0
  49. package/dist/cli/sliceNew.js.map +1 -0
  50. package/dist/cli/stateFile.d.ts +74 -0
  51. package/dist/cli/stateFile.js +191 -0
  52. package/dist/cli/stateFile.js.map +1 -0
  53. package/dist/cli.js +535 -43
  54. package/dist/cli.js.map +1 -1
  55. package/dist/emit/coverageJson.d.ts +8 -0
  56. package/dist/emit/coverageJson.js +30 -0
  57. package/dist/emit/coverageJson.js.map +1 -0
  58. package/dist/emit/diffJson.d.ts +9 -1
  59. package/dist/emit/diffJson.js +44 -1
  60. package/dist/emit/diffJson.js.map +1 -1
  61. package/dist/emit/dot.js +41 -10
  62. package/dist/emit/dot.js.map +1 -1
  63. package/dist/emit/json.d.ts +77 -4
  64. package/dist/emit/json.js +78 -4
  65. package/dist/emit/json.js.map +1 -1
  66. package/dist/emit/validateJson.d.ts +52 -0
  67. package/dist/emit/validateJson.js +120 -0
  68. package/dist/emit/validateJson.js.map +1 -0
  69. package/dist/mcp/main.d.ts +2 -0
  70. package/dist/mcp/main.js +20 -0
  71. package/dist/mcp/main.js.map +1 -0
  72. package/dist/mcp/server.d.ts +11 -0
  73. package/dist/mcp/server.js +260 -0
  74. package/dist/mcp/server.js.map +1 -0
  75. package/dist/model/model.d.ts +30 -1
  76. package/dist/model/model.js +26 -0
  77. package/dist/model/model.js.map +1 -1
  78. package/dist/model/rules.d.ts +114 -0
  79. package/dist/model/rules.js +116 -4
  80. package/dist/model/rules.js.map +1 -1
  81. package/dist/model/validate.js +92 -8
  82. package/dist/model/validate.js.map +1 -1
  83. package/dist/parser/ast.d.ts +47 -0
  84. package/dist/parser/lexer.d.ts +16 -0
  85. package/dist/parser/lexer.js +44 -2
  86. package/dist/parser/lexer.js.map +1 -1
  87. package/dist/parser/parser.js +354 -20
  88. package/dist/parser/parser.js.map +1 -1
  89. package/dist/render/drawNotes.d.ts +11 -1
  90. package/dist/render/drawNotes.js +28 -3
  91. package/dist/render/drawNotes.js.map +1 -1
  92. package/dist/render/render.js +116 -23
  93. package/dist/render/render.js.map +1 -1
  94. package/dist/render/serve.d.ts +4 -0
  95. package/dist/render/serve.js +27 -239
  96. package/dist/render/serve.js.map +1 -1
  97. package/dist/render/sliceOverlay.d.ts +7 -2
  98. package/dist/render/sliceOverlay.js +19 -7
  99. package/dist/render/sliceOverlay.js.map +1 -1
  100. package/dist/render/sliceStatus.d.ts +7 -3
  101. package/dist/render/sliceStatus.js +48 -12
  102. package/dist/render/sliceStatus.js.map +1 -1
  103. package/dist/render/viewerHtml.d.ts +1 -0
  104. package/dist/render/viewerHtml.js +5 -0
  105. package/dist/render/viewerHtml.js.map +1 -0
  106. package/dist/render/watch.d.ts +10 -0
  107. package/dist/render/watch.js +29 -0
  108. package/dist/render/watch.js.map +1 -1
  109. package/dist/templates.d.ts +20 -1
  110. package/dist/templates.js +172 -3
  111. package/dist/templates.js.map +1 -1
  112. package/dist/util/markers.d.ts +13 -0
  113. package/dist/util/markers.js +30 -0
  114. package/dist/util/markers.js.map +1 -0
  115. package/dist/util/walkDir.d.ts +10 -1
  116. package/dist/util/walkDir.js +11 -7
  117. package/dist/util/walkDir.js.map +1 -1
  118. package/package.json +12 -3
  119. package/.claude/skills/event-modeling/templates/live.html +0 -117
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling
3
- em-version: 1.7.2
3
+ em-version: 1.8.1
4
4
  description: >-
5
5
  Use when the user wants to event-model a business process or system: building, editing,
6
6
  updating, or maintaining a model — extending or detailing an existing one into slices,
@@ -77,21 +77,23 @@ vendored alongside this skill.
77
77
  is missing an **element**, not an arrow.
78
78
  - **Validate continuously.** Run `em validate` and fix errors/warnings as you go (see DSL ref).
79
79
  - **Save state at the end of every session** so work resumes cleanly. Also append one line to
80
- the Usage log: the phase(s) touched and the `em validate` diagnostic *categories* that fired
81
- (the exact fixed strings from `docs/usage-data.md`, e.g. "read model has no consumer" —
82
- never the full message or domain content). This is the team's only usage signal today (`docs/usage-data.md`) — keep it cheap
83
- and habitual, not a task to skip.
80
+ the Usage log: the phase(s) touched and the diagnostic *categories* that fired — run `em
81
+ validate <model>.em --json` and dedupe each diagnostic's `usageCategory` field directly
82
+ (never the full message or domain content). This is the team's only usage signal today
83
+ (`docs/usage-data.md`) — keep it cheap and habitual, not a task to skip.
84
84
 
85
85
  ## Preconditions (run first)
86
86
 
87
87
  1. Check the tool: `em --version`. If missing, tell the user to run `npm i -g @milehimikey/em`
88
88
  and stop until installed.
89
89
  2. Locate the model. Look for an existing `<dir>/.event-modeling.md` and `*.em` in the working
90
- directory (or a `models/` subfolder). If found, read the state file. If not, and the phase
91
- needs one, ask the user for the model name and where to create it.
92
- 3. Parse the argument (`$ARGUMENTS`) to pick the phase below. With **no argument**, read the
93
- state file and resume the recorded phase/step; if no model exists, propose starting `discover`
94
- (greenfield) or `extract` (modeling an existing system).
90
+ directory (or a `models/` subfolder). If found, run `em state read <dir>` to read the state
91
+ file's mechanical fields (model path, phase, step, last updated, last conformance, last
92
+ review) as JSON — don't parse the bullets by hand. If not, and the phase needs one, ask the
93
+ user for the model name and where to create it.
94
+ 3. Parse the argument (`$ARGUMENTS`) to pick the phase below. With **no argument**, use
95
+ `em state read <dir>`'s `phase`/`step` to resume the recorded phase/step; if no model exists,
96
+ propose starting `discover` (greenfield) or `extract` (modeling an existing system).
95
97
  4. Populate the state file's Participants section at session start. For a live workshop, ask for
96
98
  a single human proxy to relay questions to the room, and attribute every answer/decision in
97
99
  the Decisions log to a named participant.
@@ -102,7 +104,6 @@ vendored alongside this skill.
102
104
  <model-name>/
103
105
  <model-name>.em # the model (slice docs linked via note "...")
104
106
  <model-name>.svg # render target for em watch
105
- live.html # file:// auto-refresh viewer (copy of templates/live.html, verbatim)
106
107
  README.md # overview + slice index (from templates/model-readme.md)
107
108
  .event-modeling.md # resumable state (from templates/state.md)
108
109
  slices/<slice-name>.md # one rich slice doc per slice (from templates/slice.md)
@@ -111,14 +112,19 @@ vendored alongside this skill.
111
112
  <model-name>-asis.em # conform-phase scratch model, regenerated per run — git-ignore this
112
113
  ```
113
114
 
114
- When creating a new model, scaffold the directory and copy the templates in (filling the
115
- placeholders). Copy `live.html` **verbatim** — it takes the SVG name from its URL query
116
- (`live.html?svg=<model-name>.svg`), so there's nothing to edit. You may use `em init` for a
117
- starter `.em`, but usually you'll build it up from the discovery conversation instead. Fill
118
- template placeholders — never leave `{{...}}` in delivered files. The `conformance/` directory
119
- and `<model-name>-asis.em` only appear once the `conform` phase runs; add the pattern `*-asis.em`
120
- to the repository's `.gitignore` the first time one is created (see `reference/conform.md`) —
121
- it's scratch, never committed.
115
+ When creating a new model, run `em scaffold <model-name>` — it creates `<model-name>/` and
116
+ writes all three starter files in one step (`<model-name>.em`, `README.md`,
117
+ `.event-modeling.md`), filling the Model Name/model-name placeholders and the state file's
118
+ mechanical fields (model path, `Current phase: discover`, `Current step: 1`, dates) for you, so
119
+ there's nothing left to hand-copy or fill in. Refuses if `<model-name>/` already exists; pass
120
+ `--force` to overwrite. You'll
121
+ usually replace the scaffolded `.em`'s content as the discovery conversation builds up the real
122
+ model — it starts out as the same starter model `em init` writes, titled from `<model-name>`.
123
+ `slices/*.md` and `conformance/` aren't part of `em scaffold`; they come from the `slice` and
124
+ `conform` phases below. The `conformance/` directory
125
+ and `<model-name>-asis.em` only appear once the `conform` phase runs; `em conform-scope
126
+ --seed-asis` creates `<model-name>-asis.em` and gitignores `*-asis.em` for you (see
127
+ `reference/conform.md`) — it's scratch, never committed.
122
128
 
123
129
  ---
124
130
 
@@ -160,8 +166,10 @@ phase applies to field tables, below.
160
166
  both are worth raising with the user rather than leaving dangling.
161
167
 
162
168
  End of phase: write/refresh the `.em`, render it, update `.event-modeling.md` (steps done,
163
- decisions, open questions) and `README.md`'s slice index. Tell the user they can stop here and
164
- resume with `/event-modeling model`.
169
+ decisions, open questions — run `em state set-phase model` rather than hand-editing `Current
170
+ phase:`), and run `em slice index <model-name>.em` to seed `README.md`'s Slices table (every
171
+ slice already reads "no doc yet" — no slice docs exist until the `slice` phase writes them).
172
+ Tell the user they can stop here and resume with `/event-modeling model`.
165
173
 
166
174
  ## Phase: `extract` — current-state model of an existing system
167
175
 
@@ -181,8 +189,9 @@ state).
181
189
  - **Current-state-only:** park unknowns as `# TBD` comments in the `.em`, mirrored in the state
182
190
  file's Open Questions — never guess intended design.
183
191
 
184
- End of phase: validated as-is model; state file updated (source mode, rounds, decisions) and
185
- `README.md`'s slice index seeded; then chain to `/event-modeling model` (steps 5-7).
192
+ End of phase: validated as-is model; state file updated (source mode, rounds, decisions; `em
193
+ state set-phase model` for `Current phase:`); run `em slice index <model-name>.em` to seed
194
+ `README.md`'s Slices table; then chain to `/event-modeling model` (steps 5-7).
186
195
 
187
196
  ## Phase: `model` — steps 5-7
188
197
 
@@ -211,12 +220,14 @@ Goal: a structurally complete, **validated** model with correct patterns and swi
211
220
  this fact and what they do with it. The honest answers are "here's the read model we missed" or
212
221
  "nobody — so why are we recording it", and both improve the model.
213
222
 
214
- End of phase: render, update state, suggest `/event-modeling slice` to write implementation specs.
223
+ End of phase: render, update state (`em state set-phase slice`), suggest `/event-modeling slice`
224
+ to write implementation specs.
215
225
 
216
226
  ## Phase: `slice` — deep slice documents
217
227
 
218
228
  Goal: implementation-ready specs. Go slice by slice (let the user pick order, or follow the
219
- timeline). Check `README.md`'s slice index for what's already done.
229
+ timeline). Check `README.md`'s Slices table for what's already done (run `em slice index
230
+ <model-name>.em` first if it looks stale).
220
231
 
221
232
  This is also where **branch / unhappy-path events** are discovered and added to the model — as a
222
233
  slice's alternate/error flows surface (a rejection, removal, cancellation, decline, expiry), add
@@ -245,27 +256,36 @@ For each slice:
245
256
  adjacent real sources (OpenAPI specs, DB migrations, existing DTOs/event classes in sibling
246
257
  contexts) before finalizing field names/types or invariants — don't guess a shape that's
247
258
  already defined elsewhere.
248
- 2. Write the doc to `slices/<slice-name>.md` (kebab-case the slice name), with the YAML
249
- frontmatter block at the very top — all five of `schemaVersion`/`pattern`/`swimlane`/
250
- `status`/`version` (kebab-case `pattern` value, `schemaVersion: 1`, `version` starting at
251
- `1`; omitting any of the five makes the doc `frontmatter-invalid` to `em export` and the
252
- readiness gate), plus `implementedIn` once shipped — the canonical, machine-read
253
- metadata dialect (`- **Status:** ...` bullet lines are legacy/accepted input only; never
254
- write new docs that way). When this doc exists because of a split, merge, or rename, add the
255
- matching lineage key(s) too (`split-from`/`merged-from`/`superseded-by`, `<slice-key>@v<N>`
256
- grammar — see `docs/slice-doc-schema.md` for the full schema). On a re-ratification (step 0),
257
- bump `version` and flip `status` here instead of setting them fresh. Record the originating
258
- need (ticket/conversation link) in the Intent section when one exists.
259
+ 2. **First-time authoring:** scaffold the doc mechanically rather than hand-writing the
260
+ frontmatter — `em slice new "<slice name>" --pattern <state-change|state-view|automation|
261
+ translation> --swimlane "<Persona> → <Context>"` writes `slices/<slice-name>.md`
262
+ (kebab-cased to match, via the same slugging `em` uses everywhere else) with the canonical
263
+ `schemaVersion`/`pattern`/`swimlane`/`status: draft`/`version: 1` frontmatter — exactly the
264
+ five keys `em export` and the readiness gate require, no more — and the `# Slice:` heading +
265
+ diagram-image stub already in place. Both `--pattern` and `--swimlane` are required; an
266
+ invalid `--pattern` is refused with the valid choices listed. Never hand-type this block, and
267
+ never fall back to a placeholder pattern/swimlane to dodge the flags. Then fill in every
268
+ judgment section below the stub from step 1 (Intent, Command, Event(s), Invariants,
269
+ Scenarios, ...) — the doc's prose is still entirely hand-authored, only the frontmatter/
270
+ heading scaffold is mechanized. Record the originating need (ticket/conversation link) in the
271
+ Intent section when one exists. When this doc exists because of a split, merge, or rename,
272
+ add the matching lineage key(s) by hand (`split-from`/`merged-from`/`superseded-by`,
273
+ `<slice-key>@v<N>` grammar — see `docs/slice-doc-schema.md` for the full schema).
274
+ **Re-ratification (step 0):** the doc already exists, so `em slice new` doesn't apply here
275
+ (it refuses to overwrite an existing file without `--force`, and forcing would blow away the
276
+ doc's authored body) — bump `version` and flip `status` back to `ready-to-implement` by hand
277
+ in the existing frontmatter instead.
259
278
  3. Render the slice's own diagram: `em render <model>.em --slice "<slice name>" -o
260
- slices/<slice-name>.svg` (kebab-case, matching the doc's filename) — redraws just this slice
261
- in its own canonical pattern shape, and add `![Diagram](./<slice-name>.svg)` near the top of
262
- the doc, right after the `# Slice:` heading (below the frontmatter block).
263
- 4. Wire it into the `.em`: add `note "slices/<slice-name>.md"` to the slice's primary element
264
- (the command for State Change, the view for State View, the processor for Automation, the
265
- translation for Translation).
266
- 5. Update `README.md`'s slice index — the one canonical slice table (`draft` → `reviewed` →
267
- `ready-to-implement`, later `implemented` once shipped, with its Implemented-in link
268
- filled in).
279
+ slices/<slice-name>.svg` (kebab-case, matching the doc's filename and the `![Diagram]` stub
280
+ `em slice new` already wrote) — redraws just this slice in its own canonical pattern shape.
281
+ 4. Wire it into the `.em`: `em slice new` (step 2) printed the exact `note
282
+ "slices/<slice-name>.md"` line to add to the slice's primary element (the command for State
283
+ Change, the view for State View, the processor for Automation, the translation for
284
+ Translation) — `em slice new` only writes the new doc file, never edits the `.em` source
285
+ itself, so add that line by hand.
286
+ 5. Run `em slice index <model-name>.em` to regenerate `README.md`'s Slices table — the one
287
+ canonical slice index — from the model and the doc frontmatter you just wrote (status,
288
+ `implementedIn` once shipped). Never hand-edit the table; it's a generated block.
269
289
  6. Re-render and `em validate`.
270
290
 
271
291
  When a slice is **ratified** — a human flips its `status` to `ready-to-implement` with every
@@ -282,13 +302,14 @@ where the agent builds rather than facilitates.
282
302
  contract.** In short: gate on `em validate <model>.em --slice-ready <key>` (stop and hand
283
303
  back if it fails — never edit the doc to make the gate pass); treat the slice doc as the
284
304
  spec (read-only, except the merge-time `status`/`implementedIn` flip); surface every gap to
285
- the user instead of deciding it silently; cover every INV-n and every scenario with tests;
305
+ the user instead of deciding it silently; cover every INV-<MNEMONIC>-n and every scenario with tests;
286
306
  in spec-kit projects, allocate via em-sdd-bridge (redirect mode) and never run
287
307
  `/speckit.specify`.
288
308
 
289
309
  End of phase: PR merged, slice doc flipped to `status: implemented` with `implementedIn`
290
- filled, `README.md`'s slice index updated. Implement doesn't chain to another phase — run it
291
- once per ratified slice; `conform` later checks the result against the model.
310
+ filled, `em slice index <model-name>.em` run to refresh `README.md`'s Slices table. Implement
311
+ doesn't chain to another phase — run it once per ratified slice; `conform` later checks the
312
+ result against the model.
292
313
 
293
314
  ## Phase: `conform` — drift check against the codebase
294
315
 
@@ -300,31 +321,35 @@ and report where they've drifted — advisory only, never a gate, never an unpro
300
321
  stance guardrails (evidence-first, uncertainty is never drift, propose-don't-edit). It reuses
301
322
  `extract`'s sourcing/mode rules for reading the target codebase rather than duplicating them.
302
323
 
303
- In short: for each in-scope slice, gather code evidence *before* comparing to the model or doc;
304
- write the as-is picture into a scratch model (`<model-name>-asis.em`, reusing the canonical
305
- model's names wherever the code matches them); run `em diff <model-name>.em
324
+ In short: run `em conform-scope <model-name>.em --repo <target-repo-path> --seed-asis` to
325
+ compute the in-scope slice set (diff-scoped by default, via `Last conformance:` + the target
326
+ repo's changed paths mapped through each slice doc's `implementedIn:`) and seed the scratch
327
+ model in one step; for each in-scope slice, gather code evidence *before* comparing to the model
328
+ or doc; write the as-is picture into that scratch model (`<model-name>-asis.em`, reusing the
329
+ canonical model's names wherever the code matches them); run `em diff <model-name>.em
306
330
  <model-name>-asis.em --json` and let `em` decide the structural deltas; classify every finding
307
331
  (real drift / model gap / internal inconsistency / uncertainty) with cited evidence; write
308
332
  `conformance/<date>-report.md` with proposed `issue "conformance: …"` red notes; apply only the
309
- proposals the user ratifies, then re-render and validate; update the state file's
310
- `Last conformance:` marker.
333
+ proposals the user ratifies, then re-render and validate; run `em state set-conformance
334
+ <revision> --report <path>` to update the state file's `Last conformance:` marker.
311
335
 
312
- End of phase: state file's `Last conformance:` marker updated, Decisions log entry if any
336
+ End of phase: state file's `Last conformance:` marker updated (via `em state set-conformance`),
337
+ Decisions log entry if any
313
338
  proposals were applied. Conform doesn't chain to another phase — it's a recurring loop, run
314
339
  again whenever the codebase has moved.
315
340
 
316
341
  ## Phase: `watch` — live team view
317
342
 
318
- **Recommended (instant push, no polling):** start the watcher with `--serve` in the background:
343
+ Start the watcher with `--serve` in the background:
319
344
  `em watch <model-name>.em -o <model-name>.svg --serve` (run_in_background). It re-renders on every
320
345
  save and pushes an instant reload to the browser over Server-Sent Events. Tell the user to open the
321
346
  URL it prints (e.g. `http://localhost:5173/?svg=<model-name>.svg`) and share their screen — updates
322
- appear the moment you save, with no idle churn between edits.
347
+ appear the moment you save, with no polling and no idle churn between edits.
323
348
 
324
- **No-server fallback (`file://`):** if the user prefers not to run a server, start the plain watcher
325
- `em watch <model-name>.em -o <model-name>.svg` (run_in_background) and have them open the copied
326
- `live.html?svg=<model-name>.svg` in a browser. It polls every ~2s and reloads without flicker. No
327
- editing of `live.html` is needed — the `?svg=` query picks the model.
349
+ The viewer navigates like a map — drag to pan, scroll/pinch to zoom, **Fit** to reset — and its
350
+ **Review mode** steps through slices one at a time (see the `review` phase). A save that fails to
351
+ render never blanks the shared screen: the last good diagram stays up, an error banner explains
352
+ what went wrong, and the viewer recovers on its own at the next successful render.
328
353
 
329
354
  ## Phase: `review` — stakeholder walkthrough
330
355
 
@@ -349,8 +374,8 @@ losing the current slice or resetting review mode.
349
374
 
350
375
  Wrap-up: run `em validate --list-issues` to sweep everything captured during the session and
351
376
  walk each one with the user, same as any open issue. Update the state file's Participants
352
- section with who attended, and set a `Last stakeholder review:` marker (mirrors `Last
353
- conformance:`).
377
+ section with who attended, and run `em state set-review <date>` to set the `Last stakeholder
378
+ review:` marker (mirrors `Last conformance:`).
354
379
 
355
380
  End of phase: state file's `Last stakeholder review:` marker updated, every issue captured
356
381
  live triaged (resolved on the spot, moved to Open questions / parking lot, or left open on
@@ -393,16 +418,18 @@ command instead.
393
418
  ```bash
394
419
  em --version
395
420
  em init <name>.em # optional starter scaffold
421
+ em scaffold <name> # full project: <slug>/<slug>.em, README.md, .event-modeling.md
396
422
  em validate <name>.em # check rules; exit 0 if clean/warnings only
397
423
  em render <name>.em -o <name>.svg # render (svg/png/pdf by extension)
398
424
  em render <name>.em --emit-dot # inspect generated Graphviz DOT
399
425
  em render <name>.em --slice "<slice-name>" -o slices/<slug>.svg # this slice's own diagram
400
426
  em watch <name>.em -o <name>.svg # re-render on save (run in background)
401
- em watch <name>.em -o <name>.svg --serve # + live viewer with instant push-reload (--port N)
427
+ em watch <name>.em -o <name>.svg --serve # + the live browser viewer: instant push-reload, pan/zoom (--port N)
402
428
  # click "Review mode" for a slice-by-slice storyboard walkthrough
403
429
  ```
404
430
  <!-- GENERATED:cli-quick:end -->
405
431
 
406
432
  Always finish a working session by: re-rendering, running `em validate`, and updating
407
- `.event-modeling.md` with the current phase/step, decisions, open questions, and a Usage log
408
- entry (phases touched + validate diagnostic categories hit).
433
+ `.event-modeling.md` — `em state set-phase <phase> [--step <n>]` for the current phase/step,
434
+ decisions and open questions by hand, and a Usage log entry (phases touched + validate
435
+ diagnostic categories hit).
@@ -72,12 +72,34 @@ authoritative.
72
72
 
73
73
  ### 1. Scope
74
74
 
75
- Default: **diff-scoped.** Read the state file's `Last conformance:` marker (date + target-repo
76
- revision). If it's set, run `git diff --name-only <recorded-revision>..HEAD` from the target
77
- repo's root to list the changed paths (`git log` alone prints commit subjects, not paths), then
78
- map those paths to slices (via each slice doc's known code locations, `implementedIn:` links,
79
- or a quick Grep if those are stale) — that's your in-scope set. If the marker reads `never`
80
- (first run) or the user passes `--full`, scope is every `implemented` slice.
75
+ Run `em conform-scope <model-name>.em --repo <target-repo-path>` — it mechanizes everything
76
+ about scoping that's deterministic: parsing `Last conformance:` (via the same state-file reader
77
+ `em state read` uses), running `git diff --name-only <revision>..HEAD` in the target repo, and
78
+ mapping each changed path to a slice via that slice doc's `implementedIn:` link (a bare/embedded
79
+ repo-relative path that's a prefix of or equal to the changed path — a URL-only `implementedIn`,
80
+ e.g. a PR link, deterministically matches nothing). It prints one JSON document
81
+ (`docs/cli.md`'s conform-scope section documents the envelope):
82
+
83
+ ```json
84
+ { "lastConformance": { "date": "...", "revision": "..." } | null,
85
+ "changedPaths": ["..."],
86
+ "candidateSlices": [ { "key": "checkout", "matchedBy": "implementedIn", "paths": ["..."] } ],
87
+ "unmappedPaths": ["..."] }
88
+ ```
89
+
90
+ Default: **diff-scoped** — `lastConformance` set, `--full` not passed — `candidateSlices` is
91
+ your in-scope set for step 2. If `lastConformance` is `null` (first run) or you pass `--full`,
92
+ `em conform-scope` scopes every `implemented` slice instead (`matchedBy: "full"`,
93
+ `changedPaths`/`unmappedPaths` both empty) — the tool makes this call for you, no need to
94
+ special-case it yourself.
95
+
96
+ **`unmappedPaths` is your judgment queue, not a dead end.** A changed path the tool couldn't
97
+ place mechanically (`implementedIn` stale, a URL-only link, code that moved) still might belong
98
+ to an in-scope slice — a quick Grep for the path's obvious symbols against the slice docs/model
99
+ vocabulary is exactly the judgment call this phase reserves for you (`em conform-scope` never
100
+ guesses on purpose). Fold anything you place this way into your in-scope set alongside
101
+ `candidateSlices`; leave genuinely unplaceable paths out of scope but note them in the report's
102
+ run metadata rather than silently dropping them.
81
103
 
82
104
  Cost containment here is cadence, not a trigger condition — diff-scoped-by-default is what
83
105
  keeps a recurring conform run cheap; don't invent a smarter trigger.
@@ -125,9 +147,11 @@ For each slice in scope:
125
147
  without-link"` (status: implemented, no link at all) is a genuine coherence problem, but
126
148
  it's already surfaced by `em validate`'s `frontmatter-coherence-implemented-without-link`
127
149
  warning — don't re-raise it here as a separate conform finding.
128
- 3. Write what you found into the scratch model (`<model-name>-asis.em`, see below). **Seed the
129
- scratch model as a copy of the canonical `.em` and replace only the in-scope slices** with
130
- the as-is picture, leaving out-of-scope slices byte-identical. This is not an optimization:
150
+ 3. Write what you found into the scratch model (`<model-name>-asis.em`, see below) — start it
151
+ with `em conform-scope <model-name>.em --repo <target-repo-path> --seed-asis`, which
152
+ byte-copies the canonical `.em` to `<model-name>-asis.em` and ensures `*-asis.em` is
153
+ gitignored (idempotent — safe to pass on every run). **Then replace only the in-scope
154
+ slices** with the as-is picture, leaving out-of-scope slices byte-identical. This is not an optimization:
131
155
  `em diff` matches slices by name, so a scratch model containing *only* the in-scope slices
132
156
  reports every other canonical slice as `slice-removed` plus one `element-removed` per
133
157
  element — a phantom-removal flood on every diff-scoped run, which is the exact false drift
@@ -215,26 +239,27 @@ stays auditable) but don't ask the user to ratify what's already ratified. **You
215
239
  canonical model or a slice doc unprompted** — walk the report with the user, apply only the
216
240
  proposals they approve, then re-render and `em validate`.
217
241
 
218
- End of run: update the state file's `Last conformance:` marker, exact format:
242
+ End of run: update the state file's `Last conformance:` marker with
219
243
 
220
244
  ```
221
- - **Last conformance:** YYYY-MM-DD @ <target-repo revision> — report: conformance/YYYY-MM-DD-report.md
245
+ em state set-conformance <target-repo revision> --report conformance/YYYY-MM-DD-report.md
222
246
  ```
223
247
 
224
- The revision is the one you just diffed against, so the next run's scope starts from here —
225
- step 1 parses this line, so keep the format exact. **The marker only advances with the human
226
- in the loop**: in an interactive session, update it after walking the report with the user; a
227
- headless/scheduled run writes the report but never the marker (nobody ratified the outcome),
228
- so the next run re-walks the same span — see `docs/ci.md`. If any proposals were ratified and
229
- applied, log a Decisions entry noting what changed and why.
248
+ — the revision is the one you just diffed against, so the next run's scope starts from here.
249
+ The command writes the exact format step 1 parses back out; never hand-edit the bullet.
250
+ **The marker only advances with the human in the loop**: in an interactive session, run it
251
+ after walking the report with the user; a headless/scheduled run writes the report but never
252
+ the marker (nobody ratified the outcome), so the next run re-walks the same span — see
253
+ `docs/ci.md`. If any proposals were ratified and applied, log a Decisions entry noting what
254
+ changed and why.
230
255
 
231
256
  ## Conventions
232
257
 
233
258
  - **Scratch model:** `<model-name>-asis.em`, written **next to** the canonical model (same
234
259
  directory as `.event-modeling.md`). Always seeded as a copy of the canonical model with only
235
- the in-scope slices rewritten (step 2), never built up from nothing. It's regenerated every
236
- conform run — add the pattern `*-asis.em` to the repository's `.gitignore` (create the entry
237
- if there isn't one) so it never gets committed.
260
+ the in-scope slices rewritten (step 2) — `em conform-scope --seed-asis` does the seeding and
261
+ the gitignoring (`*-asis.em`, idempotent) mechanically, never built up from nothing and never
262
+ hand-maintained. It's regenerated every conform run.
238
263
  - **Report location:** `conformance/<YYYY-MM-DD>-report.md` in the model directory. One file
239
264
  per run; don't overwrite a prior date's report.
240
265
  - **Red note wording:** `issue "conformance: <what's wrong, plainly>"` — plain enough that