@milehimikey/em 1.11.0 → 1.13.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.
Files changed (154) hide show
  1. package/.claude/skills/event-modeling/SKILL.md +4 -2
  2. package/.claude/skills/event-modeling-conform/SKILL.md +20 -9
  3. package/.claude/skills/event-modeling-conform/reference/conform.md +107 -10
  4. package/.claude/skills/event-modeling-design/SKILL.md +22 -6
  5. package/.claude/skills/event-modeling-discover/SKILL.md +1 -1
  6. package/.claude/skills/event-modeling-implement/SKILL.md +12 -6
  7. package/.claude/skills/event-modeling-implement/reference/implement.md +165 -18
  8. package/.claude/skills/event-modeling-review/SKILL.md +5 -1
  9. package/.claude/skills/event-modeling-shared/reference/em-dsl.md +57 -8
  10. package/.claude/skills/event-modeling-shared/reference/operating-principles.md +13 -3
  11. package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +69 -0
  12. package/.claude/skills/event-modeling-shared/templates/conformance-report.md +8 -1
  13. package/.claude/skills/event-modeling-shared/templates/constitution.md +8 -1
  14. package/.claude/skills/event-modeling-shared/templates/state.md +3 -0
  15. package/README.md +1 -0
  16. package/dist/catalog/build.js +42 -1
  17. package/dist/catalog/build.js.map +1 -1
  18. package/dist/catalog/coverage.d.ts +15 -0
  19. package/dist/catalog/coverage.js +34 -0
  20. package/dist/catalog/coverage.js.map +1 -0
  21. package/dist/catalog/docJoin.d.ts +20 -2
  22. package/dist/catalog/docJoin.js +32 -4
  23. package/dist/catalog/docJoin.js.map +1 -1
  24. package/dist/catalog/docModelConsistencyValidate.js +1 -1
  25. package/dist/catalog/docModelConsistencyValidate.js.map +1 -1
  26. package/dist/catalog/driftSignal.d.ts +11 -5
  27. package/dist/catalog/driftSignal.js +18 -4
  28. package/dist/catalog/driftSignal.js.map +1 -1
  29. package/dist/catalog/modelVersionValidate.d.ts +9 -0
  30. package/dist/catalog/modelVersionValidate.js +38 -0
  31. package/dist/catalog/modelVersionValidate.js.map +1 -0
  32. package/dist/catalog/noteBindingValidate.js +18 -0
  33. package/dist/catalog/noteBindingValidate.js.map +1 -1
  34. package/dist/catalog/orphanedSliceDocValidate.d.ts +8 -1
  35. package/dist/catalog/orphanedSliceDocValidate.js +33 -6
  36. package/dist/catalog/orphanedSliceDocValidate.js.map +1 -1
  37. package/dist/catalog/pages.d.ts +16 -1
  38. package/dist/catalog/pages.js +16 -4
  39. package/dist/catalog/pages.js.map +1 -1
  40. package/dist/catalog/sliceDoc.d.ts +12 -0
  41. package/dist/catalog/sliceDoc.js +15 -0
  42. package/dist/catalog/sliceDoc.js.map +1 -1
  43. package/dist/catalog/sliceReadyValidate.d.ts +12 -1
  44. package/dist/catalog/sliceReadyValidate.js +4 -4
  45. package/dist/catalog/sliceReadyValidate.js.map +1 -1
  46. package/dist/cli/agentsMd.js +9 -3
  47. package/dist/cli/agentsMd.js.map +1 -1
  48. package/dist/cli/ciInit.js +20 -0
  49. package/dist/cli/ciInit.js.map +1 -1
  50. package/dist/cli/conformScope.d.ts +1 -0
  51. package/dist/cli/conformScope.js +13 -4
  52. package/dist/cli/conformScope.js.map +1 -1
  53. package/dist/cli/conformSupersede.d.ts +24 -2
  54. package/dist/cli/conformSupersede.js +44 -3
  55. package/dist/cli/conformSupersede.js.map +1 -1
  56. package/dist/cli/coverage.d.ts +34 -9
  57. package/dist/cli/coverage.js +61 -24
  58. package/dist/cli/coverage.js.map +1 -1
  59. package/dist/cli/findings.d.ts +134 -0
  60. package/dist/cli/findings.js +355 -0
  61. package/dist/cli/findings.js.map +1 -0
  62. package/dist/cli/markImplemented.js +12 -1
  63. package/dist/cli/markImplemented.js.map +1 -1
  64. package/dist/cli/metrics.d.ts +93 -0
  65. package/dist/cli/metrics.js +331 -0
  66. package/dist/cli/metrics.js.map +1 -0
  67. package/dist/cli/modelVersion.d.ts +139 -0
  68. package/dist/cli/modelVersion.js +256 -0
  69. package/dist/cli/modelVersion.js.map +1 -0
  70. package/dist/cli/ratify.js +17 -1
  71. package/dist/cli/ratify.js.map +1 -1
  72. package/dist/cli/reratify.d.ts +17 -0
  73. package/dist/cli/reratify.js +37 -2
  74. package/dist/cli/reratify.js.map +1 -1
  75. package/dist/cli/review.js +12 -1
  76. package/dist/cli/review.js.map +1 -1
  77. package/dist/cli/skillCheck.js +2 -2
  78. package/dist/cli/skillCheck.js.map +1 -1
  79. package/dist/cli/sliceConform.d.ts +50 -0
  80. package/dist/cli/sliceConform.js +206 -0
  81. package/dist/cli/sliceConform.js.map +1 -0
  82. package/dist/cli/sliceIndex.d.ts +2 -0
  83. package/dist/cli/sliceIndex.js +24 -7
  84. package/dist/cli/sliceIndex.js.map +1 -1
  85. package/dist/cli/sliceLink.js +16 -0
  86. package/dist/cli/sliceLink.js.map +1 -1
  87. package/dist/cli/sliceNew.d.ts +12 -0
  88. package/dist/cli/sliceNew.js +23 -0
  89. package/dist/cli/sliceNew.js.map +1 -1
  90. package/dist/cli/sliceStubAll.d.ts +76 -0
  91. package/dist/cli/sliceStubAll.js +189 -0
  92. package/dist/cli/sliceStubAll.js.map +1 -0
  93. package/dist/cli/stateFile.d.ts +63 -7
  94. package/dist/cli/stateFile.js +179 -18
  95. package/dist/cli/stateFile.js.map +1 -1
  96. package/dist/cli/status.d.ts +90 -1
  97. package/dist/cli/status.js +151 -16
  98. package/dist/cli/status.js.map +1 -1
  99. package/dist/cli/upgrade.d.ts +122 -0
  100. package/dist/cli/upgrade.js +476 -0
  101. package/dist/cli/upgrade.js.map +1 -0
  102. package/dist/cli.js +586 -66
  103. package/dist/cli.js.map +1 -1
  104. package/dist/emit/coverageJson.d.ts +2 -2
  105. package/dist/emit/coverageJson.js +6 -2
  106. package/dist/emit/coverageJson.js.map +1 -1
  107. package/dist/emit/freshnessJson.d.ts +1 -1
  108. package/dist/emit/freshnessJson.js +3 -1
  109. package/dist/emit/freshnessJson.js.map +1 -1
  110. package/dist/emit/json.d.ts +34 -1
  111. package/dist/emit/json.js +84 -2
  112. package/dist/emit/json.js.map +1 -1
  113. package/dist/emit/metricsJson.d.ts +7 -0
  114. package/dist/emit/metricsJson.js +27 -0
  115. package/dist/emit/metricsJson.js.map +1 -0
  116. package/dist/emit/statusJson.d.ts +1 -1
  117. package/dist/emit/statusJson.js +22 -1
  118. package/dist/emit/statusJson.js.map +1 -1
  119. package/dist/emit/upgradeJson.d.ts +5 -0
  120. package/dist/emit/upgradeJson.js +26 -0
  121. package/dist/emit/upgradeJson.js.map +1 -0
  122. package/dist/emit/validateJson.d.ts +10 -5
  123. package/dist/emit/validateJson.js +22 -8
  124. package/dist/emit/validateJson.js.map +1 -1
  125. package/dist/mcp/server.d.ts +1 -1
  126. package/dist/mcp/server.js +151 -22
  127. package/dist/mcp/server.js.map +1 -1
  128. package/dist/model/continuation.d.ts +23 -0
  129. package/dist/model/continuation.js +49 -0
  130. package/dist/model/continuation.js.map +1 -0
  131. package/dist/model/queryIndex.js +1 -1
  132. package/dist/model/queryIndex.js.map +1 -1
  133. package/dist/model/rules.d.ts +13 -0
  134. package/dist/model/rules.js +18 -0
  135. package/dist/model/rules.js.map +1 -1
  136. package/dist/model/sliceDocIndex.d.ts +12 -5
  137. package/dist/model/sliceDocIndex.js +18 -7
  138. package/dist/model/sliceDocIndex.js.map +1 -1
  139. package/dist/model/validate.d.ts +20 -0
  140. package/dist/model/validate.js +94 -45
  141. package/dist/model/validate.js.map +1 -1
  142. package/dist/render/sliceStatus.d.ts +3 -3
  143. package/dist/render/sliceStatus.js +27 -29
  144. package/dist/render/sliceStatus.js.map +1 -1
  145. package/dist/templates.d.ts +3 -3
  146. package/dist/templates.js +15 -2
  147. package/dist/templates.js.map +1 -1
  148. package/dist/util/localDate.d.ts +2 -0
  149. package/dist/util/localDate.js +17 -0
  150. package/dist/util/localDate.js.map +1 -0
  151. package/dist/util/semver.d.ts +19 -0
  152. package/dist/util/semver.js +54 -0
  153. package/dist/util/semver.js.map +1 -0
  154. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling
