@milehimikey/em 1.12.0 → 1.13.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 (112) hide show
  1. package/.claude/skills/event-modeling/SKILL.md +5 -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 +26 -4
  5. package/.claude/skills/event-modeling-discover/SKILL.md +1 -1
  6. package/.claude/skills/event-modeling-implement/SKILL.md +7 -4
  7. package/.claude/skills/event-modeling-implement/reference/implement.md +26 -8
  8. package/.claude/skills/event-modeling-review/SKILL.md +5 -1
  9. package/.claude/skills/event-modeling-shared/reference/em-dsl.md +45 -6
  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 +39 -0
  12. package/.claude/skills/event-modeling-shared/templates/conformance-report.md +8 -1
  13. package/.claude/skills/event-modeling-shared/templates/state.md +3 -0
  14. package/README.md +1 -0
  15. package/dist/catalog/docJoin.d.ts +9 -0
  16. package/dist/catalog/docJoin.js +6 -0
  17. package/dist/catalog/docJoin.js.map +1 -1
  18. package/dist/catalog/driftSignal.d.ts +11 -5
  19. package/dist/catalog/driftSignal.js +18 -4
  20. package/dist/catalog/driftSignal.js.map +1 -1
  21. package/dist/catalog/modelVersionValidate.d.ts +9 -0
  22. package/dist/catalog/modelVersionValidate.js +38 -0
  23. package/dist/catalog/modelVersionValidate.js.map +1 -0
  24. package/dist/catalog/sliceDoc.d.ts +12 -0
  25. package/dist/catalog/sliceDoc.js +15 -0
  26. package/dist/catalog/sliceDoc.js.map +1 -1
  27. package/dist/cli/ciInit.d.ts +24 -0
  28. package/dist/cli/ciInit.js +85 -15
  29. package/dist/cli/ciInit.js.map +1 -1
  30. package/dist/cli/conformScope.d.ts +1 -0
  31. package/dist/cli/conformScope.js +3 -1
  32. package/dist/cli/conformScope.js.map +1 -1
  33. package/dist/cli/conformSupersede.d.ts +24 -2
  34. package/dist/cli/conformSupersede.js +44 -3
  35. package/dist/cli/conformSupersede.js.map +1 -1
  36. package/dist/cli/coverage.d.ts +16 -2
  37. package/dist/cli/coverage.js +26 -4
  38. package/dist/cli/coverage.js.map +1 -1
  39. package/dist/cli/findings.d.ts +134 -0
  40. package/dist/cli/findings.js +355 -0
  41. package/dist/cli/findings.js.map +1 -0
  42. package/dist/cli/metrics.d.ts +93 -0
  43. package/dist/cli/metrics.js +331 -0
  44. package/dist/cli/metrics.js.map +1 -0
  45. package/dist/cli/modelVersion.d.ts +139 -0
  46. package/dist/cli/modelVersion.js +256 -0
  47. package/dist/cli/modelVersion.js.map +1 -0
  48. package/dist/cli/reratify.d.ts +24 -1
  49. package/dist/cli/reratify.js +73 -17
  50. package/dist/cli/reratify.js.map +1 -1
  51. package/dist/cli/skillCheck.js +2 -2
  52. package/dist/cli/skillCheck.js.map +1 -1
  53. package/dist/cli/sliceConform.d.ts +50 -0
  54. package/dist/cli/sliceConform.js +206 -0
  55. package/dist/cli/sliceConform.js.map +1 -0
  56. package/dist/cli/sliceIndex.d.ts +2 -0
  57. package/dist/cli/sliceIndex.js +15 -3
  58. package/dist/cli/sliceIndex.js.map +1 -1
  59. package/dist/cli/sliceNew.d.ts +12 -0
  60. package/dist/cli/sliceNew.js +23 -0
  61. package/dist/cli/sliceNew.js.map +1 -1
  62. package/dist/cli/sliceStubAll.d.ts +76 -0
  63. package/dist/cli/sliceStubAll.js +189 -0
  64. package/dist/cli/sliceStubAll.js.map +1 -0
  65. package/dist/cli/stateFile.d.ts +63 -7
  66. package/dist/cli/stateFile.js +179 -18
  67. package/dist/cli/stateFile.js.map +1 -1
  68. package/dist/cli/status.d.ts +79 -1
  69. package/dist/cli/status.js +134 -15
  70. package/dist/cli/status.js.map +1 -1
  71. package/dist/cli/upgrade.d.ts +132 -0
  72. package/dist/cli/upgrade.js +524 -0
  73. package/dist/cli/upgrade.js.map +1 -0
  74. package/dist/cli.js +609 -50
  75. package/dist/cli.js.map +1 -1
  76. package/dist/emit/coverageJson.d.ts +5 -2
  77. package/dist/emit/coverageJson.js +6 -2
  78. package/dist/emit/coverageJson.js.map +1 -1
  79. package/dist/emit/freshnessJson.d.ts +1 -1
  80. package/dist/emit/freshnessJson.js +3 -1
  81. package/dist/emit/freshnessJson.js.map +1 -1
  82. package/dist/emit/json.d.ts +11 -1
  83. package/dist/emit/json.js +35 -1
  84. package/dist/emit/json.js.map +1 -1
  85. package/dist/emit/metricsJson.d.ts +7 -0
  86. package/dist/emit/metricsJson.js +27 -0
  87. package/dist/emit/metricsJson.js.map +1 -0
  88. package/dist/emit/statusJson.d.ts +1 -1
  89. package/dist/emit/statusJson.js +17 -1
  90. package/dist/emit/statusJson.js.map +1 -1
  91. package/dist/emit/upgradeJson.d.ts +5 -0
  92. package/dist/emit/upgradeJson.js +29 -0
  93. package/dist/emit/upgradeJson.js.map +1 -0
  94. package/dist/emit/validateJson.d.ts +6 -2
  95. package/dist/emit/validateJson.js +12 -5
  96. package/dist/emit/validateJson.js.map +1 -1
  97. package/dist/mcp/server.d.ts +1 -1
  98. package/dist/mcp/server.js +137 -9
  99. package/dist/mcp/server.js.map +1 -1
  100. package/dist/model/rules.d.ts +7 -0
  101. package/dist/model/rules.js +12 -0
  102. package/dist/model/rules.js.map +1 -1
  103. package/dist/model/validate.d.ts +20 -0
  104. package/dist/model/validate.js +94 -45
  105. package/dist/model/validate.js.map +1 -1
  106. package/dist/templates.d.ts +2 -2
  107. package/dist/templates.js +7 -1
  108. package/dist/templates.js.map +1 -1
  109. package/dist/util/semver.d.ts +19 -0
  110. package/dist/util/semver.js +54 -0
  111. package/dist/util/semver.js.map +1 -0
  112. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling
