@milehimikey/em 1.21.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/.claude/agents/em-implementer.md +10 -0
  2. package/.claude/agents/em-validator.md +1 -0
  3. package/.claude/skills/event-modeling/SKILL.md +1 -1
  4. package/.claude/skills/event-modeling-conform/SKILL.md +7 -4
  5. package/.claude/skills/event-modeling-conform/reference/conform.md +82 -4
  6. package/.claude/skills/event-modeling-design/SKILL.md +1 -1
  7. package/.claude/skills/event-modeling-discover/SKILL.md +1 -1
  8. package/.claude/skills/event-modeling-engagement/SKILL.md +1 -1
  9. package/.claude/skills/event-modeling-engagement/reference/engagement.md +1 -0
  10. package/.claude/skills/event-modeling-implement/SKILL.md +5 -3
  11. package/.claude/skills/event-modeling-implement/reference/implement.md +14 -0
  12. package/.claude/skills/event-modeling-review/SKILL.md +1 -1
  13. package/.claude/skills/event-modeling-shared/reference/em-dsl.md +19 -6
  14. package/.claude/skills/event-modeling-shared/reference/operating-principles.md +26 -15
  15. package/.claude-plugin/marketplace.json +2 -2
  16. package/dist/cli/api.d.ts +84 -0
  17. package/dist/cli/api.js +146 -15
  18. package/dist/cli/api.js.map +1 -1
  19. package/dist/cli/bindings.d.ts +152 -0
  20. package/dist/cli/bindings.js +462 -0
  21. package/dist/cli/bindings.js.map +1 -0
  22. package/dist/cli/conformScope.d.ts +32 -0
  23. package/dist/cli/conformScope.js +68 -5
  24. package/dist/cli/conformScope.js.map +1 -1
  25. package/dist/cli/engagement.d.ts +24 -1
  26. package/dist/cli/engagement.js +50 -6
  27. package/dist/cli/engagement.js.map +1 -1
  28. package/dist/cli/engagementBrief.d.ts +127 -0
  29. package/dist/cli/engagementBrief.js +313 -0
  30. package/dist/cli/engagementBrief.js.map +1 -0
  31. package/dist/cli/engagementFile.d.ts +14 -0
  32. package/dist/cli/engagementFile.js +54 -0
  33. package/dist/cli/engagementFile.js.map +1 -1
  34. package/dist/cli/status.d.ts +5 -0
  35. package/dist/cli/status.js +1 -0
  36. package/dist/cli/status.js.map +1 -1
  37. package/dist/cli/upgrade.js +9 -10
  38. package/dist/cli/upgrade.js.map +1 -1
  39. package/dist/cli.js +143 -11
  40. package/dist/cli.js.map +1 -1
  41. package/dist/emit/api.d.ts +8 -1
  42. package/dist/emit/api.js +68 -24
  43. package/dist/emit/api.js.map +1 -1
  44. package/dist/emit/apiSurfaceJson.d.ts +3 -0
  45. package/dist/emit/apiSurfaceJson.js +26 -0
  46. package/dist/emit/apiSurfaceJson.js.map +1 -0
  47. package/dist/emit/engagementJson.d.ts +8 -3
  48. package/dist/emit/engagementJson.js +31 -4
  49. package/dist/emit/engagementJson.js.map +1 -1
  50. package/dist/mcp/server.js +91 -3
  51. package/dist/mcp/server.js.map +1 -1
  52. package/dist/model/model.d.ts +17 -5
  53. package/dist/model/model.js +18 -17
  54. package/dist/model/model.js.map +1 -1
  55. package/dist/templates.d.ts +4 -0
  56. package/dist/templates.js +29 -0
  57. package/dist/templates.js.map +1 -1
  58. package/package.json +1 -1
  59. package/plugin/.claude-plugin/plugin.json +2 -2
  60. package/plugin/agents/em-implementer.md +10 -0
  61. package/plugin/agents/em-validator.md +1 -0
  62. package/plugin/shared/reference/em-dsl.md +19 -6
  63. package/plugin/shared/reference/operating-principles.md +26 -15
  64. package/plugin/skills/conform/SKILL.md +7 -4
  65. package/plugin/skills/conform/reference/conform.md +82 -4
  66. package/plugin/skills/design/SKILL.md +1 -1
  67. package/plugin/skills/discover/SKILL.md +1 -1
  68. package/plugin/skills/engagement/SKILL.md +1 -1
  69. package/plugin/skills/engagement/reference/engagement.md +1 -0
  70. package/plugin/skills/event-modeling/SKILL.md +1 -1
  71. package/plugin/skills/implement/SKILL.md +5 -3
  72. package/plugin/skills/implement/reference/implement.md +14 -0
  73. package/plugin/skills/review/SKILL.md +1 -1
