@milehimikey/em 1.6.1 → 1.7.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.
- package/.claude/skills/event-modeling/SKILL.md +94 -49
- package/.claude/skills/event-modeling/reference/conform.md +30 -8
- package/.claude/skills/event-modeling/reference/em-dsl.md +194 -73
- package/.claude/skills/event-modeling/reference/extract.md +14 -11
- package/.claude/skills/event-modeling/reference/implement.md +172 -0
- package/.claude/skills/event-modeling/reference/methodology.md +40 -33
- package/.claude/skills/event-modeling/templates/conformance-report.md +15 -9
- package/.claude/skills/event-modeling/templates/model-readme.md +7 -7
- package/.claude/skills/event-modeling/templates/slice.md +73 -7
- package/.claude/skills/event-modeling/templates/state.md +7 -6
- package/README.md +1 -0
- package/dist/catalog/build.d.ts +5 -0
- package/dist/catalog/build.js +1 -3
- package/dist/catalog/build.js.map +1 -1
- package/dist/catalog/classify.d.ts +7 -8
- package/dist/catalog/classify.js +7 -8
- package/dist/catalog/classify.js.map +1 -1
- package/dist/catalog/docJoin.d.ts +39 -0
- package/dist/catalog/docJoin.js +86 -0
- package/dist/catalog/docJoin.js.map +1 -0
- package/dist/catalog/driftSignal.d.ts +16 -0
- package/dist/catalog/driftSignal.js +24 -0
- package/dist/catalog/driftSignal.js.map +1 -0
- package/dist/catalog/frontmatterCoherenceValidate.d.ts +8 -0
- package/dist/catalog/frontmatterCoherenceValidate.js +52 -0
- package/dist/catalog/frontmatterCoherenceValidate.js.map +1 -0
- package/dist/catalog/lineageValidate.d.ts +9 -0
- package/dist/catalog/lineageValidate.js +161 -0
- package/dist/catalog/lineageValidate.js.map +1 -0
- package/dist/catalog/readSliceDoc.d.ts +2 -0
- package/dist/catalog/readSliceDoc.js +21 -0
- package/dist/catalog/readSliceDoc.js.map +1 -0
- package/dist/catalog/sliceDoc.d.ts +94 -3
- package/dist/catalog/sliceDoc.js +157 -7
- package/dist/catalog/sliceDoc.js.map +1 -1
- package/dist/catalog/sliceReadyValidate.d.ts +11 -0
- package/dist/catalog/sliceReadyValidate.js +85 -0
- package/dist/catalog/sliceReadyValidate.js.map +1 -0
- package/dist/cli/diff-inputs.d.ts +20 -0
- package/dist/cli/diff-inputs.js +75 -18
- package/dist/cli/diff-inputs.js.map +1 -1
- package/dist/cli/ledgerCheck.d.ts +38 -0
- package/dist/cli/ledgerCheck.js +116 -0
- package/dist/cli/ledgerCheck.js.map +1 -0
- package/dist/cli/skillCheck.d.ts +18 -0
- package/dist/cli/skillCheck.js +63 -0
- package/dist/cli/skillCheck.js.map +1 -0
- package/dist/cli/skillSync.d.ts +22 -0
- package/dist/cli/skillSync.js +69 -0
- package/dist/cli/skillSync.js.map +1 -0
- package/dist/cli/skillVersionCheck.d.ts +32 -0
- package/dist/cli/skillVersionCheck.js +145 -0
- package/dist/cli/skillVersionCheck.js.map +1 -0
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +203 -32
- package/dist/cli.js.map +1 -1
- package/dist/emit/diffJson.d.ts +1 -1
- package/dist/emit/diffJson.js +18 -14
- package/dist/emit/diffJson.js.map +1 -1
- package/dist/emit/dot.js +46 -5
- package/dist/emit/dot.js.map +1 -1
- package/dist/emit/json.d.ts +10 -25
- package/dist/emit/json.js +70 -103
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/ledgerJson.d.ts +5 -0
- package/dist/emit/ledgerJson.js +25 -0
- package/dist/emit/ledgerJson.js.map +1 -0
- package/dist/emit/skillCheckJson.d.ts +5 -0
- package/dist/emit/skillCheckJson.js +32 -0
- package/dist/emit/skillCheckJson.js.map +1 -0
- package/dist/model/diff.d.ts +44 -1
- package/dist/model/diff.js +51 -9
- package/dist/model/diff.js.map +1 -1
- package/dist/model/edges.js +17 -17
- package/dist/model/edges.js.map +1 -1
- package/dist/model/model.d.ts +1 -1
- package/dist/model/refs.d.ts +23 -0
- package/dist/model/refs.js +75 -0
- package/dist/model/refs.js.map +1 -0
- package/dist/model/rules.d.ts +253 -0
- package/dist/model/rules.js +254 -0
- package/dist/model/rules.js.map +1 -0
- package/dist/model/validate.d.ts +23 -1
- package/dist/model/validate.js +207 -69
- package/dist/model/validate.js.map +1 -1
- package/dist/parser/ast.d.ts +3 -2
- package/dist/parser/lexer.d.ts +17 -2
- package/dist/parser/lexer.js +119 -13
- package/dist/parser/lexer.js.map +1 -1
- package/dist/parser/parser.js +75 -34
- package/dist/parser/parser.js.map +1 -1
- package/dist/pipeline.d.ts +9 -0
- package/dist/pipeline.js +4 -2
- package/dist/pipeline.js.map +1 -1
- package/dist/render/sliceDiagram.js +33 -35
- package/dist/render/sliceDiagram.js.map +1 -1
- package/dist/render/sliceStatus.js +1 -1
- package/dist/render/sliceStatus.js.map +1 -1
- package/dist/util/isMainModule.d.ts +14 -0
- package/dist/util/isMainModule.js +33 -0
- package/dist/util/isMainModule.js.map +1 -0
- package/dist/util/walkDir.d.ts +4 -0
- package/dist/util/walkDir.js +28 -0
- package/dist/util/walkDir.js.map +1 -0
- package/package.json +5 -2
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: event-modeling
|
|
3
|
+
em-version: 1.7.1
|
|
3
4
|
description: >-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
a ratified model for drift against the codebase that implements it. Works in resumable phases
|
|
11
|
-
via an argument: `discover` (steps 1-4, greenfield), `extract` (current-state model of an
|
|
12
|
-
existing system), `model` (steps 5-7), `slice` (deep slice specs), `conform` (drift check
|
|
13
|
-
against the codebase), plus `watch` and `validate`. With no argument it resumes from the saved
|
|
14
|
-
state file.
|
|
5
|
+
Use when the user wants to event-model a business process or system: building, editing,
|
|
6
|
+
updating, or maintaining a model — extending or detailing an existing one into slices,
|
|
7
|
+
extracting a current-state model from an existing codebase, implementing a ratified slice, or
|
|
8
|
+
checking a model for drift against the code. Drives the `em` CLI through resumable phases —
|
|
9
|
+
discover, extract, model, slice, implement, conform, watch, review, validate — or resumes
|
|
10
|
+
automatically with no argument.
|
|
15
11
|
---
|
|
16
12
|
|
|
17
13
|
# Event Modeling with `em`
|
|
18
14
|
|
|
19
15
|
You are facilitating an Event Modeling session. Your job is to **extract an accurate model from
|
|
20
16
|
the user through Socratic questioning** — never to invent the domain. You drive the `em` CLI to
|
|
21
|
-
render the model live, and you produce implementation-ready slice
|
|
17
|
+
render the model live, and you produce implementation-ready slice docs.
|
|
22
18
|
|
|
23
19
|
Read `reference/methodology.md` (the 7 steps + 4 patterns) and `reference/em-dsl.md` (DSL syntax and
|
|
24
20
|
validation rules) before doing real work — they are the source of truth. Templates live in
|
|
25
|
-
`templates/`.
|
|
21
|
+
`templates/`. References to `docs/*.md` throughout this skill mean the
|
|
22
|
+
[em repository's docs](https://github.com/milehimikey/em/tree/main/docs) — they are not
|
|
23
|
+
vendored alongside this skill.
|
|
26
24
|
|
|
27
25
|
## Operating principles (every phase)
|
|
28
26
|
|
|
@@ -55,23 +53,24 @@ validation rules) before doing real work — they are the source of truth. Templ
|
|
|
55
53
|
keep a sub-flow that detours into another context together, not parked at the end of the model).
|
|
56
54
|
Declare every instance after the first with
|
|
57
55
|
**`view X again from "..."`** — `again` instances are exempt from the duplicate-name warning even
|
|
58
|
-
when referenced, and each reference resolves to the right instance.
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
when referenced, and each reference resolves to the right instance. A reaction's command is
|
|
57
|
+
wired by same-slice presence, exactly like `ui → command` — no positional/adjacency rule to get
|
|
58
|
+
right (see `em-dsl.md`).
|
|
61
59
|
See `reference/methodology.md` (State View) and `reference/em-dsl.md`.
|
|
62
60
|
- **Never connect two instances of one read model.** The repeat is a timeline device, not a flow:
|
|
63
61
|
continuity is implied by the shared name, and the events arriving at each instance are what show
|
|
64
62
|
it changing. An arrow between instances says the read model feeds itself, and is an error.
|
|
65
63
|
- **Every slice is a COMPLETE pattern, never a half-slice.** A State Change is
|
|
66
64
|
`ui → command → event`; a State View is `event → read model → ui` (or `→ reaction`). So: a
|
|
67
|
-
command needs something that **triggers** it (the `ui` it's issued from, or the reaction
|
|
68
|
-
|
|
69
|
-
own. A command nothing points at is a write nobody can start;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
command needs something that **triggers** it (the `ui` it's issued from, or the reaction that
|
|
66
|
+
triggers it, also in this slice), its event needs a **reader**, and that read model needs a
|
|
67
|
+
**consumer** of its own. A command nothing points at is a write nobody can start; a reaction
|
|
68
|
+
that triggers no command is a decision the system never acts on; an event nothing projects is
|
|
69
|
+
a write nobody can see; a read model nothing displays is information dropped on the floor.
|
|
70
|
+
Write the whole chain together rather than sweeping up dangling ends later. Reactions don't
|
|
71
|
+
count as readers of *events* — they read views. **Every instance** of a repeated read model
|
|
72
|
+
needs its own consumer: if you repeat a view next to an event just to keep the arrow short,
|
|
73
|
+
bring its screen along, or don't add the instance.
|
|
75
74
|
- **Only six connections are legal:** `ui → command`, `command → event`, `event → read model`,
|
|
76
75
|
`read model → ui`, `read model → reaction`, `reaction → command`. Reaching for anything else —
|
|
77
76
|
above all `command → read model` (the CQRS violation) or `read model → command` — means the model
|
|
@@ -79,8 +78,8 @@ validation rules) before doing real work — they are the source of truth. Templ
|
|
|
79
78
|
- **Validate continuously.** Run `em validate` and fix errors/warnings as you go (see DSL ref).
|
|
80
79
|
- **Save state at the end of every session** so work resumes cleanly. Also append one line to
|
|
81
80
|
the Usage log: the phase(s) touched and the `em validate` diagnostic *categories* that fired
|
|
82
|
-
(
|
|
83
|
-
content). This is the team's only usage signal today (`docs/usage-data.md`) — keep it cheap
|
|
81
|
+
(the exact fixed strings from `docs/usage-data.md`, e.g. "read model has no consumer" —
|
|
82
|
+
never the full message or domain content). This is the team's only usage signal today (`docs/usage-data.md`) — keep it cheap
|
|
84
83
|
and habitual, not a task to skip.
|
|
85
84
|
|
|
86
85
|
## Preconditions (run first)
|
|
@@ -146,8 +145,9 @@ phase applies to field tables, below.
|
|
|
146
145
|
3. **Inputs (step 3).** For each event, find the **command** that causes it (imperative name).
|
|
147
146
|
Form `command → event` slices (State Change pattern). Every command needs a **trigger** in the
|
|
148
147
|
same breath: the screen the user issues it from (a `ui` in the slice), or — for the Automation
|
|
149
|
-
and Translation patterns — the reaction in
|
|
150
|
-
a write nobody can start. *"Who does this, and where are they when they
|
|
148
|
+
and Translation patterns — the reaction that triggers it, also in this slice. A command
|
|
149
|
+
nothing points at is a write nobody can start. *"Who does this, and where are they when they
|
|
150
|
+
do it?"*
|
|
151
151
|
4. **Outputs (step 4).** Identify the **read models / views** consumers need and wire them with
|
|
152
152
|
`from "Event"` (State View pattern), each with the screen (or reaction) that consumes it — a
|
|
153
153
|
read model nothing displays is information dropped on the floor. In a **headless/API** model
|
|
@@ -190,23 +190,23 @@ Goal: a structurally complete, **validated** model with correct patterns and swi
|
|
|
190
190
|
|
|
191
191
|
1. **Swimlanes & patterns (step 5).** Group events into **contexts** (bounded contexts /
|
|
192
192
|
aggregates) — ask which events share a consistency boundary and who owns them. Classify each
|
|
193
|
-
slice as one of the 4 patterns. **
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
it **triggers a command and never records an event
|
|
197
|
-
external inputs (externally triggered: external →
|
|
198
|
-
|
|
199
|
-
event).
|
|
193
|
+
slice as one of the 4 patterns. **Share the slice between every automation or translation and
|
|
194
|
+
the command it triggers** (the reaction — processor/translation — together with the command
|
|
195
|
+
and event it produces; the read model it watches, if any, stays in the slice before). A
|
|
196
|
+
translation or automation is a reaction: it **triggers a command and never records an event
|
|
197
|
+
directly**. Add `translation` slices for external inputs (externally triggered: external →
|
|
198
|
+
translation → command → event, no slice before) and for the system reacting to its own state
|
|
199
|
+
(internally triggered: read model in the slice before → translation → command → event).
|
|
200
200
|
2. **Elaborate scenarios — first pass (step 6).** For each slice, capture the happy-path
|
|
201
201
|
Given/When/Then and the obvious invariants as short notes. (The full spec is the `slice` phase.)
|
|
202
202
|
3. **Evaluate completeness (step 7).** Walk the model: every slice is a **complete** pattern, not a
|
|
203
203
|
half-slice — **every command has something that triggers it**, every command emits an event,
|
|
204
204
|
**every event is read by a read model**, **every read model has a consumer**, every view has a
|
|
205
205
|
source, every UI is reachable, every connection is
|
|
206
|
-
one of the six legal pairs, and
|
|
207
|
-
|
|
208
|
-
and warnings —
|
|
209
|
-
|
|
206
|
+
one of the six legal pairs, and every automation **and** translation triggers a command (none
|
|
207
|
+
wired straight to an event, none with no command at all). Run `em validate` and resolve all
|
|
208
|
+
errors and warnings — it catches a reaction wired straight to an event too now (see
|
|
209
|
+
`reference/em-dsl.md`), so a clean run covers this case.
|
|
210
210
|
For an unread event, don't just bolt on a view to silence the warning: ask the user who looks at
|
|
211
211
|
this fact and what they do with it. The honest answers are "here's the read model we missed" or
|
|
212
212
|
"nobody — so why are we recording it", and both improve the model.
|
|
@@ -226,6 +226,16 @@ phases is the starting point, not the finished event set. **Every new event need
|
|
|
226
226
|
real (someone has to see that the request was declined).
|
|
227
227
|
|
|
228
228
|
For each slice:
|
|
229
|
+
0. **Check for re-ratification first.** If `slices/<slice-name>.md` already exists with
|
|
230
|
+
`status: implemented`, this is a re-ratification, not fresh authoring: hold a Socratic
|
|
231
|
+
deep-dive on what changed (same rigor as step 1, scoped to the delta), update whichever
|
|
232
|
+
sections actually changed, then express the change as the `## Delta` section — fixed heading,
|
|
233
|
+
`### Added`/`Modified`/`Removed`/`Renamed` Requirement blocks each carrying its own scenarios
|
|
234
|
+
(see `templates/slice.md` and `docs/slice-doc-schema.md#delta-section-grammar-and-lifecycle`)
|
|
235
|
+
— **overwriting** whatever the section held before, never appending to it. Then continue at
|
|
236
|
+
step 2 to bump `version` and flip `status` back to `ready-to-implement`, leaving
|
|
237
|
+
`implementedIn` naming the prior version's PR (intended drift signal, not a bug — see the
|
|
238
|
+
schema doc). Otherwise, this is first-time authoring: continue at step 1.
|
|
229
239
|
1. Hold a Socratic deep-dive to fill every section of `templates/slice.md`: intent, trigger/actor,
|
|
230
240
|
command + field table (types & rules), event(s) + payload (mark immutable facts), invariants
|
|
231
241
|
(give each a stable ID), Given/When/Then scenarios (happy path + rule boundaries + edge cases),
|
|
@@ -235,19 +245,51 @@ For each slice:
|
|
|
235
245
|
adjacent real sources (OpenAPI specs, DB migrations, existing DTOs/event classes in sibling
|
|
236
246
|
contexts) before finalizing field names/types or invariants — don't guess a shape that's
|
|
237
247
|
already defined elsewhere.
|
|
238
|
-
2. Write the doc to `slices/<slice-name>.md` (kebab-case the slice name)
|
|
248
|
+
2. Write the doc to `slices/<slice-name>.md` (kebab-case the slice name), with the YAML
|
|
249
|
+
frontmatter block at the very top — all five of `schemaVersion`/`pattern`/`swimlane`/
|
|
250
|
+
`status`/`version` (kebab-case `pattern` value, `schemaVersion: 1`, `version` starting at
|
|
251
|
+
`1`; omitting any of the five makes the doc `frontmatter-invalid` to `em export` and the
|
|
252
|
+
readiness gate), plus `implementedIn` once shipped — the canonical, machine-read
|
|
253
|
+
metadata dialect (`- **Status:** ...` bullet lines are legacy/accepted input only; never
|
|
254
|
+
write new docs that way). When this doc exists because of a split, merge, or rename, add the
|
|
255
|
+
matching lineage key(s) too (`split-from`/`merged-from`/`superseded-by`, `<slice-key>@v<N>`
|
|
256
|
+
grammar — see `docs/slice-doc-schema.md` for the full schema). On a re-ratification (step 0),
|
|
257
|
+
bump `version` and flip `status` here instead of setting them fresh. Record the originating
|
|
239
258
|
need (ticket/conversation link) in the Intent section when one exists.
|
|
240
259
|
3. Render the slice's own diagram: `em render <model>.em --slice "<slice name>" -o
|
|
241
260
|
slices/<slice-name>.svg` (kebab-case, matching the doc's filename) — redraws just this slice
|
|
242
261
|
in its own canonical pattern shape, and add `` near the top of
|
|
243
|
-
the doc, right after the
|
|
262
|
+
the doc, right after the `# Slice:` heading (below the frontmatter block).
|
|
244
263
|
4. Wire it into the `.em`: add `note "slices/<slice-name>.md"` to the slice's primary element
|
|
245
264
|
(the command for State Change, the view for State View, the processor for Automation, the
|
|
246
265
|
translation for Translation).
|
|
247
|
-
5. Update `README.md`'s slice index — the one canonical slice table (`draft` →
|
|
248
|
-
`ready-to-implement`, later `implemented` once shipped, with
|
|
266
|
+
5. Update `README.md`'s slice index — the one canonical slice table (`draft` → `reviewed` →
|
|
267
|
+
`ready-to-implement`, later `implemented` once shipped, with its Implemented-in link
|
|
268
|
+
filled in).
|
|
249
269
|
6. Re-render and `em validate`.
|
|
250
270
|
|
|
271
|
+
When a slice is **ratified** — a human flips its `status` to `ready-to-implement` with every
|
|
272
|
+
open question resolved — it's ready to hand to an implementer. Confirm with
|
|
273
|
+
`em validate <model>.em --slice-ready <key>`, and point whoever (or whatever) implements it
|
|
274
|
+
at `reference/implement.md`.
|
|
275
|
+
|
|
276
|
+
## Phase: `implement` — build one ratified slice
|
|
277
|
+
|
|
278
|
+
Goal: turn a single `ready-to-implement` slice into merged, verified code — the one phase
|
|
279
|
+
where the agent builds rather than facilitates.
|
|
280
|
+
|
|
281
|
+
**Read `reference/implement.md` before doing any implement work and follow it as the
|
|
282
|
+
contract.** In short: gate on `em validate <model>.em --slice-ready <key>` (stop and hand
|
|
283
|
+
back if it fails — never edit the doc to make the gate pass); treat the slice doc as the
|
|
284
|
+
spec (read-only, except the merge-time `status`/`implementedIn` flip); surface every gap to
|
|
285
|
+
the user instead of deciding it silently; cover every INV-n and every scenario with tests;
|
|
286
|
+
in spec-kit projects, allocate via em-sdd-bridge (redirect mode) and never run
|
|
287
|
+
`/speckit.specify`.
|
|
288
|
+
|
|
289
|
+
End of phase: PR merged, slice doc flipped to `status: implemented` with `implementedIn`
|
|
290
|
+
filled, `README.md`'s slice index updated. Implement doesn't chain to another phase — run it
|
|
291
|
+
once per ratified slice; `conform` later checks the result against the model.
|
|
292
|
+
|
|
251
293
|
## Phase: `conform` — drift check against the codebase
|
|
252
294
|
|
|
253
295
|
Goal: check a **ratified** model (and its slice docs) against the codebase that implements it,
|
|
@@ -322,8 +364,8 @@ rule (see `reference/em-dsl.md`) and proposing the fix. Apply fixes on agreement
|
|
|
322
364
|
|
|
323
365
|
| Diagnostic | Fix |
|
|
324
366
|
|---|---|
|
|
325
|
-
|
|
|
326
|
-
| **command has nothing that triggers it** | Add the `ui` it's issued from — or, if the system issues it, the reaction in
|
|
367
|
+
| reaction triggers no command | Add the command it issues, in this same slice, or an explicit `arrow` to one elsewhere |
|
|
368
|
+
| **command has nothing that triggers it** | Add the `ui` it's issued from — or, if the system issues it, the reaction that triggers it, also in this slice. Ask *"who does this, and where are they when they do it?"* |
|
|
327
369
|
| **read model has no consumer** | Add the screen that displays it, or the reaction that watches it. If it's a repeat added only to shorten an arrow and nothing looks at it there, drop the instance |
|
|
328
370
|
| read model has no source | Add the missing `from "Event"` |
|
|
329
371
|
| command produces no event | Give the command its event, or drop the command |
|
|
@@ -337,15 +379,17 @@ relevant element over a `# TBD` comment — it shows up as a red marker on the r
|
|
|
337
379
|
`em validate` tracks it as an open-issue warning, so it isn't lost once rendered. `em validate
|
|
338
380
|
--list-issues` gives a quick sweep of everything still open.
|
|
339
381
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
382
|
+
`em validate` now catches a reaction wired straight to an event too — any reaction with no
|
|
383
|
+
`command` in its own slice, and no explicit arrow to one, warns "triggers no command". A
|
|
384
|
+
`translation`/`processor`/`automation` should always trigger a `command` in its own slice
|
|
385
|
+
(`reaction → command → event`); if one instead records an event directly, route it through a
|
|
386
|
+
command instead.
|
|
344
387
|
|
|
345
388
|
---
|
|
346
389
|
|
|
347
390
|
## em command reference (quick)
|
|
348
391
|
|
|
392
|
+
<!-- GENERATED:cli-quick:start -- run `npm run docs:generate` to refresh, do not hand-edit -->
|
|
349
393
|
```bash
|
|
350
394
|
em --version
|
|
351
395
|
em init <name>.em # optional starter scaffold
|
|
@@ -357,6 +401,7 @@ em watch <name>.em -o <name>.svg # re-render on save (run in backgroun
|
|
|
357
401
|
em watch <name>.em -o <name>.svg --serve # + live viewer with instant push-reload (--port N)
|
|
358
402
|
# click "Review mode" for a slice-by-slice storyboard walkthrough
|
|
359
403
|
```
|
|
404
|
+
<!-- GENERATED:cli-quick:end -->
|
|
360
405
|
|
|
361
406
|
Always finish a working session by: re-rendering, running `em validate`, and updating
|
|
362
407
|
`.event-modeling.md` with the current phase/step, decisions, open questions, and a Usage log
|
|
@@ -34,10 +34,11 @@ difference is what you do with what you find: extract *builds* a model from the
|
|
|
34
34
|
|
|
35
35
|
1. A canonical `.em` model with a state file (`.event-modeling.md`), reachable the same way the
|
|
36
36
|
SKILL.md preconditions locate it.
|
|
37
|
-
2. The
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
tell the user and skip it rather than reporting "drift"
|
|
37
|
+
2. The slices you're about to check should be **implemented** — docs at `status: implemented`
|
|
38
|
+
(or the status the user says corresponds to shipped code) for whichever slices are in scope.
|
|
39
|
+
Checking a `draft` or `ready-to-implement` slice against code is a wasted walk — ratified or
|
|
40
|
+
not, nobody has built to it yet; tell the user and skip it rather than reporting "drift"
|
|
41
|
+
against it.
|
|
41
42
|
3. The codebase to check: the state file's **Existing system refs** (populated during
|
|
42
43
|
`extract`, if this model came from one) or ask the user for the repo path if not set. Record
|
|
43
44
|
it if missing. In a headless/scheduled run with no user to ask, default to the repository
|
|
@@ -56,7 +57,7 @@ named invariants, Given/When/Then scenarios). Conform checks all three surfaces
|
|
|
56
57
|
|---|---|---|---|
|
|
57
58
|
| **Structural** — `.em` ↔ code | slices/elements/fields/flow | `em` (deterministic) | `em diff --json` on canonical vs. an as-is scratch model |
|
|
58
59
|
| **Spec** — slice doc ↔ code | field rules not enforced, named invariants (`INV-*`) without enforcement/test sites, GWT scenarios without test sites | you (judgment) | per-slice evidence walk: each checkable claim in the doc mapped to a code/test site by name (`INV-CHK-4` → its enforcement site + its test) |
|
|
59
|
-
| **Internal** — slice doc ↔ `.em` | the doc's
|
|
60
|
+
| **Internal** — slice doc ↔ `.em` | the doc's frontmatter (`pattern:`, `status:`) or its Command/Event/Read Model sections and field tables disagreeing with the model's own elements/fields | you (judgment, v1) | cross-check the doc's structured sections against the slice's model elements |
|
|
60
61
|
|
|
61
62
|
The internal surface is deterministically checkable in principle (structured doc sections +
|
|
62
63
|
`{ fields }` blocks) — promoting it to an `em validate` rule is a natural follow-up; file it as
|
|
@@ -74,7 +75,7 @@ authoritative.
|
|
|
74
75
|
Default: **diff-scoped.** Read the state file's `Last conformance:` marker (date + target-repo
|
|
75
76
|
revision). If it's set, run `git diff --name-only <recorded-revision>..HEAD` from the target
|
|
76
77
|
repo's root to list the changed paths (`git log` alone prints commit subjects, not paths), then
|
|
77
|
-
map those paths to slices (via each slice doc's known code locations, `
|
|
78
|
+
map those paths to slices (via each slice doc's known code locations, `implementedIn:` links,
|
|
78
79
|
or a quick Grep if those are stale) — that's your in-scope set. If the marker reads `never`
|
|
79
80
|
(first run) or the user passes `--full`, scope is every `implemented` slice.
|
|
80
81
|
|
|
@@ -112,6 +113,18 @@ For each slice in scope:
|
|
|
112
113
|
3). If it does, this is not a fresh finding to litigate: classify it as **Accepted
|
|
113
114
|
divergence** (step 4) and cite the annotation text as the evidence. This is the specific,
|
|
114
115
|
per-element, ratified counterpart to the idiom-level bullet above.
|
|
116
|
+
- **Unpropagated deltas (MIL-85):** before treating any slice-level finding as drift, check
|
|
117
|
+
that slice's `doc.driftSignal` in `em export --json` (see `docs/slice-doc-schema.md`'s
|
|
118
|
+
"`status` under re-ratification" section for the mechanics). `"unpropagated-delta"` means
|
|
119
|
+
the slice was re-ratified (a new
|
|
120
|
+
`version`, `status` flipped back off `implemented`) but `implementedIn` still names the
|
|
121
|
+
*prior* version's PR — the code you're evidence-walking is that prior version, on purpose.
|
|
122
|
+
Do not diff it against the newer doc content and do not report a mismatch as Real drift or
|
|
123
|
+
a Model gap; classify it as **Unpropagated delta** (step 4) instead and stop — the finding
|
|
124
|
+
is "this delta hasn't shipped yet," not a defect in the shipped code. `"implemented-
|
|
125
|
+
without-link"` (status: implemented, no link at all) is a genuine coherence problem, but
|
|
126
|
+
it's already surfaced by `em validate`'s `frontmatter-coherence-implemented-without-link`
|
|
127
|
+
warning — don't re-raise it here as a separate conform finding.
|
|
115
128
|
3. Write what you found into the scratch model (`<model-name>-asis.em`, see below). **Seed the
|
|
116
129
|
scratch model as a copy of the canonical `.em` and replace only the in-scope slices** with
|
|
117
130
|
the as-is picture, leaving out-of-scope slices byte-identical. This is not an optimization:
|
|
@@ -178,6 +191,12 @@ step 2 — sorts into exactly one class:
|
|
|
178
191
|
`.em`/`em export` for a spec/internal finding). This is what the annotation is *for*: a
|
|
179
192
|
reasoned, ratified deviation stops being re-reported as drift on every run. Cite the
|
|
180
193
|
annotation text, not fresh judgment — that judgment already happened when it was written.
|
|
194
|
+
- **Unpropagated delta** (MIL-85) — the slice's `doc.driftSignal` (`em export --json`) is
|
|
195
|
+
`"unpropagated-delta"`: a ratified version bump hasn't shipped yet, so `implementedIn` still
|
|
196
|
+
names prior work on purpose. Distinct from Accepted divergence — this is a structurally-
|
|
197
|
+
derived, deterministic signal (`status`/`implementedIn` coherence), not a human-authored
|
|
198
|
+
`divergence` annotation; keep the two separate so a reader can tell which mechanism produced
|
|
199
|
+
which finding. Cite `slice.doc.driftSignal` and `slice.doc.version` together as evidence.
|
|
181
200
|
- **Extraction uncertainty** — no evidence either way. Never reported as drift or a gap.
|
|
182
201
|
|
|
183
202
|
Every classification must cite the evidence recorded in step 2 (or the `em diff` entry, for
|
|
@@ -203,8 +222,11 @@ End of run: update the state file's `Last conformance:` marker, exact format:
|
|
|
203
222
|
```
|
|
204
223
|
|
|
205
224
|
The revision is the one you just diffed against, so the next run's scope starts from here —
|
|
206
|
-
step 1 parses this line, so keep the format exact.
|
|
207
|
-
|
|
225
|
+
step 1 parses this line, so keep the format exact. **The marker only advances with the human
|
|
226
|
+
in the loop**: in an interactive session, update it after walking the report with the user; a
|
|
227
|
+
headless/scheduled run writes the report but never the marker (nobody ratified the outcome),
|
|
228
|
+
so the next run re-walks the same span — see `docs/ci.md`. If any proposals were ratified and
|
|
229
|
+
applied, log a Decisions entry noting what changed and why.
|
|
208
230
|
|
|
209
231
|
## Conventions
|
|
210
232
|
|