3
- em-version: 1.12.0
3
+ em-version: 1.13.1
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,10 @@ 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
+ even one minor version behind the installed em is a STOP, not a warning — only a patch-only
36
+ gap proceeds normally.
34
37
  2. Parse `$ARGUMENTS` for a phase name.
35
38
  - **A recognized phase name** (`discover`, `extract`, `model`, `slice`, `implement`,
36
39
  `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.12.0
3
+ em-version: 1.13.1
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/process.md#model-versions`.
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.12.0
3
+ em-version: 1.13.1
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
@@ -51,7 +51,11 @@ Goal: a structurally complete, **validated** model with correct patterns and swi
51
51
  deep-dive in the `slice` phase below); the docs are the home for everything collected from
52
52
  here on, not yet implementation-ready specs. Because every doc already exists by the time the
53
53
  `slice` phase begins, its own step 2 scaffolding call is then a no-op — that phase picks up
54
- 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.
55
59
  3. **Evaluate completeness (step 7).** Walk the model: every slice is a **complete** pattern, not a
56
60
  half-slice — **every command has something that triggers it**, every command emits an event,
57
61
  **every event is read by a read model**, **every read model has a consumer**, every view has a
@@ -63,6 +67,10 @@ Goal: a structurally complete, **validated** model with correct patterns and swi
63
67
  For an unread event, don't just bolt on a view to silence the warning: ask the user who looks at
64
68
  this fact and what they do with it. The honest answers are "here's the read model we missed" or
65
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.
66
74
 
67
75
  End of phase: render, update state (`em state set-phase slice` — the mechanical marker the state
68
76
  machine expects), and stop. Every slice already has a draft doc ready to receive the deep spec,
@@ -107,7 +115,16 @@ For each slice:
107
115
  anything unresolved rather than guessing. If the slice lives in an existing codebase, Grep/Read
108
116
  adjacent real sources (OpenAPI specs, DB migrations, existing DTOs/event classes in sibling
109
117
  contexts) before finalizing field names/types or invariants — don't guess a shape that's
110
- already defined elsewhere.
118
+ already defined elsewhere. Before finalizing an invariant, also compare it with the slices in
119
+ **this same model** — never another `.em` model — that make the same kind of change (other
120
+ `Archive*` or `Create*` state changes on different entities, say). If one of them already
121
+ states an analogous rule, either state the same rule here — written out in this doc under
122
+ this slice's own `INV-<MNEMONIC>-n` ID, not by pointing at the sibling's — or record why this
123
+ slice's case differs. If this slice has a rule those siblings lack, raise that with the user
124
+ as an open question against each of them; a ratified sibling changes only through its own
125
+ re-ratification, never as a side effect of this slice. Repeating a rule across slice docs is
126
+ correct: each doc is a self-contained spec, and whether the code behind those rules is shared
127
+ is the constitution's call, not this doc's.
111
128
  2. **First-time authoring:** scaffold the doc mechanically rather than hand-writing the
112
129
  frontmatter — `em slice new "<slice name>" --pattern <state-change|state-view|automation|
113
130
  translation> --swimlane "<Persona> → <Context>" --wire <model>.em` writes `slices/<slice-name>.md`
@@ -136,7 +153,12 @@ For each slice:
136
153
  doc's authored body) — run `em slice reratify <model>.em <slice-key>` instead: it bumps
137
154
  `version` and flips `status` back to `ready-to-implement` in the existing frontmatter,
138
155
  clearing any stale `ratifiedBy:`/`ratifiedOn:` from the prior version so a follow-up
