@milehimikey/em 1.13.1 → 1.14.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 (235) hide show
  1. package/.claude/agents/em-critic.md +26 -0
  2. package/.claude/agents/em-implementer.md +34 -0
  3. package/.claude/agents/em-reviewer.md +31 -0
  4. package/.claude/agents/em-validator.md +27 -0
  5. package/.claude/skills/event-modeling/SKILL.md +50 -11
  6. package/.claude/skills/event-modeling-conform/SKILL.md +1 -1
  7. package/.claude/skills/event-modeling-design/SKILL.md +127 -18
  8. package/.claude/skills/event-modeling-discover/SKILL.md +1 -1
  9. package/.claude/skills/event-modeling-engagement/SKILL.md +192 -0
  10. package/.claude/skills/event-modeling-engagement/reference/engagement.md +143 -0
  11. package/.claude/skills/event-modeling-implement/SKILL.md +1 -1
  12. package/.claude/skills/event-modeling-implement/reference/implement.md +38 -11
  13. package/.claude/skills/event-modeling-review/SKILL.md +2 -2
  14. package/.claude/skills/event-modeling-shared/reference/em-dsl.md +279 -189
  15. package/.claude/skills/event-modeling-shared/reference/operating-principles.md +61 -0
  16. package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +116 -5
  17. package/.claude/skills/event-modeling-shared/templates/constitution.md +18 -1
  18. package/.claude/skills/event-modeling-shared/templates/slice.md +64 -39
  19. package/.claude/skills/event-modeling-shared/templates/state.md +5 -1
  20. package/.claude-plugin/marketplace.json +14 -0
  21. package/README.md +25 -11
  22. package/dist/catalog/apiFirst.d.ts +28 -0
  23. package/dist/catalog/apiFirst.js +49 -0
  24. package/dist/catalog/apiFirst.js.map +1 -0
  25. package/dist/catalog/docJoin.d.ts +13 -0
  26. package/dist/catalog/docJoin.js +11 -0
  27. package/dist/catalog/docJoin.js.map +1 -1
  28. package/dist/catalog/docModelConsistencyValidate.js +44 -4
  29. package/dist/catalog/docModelConsistencyValidate.js.map +1 -1
  30. package/dist/catalog/invariantsValidate.d.ts +4 -0
  31. package/dist/catalog/invariantsValidate.js +102 -0
  32. package/dist/catalog/invariantsValidate.js.map +1 -0
  33. package/dist/catalog/scenarios.d.ts +15 -0
  34. package/dist/catalog/scenarios.js +97 -0
  35. package/dist/catalog/scenarios.js.map +1 -0
  36. package/dist/catalog/sliceDoc.d.ts +8 -0
  37. package/dist/catalog/sliceDoc.js +9 -0
  38. package/dist/catalog/sliceDoc.js.map +1 -1
  39. package/dist/catalog/sliceReadyValidate.d.ts +31 -4
  40. package/dist/catalog/sliceReadyValidate.js +66 -8
  41. package/dist/catalog/sliceReadyValidate.js.map +1 -1
  42. package/dist/catalog/sliceSections.d.ts +55 -0
  43. package/dist/catalog/sliceSections.js +317 -0
  44. package/dist/catalog/sliceSections.js.map +1 -0
  45. package/dist/cli/agentsMd.js +7 -1
  46. package/dist/cli/agentsMd.js.map +1 -1
  47. package/dist/cli/api.d.ts +90 -0
  48. package/dist/cli/api.js +318 -0
  49. package/dist/cli/api.js.map +1 -0
  50. package/dist/cli/ciInit.d.ts +82 -21
  51. package/dist/cli/ciInit.js +468 -64
  52. package/dist/cli/ciInit.js.map +1 -1
  53. package/dist/cli/conformScope.d.ts +28 -0
  54. package/dist/cli/conformScope.js +67 -0
  55. package/dist/cli/conformScope.js.map +1 -1
  56. package/dist/cli/coverage.d.ts +9 -0
  57. package/dist/cli/coverage.js +60 -8
  58. package/dist/cli/coverage.js.map +1 -1
  59. package/dist/cli/defer.d.ts +55 -0
  60. package/dist/cli/defer.js +244 -0
  61. package/dist/cli/defer.js.map +1 -0
  62. package/dist/cli/engagement.d.ts +210 -0
  63. package/dist/cli/engagement.js +444 -0
  64. package/dist/cli/engagement.js.map +1 -0
  65. package/dist/cli/engagementFile.d.ts +86 -0
  66. package/dist/cli/engagementFile.js +255 -0
  67. package/dist/cli/engagementFile.js.map +1 -0
  68. package/dist/cli/metrics.d.ts +10 -0
  69. package/dist/cli/metrics.js +49 -1
  70. package/dist/cli/metrics.js.map +1 -1
  71. package/dist/cli/pluginPin.d.ts +55 -0
  72. package/dist/cli/pluginPin.js +188 -0
  73. package/dist/cli/pluginPin.js.map +1 -0
  74. package/dist/cli/ratify.d.ts +27 -2
  75. package/dist/cli/ratify.js +112 -13
  76. package/dist/cli/ratify.js.map +1 -1
  77. package/dist/cli/reratify.d.ts +4 -2
  78. package/dist/cli/reratify.js +41 -16
  79. package/dist/cli/reratify.js.map +1 -1
  80. package/dist/cli/scopeInputs.d.ts +48 -0
  81. package/dist/cli/scopeInputs.js +176 -0
  82. package/dist/cli/scopeInputs.js.map +1 -0
  83. package/dist/cli/skillCheck.d.ts +15 -1
  84. package/dist/cli/skillCheck.js +22 -1
  85. package/dist/cli/skillCheck.js.map +1 -1
  86. package/dist/cli/skillDirs.d.ts +5 -0
  87. package/dist/cli/skillDirs.js +13 -1
  88. package/dist/cli/skillDirs.js.map +1 -1
  89. package/dist/cli/skillSync.d.ts +4 -0
  90. package/dist/cli/skillSync.js +23 -0
  91. package/dist/cli/skillSync.js.map +1 -1
  92. package/dist/cli/sliceNew.d.ts +11 -7
  93. package/dist/cli/sliceNew.js +91 -18
  94. package/dist/cli/sliceNew.js.map +1 -1
  95. package/dist/cli/sliceSync.d.ts +50 -0
  96. package/dist/cli/sliceSync.js +170 -0
  97. package/dist/cli/sliceSync.js.map +1 -0
  98. package/dist/cli/status.d.ts +24 -1
  99. package/dist/cli/status.js +20 -1
  100. package/dist/cli/status.js.map +1 -1
  101. package/dist/cli/systemInputs.d.ts +53 -10
  102. package/dist/cli/systemInputs.js +186 -11
  103. package/dist/cli/systemInputs.js.map +1 -1
  104. package/dist/cli/upgrade.d.ts +16 -3
  105. package/dist/cli/upgrade.js +366 -30
  106. package/dist/cli/upgrade.js.map +1 -1
  107. package/dist/cli/usageLog.d.ts +4 -2
  108. package/dist/cli/usageLog.js +4 -2
  109. package/dist/cli/usageLog.js.map +1 -1
  110. package/dist/cli.js +599 -94
  111. package/dist/cli.js.map +1 -1
  112. package/dist/emit/api.d.ts +29 -0
  113. package/dist/emit/api.js +220 -0
  114. package/dist/emit/api.js.map +1 -0
  115. package/dist/emit/apiCheckJson.d.ts +3 -0
  116. package/dist/emit/apiCheckJson.js +21 -0
  117. package/dist/emit/apiCheckJson.js.map +1 -0
  118. package/dist/emit/codeownersJson.d.ts +3 -0
  119. package/dist/emit/codeownersJson.js +19 -0
  120. package/dist/emit/codeownersJson.js.map +1 -0
  121. package/dist/emit/diffJson.d.ts +1 -1
  122. package/dist/emit/diffJson.js +8 -1
  123. package/dist/emit/diffJson.js.map +1 -1
  124. package/dist/emit/engagementJson.d.ts +8 -0
  125. package/dist/emit/engagementJson.js +46 -0
  126. package/dist/emit/engagementJson.js.map +1 -0
  127. package/dist/emit/glossaryJson.d.ts +1 -1
  128. package/dist/emit/glossaryJson.js +4 -1
  129. package/dist/emit/glossaryJson.js.map +1 -1
  130. package/dist/emit/json.d.ts +17 -1
  131. package/dist/emit/json.js +30 -1
  132. package/dist/emit/json.js.map +1 -1
  133. package/dist/emit/metricsJson.d.ts +1 -1
  134. package/dist/emit/metricsJson.js +4 -1
  135. package/dist/emit/metricsJson.js.map +1 -1
  136. package/dist/emit/queryJson.d.ts +1 -1
  137. package/dist/emit/queryJson.js +7 -1
  138. package/dist/emit/queryJson.js.map +1 -1
  139. package/dist/emit/scopeJson.d.ts +12 -0
  140. package/dist/emit/scopeJson.js +26 -0
  141. package/dist/emit/scopeJson.js.map +1 -0
  142. package/dist/emit/skillCheckJson.d.ts +3 -2
  143. package/dist/emit/skillCheckJson.js +10 -2
  144. package/dist/emit/skillCheckJson.js.map +1 -1
  145. package/dist/emit/statusJson.d.ts +1 -1
  146. package/dist/emit/statusJson.js +15 -1
  147. package/dist/emit/statusJson.js.map +1 -1
  148. package/dist/emit/systemJson.d.ts +15 -8
  149. package/dist/emit/systemJson.js +28 -13
  150. package/dist/emit/systemJson.js.map +1 -1
  151. package/dist/emit/validateJson.d.ts +3 -3
  152. package/dist/emit/validateJson.js +10 -4
  153. package/dist/emit/validateJson.js.map +1 -1
  154. package/dist/mcp/server.d.ts +1 -1
  155. package/dist/mcp/server.js +163 -31
  156. package/dist/mcp/server.js.map +1 -1
  157. package/dist/model/diff.d.ts +4 -1
  158. package/dist/model/diff.js +44 -8
  159. package/dist/model/diff.js.map +1 -1
  160. package/dist/model/glossary.d.ts +2 -0
  161. package/dist/model/glossary.js +1 -0
  162. package/dist/model/glossary.js.map +1 -1
  163. package/dist/model/model.d.ts +55 -2
  164. package/dist/model/model.js +57 -0
  165. package/dist/model/model.js.map +1 -1
  166. package/dist/model/qualifiedRef.d.ts +18 -0
  167. package/dist/model/qualifiedRef.js +26 -0
  168. package/dist/model/qualifiedRef.js.map +1 -1
  169. package/dist/model/queryIndex.d.ts +9 -1
  170. package/dist/model/queryIndex.js +18 -2
  171. package/dist/model/queryIndex.js.map +1 -1
  172. package/dist/model/rules.d.ts +143 -2
  173. package/dist/model/rules.js +162 -3
  174. package/dist/model/rules.js.map +1 -1
  175. package/dist/model/validate.d.ts +40 -0
  176. package/dist/model/validate.js +147 -1
  177. package/dist/model/validate.js.map +1 -1
  178. package/dist/parser/ast.d.ts +31 -3
  179. package/dist/parser/parser.js +148 -14
  180. package/dist/parser/parser.js.map +1 -1
  181. package/dist/query/format.js +1 -1
  182. package/dist/query/format.js.map +1 -1
  183. package/dist/query/verbs.d.ts +6 -0
  184. package/dist/query/verbs.js +6 -2
  185. package/dist/query/verbs.js.map +1 -1
  186. package/dist/system/adaptation.d.ts +14 -0
  187. package/dist/system/adaptation.js +49 -0
  188. package/dist/system/adaptation.js.map +1 -0
  189. package/dist/system/codeowners.d.ts +77 -0
  190. package/dist/system/codeowners.js +242 -0
  191. package/dist/system/codeowners.js.map +1 -0
  192. package/dist/system/manifest.d.ts +10 -5
  193. package/dist/system/manifest.js +54 -26
  194. package/dist/system/manifest.js.map +1 -1
  195. package/dist/system/migrateManifest.d.ts +28 -0
  196. package/dist/system/migrateManifest.js +155 -0
  197. package/dist/system/migrateManifest.js.map +1 -0
  198. package/dist/system/scope.d.ts +46 -0
  199. package/dist/system/scope.js +132 -0
  200. package/dist/system/scope.js.map +1 -0
  201. package/dist/system/verify.d.ts +50 -13
  202. package/dist/system/verify.js +179 -58
  203. package/dist/system/verify.js.map +1 -1
  204. package/dist/templates.d.ts +2 -2
  205. package/dist/templates.js +23 -2
  206. package/dist/templates.js.map +1 -1
  207. package/package.json +5 -2
  208. package/plugin/.claude-plugin/plugin.json +18 -0
  209. package/plugin/agents/em-critic.md +27 -0
  210. package/plugin/agents/em-implementer.md +35 -0
  211. package/plugin/agents/em-reviewer.md +32 -0
  212. package/plugin/agents/em-validator.md +28 -0
  213. package/plugin/shared/reference/em-dsl.md +871 -0
  214. package/plugin/shared/reference/methodology.md +329 -0
  215. package/plugin/shared/reference/operating-principles.md +222 -0
  216. package/plugin/shared/reference/slice-doc-schema.md +574 -0
  217. package/plugin/shared/templates/conformance-report.md +85 -0
  218. package/plugin/shared/templates/constitution.md +136 -0
  219. package/plugin/shared/templates/model-readme.md +46 -0
  220. package/plugin/shared/templates/slice.md +251 -0
  221. package/plugin/shared/templates/state.md +77 -0
  222. package/plugin/skills/conform/SKILL.md +93 -0
  223. package/plugin/skills/conform/reference/conform.md +428 -0
  224. package/plugin/skills/design/SKILL.md +298 -0
  225. package/plugin/skills/discover/SKILL.md +90 -0
  226. package/plugin/skills/discover/reference/extract.md +147 -0
  227. package/plugin/skills/engagement/SKILL.md +193 -0
  228. package/plugin/skills/engagement/reference/engagement.md +144 -0
  229. package/plugin/skills/event-modeling/SKILL.md +132 -0
  230. package/plugin/skills/implement/SKILL.md +61 -0
  231. package/plugin/skills/implement/reference/implement.md +439 -0
  232. package/plugin/skills/review/SKILL.md +74 -0
  233. package/dist/emit/typespec.d.ts +0 -26
  234. package/dist/emit/typespec.js +0 -356
  235. package/dist/emit/typespec.js.map +0 -1