3
- em-version: 1.11.0
3
+ em-version: 1.13.0
4
4
  description: >-
5
5
  Use when the user runs `/event-modeling` (with or without a phase name), or wants to resume an
6
6
  event-modeling session without specifying which part of the process applies. Reads the model's
@@ -30,7 +30,9 @@ phase lives in.
30
30
  ## Routing logic
31
31
 
32
32
  1. Check the tool: `em --version`. If missing, tell the user to run `npm i -g @milehimikey/em`
33
- and stop until installed.
33
+ and stop until installed. Then check this vendored bundle's own currency against it — see
34
+ `../event-modeling-shared/reference/operating-principles.md`'s Preconditions step 2: a bundle
35
+ more than a minor version stale is a STOP, not a warning.
34
36
  2. Parse `$ARGUMENTS` for a phase name.
35
37
  - **A recognized phase name** (`discover`, `extract`, `model`, `slice`, `implement`,
36
38
  `conform`, `validate`, `watch`, `review`): look it up in the table above and invoke that
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-conform
3
- em-version: 1.11.0
3
+ em-version: 1.13.0
4
4
  description: >-
5
5
  Use when checking a ratified event model (and its slice docs) for drift against the codebase
6
6
  that implements it — advisory only, never a gate, never an unprompted edit — or when walking