139
- `em slice ratify --by <name>` (if the team records that) applies cleanly.
156
+ `em slice ratify --by <name>` (if the team records that) applies cleanly. The same command
157
+ changes a ratified doc that **never shipped** (`ready-to-implement` with `ratifiedBy` set — a
158
+ gap answered mid-build, MIL-258): it bumps `version` and clears the sign-off but leaves
159
+ `status` alone. Either way the doc is not ratified until `em slice ratify --by <name>` records
160
+ the new sign-off. A `ready-to-implement` doc with no `ratifiedBy` is already awaiting that
161
+ sign-off and refuses a second `reratify`; a `draft`/`reviewed` doc is simply edited.
140
162
  3. Render the slice's own diagram: `em render <model>.em --slice "<slice name>" -o
141
163
  slices/<slice-name>.svg` (kebab-case, matching the doc's filename and the `![Diagram]` stub
142
164
  `em slice new` already wrote) — redraws just this slice in its own canonical pattern shape.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-discover
3
- em-version: 1.12.0
3
+ em-version: 1.13.1
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.12.0
3
+ em-version: 1.13.1
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
@@ -21,11 +21,14 @@ land a one-time foundation PR holding every model event (plus the shared interfa
21
21
  slices only ever import contracts, never invent or reach into a sibling's; build in dependency
22
22
  order from `em query upstream`, not timeline order; treat the slice doc as
23
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
24
+ slice doc per PR — a `covers:` doc's two keys ship together in that one PR, and an `again` view
25
+ instance is a continuation of its originating slice (no doc, status, or PR of its own — it
26
+ ships in the originating doc's PR); ship the endpoint a
26
27
  `ui`-triggered command or `ui`-consumed view obligates, and surface — never invent — one the
27
28
  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
+ `INV-<MNEMONIC>-n` and every scenario with tests, proving the citations before merge with
30
+ `em coverage <model>.em --slice <key> --tests <dir> --strict` (the default form skips a
31
+ `ready-to-implement` slice); in spec-kit projects, allocate via
29
32
  em-sdd-bridge (redirect mode) and never run `/speckit.specify`.
30
33
 
31
34
  **Gate: no constitution, no first slice.** The constitution is the project's ratified house rules
@@ -35,9 +35,10 @@ every `## Open Questions` checkbox is checked, and no status/version/link incohe
35
35
  `statusReady`/`noUncheckedOpenQuestions`) if you need to say which one is blocking.
36
36
 
37
37
  **`ready: false` means stop** — with one named exception: a slice already `status: implemented`
38
- with `driftSignal: in-sync` also reads `ready: false` (its `statusReady` gate fails because
39
- nothing is newly ratified), and that specific case is re-implementation/repair, not a blocker —
40
- see §3's third mode before treating it as one. For every other `false`, report which `gates`
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`
41
42
  entries are `false` (and any `diagnostics` entries concerning this slice) and hand the slice
42
43
  back to the humans. Never make the gate pass yourself — checking an open-question box, flipping
43
44
  `status`, or editing frontmatter are ratification decisions, and ratification happens in a
@@ -86,7 +87,9 @@ section — and the routing from it is mechanical, not a technical choice you ma
86
87
  translation, a view read only by a reaction) means internal-only: no endpoint. If one seems
87
88
  needed anyway, that's a gap to surface (§4), not a technical choice to make mid-implementation
88
89
  — adding a route the model doesn't show is exactly the kind of silent divergence §4 exists to
89
- catch.
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).
90
93
  - **`public` events and views** are the model's published integration surface: their shape is a
91
94
  contract, not an implementation detail. `em validate --list-public` lists them; `em typespec`
92
95
  is the POC generator for a downstream schema. Changing a public element's shape is a ratified
@@ -122,8 +125,11 @@ Check the doc's `version:` and `## Delta` section (or `em export`'s `slice.doc.d
122
125
  the people who've edited it (generated-then-owned); regeneration is legal only for slices
123
126
  whose code never merged.
124
127
  - **Re-implementation / repair** (`status: implemented`, `implementedIn` set, `driftSignal:
125
- in-sync` — `--slice-ready` reports `ready: false` purely because `statusReady` fails, with no
126
- other gate false and no doc content changed): the doc hasn't changed, but the shipped code
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
127
133
  needs rebuilding or fixing — deleted code, a reverted PR, a bug in behavior the doc already
128
134
  specifies. **The doc is still the spec.** The gate's `false` here means "nothing new is
129
135
  ratified," not "stop" — it is not license to self-initiate: proceed only when a human has
@@ -151,6 +157,12 @@ undocumented ordering, a contradiction with adjacent code. The discipline:
151
157
  your recommendation. The human resolves it — at the model, where the resolution lands as an
152
158
  answered open question or a small ratified delta alongside your fix, so the decision is
153
159
  recorded instead of buried in an implementation diff.
160
+ - **How a delta is ratified on a doc that never shipped** (it is `ready-to-implement` with
161
+ `ratifiedBy` set): once the human has answered, the doc changes by `em slice reratify
162
+ <model>.em <slice-key>` (bumps `version:`, clears the old sign-off, leaves `status` alone),
163
+ the answer is written into the doc, and the human re-signs with `em slice ratify <model>.em
164
+ <slice-key> --by <name>`. That is the human's step, not yours — you never run `ratify`, and
165
+ the doc is not ratified again until they do; resume the build after that.
154
166
  - **Never edit the ratified doc to record your own answer**, and never quietly pick a behavior