@@ -0,0 +1,439 @@
1
+ <!-- GENERATED FILE from .claude/skills/event-modeling-implement/reference/implement.md by scripts/build-plugin.ts — do not hand-edit; run npm run docs:generate -->
2
+ # Implementing a ratified slice
3
+
4
+ The contract for the implementation half of the workflow: an agent (or engineer) turning **one
5
+ ratified slice** into merged, verified code. The facilitation phases (`discover`/`extract` →
6
+ `model` → `slice`) produce the inputs; this document governs consuming them. It applies to any
7
+ implementing agent, whether or not the session started from `/em:event-modeling`.
8
+
9
+ **The contract in one paragraph:** the slice doc is the spec — nothing between it and the code
10
+ is a source of truth. Verify readiness mechanically before writing any code; implement exactly
11
+ what the doc says; put every gap in front of a human instead of deciding it silently; never
12
+ edit the ratified doc except the two lifecycle fields at merge; prove the work with tests
13
+ traceable to the doc's invariants and scenarios.
14
+
15
+ Why the rules are shaped this way: **agents propose, humans ratify.** Everything in the model
16
+ and its slice docs is there because a human decided it on purpose — that is what makes the
17
+ model authoritative. An implementing agent that silently patches a gap, or edits a ratified
18
+ doc outside a session, converts the model into just another generated artifact and voids the
19
+ whole methodology. (The full human/agent partition is `docs/process.md` in the
20
+ [em repository](https://github.com/milehimikey/em/blob/main/docs/process.md) — not vendored
21
+ with this skill.)
22
+
23
+ ## 1. Gate: verify readiness before starting
24
+
25
+ ```bash
26
+ em validate <model>.em --slice-ready <slice-key> --json
27
+ ```
28
+
29
+ `<slice-key>` is the slice's export key — the kebab-case slug of its name (`"Place Order"` →
30
+ `place-order`). Don't guess it or hand-slug the name yourself: list every slice's key with
31
+ `em export <model>.em | jq -r '.model.slices[].key'`. Read the JSON document's `ready` field —
32
+ don't infer it from the exit code or any printed text. `ready: true` means: the slice has a doc
33
+ bound via `note "slices/<key>.md"`, its frontmatter is usable, `status: ready-to-implement`,
34
+ every `## Open Questions` checkbox is checked, and no status/version/link incoherence is flagged
35
+ — `gates` names each of those 4 conditions individually (`docBound`/`frontmatterUsable`/
36
+ `statusReady`/`noUncheckedOpenQuestions`) if you need to say which one is blocking.
37
+
38
+ **`ready: false` means stop** — with one named exception: a slice already `status: implemented`
39
+ with `driftSignal: in-sync` or `uncertified` (MIL-214) also reads `ready: false` (its
40
+ `statusReady` gate fails because nothing is newly ratified), and that specific case is
41
+ re-implementation/repair, not a blocker — see §3's third mode before treating it as one. For
42
+ every other `false`, report which `gates`
43
+ entries are `false` (and any `diagnostics` entries concerning this slice) and hand the slice
44
+ back to the humans. Never make the gate pass yourself — checking an open-question box, flipping
45
+ `status`, or editing frontmatter are ratification decisions, and ratification happens in a
46
+ facilitated session, not in an implementation branch.
47
+
48
+ ## 2. Read the spec
49
+
50
+ **First, read the project's constitution** — the house rules for *how* implementation happens
51
+ here (stack and architectural shape, which implementation skill each slice pattern routes to,
52
+ code style, testing norms, NFR baselines, review and merge norms). It lives in one of exactly two
53
+ places, never both:
54
+
55
+ - **spec-kit project** (a `.specify/` directory exists at or above the model):
56
+ `.specify/memory/constitution.md` — spec-kit's own slot, which em defers to.
57
+ - **anything else**: `constitution.md` beside the model, where `em scaffold` writes it.
58
+
59
+ `em status <model>.em --json` reports which one applies and whether it's there
60
+ (`conformance[].constitution`) — existence only; nothing in `em` reads or judges its content.
61
+ **Its rules bound every technical choice you make on this slice** (see §4). If it's missing, or
62
+ its `ratifiedBy:` is empty (spec-kit's file: the `**Ratified**:` footer still a placeholder),
63
+ it isn't ratified — go to §7 before writing code.
64
+
65
+ Then read `slices/<slice-key>.md` end to end — every section is load-bearing:
66
+
67
+ | Section | What it is to the implementer |
68
+ |---|---|
69
+ | frontmatter `pattern:` | Which of the four patterns' implementation shapes to build (State Change / State View / Automation / Translation) |
70
+ | Command / Event field tables | The contracts — names, types, validation rules, immutable-fact markers |
71
+ | `## Invariants / Business Rules` (`INV-<MNEMONIC>-n` IDs) | The non-negotiable rules; every one needs a test citing its ID |
72
+ | `## Scenarios (Given / When / Then)` | The acceptance tests, already written — compile them, don't reinvent them |
73
+ | `## Alternate & Error Flows` | Retries, idempotency, compensations — real requirements, not appendix |
74
+ | `## Non-Functional Requirements` | Authz, PII, performance — implement or consciously surface, never skip |
75
+ | `## Dependencies & Read Models Affected` | The blast radius — what else to check before and after |
76
+
77
+ **Interface obligations follow from the model, not from the doc's prose.** The DSL already
78
+ encodes what's reachable — see `em-dsl.md`'s "Headless / API systems & repeated read models"
79
+ section — and the routing from it is mechanical, not a technical choice you make while coding:
80
+
81
+ - A **command with a `ui` trigger** ships the endpoint that dispatches it as part of this slice
82
+ — shape, verb, status codes, and error mapping follow the constitution's interface conventions
83
+ (§7). Because: the model already said this command is reachable from outside; leaving it
84
+ reachable only through an internal gateway silently narrows what the model ratified.
85
+ - A **view with a `ui` consumer** ships the query endpoint as part of this slice, same
86
+ conventions.
87
+ - **No `ui`** on the trigger or the consumer (a command dispatched by a processor or a
88
+ translation, a view read only by a reaction) means internal-only: no endpoint. If one seems
89
+ needed anyway, that's a gap to surface (§4), not a technical choice to make mid-implementation
90
+ — adding a route the model doesn't show is exactly the kind of silent divergence §4 exists to
91
+ catch. An endpoint on a view the model shows no `ui` reading is a gap to surface the same way
92
+ (MIL-215) — conform will classify it as a **model gap**, never drift to delete, once you flag
93
+ it (`../../conform/reference/conform.md`, Flow step 4).
94
+ - **`public` commands, events and views** are the model's published integration surface: their
95
+ shape is a contract, not an implementation detail. `em validate --list-public` lists them;
96
+ `em api generate` writes the model-owned contract (`<model dir>/contracts/<model key>.tsp`).
97
+ Changing a public element's shape is a ratified delta, never an implementation-time choice.
98
+
99
+ For timeline context, read the slice's surroundings in the `.em` (what triggers it, what
100
+ consumes its output) — the slice's own diagram (`slices/<slice-key>.svg`) shows its canonical
101
+ pattern shape. For machine-readable facts, use `em export <model>.em --slice <slice-key>`
102
+ rather than parsing the DSL or the doc's frontmatter yourself: it returns just this slice's
103
+ object — `pattern`, element refs, fields, and the joined doc metadata (`slice.doc.status`,
104
+ `version`, `driftSignal`) — without piping the whole model's export to find one `slice.doc`.
105
+ When the view repeats later via `again` (MIL-208), that same call on the *originating* slice
106
+ also returns `alsoReads: [{ event, atSlice }]` — the union of every event the read model
107
+ consumes across all its later continuations, in timeline order — so implementing it never means
108
+ walking each continuation by hand to assemble the full event list.
109
+
110
+ If the project ships pattern-specific implementation skills (for example an Axon/DCB skill
111
+ set keyed on a slice doc's `pattern:` frontmatter), route by the slice's pattern and follow
112
+ those.
113
+
114
+ ## 3. Three modes: first version, ratified delta, re-implementation/repair
115
+
116
+ Check the doc's `version:` and `## Delta` section (or `em export`'s `slice.doc.driftSignal`):
117
+
118
+ - **First implementation** (`version: 1`, no `## Delta`, `driftSignal: never-implemented`):
119
+ green-field slice implementation. Build the whole pattern shape the doc specifies.
120
+ - **Ratified delta** (`version` > 1, `## Delta` present, `status: ready-to-implement` while
121
+ `implementedIn` still names the prior version's PR — `driftSignal: unpropagated-delta`):
122
+ this is a **change to existing, owned code**. The `## Delta` section's typed operations
123
+ (Added/Modified/Removed/Renamed, each with scenarios) scope the work precisely — which
124
+ invariants, which scenarios, which tests change. Touch what the delta names; leave the rest.
125
+ **Never regenerate merged code wholesale from the model** — after merge, code is owned by
126
+ the people who've edited it (generated-then-owned); regeneration is legal only for slices
127
+ whose code never merged.
128
+ - **Re-implementation / repair** (`status: implemented`, `implementedIn` set, `driftSignal:
129
+ in-sync` **or** `uncertified` (MIL-214 — certification status is orthogonal to whether the doc
130
+ changed; most shipped slices sit at `uncertified` until a conform sweep certifies them, which
131
+ doesn't change which mode this is) — `--slice-ready` reports `ready: false` purely because
132
+ `statusReady` fails, with no other gate false and no doc content changed): the doc hasn't
133
+ changed, but the shipped code
134
+ needs rebuilding or fixing — deleted code, a reverted PR, a bug in behavior the doc already
135
+ specifies. **The doc is still the spec.** The gate's `false` here means "nothing new is
136
+ ratified," not "stop" — it is not license to self-initiate: proceed only when a human has
137
+ asked for this specific re-work. Scope the change to what the repair needs, exactly like a
138
+ delta (generated-then-owned still applies — don't regenerate the whole slice wholesale just
139
+ because the gate reads oddly); if what you'd change is really a change in behavior rather than
140
+ a repair of it, that's a ratified delta (the bullet above), not this mode — when unsure which
141
+ one you're in, ask the human rather than guess.
142
+
143
+ No lifecycle flip is needed unless `implementedIn` changes. If it does,
144
+ `em slice mark-implemented <model>.em <slice-key> <new-pr-url>` will **refuse** rather than
145
+ overwrite: a doc already `implemented` with a different `implementedIn` URL is left untouched
146
+ and the command reports the conflict (`src/cli/markImplemented.ts`) instead of silently
147
+ replacing provenance. That refusal is correct, not a bug to route around — never hand-edit the
148
+ frontmatter to force it through. Surface the conflict to the human instead: they decide whether
149
+ the new PR supersedes the recorded one (and re-run `mark-implemented` themselves, or ask you to,
150
+ once they've decided) or whether the existing link should stand.
151
+
152
+ ## 4. Gaps: propose, never decide
153
+
154
+ Mid-implementation you will hit things the doc doesn't answer — a field's edge case, an
155
+ undocumented ordering, a contradiction with adjacent code. The discipline:
156
+
157
+ - **Stop that thread and surface it.** State precisely what's unspecified, the options, and
158
+ your recommendation. The human resolves it — at the model, where the resolution lands as an
159
+ answered open question or a small ratified delta alongside your fix, so the decision is
160
+ recorded instead of buried in an implementation diff.
161
+ - **How a delta is ratified on a doc that never shipped** (it is `ready-to-implement` with
162
+ `ratifiedBy` set): once the human has answered, the doc changes by `em slice reratify
163
+ <model>.em <slice-key>` (bumps `version:`, clears the old sign-off, leaves `status` alone),
164
+ the answer is written into the doc, and the human re-signs with `em slice ratify <model>.em
165
+ <slice-key> --by <name>` — on a slice owning a `public` element both commands also need
166
+ `--meaning-unchanged` or `--contract-change "<why>"` (MIL-238). That is the human's step, not
167
+ yours — you never run `ratify`, and
168
+ the doc is not ratified again until they do; resume the build after that.
169
+ - **Never edit the ratified doc to record your own answer**, and never quietly pick a behavior
170
+ a business person could have an opinion on. Silent divergence is the failure mode the whole
171
+ conformance loop exists to catch — don't manufacture it.
172
+ - Purely technical choices with no behavioral surface (private naming, idiomatic structure,
173
+ which assertion library) are yours — **within the constitution's rules** (§2); anything
174
+ observable in behavior, data, or contract is not. If no constitution exists (or its
175
+ `ratifiedBy` is empty), surface that to the human and do not proceed on unilateral style or
176
+ stack decisions for a first slice: run the constitution step (§7) first.
177
+
178
+ ## 5. Definition of done
179
+
180
+ **The unit is the slice doc: one slice doc = one PR.** A doc that `covers:` another slice (an
181
+ automation's to-do-list view and its reaction, MIL-121) is one spec, not two — it ships in one
182
+ PR, and `mark-implemented` runs for both keys against the same URL. A read model is one doc,
183
+ even when a `view X again` clause repeats it across later positions on the timeline (MIL-208):
184
+ the later instance is a **continuation** of the slice holding `X`'s first declaration, not a
185
+ spec unit of its own — no doc, no status, no ratification, no PR of its own. Its behavior
186
+ belongs in the originating doc's `## Scenarios` (one scenario per event the later instance
187
+ feeds), not a doc of its own; `em export --slice <originating-key>` lists the full union of
188
+ events the read model consumes across every position via `alsoReads` (§2). Never fold multiple
189
+ slice docs' implementations into one PR because they touch the same read model, ship together,
190
+ or seem small — see §10.
191
+
192
+ - The PR description cites exactly one slice doc (plus its `covers:` keys, if any) and lists
193
+ that doc's invariants alongside the tests that cover them.
194
+ - Every `INV-<MNEMONIC>-n` invariant has at least one test that cites its ID — checked mechanically by
195
+ `em coverage <model>.em --slice <slice-key> --tests <dir> --strict` (MIL-130, MIL-255); run it
196
+ before merge rather than eyeballing citations by hand. `--slice` is what makes this check the
197
+ slice under build: the default form, `em coverage <model>.em --tests <dir>`, counts only slices
198
+ already flipped to `implemented` (MIL-207), and your slice is still `ready-to-implement` until
199
+ the §6 flip — so the default form reports it `inScope: false`, checks nothing, and exits 0. It
200
+ is a regression check for shipped slices, not the definition-of-done check. (`--include-ready`
201
+ is no substitute: it counts every ratified slice, so `--strict` fails on slices nobody has
202
+ 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.
203
+ - Every scenario in `## Scenarios (Given / When / Then)` exists as a passing test; rejection
204
+ scenarios assert the doc's named rejection reason.
205
+ - Alternate/error flows (idempotency included) are covered by tests.
206
+ - The build and full test suite are green; the model still validates (`em validate` in CI —
207
+ you didn't touch the `.em`, so this only fails if something else broke).
208
+ - Nothing between the slice doc and the code was committed as a source of truth (see §9 —
209
+ work containers are ephemeral; generated or symlinked specs are renderings).
210
+
211
+ ## 6. At merge: the lifecycle flip
212
+
213
+ The PR being merged here is the one doc's PR (§5) — its description cites exactly this slice doc
214
+ (plus any `covers:` keys) and nothing else, which is what makes the flip below unambiguous: one
215
+ PR, one `implementedIn` URL, applied to every key that PR's doc covers.
216
+
217
+ When the PR merges, exactly **two** frontmatter fields change on the slice doc:
218
+
219
+ ```yaml
220
+ status: implemented
221
+ implementedIn: <PR or commit URL>
222
+ ```
223
+
224
+ This is supply-loop mechanics, not ratification — it's the one edit an implementing agent makes
225
+ to a slice doc, and it's why `em ledger` deliberately excludes these two fields from what
226
+ counts as content. **Do not bump `version:`** — versions bump only when a delta is ratified;
227
+ a bump here is a ledger defect.
228
+
229
+ `em slice mark-implemented <model>.em <slice-key> <pr-url>` does the flip for you (MIL-103) —
230
+ resolves the doc via the same note-binding join `--slice-ready` uses, is idempotent on a re-run
231
+ with the same URL, and refuses (never silently overwrites) if the doc is already `implemented`
232
+ with a different URL. Prefer it over hand-editing the doc's frontmatter.
233
+
234
+ Then, if the project keeps a model README (from `../../../shared/templates/model-readme.md`), run
235
+ `em slice index <model-name>.em` so its generated Slices table reflects the new status and
236
+ link — never hand-edit that table. The `implementedIn` link is what the `conform` phase later
237
+ uses to anchor drift-checking — leaving it empty blinds the loop.
238
+
239
+ ## 7. Before the first slice: the constitution
240
+
241
+ The first time this project's slices reach implementation — or any time §2 finds no constitution,
242
+ or one whose `ratifiedBy` is still empty — **stop and run this short conversation before writing
243
+ code.** It happens once per project, not once per slice.
244
+
245
+ Start from the template the skill bundle ships,
246
+ `../../../shared/templates/constitution.md`. Each of its five sections opens with the
247
+ question to ask; ask them **conversationally, one section at a time**, and write the answers into
248
+ the document as you go — never fill a section by guessing, by reading the codebase and inferring
249
+ "what they probably do", or by pasting the template's own examples. Unanswerable questions get
250
+ parked in the document as open items, exactly like a slice doc's Open Questions:
251
+
252
+ 1. **Stack and architectural shape** — languages/runtimes, frameworks, the architectural pattern,
253
+ where a slice's code lives, and the routing table: which implementation skill or approach each
254
+ of the four slice patterns uses (for example, State Change slices → the `axon-*` skill set).
255
+ That table is what you obey in §2 when you read a slice's `pattern:`. This is also where the
256
+ **interface conventions** question gets asked — resource style, error/rejection mapping,
257
+ versioning, auth at the edge — so the shape of every endpoint the interface obligations
258
+ paragraph (§2) and the foundation step (§8) require is decided once, here, instead of
259
+ invented per slice.
260
+ 2. **Code style** — formatter/linter, naming, module layout, and what "idiomatic" means here.
261
+ 3. **Testing norms** — which test levels each pattern requires, where invariant and scenario
262
+ tests live, and the test-naming convention that lets `em coverage` trace `INV-<MNEMONIC>-n`
263
+ citations.
264
+ 4. **NFR baselines** — authz model, PII handling, performance defaults, observability: the
265
+ standing defaults every slice inherits where its own `## Non-Functional Requirements` section
266
+ is silent.
267
+ 5. **Review and merge norms** — who reviews, what blocks a merge, and who runs
268
+ `em slice mark-implemented` at merge (§6).
269
+
270
+ **A human ratifies it.** The answers are the project's, not yours — you drafted the wording, they
271
+ sign it off. In the em-native file that's the `ratifiedBy:`/`ratifiedOn:` frontmatter (a named
272
+ person and an ISO date, hand-filled — no `em` command writes this file, and an empty `ratifiedBy:`
273
+ means *draft*). In a spec-kit project it's that file's own `**Ratified**:` footer line — never add
274
+ frontmatter to spec-kit's document. Until it's ratified, treat it as a proposal: you may not
275
+ build a first slice on it.
276
+
277
+ **In a spec-kit project, merge — never duplicate.** The constitution IS
278
+ `.specify/memory/constitution.md`; em writes no second file and neither do you. Append em's five
279
+ sections to it under their own `##` headings, **leaving every existing section byte-untouched** —
280
+ including spec-kit's own `## Core Principles` and `## Governance`, and any principle a team
281
+ already wrote. If a heading of the same name is already there, add to it rather than replacing it,
282
+ and show the human the diff before writing. Two cautions: spec-kit's `/speckit.constitution`
283
+ command rewrites that whole file from its template, so run it (if at all) **before** this
284
+ conversation, never after — and never use it to author em's sections. If the file is still the
285
+ blank stock template (`[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`, … placeholders), say so: filling
286
+ spec-kit's own placeholders is the team's call, and em's sections go in alongside them either way.
287
+
288
+ `em status` will then report `constitution: present` for the model. That's the whole mechanical
289
+ check — em stores and locates this document, and never validates a word of it.
290
+
291
+ ## 8. Foundation: contracts first
292
+
293
+ Once per project, before the first slice PR ever opens, land one **foundation PR** that turns
294
+ the model's events — and the cross-cutting shell the constitution names — into code, and
295
+ nothing else. Skip this and the failure is the same on every project that's skipped it: the
296
+ first slice PR ships fine, then the second one needs an event the first slice already defined
297
+ informally, and every PR after that either redefines it slightly differently or reaches into a
298
+ sibling slice's package to reuse it — the boundary the constitution drew is gone within a week.
299
+
300
+ 1. **What it contains.** Every event `em export <model>.em` lists in `events[]`, each placed in
301
+ the home the constitution's "where a slice's code lives" rule assigns to its *emitting*
302
+ slice — not a separate shared "events" module, so nothing about where an event lives depends
303
+ on this PR existing rather than the constitution. Fields come verbatim from the slice docs'
304
+ Event tables, with types mapped per the constitution's stack conventions. Add the
305
+ cross-cutting shell the constitution names: shared ports, and the request/response boundary
306
+ and error mapping the interface obligations above (§2) plug their endpoints into. **No
307
+ handlers, no projections — contracts only.** Because: a handler or a projection belongs to
308
+ the slice that owns the behavior behind it; folding one into the foundation PR turns a shared
309
+ contract into a pre-empted slice.
310
+ 2. **It merges before any slice PR opens.** Every slice branch is cut *after* the foundation PR
311
+ has landed on `main` — never from a commit that predates it, and never alongside an open,
312
+ unmerged foundation PR. Within an engagement, cut the slice branch from the base the
313
+ engagement plan names (`em engagement plan`); outside an engagement, from `main`. A slice PR
314
+ never carries foundation files. Because: a slice PR opened while the foundation is still in
315
+ review shows a diff dominated by files the slice didn't write and can't be held accountable
316
+ for, and its merge depends on someone else's review timeline instead of its own. The plan's
317
+ base is either `main` or `impl/<upstream>` (the one unmerged upstream slice this slice builds
318
+ on); either way it already contains the foundation.
319
+
320
+ 2a. **While a dependent PR is open, the lower PR merges with a merge commit; squash is forbidden
321
+ in that state (it strands the dependent's history).** A PR is the *lower* one when another
322
+ open PR targets its branch as its base. Once no open PR depends on it, the project's usual
323
+ merge strategy applies. Because: a squash rewrites the lower branch's commits into one new
324
+ commit on `main`, so the dependent branch still carries the originals and its diff against
325
+ `main` shows them again — it then needs a hand rebase (`git rebase --onto main <old base
326
+ tip>`). A merge commit keeps the original commits: once the lower branch is merged and
327
+ deleted, the dependent is retargeted to `main` and its diff shrinks to its own commits with
328
+ no rebase.
329
+
330
+ 3. **A slice never creates, edits, or reaches into another slice's code.** It *imports* events —
331
+ only events — from wherever the foundation placed them; a sibling slice's handlers, storage,
332
+ and other internals stay off limits. Because: the boundary the constitution drew only holds if
333
+ every slice actually stays inside it — a slice that quietly builds on a sibling's internals has
334
+ erased that boundary informally, one import at a time.
335
+ 4. **A ratified delta that adds or changes an event re-runs this step for that event, first.**
336
+ Land the code change for the new or changed event — in its emitting slice's home, following
337
+ rule 1 — before the slice's delta PR opens, exactly as if it were the first pass. Because: the
338
+ same contract-before-consumer ordering that applies once per project applies again every time
339
+ the contract itself changes; an event isn't a stable shared type just because it was one
340
+ yesterday.
341
+
342
+ ### Order of work
343
+
344
+ The foundation PR above answers most of "which slice next" by itself — once every event exists
345
+ as a contract, a read slice no longer has to wait for the write slice that will eventually
346
+ produce it. What's left is ordering the slice PRs against each other, and that ordering comes
347
+ from the dependency graph, not from where a slice sits on the timeline:
348
+
349
+ 1. **Foundation first removes most ordering constraints.** With every event already landed as a
350
+ contract (rules 1–4 above), a slice's remaining dependency is on other *slices*, not on
351
+ events existing at all — that's what turns "order every slice against every other slice"
352
+ into the short, per-pattern list below.
353
+ 2. **Then take dependency order from the graph, not the timeline.** Before starting a slice,
354
+ run `em query upstream <model>.em --of <slice's command-or-view ref>` — anything it returns
355
+ that's still `ready-to-implement` is a candidate to build first; `em query producers
356
+ <model>.em --event <name>` names the slices that own a specific event's producing commands
357
+ when you need to check one directly. Concretely, per pattern:
358
+ - **State Change** with no upstream is always startable — nothing but the foundation gates it.
359
+ - **State View** is startable as soon as the events it reads exist as contracts (the
360
+ foundation alone satisfies this), but build it *after* their producing slices have merged
361
+ when you can — its fixture tests then exercise real commands instead of hand-rolled event
362
+ fixtures.
363
+ - **Automation** goes after both the command it triggers and the to-do-list view it reads
364
+ (bound via `covers:` when the two are written as one doc) — a reaction can't be tested
365
+ against a command handler or a to-do list that doesn't exist yet.
366
+ - **Translation** goes after the command it triggers, same reasoning as an Automation's
367
+ triggered-command dependency.
368
+ 3. **Timeline order is the ratification order, not the build order.** Ratifying slices in
369
+ timeline order is deliberate — it's the order stakeholders reason about the business process
370
+ in. Carrying that same order into implementation is the mistake this section exists to head
371
+ off: build order comes from the dependency graph above, and the two orders routinely
372
+ disagree.
373
+
374
+ ## 9. Spec-kit projects: the SDD adapter
375
+
376
+ If the repository uses spec-kit (a `.specify/` directory exists), do not hand-author spec-kit
377
+ artifacts — allocate through **em-sdd-bridge**, redirect mode preferred:
378
+
379
+ ```bash
380
+ npx em-sdd-bridge@<pinned-version> <slice-key> --symlink
381
+ ```
382
+
383
+ That allocates the feature branch and `specs/NNN-slug/` dir, runs the same readiness gates,
384
+ and drops `spec.md` as a **symlink to the slice doc** — the slice doc itself travels through
385
+ plan/tasks as FEATURE_SPEC. The rules that keep redirect mode safe:
386
+
387
+ - **Never run `/speckit.specify`.** The ratified slice *is* the spec; an interactive specify
388
+ session against a defined slice creates a second, unratified source of truth.
389
+ - **`/speckit.clarify` must never write into a slice doc.** Open questions resolve at the
390
+ model (that's what the readiness gate enforced); a ratified slice has nothing to clarify.
391
+ Projects using em-sdd-preset's overlays carry a mechanical guard for this — respect the
392
+ rule even where the guard isn't installed.
393
+ - `/speckit.plan` and `/speckit.tasks` may run against the slice doc directly; the preset's
394
+ redirect preambles map spec-kit's section vocabulary onto the slice doc's sections.
395
+ - **Emission fallback**: where redirect can't work (Windows checkouts without symlink
396
+ privileges, a toolchain that mutates its spec files), run the bridge without `--symlink` to
397
+ render `spec.md` from the slice doc. The generated file is a rendering — never hand-edit it;
398
+ regenerate it from the slice doc instead.
399
+ - Everything under `specs/NNN-*/` is an **ephemeral work container** — one per change effort,
400
+ discardable; the PR is the durable record of the effort, the slice doc the durable
401
+ definition of the behavior.
402
+
403
+ No spec-kit (or any SDD tool)? Implement straight from the slice doc — it already contains
404
+ everything a spec holds. Don't introduce an intermediate spec document of your own.
405
+
406
+ ## 10. Never do
407
+
408
+ | Rule | Because |
409
+ |---|---|
410
+ | Never implement from a slice that fails `--slice-ready` | The gate is the handoff contract; bypassing it hands you unratified decisions |
411
+ | Never edit a ratified slice doc, except the two §6 fields at merge | Doc content is ratified; edits outside a session are unratified decisions |
412
+ | Never edit the `.em` model | Model edits are ratified decisions — propose, don't write |
413
+ | Never bump `version:` | Versions move only with ratified deltas; see `em ledger` |
414
+ | Never silently decide unspecified behavior | Silent divergence is the disease the conformance loop exists to catch |
415
+ | 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 |
416
+ | Never regenerate merged code from the model | Generated-then-owned: post-merge code belongs to its owners |
417
+ | Never commit an authored intermediate spec | The slice is the spec; anything between it and the code is a rendering |
418
+ | 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) |
419
+ | 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` |
420
+ | Stay on your side of the seam: never edit another model's directory, slice docs or contract file | Another model's `public` element is its owners' decision; a needed change goes to them as a seam change request, not into your PR |
421
+ | Never hand-edit a generated contract (`contracts/*.tsp`) | It is derived from the model by `em api generate`; a hand edit is a contract change nobody ratified |
422
+
423
+ **Mirror image of the design write scope (MIL-236).** The design session never writes generated
424
+ contracts, SDD/spec artifacts (`specs/`, `.specify/`), implementation source, or a draft's
425
+ `version:`, and never reads code as evidence for a modeling decision (see
426
+ `../../../shared/reference/operating-principles.md`, "Write scope and evidence").
427
+ Implementation is the other side: implement reads them; design never writes them. You read the
428
+ contract and the constitution as inputs, work in code and (on spec-kit projects) the `specs/`
429
+ container per §9, and never write the model or its slice docs (except the two §6 fields at
430
+ merge).
431
+
432
+ ## 11. Afterward: the loop closes
433
+
434
+ Implementation isn't the end of the slice's story. On a cadence — or whenever someone asks —
435
+ the `conform` phase checks implemented slices against the code, using the `implementedIn` link
436
+ you recorded, and reports drift for humans to rule on (see the `em:conform` skill's
437
+ `reference/conform.md`). Your two
438
+ duties to that future loop are already behind you if you followed this doc: an accurate
439
+ lifecycle flip, and zero silent decisions.
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: review
3
+ em-version: 1.14.1
4
+ description: >-
5
+ Use when starting em's live browser viewer (`em watch --serve`) so a team can watch a model
6
+ update in real time, or facilitating a SCHEDULED stakeholder walkthrough that steps through
7
+ slices one at a time in Review mode, capturing anything the room raises live as `issue "..."`
8
+ red notes. Drives `em`'s watch and review phases.
9
+ ---
10
+ <!-- GENERATED FILE from .claude/skills/event-modeling-review/SKILL.md by scripts/build-plugin.ts — do not hand-edit; run npm run docs:generate -->
11
+
12
+ # Event Modeling — watch & review
13
+
14
+ ## Phase: `watch` — live team view
15
+
16
+ Start the watcher with `--serve` in the background:
17
+ `em watch <model-name>.em -o <model-name>.svg --serve` (run_in_background). It re-renders on every
18
+ save and pushes an instant reload to the browser over Server-Sent Events. Tell the user to open the
19
+ URL it prints (e.g. `http://localhost:5173/?svg=<model-name>.svg`) and share their screen — updates
20
+ appear the moment you save, with no polling and no idle churn between edits.
21
+
22
+ The viewer navigates like a map — drag to pan, scroll/pinch to zoom, **Fit** to reset — and its
23
+ **Review mode** steps through slices one at a time (see the `review` phase below). A save that
24
+ fails to render never blanks the shared screen: the last good diagram stays up, an error banner
25
+ explains what went wrong, and the viewer recovers on its own at the next successful render.
26
+
27
+ ## Phase: `review` — stakeholder walkthrough
28
+
29
+ Goal: step a real stakeholder review session through the model slice by slice, one slice
30
+ spotlighted at a time, with any open questions the room raises captured live as `issue "..."`
31
+ red notes.
32
+
33
+ **Trigger: a real stakeholder review session is on the calendar — a scheduled use, not
34
+ speculation.** Don't propose this phase proactively; it exists for facilitated reviews with
35
+ non-engineer stakeholders in the room, not routine model editing.
36
+
37
+ Start the same live server as `watch`: `em watch <model-name>.em -o <model-name>.svg --serve`
38
+ (run_in_background). Open the printed URL, click **Review mode** in the header, and share the
39
+ screen. Use Prev/Next (or the left/right arrow keys) to step through slices in declaration
40
+ order — each one pans/zooms into view with everything else dimmed, so the room's attention
41
+ tracks one slice at a time.
42
+
43
+ **When a State View slice is on screen, ask who reads it (MIL-215):** a person or client in the
44
+ room → the `ui` should draw it; another system → `public`; only an automation → nothing, it's
45
+ internal by design and needs no endpoint.
46
+
47
+ **Live capture:** when a stakeholder raises something unresolved, add `issue "..."` to the
48
+ relevant element in the `.em` file and save — exactly the same mechanism `em:conform`
49
+ uses for any other issue. The browser updates over the existing SSE push within moments, without
50
+ losing the current slice or resetting review mode.
51
+
52
+ Wrap-up: run `em validate --list-issues` to sweep everything captured during the session and
53
+ walk each one with the user, same as any open issue. Update the state file's Participants
54
+ section with who attended, and run `em state set-review <date>` to set the `Last stakeholder
55
+ review:` marker (mirrors `Last conformance:`).
56
+
57
+ **Per-slice outcome.** A slice whose open questions are all resolved in the room →
58
+ `em slice review <model>.em <key> --by <name>` (flips its doc to `status: reviewed` and records
59
+ `reviewedBy:`/`reviewedOn:`). Anything still open stays `draft` — the walkthrough doesn't decide
60
+ it, the next session or the open-questions list does. A question this version will not answer is deferred with `em slice defer <model> <key> "<question>" --until v<n> --decision "<what this version does>"` — never left `- [ ]`, never deleted, never answered by guessing.
61
+
62
+ **The facilitator never ratifies, never offers to ratify, and never suggests ratification in a
63
+ review session. Ratification is a separate human gate after review**
64
+ (docs/process.md#the-slice-lifecycle-gates). It is typically multi-person, routed through
65
+ CODEOWNERS on `slices/**`, and it is not this session's to run — `em slice ratify` will itself
66
+ refuse a doc that hasn't been through `em slice review`.
67
+
68
+ End of phase: state file's `Last stakeholder review:` marker updated, every walked slice whose
69
+ questions all closed moved to `status: reviewed`, every issue captured live triaged (resolved on the spot, moved to Open questions / parking lot, or left open on
70
+ purpose). Review doesn't chain to another phase — it's a recurring, scheduled activity like
71
+ `conform`, not a step in the discover → model → slice sequence.
72
+
73
+ Preconditions (tool check, model location) are the same as every other phase — see
74
+ `${CLAUDE_PLUGIN_ROOT}/shared/reference/operating-principles.md`.
@@ -1,26 +0,0 @@
1
- import { NormalizedModel } from "../model/model.js";
2
- import { RefsResult } from "../model/refs.js";
3
- import { Diagnostic } from "../model/validate.js";
4
- export declare const TYPESPEC_SCHEMA_VERSION = "1.0";
5
- export interface TypeSpecResult {
6
- /** TypeSpec source text, no trailing newline. */
7
- text: string;
8
- /** Same diagnostics `buildExport` would raise for this model (doc-join warnings, ref
9
- * collisions, etc.) — the caller decides how to print/gate these, same posture as
10
- * `buildExport`'s own `diagnostics` field. */
11
- diagnostics: Diagnostic[];
12
- /** Human-readable notes about fields whose em type string had no scalar mapping and fell
13
- * back to `unknown` — informational only, never blocking (POC's "best-effort inference with
14
- * a warning" choice — see the type-mapping section below). Empty when every included
15
- * field's type mapped cleanly, or declared no type at all (an untyped field isn't a mapping
16
- * failure — see `mapFieldType`). */
17
- unmappedTypes: string[];
18
- }
19
- export declare const SCALAR_TYPE_MAP: Readonly<Record<string, string>>;
20
- /**
21
- * Build the `em typespec <file>` document: TypeSpec source text for a model's contract
22
- * surface. Mirrors `buildExport`'s parameter contract exactly (same four inputs, same
23
- * "already-validated, error-free model" precondition — the caller, cli.ts, applies the same
24
- * refuse-on-error gate `em export` uses before calling this).
25
- */
26
- export declare function buildTypeSpec(model: NormalizedModel, refs: RefsResult, diagnostics: Diagnostic[], source: string, path: string): TypeSpecResult;