@@ -33,18 +33,29 @@ or doc; write the as-is picture into that scratch model (`<model-name>-asis.em`,
33
33
  canonical model's names wherever the code matches them); run `em diff <model-name>.em
34
34
  <model-name>-asis.em --json` and let `em` decide the structural deltas; classify every finding
35
35
  (real drift / model gap / internal inconsistency / uncertainty) with cited evidence; write
36
- `conformance/<date>-report.md` with proposed `issue "conformance: …"` red notes; apply only the
37
- proposals the user ratifies, then re-render and validate; run `em state set-conformance
38
- <revision> --report <path>` to update the state file's `Last conformance:` marker.
36
+ `conformance/<date>-report.md` **and its structured twin `conformance/<date>-findings.json`**
37
+ (one entry per finding, `em conform-findings check <path>` to verify) with proposed `issue
38
+ "conformance: …"` red notes; apply only the proposals the user ratifies, then re-render and
39
+ validate; run `em state set-conformance <revision> --report <path>` to update the state file's
40
+ `Last conformance:` marker.
39
41
 
40
42
  Ruling on a finding is a human gate, like ratifying a slice
41
43
  (docs/process.md#the-slice-lifecycle-gates): the sweep gathers evidence and proposes, a person
42
- decides, and `em state set-conformance` records the decision — never run it on your own judgment.
44
+ decides, and `em conform-supersede ... --locus <model|doc|code|none> --by <name>` records the
45
+ ruling on the findings record (and stamps the report) — never rule on your own judgment. Once
46
+ every finding touching a slice is ruled, `em slice conform <model-name>.em <key> --at <rev>`
47
+ certifies that version of the slice.
43
48
 
44
- End of phase: state file's `Last conformance:` marker updated (via `em state set-conformance`),
45
- Decisions log entry if any
46
- proposals were applied. Conform doesn't chain to another phase — it's a recurring loop, run
47
- again whenever the codebase has moved.
49
+ End of phase: state file's `Last conformance:` marker updated (via `em state set-conformance` —
50
+ refuses while any `implemented` slice still has an unruled finding; `--partial` escapes with a
51
+ loud notice), Decisions log entry if any proposals were applied. Conform doesn't chain to
52
+ another phase — it's a recurring loop, run again whenever the codebase has moved.
53
+
54
+ A full (non-`--partial`) `em state set-conformance` also **certifies the model's current design
55
+ version** (MIL-218, `docs/process.md#model-versions`) — it refuses if no design version has ever
56
+ been bumped ("bump a model version first") or if the model changed during this run without a
57
+ re-bump; run `em model version bump <model-name>.em --by <name>` before the final `em state
58
+ set-conformance` call if either applies.
48
59
 
49
60
  ## Phase: `validate`
50
61
 
@@ -234,10 +234,22 @@ step 2 — sorts into exactly one class:
234
234
  which finding. Cite `slice.doc.driftSignal` and `slice.doc.version` together as evidence.
235
235
  - **Extraction uncertainty** — no evidence either way. Never reported as drift or a gap.
236
236
 
237
+ **Read-model exposure (MIL-215).** Two rulings apply the classes above to a `view`'s exposure —
238
+ whether it ships a query endpoint — instead of leaving each case to fresh judgment:
239
+
240
+ - An **internal view** (no `ui` reads it, and it isn't marked `public`) implemented as
241
+ criteria-sourced state (a reaction's own read, no materialized projection — the general idiom
242
+ step 2 already names) or as an unexposed projection is **Conformant, never dead code to
243
+ flag**. It's the read operation the model draws to say an automation or translation *must*
244
+ read, not an endpoint promise; don't propose deleting it.
245
+ - An **endpoint in code on a view the model shows no `ui` reading and no `public` marking** is a
246
+ **Model gap** — "add the `ui` or remove the endpoint" — **never Real drift to delete**.
247
+ Nobody decided whether that view is exposed; deleting the code decides it for them.
248
+
237
249
  Every classification must cite the evidence recorded in step 2 (or the `em diff` entry, for
238
250
  structural findings) — a finding with no citation isn't ready to report.
239
251
 
240
- ### 5. Report + proposals
252
+ ### 5. Report + findings record + proposals
241
253
 
242
254
  Write `conformance/<YYYY-MM-DD>-report.md` in the model directory, from
243
255
  `../../event-modeling-shared/templates/conformance-report.md`. For a real-drift or model-gap finding, propose a
@@ -250,6 +262,71 @@ stays auditable) but don't ask the user to ratify what's already ratified. **You
250
262
  canonical model or a slice doc unprompted** — walk the report with the user, apply only the
251
263
  proposals they approve, then re-render and `em validate`.
252
264
 
265
+ **Also write the findings JSON (MIL-214).** Alongside the report, write
266
+ `conformance/<YYYY-MM-DD>-findings.json` — one entry per `### n.` finding, ids matching the
267
+ report's own numbering. Shape (`findingsSchemaVersion: "1.0"`, additive-only, 2-space indent,
268
+ keys sorted, findings sorted by `id`, trailing newline):
269
+
270
+ ```json
271
+ {
272
+ "findingsSchemaVersion": "1.0",
273
+ "model": "checkout.em",
274
+ "report": "conformance/YYYY-MM-DD-report.md",
275
+ "revision": "<target-repo revision>",
276
+ "findings": [
277
+ {
278
+ "id": 1,
279
+ "surface": "structural",
280
+ "class": "Real drift",
281
+ "slice": "checkout",
282
+ "evidence": "code shows X at path/to/File.kt:42",
283
+ "locus": null,
284
+ "resolvedBy": null,
285
+ "resolvedOn": null
286
+ }
287
+ ]
288
+ }
289
+ ```
290
+
291
+ `surface` is one of `structural` (`.em` <-> code — step 3's diff), `spec` (slice doc <-> code —
292
+ step 2's invariant/scenario walk), `internal` (slice doc <-> `.em` — step 2's `doc-model-*`
293
+ diagnostics), or `other`. `class` is the step-4 classification verbatim (Real drift, Model gap,
294
+ Internal inconsistency, Accepted divergence, Unpropagated delta, Extraction uncertainty). `slice`
295
+ is the concerned slice's export key, or `null` for a finding that isn't attributable to one
296
+ (counts as in-scope for every slice's unruled-findings check). `locus`/`resolvedBy`/`resolvedOn`
297
+ start `null` — a later `em conform-supersede --locus --by` call fills them in once a human rules.
298
+ Run `em conform-findings check conformance/YYYY-MM-DD-findings.json` before ending the session —
299
+ a headless run's mechanical proof it wrote a valid record.
300
+
301
+ **Ruling on a finding (MIL-214) — once the user decides.** Run, per finding or batch of findings
302
+ ruled the same way:
303
+
304
+ ```
305
+ em conform-supersede <model-name>.em conformance/YYYY-MM-DD-report.md --as-of <target-repo revision> \
306
+ --findings <spec> --locus <model|doc|code|none> --by <name>
307
+ ```
308
+
309
+ — this records `locus`/`resolvedBy`/`resolvedOn` on the named findings in the JSON (refusing to
310
+ silently overwrite an already-different `locus`) AND stamps the report's "superseded as of `<rev>`"
311
+ banner in the same call (see below). `locus: code` on an unresolved finding is the carrier for
312
+ "the spec is right, the code is wrong" — no doc delta required for that case any more; `locus:
313
+ model` means fix the `.em` (apply the proposed red note, or a stronger edit the user chose
314
+ instead); `locus: doc` means the slice doc needs a delta/re-ratification; `locus: none` covers
315
+ Accepted divergence/Unpropagated delta/Extraction uncertainty, where nothing needs to change.
316
+
317
+ **Certifying a slice, once every finding touching it is ruled (MIL-214).** For each in-scope
318
+ slice with no unruled findings left:
319
+
320
+ ```
321
+ em slice conform <model-name>.em <slice-key> --at <target-repo revision>
322
+ ```
323
+
324
+ — records `conformedVersion`/`conformedAt`/`conformedOn` on that slice's doc, so
325
+ `driftSignal` reads `in-sync` again (it reads `uncertified` for an implemented slice that's never
326
+ been through this) instead of just trusting `implementedIn`. Legal only for `status: implemented`
327
+ with a link, and itself refuses if an unruled finding for that slice still exists at this
328
+ revision — the mechanical proof this step comes only after rulings, not before.
329
+
253
330
  End of run: update the state file's `Last conformance:` marker with
254
331
 
255
332
  ```
@@ -258,14 +335,21 @@ em state set-conformance <target-repo revision> --report conformance/YYYY-MM-DD-
258
335
 
259
336
  — the revision is the one you just diffed against, so the next run's scope starts from here.
260
337
  The command writes the exact format step 1 parses back out; never hand-edit the bullet.
338
+ **Refuses (MIL-214) while any `implemented` slice still has an unruled finding** in the findings
339
+ JSON beside the report — rule on every finding first (or certify what's already ruled via `em
340
+ slice conform` above), or pass `--partial` to record the marker with a loud notice instead
341
+ (`notice: conformance marker recorded as PARTIAL — N finding(s) unruled`) when the team
342
+ deliberately wants to advance the marker without finishing every ruling this session.
261
343
  **The marker only advances with the human in the loop**: in an interactive session, run it
262
- after walking the report with the user; a headless/scheduled run writes the report but never
263
- the marker (nobody ratified the outcome), so the next run re-walks the same span — see
264
- `docs/ci.md`. If any proposals were ratified and applied, log a Decisions entry noting what
344
+ after walking the report with the user; a headless/scheduled run writes the report and findings
345
+ JSON but never the marker (nobody ratified the outcome), so the next run re-walks the same span —
346
+ see `docs/ci.md`. If any proposals were ratified and applied, log a Decisions entry noting what
265
347
  changed and why.
266
348
 
267
- **Superseding the report you just walked (MIL-164).** Once the user has ruled on this run's
268
- findings, also run:
349
+ **Superseding the report you just walked (MIL-164).** The `--locus`/`--by` call above already
350
+ stamps the report's banner in the same call when a ruling was recorded; if a finding's ruling
351
+ doesn't need `--locus`/`--by` recorded (a migration-path report predating the findings JSON, or
352
+ a ruling you're only banner-stamping after the fact), run the same command without them:
269
353
 
270
354
  ```
271
355
  em conform-supersede <model-name>.em conformance/YYYY-MM-DD-report.md --as-of <target-repo revision> --findings <spec>
@@ -298,10 +382,23 @@ each call adds its own stamp rather than overwriting the last.
298
382
  ## Completion & handoff
299
383
 
300
384
  Conform is complete when: every in-scope slice has been walked (step 2), the scratch model has
301
- been diffed (step 3), every finding is classified with cited evidence (step 4), the report is
302
- written (step 5), the state file's `Last conformance:` marker is updated, and the user has seen
303
- the report and said which proposals (if any) to apply. Applied proposals get re-rendered and
304
- re-validated before you call the run done.
385
+ been diffed (step 3), every finding is classified with cited evidence (step 4), the report AND
386
+ its findings JSON are written (step 5), the state file's `Last conformance:` marker is updated
387
+ (or deliberately left as `--partial`), and the user has seen the report and said which proposals
388
+ (if any) to apply and which findings resolve to which locus. Applied proposals get re-rendered
389
+ and re-validated before you call the run done.
390
+
391
+ A full (non-`--partial`) `em state set-conformance` does one more thing (MIL-218): it also
392
+ **certifies** the model's current design version — writes `certified: { at, on, report,
393
+ findings }` into that version's `model-versions/v<N>.json` manifest, and rewrites the state
394
+ file's `Certified:` bullet. This is the "conform ran clean against version N" fact a
395
+ stakeholder or a release note can point at. It only works on an already-**bumped** design
396
+ version — `em state set-conformance` refuses (pointing at `em model version bump`) if no
397
+ manifest exists yet, or if the model has drifted since the last bump (the certification would
398
+ otherwise name a version that isn't what conform actually walked). If the model changed during
399
+ this conform run (a slice's `version:` moved, or the `.em` file itself changed), bump a new
400
+ design version (`em model version bump --by <name>`) before the final `em state
401
+ set-conformance` call. `--partial` never certifies. See `docs/model-versions.md`.
305
402
 
306
403
  Conform doesn't chain to another phase automatically — it's a recurring loop, not a step in
307
404
  building the model. Suggest running it again next time the target codebase has moved, at
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-design
3
- em-version: 1.11.0
3
+ em-version: 1.13.0
4
4
  description: >-
5
5
  Use when structuring a draft event model into swimlanes and the four patterns (State Change,
6
6
  State View, Automation, Translation), evaluating a model's structural completeness, or writing
@@ -40,15 +40,22 @@ Goal: a structurally complete, **validated** model with correct patterns and swi
40
40
  slice, none skipped: `em slice new "<slice name>" --pattern <state-change|state-view|