155
167
  a business person could have an opinion on. Silent divergence is the failure mode the whole
156
168
  conformance loop exists to catch — don't manufacture it.
@@ -177,8 +189,14 @@ or seem small — see §10.
177
189
  - The PR description cites exactly one slice doc (plus its `covers:` keys, if any) and lists
178
190
  that doc's invariants alongside the tests that cover them.
179
191
  - Every `INV-<MNEMONIC>-n` invariant has at least one test that cites its ID — checked mechanically by
180
- `em coverage <model>.em --tests <dir>` (MIL-130); run it (add `--strict` in CI) rather than
181
- eyeballing citations by hand.
192
+ `em coverage <model>.em --slice <slice-key> --tests <dir> --strict` (MIL-130, MIL-255); run it
193
+ before merge rather than eyeballing citations by hand. `--slice` is what makes this check the
194
+ slice under build: the default form, `em coverage <model>.em --tests <dir>`, counts only slices
195
+ already flipped to `implemented` (MIL-207), and your slice is still `ready-to-implement` until
196
+ the §6 flip — so the default form reports it `inScope: false`, checks nothing, and exits 0. It
197
+ is a regression check for shipped slices, not the definition-of-done check. (`--include-ready`
198
+ is no substitute: it counts every ratified slice, so `--strict` fails on slices nobody has
199
+ started.) A continuation key resolves to its originating slice's doc. If it exits 1 with "not in scope", the slice's doc is not `ready-to-implement`/`implemented` — nothing was checked, so stop and surface it rather than treating the run as a pass.
182
200
  - Every scenario in `## Scenarios (Given / When / Then)` exists as a passing test; rejection
183
201
  scenarios assert the doc's named rejection reason.
184
202
  - Alternate/error flows (idempotency included) are covered by tests.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling-review
3
- em-version: 1.12.0
3
+ em-version: 1.13.1
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
@@ -49,17 +49,27 @@ em slice new <name> --pattern <pattern> # slice pattern: s
49
49
  em slice new <name> --swimlane <swimlane> # swimlane, e.g. "Persona → Context"
50
50
  em slice new <name> -f, --force # overwrite the file if it already exists
51
51
  em slice new <name> --wire <model-file> # also insert the `note "slices/<key>.md"` line onto the slice's primary element in this .em file (matched by export key), instead of just printing it to paste by hand (MIL-161)
52
+ em slice new <name> --stub # write a near-free stub instead: same 5 frontmatter keys, but a one-line placeholder body instead of the diagram-image stub and every judgment section (MIL-184) — deepen it later by re-running without --stub and -f
53
+ em slice stub-all <file> # scaffold + wire a near-free stub (`em slice new --stub`'s content, MIL-184) for every slice in <file> with no resolvable doc — the fast path to status coloring for an exploratory/backbone model without hand-running `slice new` per slice. Skips a continuation slice (MIL-208, it has no doc of its own), an already-documented slice, and a slice whose pattern can't be classified
54
+ em slice stub-all <file> --status <status> # target status for every stub: draft | reviewed | ready-to-implement | implemented
55
+ em slice stub-all <file> --by <name> # identity for reviewedBy/ratifiedBy — required unless --status draft
56
+ em slice stub-all <file> --implemented-in <url> # PR/commit URL for implementedIn — required with --status implemented
57
+ em slice stub-all <file> --dry-run # list what would be stubbed/wired without writing anything
52
58
  em slice index <file> # rewrite the model's sibling README.md's GENERATED Slices table from `em export`'s slice facts (key, pattern, doc status/implementedIn) — the hand-maintained table is deprecated
53
59
  em slice index <file> --check # verify the table is current; exit non-zero on drift without writing (CI)
54
60
  em slice mark-implemented <file> <slice-key> <pr-url> # flip a slice doc's frontmatter to `status: implemented` / `implementedIn: <pr-url>` — the one edit an implementing agent makes to a ratified doc at merge (MIL-103, replaces the em-sdd-bridge `em-sdd-mark-implemented` script; see reference/implement.md §6). Idempotent on the same URL; refuses to overwrite a different one; never touches `version:` or the doc body
55
61
  em slice review <file> <slice-key> # flip a slice doc's frontmatter to `status: reviewed` and record `reviewedBy:`/`reviewedOn:` — the FIRST of the two human gates (MIL-201, docs/process.md#the-slice-lifecycle-gates): the room walked this slice and every open question it raised is resolved. Ratification is a separate, later gate (`em slice ratify`). Legal from `status: draft`; idempotent on the same --by/--on pair; refuses to overwrite a different one already recorded; refuses a doc already `ready-to-implement`/`implemented`; never touches `version:` or the doc body
56
62
  em slice review <file> <slice-key> --by <name> # the reviewer's (or facilitator's) name
57
63
  em slice review <file> <slice-key> --on <date> # review date, YYYY-MM-DD (default: today, local date)
