@milehimikey/em 1.8.1 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/event-modeling/SKILL.md +58 -404
- package/.claude/skills/event-modeling-conform/SKILL.md +77 -0
- package/.claude/skills/{event-modeling → event-modeling-conform}/reference/conform.md +40 -14
- package/.claude/skills/event-modeling-design/SKILL.md +139 -0
- package/.claude/skills/event-modeling-discover/SKILL.md +89 -0
- package/.claude/skills/{event-modeling → event-modeling-discover}/reference/extract.md +3 -2
- package/.claude/skills/event-modeling-implement/SKILL.md +40 -0
- package/.claude/skills/{event-modeling → event-modeling-implement}/reference/implement.md +3 -2
- package/.claude/skills/event-modeling-review/SKILL.md +58 -0
- package/.claude/skills/{event-modeling → event-modeling-shared}/reference/em-dsl.md +115 -83
- package/.claude/skills/{event-modeling → event-modeling-shared}/reference/methodology.md +6 -5
- package/.claude/skills/event-modeling-shared/reference/operating-principles.md +150 -0
- package/.claude/skills/event-modeling-shared/reference/slice-doc-schema.md +381 -0
- package/.claude/skills/{event-modeling → event-modeling-shared}/templates/model-readme.md +2 -2
- package/.claude/skills/{event-modeling → event-modeling-shared}/templates/slice.md +57 -14
- package/README.md +24 -4
- package/dist/catalog/build.js +9 -0
- package/dist/catalog/build.js.map +1 -1
- package/dist/catalog/docJoin.d.ts +15 -0
- package/dist/catalog/docJoin.js +8 -0
- package/dist/catalog/docJoin.js.map +1 -1
- package/dist/catalog/modelCollisionValidate.d.ts +22 -0
- package/dist/catalog/modelCollisionValidate.js +67 -0
- package/dist/catalog/modelCollisionValidate.js.map +1 -0
- package/dist/catalog/orphanedSliceDocValidate.d.ts +11 -0
- package/dist/catalog/orphanedSliceDocValidate.js +98 -0
- package/dist/catalog/orphanedSliceDocValidate.js.map +1 -0
- package/dist/catalog/sliceDoc.d.ts +15 -0
- package/dist/catalog/sliceDoc.js +18 -0
- package/dist/catalog/sliceDoc.js.map +1 -1
- package/dist/cli/changelogBuild.d.ts +12 -0
- package/dist/cli/changelogBuild.js +89 -0
- package/dist/cli/changelogBuild.js.map +1 -0
- package/dist/cli/ciInit.d.ts +42 -0
- package/dist/cli/ciInit.js +298 -0
- package/dist/cli/ciInit.js.map +1 -0
- package/dist/cli/conformSupersede.d.ts +32 -0
- package/dist/cli/conformSupersede.js +102 -0
- package/dist/cli/conformSupersede.js.map +1 -0
- package/dist/cli/coverage.d.ts +6 -1
- package/dist/cli/coverage.js +28 -3
- package/dist/cli/coverage.js.map +1 -1
- package/dist/cli/frontmatterSurgery.d.ts +28 -0
- package/dist/cli/frontmatterSurgery.js +66 -0
- package/dist/cli/frontmatterSurgery.js.map +1 -0
- package/dist/cli/markImplemented.js +6 -45
- package/dist/cli/markImplemented.js.map +1 -1
- package/dist/cli/ratify.d.ts +41 -0
- package/dist/cli/ratify.js +151 -0
- package/dist/cli/ratify.js.map +1 -0
- package/dist/cli/reratify.d.ts +33 -0
- package/dist/cli/reratify.js +137 -0
- package/dist/cli/reratify.js.map +1 -0
- package/dist/cli/skillCheck.d.ts +6 -0
- package/dist/cli/skillCheck.js +46 -0
- package/dist/cli/skillCheck.js.map +1 -1
- package/dist/cli/skillDirs.d.ts +15 -0
- package/dist/cli/skillDirs.js +34 -0
- package/dist/cli/skillDirs.js.map +1 -0
- package/dist/cli/skillSync.d.ts +10 -0
- package/dist/cli/skillSync.js +15 -0
- package/dist/cli/skillSync.js.map +1 -1
- package/dist/cli/sliceIndex.d.ts +3 -0
- package/dist/cli/sliceIndex.js +6 -2
- package/dist/cli/sliceIndex.js.map +1 -1
- package/dist/cli/sliceLink.d.ts +52 -0
- package/dist/cli/sliceLink.js +152 -0
- package/dist/cli/sliceLink.js.map +1 -0
- package/dist/cli/status.d.ts +261 -0
- package/dist/cli/status.js +536 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/usageLog.d.ts +75 -0
- package/dist/cli/usageLog.js +193 -0
- package/dist/cli/usageLog.js.map +1 -0
- package/dist/cli.js +503 -132
- package/dist/cli.js.map +1 -1
- package/dist/emit/freshnessJson.d.ts +6 -0
- package/dist/emit/freshnessJson.js +24 -0
- package/dist/emit/freshnessJson.js.map +1 -0
- package/dist/emit/json.d.ts +62 -8
- package/dist/emit/json.js +14 -3
- package/dist/emit/json.js.map +1 -1
- package/dist/emit/statusJson.d.ts +7 -0
- package/dist/emit/statusJson.js +39 -0
- package/dist/emit/statusJson.js.map +1 -0
- package/dist/emit/typespec.d.ts +26 -0
- package/dist/emit/typespec.js +356 -0
- package/dist/emit/typespec.js.map +1 -0
- package/dist/emit/usageReportJson.d.ts +3 -0
- package/dist/emit/usageReportJson.js +23 -0
- package/dist/emit/usageReportJson.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.js +301 -11
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/rules.d.ts +13 -0
- package/dist/model/rules.js +20 -0
- package/dist/model/rules.js.map +1 -1
- package/dist/templates.d.ts +1 -1
- package/dist/templates.js +2 -2
- package/dist/util/markers.d.ts +16 -4
- package/dist/util/markers.js +23 -10
- package/dist/util/markers.js.map +1 -1
- package/package.json +2 -1
- /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/conformance-report.md +0 -0
- /package/.claude/skills/{event-modeling → event-modeling-shared}/templates/state.md +0 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
<!-- GENERATED FILE — do not hand-edit. Synced from docs/slice-doc-schema.md by
|
|
2
|
+
scripts/generate-skill-docs.ts (`npm run docs:generate`); `npm run docs:check` fails
|
|
3
|
+
on drift. A few links below are rewritten for this vendored location (see that
|
|
4
|
+
script's buildVendoredSliceDocSchema for exactly what changes and why) — everything
|
|
5
|
+
else is identical to the source doc. -->
|
|
6
|
+
|
|
7
|
+
# Slice-doc frontmatter schema
|
|
8
|
+
|
|
9
|
+
This documents the machine-read YAML frontmatter dialect `src/catalog/sliceDoc.ts` parses out
|
|
10
|
+
of `slices/<slice-key>.md` — the contract `em export`'s slice-frontmatter join reads. It covers
|
|
11
|
+
the **frontmatter block only**. Body/prose authoring conventions (Intent, Scenarios, Open
|
|
12
|
+
Questions, …) live in the event-modeling skill's
|
|
13
|
+
[`templates/slice.md`](../templates/slice.md), not here — with two
|
|
14
|
+
exceptions:
|
|
15
|
+
|
|
16
|
+
- The `## Open Questions` section's GFM checkboxes (`- [ ]` / `- [x]`) *are* now machine-parsed
|
|
17
|
+
by `sliceDoc.ts` too (`openQuestionsTotal`/`openQuestionsUnchecked`, MIL-87), feeding
|
|
18
|
+
`em validate --slice-ready <key>` (see [validation.md#slice-readiness](https://github.com/milehimikey/em/blob/main/docs/validation.md#slice-readiness)).
|
|
19
|
+
The section's cross-version lifecycle (MIL-156) is documented here too, alongside `## Delta`'s
|
|
20
|
+
— see [Open Questions section: lifecycle](#open-questions-section-lifecycle) below. Everything
|
|
21
|
+
else about the section's authoring — what a good open question looks like, when to resolve one
|
|
22
|
+
— stays owned by the skill template; this doc only covers the counting mechanics and lifecycle.
|
|
23
|
+
- The `## Delta` section's grammar and lifecycle (MIL-88) is documented here, in full, alongside
|
|
24
|
+
the lineage keys it complements — a 2026-08-14 ruling deliberately kept the slice-doc contract
|
|
25
|
+
as one document rather than splitting a structurally-related convention across two files, even
|
|
26
|
+
though (unlike Open Questions) `## Delta` is currently display-only prose that no `em` command
|
|
27
|
+
parses yet. See [Delta section: grammar and lifecycle](#delta-section-grammar-and-lifecycle)
|
|
28
|
+
below; authoring voice/tone for the section still lives in the skill template, same as every
|
|
29
|
+
other body section.
|
|
30
|
+
|
|
31
|
+
## How the parser reads frontmatter
|
|
32
|
+
|
|
33
|
+
A leading `---` / `---` fence, at the literal start of the file (like Jekyll/Hugo — a guidance
|
|
34
|
+
comment above the fence means the frontmatter doesn't count yet). Inside the fence: top-level
|
|
35
|
+
scalar `key: value` lines only — **no lists, no nesting, no real YAML**. Quoted values have
|
|
36
|
+
their outer quotes stripped; a value that's empty after trimming is dropped. Keys are matched
|
|
37
|
+
case-sensitively as `[A-Za-z][\w-]*` but folded to lowercase for lookup. Any line that doesn't
|
|
38
|
+
match that shape — including `#`-prefixed comment lines, blank lines, and YAML list
|
|
39
|
+
continuation lines (` - item`) — is silently skipped. An unterminated fence (no closing `---`)
|
|
40
|
+
means "no frontmatter at all": the whole file is treated as body.
|
|
41
|
+
|
|
42
|
+
No `yaml` dependency, by design — a real YAML parser was added and reverted (commit `6de0a05`,
|
|
43
|
+
"keep the Two Laws of the Timeline"). This is a deliberately shallow line-scan, and stays that
|
|
44
|
+
way: real YAML would also start accepting nesting/lists that this schema explicitly doesn't
|
|
45
|
+
define a meaning for.
|
|
46
|
+
|
|
47
|
+
`SliceDoc` (`src/catalog/sliceDoc.ts`) also exposes `frontmatterPresent` (was a well-formed
|
|
48
|
+
fence found and closed at all) and `missingRequiredFields` (which of the required-at-every-
|
|
49
|
+
status keys, above, were absent) — the mechanical basis `em export`'s doc join (MIL-91) uses
|
|
50
|
+
to decide `frontmatter-invalid` without re-deriving frontmatter-shape rules of its own.
|
|
51
|
+
|
|
52
|
+
## Canonical keys
|
|
53
|
+
|
|
54
|
+
| Key | Type | Grammar / enum | Read by |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| `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) |
|
|
57
|
+
| `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`) |
|
|
58
|
+
| `swimlane` | string | free text, `<Persona> → <Context>` | display-only |
|
|
59
|
+
| `status` | string, case-insensitive | `draft` \| `reviewed` \| `ready-to-implement` \| `implemented` | `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
|
+
| `version` | integer | positive integer, starts at `1` | joined into `em export`'s `slice.doc.version` (schema `1.4`, MIL-91) |
|
|
61
|
+
| `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)) |
|
|
62
|
+
| `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)) |
|
|
63
|
+
| `merged-from` | list of refs | comma-separated `<slice-key>@v<N>, ...` | joined into `em export`'s `slice.doc.mergedFrom` (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)) |
|
|
64
|
+
| `superseded-by` | list of refs | comma-separated `<slice-key>@v<N>, ...` | joined into `em export`'s `slice.doc.supersededBy` (schema `1.4`, MIL-91) and `em diff`'s `slice-removed` 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)) |
|
|
65
|
+
| `covers` | list of slice keys | comma-separated `<slice-key>, ...` (plain keys — **not** the `<slice-key>@v<N>` ref grammar above) | ratifies a cross-slice binding (MIL-121 — see [Cross-slice coverage](#cross-slice-coverage-covers) below): read by `em export`'s doc join, `em validate --slice-ready`, and (best-effort) `em render`/`em watch`'s Slice Status legend |
|
|
66
|
+
| `ratifiedBy` | string | free text (typically a person's name) | written only by `em slice ratify` (MIL-165 — see [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-ratify-file-slice-key---by-name)); joined into `em export`'s `slice.doc.ratifiedBy` (schema `1.8`) and `em slice index`'s Ratified by column |
|
|
67
|
+
| `ratifiedOn` | string | `YYYY-MM-DD` | written only by `em slice ratify` (MIL-165); joined into `em export`'s `slice.doc.ratifiedOn` (schema `1.8`) |
|
|
68
|
+
| `owner` | string | free text (typically a person or team name) | hand-filled — no `em` command writes it; joined into `em export`'s `slice.doc.owner` (schema `1.9`, MIL-171), `em slice index`'s Owner column, and `em status`'s per-slice `owners[]` |
|
|
69
|
+
| `tracking` | string | free text (typically an external ticket/issue URL) | hand-filled — no `em` command writes it; joined into `em export`'s `slice.doc.tracking` (schema `1.9`, MIL-171) and `em slice index`'s Tracking column. This is the exact field `em-tracker-bridge` reads to find the ticket mirroring this slice — `em` only stores and displays it, it never talks to a tracker itself |
|
|
70
|
+
|
|
71
|
+
Five keys — `schemaVersion`/`pattern`/`swimlane`/`status`/`version` — are what
|
|
72
|
+
`hasUsableFrontmatter()` requires: a doc omitting any of them is `frontmatter-invalid` to
|
|
73
|
+
`em export`'s doc join and to `em validate --slice-ready` (the parser itself never *throws*
|
|
74
|
+
over an omission — it reports). `implementedIn` and the lineage keys are the genuinely
|
|
75
|
+
optional ones; `implementedIn`'s required-once-implemented rule in the table below is
|
|
76
|
+
convention, not parser-enforced.
|
|
77
|
+
|
|
78
|
+
## Required vs optional, by `status`
|
|
79
|
+
|
|
80
|
+
| Key | draft | reviewed | ready-to-implement | implemented |
|
|
81
|
+
|---|---|---|---|---|
|
|
82
|
+
| `schemaVersion`, `pattern`, `swimlane`, `status` | required | required | required | required |
|
|
83
|
+
| `version` | required (starts at `1`) | required | required | required |
|
|
84
|
+
| `implementedIn` | optional | optional | optional | required once the slice has *ever* reached `implemented` — may still name a **prior** version's PR during re-ratification, see below |
|
|
85
|
+
| `split-from`, `merged-from`, `superseded-by` | optional in every state — present only on docs created by a split/merge, or on a doc that has been retired |
|
|
86
|
+
| `covers` | optional in every state — present only on a doc that deliberately also serves another slice (MIL-121, see below); most docs never carry it |
|
|
87
|
+
| `ratifiedBy`, `ratifiedOn` | optional in every state — present once `em slice ratify` (MIL-165) has run at least once; a doc predating this feature, or ratified by hand, simply omits both |
|
|
88
|
+
| `owner`, `tracking` | optional in every state — hand-filled whenever a team wants a who-holds-this / external-tracker link; most docs never carry either (MIL-171) |
|
|
89
|
+
|
|
90
|
+
`em export`'s slice-doc join (MIL-91) is the first `em` command to mechanically check the
|
|
91
|
+
required row above: a bound doc missing any of `schemaVersion`/`pattern`/`swimlane`/`status`/
|
|
92
|
+
`version` (or missing a frontmatter block entirely) reports `slice.doc.reason:
|
|
93
|
+
"frontmatter-invalid"` plus a warning diagnostic — report, never fail, same as every other
|
|
94
|
+
export finding. `implementedIn`'s conditional requirement (once a slice has *ever* reached
|
|
95
|
+
`implemented`) is **not** checked — that needs git history no doc-only parse has access to.
|
|
96
|
+
No `em` command fails a build over this table. `em validate`'s frontmatter-coherence check
|
|
97
|
+
(MIL-85 — see [validation.md#frontmatter-coherence](https://github.com/milehimikey/em/blob/main/docs/validation.md#frontmatter-coherence)) warns
|
|
98
|
+
(never fails) on the one combination checkable without git history: `status: implemented` with
|
|
99
|
+
no `implementedIn` link at all.
|
|
100
|
+
|
|
101
|
+
## Lineage: grammar and cardinality
|
|
102
|
+
|
|
103
|
+
Grammar: `<slice-key>@v<N>` — `<slice-key>` is the referenced slice's kebab-case filename stem
|
|
104
|
+
(matches `kebabSlug()`, `src/util/slug.ts`); `<N>` is a positive integer, the referenced
|
|
105
|
+
slice's `version` at the point of reference.
|
|
106
|
+
|
|
107
|
+
| Key | Cardinality | Why |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `split-from` | **single** ref | A slice splits *from* exactly one parent, even though a split can produce multiple successors. |
|
|
110
|
+
| `merged-from` | **list**, comma-separated | A merge combines two or more source slices into one surviving doc. |
|
|
111
|
+
| `superseded-by` | **list**, comma-separated | The retired side of a split names potentially multiple successors; the retired side of a merge or a simple rename usually names exactly one, but the grammar stays list-shaped either way. |
|
|
112
|
+
|
|
113
|
+
**Worked example** (a split): `checkout` v4 splits into `checkout` v5 plus a new
|
|
114
|
+
`apply-discount` v1. The retired parent doc, `checkout.md`, gets:
|
|
115
|
+
|
|
116
|
+
```yaml
|
|
117
|
+
version: 4
|
|
118
|
+
status: implemented
|
|
119
|
+
superseded-by: checkout@v5, apply-discount@v1
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Both surviving docs carry the back-link — `checkout.md` (now at v5) and `apply-discount.md`
|
|
123
|
+
each get:
|
|
124
|
+
|
|
125
|
+
```yaml
|
|
126
|
+
split-from: checkout@v4
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Scope note:** the parser (`sliceDoc.ts`) itself still never checks that a referenced
|
|
130
|
+
slice/version actually *exists* — that stays deliberately out of scope here, by design (fs-free,
|
|
131
|
+
pure). A malformed or dangling ref still parses (its `raw` text is preserved, `sliceKey`/
|
|
132
|
+
`version` come back `null` for a malformed value); referential checking is a separate, fs-aware
|
|
133
|
+
layer.
|
|
134
|
+
|
|
135
|
+
`em validate` (`src/catalog/lineageValidate.ts`, MIL-84) is that layer. It checks what the
|
|
136
|
+
*current tree* can prove wrong and stays silent about what it can't — see
|
|
137
|
+
[validation.md#lineage](https://github.com/milehimikey/em/blob/main/docs/validation.md#lineage) for exactly what's checked (grammar,
|
|
138
|
+
self-reference/cycles, dangling `superseded-by`, impossible version arithmetic) versus what's
|
|
139
|
+
deliberately never flagged (a `split-from`/`merged-from` naming a key legitimately absent from
|
|
140
|
+
the current tree — the normal state after a real split/merge). Deep historical verification —
|
|
141
|
+
did `slice@vN` really, once, exist? — stays out of core validate; the reason that's sufficient
|
|
142
|
+
is a same-commit authoring convention, not new plumbing (`em ledger`, below, is the opt-in,
|
|
143
|
+
two-revision command for the related-but-different version/content invariant):
|
|
144
|
+
|
|
145
|
+
> Lineage refs (`split-from:`/`merged-from:`/`superseded-by:`) are written in the same
|
|
146
|
+
> ratification commit that performs the operation they record, so the PR diff contains both
|
|
147
|
+
> sides of the claim (the predecessor at its final version, and the ref naming it). The review
|
|
148
|
+
> airlock is the history check.
|
|
149
|
+
|
|
150
|
+
## Cross-slice coverage: `covers`
|
|
151
|
+
|
|
152
|
+
Since `em` 1.7.1 (MIL-120), the canonical Automation/Translation shape is two raw slices: a
|
|
153
|
+
bare `view` slice, and the reaction+command+event slice that reads it. Each slice can still bind
|
|
154
|
+
its own `slices/<key>.md` doc the ordinary way, but a team documenting the whole design unit as
|
|
155
|
+
**one** doc needs a way to make the view-only slice count as doc-bound too, without splitting
|
|
156
|
+
the write-up back into two files. `covers` (MIL-121) is that escape hatch — a deliberately
|
|
157
|
+
two-ended handshake, not a one-sided claim:
|
|
158
|
+
|
|
159
|
+
1. In the `.em`, an element in the *covered* slice (the one with no doc of its own) carries
|
|
160
|
+
`note "slices/<other-key>.md"` — a path in the ordinary `slices/<key>.md` shape, just naming
|
|
161
|
+
a *different* slice's canonical doc instead of its own.
|
|
162
|
+
2. That other doc's own frontmatter ratifies the coverage with `covers`, naming the covered
|
|
163
|
+
slice's key back — same comma-separated, single scalar-line shape as `merged-from`/
|
|
164
|
+
`superseded-by` (this parser's frontmatter dialect has **no** real YAML list support, see
|
|
165
|
+
above):
|
|
166
|
+
```yaml
|
|
167
|
+
covers: detect-unpaid-orders
|
|
168
|
+
```
|
|
169
|
+
Multiple covered slices: `covers: detect-unpaid-orders, some-other-slice`.
|
|
170
|
+
|
|
171
|
+
Both sides are required. A `note` naming another slice's doc with no matching `covers` entry on
|
|
172
|
+
that doc — the file is missing, its frontmatter isn't usable, or `covers` doesn't list this
|
|
173
|
+
slice back — leaves the noting slice exactly as unbound as if it had no note at all
|
|
174
|
+
(`no-doc-bound`); em never guesses at a one-sided claim. When ratified, every consumer that
|
|
175
|
+
reads a bound doc's canonical fields (`em export`'s `slice.doc`, `em validate --slice-ready`,
|
|
176
|
+
`em render`/`em watch`'s Slice Status legend) reads the **covering** doc's `status`/`version`/
|
|
177
|
+
`implementedIn`/lineage/Open Questions, not the covered slice's own (nonexistent) file. A doc
|
|
178
|
+
covers its own canonical slice key implicitly — `covers` never needs to list it.
|
|
179
|
+
|
|
180
|
+
`covers` is a plain list of slice keys (`<slice-key>`, e.g. `detect-unpaid-orders`), **not** the
|
|
181
|
+
`<slice-key>@v<N>` ref grammar the lineage keys use above: coverage is a standing "this doc also
|
|
182
|
+
serves that slice" declaration, with no version component — unlike lineage, which records a
|
|
183
|
+
specific historical hop.
|
|
184
|
+
|
|
185
|
+
**Out of scope for THIS join:** `resolveSliceDocJoin` itself never warns on a *mismatched*
|
|
186
|
+
cross-note (a note naming a doc that doesn't ratify it back) — the slice's doc join still stays
|
|
187
|
+
silently `no-doc-bound`, the same as never having written the note; the join's own job is
|
|
188
|
+
resolving the *winning* binding, not auditing every note that didn't win. `em validate` does flag
|
|
189
|
+
the mismatch, as its own separate rule (MIL-126) — see
|
|
190
|
+
[validation.md#note-binding-mismatch](https://github.com/milehimikey/em/blob/main/docs/validation.md#note-binding-mismatch): a dangling cross-note
|
|
191
|
+
(missing file), one pointing at a doc with unusable frontmatter, one pointing at a usable doc
|
|
192
|
+
that just doesn't ratify (`covers` doesn't list this slice back), and an extra note doing nothing
|
|
193
|
+
in a slice that's already bound elsewhere, each get their own diagnostic there.
|
|
194
|
+
|
|
195
|
+
## Delta section: grammar and lifecycle
|
|
196
|
+
|
|
197
|
+
`## Delta` is the body section that pairs with a re-ratification (see "`status` under
|
|
198
|
+
re-ratification" below) — a structured record of what changed to produce the version currently
|
|
199
|
+
in the frontmatter, in typed operation blocks (MIL-88) rather than a one-line summary. Like the
|
|
200
|
+
lineage keys above, it's currently authored, not parsed — no `em` command reads *this section*
|
|
201
|
+
— but it's documented here rather than left purely to the skill template because its shape is a
|
|
202
|
+
structural contract other tooling may parse later, same reasoning as the lineage grammar.
|
|
203
|
+
`em diff --json` now emits the same four-word vocabulary on its own structural entries (`op:
|
|
204
|
+
"Added" | "Modified" | "Removed" | "Renamed"`, schema `1.7`, MIL-131 — see
|
|
205
|
+
[cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-diff-old-new)), so the two sides speak the same language; comparing an
|
|
206
|
+
authored `## Delta` against the structural diff of the revisions it claims to describe is still
|
|
207
|
+
a separate, not-yet-built decision.
|
|
208
|
+
|
|
209
|
+
**The heading is always the literal string `## Delta` — never a variable heading** (e.g. never
|
|
210
|
+
`## Delta: v1 → v2`). Several consumers key on exact `##` text when locating sections in a slice
|
|
211
|
+
doc (the SDD-bridge's section splitter, the slice-to-spec mapping table, the redirect prompt
|
|
212
|
+
preambles); a heading that changes every ratification would break exact-match lookup and move
|
|
213
|
+
the anchor on every hop — the same problem a made-up per-doc key would cause anywhere else in
|
|
214
|
+
this schema. Version range, ratification date, and a one-line summary go on the **first line
|
|
215
|
+
inside** the section instead, as display text — not a frontmatter key, not parsed:
|
|
216
|
+
|
|
217
|
+
```markdown
|
|
218
|
+
## Delta
|
|
219
|
+
**v1 → v2, ratified 2026-08-12** — one-line summary of the ratified change.
|
|
220
|
+
|
|
221
|
+
### Added
|
|
222
|
+
#### Requirement: {{title}} ({{stable ID, e.g. an INV-<MNEMONIC>-n from ## Invariants}})
|
|
223
|
+
{{requirement text}}
|
|
224
|
+
##### Scenario: {{name}}
|
|
225
|
+
- **Given:** {{...}}
|
|
226
|
+
- **When:** {{...}}
|
|
227
|
+
- **Then:** {{...}}
|
|
228
|
+
|
|
229
|
+
### Modified
|
|
230
|
+
(same shape as Added — the ID names the requirement that changed)
|
|
231
|
+
|
|
232
|
+
### Removed
|
|
233
|
+
#### Requirement: {{title}} ({{stable ID}})
|
|
234
|
+
{{why it was removed}}
|
|
235
|
+
|
|
236
|
+
### Renamed
|
|
237
|
+
- {{old title}} ({{old ID}}) → {{new title}} ({{new ID}})
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Stable IDs follow `INV-<MNEMONIC>-<n>` — a short (2-4 uppercase letters/digits) abbreviation of
|
|
241
|
+
the slice's key, unique among the model's slices, then a small integer, optionally letter-suffixed
|
|
242
|
+
for a closely-related sub-invariant (`INV-CHK-3a`) — see the Invariants section guidance in
|
|
243
|
+
[`templates/slice.md`](../templates/slice.md). Per-slice prefixes
|
|
244
|
+
make IDs globally unique across the model, so an `em coverage` citation is exact instead of
|
|
245
|
+
ambiguous across slices.
|
|
246
|
+
|
|
247
|
+
**Four `###` subsections, in that fixed order, Title Case singular words** — `Added`, `Modified`,
|
|
248
|
+
`Removed`, `Renamed` — not OpenSpec's shouting-case `ADDED Requirements` grouping. This is the
|
|
249
|
+
one deliberate divergence from the OpenSpec grammar the convention was validated against: the
|
|
250
|
+
four *operations* are retained (independent convergent design — OpenSpec arrived at the same
|
|
251
|
+
vocabulary from its own change-management-first angle), but OpenSpec's flat, file-per-delta
|
|
252
|
+
heading topology is not, because a slice doc's delta is a section inside a doc with its own
|
|
253
|
+
parsed heading contract, not a standalone file. Omit any of the four subsections with no entries
|
|
254
|
+
this hop — most re-ratifications touch one or two operations, not all four.
|
|
255
|
+
|
|
256
|
+
**`Renamed` is a requirement-level operation, not a slice-level one.** It records an invariant or
|
|
257
|
+
requirement *within this slice* being renamed or renumbered (e.g. `INV-CHK-3` → `INV-CHK-3a`) —
|
|
258
|
+
it is not a substitute for the `split-from`/`merged-from`/`superseded-by` lineage keys above,
|
|
259
|
+
which record the slice-doc-level operation of one doc splitting, merging, or being renamed into
|
|
260
|
+
another. `em diff`'s own `ChangeType` deliberately treats a slice/element rename as remove+add,
|
|
261
|
+
never a first-class rename (`src/model/diff.ts`: "a rename IS a model change") — `Renamed` here
|
|
262
|
+
is a finer grain, inside one otherwise-unchanged slice, and doesn't revisit that decision.
|
|
263
|
+
|
|
264
|
+
**Lifecycle: replace, never accumulate — the section is a window onto the latest hop, not a
|
|
265
|
+
scroll of every hop.** A slice's first version (`v1`) carries no `## Delta` section at all —
|
|
266
|
+
absence means no hop has happened yet, not an empty section. Ratifying `v2` writes the section
|
|
267
|
+
for the first time, in the same commit that bumps `version` and flips `status`. Ratifying `v3`
|
|
268
|
+
**overwrites** it with the `v2 → v3` hop; the `v1 → v2` content is not retained in the doc.
|
|
269
|
+
Full history is git's job — the same-commit ratification convention above makes `git log -p
|
|
270
|
+
slices/<name>.md` a precise, zero-maintenance delta archive — and a rolled-up multi-hop view, if
|
|
271
|
+
ever wanted, is a *rendering* (e.g. a future `em changelog`), never hand-maintained doc content.
|
|
272
|
+
An accumulating in-doc log would be a second history that diverges from git, grows unboundedly
|
|
273
|
+
over a slice's life, references requirements that have since moved (a *live* doc quietly going
|
|
274
|
+
stale reads as current, unlike git which is honestly historical), and forces every reader to
|
|
275
|
+
work out which delta is the live one — exactly the ambiguity `driftSignal` (MIL-85, below) is
|
|
276
|
+
built to avoid.
|
|
277
|
+
|
|
278
|
+
## Open Questions section: lifecycle
|
|
279
|
+
|
|
280
|
+
`## Open Questions` (MIL-87 for the counting mechanics; MIL-156 for this lifecycle) had no
|
|
281
|
+
cross-version story until now: `countOpenQuestions()` counts every GFM task item under the
|
|
282
|
+
heading, but nothing ever pruned a resolved (`- [x]`) one — left unaddressed, the section grows
|
|
283
|
+
by accretion across every re-ratification of a long-lived slice, the same problem `## Delta`
|
|
284
|
+
(above) solves for by replacing its content wholesale each hop.
|
|
285
|
+
|
|
286
|
+
**Decision: prune resolved items on the same commit that ratifies the next version — replace,
|
|
287
|
+
never accumulate, same stance as `## Delta`, applied by hand instead of by section-rewrite.**
|
|
288
|
+
Concretely:
|
|
289
|
+
|
|
290
|
+
- While the *current* version is still being drafted or reviewed, a checked item can stay in the
|
|
291
|
+
doc — it's a visible record of what this round already decided, not yet an accumulation
|
|
292
|
+
problem (a slice's first version, `v1`, commonly ships with every question already resolved;
|
|
293
|
+
see `examples/order-fulfillment/slices/browse-catalog.md`).
|
|
294
|
+
- On the commit that bumps `version` and rewrites `## Delta` for the next hop, prune every
|
|
295
|
+
already-checked item from `## Open Questions` — keep only what's still open (`- [ ]`), plus
|
|
296
|
+
anything new that hop's change surfaced.
|
|
297
|
+
- Full history isn't lost: it lives in git the same way `## Delta`'s superseded hops do —
|
|
298
|
+
`git log -p slices/<name>.md` shows exactly which questions were open, and how they were
|
|
299
|
+
answered, at each prior version.
|
|
300
|
+
|
|
301
|
+
**Why not keep resolved items as a permanent audit trail instead?** Same reasoning `## Delta`'s
|
|
302
|
+
lifecycle section gives: an ever-growing scroll of resolved questions is a second history that
|
|
303
|
+
diverges from git, grows unboundedly over a long-lived slice's life, and forces every reader to
|
|
304
|
+
work out which resolutions are still relevant to the *current* version versus leftover from a
|
|
305
|
+
prior one — exactly the ambiguity a live, current-version-only section avoids.
|
|
306
|
+
|
|
307
|
+
**Not a parsing/grammar change.** `countOpenQuestions()` (`sliceDoc.ts`) and
|
|
308
|
+
`slice-ready-open-questions-unchecked` (`sliceReadyValidate.ts`,
|
|
309
|
+
[validation.md#slice-readiness](https://github.com/milehimikey/em/blob/main/docs/validation.md#slice-readiness)) are unaffected: both already
|
|
310
|
+
only care about the CURRENT doc's checkbox state, never about how many hops of history the
|
|
311
|
+
section has accumulated. This is purely an authoring convention — same "documented, not
|
|
312
|
+
mechanically enforced" status `## Delta`'s own lifecycle has (no `em` command checks that pruning
|
|
313
|
+
actually happened on re-ratification).
|
|
314
|
+
|
|
315
|
+
## `status` under re-ratification
|
|
316
|
+
|
|
317
|
+
When a new version is ratified for a slice whose previous version already shipped, `status`
|
|
318
|
+
tracks the **current version's** implementation state, not a running "has this ever shipped"
|
|
319
|
+
flag. Ratifying v2 on an `implemented` slice flips `status` back to `ready-to-implement`, while
|
|
320
|
+
`implementedIn` keeps naming the v1 PR until v2 ships. That deliberate mismatch — version 2,
|
|
321
|
+
implemented-link still pointing at v1's work — is not staleness, it's the **drift signal**: a
|
|
322
|
+
reader, `em export`'s `slice.doc.driftSignal` (`"unpropagated-delta"`, schema `1.5`, MIL-85), and
|
|
323
|
+
the event-modeling skill's `conform` phase all read it the same way — a ratified delta hasn't
|
|
324
|
+
shipped yet, not a fresh finding against the still-live v1 code. `em validate`'s
|
|
325
|
+
frontmatter-coherence check (MIL-85) deliberately never flags this combination — only
|
|
326
|
+
`status: implemented` with no `implementedIn` link at all is checkable incoherence; see
|
|
327
|
+
[validation.md#frontmatter-coherence](https://github.com/milehimikey/em/blob/main/docs/validation.md#frontmatter-coherence).
|
|
328
|
+
|
|
329
|
+
Pair a re-ratification with a `## Delta` section (see
|
|
330
|
+
[Delta section: grammar and lifecycle](#delta-section-grammar-and-lifecycle) above) recording
|
|
331
|
+
the ratified change in typed operation blocks, so it's reviewable without opening git.
|
|
332
|
+
|
|
333
|
+
**Mechanically checking the invariant this section describes:** `em ledger` (MIL-89, opt-in —
|
|
334
|
+
see [cli.md#em-ledger-file](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-ledger-file)) checks that `version:` and a slice doc's
|
|
335
|
+
content (body + lineage refs) always change together across two git revisions — a version bump
|
|
336
|
+
with no real content change, or a content change with no version bump, is a ledger bug.
|
|
337
|
+
It **deliberately excludes `status`/`implementedIn`** from what counts as "content" for exactly
|
|
338
|
+
the reason this section explains: a re-ratification legitimately flips `status` and leaves
|
|
339
|
+
`implementedIn` naming prior work, with no version bump of its own — including either field in
|
|
340
|
+
the comparison would flag every ordinary lifecycle transition as a false positive.
|
|
341
|
+
|
|
342
|
+
## Unknown keys
|
|
343
|
+
|
|
344
|
+
**Captured, never read, never a warning or error.** Real docs in the wild carry extra
|
|
345
|
+
non-canonical keys — `id`, `title`, `model`, `created`, `updated`, and YAML-list-valued keys
|
|
346
|
+
like `upstreamEvents`. Every top-level `key: value` scalar line is captured internally
|
|
347
|
+
regardless of whether it's one of the keys above; only the keys this document defines are ever
|
|
348
|
+
read back out onto `SliceDoc`. A list-valued key's own line (`upstreamEvents:`, value empty) is
|
|
349
|
+
captured with an empty value; its `- item` continuation lines don't match the `key: value` shape
|
|
350
|
+
at all and are simply skipped. Nothing throws, nothing warns — adding a new non-canonical key to
|
|
351
|
+
a doc is always safe.
|
|
352
|
+
|
|
353
|
+
## `schemaVersion` vs `version` — don't conflate these
|
|
354
|
+
|
|
355
|
+
| | `schemaVersion` | `version` |
|
|
356
|
+
|---|---|---|
|
|
357
|
+
| What it versions | The frontmatter dialect itself | This one slice's ratified definition |
|
|
358
|
+
| Who bumps it | `em` maintainers, when the dialect's canonical keys change | Whoever ratifies a delta on this slice |
|
|
359
|
+
| Cardinality | One value, same across every doc using this dialect | One per slice doc, incrementing per ratified delta |
|
|
360
|
+
| Current value | `1` (unchanged since MIL-86) | Starts at `1` |
|
|
361
|
+
| Read by `em` today | Value: no — captured, not exposed on `SliceDoc`. Presence: required for usable frontmatter | Yes — parsed onto `SliceDoc.version` |
|
|
362
|
+
|
|
363
|
+
## Legacy status bullet line
|
|
364
|
+
|
|
365
|
+
Docs written before the frontmatter dialect existed may use `- **Status:** ...` instead of
|
|
366
|
+
frontmatter `status:` — still accepted, status only. `version` and the lineage keys have no
|
|
367
|
+
legacy form; they're frontmatter-only from the day they were introduced.
|
|
368
|
+
|
|
369
|
+
## See also
|
|
370
|
+
|
|
371
|
+
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-render-file) — slice status colors
|
|
372
|
+
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-catalog-files) — pattern / doc lookup
|
|
373
|
+
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-ratify-file-slice-key---by-name) — `em slice ratify`, the mechanized ratification act (`ratifiedBy`/`ratifiedOn`, schema `1.8`, MIL-165)
|
|
374
|
+
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-slice-reratify-file-slice-key) — `em slice reratify`, the mechanized re-ratification version bump/status flip (MIL-161)
|
|
375
|
+
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-export-file) — the `em export` join (`slice.pattern`/`slice.doc`, schema `1.4`, MIL-91), including `owner`/`tracking` (schema `1.9`, MIL-171)
|
|
376
|
+
- [cli.md](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-diff-old-new) — the `em diff` lineage annotation (schema `1.6`, MIL-84)
|
|
377
|
+
- [validation.md#lineage](https://github.com/milehimikey/em/blob/main/docs/validation.md#lineage) — `em validate`'s lineage-ref resolution (MIL-84)
|
|
378
|
+
- [validation.md#slice-readiness](https://github.com/milehimikey/em/blob/main/docs/validation.md#slice-readiness) — `em validate --slice-ready`'s note-binding gate, including the `covers` cross-binding (MIL-121)
|
|
379
|
+
- [cli.md#em-coverage-file---tests-dir](https://github.com/milehimikey/em/blob/main/docs/cli.md#em-coverage-file---tests-dir) — `em coverage`'s INV-ID extraction, scoped to the Invariants/Delta sections' structural (non-nested) bullet lines (MIL-149/MIL-155/MIL-156)
|
|
380
|
+
- [validation.md#note-binding-mismatch](https://github.com/milehimikey/em/blob/main/docs/validation.md#note-binding-mismatch) — `em validate`'s check for a doc-shaped note that doesn't participate in its slice's binding (MIL-126)
|
|
381
|
+
- [`templates/slice.md`](../templates/slice.md) — the authored template
|
|
@@ -37,8 +37,8 @@ never connected to one another.
|
|
|
37
37
|
`em slice index {{model-name}}.em` to (re)write the table below from the model and its
|
|
38
38
|
slice docs; never hand-edit between the markers. -->
|
|
39
39
|
<!-- GENERATED:slices:start -->
|
|
40
|
-
| # | Slice | Pattern | Status | Implemented in | Design doc |
|
|
41
|
-
|
|
40
|
+
| # | Slice | Pattern | Status | Ratified by | Owner | Tracking | Implemented in | Design doc |
|
|
41
|
+
|---|-------|---------|--------|-------------|-------|----------|----------------|------------|
|
|
42
42
|
<!-- GENERATED:slices:end -->
|
|
43
43
|
|
|
44
44
|
## Status
|
|
@@ -22,7 +22,7 @@ ships; that mismatch is an intended drift signal, not a bug), and fill in the `#
|
|
|
22
22
|
below with this hop's change, replacing whatever it held before (it always shows only the latest
|
|
23
23
|
hop — full history lives in git, same-commit-ratification convention). Full grammar — the fixed
|
|
24
24
|
heading, the four operation subsections, why the heading never varies, the replace-not-accumulate
|
|
25
|
-
lifecycle — is documented in
|
|
25
|
+
lifecycle — is documented in ../reference/slice-doc-schema.md#delta-section-grammar-and-lifecycle; treat
|
|
26
26
|
it the same Socratic way as every other section here, don't generate it mechanically.
|
|
27
27
|
|
|
28
28
|
The three lineage keys only apply when this doc was produced by a split, merge, or rename —
|
|
@@ -35,8 +35,19 @@ to write up. Delete it otherwise; most docs never carry it. Requires a matching
|
|
|
35
35
|
`note "slices/{{this-slice-name}}.md"` on an element in the OTHER slice — this key alone doesn't
|
|
36
36
|
bind anything. Plain slice keys, comma-separated — not the `<slice-key>@v<N>` ref grammar above.
|
|
37
37
|
|
|
38
|
+
`ratifiedBy`/`ratifiedOn` record who ratified this doc's current `status`/`version`, and when —
|
|
39
|
+
don't hand-fill these; run `em slice ratify <model>.em {{this-slice-name}} --by "<name>"` at the
|
|
40
|
+
handoff gate instead (docs/process.md#what-ratified-means), which flips `status` to
|
|
41
|
+
`ready-to-implement` and writes both in one edit.
|
|
42
|
+
|
|
43
|
+
`owner`/`tracking` are optional and, unlike `ratifiedBy`/`ratifiedOn`, hand-filled — no `em`
|
|
44
|
+
command writes either. `owner` is free text naming who (a person or team) holds this slice;
|
|
45
|
+
`tracking` is a URL into an external tracker (Jira, Linear, ...) mirroring it — the exact field
|
|
46
|
+
`em-tracker-bridge` reads to find the mirrored ticket. `em` only stores and displays both; it
|
|
47
|
+
never talks to a tracker itself. Delete both otherwise; most docs never carry them.
|
|
48
|
+
|
|
38
49
|
Full machine schema — required-vs-optional keys per `status`, value types/enums, the
|
|
39
|
-
unknown-key policy — is documented in
|
|
50
|
+
unknown-key policy — is documented in ../reference/slice-doc-schema.md.
|
|
40
51
|
|
|
41
52
|
The diagram below is generated, not hand-drawn: `em render <model>.em --slice "{{Slice Name}}"
|
|
42
53
|
-o slices/{{slice-name}}.svg` (kebab-case the slice name to match this doc's own filename).
|
|
@@ -51,14 +62,17 @@ version: 1
|
|
|
51
62
|
implementedIn: {{PR/commit link — fill in once status is `implemented`}}
|
|
52
63
|
# Lineage — only when this doc exists because of a split, merge, or rename (delete these three
|
|
53
64
|
# lines otherwise). Grammar: <slice-key>@v<N>. See
|
|
54
|
-
#
|
|
65
|
+
# ../reference/slice-doc-schema.md#lineage-grammar-and-cardinality.
|
|
55
66
|
# split-from: <slice-key>@v<N>
|
|
56
67
|
# merged-from: <slice-key>@v<N>, <slice-key>@v<N>
|
|
57
68
|
# superseded-by: <slice-key>@v<N>, <slice-key>@v<N>
|
|
58
69
|
# Cross-slice coverage — only when this doc also covers another slice with no doc of its own
|
|
59
70
|
# (e.g. the view-only half of a two-slice Automation/Translation, MIL-121); delete otherwise.
|
|
60
|
-
# Plain slice keys, comma-separated. See
|
|
71
|
+
# Plain slice keys, comma-separated. See ../reference/slice-doc-schema.md#cross-slice-coverage-covers.
|
|
61
72
|
# covers: <slice-key>, <slice-key>
|
|
73
|
+
# Ownership / tracking — optional, hand-filled (no `em` command writes either); delete otherwise.
|
|
74
|
+
# owner: <person or team>
|
|
75
|
+
# tracking: <ticket URL>
|
|
62
76
|
---
|
|
63
77
|
# Slice: {{Slice Name}}
|
|
64
78
|
|
|
@@ -67,7 +81,7 @@ implementedIn: {{PR/commit link — fill in once status is `implemented`}}
|
|
|
67
81
|
<!-- Only on re-ratification of an already-`implemented` slice — omit this whole section on a
|
|
68
82
|
slice's first version (v1 has no delta yet). The heading is always the literal `## Delta`,
|
|
69
83
|
never `## Delta: vX → vY` — hop metadata is a display line inside the section instead (see
|
|
70
|
-
|
|
84
|
+
../reference/slice-doc-schema.md#delta-section-grammar-and-lifecycle for why). Replace this
|
|
71
85
|
section's content wholesale on the next re-ratification — it shows only the latest hop, not
|
|
72
86
|
an accumulating log. Omit any of the four subsections below with no entries this hop; keep
|
|
73
87
|
the remaining ones in this order (Added/Modified/Removed/Renamed). `Renamed` is for a
|
|
@@ -81,7 +95,9 @@ implementedIn: {{PR/commit link — fill in once status is `implemented`}}
|
|
|
81
95
|
#### Requirement: {{title}} ({{stable ID, e.g. an INV-{{MNEMONIC}}-n from Invariants below}})
|
|
82
96
|
{{requirement text — same voice as an Invariants entry}}
|
|
83
97
|
##### Scenario: {{name}}
|
|
84
|
-
- **
|
|
98
|
+
- **Given:** {{...}}
|
|
99
|
+
- **When:** {{...}}
|
|
100
|
+
- **Then:** {{...}}
|
|
85
101
|
|
|
86
102
|
### Modified
|
|
87
103
|
<!-- Same shape as Added — the stable ID names the requirement that changed. -->
|
|
@@ -145,17 +161,34 @@ an event directly.}}
|
|
|
145
161
|
<!-- What must ALWAYS hold. Give each a stable ID so tests and code can reference it:
|
|
146
162
|
`INV-<MNEMONIC>-<n>`, where `<MNEMONIC>` is a short (2-4 letter/digit), slice-unique
|
|
147
163
|
abbreviation of this slice's key (e.g. slice `checkout` -> `INV-CHK-1`) — see
|
|
148
|
-
|
|
149
|
-
(`INV-CHK-3a`).
|
|
164
|
+
../reference/slice-doc-schema.md. Add a letter suffix for a closely-related sub-invariant
|
|
165
|
+
(`INV-CHK-3a`). Keep the rule statement itself to one line. If it needs more — why the rule
|
|
166
|
+
exists, what "violation" looks like in practice, an edge case worth calling out — add that as
|
|
167
|
+
a nested bullet under the rule instead of one long run-on sentence: this section renders as
|
|
168
|
+
HTML (`em catalog`/`em render`/`em watch`), and a nested bullet stays visually distinct where
|
|
169
|
+
a wrapped sentence collapses into a wall of text. The ID must stay on the rule's own
|
|
170
|
+
top-level bullet line — `em coverage` extracts INV IDs from that line only, never from a
|
|
171
|
+
nested elaboration bullet underneath it. -->
|
|
150
172
|
- **INV-{{MNEMONIC}}-1:** {{rule that the command enforces; violation ⇒ rejection}}
|
|
173
|
+
- {{optional: rationale, edge-case detail, or what "violation" means here — its own bullet}}
|
|
151
174
|
- **INV-{{MNEMONIC}}-2:** {{...}}
|
|
152
175
|
|
|
153
176
|
## Scenarios (Given / When / Then)
|
|
154
|
-
<!-- The executable specification. Cover the happy path AND the key rule boundaries.
|
|
155
|
-
-
|
|
156
|
-
|
|
157
|
-
- **
|
|
158
|
-
- **
|
|
177
|
+
<!-- The executable specification. Cover the happy path AND the key rule boundaries. Each
|
|
178
|
+
scenario is a case-label bullet with Given/When/Then as nested sub-bullets — not one run-on
|
|
179
|
+
sentence — so the case reads as distinct beats once rendered instead of a dense paragraph. -->
|
|
180
|
+
- **Happy path**
|
|
181
|
+
- **Given:** {{starting state / prior events}}
|
|
182
|
+
- **When:** {{command/trigger}}
|
|
183
|
+
- **Then:** {{event(s) recorded}} and {{resulting read-model change}}.
|
|
184
|
+
- **Rejected (INV-{{MNEMONIC}}-1)**
|
|
185
|
+
- **Given:** {{state}}
|
|
186
|
+
- **When:** {{command}}
|
|
187
|
+
- **Then:** rejected with reason; no event.
|
|
188
|
+
- **{{Edge case}}**
|
|
189
|
+
- **Given:** {{...}}
|
|
190
|
+
- **When:** {{...}}
|
|
191
|
+
- **Then:** {{...}}
|
|
159
192
|
|
|
160
193
|
## Alternate & Error Flows
|
|
161
194
|
<!-- Failure paths, retries, compensations, timeouts, idempotency. -->
|
|
@@ -174,5 +207,15 @@ an event directly.}}
|
|
|
174
207
|
- **Downstream read models / slices affected:** {{...}}
|
|
175
208
|
|
|
176
209
|
## Open Questions
|
|
177
|
-
<!-- Park unresolved items here instead of guessing. Mirror them into .event-modeling.md.
|
|
210
|
+
<!-- Park unresolved items here instead of guessing. Mirror them into .event-modeling.md.
|
|
211
|
+
|
|
212
|
+
Lifecycle across versions: while THIS version is still being worked, a resolved item
|
|
213
|
+
(`- [x]`) can stay checked here as a visible record of what's already been decided this
|
|
214
|
+
round. On the same commit that ratifies the NEXT version (bumps `version`, rewrites
|
|
215
|
+
`## Delta` above) — prune every already-checked item from this list; keep only what's still
|
|
216
|
+
open, plus anything new the delta itself surfaced. Same "replace, never accumulate" stance
|
|
217
|
+
as `## Delta`, for the same reason: an ever-growing scroll of resolved questions goes stale
|
|
218
|
+
exactly like an accumulating Delta log would, and full history already lives in git
|
|
219
|
+
(`git log -p slices/<name>.md`) — this section is a live worklist, not an audit trail. See
|
|
220
|
+
../reference/slice-doc-schema.md#open-questions-section-lifecycle. -->
|
|
178
221
|
- [ ] {{question}}
|
package/README.md
CHANGED
|
@@ -64,16 +64,35 @@ minutes, and [docs/workflow.md](docs/workflow.md) picks up where it leaves off:
|
|
|
64
64
|
gets specified, gated in CI, handed to implementation, and checked against the code that
|
|
65
65
|
implements it.
|
|
66
66
|
|
|
67
|
+
## How it works
|
|
68
|
+
|
|
69
|
+
Model, gate, ratify, implement, check — repeat as the system evolves. Humans make the calls
|
|
70
|
+
that matter (build the model, ratify a slice, rule on drift); `em` and its agents handle the
|
|
71
|
+
mechanical parts in between. This is the loop in miniature — see
|
|
72
|
+
[docs/workflow.md](docs/workflow.md) for the full seven-stage lifecycle and
|
|
73
|
+
[docs/process.md](docs/process.md) for exactly who (or what) does each part.
|
|
74
|
+
|
|
75
|
+
```mermaid
|
|
76
|
+
flowchart LR
|
|
77
|
+
Model["Model<br/>.em file"] --> Gate["Gate<br/>em validate in CI"]
|
|
78
|
+
Gate --> Ratify["Ratify a slice<br/>a human signs off"]
|
|
79
|
+
Ratify --> Implement["Implement<br/>agent or engineer builds it"]
|
|
80
|
+
Implement --> Conform["Conform<br/>em conform checks the code"]
|
|
81
|
+
Conform -->|drift found, ratified| Model
|
|
82
|
+
```
|
|
83
|
+
|
|
67
84
|
## Model with AI
|
|
68
85
|
|
|
69
|
-
`em` ships a Claude Code skill
|
|
70
|
-
|
|
86
|
+
`em` ships a Claude Code skill bundle — one router skill plus five focused, SDLC-stage skills
|
|
87
|
+
(discover/extract, model/slice, implement, conform/validate, watch/review) — that runs a
|
|
88
|
+
facilitated Event Modeling session: the AI asks the questions, you supply the domain, and the
|
|
89
|
+
model renders live as it grows.
|
|
71
90
|
|
|
72
91
|
```bash
|
|
73
|
-
em skill install # copy the skill into .claude/skills/
|
|
92
|
+
em skill install # copy the skill bundle into .claude/skills/
|
|
74
93
|
```
|
|
75
94
|
|
|
76
|
-
Then run `/event-modeling` in Claude Code. The same
|
|
95
|
+
Then run `/event-modeling` in Claude Code. The same bundle also runs the reverse direction:
|
|
77
96
|
`extract` derives a model from a system that already exists, and `conform` checks a model
|
|
78
97
|
against the code implementing it and reports where they've drifted. See
|
|
79
98
|
[docs/ai-workflow.md](docs/ai-workflow.md) for the phases and what a session produces, and the
|
|
@@ -98,6 +117,7 @@ built this way.
|
|
|
98
117
|
| [docs/usage-data.md](docs/usage-data.md) | What usage data em captures, and how to roll it up for a retro |
|
|
99
118
|
| [docs/architecture.md](docs/architecture.md) | How rendering works; why Graphviz, not PlantUML |
|
|
100
119
|
| [docs/roadmap.md](docs/roadmap.md) | What's planned |
|
|
120
|
+
| [docs/decisions/](docs/decisions/) | Write-ups for open design questions (starts with [MIL-162](docs/decisions/mil-162-teachable-navigator.md), the stakeholder-portal decision) |
|
|
101
121
|
|
|
102
122
|
## Development
|
|
103
123
|
|
package/dist/catalog/build.js
CHANGED
|
@@ -17,6 +17,7 @@ import { layoutDot, composeSvg, writeRendered } from "../render/render.js";
|
|
|
17
17
|
import { buildSliceDiagram } from "../render/sliceDiagram.js";
|
|
18
18
|
import { dedupe, kebabSlug } from "../util/slug.js";
|
|
19
19
|
import { classifySlicePattern } from "./classify.js";
|
|
20
|
+
import { detectSliceDocCollisions } from "./modelCollisionValidate.js";
|
|
20
21
|
import { parseSliceDoc } from "./sliceDoc.js";
|
|
21
22
|
import { renderIndexPage, renderSlicePage } from "./pages.js";
|
|
22
23
|
export async function buildCatalog(inputs, opts) {
|
|
@@ -28,6 +29,14 @@ export async function buildCatalog(inputs, opts) {
|
|
|
28
29
|
const modelSummaries = [];
|
|
29
30
|
const diagnostics = [];
|
|
30
31
|
let sliceCount = 0;
|
|
32
|
+
// MIL-160: catalog's own doc discovery below (existsSync+parseSliceDoc, deliberately not
|
|
33
|
+
// routed through readSliceDoc.ts's `note`-aware convention — see this module's header
|
|
34
|
+
// comment) reads straight off `dirname(file)/slices/<key>.md`, same as every other doc-aware
|
|
35
|
+
// command — so two input models sharing a directory with overlapping slice keys would
|
|
36
|
+
// silently mix up whose doc is whose here too. Checked once, up front, over every input.
|
|
37
|
+
const collisions = detectSliceDocCollisions(inputs.map(({ file, refs }) => ({ file, sliceKeys: refs.sliceKeys })));
|
|
38
|
+
for (const d of collisions)
|
|
39
|
+
diagnostics.push({ file: d.refs?.[2] ?? "", diagnostics: [d] });
|
|
31
40
|
for (const { file, model, grid, dot, refs } of inputs) {
|
|
32
41
|
const modelKey = dedupe(kebabSlug(basename(file, extname(file))), usedModelKeys, "~");
|
|
33
42
|
const modelDir = join(outDir, modelKey);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/catalog/build.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/catalog/build.ts"],"names":[],"mappings":"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"}
|