41
41
  automation|translation> --swimlane "<Persona> → <Context>" --wire <model>.em` writes
42
42
  `slices/<slice-name>.md` at `status: draft` (the same command, flags, and `--wire`
43
- note-binding the `slice` phase's step 2 below documents in full). Then, for each freshly
44
- scaffolded doc, hold a first-pass Socratic pass and write the happy-path Given/When/Then into
43
+ note-binding the `slice` phase's step 2 below documents in full). A slice whose only element
44
+ is a `view X again` instance is a **continuation** (MIL-208), not a slice to scaffold —
45
+ `--wire` refuses it and names the originating slice holding `X`'s first declaration; its
46
+ scenarios go into that doc instead. Then, for each freshly scaffolded doc, hold a first-pass
47
+ Socratic pass and write the happy-path Given/When/Then into
45
48
  its `## Scenarios (Given / When / Then)` section and the obvious invariants known so far into
46
49
  its `## Invariants / Business Rules` section — **into the doc, never into the state file.**
47
50
  Keep this pass shallow (no field tables, alternate/error flows, or NFRs yet — that's the full
48
51
  deep-dive in the `slice` phase below); the docs are the home for everything collected from
49
52
  here on, not yet implementation-ready specs. Because every doc already exists by the time the
50
53
  `slice` phase begins, its own step 2 scaffolding call is then a no-op — that phase picks up