58
- em slice ratify <file> <slice-key> # flip a slice doc's frontmatter to `status: ready-to-implement` and record `ratifiedBy:`/`ratifiedOn:` — the handoff sign-off (MIL-165, docs/process.md#the-slice-lifecycle-gates) that makes who ratified, and when, a first-class recorded fact. Refuses a doc that never passed the review gate (`em slice review`) unless --skip-review is passed. Idempotent on the same --by/--on pair; refuses to overwrite a different one already recorded; never touches `version:` or the doc body
64
+ em slice ratify <file> <slice-key> # flip a slice doc's frontmatter to `status: ready-to-implement` and record `ratifiedBy:`/`ratifiedOn:` — the handoff sign-off (MIL-165, docs/process.md#the-slice-lifecycle-gates) that makes who ratified, and when, a first-class recorded fact. The review gate is a check on the doc's current `status:`, not on whether `reviewedBy:`/`reviewedOn:` are populated: a doc at `reviewed` or `ready-to-implement` passes (the latter is where `em slice reratify` leaves a doc, so the follow-up ratify needs no --skip-review); any other status — a `draft` that never went through `em slice review` — is refused unless --skip-review is passed. Idempotent on the same --by/--on pair; refuses to overwrite a different one already recorded; never touches `version:` or the doc body
59
65
  em slice ratify <file> <slice-key> --by <name> # the ratifier's name
60
66
  em slice ratify <file> <slice-key> --on <date> # ratification date, YYYY-MM-DD (default: today, local date)
61
67
  em slice ratify <file> <slice-key> --skip-review # ratify without a recorded review — prints a loud notice on stderr
62
- em slice reratify <file> <slice-key> # bump `version:` and flip a shipped slice doc's frontmatter back to `status: ready-to-implement` — the re-ratification mechanical edit (MIL-161, mirrors `em slice mark-implemented`). Only applies to a doc at `status: implemented`; clears any stale `ratifiedBy:`/`ratifiedOn:`/`reviewedBy:`/`reviewedOn:` (they describe the PRIOR version's review and sign-off) so a follow-up `em slice ratify --by` applies cleanly — and needs no fresh review; never touches `implementedIn:` or the doc body
68
+ em slice reratify <file> <slice-key> # bump `version:` and flip a shipped slice doc's frontmatter back to `status: ready-to-implement` — the re-ratification mechanical edit (MIL-161, mirrors `em slice mark-implemented`). Applies to a doc at `status: implemented`, or (MIL-258) to a `ready-to-implement` doc that is ratified but not yet shipped — there it bumps `version:` and clears the sign-off but leaves `status:` alone; a `ready-to-implement` doc with no `ratifiedBy:` refuses (awaiting `em slice ratify --by`). Clears any stale `ratifiedBy:`/`ratifiedOn:`/`reviewedBy:`/`reviewedOn:` (they describe the PRIOR version's review and sign-off) so a follow-up `em slice ratify --by` applies cleanly — and needs no fresh review; never touches `implementedIn:` or the doc body
69
+ em slice conform <file> <slice-key> # record per-slice-per-version conformance certification: sets `conformedVersion:`/`conformedAt:`/`conformedOn:` on a slice doc (MIL-214) — the fact `driftSignal: in-sync` now depends on. Legal only for `status: implemented` with an `implementedIn:` link. Idempotent on the same (version, --at) pair; a different --at simply overwrites (a later re-certification is normal — there's no way for em to tell 'later' from 'earlier' for an arbitrary revision string, so there's no --force to reach for). Refuses when the newest conformance/*-findings.json matching --at still has an unruled finding in scope for this slice; --skip-findings-check overrides with a loud notice.
70
+ em slice conform <file> <slice-key> --at <rev> # the target-repo revision this certification sweep diffed against
71
+ em slice conform <file> <slice-key> --on <date> # certification date, YYYY-MM-DD (default: today, local date)
72
+ em slice conform <file> <slice-key> --skip-findings-check # certify even with unruled findings in scope — prints a loud notice on stderr
63
73
  em changelog <file> # render a model's git history as a business-readable ledger (see docs/cli.md)
64
74
  em changelog <file> --from <rev> # start the walk at this revision (inclusive)
65
75
  em changelog <file> --to <rev> # end the walk at this revision (inclusive; default HEAD)
@@ -67,21 +77,32 @@ em changelog <file> -o, --out <path> # write to a file
67
77
  em state read [dir] # print the state file's mechanical fields as JSON
68
78
  em state set-phase <phase> [dir] # rewrite Current phase: (and Last updated:); --step also rewrites Current step:
69
79
  em state set-phase <phase> [dir] --step <n> # also set Current step: to this value
70
- em state set-conformance <revision> [dir] # rewrite Last conformance: (and Last updated:) in the exact format reference/conform.md parses
80
+ em state set-conformance <revision> [dir] # rewrite Last conformance: (and Last updated:) in the exact format reference/conform.md parses. Refuses (MIL-214) while any `implemented` slice has an unruled conformance finding in the findings JSON beside --report (a `slice: null` finding blocks every slice); --partial records the marker with a ` (partial)` suffix instead, with a loud notice. Without a findings JSON beside --report: warns once and records the marker as given (migration path for a report predating `em conform-findings`)
71
81
  em state set-conformance <revision> [dir] --report <path> # path to the conformance report just written
82
+ em state set-conformance <revision> [dir] --partial # record the marker as PARTIAL even though some in-scope findings are still unruled
72
83
  em state set-review <date> [dir] # rewrite Last stakeholder review: (and Last updated:)
