@milehimikey/em 1.19.7 → 1.21.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.
- package/.claude/skills/event-modeling/SKILL.md +1 -1
- package/.claude/skills/event-modeling-conform/SKILL.md +1 -1
- package/.claude/skills/event-modeling-conform/reference/conform.md +29 -1
- package/.claude/skills/event-modeling-design/SKILL.md +33 -7
- package/.claude/skills/event-modeling-discover/SKILL.md +2 -2
- package/.claude/skills/event-modeling-discover/reference/extract.md +12 -0
- package/.claude/skills/event-modeling-engagement/SKILL.md +1 -1
- package/.claude/skills/event-modeling-implement/SKILL.md +7 -2
- package/.claude/skills/event-modeling-implement/reference/implement.md +73 -6
- package/.claude/skills/event-modeling-review/SKILL.md +19 -7
- package/.claude/skills/event-modeling-shared/reference/em-dsl.md +57 -5
- package/.claude/skills/event-modeling-shared/reference/methodology.md +51 -2
- package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +2 -1
- package/.claude/skills/event-modeling-shared/templates/model-readme.md +10 -2
- package/.claude/skills/event-modeling-shared/templates/slice.md +12 -1
- package/.claude-plugin/marketplace.json +2 -2
- package/dist/catalog/build.js +6 -5
- package/dist/catalog/build.js.map +1 -1
- package/dist/catalog/coverage.d.ts +3 -0
- package/dist/catalog/coverage.js +12 -0
- package/dist/catalog/coverage.js.map +1 -1
- package/dist/catalog/docBadge.d.ts +16 -0
- package/dist/catalog/docBadge.js +50 -0
- package/dist/catalog/docBadge.js.map +1 -0
- package/dist/catalog/docLocate.d.ts +17 -0
- package/dist/catalog/docLocate.js +97 -0
- package/dist/catalog/docLocate.js.map +1 -0
- package/dist/catalog/docModelConsistencyValidate.js +9 -2
- package/dist/catalog/docModelConsistencyValidate.js.map +1 -1
- package/dist/catalog/frontmatterCoherenceValidate.js +16 -1
- package/dist/catalog/frontmatterCoherenceValidate.js.map +1 -1
- package/dist/catalog/invTokens.d.ts +49 -0
- package/dist/catalog/invTokens.js +94 -0
- package/dist/catalog/invTokens.js.map +1 -0
- package/dist/catalog/orphanedSliceDocValidate.js +15 -10
- package/dist/catalog/orphanedSliceDocValidate.js.map +1 -1
- package/dist/catalog/pages.js +48 -1
- package/dist/catalog/pages.js.map +1 -1
- package/dist/catalog/readSliceDoc.js +5 -4
- package/dist/catalog/readSliceDoc.js.map +1 -1
- package/dist/catalog/scenarioQualityValidate.js +2 -2
- package/dist/catalog/scenarioQualityValidate.js.map +1 -1
- package/dist/catalog/scenarios.d.ts +4 -0
- package/dist/catalog/scenarios.js +4 -1
- package/dist/catalog/scenarios.js.map +1 -1
- package/dist/catalog/sliceDoc.d.ts +54 -1
- package/dist/catalog/sliceDoc.js +99 -2
- package/dist/catalog/sliceDoc.js.map +1 -1
- package/dist/catalog/sliceDocRender.d.ts +3 -0
- package/dist/catalog/sliceDocRender.js +295 -0
- package/dist/catalog/sliceDocRender.js.map +1 -0
- package/dist/catalog/sliceSections.d.ts +18 -1
- package/dist/catalog/sliceSections.js +38 -4
- package/dist/catalog/sliceSections.js.map +1 -1
- package/dist/cli/coverage.d.ts +13 -23
- package/dist/cli/coverage.js +51 -91
- package/dist/cli/coverage.js.map +1 -1
- package/dist/cli/defer.js +3 -2
- package/dist/cli/defer.js.map +1 -1
- package/dist/cli/ledgerCheck.js +11 -8
- package/dist/cli/ledgerCheck.js.map +1 -1
- package/dist/cli/markImplemented.js +2 -2
- package/dist/cli/markImplemented.js.map +1 -1
- package/dist/cli/ratify.js +2 -2
- package/dist/cli/ratify.js.map +1 -1
- package/dist/cli/refsCheck.d.ts +52 -0
- package/dist/cli/refsCheck.js +129 -2
- package/dist/cli/refsCheck.js.map +1 -1
- package/dist/cli/render-inputs.d.ts +1 -1
- package/dist/cli/render-inputs.js +3 -2
- package/dist/cli/render-inputs.js.map +1 -1
- package/dist/cli/review.js +2 -2
- package/dist/cli/review.js.map +1 -1
- package/dist/cli/revise.js +2 -2
- package/dist/cli/revise.js.map +1 -1
- package/dist/cli/skillDirs.d.ts +22 -0
- package/dist/cli/skillDirs.js +24 -0
- package/dist/cli/skillDirs.js.map +1 -1
- package/dist/cli/sliceConform.d.ts +57 -1
- package/dist/cli/sliceConform.js +111 -10
- package/dist/cli/sliceConform.js.map +1 -1
- package/dist/cli/sliceIndex.d.ts +19 -3
- package/dist/cli/sliceIndex.js +81 -17
- package/dist/cli/sliceIndex.js.map +1 -1
- package/dist/cli/sliceNew.js +2 -0
- package/dist/cli/sliceNew.js.map +1 -1
- package/dist/cli/sliceStubAll.js +7 -2
- package/dist/cli/sliceStubAll.js.map +1 -1
- package/dist/cli/sliceSync.d.ts +12 -0
- package/dist/cli/sliceSync.js +42 -4
- package/dist/cli/sliceSync.js.map +1 -1
- package/dist/cli/status.d.ts +3 -4
- package/dist/cli/status.js +5 -4
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/storylineSplit.d.ts +18 -0
- package/dist/cli/storylineSplit.js +110 -0
- package/dist/cli/storylineSplit.js.map +1 -0
- package/dist/cli/upgrade.js +39 -14
- package/dist/cli/upgrade.js.map +1 -1
- package/dist/cli/watchStoryline.d.ts +33 -0
- package/dist/cli/watchStoryline.js +65 -0
- package/dist/cli/watchStoryline.js.map +1 -0
- package/dist/cli.js +423 -71
- package/dist/cli.js.map +1 -1
- package/dist/emit/docJson.d.ts +99 -0
- package/dist/emit/docJson.js +197 -0
- package/dist/emit/docJson.js.map +1 -0
- package/dist/emit/json.d.ts +22 -1
- package/dist/emit/json.js +12 -1
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/refsJson.d.ts +5 -3
- package/dist/emit/refsJson.js +5 -2
- package/dist/emit/refsJson.js.map +1 -1
- package/dist/mcp/server.js +43 -9
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/continuation.d.ts +9 -0
- package/dist/model/continuation.js +30 -0
- package/dist/model/continuation.js.map +1 -1
- package/dist/model/edges.d.ts +1 -1
- package/dist/model/edges.js +8 -1
- package/dist/model/edges.js.map +1 -1
- package/dist/model/loadModel.d.ts +38 -0
- package/dist/model/loadModel.js +122 -0
- package/dist/model/loadModel.js.map +1 -0
- package/dist/model/model.d.ts +9 -4
- package/dist/model/model.js +4 -0
- package/dist/model/model.js.map +1 -1
- package/dist/model/rules.d.ts +31 -0
- package/dist/model/rules.js +31 -0
- package/dist/model/rules.js.map +1 -1
- package/dist/model/shapeLint.js +143 -0
- package/dist/model/shapeLint.js.map +1 -1
- package/dist/model/sliceDocIndex.js +13 -5
- package/dist/model/sliceDocIndex.js.map +1 -1
- package/dist/model/sliceDocPath.d.ts +19 -0
- package/dist/model/sliceDocPath.js +49 -0
- package/dist/model/sliceDocPath.js.map +1 -0
- package/dist/model/storylineMap.d.ts +20 -0
- package/dist/model/storylineMap.js +55 -0
- package/dist/model/storylineMap.js.map +1 -0
- package/dist/model/validate.d.ts +7 -0
- package/dist/model/validate.js +127 -0
- package/dist/model/validate.js.map +1 -1
- package/dist/parser/ast.d.ts +27 -0
- package/dist/parser/parser.d.ts +17 -1
- package/dist/parser/parser.js +142 -3
- package/dist/parser/parser.js.map +1 -1
- package/dist/pipeline.d.ts +16 -0
- package/dist/pipeline.js +19 -2
- package/dist/pipeline.js.map +1 -1
- package/dist/render/drawEdges.d.ts +5 -1
- package/dist/render/drawEdges.js +57 -4
- package/dist/render/drawEdges.js.map +1 -1
- package/dist/render/drawNotes.d.ts +4 -1
- package/dist/render/drawNotes.js +40 -10
- package/dist/render/drawNotes.js.map +1 -1
- package/dist/render/render.d.ts +11 -0
- package/dist/render/render.js +93 -10
- package/dist/render/render.js.map +1 -1
- package/dist/render/serve.d.ts +5 -0
- package/dist/render/serve.js +18 -2
- package/dist/render/serve.js.map +1 -1
- package/dist/render/sliceDiagram.js +3 -0
- package/dist/render/sliceDiagram.js.map +1 -1
- package/dist/render/sliceOverlay.d.ts +5 -1
- package/dist/render/sliceOverlay.js +24 -2
- package/dist/render/sliceOverlay.js.map +1 -1
- package/dist/render/sliceStatus.d.ts +8 -0
- package/dist/render/sliceStatus.js +22 -15
- package/dist/render/sliceStatus.js.map +1 -1
- package/dist/render/storylineBands.d.ts +0 -3
- package/dist/render/storylineBands.js +2 -22
- package/dist/render/storylineBands.js.map +1 -1
- package/dist/render/storylineDiagram.js +17 -69
- package/dist/render/storylineDiagram.js.map +1 -1
- package/dist/render/storylineMap.d.ts +18 -0
- package/dist/render/storylineMap.js +263 -0
- package/dist/render/storylineMap.js.map +1 -0
- package/dist/render/storylinePicker.d.ts +9 -0
- package/dist/render/storylinePicker.js +17 -0
- package/dist/render/storylinePicker.js.map +1 -0
- package/dist/render/svgGeometry.d.ts +9 -0
- package/dist/render/svgGeometry.js +16 -0
- package/dist/render/svgGeometry.js.map +1 -1
- package/dist/render/viewerHtml.js +1 -1
- package/dist/render/viewerHtml.js.map +1 -1
- package/dist/templates.d.ts +1 -1
- package/dist/templates.js +10 -2
- package/dist/templates.js.map +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/shared/reference/em-dsl.md +57 -5
- package/plugin/shared/reference/methodology.md +51 -2
- package/plugin/shared/reference/slice-doc-schema.md +2 -1
- package/plugin/shared/templates/model-readme.md +10 -2
- package/plugin/shared/templates/slice.md +12 -1
- package/plugin/skills/conform/SKILL.md +1 -1
- package/plugin/skills/conform/reference/conform.md +29 -1
- package/plugin/skills/design/SKILL.md +33 -7
- package/plugin/skills/discover/SKILL.md +2 -2
- package/plugin/skills/discover/reference/extract.md +12 -0
- package/plugin/skills/engagement/SKILL.md +1 -1
- package/plugin/skills/event-modeling/SKILL.md +1 -1
- package/plugin/skills/implement/SKILL.md +7 -2
- package/plugin/skills/implement/reference/implement.md +73 -6
- package/plugin/skills/review/SKILL.md +19 -7
package/dist/templates.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const STARTER_EM = "model \"Order Fulfillment\"\n\npersona Customer\npersona Manager\n\ncontext Order\ncontext Payment\n\n# --- Command pattern: UI -> command -> event ---\nslice \"Browse Catalog\" {\n ui Product Catalog @Customer\n command Place Order\n event Order Placed @Order\n}\n\n# --- View pattern: event -> read model -> UI ---\nslice \"View Open Orders\" {\n view Open Orders from \"Order Placed\"\n ui Order List @Customer\n}\n\nslice \"Checkout\" {\n ui Checkout Screen @Customer\n command Submit Payment\n event Payment Requested @Payment\n}\n\n# --- View pattern: a human view of pending payments ---\nslice \"Manager Review\" {\n view Pending Payments from \"Payment Requested\"\n ui Payment Dashboard @Manager\n}\n\n# --- Read model the automation watches, in its own slice ---\nslice \"Payments To Process\" {\n view Payments To Process from \"Payment Requested\"\n}\n\n# --- Automation slice: the processor, the command it triggers, and that command's event ---\nslice \"Capture Payment\" {\n processor Payment Gateway from \"Payments To Process\"\n command Capture Payment\n event Payment Captured @Payment\n}\n\nslice \"Show Receipt\" {\n view Receipts from \"Payment Captured\"\n ui Receipt Screen @Customer\n}\n";
|
|
2
2
|
/** Raw copy of templates/model-readme.md, \`{{...}}\` placeholders intact — see scaffoldReadme(). */
|
|
3
|
-
export declare const MODEL_README_TEMPLATE = "# {{Model Name}}\n\n{{One-paragraph description of the business process(es) this event model covers.}}\n\n## Live view\nWhile modeling, run the live view so the team can watch the diagram update:\n\n```bash\nem watch {{model-name}}.em -o {{model-name}}.svg --serve # re-render + instant push-reload\n# then open the URL it prints (http://localhost:5173/?svg={{model-name}}.svg) and share the screen\n```\n\nPan/zoom to navigate the diagram (drag, scroll; **Fit** resets), and click **Review mode** in\nthe header for a slice-by-slice walkthrough. If a save fails to render, the viewer keeps the\nlast good diagram and shows an error banner until the next successful load.\n\nStatic render: `em render {{model-name}}.em -o {{model-name}}.svg`\n\n## Patterns legend\n- **State Change** \u2014 UI \u2192 Command \u2192 Event\n- **State View** \u2014 Event(s) \u2192 Read Model \u2192 UI\n- **Automation** \u2014 Read Model (slice before) \u2192 Processor + Command \u2192 Event, together\n- **Translation** \u2014 External input (or Read Model, slice before) \u2192 Translation + Command \u2192 Event, together\n\nBetween them these are the only legal connections: `ui \u2192 command`, `command \u2192 event`,\n`event \u2192 read model`, `read model \u2192 ui`, `read model \u2192 reaction`, `reaction \u2192 command`. A command\nnever reaches a read model directly \u2014 the event goes between them. Every slice is joined up at\nboth ends: something triggers each command (the screen it's issued from, or the reaction that\ntriggers it, also in this slice), and every event a command records is read by some read model \u2014 so each State\nChange slice is paired with the State View slice that projects its event. A read model repeated\nalong the timeline (`view X again`) shows the same projection at a later point; the instances are\nnever connected to one another.\n\n## Slices\n<!-- The canonical slice index \u2014 the ONE place slices are enumerated (the state file\n points here rather than keeping its own copy). Generated \u2014 run\n `em slice index {{model-name}}.em` to (re)write the table below from the model and its\n slice docs; never hand-edit between the markers. -->\n<!-- GENERATED:slices:start -->\n| # | Slice | Pattern | Status |
|
|
3
|
+
export declare const MODEL_README_TEMPLATE = "# {{Model Name}}\n\n{{One-paragraph description of the business process(es) this event model covers.}}\n\n## Live view\nWhile modeling, run the live view so the team can watch the diagram update:\n\n```bash\nem watch {{model-name}}.em -o {{model-name}}.svg --serve # re-render + instant push-reload\n# then open the URL it prints (http://localhost:5173/?svg={{model-name}}.svg) and share the screen\n```\n\nPan/zoom to navigate the diagram (drag, scroll; **Fit** resets), and click **Review mode** in\nthe header for a slice-by-slice walkthrough. If a save fails to render, the viewer keeps the\nlast good diagram and shows an error banner until the next successful load.\n\nStatic render: `em render {{model-name}}.em -o {{model-name}}.svg`\n\n## Patterns legend\n- **State Change** \u2014 UI \u2192 Command \u2192 Event\n- **State View** \u2014 Event(s) \u2192 Read Model \u2192 UI\n- **Automation** \u2014 Read Model (slice before) \u2192 Processor + Command \u2192 Event, together\n- **Translation** \u2014 External input (or Read Model, slice before) \u2192 Translation + Command \u2192 Event, together\n\nBetween them these are the only legal connections: `ui \u2192 command`, `command \u2192 event`,\n`event \u2192 read model`, `read model \u2192 ui`, `read model \u2192 reaction`, `reaction \u2192 command`. A command\nnever reaches a read model directly \u2014 the event goes between them. Every slice is joined up at\nboth ends: something triggers each command (the screen it's issued from, or the reaction that\ntriggers it, also in this slice), and every event a command records is read by some read model \u2014 so each State\nChange slice is paired with the State View slice that projects its event. A read model repeated\nalong the timeline (`view X again`) shows the same projection at a later point; the instances are\nnever connected to one another.\n\n## Storylines\n<!-- Generated \u2014 `em slice index {{model-name}}.em` writes one row per storyline between the\n markers (count, implemented, diagram); the canvas is `em render {{model-name}}.em --map`. -->\n<!-- GENERATED:storylines:start -->\n| Storyline | Slices | Implemented | Diagram |\n|-----------|--------|-------------|---------|\n<!-- GENERATED:storylines:end -->\n\n## Slices\n<!-- The canonical slice index \u2014 the ONE place slices are enumerated (the state file\n points here rather than keeping its own copy). Generated \u2014 run\n `em slice index {{model-name}}.em` to (re)write the table below from the model and its\n slice docs; never hand-edit between the markers. -->\n<!-- GENERATED:slices:start -->\n| # | Slice | Pattern | Status | Design doc |\n|---|-------|---------|--------|------------|\n<!-- GENERATED:slices:end -->\n\n## Status\nSee [`.event-modeling.md`](.event-modeling.md) for current phase, decisions, and open questions.\n";
|
|
4
4
|
/** Raw copy of templates/state.md, \`{{...}}\` placeholders intact — see scaffoldStateFile(). */
|
|
5
5
|
export declare const STATE_TEMPLATE = "<!--\nResumable progress state for an event model. Stored as <model>/.event-modeling.md\nThe skill reads this on `/event-modeling` (no arg) to resume where you left off.\nKeep it current at the end of every working session.\n-->\n\n# Event Modeling Progress \u2014 {{Model Name}}\n\n- **Model file:** `{{model-name}}.em`\n- **Em version:** {{X.Y.Z}}\n- **Current phase:** {{discover | extract | model | slice | implement | conform | review | validate}}\n- **Current step:** {{1\u20137, see methodology; or extraction round R1\u2013R7}}\n- **Last updated:** {{YYYY-MM-DD}}\n- **Last conformance:** {{YYYY-MM-DD @ <target-repo revision> \u2014 report: conformance/<date>-report.md | never}}\n- **Model version:** {{N | none}}\n- **Certified:** {{v<N> @ <target-repo revision> (YYYY-MM-DD) | never}}\n- **Last stakeholder review:** {{YYYY-MM-DD \u2014 attendees: see Participants | never}}\n\n## Session inputs\n- **Scope line:** {{one-line description of what's in/out of bounds for this model}}\n- **PRD / spec reference:** {{path, link, or \"none\"}}\n- **Headless/API model:** {{yes | no}}\n- **Source mode:** {{greenfield | extract-event-driven | extract-procedural}}\n- **Existing system refs:** {{repo paths, event-schema/topic locations, docs \u2014 or \"n/a\"}}\n\n## Participants\n<!-- Populate at session start. Live workshop: one human proxy relays questions to the room;\n attribute every answer/decision in the Decisions log to a named participant here. -->\n- {{Name}} \u2014 {{role}} \u2014 {{domain area}}\n\n## Extraction progress (existing-system models only \u2014 delete for greenfield)\n- [ ] R1. Candidate events (extracted/synthesized, filtered, confirmed)\n- [ ] R2. Timeline order (as-is narrative, actors/callers, first render)\n- [ ] R3. Commands / inputs\n- [ ] R4. Read models / outputs (validate from here)\n- [ ] R5. Boundaries & reactions (reaction shares its slice with the command it triggers)\n- [ ] R6. Gap & TBD reconciliation\n- [ ] R7. Convergence (render + validate clean, user confirmed as-is)\n\n## Steps completed\n- [ ] 1. Brainstorm events\n- [ ] 2. Plot / storyboard (personas + UI)\n- [ ] 3. Inputs (commands)\n- [ ] 4. Outputs (read models)\n- [ ] 5. Swimlanes & apply patterns\n- [ ] 6. Elaborate scenarios\n- [ ] 7. Evaluate completeness (`em validate` clean)\n\n## Decisions log\n<!-- Resolved choices, with the reasoning, so they aren't re-litigated. In a live workshop,\n attribute each entry to the participant who made the call (see Participants above).\n Every entry is a dated bullet (\"- YYYY-MM-DD: ...\"); em changelog skips any other line.\n Seam change request (a needed change to another model's public element; never edit that\n model, keep the open question blocked on its owners):\n - YYYY-MM-DD: seam change request \u2192 <producerKey>:<kind>.<slug> \u2014 <what> \u2014 <why> -->\n- {{YYYY-MM-DD}}: {{decision}} \u2014 {{why}} \u2014 by {{participant, if a live workshop}}\n\n## Usage log\n<!-- The team's only usage signal today (see docs/usage-data.md) \u2014 cheap and coarse on purpose.\n One line per session: phase(s) touched, and validate diagnostic *categories* hit (one of\n the exact fixed strings in docs/usage-data.md#categories, e.g. \"read model has no\n consumer\" \u2014 never the full instance message or any domain content). Append, never edit\n past entries. -->\n- {{YYYY-MM-DD}}: phases: {{discover | extract | model | slice | implement | conform | review | validate | watch, ...}} \u2014 validate: {{diagnostic category (docs/usage-data.md#categories), ... | none}}\n\n## Open questions / parking lot\n<!-- Unresolved items to bring back to the user. Never guess these. Metadata is optional and\n flat \u2014 add only what's known: source (ticket/conversation that spawned it), blocked on\n (who/what), revisit (when). -->\n- [ ] {{question}} \u2014 source: {{ticket/conversation link, optional}} \u2014 blocked on: {{who/what, optional}} \u2014 revisit: {{when, optional}}\n\n## Slice inventory\n<!-- Deliberately NOT a table: the canonical slice index (slice, pattern, status, doc link)\n lives in README.md's \"Slices\" section \u2014 one source of truth, updated there. This file\n only tracks resumable session state. -->\nSee `README.md` \u2192 **Slices** for the slice index and per-slice doc status.\n";
|
|
6
6
|
/** Raw copy of templates/constitution.md, \`{{...}}\` placeholders intact — see
|
package/dist/templates.js
CHANGED
|
@@ -93,14 +93,22 @@ Change slice is paired with the State View slice that projects its event. A read
|
|
|
93
93
|
along the timeline (\`view X again\`) shows the same projection at a later point; the instances are
|
|
94
94
|
never connected to one another.
|
|
95
95
|
|
|
96
|
+
## Storylines
|
|
97
|
+
<!-- Generated — \`em slice index {{model-name}}.em\` writes one row per storyline between the
|
|
98
|
+
markers (count, implemented, diagram); the canvas is \`em render {{model-name}}.em --map\`. -->
|
|
99
|
+
<!-- GENERATED:storylines:start -->
|
|
100
|
+
| Storyline | Slices | Implemented | Diagram |
|
|
101
|
+
|-----------|--------|-------------|---------|
|
|
102
|
+
<!-- GENERATED:storylines:end -->
|
|
103
|
+
|
|
96
104
|
## Slices
|
|
97
105
|
<!-- The canonical slice index — the ONE place slices are enumerated (the state file
|
|
98
106
|
points here rather than keeping its own copy). Generated — run
|
|
99
107
|
\`em slice index {{model-name}}.em\` to (re)write the table below from the model and its
|
|
100
108
|
slice docs; never hand-edit between the markers. -->
|
|
101
109
|
<!-- GENERATED:slices:start -->
|
|
102
|
-
| # | Slice | Pattern | Status |
|
|
103
|
-
|
|
110
|
+
| # | Slice | Pattern | Status | Design doc |
|
|
111
|
+
|---|-------|---------|--------|------------|
|
|
104
112
|
<!-- GENERATED:slices:end -->
|
|
105
113
|
|
|
106
114
|
## Status
|
package/dist/templates.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,mCAAmC;AAEnC,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDzB,CAAC;AAEF,wDAAwD;AACxD,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,2FAA2F;AAC3F,2FAA2F;AAC3F,+FAA+F;AAC/F,2FAA2F;AAC3F,2CAA2C;AAE3C,qGAAqG;AACrG,MAAM,CAAC,MAAM,qBAAqB,GAAG
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../src/templates.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,mCAAmC;AAEnC,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDzB,CAAC;AAEF,wDAAwD;AACxD,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,2FAA2F;AAC3F,2FAA2F;AAC3F,+FAA+F;AAC/F,2FAA2F;AAC3F,2CAA2C;AAE3C,qGAAqG;AACrG,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDpC,CAAC;AAEF,iGAAiG;AACjG,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4E7B,CAAC;AAEF;8BAC8B;AAC9B,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqIpC,CAAC;AAEF;oFACoF;AACpF,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,0FAA0F;IAC1F,yFAAyF;IACzF,6FAA6F;IAC7F,OAAO,UAAU,CAAC,OAAO,CAAC,2BAA2B,EAAE,GAAG,EAAE,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC;AACnF,CAAC;AAED;;;;4DAI4D;AAC5D,MAAM,UAAU,cAAc,CAAC,WAAmB,EAAE,QAAgB;IAClE,6FAA6F;IAC7F,4EAA4E;IAC5E,OAAO,qBAAqB,CAAC,OAAO,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC;SAC3E,OAAO,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC;SAC9C,OAAO,CACN,oFAAoF,EACpF,yFAAyF,CAC1F,CAAC;AACN,CAAC;AAED;;;;8FAI8F;AAC9F,MAAM,UAAU,iBAAiB,CAAC,WAAmB,EAAE,QAAgB,EAAE,KAAa,EAAE,SAAiB;IACvG,qFAAqF;IACrF,wFAAwF;IACxF,4BAA4B;IAC5B,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC;SACvE,OAAO,CAAC,gBAAgB,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC;SACzC,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,8DAA8D;SACpG,OAAO,CAAC,kFAAkF,EAAE,UAAU,CAAC;SACvG,OAAO,CAAC,+DAA+D,EAAE,GAAG,CAAC;SAC7E,OAAO,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC,8DAA8D;QAChG,oEAAoE;SACnE,OAAO,CAAC,6FAA6F,EAAE,OAAO,CAAC;SAC/G,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,qDAAqD;SACrF,OAAO,CAAC,wDAAwD,EAAE,OAAO,CAAC,CAAC,yBAAyB;SACpG,OAAO,CAAC,2DAA2D,EAAE,OAAO,CAAC,CAAC;IAEjF,OAAO,MAAM;SACV,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;SACtC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;;;4CAQ4C;AAC5C,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,6FAA6F;IAC7F,0FAA0F;IAC1F,wCAAwC;IACxC,OAAO,qBAAqB,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC;AAC9E,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "em",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
4
4
|
"description": "Event Modeling with em: discover, design, implement, conform, review and engagement skills over a slice-first text DSL, plus the em MCP server.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mike Key"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"command": "npx",
|
|
11
11
|
"args": [
|
|
12
12
|
"-y",
|
|
13
|
-
"@milehimikey/em@1.
|
|
13
|
+
"@milehimikey/em@1.21.0",
|
|
14
14
|
"mcp"
|
|
15
15
|
]
|
|
16
16
|
}
|
|
@@ -23,12 +23,15 @@ em render <file> # transpile
|
|
|
23
23
|
em render <file> -o, --out <path> # output path (extension picks the format)
|
|
24
24
|
em render <file> -T, --format <fmt> # output format (svg, png, pdf, ...)
|
|
25
25
|
em render <file> --slice <name> # render only this slice, redrawn in its own canonical pattern shape (default out: slices/<kebab-slug>.svg)
|
|
26
|
-
em render <file> --storyline <name> # render only this storyline: its slices in order,
|
|
26
|
+
em render <file> --storyline <name> # render only this storyline: its own slices in order, nothing from outside it (default out: storylines/<kebab-slug>.svg)
|
|
27
|
+
em render <file> --map # render every storyline to storylines/<kebab-slug>.svg plus a draggable canvas of them all, with the flow between storylines, at storylines/map.html (-o picks the html path)
|
|
27
28
|
em render <file> --emit-dot # print the generated DOT instead of rendering
|
|
28
29
|
em render <file> --keep-empty-lanes # keep the API lane even when empty
|
|
29
30
|
em export <file> # export a versioned JSON snapshot of the normalized model
|
|
30
31
|
em export <file> -o, --out <path> # write to a file instead of stdout
|
|
31
32
|
em export <file> --slice <key> # export only this slice's object (pattern/fields/doc) instead of the whole model (export key, MIL-128) — refuses only if THIS slice has an error; an unrelated slice's breakage elsewhere in the model doesn't block it (see docs/cli.md)
|
|
33
|
+
em export <file> --doc-json # emit the structured slice-doc export (GH #401) instead of the model snapshot: per slice the frontmatter join plus the parsed sections as data (fields, invariants, scenarios, error flows, open questions) and a model-level invariant catalog. Own schema version; whole model only (does not combine with --slice)
|
|
34
|
+
em export <file> --include-html # with --doc-json, include each slice doc's rendered HTML body (excluded by default; the authored body never appears in a plain export)
|
|
32
35
|
em api generate <file> # write the TypeSpec contract for the model's public commands, events and views to <model dir>/contracts/<model key>.tsp
|
|
33
36
|
em api generate <file> -o, --out <path> # write to this path instead of <model dir>/contracts/<model key>.tsp
|
|
34
37
|
em api generate <file> --stdout # print the contract instead of writing it
|
|
@@ -69,6 +72,7 @@ em slice stub-all <file> --implemented-in <url> # PR/commit
|
|
|
69
72
|
em slice stub-all <file> --dry-run # list what would be stubbed/wired without writing anything
|
|
70
73
|
em slice index <file> # rewrite the model's sibling README.md's GENERATED Slices table from `em export`'s slice facts (key, pattern, doc status/implementedIn) — the hand-maintained table is deprecated
|
|
71
74
|
em slice index <file> --check # verify the table is current; exit non-zero on drift without writing (CI)
|
|
75
|
+
em slice index <file> --full # every lifecycle column (reviewed/ratified/owner/tracking/implemented/conformed) instead of the reader's five
|
|
72
76
|
em slice mark-implemented <file> <slice-key> <pr-url> # flip a slice doc's frontmatter to `status: implemented` / `implementedIn: <pr-url>` — the one edit an implementing agent makes to a ratified doc at merge (MIL-103, replaces the em-sdd-bridge `em-sdd-mark-implemented` script; see reference/implement.md §6). Applies only to a `ready-to-implement` doc (MIL-277: a `draft`/`reviewed` doc refuses — ratify first). Also records the shipped version beside the link (MIL-284): `shippedVersion:`, `shippedRef:` (the doc's `ratifiedRef:`, when it has one) and `shippedOn:`, and opens the next version as a `draft` when an Open Question was deferred to it (MIL-283). Idempotent on the same URL — also after that draft opened; refuses to overwrite a different one; never touches the doc body except to re-open those deferred questions
|
|
73
77
|
em slice mark-implemented <file> <slice-key> <pr-url> --on <date> # merge date recorded as `shippedOn:`, YYYY-MM-DD (default: today, local date; MIL-284)
|
|
74
78
|
em slice mark-implemented <file> <slice-key> <pr-url> --json # print a JSON document instead of text: { path, changed, implementedIn, nextDraft: { version, reopened[] } | null } (GH #285)
|
|
@@ -99,10 +103,13 @@ em slice defer <file> <slice-key> [question] --decision <text> # what this
|
|
|
99
103
|
em slice defer <file> <slice-key> [question] --from-issue <text> # defer a captured `issue "..."` on this slice instead of a doc Open Question (case-sensitive substring of its text)
|
|
100
104
|
em slice defer <file> <slice-key> [question] --by <name> # who deferred it
|
|
101
105
|
em slice defer <file> <slice-key> [question] --on <date> # deferral date, YYYY-MM-DD (default: today, local date)
|
|
102
|
-
em slice conform <file> <slice-key> # record per-slice-per-version conformance certification: sets `conformedVersion:`/`conformedAt:`/`conformedOn:` on a slice doc (MIL-214) — the fact `driftSignal: in-sync` now depends on. Legal only for a shipped slice (`status: implemented`, or any status with a `shippedVersion:` — MIL-283) with an `implementedIn:` link; `conformedVersion:` is the shipped version. Idempotent on the same (version, --at) pair; a different --at simply overwrites (a later re-certification is normal — there's no way for em to tell 'later' from 'earlier' for an arbitrary revision string, so there's no --force to reach for). Refuses when the conformance/<date>[-<name>]-findings.json file matching --at still has an unruled finding in scope for this slice; --skip-findings-check overrides with a loud notice.
|
|
106
|
+
em slice conform <file> <slice-key> # record per-slice-per-version conformance certification: sets `conformedVersion:`/`conformedAt:`/`conformedOn:` on a slice doc (MIL-214) — the fact `driftSignal: in-sync` now depends on. Legal only for a shipped slice (`status: implemented`, or any status with a `shippedVersion:` — MIL-283) with an `implementedIn:` link; `conformedVersion:` is the shipped version. Idempotent on the same (version, --at) pair; a different --at simply overwrites (a later re-certification is normal — there's no way for em to tell 'later' from 'earlier' for an arbitrary revision string, so there's no --force to reach for). Refuses when the conformance/<date>[-<name>]-findings.json file matching --at still has an unruled finding in scope for this slice; --skip-findings-check overrides with a loud notice. GH #400: --preview runs the same doc-resolution and findings-check read for a slice that hasn't shipped yet — the shipped/implementedIn gates are waived and NOTHING is ever written to the doc; output is ephemeral (text or --json) unless --write-findings opts into persisting a normal findings file.
|
|
103
107
|
em slice conform <file> <slice-key> --at <rev> # the target-repo revision this certification sweep diffed against — or, when what was exercised is not a commit that stays reachable (a per-PR environment under squash/rebase merges, a build or image), an opaque `<kind>:<id>` such as build:1234 or deploy:eu-1-2026-10-15 (GH #261); recorded verbatim, skipped by git-reachability checks
|
|
104
108
|
em slice conform <file> <slice-key> --on <date> # certification date, YYYY-MM-DD (default: today, local date)
|
|
105
109
|
em slice conform <file> <slice-key> --skip-findings-check # certify even with unruled findings in scope — prints a loud notice on stderr
|
|
110
|
+
em slice conform <file> <slice-key> --preview # GH #400: pre-ship advisory mode — waives the shipped-status/`implementedIn:` gates, writes NOTHING to the doc (no conformedVersion/conformedAt/conformedOn, ever); ephemeral by default, --write-findings opts into persisting a normal findings file. --skip-findings-check has no effect in this mode (preview never refuses on findings)
|
|
111
|
+
em slice conform <file> <slice-key> --write-findings # with --preview: persist the preview's own unruled findings as conformance/<on>-<slice-key>-preview-findings.json
|
|
112
|
+
em slice conform <file> <slice-key> --json # with --preview: print a JSON document instead of the text report
|
|
106
113
|
em changelog <file> # render a model's git history as a business-readable ledger (see docs/cli.md)
|
|
107
114
|
em changelog <file> --from <rev> # start the walk at this revision (inclusive)
|
|
108
115
|
em changelog <file> --to <rev> # end the walk at this revision (inclusive; default HEAD)
|
|
@@ -146,6 +153,7 @@ em watch <file> -T, --format <fmt> # output for
|
|
|
146
153
|
em watch <file> --keep-empty-lanes # keep the API lane even when empty
|
|
147
154
|
em watch <file> --serve # serve a live viewer with instant push-reload (no polling)
|
|
148
155
|
em watch <file> --port <n> # port for --serve (default 5173)
|
|
156
|
+
em watch <file> --storyline <name> # GH #309 (deferred from #277): filter the live view to one storyline's subset — the same subset `em render --storyline` draws (its own slices in order, plus dimmed stub columns for what they read from outside it and the `after` end state). Whenever the model declares any storylines the viewer also offers a picker to switch to the full model or another declared storyline, live, without restarting. An unknown name errors, listing the declared storylines; requires --serve
|
|
149
157
|
em validate <file> # check a model against event-modeling rules
|
|
150
158
|
em validate <file> --list-issues # print only open `issue` diagnostics (slice, element, line, text)
|
|
151
159
|
em validate <file> --list-divergences # print only accepted-divergence annotations (slice, element, line, text) — never fails the build
|
|
@@ -165,6 +173,7 @@ em refs <file> # check that
|
|
|
165
173
|
em refs <file> --reachable-from <rev> # the branch or commit every ref must be an ancestor of (e.g. origin/main)
|
|
166
174
|
em refs <file> --waive <slice-key> # excuse this slice's non-ancestor/unresolved/undecidable results from the exit code (repeatable); still reported
|
|
167
175
|
em refs <file> --waive-file <path> # a baseline file of slice keys to waive, one per line (`#` comments allowed); missing file = no waivers
|
|
176
|
+
em refs <file> --check-order # advisory-only (GH #399): for every slice doc with a ratifiedRef, report whether a commit between the branch's fork point and ratifiedRef already touched code other than the doc itself — a retrofit signal for inline ratification (spec written to describe code that already exists). History is rewritable, so this NEVER affects the exit code or `ok`, and is never a validate gate — see docs/process.md's inline-ratification section
|
|
168
177
|
em refs <file> --json # print a JSON document instead of the text report (see docs/cli.md)
|
|
169
178
|
em ledger <file> # check slice docs' version: field agrees with their content across two git revisions (opt-in CI check, MIL-89 — never part of `em validate`, see docs/ci.md)
|
|
170
179
|
em ledger <file> --from <rev> # baseline revision
|
|
@@ -269,15 +278,25 @@ em mcp # start an M
|
|
|
269
278
|
em skill install # copy the event-modeling skill bundle into .claude/skills/ (event-modeling, event-modeling-discover/-design/-implement/-conform/-review, event-modeling-shared); across a structural bundle change (e.g. the MIL-157 split of the old single event-modeling/ directory into this six-directory bundle), `em skill sync` is the migration path — --force now performs the same reconcile (MIL-180)
|
|
270
279
|
em skill install -f, --force # overwrite an existing installation, reconciling added/updated/removed files within the bundle's own managed directories the same way `em skill sync` does — never touching an unrelated sibling skill (MIL-180)
|
|
271
280
|
em skill install --no-agents-md # skip writing/updating the AGENTS.md agent-contract section (on by default, MIL-129)
|
|
281
|
+
em skill install --skills-dir <dir> # where the vendored skill bundle lives, relative to the repo root (default .claude/skills; .agents/skills when that exists and .claude/skills does not — GH #412)
|
|
282
|
+
em skill install --agents-dir <dir> # where the four em sub-agent definitions live, relative to the repo root (default .claude/agents, or .agents/agents beside an .agents/skills bundle — GH #412)
|
|
272
283
|
em skill sync [path] # update the vendored .claude/skills/ event-modeling skill bundle in [path] to match the installed em package (overwrites unconditionally; local edits are never merged, MIL-93)
|
|
273
284
|
em skill sync [path] --no-agents-md # skip writing/updating the AGENTS.md agent-contract section (on by default, MIL-129)
|
|
285
|
+
em skill sync [path] --skills-dir <dir> # where the vendored skill bundle lives, relative to the repo root (default .claude/skills; .agents/skills when that exists and .claude/skills does not — GH #412)
|
|
286
|
+
em skill sync [path] --agents-dir <dir> # where the four em sub-agent definitions live, relative to the repo root (default .claude/agents, or .agents/agents beside an .agents/skills bundle — GH #412)
|
|
274
287
|
em skill check [path] # check [path]'s em skills for drift against the installed em package: the em Claude Code plugin's pin (settings + this machine's marketplace registry) when the repo declares it, and the vendored .claude/skills/ bundle when present; exits non-zero on any mismatch (CI-ready, MIL-93, MIL-231)
|
|
275
288
|
em skill check [path] --json # print a JSON document instead of the text report (see docs/cli.md)
|
|
276
289
|
em skill check [path] --ci # also fail (exit 1) when the declared plugin is not registered on this machine (implied by CI=true in the environment); without it that finding prints the install commands on stderr and exits 0
|
|
290
|
+
em skill check [path] --skills-dir <dir> # where the vendored skill bundle lives, relative to the repo root (default .claude/skills; .agents/skills when that exists and .claude/skills does not — GH #412)
|
|
291
|
+
em skill check [path] --agents-dir <dir> # where the four em sub-agent definitions live, relative to the repo root (default .claude/agents, or .agents/agents beside an .agents/skills bundle — GH #412)
|
|
277
292
|
em ci init <model> # install .github/workflows/em-ci.yml (PR gates: em validate, em slice index --check, em coverage --strict, em ledger, em skill check, em glossary --fail-on-conflicts, plus a push-triggered status-badge rebuild) and em-conform.yml (scheduled, advisory-only conformance cadence) — same install discipline as `em skill install`: marker-delimited, idempotent, --check for CI self-verification (MIL-166, see docs/ci.md). Give it a system.yaml (or its directory) instead of a model to cover every model in the system: one workflow, per-model jobs, a conform matrix (MIL-233)
|
|
278
293
|
em ci init <model> --tests <dir> # test directory the coverage/status steps scan for INV-* citations
|
|
279
294
|
em ci init <model> -f, --force # replace an existing workflow file that has no GENERATED markers, or a managed block generated for a different set of models
|
|
280
295
|
em ci init <model> --check # verify both files match the current preset; exit non-zero on drift without writing (CI)
|
|
296
|
+
em storyline split <file> # move each inline `storyline "X" { … }` block into its own storyline model file <slug>/<slug>.em (a `storyline "X" [source]` header, then the block's slices) and leave the one-line declaration `storyline "X" [after "Y"]` in the root (GH #421). Slice docs stay under the root's slices/. A storyline declared in several blocks is left alone (merge them first)
|
|
297
|
+
em storyline split <file> --storyline <name> # split only this storyline
|
|
298
|
+
em storyline split <file> --dry-run # print what would be written without touching anything
|
|
299
|
+
em storyline split <file> -f, --force # overwrite a storyline model file that already exists
|
|
281
300
|
em storyline suggest <file> # advisory (GH #290): propose `storyline` blocks for a model that has none — one per distinct slice `source "url"`, the remaining slices grouped by the view-instance chains (`again`) they feed — printed as a unified diff on stdout (apply with `patch -p1` or `git apply`); never writes the model
|
|
282
301
|
em upgrade <file> # bring a model repo authored under an older em (1.6 forward) up to the installed version: an ordered list of mechanical steps (skill bundle, reaction shape, state-file bullets, generated CI blocks, constitution scaffold) plus a human list of things no command can safely decide by itself (MIL-219, see docs/upgrading.md). Dry-run by default; --apply makes one git commit per applicable step, refusing on a dirty working tree
|
|
283
302
|
em upgrade <file> --apply # apply every applicable mechanical step, one git commit each, then a final `Em version:` commit
|
|
@@ -304,12 +323,14 @@ context Name # an event swimlane row (bounded context / aggr
|
|
|
304
323
|
storyline "Name" [source "url"] [after "Other"] { # optional chapter grouping slices (see Storylines)
|
|
305
324
|
slice "Name" { ... }
|
|
306
325
|
}
|
|
326
|
+
storyline "Name" [after "Other"] [in "path.em"] # a storyline MODEL: its slices live in <slug>/<slug>.em (see Storylines)
|
|
307
327
|
|
|
308
328
|
slice "Name" [source "url"] { # one vertical time step (a column); source is optional
|
|
309
329
|
ui Free Text @Persona # screen; @Persona picks its row (defaults to first/"User")
|
|
310
330
|
command Free Text # state-changing request (API band)
|
|
311
331
|
invariant INV-ORD-1 "Rule" # rule guarding the command/event just above (see Clauses)
|
|
312
332
|
view Free Text from "Event A", "Event B" # read model fed by event(s)
|
|
333
|
+
view Free Text from "Event A" updates from "Event B", "Event C" # B, C keep rows current: read, never drawn (see Clauses)
|
|
313
334
|
view Free Text again from "Event C" # later instance of an evolving read model (see Clauses)
|
|
314
335
|
event Free Text @Context # recorded fact; @Context picks its row (defaults to "Domain")
|
|
315
336
|
processor Free Text from "View" # automation; aliases: automation | saga | translation
|
|
@@ -353,6 +374,14 @@ type Name { field: Type, ... } # named structured type, reusable from any f
|
|
|
353
374
|
previous instance of V that also reads E), and EVERY site needs a reader at or after it (add `view V again from "E"`
|
|
354
375
|
after the last site, or `event-unread` warns for that site). The same name in a different context
|
|
355
376
|
is still a `duplicate-name` warning.
|
|
377
|
+
- **`updates from "Event", …`** (views only, GH #414): the subset of a view's sources that only keep a
|
|
378
|
+
row current or remove it (a due date moved, an address changed, a loan returned). They are folded
|
|
379
|
+
into the view's `from` for every check — `derived from`, completeness, the generated built-from
|
|
380
|
+
list — but never drawn as arrows: the diagram shows the line from the event that puts work on the
|
|
381
|
+
list, and lists the rest under "Kept current by". The author chooses the triggers: `view Holds To
|
|
382
|
+
Fulfill from "Hold Placed", "Tool Returned" updates from "Hold Collected", "Hold Cancelled"`.
|
|
383
|
+
Valid on an `again` instance too. A to-do view with more than one or two inbound arrows is missing
|
|
384
|
+
this split.
|
|
356
385
|
- **`again`** (views only): `view <Name> again [from "Event", …]` declares a later instance of an
|
|
357
386
|
already-declared read model — the forward-only device for a view that evolves as later events
|
|
358
387
|
land. Instances are ONE logical view: the first declaration owns the `note` binding; each
|
|
@@ -490,7 +519,19 @@ type Name { field: Type, ... } # named structured type, reusable from any f
|
|
|
490
519
|
declared `type T`, with `derived from "Child Created", "Child Deleted"`, embeds a child entity:
|
|
491
520
|
each field of `T` must trace to a named event (`fields-completeness/view-field-no-source`
|
|
492
521
|
otherwise); a field also traces one level through the declared element type of an array field
|
|
493
|
-
on the event (`optionValues: VariantOptionValue[]`), no deeper
|
|
522
|
+
on the event (`optionValues: VariantOptionValue[]`), no deeper by same name. When the event
|
|
523
|
+
renamed or flattened the field, declare the element field's source by **path** into the named
|
|
524
|
+
event, as the unquoted form of the same clause (GH #383): `attributeValueIds: string[] derived
|
|
525
|
+
from values[].attributeValueId` — a `.`-joined chain of identifiers, each `[]`-suffixed exactly
|
|
526
|
+
when it steps through an array field (the marker is enforced against the event field's actual
|
|
527
|
+
arrayness). The path must resolve on a named event — every named event is tried; non-leaf
|
|
528
|
+
segments must be `type`-valued fields — and the leaf field's type must match the element
|
|
529
|
+
field's (array markers stripped); an unresolved path or leaf-type mismatch is
|
|
530
|
+
`fields-completeness/view-field-no-source` (implicit same-name nested tracing matches names
|
|
531
|
+
only; the explicit path form earns the stronger leaf-type check). The quoted event-list form
|
|
532
|
+
and the unquoted path form are mutually exclusive on one field — both at once is a parse error.
|
|
533
|
+
A plain (non-collection) view field may carry the same path form, checked the same way against
|
|
534
|
+
the view's source events — never silently exempt like a bare `derived` field. An
|
|
494
535
|
element field the projection computes rather than copies (an audit stamp from event metadata,
|
|
495
536
|
say) is marked `derived` on the `type` field itself — bare or `derived from "<events>"`, same
|
|
496
537
|
syntax as a view field (GH #382): it is then skipped by `view-field-no-source`, and a traced
|
|
@@ -531,8 +572,15 @@ type Name { field: Type, ... } # named structured type, reusable from any f
|
|
|
531
572
|
Slices keep their file-order timeline position; a slice outside any storyline is allowed;
|
|
532
573
|
storylines don't nest and a repeated name continues that storyline (its slices join it; a continuation may not add or change
|
|
533
574
|
`source`/`after` — parse error). The full render draws a
|
|
534
|
-
labelled band above the slice headers; `em render --storyline "Name"` draws one story alone
|
|
535
|
-
|
|
575
|
+
labelled band above the slice headers; `em render --storyline "Name"` draws one story alone — its own
|
|
576
|
+
slices only, nothing from outside it — and `em render <root>.em --map` puts every story's real
|
|
577
|
+
diagram on one draggable canvas with the flow between stories (`after` thick, reads dashed and
|
|
578
|
+
labelled). **Storyline models (GH #421):** `storyline "Name" [after "Other"] [in "path.em"]` with no
|
|
579
|
+
body declares a storyline whose slices live in `<slug>/<slug>.em` — a file that starts with
|
|
580
|
+
`storyline "Name" [source "url"]` and holds slice blocks only — with its docs in `<slug>/slices/`;
|
|
581
|
+
the root is the compile unit (always give em the root), and `em storyline split <root>.em` turns
|
|
582
|
+
inline blocks into files, moving each story's docs. A storyline that reads another declares `after`
|
|
583
|
+
it (`storyline-reads-without-after`). `em export` carries `slice.storyline` and
|
|
536
584
|
`model.storylines[]`; `em query slices --storyline`; `em slice index` adds a Storyline column. Once
|
|
537
585
|
any storyline exists a slice outside every one is the advisory warning `slice-outside-storyline`.
|
|
538
586
|
`after "<other>"` reads the storyline as if its slices followed the referenced storyline's last
|
|
@@ -858,6 +906,7 @@ not the prose above has caught up yet. `--slice-ready <key>`-only codes are excl
|
|
|
858
906
|
<!-- GENERATED:validate-rules:start -- run `npm run docs:generate` to refresh, do not hand-edit -->
|
|
859
907
|
| Code | Severity | Title | Fix |
|
|
860
908
|
|---|---|---|---|
|
|
909
|
+
| `again-restates-sources` | warning | Continuation restates sources an earlier instance already read | Name only the events that changed the view since the previous instance on the `again` line; the view's field sources are the union across instances, so nothing is lost (docs/dsl.md#view--again). |
|
|
861
910
|
| `alternative-events-no-command` | error | Alternative events without a command | Add the command whose decision records one of the alternatives, in the same slice. |
|
|
862
911
|
| `arrow-backward` | error | Backward arrow | Restructure so the target comes later. |
|
|
863
912
|
| `arrow-unresolved-source` | error | Arrow source unresolved | Fix the arrow's source name. |
|
|
@@ -898,6 +947,7 @@ not the prose above has caught up yet. `--slice-ready <key>`-only codes are excl
|
|
|
898
947
|
| `fields-completeness/view-field-no-source` | warning | View field with no source | Add the field to a source event, or remove it from the view. |
|
|
899
948
|
| `frontmatter-coherence-implemented-without-link` | warning | Implemented without a link | Add `implementedIn` once the slice ships. |
|
|
900
949
|
| `frontmatter-invalid` | warning | Invalid or missing frontmatter | Add the required frontmatter keys, or add a frontmatter block. |
|
|
950
|
+
| `frontmatter-status-unrecognized` | warning | Unrecognized slice status | Set `status:` to one of draft, reviewed, ready-to-implement, implemented. |
|
|
901
951
|
| `grid-collision` | error | Band collision | Split the colliding elements into separate slices. |
|
|
902
952
|
| `invariant-without-scenario` | warning | Invariant cited by no scenario | Cite the INV id in the Given/When/Then (or title) of the scenario that exercises it, or add one. |
|
|
903
953
|
| `invariants/declared-in-both` | warning | Invariant declared in the model and in a slice doc | Keep the model's `invariant` line; in the doc, cite the ID and elaborate instead of restating it as a `**INV-…:**` rule. |
|
|
@@ -941,6 +991,7 @@ not the prose above has caught up yet. `--slice-ready <key>`-only codes are excl
|
|
|
941
991
|
| `storyline-after-cycle` | error | Storyline `after` cycle | Remove an `after` clause so no storyline comes after itself. |
|
|
942
992
|
| `storyline-after-out-of-order` | error | Backward timeline (storyline declared above the one it comes after) | Move the storyline block below the storyline it comes `after`, or restructure the feed. |
|
|
943
993
|
| `storyline-after-unknown` | error | `after` names an unknown storyline | Name a storyline declared in this model, or drop the `after` clause. |
|
|
994
|
+
| `storyline-reads-without-after` | warning | Storyline reads another without declaring `after` it | Add `after "<the storyline it reads>"` to the reading storyline (or to one between them); if the two stories are parallel on purpose, accept it on the shape exit gate (docs/storyline.md). |
|
|
944
995
|
| `system-manifest-invalid` | error | Seam manifest invalid | Fix the manifest: `systemSchemaVersion: "2.0"`, `models:` with a readable `source` per model, and nothing else (`seams:`/`owner:` moved into the models — run `em upgrade`). |
|
|
945
996
|
| `system-manifest-outdated` | warning | Seam manifest is schema 1.0 | Run `em upgrade <model>.em --apply` once: it moves `seams:` into `consumes` clauses and `owner:` onto each model header, and rewrites the manifest to 2.0. |
|
|
946
997
|
| `system-model-key-mismatch` | error | Manifest model key differs from the export's `model.key` | Rename the manifest's `models:` key to the computed key the message prints. |
|
|
@@ -955,6 +1006,7 @@ not the prose above has caught up yet. `--slice-ready <key>`-only codes are excl
|
|
|
955
1006
|
| `view-again-without-earlier` | error | `again` without an earlier declaration | Declare the view plainly the first time it appears. |
|
|
956
1007
|
| `view-from-future-event` | error | Backward timeline (view reads a future event) | Move the source to a later `view X again` instance. |
|
|
957
1008
|
| `view-from-unresolved` | error | Unknown event source | Fix the `from` reference to name an existing event. |
|
|
1009
|
+
| `view-lookup-source` | warning | View reads an event only as a lookup | Carry the field on the event that creates this view's own row instead; if this is a genuine cross-context row change, accept it on the shape exit gate (docs/validation.md#the-shape-exit-gate) rather than fixing it (docs/patterns.md#state-view). |
|
|
958
1010
|
| `view-no-source` | warning | Read model without source | Add `from "Event"`, or place the view in a slice with an event. |
|
|
959
1011
|
<!-- GENERATED:validate-rules:end -->
|
|
960
1012
|
|
|
@@ -219,7 +219,11 @@ drift into **CRUD laid on a timeline**; these rules stop that. Quoted lines are
|
|
|
219
219
|
reorganize are **secondary storylines** (chapters; Dilger: "one linear flow from left to right. No
|
|
220
220
|
exceptions… Linearize it!", "Model one process at a time, each with its own clear ending"). Never one
|
|
221
221
|
lifecycle block per entity. Name the main and every secondary storyline; a `storyline "Name" { … }`
|
|
222
|
-
block groups the slices (`dsl.md`, Storylines).
|
|
222
|
+
block groups the slices (`dsl.md`, Storylines). **A storyline is the unit a reader consumes, so it
|
|
223
|
+
is the unit an author edits too (GH #421):** the root model lists the storylines and their flow
|
|
224
|
+
(`storyline "Name" [after "Other"]`), and each story's slices live in `<slug>/<slug>.em` with its
|
|
225
|
+
docs in `<slug>/slices/`. Draft with inline blocks if that is faster, then `em storyline split
|
|
226
|
+
<root>.em` once the storylines are named — before docs are wired, so nothing moves twice.
|
|
223
227
|
- **Build from walkthroughs first.** The story already lives in the spec's walkthroughs, use cases and
|
|
224
228
|
user journeys. Build the timeline from those; the resource/API reference (OpenAPI, endpoint tables,
|
|
225
229
|
migrations) fills only the operations no walkthrough touches, and is read last. Headless: a persona
|
|
@@ -317,12 +321,57 @@ drift into **CRUD laid on a timeline**; these rules stop that. Quoted lines are
|
|
|
317
321
|
view carries ids; child with its own data → embedded in the parent view; child queried without the
|
|
318
322
|
parent id → its own view. Aggregate rules decide write-side consistency, never read models. *(em
|
|
319
323
|
ruling)*
|
|
324
|
+
- **Views as lookups: an event that creates a row carries what the row shows.** A view reads another
|
|
325
|
+
event only when that event adds, changes or removes a row the view already owns — never merely to
|
|
326
|
+
fill a column on a row some *other* event created. **Per-view check:** for each `from "E"` on a view,
|
|
327
|
+
ask *does E add, change or remove a row here? If it only fills a column, put the column on the event
|
|
328
|
+
that creates the row and drop E.* Generated models routinely come out wrong here — a wide fan-out of
|
|
329
|
+
"reference" events into every view that shows a name, and views keeping a lookup table ("every
|
|
330
|
+
neighbor's name and current email, every tool's name") beside their own rows. Fix: the decider
|
|
331
|
+
already read what it needed to enforce its own invariants (e.g. a checkout decider that reads Tool
|
|
332
|
+
Added and Neighbor Registered to validate the request already has `toolName`/`neighborName` in hand),
|
|
333
|
+
so have it assign those fields onto the event it records — the view then needs nothing beyond that
|
|
334
|
+
one event. A slice doc that needs a "Bookkeeping" paragraph (the view keeps, beyond its own rows, a
|
|
335
|
+
lookup of some other entity's fields) has this smell; see `docs/patterns.md#state-view` for the
|
|
336
|
+
worked overdue-notice example.
|
|
337
|
+
`view-lookup-source` is the mechanical, advisory half — it catches the cross-context cases with a few
|
|
338
|
+
false positives; a within-context lookup (`Tool Checked Out` read only to learn whose loan a later
|
|
339
|
+
event concerns) is invisible to it, so this check still has to be done by eye.
|
|
340
|
+
**Then split what is left into trigger and housekeeping** (Dilger: show the line from the event
|
|
341
|
+
that triggers the automation, not every event that touches its read model; GH #414). Of the
|
|
342
|
+
events a view legitimately reads, only the ones that **put work on the list** are the story — they
|
|
343
|
+
go in `from` and are drawn. Every event that merely **keeps a row current or removes it** (a due
|
|
344
|
+
date moved, an address changed, a loan returned) goes in `updates from`: still a source for
|
|
345
|
+
`derived from`, completeness and the generated built-from list, never an arrow. Write the to-do
|
|
346
|
+
list as `view Overdue Loans To Notify from "Tool Checked Out" updates from "Loan Extended",
|
|
347
|
+
"Neighbor Email Changed", "Tool Returned"`. The author chooses the triggers — `Holds To Fulfill`
|
|
348
|
+
keeps two (`from "Hold Placed", "Tool Returned"`) because both put a fulfillable hold on the
|
|
349
|
+
list. **Per-view check:** *which of these events is the reason this row appears? That is `from`;
|
|
350
|
+
everything else is `updates from`.* The render's "Kept current by" legend is the readback: if a
|
|
351
|
+
to-do view shows more than one or two inbound arrows, the split is missing. A State View that is
|
|
352
|
+
not a to-do list gets the same treatment — its screen's story is the event that creates the row.
|
|
320
353
|
- **Write side: children belong in the parent's context** when the child's invariants are checks against
|
|
321
354
|
the parent. A sub-resource schema shared across parent types is one event per parent on the parent's
|
|
322
355
|
context, not a shared aggregate — check the spec's event reference, not its resource section. Where
|
|
323
356
|
two slices record the same fact, repeat the event bare (same name, same context). *(em ruling)*
|
|
324
357
|
- **Repeat the view after every command that changes it** (`again`, span-1 — see State View above), so
|
|
325
|
-
the reader sees the information arrive rather than a view at the end.
|
|
358
|
+
the reader sees the information arrive rather than a view at the end. **A continuation names only
|
|
359
|
+
what changed:** `view X again from "E"` lists the event(s) that changed the view since the previous
|
|
360
|
+
instance — never the originating instance's whole source list again. Field sources are the union
|
|
361
|
+
across instances, so restating loses nothing and only draws the same arrows twice;
|
|
362
|
+
`again-restates-sources` (GH #424) is the mechanical half.
|
|
363
|
+
- **Storylines read as stories** (owner rulings 2026-11-03, after Dilger). (1) **A storyline that reads
|
|
364
|
+
another declares `after` it:** an event of story A feeding a view of story B means B comes after A
|
|
365
|
+
in the telling — write `storyline "B" after "A"` (or on a storyline between them); two stories that
|
|
366
|
+
really run in parallel read nothing from each other. `storyline-reads-without-after` (GH #420) is
|
|
367
|
+
the mechanical half. (2) **Review each story on its own render and on the canvas, never on the
|
|
368
|
+
full timeline:** `em render <root>.em --map` draws every storyline's real diagram as a frame with
|
|
369
|
+
the flow between stories (`after` thick, reads dashed and labelled by event); the full timeline is
|
|
370
|
+
for `em diff` and ordering checks, not for reading. A storyline render shows only the storyline —
|
|
371
|
+
nothing from outside it is drawn, so an inbound arrow you miss there is a connector on the canvas.
|
|
372
|
+
(3) **Housekeeping is not drawn** (`updates from`, above) and **continuations name only what
|
|
373
|
+
changed** (above): together these are what keeps a story's render to one line per cause. *(em
|
|
374
|
+
ruling, built on Dilger's "the line from the event that triggers it")*
|
|
326
375
|
- **Outcomes are events of one slice** (Dilger: "One decision. One event. One state change."; one
|
|
327
376
|
action with two outcomes is the legitimate exception): alternative events on one context in one slice
|
|
328
377
|
(`event A | B @Ctx`, GH #278), failure as a scenario first, a chapter only when core (it changes what the user does next, or has
|
|
@@ -57,7 +57,7 @@ to decide `frontmatter-invalid` without re-deriving frontmatter-shape rules of i
|
|
|
57
57
|
| `schemaVersion` | integer | `1` (current dialect version) | its *value* is not read back by any `em` command today (reserved) — but its *presence* is required by `hasUsableFrontmatter()`: a doc omitting it is `frontmatter-invalid` (see below) |
|
|
58
58
|
| `pattern` | string | `state-change` \| `state-view` \| `automation` \| `translation` | authored/informational only — `em catalog` and `em export` both derive pattern from the `.em` AST instead (`em export`'s `slice.pattern`, schema `1.4`) |
|
|
59
59
|
| `swimlane` | string | free text, `<Persona> → <Context>` | display-only |
|
|
60
|
-
| `status` | string, case-insensitive | `draft` \| `reviewed` \| `ready-to-implement` \| `implemented` | written by `em slice review` (→ `reviewed`, MIL-201), `em slice ratify`/`em slice reratify` (→ `ready-to-implement`) and `em slice mark-implemented` (→ `implemented`); read by `em catalog`, `em render`/`em watch` header coloring; joined into `em export`'s `slice.doc.status` (schema `1.4`); paired with `implementedIn` to compute `slice.doc.driftSignal` (schema `1.5`, MIL-85) and `em validate`'s frontmatter-coherence check (MIL-85 — see [validation.md#frontmatter-coherence](https://github.com/milehimikey/em/blob/main/docs/validation.md#frontmatter-coherence)) |
|
|
60
|
+
| `status` | string, case-insensitive | `draft` \| `reviewed` \| `ready-to-implement` \| `implemented` | written by `em slice review` (→ `reviewed`, MIL-201), `em slice ratify`/`em slice reratify` (→ `ready-to-implement`) and `em slice mark-implemented` (→ `implemented`); read by `em catalog`, `em render`/`em watch` header coloring; joined into `em export`'s `slice.doc.status` (schema `1.4`); paired with `implementedIn` to compute `slice.doc.driftSignal` (schema `1.5`, MIL-85) and `em validate`'s frontmatter-coherence check (MIL-85 — see [validation.md#frontmatter-coherence](https://github.com/milehimikey/em/blob/main/docs/validation.md#frontmatter-coherence)); any other value is read as written but `em validate` warns `frontmatter-status-unrecognized` (GH #411) |
|
|
61
61
|
| `version` | integer | positive integer, starts at `1` | joined into `em export`'s `slice.doc.version` (schema `1.4`, MIL-91) |
|
|
62
62
|
| `implementedIn` | string | free text (PR/commit link) | joined into `em export`'s `slice.doc.implementedIn` (schema `1.4`, MIL-91); paired with `status` to compute `slice.doc.driftSignal` (schema `1.5`, MIL-85) and `em validate`'s frontmatter-coherence check (MIL-85 — see [validation.md#frontmatter-coherence](https://github.com/milehimikey/em/blob/main/docs/validation.md#frontmatter-coherence)) |
|
|
63
63
|
| `split-from` | single ref | `<slice-key>@v<N>` | joined into `em export`'s `slice.doc.splitFrom` (schema `1.4`, MIL-91) and `em diff`'s `slice-added` entries (schema `1.6`, MIL-84); current-tree referential checks by `em validate` (MIL-84 — see [validation.md#lineage](https://github.com/milehimikey/em/blob/main/docs/validation.md#lineage)) |
|
|
@@ -473,6 +473,7 @@ re-run `em slice sync`.
|
|
|
473
473
|
|
|
474
474
|
| Region | Section | Body |
|
|
475
475
|
|---|---|---|
|
|
476
|
+
| `em-slice-story` | right under `` | one line: `Step N of M in **<Storyline>** · after <Prev> · before <Next> · <Pattern>` (Prev and Next link to the neighbouring slices' docs; a continuation neighbour is named, not linked) — where the slice sits in its story; the one region `em slice sync` inserts when missing on an unsigned doc (see `em slice sync` in the CLI reference) |
|
|
476
477
|
| `em-slice-command` | `## Command / Input` | `**Command:** \`Name\`` + `\| Field \| Type \| Required \| Rules / Validation \|` (Required is `no` for a `name?: Type` field) |
|
|
477
478
|
| `em-slice-event` | `## Event(s) Emitted` | `**Event:** \`Name\` → context \`Ctx\`` + `\| Field \| Type \| Immutable Fact? \| Source / Notes \|` (Source: the same-slice command field it is copied from; failing that, the command from another slice that also records the event, written `not supplied by this command (from \`A\`, slice "Create")` (GH #344 / #362, the same union `fields-completeness/event-field-no-source` checks; worded as a statement about this slice, since the repeat's own command does not take the field); `assigned` for a system-assigned field, else `{{ }}`) |
|
|
478
479
|
| `em-slice-view` | `## Read Model / View` | `- **View:** \`Name\` built from events: …` (the union across the originating and every `again` instance; each later event is annotated `(via "<slice>")` with the slice of the instance that adds it) + `\| Field \| Type \| Source / Notes \|` (Source: the source event, from that union, carrying the field, `Derived` for a `derived` field, `Collection of \`T\`, fed by …` for a `T[] derived from …` field — followed by one neutral Given/Then scenario stub per named event under the table, to copy into `## Scenarios` and complete there (the region itself stays read-only); `em slice sync` retires a stub once an authored scenario covers that field and event, by the stub's `<field> after <Event>` title or by a Given naming the event with the field named in the block (GH #368), and drops the `Scenario stubs for` line when none is left — else `{{ }}`) |
|
|
@@ -32,14 +32,22 @@ Change slice is paired with the State View slice that projects its event. A read
|
|
|
32
32
|
along the timeline (`view X again`) shows the same projection at a later point; the instances are
|
|
33
33
|
never connected to one another.
|
|
34
34
|
|
|
35
|
+
## Storylines
|
|
36
|
+
<!-- Generated — `em slice index {{model-name}}.em` writes one row per storyline between the
|
|
37
|
+
markers (count, implemented, diagram); the canvas is `em render {{model-name}}.em --map`. -->
|
|
38
|
+
<!-- GENERATED:storylines:start -->
|
|
39
|
+
| Storyline | Slices | Implemented | Diagram |
|
|
40
|
+
|-----------|--------|-------------|---------|
|
|
41
|
+
<!-- GENERATED:storylines:end -->
|
|
42
|
+
|
|
35
43
|
## Slices
|
|
36
44
|
<!-- The canonical slice index — the ONE place slices are enumerated (the state file
|
|
37
45
|
points here rather than keeping its own copy). Generated — run
|
|
38
46
|
`em slice index {{model-name}}.em` to (re)write the table below from the model and its
|
|
39
47
|
slice docs; never hand-edit between the markers. -->
|
|
40
48
|
<!-- GENERATED:slices:start -->
|
|
41
|
-
| # | Slice | Pattern | Status |
|
|
42
|
-
|
|
49
|
+
| # | Slice | Pattern | Status | Design doc |
|
|
50
|
+
|---|-------|---------|--------|------------|
|
|
43
51
|
<!-- GENERATED:slices:end -->
|
|
44
52
|
|
|
45
53
|
## Status
|
|
@@ -80,6 +80,10 @@ implementedIn: {{PR/commit link — fill in once status is `implemented`}}
|
|
|
80
80
|
|
|
81
81
|

|
|
82
82
|
|
|
83
|
+
<!-- GENERATED:em-slice-story:start — generated from the model by `em slice sync`; do not hand-edit -->
|
|
84
|
+
_Run `em slice sync` to place this slice in its story._
|
|
85
|
+
<!-- GENERATED:em-slice-story:end -->
|
|
86
|
+
|
|
83
87
|
<!-- Only on re-ratification of an already-`implemented` slice — omit this whole section on a
|
|
84
88
|
slice's first version (v1 has no delta yet). The heading is always the literal `## Delta`,
|
|
85
89
|
never `## Delta: vX → vY` — hop metadata is a display line inside the section instead (see
|
|
@@ -165,7 +169,14 @@ an event directly.}}
|
|
|
165
169
|
line and field table are a GENERATED region (one per read model; `em-slice-view-<view-slug>`
|
|
166
170
|
when there are several): Source / Notes names the source event a field is copied from, or
|
|
167
171
|
`Derived` for a field marked `derived` in the `.em` (docs/dsl.md#derived-fields) — say how
|
|
168
|
-
it is derived in prose below the region. `{{ }}` marks a field the model cannot trace.
|
|
172
|
+
it is derived in prose below the region. `{{ }}` marks a field the model cannot trace.
|
|
173
|
+
If describing a field here needs a "Bookkeeping" paragraph — this view also keeps, beyond its
|
|
174
|
+
own rows, a lookup of some other entity's name/email/etc. so it can display it — that is the
|
|
175
|
+
views-as-lookups smell (methodology reference, "Views as lookups"): the field belongs on the
|
|
176
|
+
event that creates this view's row instead, copied from state the command/decider already
|
|
177
|
+
reads to enforce its own invariants. Fix the `.em`, not the prose. The built-from list names
|
|
178
|
+
every source, trigger and housekeeping alike; in the `.em` only the triggering event(s) sit in
|
|
179
|
+
`from`, the rest in `updates from` (methodology reference, "trigger and housekeeping"). -->
|
|
169
180
|
<!-- GENERATED:em-slice-view:start — generated from the model by `em slice sync`; do not hand-edit -->
|
|
170
181
|
- **View:** `{{View Name}}` built from events: {{"Event A", "Event B"}}
|
|
171
182
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: conform
|
|
3
|
-
em-version: 1.
|
|
3
|
+
em-version: 1.21.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
|
|
@@ -40,7 +40,9 @@ difference is what you do with what you find: extract *builds* a model from the
|
|
|
40
40
|
(or the status the user says corresponds to shipped code) for whichever slices are in scope.
|
|
41
41
|
Checking a `draft` or `ready-to-implement` slice against code is a wasted walk — ratified or
|
|
42
42
|
not, nobody has built to it yet; tell the user and skip it rather than reporting "drift"
|
|
43
|
-
against it.
|
|
43
|
+
against it. (GH #400: the ONE exception is a deliberate pre-ship advisory run — see
|
|
44
|
+
`--preview` under step 5 below — not a reason to treat this precondition as optional for an
|
|
45
|
+
ordinary post-ship sweep.)
|
|
44
46
|
3. The codebase to check: the state file's **Existing system refs** (populated during
|
|
45
47
|
`extract`, if this model came from one) or ask the user for the repo path if not set. Record
|
|
46
48
|
it if missing. In a headless/scheduled run with no user to ask, default to the repository
|
|
@@ -336,6 +338,32 @@ been through this) instead of just trusting `implementedIn`. Legal only for `sta
|
|
|
336
338
|
with a link, and itself refuses if an unruled finding for that slice still exists at this
|
|
337
339
|
revision — the mechanical proof this step comes only after rulings, not before.
|
|
338
340
|
|
|
341
|
+
**Pre-ship advisory mode: `--preview` (GH #400).** The certify step above is legal only for a
|
|
342
|
+
**shipped** slice (`status: implemented`/`shippedVersion:` + `implementedIn:`) — precondition 2
|
|
343
|
+
reflects that this phase ordinarily walks shipped code. `--preview` is the deliberate exception:
|
|
344
|
+
the SAME doc-resolution and findings-check read, legal for a slice that hasn't shipped yet
|
|
345
|
+
(the shipped/`implementedIn:` preconditions are waived), and it **never writes anything** —
|
|
346
|
+
no `conformedVersion`/`conformedAt`/`conformedOn`, ever, regardless of outcome:
|
|
347
|
+
|
|
348
|
+
```
|
|
349
|
+
em slice conform <model-name>.em <slice-key> --at <target-repo revision> --preview
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Use this to run a conform sweep against your OWN implementing branch before it merges — catching
|
|
353
|
+
spec/code drift while you can still fix it on the same branch, rather than after shipping. The
|
|
354
|
+
walk itself (steps 1-4 above) is unchanged; only the certify step's preconditions differ. Output
|
|
355
|
+
is ephemeral by default (nothing is written, not even to `conformance/`); pass
|
|
356
|
+
`--write-findings` to persist the run's own unruled findings as a normal
|
|
357
|
+
`conformance/<date>-<slice-key>-preview-findings.json` (this is deliberate — `docs/cli.md`'s
|
|
358
|
+
`em slice conform --preview` section documents the exact shape and naming). Know before opting
|
|
359
|
+
in: the written file has no sibling report (`report` is synthetic), so `em conform-supersede`
|
|
360
|
+
refuses to rule on it — unruled entries in it gate certify/`set-conformance` at that revision
|
|
361
|
+
until you rule them in the file by hand, delete the snapshot, or author the sibling report.
|
|
362
|
+
`em state set-conformance` and the unruled-findings gates are unaffected by
|
|
363
|
+
this mode either way: a default preview run writes nothing for them to read, so it can never
|
|
364
|
+
block a later certify or `set-conformance` call. There is no `--slice-ready` integration for this
|
|
365
|
+
mode yet.
|
|
366
|
+
|
|
339
367
|
End of run: update the state file's `Last conformance:` marker with
|
|
340
368
|
|
|
341
369
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: design
|
|
3
|
-
em-version: 1.
|
|
3
|
+
em-version: 1.21.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
|
|
@@ -72,7 +72,13 @@ Goal: a structurally complete, **validated** model with correct patterns and swi
|
|
|
72
72
|
optional `after "<storyline>"` timeline clause: `em-dsl.md`) so the diagram gets a band per
|
|
73
73
|
story and `em render --storyline "Name"` can show one alone; slices keep their file order, and
|
|
74
74
|
a model can adopt storylines incrementally (`slice-outside-storyline` is only an advisory
|
|
75
|
-
warning) — but name them before you slice, not after.
|
|
75
|
+
warning) — but name them before you slice, not after. **Once the storylines are named, give
|
|
76
|
+
each its own file** (GH #421): run `em storyline split <root>.em` so the root keeps the
|
|
77
|
+
vocabulary and the storyline list with its flow (`storyline "Name" [after "Other"]`) and each
|
|
78
|
+
story's slices live in `<slug>/<slug>.em` with its docs in `<slug>/slices/` — do this before any
|
|
79
|
+
doc is wired, so nothing moves twice. **A storyline that reads another story's events declares
|
|
80
|
+
`after` it** (`storyline-reads-without-after` flags the ones you miss); two stories that run in
|
|
81
|
+
parallel read nothing from each other. Then group events into **contexts** (bounded contexts /
|
|
76
82
|
aggregates) — ask which events share a consistency boundary and who owns them. Classify each
|
|
77
83
|
slice as one of the 4 patterns. **Share the slice between every automation or translation and
|
|
78
84
|
the command it triggers** (the reaction — processor/translation — together with the command
|
|
@@ -89,16 +95,29 @@ Goal: a structurally complete, **validated** model with correct patterns and swi
|
|
|
89
95
|
shape — reshape it with the "Reshaping an existing model" checklist. Then the **intent test**
|
|
90
96
|
per command (would a business person say this name at this step in the story? an endpoint-shaped
|
|
91
97
|
name fails), the **question test** per view (write the question it answers; no question, no
|
|
92
|
-
read model; a child view only when its query needs what the parent view lacks),
|
|
98
|
+
read model; a child view only when its query needs what the parent view lacks), the
|
|
99
|
+
**views-as-lookups check** per `from "E"` on a view (does E add, change or remove a row here? if
|
|
100
|
+
it only fills a column, put the column on the event that creates the row and drop E — see
|
|
101
|
+
`${CLAUDE_PLUGIN_ROOT}/shared/reference/methodology.md`, "Views as lookups"), then the
|
|
102
|
+
**trigger / housekeeping split** on what is left (*which event is the reason this row appears?*
|
|
103
|
+
that one stays in `from`; every event that only keeps a row current or removes it moves to
|
|
104
|
+
`updates from` — the view still reads it, the diagram no longer draws it; a to-do list with more
|
|
105
|
+
than one or two inbound arrows is missing this split), the **continuation check** per `view X
|
|
106
|
+
again` (it names only the events that changed the view since the previous instance, never the
|
|
107
|
+
first instance's list again), and the
|
|
93
108
|
**conditional-invariant signal** (invariants or fields that apply only "if `<field>` is set"
|
|
94
|
-
mean two intents in one command: split it).
|
|
95
|
-
`
|
|
96
|
-
|
|
109
|
+
mean two intents in one command: split it). Read each story on its own render and on the canvas
|
|
110
|
+
(`em render <root>.em --map`), not on the full timeline. The `timeline-entity-clustered`,
|
|
111
|
+
`command-second-intent`, `automation-split-by-outcome`, `view-lookup-source`,
|
|
112
|
+
`again-restates-sources` and `storyline-reads-without-after` lints are the
|
|
113
|
+
mechanical half (the lookup one only catches the cross-context cases — do the check by eye too); the
|
|
114
|
+
design exit gate is `em validate --shape`. Shape the model first, scaffold docs after: a rename,
|
|
97
115
|
split or merge from the reshape would orphan docs already wired with `--wire`. The `slice` phase is unchanged (timeline order).
|
|
98
116
|
3. **Elaborate scenarios — first pass (step 6).** Scaffold every slice's doc now, one per
|
|
99
117
|
slice, none skipped: `em slice new "<slice name>" --pattern <state-change|state-view|
|
|
100
118
|
automation|translation> --swimlane "<Persona> → <Context>" --wire <model>.em` writes
|
|
101
|
-
`slices/<slice-name>.md` at `status: draft` (the
|
|
119
|
+
`slices/<slice-name>.md` at `status: draft` (into the slice's own storyline folder when the model
|
|
120
|
+
is split — pass the ROOT model to `--wire`) (the same command, flags, and `--wire`
|
|
102
121
|
note-binding the `slice` phase's step 2 below documents in full). A slice whose only element
|
|
103
122
|
is a `view X again` instance is a **continuation** (MIL-208), not a slice to scaffold —
|
|
104
123
|
`--wire` refuses it and names the originating slice holding `X`'s first declaration; its
|
|
@@ -131,6 +150,13 @@ Goal: a structurally complete, **validated** model with correct patterns and swi
|
|
|
131
150
|
that reads it; another model/system reads it → mark it `public`; only an automation reads
|
|
132
151
|
it → nothing, it's internal by design. No new keyword — reachability is already what `ui` and
|
|
133
152
|
`public` mean.
|
|
153
|
+
**Per `view`, also ask whether each of its sources earns its place (GH #398):** for every
|
|
154
|
+
`from "E"` on the view, does E add, change or remove a row here — or only fill a column on a
|
|
155
|
+
row some other event already created? The latter is the views-as-lookups smell (methodology
|
|
156
|
+
reference, "Views as lookups"): drop E as a source and have the event that creates the row
|
|
157
|
+
carry the field instead. `view-lookup-source` flags the cross-context instances of this
|
|
158
|
+
mechanically; a lookup from the view's own context (no `@Context` mismatch to key on) only
|
|
159
|
+
this by-eye check catches.
|
|
134
160
|
**Per translation fed from another model, declare what it consumes (MIL-235):** write
|
|
135
161
|
`translation Order Intake consumes checkout:event.order-submitted`. The ref is
|
|
136
162
|
`<modelKey>:<kind>.<slug>`, where kind is `event` or `view` and the target is marked `public`
|