51
- at its step 1's deeper pass.
54
+ at its step 1's deeper pass. For a purely exploratory/backbone-mapping model that only needs
55
+ status coloring right now (not a full spec per slice yet), `em slice stub-all <model>.em` is
56
+ the one-command fast path: a near-free stub per undocumented slice, wired, in slice order
57
+ (MIL-184) — skip the per-slice `em slice new` calls above and deepen individual docs later
58
+ when the team is ready.
52
59
  3. **Evaluate completeness (step 7).** Walk the model: every slice is a **complete** pattern, not a
53
60
  half-slice — **every command has something that triggers it**, every command emits an event,
54
61
  **every event is read by a read model**, **every read model has a consumer**, every view has a
@@ -60,6 +67,10 @@ Goal: a structurally complete, **validated** model with correct patterns and swi
60
67
  For an unread event, don't just bolt on a view to silence the warning: ask the user who looks at
61
68
  this fact and what they do with it. The honest answers are "here's the read model we missed" or
62
69
  "nobody — so why are we recording it", and both improve the model.
70
+ **Per `view`, also ask who reads it (MIL-215):** a person or client reads it → draw the `ui`
71
+ that reads it; another model/system reads it → mark it `public`; only an automation reads
72
+ it → nothing, it's internal by design. No new keyword — reachability is already what `ui` and
73
+ `public` mean.
63
74
 
64
75
  End of phase: render, update state (`em state set-phase slice` — the mechanical marker the state
65
76
  machine expects), and stop. Every slice already has a draft doc ready to receive the deep spec,
@@ -115,6 +126,9 @@ For each slice:
115
126
  "slices/<slice-name>.md"` line straight into the `.em`, onto the slice's primary element (the
116
127
  command for State Change, the view for State View, the processor for Automation, the
117
128
  translation for Translation), matched by export key — see step 4 for when it refuses instead.
129
+ A slice whose sole candidate view is a later `view X again` instance is a **continuation**
130
+ (MIL-208): `--wire` refuses it and names the originating slice holding `X`'s first
131
+ declaration — write this slice's scenarios into that doc instead of scaffolding a new one.
118
132
  Both `--pattern` and `--swimlane` are required; an invalid `--pattern` is refused with the
119
133
  valid choices listed. Never hand-type this block, and never fall back to a placeholder
120
134
  pattern/swimlane to dodge the flags. Then fill in every judgment section below the stub from
@@ -154,5 +168,7 @@ Before the project's first slice is implemented it also needs a ratified impleme
154
168
  constitution (stack, code style, testing norms, NFR baselines, review norms) — the
155
169
  `event-modeling-implement` skill elicits it, see its `reference/implement.md` §7.
156
170
 
157
- End of phase: every slice that should exist has a doc, `README.md`'s Slices table is current,
158
- and the model validates clean. Suggest `event-modeling-implement` for each ratified slice.
171
+ End of phase: every slice that should exist has a doc — except a continuation slice (MIL-208, a
172
+ later `view X again` instance), which has none by design and is documented by the originating
173
+ slice instead — `README.md`'s Slices table is current, and the model validates clean. Suggest
174
+ `event-modeling-implement` for each ratified slice.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-discover
3
- em-version: 1.11.0
3
+ em-version: 1.13.0
4
4
  description: >-
5
5
  Use when starting a brand-new event model from scratch — greenfield discovery: brainstorming
6
6
  past-tense events, storyboarding the happy path, finding the commands and read models — or when
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-implement
3
- em-version: 1.11.0
3
+ em-version: 1.13.0
4
4
  description: >-
5
5
  Use when building a single ratified event-modeling slice (status: ready-to-implement) into
6
6
  merged, tested code — the one phase where the agent builds rather than facilitates. Gates on
@@ -16,11 +16,17 @@ the agent builds rather than facilitates.
16
16
  **Read `reference/implement.md` before doing any implement work and follow it as the
17
17
  contract.** In short: gate on `em validate <model>.em --slice-ready <key>` (stop and hand
18
18
  back if it fails — never edit the doc to make the gate pass); read the project's implementation
19
- constitution before writing code and stay inside its rules; treat the slice doc as the
20
- spec (read-only, except the merge-time `status`/`implementedIn` flip); surface every gap to
21
- the user instead of deciding it silently; cover every `INV-<MNEMONIC>-n` and every scenario with
22
- tests; in spec-kit projects, allocate via em-sdd-bridge (redirect mode) and never run
23
- `/speckit.specify`.
19
+ constitution before writing code and stay inside its rules; before a project's first slice PR,
20
+ land a one-time foundation PR holding every model event (plus the shared interface shell) so
21
+ slices only ever import contracts, never invent or reach into a sibling's; build in dependency
22
+ order from `em query upstream`, not timeline order; treat the slice doc as
23
+ the spec (read-only, except the merge-time `status`/`implementedIn` flip); implement exactly one
24
+ slice doc per PR — a `covers:` doc's two keys ship together in that one PR, an `again` view
25
+ instance gets its own; ship the endpoint a
26
+ `ui`-triggered command or `ui`-consumed view obligates, and surface — never invent — one the
27
+ model doesn't show; surface every gap to the user instead of deciding it silently; cover every
28
+ `INV-<MNEMONIC>-n` and every scenario with tests; in spec-kit projects, allocate via
29
+ em-sdd-bridge (redirect mode) and never run `/speckit.specify`.
24
30
 
25
31
  **Gate: no constitution, no first slice.** The constitution is the project's ratified house rules
26
32
  — stack and architectural shape (including which implementation skill each slice pattern routes
@@ -26,18 +26,23 @@ em validate <model>.em --slice-ready <slice-key> --json
26
26
  ```
27
27
 
28
28
  `<slice-key>` is the slice's export key — the kebab-case slug of its name (`"Place Order"` →