73
84
  em state log-usage <file> # append one Usage log line — phase(s) touched + em validate's diagnostic categories hit, deduped and canonically formatted (MIL-161, docs/usage-data.md) — the mechanical half of 'save state at the end of every session' that used to be run-validate-then-hand-format; state file resolved next to <file>, same convention as em conform-scope
74
85
  em state log-usage <file> --phases <list> # comma-separated phase(s) touched this session: discover, extract, model, slice, implement, conform, review, validate, watch
86
+ em model version bump <file> # bump the model's design version: write model-versions/v<N+1>.json (sibling of slices/, conformance/) and rewrite the state file's `Model version:` bullet (MIL-218). Refuses when the state file is missing (run `em scaffold` first), when --by is empty, and when nothing has changed since the current version (same model content hash AND same slice-version vector) unless --force — a no-op bump is the one case --force is right for.
87
+ em model version bump <file> --by <name> # the bumper's name
88
+ em model version bump <file> --on <date> # bump date, YYYY-MM-DD (default: today, local date)
89
+ em model version bump <file> --force # bump even though nothing has changed since the current version
90
+ em model version show <file> # print the model's current design version and the most recently certified version, if any (model-versions/*.json — MIL-218)
91
+ em model version show <file> --json # print a JSON document instead of text
75
92
  em usage-report [root] # aggregate every .event-modeling.md's Usage log under [root] into phase/diagnostic-category tallies (MIL-161) — replaces docs/usage-data.md's hand-rolled grep/awk/sort pipeline; a logged line that doesn't match the canonical em state log-usage format is reported under unparseableLines rather than silently mistallied or dropped
76
93
  em usage-report [root] --json # print a JSON document instead of the text report
77
94
  em conform-scope <file> # mechanize conform phase step 1 (reference/conform.md): map the target repo's changed paths since Last conformance: to slices via each slice doc's implementedIn, JSON to stdout — --seed-asis also seeds the <model>-asis.em scratch model (see docs/cli.md)
78
95
  em conform-scope <file> --repo <path> # path to (or inside) the target codebase's git repository
79
96
  em conform-scope <file> --full # ignore Last conformance:/changed paths; scope every implemented slice
80
97
  em conform-scope <file> --seed-asis # write <model>-asis.em as a byte copy of the canonical model and ensure it's gitignored
81
- em conform-supersede <file> <report-path> # stamp a conformance report with a "superseded as of <rev>" banner once its findings have been ruled on (MIL-164, docs/process.md#what-ratified-means) — the companion step to run at ratification time so a reader following the report's file:line citations knows they describe an ancestor of the current model. Additive-only splice, never a rewrite of the report; idempotent on the same --as-of/--findings/--on stamp; refuses if the report doesn't exist
98
+ em conform-supersede <file> <report-path> # stamp a conformance report with a "superseded as of <rev>" banner once its findings have been ruled on (MIL-164, docs/process.md#what-ratified-means) — the companion step to run at ratification time so a reader following the report's file:line citations knows they describe an ancestor of the current model. Additive-only splice, never a rewrite of the report; idempotent on the same --as-of/--findings/--on stamp; refuses if the report doesn't exist. --locus/--by (MIL-214, both required together) additionally record the ruling itself — locus/resolvedBy/resolvedOn — on the findings named by --findings in the sibling conformance/<date>-findings.json, when one exists (warns once and stamps the banner only when it doesn't — the migration path for a report predating em conform-findings)
82
99
  em conform-supersede <file> <report-path> --as-of <rev> # the revision this ruling was made against — same value passed to `em state set-conformance`
83
100
  em conform-supersede <file> <report-path> --findings <spec> # which finding number(s) this stamps as ruled, e.g. "1-3" or "1,2,4"
84
101
  em conform-supersede <file> <report-path> --on <date> # ruling date, YYYY-MM-DD (default: today, local date)
102
+ em conform-supersede <file> <report-path> --locus <locus> # who/what the named finding(s) say is wrong: model | doc | code | none (requires --by)
103
+ em conform-supersede <file> <report-path> --by <name> # who ruled on the named finding(s) (requires --locus)
104
+ em conform-findings check <path> # shape-validate a conformance/<date>-findings.json file (findingsSchemaVersion, required fields, enum values, ids sorted+unique, a ruled finding carries resolvedBy+resolvedOn) — exit 1 on shape errors. The conform skill writes this file directly alongside its report; this is how a headless run verifies what it just wrote.
105
+ em conform-findings check <path> --json # print a JSON document instead of the text report
85
106
  em watch <file> # re-render on every save
86
107
  em watch <file> -o, --out <path> # output path (extension picks the format)
87
108
  em watch <file> -T, --format <fmt> # output format (svg, png, pdf, ...)
@@ -102,8 +123,9 @@ em ledger <file> --from <rev> # baseline revisio
102
123
  em ledger <file> --to <rev> # compare revision (default: current working tree)
103
124
  em ledger <file> --waive <slice-key> # excuse a doc-content-without-version-bump finding for this slice key (repeatable; MIL-185, see docs/cli.md) — never waives a version regression or bump-without-content-change
104
125
  em ledger <file> --json # print a JSON document instead of the text report (see docs/cli.md)