@@ -174,25 +174,36 @@ including sessions started from bare `/em:event-modeling`.
174
174
  <model-name>.svg # render target for em watch
175
175
  README.md # overview + slice index (from templates/model-readme.md)
176
176
  .event-modeling.md # resumable state (from templates/state.md)
177
+ constitution.md # implementation constitution (skipped, with a note, in a spec-kit project)
177
178
  slices/<slice-name>.md # one rich slice doc per slice (from templates/slice.md)
178
- conformance/<date>-report.md
179
- # conform-phase reports (from templates/conformance-report.md)
179
+ contracts/<model-name>.tsp
180
+ # `em api generate`'s generated TypeSpec contract — never hand-edit
181
+ model-versions/v<N>.json # `em model version bump`'s design-version snapshots
182
+ conformance/
183
+ <date>-report.md # conform-phase reports (from templates/conformance-report.md)
184
+ bindings/<slice-key>.yaml
185
+ # per-slice bindings manifests (`em conform bindings check`, GH #449)
180
186
  <model-name>-asis.em # conform-phase scratch model, regenerated per run — git-ignore this
181
187
  ```
182
188
 
183
- When creating a new model, run `em scaffold <model-name>` — it creates `<model-name>/` and
184
- writes all three starter files in one step (`<model-name>.em`, `README.md`,
185
- `.event-modeling.md`), filling the Model Name/model-name placeholders and the state file's
186
- mechanical fields (model path, `Current phase: discover`, `Current step: 1`, dates) for you, so
187
- there's nothing left to hand-copy or fill in. Refuses if `<model-name>/` already exists; pass
188
- `--force` to overwrite. You'll
189
- usually replace the scaffolded `.em`'s content as the discovery conversation builds up the real
190
- model — it starts out as the same starter model `em init` writes, titled from `<model-name>`.
191
- `slices/*.md` and `conformance/` aren't part of `em scaffold`; they come from the `slice` and
192
- `conform` phases (`em:design` and `em:conform`). The `conformance/`
193
- directory and `<model-name>-asis.em` only appear once the `conform` phase runs; `em conform-scope
194
- --seed-asis` creates `<model-name>-asis.em` and gitignores `*-asis.em` for you (see
195
- `em:conform`'s `reference/conform.md`) — it's scratch, never committed.
189
+ When creating a new model, run `em scaffold <model-name>` — it creates `<model-name>/`, writes
190
+ the four starter files in one step (`<model-name>.em`, `README.md`, `.event-modeling.md`,
191
+ `constitution.md`), filling the Model Name/model-name placeholders and the state file's
192
+ mechanical fields (model path, `Current phase: discover`, `Current step: 1`, dates) for you, and
193
+ also creates the standard `slices/`, `contracts/`, `model-versions/` and `conformance/bindings/`
194
+ directories — each seeded with a one-line README (never a `.gitkeep`) naming what lands there and
195
+ which command writes it. There's nothing left to hand-copy or fill in. Refuses if
196
+ `<model-name>/` already exists; pass `--force` to overwrite. You'll usually replace the
197
+ scaffolded `.em`'s content as the discovery conversation builds up the real model — it starts out
198
+ as the same starter model `em init` writes, titled from `<model-name>`.
199
+ Those directories exist from the start, but their real content doesn't — `slices/*.md` slice
200
+ docs come from the `slice` phase (`em:design`), `conformance/<date>-report.md`
201
+ reports from the `conform` phase (`em:conform`), and `contracts/*.tsp` /
202
+ `model-versions/*.json` / `conformance/bindings/*.yaml` only once `em api generate` / `em model
203
+ version bump` / an implementing agent's bindings manifest actually run. `<model-name>-asis.em` is
204
+ separate conform-phase scratch, not part of the scaffold at all; `em conform-scope --seed-asis`
205
+ creates it and gitignores `*-asis.em` for you (see `em:conform`'s
206
+ `reference/conform.md`) — it's scratch, never committed.
196
207
 
197
208
  ### Multi-model projects
198
209
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: conform
3
- em-version: 1.21.0
3
+ em-version: 1.22.0
4
4
  description: >-
5
5
  Use when checking a ratified event model (and its slice docs) for drift against the codebase
6
6
  that implements it — advisory only, never a gate, never an unprompted edit — or when walking
@@ -29,9 +29,12 @@ duplicating them.
29
29
  In short: run `em conform-scope <model-name>.em --repo <target-repo-path> --seed-asis` to
30
30
  compute the in-scope slice set (diff-scoped by default, via `Last conformance:` + the target
31
31
  repo's changed paths mapped through each slice doc's `implementedIn:`) and seed the scratch
32
- model in one step; for each in-scope slice, gather code evidence *before* comparing to the model
33
- or doc; write the as-is picture into that scratch model (`<model-name>-asis.em`, reusing the
34
- canonical model's names wherever the code matches them); run `em diff <model-name>.em
32
+ model in one step; for each in-scope slice, check for a `conformance/bindings/<key>.yaml` first
33
+ (GH #450) — verify it with `em conform bindings check` and scope the walk through it when it
34
+ exists, backfill it from this walk's own evidence when it doesn't — then gather code evidence
35
+ *before* comparing to the model or doc; write the as-is picture into that scratch model
36
+ (`<model-name>-asis.em`, reusing the canonical model's names wherever the code matches them);
37
+ run `em diff <model-name>.em
35
38
  <model-name>-asis.em --json` and let `em` decide the structural deltas; classify every finding
36
39
  (real drift / model gap / internal inconsistency / uncertainty) with cited evidence; write
37
40
  `conformance/<date>-report.md` **and its structured twin `conformance/<date>-findings.json`**
@@ -95,7 +95,7 @@ e.g. a PR link, deterministically matches nothing). It prints one JSON document
95
95
  ```json
96
96
  { "lastConformance": { "date": "...", "revision": "..." } | null,
97
97
  "changedPaths": ["..."],
98
- "candidateSlices": [ { "key": "checkout", "matchedBy": "implementedIn", "paths": ["..."] } ],
98
+ "candidateSlices": [ { "key": "checkout", "matchedBy": "implementedIn", "paths": ["..."], "file": null } ],
99
99
  "unmappedPaths": ["..."] }
100
100
  ```
101
101
 
@@ -105,6 +105,20 @@ your in-scope set for step 2. If `lastConformance` is `null` (first run) or you
105
105
  `changedPaths`/`unmappedPaths` both empty) — the tool makes this call for you, no need to
106
106
  special-case it yourself.
107
107
 
108
+ **Storyline models (GH #451).** A model may split its storylines into their own files — a root
109
+ declares `storyline "Name" [after "Other"]` with no body, and the storyline's slices live in
110
+ `<slug>/<slug>.em` (`docs/dsl.md`'s "Storyline models" section). `em conform-scope` already
111
+ compiles the root plus every storyline file it declares as ONE model
112
+ (the same way every other `em` command does — a storyline file never compiles on its own), so
113
+ scoping via `implementedIn` needs no special handling. What DOES change: each `candidateSlice`'s
114
+ `file` names the storyline file that slice's body lives in — posix, relative to the model's
115
+ directory — or `null` for a slice in the root file. This is which physical file you anchor on in
116
+ step 2 and which scratch file you write the as-is picture into in step 3 (`--seed-asis` seeds one
117
+ scratch file per physical file, not just the root — see there). Don't confuse a slice's `file`
118
+ with its doc's path: slice docs for a storyline model live under that storyline's own
119
+ `slices/` folder, but `em` finds them by key across every folder regardless, so doc resolution
120
+ itself needs no extra care.
121
+
108
122
  **`unmappedPaths` is your judgment queue, not a dead end.** A changed path the tool couldn't
109
123
  place mechanically (`implementedIn` stale, a URL-only link, code that moved) still might belong
110
124
  to an in-scope slice — a quick Grep for the path's obvious symbols against the slice docs/model
@@ -120,6 +134,31 @@ keeps a recurring conform run cheap; don't invent a smarter trigger.
120
134
 
121
135
  For each slice in scope:
122
136
 
137
+ **Check for an existing bindings file first (GH #450).** `conformance/bindings/<slice-key>.yaml`,
138
+ beside the model, records this slice's own prior evidence — file and identifier per model
139
+ element, and per `INV-*` invariant's enforcement/test sites (`docs/bindings.md`'s schema). Two
140
+ cases, mutually exclusive:
141
+
142
+ - **It exists:** verify it before walking anything by hand —
143
+ `em conform bindings check <model-name>.em --repo <target-repo-path> --slice <slice-key>`.
144
+ A binding that still checks out is evidence you don't need to re-derive; **scope the rest of
145
+ this slice's walk through it** — re-read only what the check reports failing (`file not
146
+ found`/`identifier not found`, an unknown `ref`) plus whatever `em conform-scope`'s
147
+ `changedPaths` (step 1) says moved since `implementedIn`. This is what turns a recurring
148
+ conform walk incremental instead of a full re-derivation every time — don't throw that away by
149
+ re-walking evidence the file already gives you clean.
150
+ - **It doesn't exist:** the common shape for a slice an external or ticket-driven implementer
151
+ shipped without ever running `em` (`docs/bindings.md` is written so that implementer can still
152
+ author one by hand from its own ticket spec; this backfill is the safety net for the ones that
153
+ didn't, or for any slice that shipped before GH #450). Walk the slice normally (the numbered
154
+ steps below) and, once you've gathered that evidence, **write
155
+ `conformance/bindings/<slice-key>.yaml` from it** — the same file an implementer would have
156
+ written, now backfilled from your conform evidence instead of from the implementer's own
157
+ knowledge of the code. This is advisory tooling catching up a gap, not a model or doc edit: it
158
+ needs no ratification and doesn't change this phase's advisory-only stance (see "Stance"
159
+ above) — you're recording where code already lives, not deciding what it should do. From the
160
+ next conform run on, this slice follows the "it exists" branch above.
161
+
123
162
  1. Read the slice's **doc** (`slices/<slice-name>.md`) alongside its elements in the `.em`.
124
163
  This tells you the vocabulary to anchor on and the claims to check — not the answer.
125
164
  2. Walk the code and **record evidence before comparing**:
@@ -140,6 +179,20 @@ For each slice in scope:
140
179
  as missing. This is the *general*, idiom-level version of the next bullet — prefer citing
141
180
  an actual `divergence` annotation when the element carries one; fall back to this idiom
142
181
  note only when it doesn't.
182
+ - **`updates from` sources (GH #451) — housekeeping evidence, not trigger evidence.** A view
183
+ declared `view X from "A" updates from "B", "C"` (`docs/dsl.md`'s `updates from` section)
184
+ splits its sources into what put a row on the list (`from`) and what keeps an existing row
185
+ current or removes it (`updates from`). The two need different evidence: a `from` source is
186
+ what an automation/processor reacting to this view should fire on, or what a reader expects
187
+ to see a NEW row appear for — missing evidence there is the usual structural/spec drift. A
188
+ `updates from` source is expected to have an update/delete handler for the SAME row, never a
189
+ "new item created" or "automation triggered" site — don't report the absence of trigger-type
190
+ evidence for an `updates from` source as drift; that is literally what the clause says it
191
+ isn't. `em export`'s `from` list is the union of both (so `em diff`'s structural comparison
192
+ sees every source regardless of which list it's in — folding `from`/`updates from` into each
193
+ other is NOT itself a structural change `em diff` would catch), but the *diagram* draws no
194
+ arrow for an `updates from` source and the *evidence walk* above should read the same way:
195
+ check it as "does this row get kept current/removed", not "does this cause a new row".
143
196
  - **Accepted divergences:** before treating any finding as drift, check whether the
144
197
  relevant canonical element already carries a `divergence "..."` annotation (visible in
145
198
  the `.em`, in `em export --json`'s `divergence` field, or — for a structural finding — as
@@ -162,8 +215,15 @@ For each slice in scope:
162
215
  3. Write what you found into the scratch model (`<model-name>-asis.em`, see below) — start it
163
216
  with `em conform-scope <model-name>.em --repo <target-repo-path> --seed-asis`, which
164
217
  byte-copies the canonical `.em` to `<model-name>-asis.em` and ensures `*-asis.em` is
165
- gitignored (idempotent — safe to pass on every run). **Then replace only the in-scope
166
- slices** with the as-is picture, leaving out-of-scope slices byte-identical. This is not an optimization:
218
+ gitignored (idempotent — safe to pass on every run). **Storyline models (GH #451):** when the
219
+ slice you're rewriting has a non-null `file` in step 1's `candidateSlices` (its body lives in
220
+ a storyline file, not the root), `--seed-asis` also wrote a scratch copy of THAT file — the
221
+ `seeded.storylineFiles` entry naming it — and the copied root's declaration already points at
222
+ it. Edit that storyline file's own `-asis` sibling, never `<model-name>-asis.em` (it has no
223
+ body for that slice to rewrite) and never the canonical storyline file (that corrupts the
224
+ real model, not a scratch copy). **Then replace only the in-scope slices** with the as-is
225
+ picture, leaving out-of-scope slices byte-identical, in whichever scratch file(s) hold them.
226
+ This is not an optimization:
167
227
  `em diff` matches slices by name, so a scratch model containing *only* the in-scope slices
168
228
  reports every other canonical slice as `slice-removed` plus one `element-removed` per
169
229
  element — a phantom-removal flood on every diff-scoped run, which is the exact false drift
@@ -406,7 +466,12 @@ each call adds its own stamp rather than overwriting the last.
406
466
  directory as `.event-modeling.md`). Always seeded as a copy of the canonical model with only
407
467
  the in-scope slices rewritten (step 2) — `em conform-scope --seed-asis` does the seeding and
408
468
  the gitignoring (`*-asis.em`, idempotent) mechanically, never built up from nothing and never
409
- hand-maintained. It's regenerated every conform run.
469
+ hand-maintained. It's regenerated every conform run. **Storyline models (GH #451):** a split
470
+ model gets ONE scratch file per physical file — `<model-name>-asis.em` for the root, plus a
471
+ `-asis` sibling for every storyline file the root declares (`seeded.storylineFiles` names
472
+ them) — never just the root; the copied root's `in` clause already points at each sibling, so
473
+ `em diff <model-name>.em <model-name>-asis.em` reads the whole scratch set as one model, same
474
+ as the canonical root reads the whole canonical set.
410
475
  - **Report location:** `conformance/<YYYY-MM-DD>-report.md` in the model directory. One file
411
476
  per run; don't overwrite a prior date's report. Its findings go in the same-stem `-findings.json`; gates read every same-revision findings file, so per-slice runs may write `<date>-<name>-findings.json`, and a ruling is written to the file the report names. The same-revision lookup uses the report's OWN revision (its `Target repo: … @ <rev>` header line; the caller's `<rev>` / `--as-of` only when the report has none).
412
477
  - **Red note wording:** `issue "conformance: <what's wrong, plainly>"` — plain enough that
@@ -448,6 +513,13 @@ whatever cadence the user wants (see `docs/ci.md` for a scheduled-run recipe).
448
513
  - **A scratch model holding only the in-scope slices** — `em diff` reads every omitted
449
514
  canonical slice as removed, so a diff-scoped run drowns in phantom removals. Seed from the
450
515
  canonical model and rewrite only the slices you walked.
516
+ - **Editing a storyline file's canonical copy as if it were the scratch model (GH #451)** — for
517
+ a slice whose `file` isn't the root, the scratch copy is that storyline file's OWN `-asis`
518
+ sibling (`seeded.storylineFiles`), never `<model-name>-asis.em` (no body there to rewrite) and
519
+ never the canonical storyline file itself (that's the model, not a scratch copy of it).
520
+ - **Treating an `updates from` source like a `from` source during the evidence walk** — a
521
+ missing "new row appears" or "automation fires" site is not drift for a source the view only
522
+ lists under `updates from`; check it for row-update/removal evidence instead (step 2).
451
523
  - **Reporting uncertainty as drift** — "I couldn't find the enforcement site" is an
452
524
  uncertainty, never a finding against the model.
453
525
  - **Editing the model or a slice doc without ratification** — conform proposes; the user
@@ -458,6 +530,12 @@ whatever cadence the user wants (see `docs/ci.md` for a scheduled-run recipe).
458
530
  - **Re-deriving what `em diff` already decided** — once you have the JSON, use it; don't
459
531
  eyeball the two `.em` files yourself looking for structural differences the tool already
460
532
  computed for you.
533
+ - **Re-deriving evidence a verified bindings file already gives you (GH #450)** — when
534
+ `em conform bindings check` passes for a slice's `conformance/bindings/<key>.yaml`, walking
535
+ every element and invariant by hand anyway defeats the point of the file; scope through it
536
+ (step 2) instead.
537
+ - **Skipping the backfill because a slice has no bindings file** — the absence is the signal to
538
+ write one from this walk's own evidence, not a reason to leave the gap for next time.
461
539
  - **Re-litigating an accepted divergence** — a non-null `acceptedDivergence` on a diff entry
462
540
  (or a `divergence` annotation on the element behind a spec/internal finding) means this exact
463
541
  question was already reasoned through and ratified. Classify it as Accepted divergence and
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: design
3
- em-version: 1.21.0
3
+ em-version: 1.22.0
4
4
  description: >-
5
5
  Use when structuring a draft event model into swimlanes and the four patterns (State Change,
6
6
  State View, Automation, Translation), evaluating a model's structural completeness, or writing
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: discover
3
- em-version: 1.21.0
3
+ em-version: 1.22.0
4
4
  description: >-
5
5
  Use when starting a brand-new event model from scratch — greenfield discovery: brainstorming
6
6
  past-tense events, storyboarding the happy path, finding the commands and read models — or when
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: engagement
3
- em-version: 1.21.0
3
+ em-version: 1.22.0
4
4
  description: >-
5
5
  Use when leading an engagement: building a named set of ratified event-modeling slices
6
6
  (`em engagement`) into one independent PR per slice, each against main, by dispatching the
@@ -48,6 +48,7 @@ Validator (em-validator, <model>):
48
48
  | diff footprint inside the slice package | PASS |
49
49
  | no diff under `slices/**`, `*.em`, `constitution.md`, `engagements/` | PASS |
50
50
  | PR body cites the slice doc | PASS |
51
+ | `conformance/bindings/<key>.yaml` exists + `em conform bindings check --slice <key> --exit-code` | PASS |
51
52
 
52
53
  Reviewer (em-reviewer, <model>): <findings list verbatim, or NO FINDINGS>
53
54
  Critic (em-critic, <model>): <findings list verbatim, or NO FINDINGS>
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: event-modeling
3
- em-version: 1.21.0
3
+ em-version: 1.22.0
4
4
  description: >-
5
5
  Use when the user runs `/em: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
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: implement
3
- em-version: 1.21.0
3
+ em-version: 1.22.0
4
4
  description: >-
5
5
  Use when building a single ratified event-modeling slice (status: ready-to-implement) into
6
6
  merged, tested code — the one phase where the agent builds rather than facilitates. Gates on
@@ -29,8 +29,10 @@ ships in the originating doc's PR); ship the endpoint a
29
29
  model doesn't show; surface every gap to the user instead of deciding it silently; cover every
30
30
  `INV-<MNEMONIC>-n` and every scenario with tests, proving the citations before merge with
31
31
  `em coverage <model>.em --slice <key> --tests <dir> --strict` (the default form skips a
32
- `ready-to-implement` slice); in spec-kit projects, allocate via
33
- em-sdd-bridge (redirect mode) and never run `/speckit.specify`.
32
+ `ready-to-implement` slice); write or update the slice's `conformance/bindings/<key>.yaml`
33
+ (GH #450, `docs/bindings.md`'s schema) and verify it with `em conform bindings check <model>.em
34
+ --repo <path> --slice <key> --exit-code` before calling the slice done; in spec-kit projects,
35
+ allocate via em-sdd-bridge (redirect mode) and never run `/speckit.specify`.
34
36
 
35
37
  **Gate: no constitution, no first slice.** The constitution is the project's ratified house rules
36
38
  — stack and architectural shape (including which implementation skill each slice pattern routes
@@ -301,6 +301,20 @@ or seem small — see §10.
301
301
  you didn't touch the `.em`, so this only fails if something else broke).
302
302
  - Nothing between the slice doc and the code was committed as a source of truth (see §9 —
303
303
  work containers are ephemeral; generated or symlinked specs are renderings).
304
+ - **The slice's bindings file is written or updated** (GH #450): `conformance/bindings/<slice-
305
+ key>.yaml`, beside the model, per [`docs/bindings.md`](https://github.com/milehimikey/em/blob/main/docs/bindings.md)'s
306
+ schema. You just wrote the code — you know which file and identifier anchors each element
307
+ this slice's doc declares (`ref: <kind>.<slug>`, bare, no `<slice-key>/` prefix) and each
308
+ `INV-<MNEMONIC>-n` invariant's enforcement and test sites. This is a file contract, not an
309
+ `em`-run write: author or hand-edit the YAML directly, the same way you'd write any other file
310
+ in your PR. Verify it before calling the slice done:
311
+ ```bash
312
+ em conform bindings check <model>.em --repo <path> --slice <slice-key> --exit-code
313
+ ```
314
+ Exit 0 is required — fix the file (a wrong `ref`, a stale `file`/`identifier` pair) rather than
315
+ shipping a binding that doesn't check out. A continuation key (§5, an `again` view instance)
316
+ has no bindings file of its own; its elements and invariants are bound inside the originating
317
+ slice's file alongside the rest of that doc's bindings.
304
318
 
305
319
  ## 6. At merge: the lifecycle flip
306
320
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: review
3
- em-version: 1.21.0
3
+ em-version: 1.22.0
4
4
  description: >-
5
5
  Use when starting em's live browser viewer (`em watch --serve`) so a team can watch a model
6
6
  update in real time, or facilitating a SCHEDULED stakeholder walkthrough that steps through