@milehimikey/em 1.13.0 → 1.14.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/agents/em-critic.md +26 -0
- package/.claude/agents/em-implementer.md +34 -0
- package/.claude/agents/em-reviewer.md +31 -0
- package/.claude/agents/em-validator.md +27 -0
- package/.claude/skills/event-modeling/SKILL.md +52 -12
- package/.claude/skills/event-modeling-conform/SKILL.md +1 -1
- package/.claude/skills/event-modeling-conform/reference/conform.md +1 -1
- package/.claude/skills/event-modeling-design/SKILL.md +140 -18
- package/.claude/skills/event-modeling-discover/SKILL.md +1 -1
- package/.claude/skills/event-modeling-engagement/SKILL.md +192 -0
- package/.claude/skills/event-modeling-engagement/reference/engagement.md +143 -0
- package/.claude/skills/event-modeling-implement/SKILL.md +7 -4
- package/.claude/skills/event-modeling-implement/reference/implement.md +51 -12
- package/.claude/skills/event-modeling-review/SKILL.md +1 -1
- package/.claude/skills/event-modeling-shared/reference/em-dsl.md +274 -188
- package/.claude/skills/event-modeling-shared/reference/operating-principles.md +61 -0
- package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +116 -4
- package/.claude/skills/event-modeling-shared/templates/constitution.md +18 -1
- package/.claude/skills/event-modeling-shared/templates/slice.md +64 -39
- package/.claude/skills/event-modeling-shared/templates/state.md +5 -1
- package/.claude-plugin/marketplace.json +14 -0
- package/README.md +25 -11
- package/dist/catalog/apiFirst.d.ts +28 -0
- package/dist/catalog/apiFirst.js +49 -0
- package/dist/catalog/apiFirst.js.map +1 -0
- package/dist/catalog/docJoin.d.ts +13 -0
- package/dist/catalog/docJoin.js +11 -0
- package/dist/catalog/docJoin.js.map +1 -1
- package/dist/catalog/docModelConsistencyValidate.js +44 -4
- package/dist/catalog/docModelConsistencyValidate.js.map +1 -1
- package/dist/catalog/invariantsValidate.d.ts +4 -0
- package/dist/catalog/invariantsValidate.js +102 -0
- package/dist/catalog/invariantsValidate.js.map +1 -0
- package/dist/catalog/scenarios.d.ts +15 -0
- package/dist/catalog/scenarios.js +97 -0
- package/dist/catalog/scenarios.js.map +1 -0
- package/dist/catalog/sliceDoc.d.ts +8 -0
- package/dist/catalog/sliceDoc.js +9 -0
- package/dist/catalog/sliceDoc.js.map +1 -1
- package/dist/catalog/sliceReadyValidate.d.ts +31 -4
- package/dist/catalog/sliceReadyValidate.js +66 -8
- package/dist/catalog/sliceReadyValidate.js.map +1 -1
- package/dist/catalog/sliceSections.d.ts +55 -0
- package/dist/catalog/sliceSections.js +317 -0
- package/dist/catalog/sliceSections.js.map +1 -0
- package/dist/cli/agentsMd.js +7 -1
- package/dist/cli/agentsMd.js.map +1 -1
- package/dist/cli/api.d.ts +90 -0
- package/dist/cli/api.js +318 -0
- package/dist/cli/api.js.map +1 -0
- package/dist/cli/ciInit.d.ts +88 -3
- package/dist/cli/ciInit.js +507 -50
- package/dist/cli/ciInit.js.map +1 -1
- package/dist/cli/conformScope.d.ts +28 -0
- package/dist/cli/conformScope.js +67 -0
- package/dist/cli/conformScope.js.map +1 -1
- package/dist/cli/coverage.d.ts +25 -2
- package/dist/cli/coverage.js +86 -12
- package/dist/cli/coverage.js.map +1 -1
- package/dist/cli/engagement.d.ts +210 -0
- package/dist/cli/engagement.js +444 -0
- package/dist/cli/engagement.js.map +1 -0
- package/dist/cli/engagementFile.d.ts +86 -0
- package/dist/cli/engagementFile.js +255 -0
- package/dist/cli/engagementFile.js.map +1 -0
- package/dist/cli/metrics.d.ts +10 -0
- package/dist/cli/metrics.js +49 -1
- package/dist/cli/metrics.js.map +1 -1
- package/dist/cli/pluginPin.d.ts +55 -0
- package/dist/cli/pluginPin.js +188 -0
- package/dist/cli/pluginPin.js.map +1 -0
- package/dist/cli/ratify.d.ts +27 -2
- package/dist/cli/ratify.js +112 -13
- package/dist/cli/ratify.js.map +1 -1
- package/dist/cli/reratify.d.ts +11 -4
- package/dist/cli/reratify.js +89 -35
- package/dist/cli/reratify.js.map +1 -1
- package/dist/cli/scopeInputs.d.ts +48 -0
- package/dist/cli/scopeInputs.js +176 -0
- package/dist/cli/scopeInputs.js.map +1 -0
- package/dist/cli/skillCheck.d.ts +15 -1
- package/dist/cli/skillCheck.js +22 -1
- package/dist/cli/skillCheck.js.map +1 -1
- package/dist/cli/skillDirs.d.ts +5 -0
- package/dist/cli/skillDirs.js +13 -1
- package/dist/cli/skillDirs.js.map +1 -1
- package/dist/cli/skillSync.d.ts +4 -0
- package/dist/cli/skillSync.js +23 -0
- package/dist/cli/skillSync.js.map +1 -1
- package/dist/cli/sliceNew.d.ts +11 -7
- package/dist/cli/sliceNew.js +91 -18
- package/dist/cli/sliceNew.js.map +1 -1
- package/dist/cli/sliceSync.d.ts +50 -0
- package/dist/cli/sliceSync.js +170 -0
- package/dist/cli/sliceSync.js.map +1 -0
- package/dist/cli/status.d.ts +24 -1
- package/dist/cli/status.js +20 -1
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/systemInputs.d.ts +53 -10
- package/dist/cli/systemInputs.js +186 -11
- package/dist/cli/systemInputs.js.map +1 -1
- package/dist/cli/upgrade.d.ts +30 -7
- package/dist/cli/upgrade.js +434 -50
- package/dist/cli/upgrade.js.map +1 -1
- package/dist/cli/usageLog.d.ts +4 -2
- package/dist/cli/usageLog.js +4 -2
- package/dist/cli/usageLog.js.map +1 -1
- package/dist/cli.js +631 -100
- package/dist/cli.js.map +1 -1
- package/dist/emit/api.d.ts +29 -0
- package/dist/emit/api.js +220 -0
- package/dist/emit/api.js.map +1 -0
- package/dist/emit/apiCheckJson.d.ts +3 -0
- package/dist/emit/apiCheckJson.js +21 -0
- package/dist/emit/apiCheckJson.js.map +1 -0
- package/dist/emit/codeownersJson.d.ts +3 -0
- package/dist/emit/codeownersJson.js +19 -0
- package/dist/emit/codeownersJson.js.map +1 -0
- package/dist/emit/coverageJson.d.ts +5 -2
- package/dist/emit/coverageJson.js +6 -2
- package/dist/emit/coverageJson.js.map +1 -1
- package/dist/emit/diffJson.d.ts +1 -1
- package/dist/emit/diffJson.js +8 -1
- package/dist/emit/diffJson.js.map +1 -1
- package/dist/emit/engagementJson.d.ts +8 -0
- package/dist/emit/engagementJson.js +46 -0
- package/dist/emit/engagementJson.js.map +1 -0
- package/dist/emit/glossaryJson.d.ts +1 -1
- package/dist/emit/glossaryJson.js +4 -1
- package/dist/emit/glossaryJson.js.map +1 -1
- package/dist/emit/json.d.ts +17 -1
- package/dist/emit/json.js +30 -1
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/metricsJson.d.ts +1 -1
- package/dist/emit/metricsJson.js +4 -1
- package/dist/emit/metricsJson.js.map +1 -1
- package/dist/emit/queryJson.d.ts +1 -1
- package/dist/emit/queryJson.js +7 -1
- package/dist/emit/queryJson.js.map +1 -1
- package/dist/emit/scopeJson.d.ts +12 -0
- package/dist/emit/scopeJson.js +26 -0
- package/dist/emit/scopeJson.js.map +1 -0
- package/dist/emit/skillCheckJson.d.ts +3 -2
- package/dist/emit/skillCheckJson.js +10 -2
- package/dist/emit/skillCheckJson.js.map +1 -1
- package/dist/emit/statusJson.d.ts +1 -1
- package/dist/emit/statusJson.js +15 -1
- package/dist/emit/statusJson.js.map +1 -1
- package/dist/emit/systemJson.d.ts +15 -8
- package/dist/emit/systemJson.js +28 -13
- package/dist/emit/systemJson.js.map +1 -1
- package/dist/emit/upgradeJson.d.ts +1 -1
- package/dist/emit/upgradeJson.js +4 -1
- package/dist/emit/upgradeJson.js.map +1 -1
- package/dist/emit/validateJson.d.ts +3 -3
- package/dist/emit/validateJson.js +10 -4
- package/dist/emit/validateJson.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +186 -37
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/diff.d.ts +4 -1
- package/dist/model/diff.js +44 -8
- package/dist/model/diff.js.map +1 -1
- package/dist/model/glossary.d.ts +2 -0
- package/dist/model/glossary.js +1 -0
- package/dist/model/glossary.js.map +1 -1
- package/dist/model/model.d.ts +55 -2
- package/dist/model/model.js +57 -0
- package/dist/model/model.js.map +1 -1
- package/dist/model/qualifiedRef.d.ts +18 -0
- package/dist/model/qualifiedRef.js +26 -0
- package/dist/model/qualifiedRef.js.map +1 -1
- package/dist/model/queryIndex.d.ts +9 -1
- package/dist/model/queryIndex.js +18 -2
- package/dist/model/queryIndex.js.map +1 -1
- package/dist/model/rules.d.ts +143 -2
- package/dist/model/rules.js +162 -3
- package/dist/model/rules.js.map +1 -1
- package/dist/model/validate.d.ts +40 -0
- package/dist/model/validate.js +147 -1
- package/dist/model/validate.js.map +1 -1
- package/dist/parser/ast.d.ts +31 -3
- package/dist/parser/parser.js +148 -14
- package/dist/parser/parser.js.map +1 -1
- package/dist/query/format.js +1 -1
- package/dist/query/format.js.map +1 -1
- package/dist/query/verbs.d.ts +6 -0
- package/dist/query/verbs.js +6 -2
- package/dist/query/verbs.js.map +1 -1
- package/dist/system/adaptation.d.ts +14 -0
- package/dist/system/adaptation.js +49 -0
- package/dist/system/adaptation.js.map +1 -0
- package/dist/system/codeowners.d.ts +77 -0
- package/dist/system/codeowners.js +242 -0
- package/dist/system/codeowners.js.map +1 -0
- package/dist/system/manifest.d.ts +10 -5
- package/dist/system/manifest.js +54 -26
- package/dist/system/manifest.js.map +1 -1
- package/dist/system/migrateManifest.d.ts +28 -0
- package/dist/system/migrateManifest.js +155 -0
- package/dist/system/migrateManifest.js.map +1 -0
- package/dist/system/scope.d.ts +46 -0
- package/dist/system/scope.js +132 -0
- package/dist/system/scope.js.map +1 -0
- package/dist/system/verify.d.ts +50 -13
- package/dist/system/verify.js +179 -58
- package/dist/system/verify.js.map +1 -1
- package/dist/templates.d.ts +2 -2
- package/dist/templates.js +23 -2
- package/dist/templates.js.map +1 -1
- package/package.json +6 -3
- package/plugin/.claude-plugin/plugin.json +18 -0
- package/plugin/agents/em-critic.md +27 -0
- package/plugin/agents/em-implementer.md +35 -0
- package/plugin/agents/em-reviewer.md +32 -0
- package/plugin/agents/em-validator.md +28 -0
- package/plugin/shared/reference/em-dsl.md +866 -0
- package/plugin/shared/reference/methodology.md +329 -0
- package/plugin/shared/reference/operating-principles.md +222 -0
- package/plugin/shared/reference/slice-doc-schema.md +566 -0
- package/plugin/shared/templates/conformance-report.md +85 -0
- package/plugin/shared/templates/constitution.md +136 -0
- package/plugin/shared/templates/model-readme.md +46 -0
- package/plugin/shared/templates/slice.md +251 -0
- package/plugin/shared/templates/state.md +77 -0
- package/plugin/skills/conform/SKILL.md +93 -0
- package/plugin/skills/conform/reference/conform.md +428 -0
- package/plugin/skills/design/SKILL.md +297 -0
- package/plugin/skills/discover/SKILL.md +90 -0
- package/plugin/skills/discover/reference/extract.md +147 -0
- package/plugin/skills/engagement/SKILL.md +193 -0
- package/plugin/skills/engagement/reference/engagement.md +144 -0
- package/plugin/skills/event-modeling/SKILL.md +132 -0
- package/plugin/skills/implement/SKILL.md +61 -0
- package/plugin/skills/implement/reference/implement.md +439 -0
- package/plugin/skills/review/SKILL.md +74 -0
- package/dist/emit/typespec.d.ts +0 -26
- package/dist/emit/typespec.js +0 -356
- package/dist/emit/typespec.js.map +0 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<!-- GENERATED FILE from .claude/skills/event-modeling-shared/templates/conformance-report.md by scripts/build-plugin.ts — do not hand-edit; run npm run docs:generate -->
|
|
2
|
+
<!--
|
|
3
|
+
Conformance report skeleton. One per conform run, stored at
|
|
4
|
+
<model-name>/conformance/<YYYY-MM-DD>-report.md (see reference/conform.md).
|
|
5
|
+
Fill every section; leave "none" rather than deleting a section with nothing to report.
|
|
6
|
+
Replace bracketed placeholders; delete guidance comments before finishing.
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
# Conformance Report — {{Model Name}} — {{YYYY-MM-DD}}
|
|
10
|
+
|
|
11
|
+
- **Model:** `{{model-name}}.em`
|
|
12
|
+
- **Target repo:** {{repo path or URL}} @ `{{revision}}`
|
|
13
|
+
- **Previous conformance revision:** {{prior target-repo revision, or "never (first run)"}}
|
|
14
|
+
- **Scope:** {{full | diff-scoped since <prior revision>}}
|
|
15
|
+
- **Slices checked:** {{comma-separated slice names, or "all implemented slices"}}
|
|
16
|
+
- **Slices skipped (not yet implemented):** {{list, or "none"}}
|
|
17
|
+
|
|
18
|
+
## Summary
|
|
19
|
+
|
|
20
|
+
| Surface | Real drift | Model gap | Internal inconsistency | Accepted divergence | Unpropagated delta | Uncertainty |
|
|
21
|
+
|---|---|---|---|---|---|---|
|
|
22
|
+
| Structural | {{n}} | {{n}} | — | {{n}} | {{n}} | {{n}} |
|
|
23
|
+
| Spec | {{n}} | {{n}} | — | {{n}} | {{n}} | {{n}} |
|
|
24
|
+
| Internal | — | — | {{n}} | {{n}} | — | {{n}} |
|
|
25
|
+
|
|
26
|
+
**Unpropagated delta** — a slice re-ratified past its shipped version (`slice.doc.driftSignal:
|
|
27
|
+
"unpropagated-delta"` in `em export --json`): a known state, not a code defect. See
|
|
28
|
+
`reference/conform.md` step 4.
|
|
29
|
+
|
|
30
|
+
{{One or two sentences: overall read — clean, mostly clean with N items, or notably drifted.}}
|
|
31
|
+
|
|
32
|
+
## Findings
|
|
33
|
+
|
|
34
|
+
<!-- One subsection per finding. Group however reads clearest (by slice, or by surface) but keep
|
|
35
|
+
every field below for every finding. Order doesn't matter; classification does.
|
|
36
|
+
|
|
37
|
+
MIL-214: this section's structured twin is `conformance/{{YYYY-MM-DD}}-findings.json`,
|
|
38
|
+
written ALONGSIDE this report (not after it) — one JSON entry per `### n.` finding below,
|
|
39
|
+
`id` matching `{{n}}`. See reference/conform.md step 5 for the exact shape and the write-then-
|
|
40
|
+
`em conform-findings check`-it discipline. A later `em conform-supersede --locus --by` call
|
|
41
|
+
records the ruling on both the JSON (locus/resolvedBy/resolvedOn) and this report's banner
|
|
42
|
+
in one call. -->
|
|
43
|
+
|
|
44
|
+
### {{n}}. {{Short finding title}}
|
|
45
|
+
|
|
46
|
+
- **Surface:** {{structural | spec | internal}}
|
|
47
|
+
- **Classification:** {{real drift | model gap | internal inconsistency | accepted divergence | unpropagated delta}}
|
|
48
|
+
- **Slice:** {{slice name}}
|
|
49
|
+
- **Evidence:** {{file path(s) and line/symbol, or the `em diff --json` entry (type + name) —
|
|
50
|
+
for accepted divergence, the `divergence "..."` annotation text itself; for unpropagated
|
|
51
|
+
delta, `slice.doc.driftSignal` and `slice.doc.version` from `em export --json`}}
|
|
52
|
+
- **Claim:** {{what the model/doc says vs. what the code/doc shows — the actual disagreement}}
|
|
53
|
+
- **Proposed red note:** `issue "conformance: {{text}}"` on {{element}} (slice "{{slice}}")
|
|
54
|
+
<!-- Omit this line entirely for internal-inconsistency findings with no clear side to flag,
|
|
55
|
+
for any accepted-divergence or unpropagated-delta finding (already ratified, or already
|
|
56
|
+
a known pending-ship state — don't propose re-ratifying either), or when the finding
|
|
57
|
+
doesn't warrant a red note (say why instead). -->
|
|
58
|
+
|
|
59
|
+
## Scenario / invariant coverage
|
|
60
|
+
|
|
61
|
+
<!-- Per in-scope slice: every named invariant and every GWT scenario the doc claims, mapped to
|
|
62
|
+
its enforcement/test site. Leave a cell explicitly blank/"none found" rather than omitting
|
|
63
|
+
the row — gaps are the point of this table. -->
|
|
64
|
+
|
|
65
|
+
### {{Slice Name}}
|
|
66
|
+
|
|
67
|
+
| Claim | Type | Enforcement site | Test site | Status |
|
|
68
|
+
|---|---|---|---|---|
|
|
69
|
+
| {{INV-XXX-1 or scenario title}} | {{invariant \| scenario}} | {{file path / symbol, or "none found"}} | {{file path / symbol, or "none found"}} | {{covered \| gap \| uncertain}} |
|
|
70
|
+
|
|
71
|
+
## Uncertainties
|
|
72
|
+
|
|
73
|
+
<!-- Listed separately from Findings — these are NOT drift. No evidence either way; say what was
|
|
74
|
+
missing (time, clarity, an ambiguous test) so a follow-up run can pick it up. -->
|
|
75
|
+
|
|
76
|
+
- **{{structural | spec | internal}}** — {{what's uncertain}} — {{slice}} — {{why: e.g. "couldn't locate the test for INV-CHK-3, only its enforcement site"}}
|
|
77
|
+
|
|
78
|
+
<!-- Tag each with its surface so these reconcile against the Summary table's Uncertainty column. -->
|
|
79
|
+
|
|
80
|
+
## Applied this run
|
|
81
|
+
|
|
82
|
+
<!-- Filled in AFTER the user reviews Findings and says what to apply. Leave "none yet — awaiting
|
|
83
|
+
ratification" until that conversation happens. -->
|
|
84
|
+
|
|
85
|
+
{{List of ratified proposals actually applied to the `.em`/slice docs, or "none yet — awaiting ratification".}}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<!-- GENERATED FILE from .claude/skills/event-modeling-shared/templates/constitution.md by scripts/build-plugin.ts — do not hand-edit; run npm run docs:generate -->
|
|
2
|
+
<!--
|
|
3
|
+
The implementation constitution: the house rules an implementing agent follows on EVERY slice —
|
|
4
|
+
stack, code style, testing norms, NFR baselines, review norms. It answers "how do we build things
|
|
5
|
+
here" once, so no slice doc has to repeat it and no agent has to invent it. Slice docs say WHAT to
|
|
6
|
+
build; this says HOW it gets built here.
|
|
7
|
+
|
|
8
|
+
Where this document lives:
|
|
9
|
+
- No SDD tool: `constitution.md` beside the model — `em scaffold` writes it there.
|
|
10
|
+
- spec-kit project (a `.specify/` directory exists anywhere above the model): the document IS
|
|
11
|
+
`.specify/memory/constitution.md`. em writes no second copy; the sections below merge into
|
|
12
|
+
that file under these same headings, never overwriting text already there, and ratification is
|
|
13
|
+
recorded in spec-kit's own `**Ratified**:` footer line instead of the frontmatter below.
|
|
14
|
+
|
|
15
|
+
How it gets filled: not by an agent guessing. Each section opens with the question a short
|
|
16
|
+
facilitated conversation asks before the first slice is implemented — the procedure is "Before the
|
|
17
|
+
first slice: the constitution" in the `em:implement` skill's `reference/implement.md`
|
|
18
|
+
(`em contract` prints it). Replace each `{{...}}` block with the real answers; delete the guidance
|
|
19
|
+
comments and any row that doesn't apply.
|
|
20
|
+
|
|
21
|
+
Ratification: `ratifiedBy:`/`ratifiedOn:` are the same identity discipline slice docs use — a
|
|
22
|
+
NAMED human and an ISO date, hand-filled at sign-off (no `em` command writes this file).
|
|
23
|
+
**A constitution with an empty `ratifiedBy:` is a draft**: an implementing agent treats it as
|
|
24
|
+
unratified, says so, and does not proceed on unilateral style or stack decisions for a first slice.
|
|
25
|
+
|
|
26
|
+
`em status` reports this document as present or absent per model — existence only. em never reads
|
|
27
|
+
or validates its content, and the CLI parses nothing here. Three lines are read as plain text by
|
|
28
|
+
the engagement skill and its sub-agents, so keep their exact shape: `- **Test command:**` (the
|
|
29
|
+
validator), `- **Merge strategy:**` and `- **Agent models:**` (the engagement skill). In a spec-kit
|
|
30
|
+
project they merge under the same headings in `.specify/memory/constitution.md`.
|
|
31
|
+
-->
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
schemaVersion: 1
|
|
35
|
+
ratifiedBy:
|
|
36
|
+
ratifiedOn:
|
|
37
|
+
---
|
|
38
|
+
# {{Project Name}} — implementation constitution
|
|
39
|
+
|
|
40
|
+
The house rules for how implementation happens in this project. They bound every "purely
|
|
41
|
+
technical choice" an implementing agent would otherwise make alone.
|
|
42
|
+
|
|
43
|
+
## Stack and architectural shape
|
|
44
|
+
|
|
45
|
+
> **What do we build on, what shape does the code take, and which implementation skill or
|
|
46
|
+
> approach does each slice pattern route to?**
|
|
47
|
+
|
|
48
|
+
- **Languages / runtimes:** {{e.g. Kotlin 2.x on JVM 21; TypeScript 5 on Node 24}}
|
|
49
|
+
- **Frameworks / platform:** {{web framework, persistence, messaging, build tool}}
|
|
50
|
+
- **Architectural pattern:** {{e.g. event-sourced CQRS with vertical slices; layered service over
|
|
51
|
+
a relational store; functional core / imperative shell}}
|
|
52
|
+
- **Where a slice's code lives:** {{one package per slice, per context, ...}}
|
|
53
|
+
- **Interface conventions:** {{resource style — REST/RPC/GraphQL, etc.; error/rejection mapping;
|
|
54
|
+
versioning; auth at the edge — the shape every `ui`-triggered command or `ui`-consumed view's
|
|
55
|
+
endpoint follows, decided once here rather than invented per slice}}
|
|
56
|
+
|
|
57
|
+
Routing — which implementation skill or approach each of the four slice patterns uses:
|
|
58
|
+
|
|
59
|
+
| Pattern | Skill / approach |
|
|
60
|
+
|---|---|
|
|
61
|
+
| State Change | {{e.g. the `axon-*` skill set — axon-entity-patterns, then axon-entity-testing}} |
|
|
62
|
+
| State View | {{e.g. the `axon-*` skill set — axon-projection-patterns, then axon-projection-testing}} |
|
|
63
|
+
| Automation | {{e.g. the `axon-*` skill set — axon-policy-patterns, then axon-policy-testing}} |
|
|
64
|
+
| Translation | {{e.g. the `axon-*` skill set — axon-translation-patterns}} |
|
|
65
|
+
|
|
66
|
+
An agent implementing a slice reads the doc's `pattern:` frontmatter and follows that row — this
|
|
67
|
+
table is the only routing rule.
|
|
68
|
+
|
|
69
|
+
## Code style
|
|
70
|
+
|
|
71
|
+
> **What does "idiomatic" mean in this codebase — formatting, naming, module layout?**
|
|
72
|
+
|
|
73
|
+
- **Formatter / linter:** {{the tool and the command that runs it — never hand-format against it}}
|
|
74
|
+
- **Naming:** {{commands, events, handlers, files, test names}}
|
|
75
|
+
- **Module layout:** {{what lives in which file/package, and what may not import what}}
|
|
76
|
+
- **Idiomatic here means:** {{the two or three habits a new contributor most often gets wrong}}
|
|
77
|
+
|
|
78
|
+
## Testing norms
|
|
79
|
+
|
|
80
|
+
> **What must be tested for each slice pattern, where do those tests live, and how are they named
|
|
81
|
+
> so `em coverage` can trace invariant IDs?**
|
|
82
|
+
|
|
83
|
+
- **Levels required per pattern:** {{e.g. State Change — decider unit tests plus a
|
|
84
|
+
given/when/then fixture test; State View — projection tests; Automation / Translation —
|
|
85
|
+
reaction tests, including a negative case}}
|
|
86
|
+
- **Invariant tests:** {{where they live}} — every `INV-<MNEMONIC>-n` in a slice doc needs at least
|
|
87
|
+
one test **citing that exact ID** in its name or a comment, so
|
|
88
|
+
`em coverage <model>.em --tests <dir>` can trace it.
|
|
89
|
+
- **Scenario tests:** {{where they live}} — one per `## Scenarios (Given / When / Then)` entry,
|
|
90
|
+
with rejection scenarios asserting the doc's named rejection reason.
|
|
91
|
+
- **Test naming convention:** {{the exact pattern, e.g. `INV-ORD-3: rejects a second submit`}}
|
|
92
|
+
- **What "green" means:** {{the command CI runs}}
|
|
93
|
+
- **Test command:** `{{the one command that runs the tests, e.g. ./gradlew test}}`
|
|
94
|
+
What the `em-validator` sub-agent runs. Keep exactly this shape: one line, the command in
|
|
95
|
+
backticks. Absent, the validator reports "no test command in the constitution" and runs only the
|
|
96
|
+
em checks.
|
|
97
|
+
|
|
98
|
+
## NFR baselines
|
|
99
|
+
|
|
100
|
+
> **What standing non-functional defaults does every slice inherit — authz, PII, performance,
|
|
101
|
+
> observability?**
|
|
102
|
+
|
|
103
|
+
- **Authorization model:** {{who may issue which commands, how it's enforced, and where}}
|
|
104
|
+
- **PII / data handling:** {{what is sensitive, what may be logged, retention}}
|
|
105
|
+
- **Performance defaults:** {{latency / throughput budgets that apply unless a slice says otherwise}}
|
|
106
|
+
- **Observability:** {{logging, metrics, tracing every slice is expected to emit}}
|
|
107
|
+
|
|
108
|
+
A slice doc's own `## Non-Functional Requirements` section overrides these for that slice; where
|
|
109
|
+
it is silent, these apply.
|
|
110
|
+
|
|
111
|
+
## Review and merge norms
|
|
112
|
+
|
|
113
|
+
> **Who reviews an implementation PR, what blocks a merge, and how does the slice doc's status
|
|
114
|
+
> flip fit in?**
|
|
115
|
+
|
|
116
|
+
- **Reviewers:** {{who — a team, a CODEOWNERS rule, the slice's ratifier}}
|
|
117
|
+
- **What blocks a merge:** {{e.g. a failing suite, an uncovered invariant, a gap that belongs back
|
|
118
|
+
at the model}}
|
|
119
|
+
- **Branch / commit conventions:** {{...}} — name only branch naming and commit-message style
|
|
120
|
+
here. **One slice doc = one PR is the implement contract's rule, not this document's to
|
|
121
|
+
amend** — a `covers:` doc ships as one PR for both keys; a read model is one doc, so a later
|
|
122
|
+
`again` instance is a continuation of the doc that first declared it, not a PR of its own. See
|
|
123
|
+
the agent guide's §5/§10.
|
|
124
|
+
- **Merge strategy:** merge-commits-when-stacked
|
|
125
|
+
{{**How do PRs merge, and what happens when one PR depends on another?** Merge commits whenever
|
|
126
|
+
a dependent PR is open; squash only a PR with no open dependent (implement contract §8 rule 2a).
|
|
127
|
+
Keep this exact line: it is the only value the engagement skill accepts, and it refuses to run
|
|
128
|
+
without it.}}
|
|
129
|
+
- **Agent models:** implementer=sonnet, validator=sonnet, reviewer=sonnet, critic=opus
|
|
130
|
+
{{**Which model runs each em sub-agent?** Keep this exact line shape, with the defaults shown or
|
|
131
|
+
your own choices. The critic must run on a different model from the implementer; `critic=codex`
|
|
132
|
+
selects the Codex critic. Absent, the engagement skill states these defaults once and
|
|
133
|
+
proceeds.}}
|
|
134
|
+
- **At merge:** run `em slice mark-implemented <model>.em <slice-key> <pr-url>` — the one edit an
|
|
135
|
+
implementing agent makes to a ratified slice doc, run by {{the PR author | CI}}. Never bump
|
|
136
|
+
`version:`; that moves only when a delta is ratified.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!-- GENERATED FILE from .claude/skills/event-modeling-shared/templates/model-readme.md by scripts/build-plugin.ts — do not hand-edit; run npm run docs:generate -->
|
|
2
|
+
# {{Model Name}}
|
|
3
|
+
|
|
4
|
+
{{One-paragraph description of the business process(es) this event model covers.}}
|
|
5
|
+
|
|
6
|
+
## Live view
|
|
7
|
+
While modeling, run the live view so the team can watch the diagram update:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
em watch {{model-name}}.em -o {{model-name}}.svg --serve # re-render + instant push-reload
|
|
11
|
+
# then open the URL it prints (http://localhost:5173/?svg={{model-name}}.svg) and share the screen
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Pan/zoom to navigate the diagram (drag, scroll; **Fit** resets), and click **Review mode** in
|
|
15
|
+
the header for a slice-by-slice walkthrough. If a save fails to render, the viewer keeps the
|
|
16
|
+
last good diagram and shows an error banner until the next successful load.
|
|
17
|
+
|
|
18
|
+
Static render: `em render {{model-name}}.em -o {{model-name}}.svg`
|
|
19
|
+
|
|
20
|
+
## Patterns legend
|
|
21
|
+
- **State Change** — UI → Command → Event
|
|
22
|
+
- **State View** — Event(s) → Read Model → UI
|
|
23
|
+
- **Automation** — Read Model (slice before) → Processor + Command → Event, together
|
|
24
|
+
- **Translation** — External input (or Read Model, slice before) → Translation + Command → Event, together
|
|
25
|
+
|
|
26
|
+
Between them these are the only legal connections: `ui → command`, `command → event`,
|
|
27
|
+
`event → read model`, `read model → ui`, `read model → reaction`, `reaction → command`. A command
|
|
28
|
+
never reaches a read model directly — the event goes between them. Every slice is joined up at
|
|
29
|
+
both ends: something triggers each command (the screen it's issued from, or the reaction that
|
|
30
|
+
triggers it, also in this slice), and every event a command records is read by some read model — so each State
|
|
31
|
+
Change slice is paired with the State View slice that projects its event. A read model repeated
|
|
32
|
+
along the timeline (`view X again`) shows the same projection at a later point; the instances are
|
|
33
|
+
never connected to one another.
|
|
34
|
+
|
|
35
|
+
## Slices
|
|
36
|
+
<!-- The canonical slice index — the ONE place slices are enumerated (the state file
|
|
37
|
+
points here rather than keeping its own copy). Generated — run
|
|
38
|
+
`em slice index {{model-name}}.em` to (re)write the table below from the model and its
|
|
39
|
+
slice docs; never hand-edit between the markers. -->
|
|
40
|
+
<!-- GENERATED:slices:start -->
|
|
41
|
+
| # | Slice | Pattern | Status | Reviewed by | Ratified by | Owner | Tracking | Implemented in | Design doc |
|
|
42
|
+
|---|-------|---------|--------|-------------|-------------|-------|----------|----------------|------------|
|
|
43
|
+
<!-- GENERATED:slices:end -->
|
|
44
|
+
|
|
45
|
+
## Status
|
|
46
|
+
See [`.event-modeling.md`](.event-modeling.md) for current phase, decisions, and open questions.
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
<!-- GENERATED FILE from .claude/skills/event-modeling-shared/templates/slice.md by scripts/build-plugin.ts — do not hand-edit; run npm run docs:generate -->
|
|
2
|
+
<!--
|
|
3
|
+
Rich slice design document. One per slice, stored in <model>/slices/<slice-name>.md and
|
|
4
|
+
linked from the .em model with: note "slices/<slice-name>.md" on the slice's defining element.
|
|
5
|
+
Fill every section through Socratic questioning. Leave "Open Questions" rather than guessing.
|
|
6
|
+
Replace the bracketed placeholders; delete guidance comments before finishing.
|
|
7
|
+
|
|
8
|
+
The frontmatter below is the canonical, machine-read metadata dialect — `em`'s own parser
|
|
9
|
+
(src/catalog/sliceDoc.ts) reads `status:`, `version:`, `pattern:`, and the lineage keys
|
|
10
|
+
(`split-from:`/`merged-from:`/`superseded-by:`) from it. `pattern` is kebab-case
|
|
11
|
+
(state-change/state-view/automation/translation) even though the skill's prose always says
|
|
12
|
+
"State Change"/"State View"/etc. — the frontmatter value is a machine key, not a display label.
|
|
13
|
+
Older docs using a `- **Status:** ...` bullet line instead of frontmatter still parse (legacy/
|
|
14
|
+
accepted input), but new docs should always use this frontmatter form; `version` and lineage
|
|
15
|
+
have no legacy form — frontmatter-only from day one.
|
|
16
|
+
|
|
17
|
+
`version` is this slice's own ratified-content version — starts at `1`, bumps when a delta is
|
|
18
|
+
ratified — distinct from `schemaVersion`, which versions the frontmatter dialect itself, not
|
|
19
|
+
this slice. When a ratified change lands on an already-`implemented` slice: bump `version`,
|
|
20
|
+
flip `status` back to `ready-to-implement` (it tracks the CURRENT version's implementation
|
|
21
|
+
state — `implementedIn` legitimately keeps naming the PRIOR version's PR until the new version
|
|
22
|
+
ships; that mismatch is an intended drift signal, not a bug), and fill in the `## Delta` section
|
|
23
|
+
below with this hop's change, replacing whatever it held before (it always shows only the latest
|
|
24
|
+
hop — full history lives in git, same-commit-ratification convention). Full grammar — the fixed
|
|
25
|
+
heading, the four operation subsections, why the heading never varies, the replace-not-accumulate
|
|
26
|
+
lifecycle — is documented in ../reference/slice-doc-schema.md#delta-section-grammar-and-lifecycle; treat
|
|
27
|
+
it the same Socratic way as every other section here, don't generate it mechanically.
|
|
28
|
+
|
|
29
|
+
The three lineage keys only apply when this doc was produced by a split, merge, or rename —
|
|
30
|
+
delete them otherwise; most slices never carry them. Grammar: `<slice-key>@v<N>`, where
|
|
31
|
+
`<slice-key>` is the referenced slice's kebab-case filename stem.
|
|
32
|
+
|
|
33
|
+
`covers` only applies when this doc is also the ratified doc for a DIFFERENT slice — typically
|
|
34
|
+
the bare `view` half of the two-slice Automation/Translation shape, which has nothing of its own
|
|
35
|
+
to write up. Delete it otherwise; most docs never carry it. Requires a matching
|
|
36
|
+
`note "slices/{{this-slice-name}}.md"` on an element in the OTHER slice — this key alone doesn't
|
|
37
|
+
bind anything. Plain slice keys, comma-separated — not the `<slice-key>@v<N>` ref grammar above.
|
|
38
|
+
|
|
39
|
+
`ratifiedBy`/`ratifiedOn` record who ratified this doc's current `status`/`version`, and when —
|
|
40
|
+
don't hand-fill these; run `em slice ratify <model> <key> --by <name>` at the
|
|
41
|
+
handoff gate instead (docs/process.md#what-ratified-means), which flips `status` to
|
|
42
|
+
`ready-to-implement` and writes both in one edit.
|
|
43
|
+
public-touching slice: add --meaning-unchanged, or --contract-change "<why>"; run em api generate first.
|
|
44
|
+
|
|
45
|
+
`owner`/`tracking` are optional and, unlike `ratifiedBy`/`ratifiedOn`, hand-filled — no `em`
|
|
46
|
+
command writes either. `owner` is free text naming who (a person or team) holds this slice;
|
|
47
|
+
`tracking` is a URL into an external tracker (Jira, Linear, ...) mirroring it — the exact field
|
|
48
|
+
`em-tracker-bridge` reads to find the mirrored ticket. `em` only stores and displays both; it
|
|
49
|
+
never talks to a tracker itself. Delete both otherwise; most docs never carry them.
|
|
50
|
+
|
|
51
|
+
Full machine schema — required-vs-optional keys per `status`, value types/enums, the
|
|
52
|
+
unknown-key policy — is documented in ../reference/slice-doc-schema.md.
|
|
53
|
+
|
|
54
|
+
The diagram below is generated, not hand-drawn: `em render <model>.em --slice "{{Slice Name}}"
|
|
55
|
+
-o slices/{{slice-name}}.svg` (kebab-case the slice name to match this doc's own filename).
|
|
56
|
+
-->
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
schemaVersion: 1
|
|
60
|
+
pattern: {{state-change | state-view | automation | translation}}
|
|
61
|
+
swimlane: {{Persona/Actor}} → {{Context/Aggregate}}
|
|
62
|
+
status: {{draft | reviewed | ready-to-implement | implemented}}
|
|
63
|
+
version: 1
|
|
64
|
+
implementedIn: {{PR/commit link — fill in once status is `implemented`}}
|
|
65
|
+
# Lineage — only when this doc exists because of a split, merge, or rename (delete these three
|
|
66
|
+
# lines otherwise). Grammar: <slice-key>@v<N>. See
|
|
67
|
+
# ../reference/slice-doc-schema.md#lineage-grammar-and-cardinality.
|
|
68
|
+
# split-from: <slice-key>@v<N>
|
|
69
|
+
# merged-from: <slice-key>@v<N>, <slice-key>@v<N>
|
|
70
|
+
# superseded-by: <slice-key>@v<N>, <slice-key>@v<N>
|
|
71
|
+
# Cross-slice coverage — only when this doc also covers another slice with no doc of its own
|
|
72
|
+
# (e.g. the view-only half of a two-slice Automation/Translation, MIL-121); delete otherwise.
|
|
73
|
+
# Plain slice keys, comma-separated. See ../reference/slice-doc-schema.md#cross-slice-coverage-covers.
|
|
74
|
+
# covers: <slice-key>, <slice-key>
|
|
75
|
+
# Ownership / tracking — optional, hand-filled (no `em` command writes either); delete otherwise.
|
|
76
|
+
# owner: <person or team>
|
|
77
|
+
# tracking: <ticket URL>
|
|
78
|
+
---
|
|
79
|
+
# Slice: {{Slice Name}}
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
|
|
83
|
+
<!-- Only on re-ratification of an already-`implemented` slice — omit this whole section on a
|
|
84
|
+
slice's first version (v1 has no delta yet). The heading is always the literal `## Delta`,
|
|
85
|
+
never `## Delta: vX → vY` — hop metadata is a display line inside the section instead (see
|
|
86
|
+
../reference/slice-doc-schema.md#delta-section-grammar-and-lifecycle for why). Replace this
|
|
87
|
+
section's content wholesale on the next re-ratification — it shows only the latest hop, not
|
|
88
|
+
an accumulating log. Omit any of the four subsections below with no entries this hop; keep
|
|
89
|
+
the remaining ones in this order (Added/Modified/Removed/Renamed). `Renamed` is for a
|
|
90
|
+
requirement/invariant renamed within this slice, not a substitute for the frontmatter
|
|
91
|
+
`split-from`/`merged-from`/`superseded-by` lineage keys above, which record the slice-doc
|
|
92
|
+
itself splitting, merging, or being renamed. -->
|
|
93
|
+
## Delta
|
|
94
|
+
**v{{X}} → v{{Y}}, ratified {{date}}** — {{one-line summary of the ratified change}}
|
|
95
|
+
|
|
96
|
+
### Added
|
|
97
|
+
#### Requirement: {{title}} ({{stable ID, e.g. an INV-{{MNEMONIC}}-n from Invariants below}})
|
|
98
|
+
{{requirement text — same voice as an Invariants entry}}
|
|
99
|
+
##### Scenario: {{name}}
|
|
100
|
+
- **Given:** {{...}}
|
|
101
|
+
- **When:** {{...}}
|
|
102
|
+
- **Then:** {{...}}
|
|
103
|
+
|
|
104
|
+
### Modified
|
|
105
|
+
<!-- Same shape as Added — the stable ID names the requirement that changed. -->
|
|
106
|
+
|
|
107
|
+
### Removed
|
|
108
|
+
#### Requirement: {{title}} ({{stable ID}})
|
|
109
|
+
{{why it was removed}}
|
|
110
|
+
|
|
111
|
+
### Renamed
|
|
112
|
+
- {{old title}} ({{old ID}}) → {{new title}} ({{new ID}})
|
|
113
|
+
|
|
114
|
+
## Intent
|
|
115
|
+
{{Why this slice exists — the user or business goal it serves, in one or two sentences. Note the
|
|
116
|
+
originating ticket/conversation link here if one exists.}}
|
|
117
|
+
|
|
118
|
+
## Trigger & Actor
|
|
119
|
+
{{Who or what initiates this slice and under what circumstances. For automations, the watched
|
|
120
|
+
read model and the triggering condition. For translations, state the trigger form: externally
|
|
121
|
+
triggered (the external system/source feeding us) or internally triggered (the read model whose
|
|
122
|
+
state we react to). Either way, name the command this reaction triggers — reactions never record
|
|
123
|
+
an event directly.}}
|
|
124
|
+
|
|
125
|
+
## Command / Input
|
|
126
|
+
<!-- GENERATED region (MIL-266): the table between the markers is written from the model —
|
|
127
|
+
`em slice new` fills it, `em slice sync <model>.em` refreshes it after any model edit. Never
|
|
128
|
+
hand-edit inside the markers: change the `.em` and re-run `em slice sync`. Required = `no`
|
|
129
|
+
for a field written `name?: Type`. A slice with several commands gets one region per command
|
|
130
|
+
(`em-slice-command-<command-slug>`); a pure State View slice's region says it has none. -->
|
|
131
|
+
<!-- GENERATED:em-slice-command:start — generated from the model by `em slice sync`; do not hand-edit -->
|
|
132
|
+
**Command:** `{{Command Name}}`
|
|
133
|
+
|
|
134
|
+
| Field | Type | Required | Rules / Validation |
|
|
135
|
+
|-------|------|----------|--------------------|
|
|
136
|
+
| {{field}} | {{Type}} | {{yes/no}} | {{constraints, formats, ranges}} |
|
|
137
|
+
<!-- GENERATED:em-slice-command:end -->
|
|
138
|
+
|
|
139
|
+
## Trigger
|
|
140
|
+
<!-- What issues this slice's command. Required: a command nothing points at is a write nobody
|
|
141
|
+
can start. Either the screen the user acts on (a `ui` in this slice), or the reaction that
|
|
142
|
+
issues it (an automation/processor/translation, also in this slice). -->
|
|
143
|
+
**Triggered by:** {{screen `X` @Persona | processor `Y`, also in this slice}}
|
|
144
|
+
|
|
145
|
+
## Event(s) Emitted
|
|
146
|
+
<!-- The immutable facts recorded. The marker line and payload table are a GENERATED region (one
|
|
147
|
+
per event; `em-slice-event-<event-slug>` when the slice records several): Source / Notes
|
|
148
|
+
names the command field a value is copied from, `assigned` for a system-assigned field, or
|
|
149
|
+
`{{ }}` where the model cannot tell. `**Read by:**` below the region is authored. -->
|
|
150
|
+
<!-- GENERATED:em-slice-event:start — generated from the model by `em slice sync`; do not hand-edit -->
|
|
151
|
+
**Event:** `{{Event Name}}` → context `{{Context}}`
|
|
152
|
+
|
|
153
|
+
| Field | Type | Immutable Fact? | Source / Notes |
|
|
154
|
+
|-------|------|-----------------|----------------|
|
|
155
|
+
| {{field}} | {{Type}} | {{yes/no}} | {{where the value comes from}} |
|
|
156
|
+
<!-- GENERATED:em-slice-event:end -->
|
|
157
|
+
**Read by:** {{which read model projects this event, and in which slice}}
|
|
158
|
+
<!-- Required, not optional. Every event must be read by a read model — an event nothing
|
|
159
|
+
projects is a write nobody can see, and `em validate` warns on it. A reaction consuming
|
|
160
|
+
it does NOT count: reactions read views, not events. If the honest answer is "nothing
|
|
161
|
+
reads it", that's a question for the business, not a field to leave blank. -->
|
|
162
|
+
|
|
163
|
+
## Read Model / View
|
|
164
|
+
<!-- For State View slices, and any read model this slice produces or feeds. The `- **View:**`
|
|
165
|
+
line and field table are a GENERATED region (one per read model; `em-slice-view-<view-slug>`
|
|
166
|
+
when there are several): Source / Notes names the source event a field is copied from, or
|
|
167
|
+
`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. -->
|
|
169
|
+
<!-- GENERATED:em-slice-view:start — generated from the model by `em slice sync`; do not hand-edit -->
|
|
170
|
+
- **View:** `{{View Name}}` built from events: {{"Event A", "Event B"}}
|
|
171
|
+
|
|
172
|
+
| Field | Type | Source / Notes |
|
|
173
|
+
|-------|------|----------------|
|
|
174
|
+
| {{field}} | {{Type}} | {{which event field it's copied from, or `Derived: <rule>`}} |
|
|
175
|
+
<!-- GENERATED:em-slice-view:end -->
|
|
176
|
+
- **Consumed by:** {{which UI screen (or API-caller persona), or reaction}}
|
|
177
|
+
<!-- "Consumed by" is required, not optional. A read model nothing displays or watches is
|
|
178
|
+
information projected out of the system and then dropped, and `em validate` warns. Every
|
|
179
|
+
instance of a repeated view needs its own consumer, not just the last one. -->
|
|
180
|
+
- **Freshness / consistency expectation:** {{real-time | eventual | on-demand}}
|
|
181
|
+
|
|
182
|
+
## Invariants / Business Rules
|
|
183
|
+
<!-- IDs and rule sentences are declared in the MODEL (MIL-265): an `invariant INV-<MNEMONIC>-<n>
|
|
184
|
+
"rule"` line after the command or event it guards (docs/dsl.md#invariants). The list between
|
|
185
|
+
the markers is GENERATED from those lines (`em slice sync`); never edit it. Below it, cite
|
|
186
|
+
each ID as a plain mention and elaborate — `- INV-CHK-1 — why it holds, edge cases, the error
|
|
187
|
+
a violation returns` — never re-declare it with the `**INV-CHK-1:**` label
|
|
188
|
+
(`invariants/declared-in-both`). A rule not (yet) in the model may still be declared below
|
|
189
|
+
with that label; em reads it as the fallback. -->
|
|
190
|
+
<!-- What must ALWAYS hold. Give each a stable ID so tests and code can reference it:
|
|
191
|
+
`INV-<MNEMONIC>-<n>`, where `<MNEMONIC>` is a short (2-4 letter/digit), slice-unique
|
|
192
|
+
abbreviation of this slice's key (e.g. slice `checkout` -> `INV-CHK-1`) — see
|
|
193
|
+
../reference/slice-doc-schema.md. Keep the rule statement itself to one line. If it needs
|
|
194
|
+
more — why the rule exists, what "violation" looks like in practice, an edge case worth
|
|
195
|
+
calling out — add that as a nested bullet under the elaboration line instead of one long
|
|
196
|
+
run-on sentence: this section renders as HTML (`em catalog`/`em render`/`em watch`), and a
|
|
197
|
+
nested bullet stays visually distinct where a wrapped sentence collapses into a wall of
|
|
198
|
+
text. The ID must stay on the top-level bullet line — `em coverage` extracts INV IDs from
|
|
199
|
+
that line only, never from a nested elaboration bullet underneath it. -->
|
|
200
|
+
<!-- GENERATED:em-slice-invariants:start — generated from the model by `em slice sync`; do not hand-edit -->
|
|
201
|
+
- **INV-{{MNEMONIC}}-1** — {{rule, as declared by `invariant INV-{{MNEMONIC}}-1 "rule"` in the model}}
|
|
202
|
+
<!-- GENERATED:em-slice-invariants:end -->
|
|
203
|
+
<!-- elaborate below this list; IDs are declared in the model -->
|
|
204
|
+
- INV-{{MNEMONIC}}-1 — {{elaboration of the model-declared rule: why it holds, what a violation looks like, the error returned}}
|
|
205
|
+
- {{optional: edge-case detail — its own bullet}}
|
|
206
|
+
- **INV-{{MNEMONIC}}-2:** {{a rule not yet in the model, declared here as the fallback — move it into the model when you can}}
|
|
207
|
+
|
|
208
|
+
## Scenarios (Given / When / Then)
|
|
209
|
+
<!-- The executable specification — authored, in a constrained shape `em` reads back (`em export
|
|
210
|
+
--json` → slice.doc.scenarios). Cover the happy path AND the key rule boundaries, one block
|
|
211
|
+
per case: a `### Scenario: <title>` heading, then exactly the three column-0 bullets
|
|
212
|
+
`- **Given:**`, `- **When:**`, `- **Then:**`, each with its beats as nested ` - ` bullets.
|
|
213
|
+
A block missing any of the three is flagged `slice-doc/structured-section-malformed`. -->
|
|
214
|
+
### Scenario: Happy path
|
|
215
|
+
- **Given:**
|
|
216
|
+
- {{starting state / prior events}}
|
|
217
|
+
- **When:**
|
|
218
|
+
- {{command/trigger}}
|
|
219
|
+
- **Then:**
|
|
220
|
+
- {{event(s) recorded}}
|
|
221
|
+
- {{resulting read-model change}}
|
|
222
|
+
|
|
223
|
+
## Alternate & Error Flows
|
|
224
|
+
<!-- Failure paths, retries, compensations, timeouts, idempotency. -->
|
|
225
|
+
- {{e.g. external call fails → retry policy / compensating event}}
|
|
226
|
+
- {{idempotency: what happens if the command/event arrives twice?}}
|
|
227
|
+
|
|
228
|
+
## Non-Functional Requirements
|
|
229
|
+
<!-- Short checklist. Idempotency is covered above under Alternate & Error Flows — not repeated
|
|
230
|
+
here. -->
|
|
231
|
+
- **Security / authz:** {{who may invoke this; role/permission checks — or "none"}}
|
|
232
|
+
- **PII & compliance:** {{personal data touched, retention/consent constraints — or "none"}}
|
|
233
|
+
- **Performance / SLA:** {{latency/throughput expectation — or "none"}}
|
|
234
|
+
|
|
235
|
+
## Dependencies & Read Models Affected
|
|
236
|
+
- **Upstream events this slice relies on:** {{...}}
|
|
237
|
+
- **Downstream read models / slices affected:** {{...}}
|
|
238
|
+
|
|
239
|
+
## Open Questions
|
|
240
|
+
<!-- Park unresolved items here instead of guessing. Mirror them into .event-modeling.md.
|
|
241
|
+
|
|
242
|
+
Lifecycle across versions: while THIS version is still being worked, a resolved item
|
|
243
|
+
(`- [x]`) can stay checked here as a visible record of what's already been decided this
|
|
244
|
+
round. On the same commit that ratifies the NEXT version (bumps `version`, rewrites
|
|
245
|
+
`## Delta` above) — prune every already-checked item from this list; keep only what's still
|
|
246
|
+
open, plus anything new the delta itself surfaced. Same "replace, never accumulate" stance
|
|
247
|
+
as `## Delta`, for the same reason: an ever-growing scroll of resolved questions goes stale
|
|
248
|
+
exactly like an accumulating Delta log would, and full history already lives in git
|
|
249
|
+
(`git log -p slices/<name>.md`) — this section is a live worklist, not an audit trail. See
|
|
250
|
+
../reference/slice-doc-schema.md#open-questions-section-lifecycle. -->
|
|
251
|
+
- [ ] {{question}}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<!-- GENERATED FILE from .claude/skills/event-modeling-shared/templates/state.md by scripts/build-plugin.ts — do not hand-edit; run npm run docs:generate -->
|
|
2
|
+
<!--
|
|
3
|
+
Resumable progress state for an event model. Stored as <model>/.event-modeling.md
|
|
4
|
+
The skill reads this on `/em:event-modeling` (no arg) to resume where you left off.
|
|
5
|
+
Keep it current at the end of every working session.
|
|
6
|
+
-->
|
|
7
|
+
|
|
8
|
+
# Event Modeling Progress — {{Model Name}}
|
|
9
|
+
|
|
10
|
+
- **Model file:** `{{model-name}}.em`
|
|
11
|
+
- **Em version:** {{X.Y.Z}}
|
|
12
|
+
- **Current phase:** {{discover | extract | model | slice | implement | conform | review | validate}}
|
|
13
|
+
- **Current step:** {{1–7, see methodology; or extraction round R1–R7}}
|
|
14
|
+
- **Last updated:** {{YYYY-MM-DD}}
|
|
15
|
+
- **Last conformance:** {{YYYY-MM-DD @ <target-repo revision> — report: conformance/<date>-report.md | never}}
|
|
16
|
+
- **Model version:** {{N | none}}
|
|
17
|
+
- **Certified:** {{v<N> @ <target-repo revision> (YYYY-MM-DD) | never}}
|
|
18
|
+
- **Last stakeholder review:** {{YYYY-MM-DD — attendees: see Participants | never}}
|
|
19
|
+
|
|
20
|
+
## Session inputs
|
|
21
|
+
- **Scope line:** {{one-line description of what's in/out of bounds for this model}}
|
|
22
|
+
- **PRD / spec reference:** {{path, link, or "none"}}
|
|
23
|
+
- **Headless/API model:** {{yes | no}}
|
|
24
|
+
- **Source mode:** {{greenfield | extract-event-driven | extract-procedural}}
|
|
25
|
+
- **Existing system refs:** {{repo paths, event-schema/topic locations, docs — or "n/a"}}
|
|
26
|
+
|
|
27
|
+
## Participants
|
|
28
|
+
<!-- Populate at session start. Live workshop: one human proxy relays questions to the room;
|
|
29
|
+
attribute every answer/decision in the Decisions log to a named participant here. -->
|
|
30
|
+
- {{Name}} — {{role}} — {{domain area}}
|
|
31
|
+
|
|
32
|
+
## Extraction progress (existing-system models only — delete for greenfield)
|
|
33
|
+
- [ ] R1. Candidate events (extracted/synthesized, filtered, confirmed)
|
|
34
|
+
- [ ] R2. Timeline order (as-is narrative, actors/callers, first render)
|
|
35
|
+
- [ ] R3. Commands / inputs
|
|
36
|
+
- [ ] R4. Read models / outputs (validate from here)
|
|
37
|
+
- [ ] R5. Boundaries & reactions (reaction shares its slice with the command it triggers)
|
|
38
|
+
- [ ] R6. Gap & TBD reconciliation
|
|
39
|
+
- [ ] R7. Convergence (render + validate clean, user confirmed as-is)
|
|
40
|
+
|
|
41
|
+
## Steps completed
|
|
42
|
+
- [ ] 1. Brainstorm events
|
|
43
|
+
- [ ] 2. Plot / storyboard (personas + UI)
|
|
44
|
+
- [ ] 3. Inputs (commands)
|
|
45
|
+
- [ ] 4. Outputs (read models)
|
|
46
|
+
- [ ] 5. Swimlanes & apply patterns
|
|
47
|
+
- [ ] 6. Elaborate scenarios
|
|
48
|
+
- [ ] 7. Evaluate completeness (`em validate` clean)
|
|
49
|
+
|
|
50
|
+
## Decisions log
|
|
51
|
+
<!-- Resolved choices, with the reasoning, so they aren't re-litigated. In a live workshop,
|
|
52
|
+
attribute each entry to the participant who made the call (see Participants above).
|
|
53
|
+
Every entry is a dated bullet ("- YYYY-MM-DD: ..."); em changelog skips any other line.
|
|
54
|
+
Seam change request (a needed change to another model's public element; never edit that
|
|
55
|
+
model, keep the open question blocked on its owners):
|
|
56
|
+
- YYYY-MM-DD: seam change request → <producerKey>:<kind>.<slug> — <what> — <why> -->
|
|
57
|
+
- {{YYYY-MM-DD}}: {{decision}} — {{why}} — by {{participant, if a live workshop}}
|
|
58
|
+
|
|
59
|
+
## Usage log
|
|
60
|
+
<!-- The team's only usage signal today (see docs/usage-data.md) — cheap and coarse on purpose.
|
|
61
|
+
One line per session: phase(s) touched, and validate diagnostic *categories* hit (one of
|
|
62
|
+
the exact fixed strings in docs/usage-data.md#categories, e.g. "read model has no
|
|
63
|
+
consumer" — never the full instance message or any domain content). Append, never edit
|
|
64
|
+
past entries. -->
|
|
65
|
+
- {{YYYY-MM-DD}}: phases: {{discover | extract | model | slice | implement | conform | review | validate | watch, ...}} — validate: {{diagnostic category (docs/usage-data.md#categories), ... | none}}
|
|
66
|
+
|
|
67
|
+
## Open questions / parking lot
|
|
68
|
+
<!-- Unresolved items to bring back to the user. Never guess these. Metadata is optional and
|
|
69
|
+
flat — add only what's known: source (ticket/conversation that spawned it), blocked on
|
|
70
|
+
(who/what), revisit (when). -->
|
|
71
|
+
- [ ] {{question}} — source: {{ticket/conversation link, optional}} — blocked on: {{who/what, optional}} — revisit: {{when, optional}}
|
|
72
|
+
|
|
73
|
+
## Slice inventory
|
|
74
|
+
<!-- Deliberately NOT a table: the canonical slice index (slice, pattern, status, doc link)
|
|
75
|
+
lives in README.md's "Slices" section — one source of truth, updated there. This file
|
|
76
|
+
only tracks resumable session state. -->
|
|
77
|
+
See `README.md` → **Slices** for the slice index and per-slice doc status.
|