105
- em coverage <file> # check that every INV-* invariant ID cited in an implemented slice doc is cited by a test under --tests <dir> (MIL-130/MIL-207) — mechanizes reference/implement.md's definition-of-done citation check; advisory by default, --strict for CI; --include-ready also counts ready-to-implement docs (forward-looking report); a continuation slice (an `again` view instance with no doc of its own, MIL-208) is excluded from the report — its invariants, if any, live in the originating slice's own doc
126
+ em coverage <file> # check that every INV-* invariant ID cited in an implemented slice doc is cited by a test under --tests <dir> (MIL-130/MIL-207) — mechanizes reference/implement.md's definition-of-done citation check; advisory by default, --strict for CI; --include-ready also counts ready-to-implement docs (forward-looking report); a continuation slice (an `again` view instance with no doc of its own, MIL-208) is excluded from the report — its invariants, if any, live in the originating slice's own doc; --slice <key> scopes the report to one slice whatever its status (MIL-255), the pre-merge definition-of-done check
106
127
  em coverage <file> --tests <dir> # directory to scan recursively for test files citing invariant IDs
128
+ em coverage <file> --slice <key> # only this slice (export key), whether ready-to-implement or implemented — no --include-ready needed; --strict then fails on this slice's uncited invariants, or if the slice is not in scope (draft/reviewed/unbound: nothing checked) (MIL-255)
107
129
  em coverage <file> --strict # exit non-zero if any invariant ID has zero citations (CI)
108
130
  em coverage <file> --include-ready # also count ready-to-implement docs, not just implemented (MIL-207)
109
131
  em coverage <file> --json # print a JSON document instead of the text report (see docs/cli.md)
@@ -117,6 +139,10 @@ em status <files> -o, --out <path> # write output to
117
139
  em freshness <file> # standalone freshness signal for one model's conformance record (MIL-164): "last conformed <rev> — N commits and M slice-PRs behind HEAD", computed from the same conform-scope machinery `em status`'s conformance clause uses — for when you want just this fact, no full state-of-the-system rollup (see docs/cli.md)
118
140
  em freshness <file> --repo <path> # git repo to compute behind-HEAD in (default: the model's own directory)
119
141
  em freshness <file> --json # print a JSON document instead of the text line
142
+ em metrics <file> # the pilot metrics named in advance by the register, computed from git history alone (MIL-170): ratification turnaround (reviewed -> ratified -> implemented), conform-cycle cadence + finding counts, and status-vs-reality disagreement over time — plus a fourth, reported as not computable from history (see docs/usage-data.md). `<file>` is an anchor .em file, used only to locate slices/, conformance/, and .event-modeling.md relative to it — same convention as em ledger; never parsed or compiled
143
+ em metrics <file> --from <rev> # baseline revision
144
+ em metrics <file> --to <rev> # compare revision (default: HEAD)
145
+ em metrics <file> --json # print a JSON document instead of the text report (see docs/cli.md)
120
146
  em query consumers <files> # views/reactions consuming an event, plus their slices
121
147
  em query consumers <files> --event <ref-or-name> # the event's export ref or display name
122
148
  em query consumers <files> --json # print a JSON document instead of the text report
@@ -163,8 +189,12 @@ em skill check [path] # check the vendor
163
189
  em skill check [path] --json # print a JSON document instead of the text report (see docs/cli.md)
164
190
  em ci init <model> # install .github/workflows/em-ci.yml (PR gates: em validate, em slice index --check, em coverage --strict, em ledger, em skill check, em glossary --fail-on-conflicts, plus a push-triggered status-badge rebuild) and em-conform.yml (scheduled, advisory-only conformance cadence) — same install discipline as `em skill install`: marker-delimited, idempotent, --check for CI self-verification (MIL-166, see docs/ci.md)
165
191
  em ci init <model> --tests <dir> # test directory the coverage/status steps scan for INV-* citations
166
- em ci init <model> -f, --force # replace an existing workflow file that has no GENERATED markers
192
+ em ci init <model> -f, --force # replace an existing workflow file that has no GENERATED markers, or a managed block generated for a different model
167
193
  em ci init <model> --check # verify both files match the current preset; exit non-zero on drift without writing (CI)