29
- `place-order`). Read the JSON document's `ready` field — don't infer it from the exit code or
30
- any printed text. `ready: true` means: the slice has a doc bound via `note "slices/<key>.md"`,
31
- its frontmatter is usable, `status: ready-to-implement`, every `## Open Questions` checkbox is
32
- checked, and no status/version/link incoherence is flagged — `gates` names each of those 4
33
- conditions individually (`docBound`/`frontmatterUsable`/`statusReady`/
34
- `noUncheckedOpenQuestions`) if you need to say which one is blocking.
35
-
36
- **`ready: false` means stop.** Report which `gates` entries are `false` (and any `diagnostics`
37
- entries concerning this slice) and hand the slice back to the humans. Never make the gate pass
38
- yourself — checking an open-question box, flipping `status`, or editing frontmatter are
39
- ratification decisions, and ratification happens in a facilitated session, not in an
40
- implementation branch.
29
+ `place-order`). Don't guess it or hand-slug the name yourself: list every slice's key with
30
+ `em export <model>.em | jq -r '.model.slices[].key'`. Read the JSON document's `ready` field —
31
+ don't infer it from the exit code or any printed text. `ready: true` means: the slice has a doc
32
+ bound via `note "slices/<key>.md"`, its frontmatter is usable, `status: ready-to-implement`,
33
+ every `## Open Questions` checkbox is checked, and no status/version/link incoherence is flagged
34
+ — `gates` names each of those 4 conditions individually (`docBound`/`frontmatterUsable`/
35
+ `statusReady`/`noUncheckedOpenQuestions`) if you need to say which one is blocking.
36
+
37
+ **`ready: false` means stop** — with one named exception: a slice already `status: implemented`
38
+ with `driftSignal: in-sync` or `uncertified` (MIL-214) also reads `ready: false` (its
39
+ `statusReady` gate fails because nothing is newly ratified), and that specific case is
40
+ re-implementation/repair, not a blocker — see §3's third mode before treating it as one. For
41
+ every other `false`, report which `gates`
42
+ entries are `false` (and any `diagnostics` entries concerning this slice) and hand the slice
43
+ back to the humans. Never make the gate pass yourself — checking an open-question box, flipping
44
+ `status`, or editing frontmatter are ratification decisions, and ratification happens in a
45
+ facilitated session, not in an implementation branch.
41
46
 
42
47
  ## 2. Read the spec
43
48
 
@@ -68,18 +73,44 @@ Then read `slices/<slice-key>.md` end to end — every section is load-bearing:
68
73
  | `## Non-Functional Requirements` | Authz, PII, performance — implement or consciously surface, never skip |
69
74
  | `## Dependencies & Read Models Affected` | The blast radius — what else to check before and after |
70
75
 
76
+ **Interface obligations follow from the model, not from the doc's prose.** The DSL already
77
+ encodes what's reachable — see `em-dsl.md`'s "Headless / API systems & repeated read models"
78
+ section — and the routing from it is mechanical, not a technical choice you make while coding:
79
+
80
+ - A **command with a `ui` trigger** ships the endpoint that dispatches it as part of this slice
81
+ — shape, verb, status codes, and error mapping follow the constitution's interface conventions
82
+ (§7). Because: the model already said this command is reachable from outside; leaving it
83
+ reachable only through an internal gateway silently narrows what the model ratified.
84
+ - A **view with a `ui` consumer** ships the query endpoint as part of this slice, same
85
+ conventions.
86
+ - **No `ui`** on the trigger or the consumer (a command dispatched by a processor or a
87
+ translation, a view read only by a reaction) means internal-only: no endpoint. If one seems
88
+ needed anyway, that's a gap to surface (§4), not a technical choice to make mid-implementation
89
+ — adding a route the model doesn't show is exactly the kind of silent divergence §4 exists to
90
+ catch. An endpoint on a view the model shows no `ui` reading is a gap to surface the same way
91
+ (MIL-215) — conform will classify it as a **model gap**, never drift to delete, once you flag
92
+ it (`../../event-modeling-conform/reference/conform.md`, Flow step 4).
93
+ - **`public` events and views** are the model's published integration surface: their shape is a
94
+ contract, not an implementation detail. `em validate --list-public` lists them; `em typespec`
95
+ is the POC generator for a downstream schema. Changing a public element's shape is a ratified
96
+ delta, never an implementation-time choice.
97
+
71
98
  For timeline context, read the slice's surroundings in the `.em` (what triggers it, what
72
99
  consumes its output) — the slice's own diagram (`slices/<slice-key>.svg`) shows its canonical
73
100
  pattern shape. For machine-readable facts, use `em export <model>.em --slice <slice-key>`
74
101
  rather than parsing the DSL or the doc's frontmatter yourself: it returns just this slice's
75
102
  object — `pattern`, element refs, fields, and the joined doc metadata (`slice.doc.status`,
76
103
  `version`, `driftSignal`) — without piping the whole model's export to find one `slice.doc`.
104
+ When the view repeats later via `again` (MIL-208), that same call on the *originating* slice
105
+ also returns `alsoReads: [{ event, atSlice }]` — the union of every event the read model
106
+ consumes across all its later continuations, in timeline order — so implementing it never means
107
+ walking each continuation by hand to assemble the full event list.
77
108
 
78
109
  If the project ships pattern-specific implementation skills (for example an Axon/DCB skill
79
110
  set keyed on a slice doc's `pattern:` frontmatter), route by the slice's pattern and follow
80
111
  those.
81
112
 
82
- ## 3. Two modes: first version vs. ratified delta
113
+ ## 3. Three modes: first version, ratified delta, re-implementation/repair
83
114
 
84
115
  Check the doc's `version:` and `## Delta` section (or `em export`'s `slice.doc.driftSignal`):
85
116
 