194
+ em upgrade <file> # bring a model repo authored under an older em (1.6 forward) up to the installed version: an ordered list of mechanical steps (skill bundle, reaction shape, state-file bullets, generated CI blocks, constitution scaffold) plus a human list of things no command can safely decide by itself (MIL-219, see docs/upgrading.md). Dry-run by default; --apply makes one git commit per applicable step, refusing on a dirty working tree
195
+ em upgrade <file> --apply # apply every applicable mechanical step, one git commit each, then a final `Em version:` commit
196
+ em upgrade <file> --check # exit non-zero only on a hard incompatibility (an existing but unparseable state file, an un-migratable .em shape) — writes nothing; what CI runs; the final line says why
197
+ em upgrade <file> --json # print a JSON document instead of text (dry-run/--check only, never with --apply)
168
198
  ```
169
199
  <!-- GENERATED:cli:end -->
170
200
 
@@ -270,6 +300,14 @@ type Name { field: Type, ... } # named structured type, reusable from any f
270
300
  this model). `em export` carries it as `public: true`/`false`; `em diff` reports a flip as
271
301
  `event marked public`/`event unmarked public` (the entry cites the element's kind, so a
272
302
  view flip reads `view "X"`); `em validate --list-public` audits the whole public surface.
303
+ **Exposure of a read model (MIL-215) is three cases, no dedicated keyword:** a person/client
304
+ reads it → draw the `ui` that reads it (ships the endpoint); another model/system reads it →
305
+ `public` (a cross-model contract, verified by `em system <manifest>`, not `em validate`); only
306
+ an automation reads it → nothing — internal by design, the read a reaction is required to
307
+ make, not an endpoint. `em validate --list-public` flags a `public` view with no `ui`/reaction
308
+ reading it anywhere in this model as an audit note ("no in-model reader"), not a warning — a
309
+ cross-model `public` view's reader legitimately lives outside this file (see "`em validate`
310
+ rules" below).
273
311
  - **`tag`** (events only): declares a DCB (Dynamic Consistency Boundary) tag key. Three forms:
274
312
  a trailing `tag` on a field line inside the event's `{ … }` block (`priceId: UUID tag`, or
275
313
  typeless `priceId tag`) — an identity tag, key defaults to the field's own name; a bare field
@@ -681,6 +719,7 @@ not the prose above has caught up yet. `--slice-ready <key>`-only codes are excl
681
719
  | `lineage-version-impossible` | error | Impossible lineage version | Fix the referenced version, or ratify the target slice first. |
682
720
  | `loops-to-forward` | error | `loops-to` target not earlier on the timeline | Point `loops-to` at an earlier view, or use `from` on a later `view … again` instance instead. |
683
721
  | `loops-to-unresolved` | error | `loops-to` target unresolved | Name a view that exists, or declare it before this event. |
722
+ | `model-version-stale` | warning | Model version stale | Run `em model version bump` to record the current model content/slice-version vector. |
684
723
  | `note-binding-dangling` | warning | Dangling cross-slice note | Create the doc at that path, or fix/remove the note. |
685
724
  | `note-binding-extra` | warning | Extra doc-binding note, ignored | Remove the note, or point it at the slice's actual bound doc. |
686
725
  | `note-binding-unratified` | warning | Unratified cross-slice note | Add `covers: <this-slice-key>` to that doc's frontmatter, or correct the note's path. |
@@ -77,7 +77,17 @@ right here as `reference/slice-doc-schema.md` (kept in sync with the em repo's
77
77
 
78
78
  1. Check the tool: `em --version`. If missing, tell the user to run `npm i -g @milehimikey/em`
79
79
  and stop until installed.
80
- 2. Locate the model. Look for an existing `<dir>/.event-modeling.md` and `*.em` in the working
80
+ 2. Check this vendored skill bundle's own currency (MIL-219): read this file's `em-version:`
81
+ frontmatter stamp (or any sibling skill's SKILL.md — they're stamped together) and compare it
82
+ to `em --version` from step 1. **If the installed em is ahead by a minor version or more
83
+ (1.9.x → 1.11.x, or any major bump), STOP** — don't proceed with discover/model/slice/
84
+ implement/conform/review work on this stamp. Tell the user the vendored bundle is stale and to
85
+ run `em skill sync` (refresh the bundle only) or `em upgrade` (the bundle plus the model
86
+ repo's other mechanical migrations, docs/upgrading.md) before continuing. A patch-only gap
87
+ (1.11.2 → 1.11.4) is never worth stopping over — proceed normally. This matters because a
88
+ stale bundle silently follows old rules: an agent reading superseded preconditions/gates
89
+ can hand back work that looks right by last week's contract and wrong by this week's.
90
+ 3. Locate the model. Look for an existing `<dir>/.event-modeling.md` and `*.em` in the working
81
91
  directory, or — for a multi-model project laid out per the convention below — one level down
82
92
  inside a `models/` subfolder (each model gets its own `models/<slug>/` directory; check each
83
93
  candidate for its own `.event-modeling.md`/`*.em` pair). If found, run `em state read <dir>`
@@ -85,12 +95,12 @@ right here as `reference/slice-doc-schema.md` (kept in sync with the em repo's
85
95
  conformance, last review) as JSON — don't parse the bullets by hand. If not, and the phase
86
96
  needs one, ask the user for the model name and where to create it (a lone model goes at the
87
97
  project root; one of several goes under `models/`, per "Multi-model projects" below).
88
- 3. If you're not sure which phase applies, or the user gave no phase, use `em state read <dir>`'s
98
+ 4. If you're not sure which phase applies, or the user gave no phase, use `em state read <dir>`'s
89
99
  `phase`/`step` to resume the recorded phase/step — or invoke the `event-modeling` skill, which
90
100
  does exactly this and routes to the right skill. If no model exists, propose starting
91
101
  `discover` (greenfield, `event-modeling-discover`) or `extract` (modeling an existing system,
92
102
  also `event-modeling-discover`).
93
- 4. Populate the state file's Participants section at session start. For a live workshop, ask for
103
+ 5. Populate the state file's Participants section at session start. For a live workshop, ask for
94
104
  a single human proxy to relay questions to the room, and attribute every answer/decision in
95
105
  the Decisions log to a named participant.
96
106