@@ -93,6 +124,29 @@ Check the doc's `version:` and `## Delta` section (or `em export`'s `slice.doc.d
93
124
  **Never regenerate merged code wholesale from the model** — after merge, code is owned by
94
125
  the people who've edited it (generated-then-owned); regeneration is legal only for slices
95
126
  whose code never merged.
127
+ - **Re-implementation / repair** (`status: implemented`, `implementedIn` set, `driftSignal:
128
+ in-sync` **or** `uncertified` (MIL-214 — certification status is orthogonal to whether the doc
129
+ changed; most shipped slices sit at `uncertified` until a conform sweep certifies them, which
130
+ doesn't change which mode this is) — `--slice-ready` reports `ready: false` purely because
131
+ `statusReady` fails, with no other gate false and no doc content changed): the doc hasn't
132
+ changed, but the shipped code
133
+ needs rebuilding or fixing — deleted code, a reverted PR, a bug in behavior the doc already
134
+ specifies. **The doc is still the spec.** The gate's `false` here means "nothing new is
135
+ ratified," not "stop" — it is not license to self-initiate: proceed only when a human has
136
+ asked for this specific re-work. Scope the change to what the repair needs, exactly like a
137
+ delta (generated-then-owned still applies — don't regenerate the whole slice wholesale just
138
+ because the gate reads oddly); if what you'd change is really a change in behavior rather than
139
+ a repair of it, that's a ratified delta (the bullet above), not this mode — when unsure which
140
+ one you're in, ask the human rather than guess.
141
+
142
+ No lifecycle flip is needed unless `implementedIn` changes. If it does,
143
+ `em slice mark-implemented <model>.em <slice-key> <new-pr-url>` will **refuse** rather than
144
+ overwrite: a doc already `implemented` with a different `implementedIn` URL is left untouched
145
+ and the command reports the conflict (`src/cli/markImplemented.ts`) instead of silently
146
+ replacing provenance. That refusal is correct, not a bug to route around — never hand-edit the
147
+ frontmatter to force it through. Surface the conflict to the human instead: they decide whether
148
+ the new PR supersedes the recorded one (and re-run `mark-implemented` themselves, or ask you to,
149
+ once they've decided) or whether the existing link should stand.
96
150
 
97
151
  ## 4. Gaps: propose, never decide
98
152
 
@@ -114,6 +168,20 @@ undocumented ordering, a contradiction with adjacent code. The discipline:
114
168
 
115
169
  ## 5. Definition of done
116
170
 
171
+ **The unit is the slice doc: one slice doc = one PR.** A doc that `covers:` another slice (an
172
+ automation's to-do-list view and its reaction, MIL-121) is one spec, not two — it ships in one
173
+ PR, and `mark-implemented` runs for both keys against the same URL. A read model is one doc,
174
+ even when a `view X again` clause repeats it across later positions on the timeline (MIL-208):
175
+ the later instance is a **continuation** of the slice holding `X`'s first declaration, not a
176
+ spec unit of its own — no doc, no status, no ratification, no PR of its own. Its behavior
177
+ belongs in the originating doc's `## Scenarios` (one scenario per event the later instance
178
+ feeds), not a doc of its own; `em export --slice <originating-key>` lists the full union of
179
+ events the read model consumes across every position via `alsoReads` (§2). Never fold multiple
180
+ slice docs' implementations into one PR because they touch the same read model, ship together,
181
+ or seem small — see §10.
182
+
183
+ - The PR description cites exactly one slice doc (plus its `covers:` keys, if any) and lists
184
+ that doc's invariants alongside the tests that cover them.
117
185
  - Every `INV-<MNEMONIC>-n` invariant has at least one test that cites its ID — checked mechanically by
118
186
  `em coverage <model>.em --tests <dir>` (MIL-130); run it (add `--strict` in CI) rather than
119
187
  eyeballing citations by hand.
@@ -122,11 +190,15 @@ undocumented ordering, a contradiction with adjacent code. The discipline:
122
190
  - Alternate/error flows (idempotency included) are covered by tests.
123
191
  - The build and full test suite are green; the model still validates (`em validate` in CI —
124
192
  you didn't touch the `.em`, so this only fails if something else broke).
125
- - Nothing between the slice doc and the code was committed as a source of truth (see §8 —
193
+ - Nothing between the slice doc and the code was committed as a source of truth (see §9 —
126
194
  work containers are ephemeral; generated or symlinked specs are renderings).
127
195
 
128
196
  ## 6. At merge: the lifecycle flip
129
197
 
198
+ The PR being merged here is the one doc's PR (§5) — its description cites exactly this slice doc
199
+ (plus any `covers:` keys) and nothing else, which is what makes the flip below unambiguous: one
200
+ PR, one `implementedIn` URL, applied to every key that PR's doc covers.
201
+
130
202
  When the PR merges, exactly **two** frontmatter fields change on the slice doc:
131
203
 
132
204
  ```yaml
@@ -165,7 +237,11 @@ parked in the document as open items, exactly like a slice doc's Open Questions:
165
237
  1. **Stack and architectural shape** — languages/runtimes, frameworks, the architectural pattern,
166
238
  where a slice's code lives, and the routing table: which implementation skill or approach each
167
239
  of the four slice patterns uses (for example, State Change slices → the `axon-*` skill set).
168
- That table is what you obey in §2 when you read a slice's `pattern:`.
240
+ That table is what you obey in §2 when you read a slice's `pattern:`. This is also where the
241
+ **interface conventions** question gets asked — resource style, error/rejection mapping,
242
+ versioning, auth at the edge — so the shape of every endpoint the interface obligations
243
+ paragraph (§2) and the foundation step (§8) require is decided once, here, instead of
244
+ invented per slice.
169
245
  2. **Code style** — formatter/linter, naming, module layout, and what "idiomatic" means here.
170
246
  3. **Testing norms** — which test levels each pattern requires, where invariant and scenario
171
247
  tests live, and the test-naming convention that lets `em coverage` trace `INV-<MNEMONIC>-n`
@@ -197,7 +273,76 @@ spec-kit's own placeholders is the team's call, and em's sections go in alongsid
197
273
  `em status` will then report `constitution: present` for the model. That's the whole mechanical
198
274
  check — em stores and locates this document, and never validates a word of it.
199
275
 
200
- ## 8. Spec-kit projects: the SDD adapter
276
+ ## 8. Foundation: contracts first
277
+
278
+ Once per project, before the first slice PR ever opens, land one **foundation PR** that turns
279
+ the model's events — and the cross-cutting shell the constitution names — into code, and
280
+ nothing else. Skip this and the failure is the same on every project that's skipped it: the
281
+ first slice PR ships fine, then the second one needs an event the first slice already defined
282
+ informally, and every PR after that either redefines it slightly differently or reaches into a
283
+ sibling slice's package to reuse it — the boundary the constitution drew is gone within a week.
284
+
285
+ 1. **What it contains.** Every event `em export <model>.em` lists in `events[]`, each placed in
286
+ the home the constitution's "where a slice's code lives" rule assigns to its *emitting*
287
+ slice — not a separate shared "events" module, so nothing about where an event lives depends
288
+ on this PR existing rather than the constitution. Fields come verbatim from the slice docs'
289
+ Event tables, with types mapped per the constitution's stack conventions. Add the
290
+ cross-cutting shell the constitution names: shared ports, and the request/response boundary
291
+ and error mapping the interface obligations above (§2) plug their endpoints into. **No
292
+ handlers, no projections — contracts only.** Because: a handler or a projection belongs to
293
+ the slice that owns the behavior behind it; folding one into the foundation PR turns a shared
294
+ contract into a pre-empted slice.
295
+ 2. **It merges before any slice PR opens.** Every slice branch is cut from `main` *after* the
296
+ foundation PR has landed there — never from a commit that predates it, and never alongside an
297
+ open, unmerged foundation PR. A slice PR never carries foundation files. Because: a slice PR
298
+ opened while the foundation is still in review shows a diff dominated by files the slice
299
+ didn't write and can't be held accountable for, and its merge depends on someone else's
300
+ review timeline instead of its own.
301
+ 3. **A slice never creates, edits, or reaches into another slice's code.** It *imports* events —
302
+ only events — from wherever the foundation placed them; a sibling slice's handlers, storage,
303
+ and other internals stay off limits. Because: the boundary the constitution drew only holds if
304
+ every slice actually stays inside it — a slice that quietly builds on a sibling's internals has
305
+ erased that boundary informally, one import at a time.
306
+ 4. **A ratified delta that adds or changes an event re-runs this step for that event, first.**
307
+ Land the code change for the new or changed event — in its emitting slice's home, following
308
+ rule 1 — before the slice's delta PR opens, exactly as if it were the first pass. Because: the
309
+ same contract-before-consumer ordering that applies once per project applies again every time
310
+ the contract itself changes; an event isn't a stable shared type just because it was one
311
+ yesterday.
312
+
313
+ ### Order of work
314
+
315
+ The foundation PR above answers most of "which slice next" by itself — once every event exists
316
+ as a contract, a read slice no longer has to wait for the write slice that will eventually
317
+ produce it. What's left is ordering the slice PRs against each other, and that ordering comes
318
+ from the dependency graph, not from where a slice sits on the timeline:
319
+
320
+ 1. **Foundation first removes most ordering constraints.** With every event already landed as a
321
+ contract (rules 1–4 above), a slice's remaining dependency is on other *slices*, not on
322
+ events existing at all — that's what turns "order every slice against every other slice"
323
+ into the short, per-pattern list below.
324
+ 2. **Then take dependency order from the graph, not the timeline.** Before starting a slice,
325
+ run `em query upstream <model>.em --of <slice's command-or-view ref>` — anything it returns
326
+ that's still `ready-to-implement` is a candidate to build first; `em query producers
327
+ <model>.em --event <name>` names the slices that own a specific event's producing commands
328
+ when you need to check one directly. Concretely, per pattern:
329
+ - **State Change** with no upstream is always startable — nothing but the foundation gates it.
330
+ - **State View** is startable as soon as the events it reads exist as contracts (the
331
+ foundation alone satisfies this), but build it *after* their producing slices have merged
332
+ when you can — its fixture tests then exercise real commands instead of hand-rolled event
333
+ fixtures.
334
+ - **Automation** goes after both the command it triggers and the to-do-list view it reads
335
+ (bound via `covers:` when the two are written as one doc) — a reaction can't be tested
336
+ against a command handler or a to-do list that doesn't exist yet.
337
+ - **Translation** goes after the command it triggers, same reasoning as an Automation's
338
+ triggered-command dependency.
339
+ 3. **Timeline order is the ratification order, not the build order.** Ratifying slices in
340
+ timeline order is deliberate — it's the order stakeholders reason about the business process
341
+ in. Carrying that same order into implementation is the mistake this section exists to head
342
+ off: build order comes from the dependency graph above, and the two orders routinely
343
+ disagree.
344
+
345
+ ## 9. Spec-kit projects: the SDD adapter
201
346
 
202
347
  If the repository uses spec-kit (a `.specify/` directory exists), do not hand-author spec-kit
203
348
  artifacts — allocate through **em-sdd-bridge**, redirect mode preferred:
@@ -229,7 +374,7 @@ plan/tasks as FEATURE_SPEC. The rules that keep redirect mode safe:
229
374
  No spec-kit (or any SDD tool)? Implement straight from the slice doc — it already contains
230
375
  everything a spec holds. Don't introduce an intermediate spec document of your own.
231
376
 
232
- ## 9. Never do
377
+ ## 10. Never do
233
378
 
234
379
  | Rule | Because |
235
380
  |---|---|
@@ -241,8 +386,10 @@ everything a spec holds. Don't introduce an intermediate spec document of your o
241
386
  | Never invent the house rules a first slice needs (stack, style, testing, NFR defaults) | They're the project's decision, ratified in the constitution — §7, not your judgment call |
242
387
  | Never regenerate merged code from the model | Generated-then-owned: post-merge code belongs to its owners |
243
388
  | Never commit an authored intermediate spec | The slice is the spec; anything between it and the code is a rendering |
389
+ | Never open a slice PR before the foundation PR has merged | The foundation is what makes an event a stable shared contract — a slice built ahead of it is building on a moving target (§8) |
390
+ | Never implement more than one slice doc in a PR | The PR is the durable record of one spec's implementation; `mark-implemented`, coverage, and conformance all key on one doc ↔ one `implementedIn` |
244
391
 
245
- ## 10. Afterward: the loop closes
392
+ ## 11. Afterward: the loop closes
246
393
 
247
394
  Implementation isn't the end of the slice's story. On a cadence — or whenever someone asks —
248
395
  the `conform` phase checks implemented slices against the code, using the `implementedIn` link
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-review
3
- em-version: 1.11.0
3
+ em-version: 1.13.0
4
4
  description: >-
5
5
  Use when starting em's live browser viewer (`em watch --serve`) so a team can watch a model
6
6
  update in real time, or facilitating a SCHEDULED stakeholder walkthrough that steps through
@@ -39,6 +39,10 @@ screen. Use Prev/Next (or the left/right arrow keys) to step through slices in d
39
39
  order — each one pans/zooms into view with everything else dimmed, so the room's attention
40
40
  tracks one slice at a time.
41
41
 
42
+ **When a State View slice is on screen, ask who reads it (MIL-215):** a person or client in the
43
+ room → the `ui` should draw it; another system → `public`; only an automation → nothing, it's
44
+ internal by design and needs no endpoint.
45
+
42
46
  **Live capture:** when a stakeholder raises something unresolved, add `issue "..."` to the
43
47
  relevant element in the `.em` file and save — exactly the same mechanism `event-modeling-conform`
44
48
  uses for any other issue. The browser updates over the existing SSE push within moments, without