@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,439 @@
|
|
|
1
|
+
<!-- GENERATED FILE from .claude/skills/event-modeling-implement/reference/implement.md by scripts/build-plugin.ts — do not hand-edit; run npm run docs:generate -->
|
|
2
|
+
# Implementing a ratified slice
|
|
3
|
+
|
|
4
|
+
The contract for the implementation half of the workflow: an agent (or engineer) turning **one
|
|
5
|
+
ratified slice** into merged, verified code. The facilitation phases (`discover`/`extract` →
|
|
6
|
+
`model` → `slice`) produce the inputs; this document governs consuming them. It applies to any
|
|
7
|
+
implementing agent, whether or not the session started from `/em:event-modeling`.
|
|
8
|
+
|
|
9
|
+
**The contract in one paragraph:** the slice doc is the spec — nothing between it and the code
|
|
10
|
+
is a source of truth. Verify readiness mechanically before writing any code; implement exactly
|
|
11
|
+
what the doc says; put every gap in front of a human instead of deciding it silently; never
|
|
12
|
+
edit the ratified doc except the two lifecycle fields at merge; prove the work with tests
|
|
13
|
+
traceable to the doc's invariants and scenarios.
|
|
14
|
+
|
|
15
|
+
Why the rules are shaped this way: **agents propose, humans ratify.** Everything in the model
|
|
16
|
+
and its slice docs is there because a human decided it on purpose — that is what makes the
|
|
17
|
+
model authoritative. An implementing agent that silently patches a gap, or edits a ratified
|
|
18
|
+
doc outside a session, converts the model into just another generated artifact and voids the
|
|
19
|
+
whole methodology. (The full human/agent partition is `docs/process.md` in the
|
|
20
|
+
[em repository](https://github.com/milehimikey/em/blob/main/docs/process.md) — not vendored
|
|
21
|
+
with this skill.)
|
|
22
|
+
|
|
23
|
+
## 1. Gate: verify readiness before starting
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
em validate <model>.em --slice-ready <slice-key> --json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`<slice-key>` is the slice's export key — the kebab-case slug of its name (`"Place Order"` →
|
|
30
|
+
`place-order`). Don't guess it or hand-slug the name yourself: list every slice's key with
|
|
31
|
+
`em export <model>.em | jq -r '.model.slices[].key'`. Read the JSON document's `ready` field —
|
|
32
|
+
don't infer it from the exit code or any printed text. `ready: true` means: the slice has a doc
|
|
33
|
+
bound via `note "slices/<key>.md"`, its frontmatter is usable, `status: ready-to-implement`,
|
|
34
|
+
every `## Open Questions` checkbox is checked, and no status/version/link incoherence is flagged
|
|
35
|
+
— `gates` names each of those 4 conditions individually (`docBound`/`frontmatterUsable`/
|
|
36
|
+
`statusReady`/`noUncheckedOpenQuestions`) if you need to say which one is blocking.
|
|
37
|
+
|
|
38
|
+
**`ready: false` means stop** — with one named exception: a slice already `status: implemented`
|
|
39
|
+
with `driftSignal: in-sync` or `uncertified` (MIL-214) also reads `ready: false` (its
|
|
40
|
+
`statusReady` gate fails because nothing is newly ratified), and that specific case is
|
|
41
|
+
re-implementation/repair, not a blocker — see §3's third mode before treating it as one. For
|
|
42
|
+
every other `false`, report which `gates`
|
|
43
|
+
entries are `false` (and any `diagnostics` entries concerning this slice) and hand the slice
|
|
44
|
+
back to the humans. Never make the gate pass yourself — checking an open-question box, flipping
|
|
45
|
+
`status`, or editing frontmatter are ratification decisions, and ratification happens in a
|
|
46
|
+
facilitated session, not in an implementation branch.
|
|
47
|
+
|
|
48
|
+
## 2. Read the spec
|
|
49
|
+
|
|
50
|
+
**First, read the project's constitution** — the house rules for *how* implementation happens
|
|
51
|
+
here (stack and architectural shape, which implementation skill each slice pattern routes to,
|
|
52
|
+
code style, testing norms, NFR baselines, review and merge norms). It lives in one of exactly two
|
|
53
|
+
places, never both:
|
|
54
|
+
|
|
55
|
+
- **spec-kit project** (a `.specify/` directory exists at or above the model):
|
|
56
|
+
`.specify/memory/constitution.md` — spec-kit's own slot, which em defers to.
|
|
57
|
+
- **anything else**: `constitution.md` beside the model, where `em scaffold` writes it.
|
|
58
|
+
|
|
59
|
+
`em status <model>.em --json` reports which one applies and whether it's there
|
|
60
|
+
(`conformance[].constitution`) — existence only; nothing in `em` reads or judges its content.
|
|
61
|
+
**Its rules bound every technical choice you make on this slice** (see §4). If it's missing, or
|
|
62
|
+
its `ratifiedBy:` is empty (spec-kit's file: the `**Ratified**:` footer still a placeholder),
|
|
63
|
+
it isn't ratified — go to §7 before writing code.
|
|
64
|
+
|
|
65
|
+
Then read `slices/<slice-key>.md` end to end — every section is load-bearing:
|
|
66
|
+
|
|
67
|
+
| Section | What it is to the implementer |
|
|
68
|
+
|---|---|
|
|
69
|
+
| frontmatter `pattern:` | Which of the four patterns' implementation shapes to build (State Change / State View / Automation / Translation) |
|
|
70
|
+
| Command / Event field tables | The contracts — names, types, validation rules, immutable-fact markers |
|
|
71
|
+
| `## Invariants / Business Rules` (`INV-<MNEMONIC>-n` IDs) | The non-negotiable rules; every one needs a test citing its ID |
|
|
72
|
+
| `## Scenarios (Given / When / Then)` | The acceptance tests, already written — compile them, don't reinvent them |
|
|
73
|
+
| `## Alternate & Error Flows` | Retries, idempotency, compensations — real requirements, not appendix |
|
|
74
|
+
| `## Non-Functional Requirements` | Authz, PII, performance — implement or consciously surface, never skip |
|
|
75
|
+
| `## Dependencies & Read Models Affected` | The blast radius — what else to check before and after |
|
|
76
|
+
|
|
77
|
+
**Interface obligations follow from the model, not from the doc's prose.** The DSL already
|
|
78
|
+
encodes what's reachable — see `em-dsl.md`'s "Headless / API systems & repeated read models"
|
|
79
|
+
section — and the routing from it is mechanical, not a technical choice you make while coding:
|
|
80
|
+
|
|
81
|
+
- A **command with a `ui` trigger** ships the endpoint that dispatches it as part of this slice
|
|
82
|
+
— shape, verb, status codes, and error mapping follow the constitution's interface conventions
|
|
83
|
+
(§7). Because: the model already said this command is reachable from outside; leaving it
|
|
84
|
+
reachable only through an internal gateway silently narrows what the model ratified.
|
|
85
|
+
- A **view with a `ui` consumer** ships the query endpoint as part of this slice, same
|
|
86
|
+
conventions.
|
|
87
|
+
- **No `ui`** on the trigger or the consumer (a command dispatched by a processor or a
|
|
88
|
+
translation, a view read only by a reaction) means internal-only: no endpoint. If one seems
|
|
89
|
+
needed anyway, that's a gap to surface (§4), not a technical choice to make mid-implementation
|
|
90
|
+
— adding a route the model doesn't show is exactly the kind of silent divergence §4 exists to
|
|
91
|
+
catch. An endpoint on a view the model shows no `ui` reading is a gap to surface the same way
|
|
92
|
+
(MIL-215) — conform will classify it as a **model gap**, never drift to delete, once you flag
|
|
93
|
+
it (`../../conform/reference/conform.md`, Flow step 4).
|
|
94
|
+
- **`public` commands, events and views** are the model's published integration surface: their
|
|
95
|
+
shape is a contract, not an implementation detail. `em validate --list-public` lists them;
|
|
96
|
+
`em api generate` writes the model-owned contract (`<model dir>/contracts/<model key>.tsp`).
|
|
97
|
+
Changing a public element's shape is a ratified delta, never an implementation-time choice.
|
|
98
|
+
|
|
99
|
+
For timeline context, read the slice's surroundings in the `.em` (what triggers it, what
|
|
100
|
+
consumes its output) — the slice's own diagram (`slices/<slice-key>.svg`) shows its canonical
|
|
101
|
+
pattern shape. For machine-readable facts, use `em export <model>.em --slice <slice-key>`
|
|
102
|
+
rather than parsing the DSL or the doc's frontmatter yourself: it returns just this slice's
|
|
103
|
+
object — `pattern`, element refs, fields, and the joined doc metadata (`slice.doc.status`,
|
|
104
|
+
`version`, `driftSignal`) — without piping the whole model's export to find one `slice.doc`.
|
|
105
|
+
When the view repeats later via `again` (MIL-208), that same call on the *originating* slice
|
|
106
|
+
also returns `alsoReads: [{ event, atSlice }]` — the union of every event the read model
|
|
107
|
+
consumes across all its later continuations, in timeline order — so implementing it never means
|
|
108
|
+
walking each continuation by hand to assemble the full event list.
|
|
109
|
+
|
|
110
|
+
If the project ships pattern-specific implementation skills (for example an Axon/DCB skill
|
|
111
|
+
set keyed on a slice doc's `pattern:` frontmatter), route by the slice's pattern and follow
|
|
112
|
+
those.
|
|
113
|
+
|
|
114
|
+
## 3. Three modes: first version, ratified delta, re-implementation/repair
|
|
115
|
+
|
|
116
|
+
Check the doc's `version:` and `## Delta` section (or `em export`'s `slice.doc.driftSignal`):
|
|
117
|
+
|
|
118
|
+
- **First implementation** (`version: 1`, no `## Delta`, `driftSignal: never-implemented`):
|
|
119
|
+
green-field slice implementation. Build the whole pattern shape the doc specifies.
|
|
120
|
+
- **Ratified delta** (`version` > 1, `## Delta` present, `status: ready-to-implement` while
|
|
121
|
+
`implementedIn` still names the prior version's PR — `driftSignal: unpropagated-delta`):
|
|
122
|
+
this is a **change to existing, owned code**. The `## Delta` section's typed operations
|
|
123
|
+
(Added/Modified/Removed/Renamed, each with scenarios) scope the work precisely — which
|
|
124
|
+
invariants, which scenarios, which tests change. Touch what the delta names; leave the rest.
|
|
125
|
+
**Never regenerate merged code wholesale from the model** — after merge, code is owned by
|
|
126
|
+
the people who've edited it (generated-then-owned); regeneration is legal only for slices
|
|
127
|
+
whose code never merged.
|
|
128
|
+
- **Re-implementation / repair** (`status: implemented`, `implementedIn` set, `driftSignal:
|
|
129
|
+
in-sync` **or** `uncertified` (MIL-214 — certification status is orthogonal to whether the doc
|
|
130
|
+
changed; most shipped slices sit at `uncertified` until a conform sweep certifies them, which
|
|
131
|
+
doesn't change which mode this is) — `--slice-ready` reports `ready: false` purely because
|
|
132
|
+
`statusReady` fails, with no other gate false and no doc content changed): the doc hasn't
|
|
133
|
+
changed, but the shipped code
|
|
134
|
+
needs rebuilding or fixing — deleted code, a reverted PR, a bug in behavior the doc already
|
|
135
|
+
specifies. **The doc is still the spec.** The gate's `false` here means "nothing new is
|
|
136
|
+
ratified," not "stop" — it is not license to self-initiate: proceed only when a human has
|
|
137
|
+
asked for this specific re-work. Scope the change to what the repair needs, exactly like a
|
|
138
|
+
delta (generated-then-owned still applies — don't regenerate the whole slice wholesale just
|
|
139
|
+
because the gate reads oddly); if what you'd change is really a change in behavior rather than
|
|
140
|
+
a repair of it, that's a ratified delta (the bullet above), not this mode — when unsure which
|
|
141
|
+
one you're in, ask the human rather than guess.
|
|
142
|
+
|
|
143
|
+
No lifecycle flip is needed unless `implementedIn` changes. If it does,
|
|
144
|
+
`em slice mark-implemented <model>.em <slice-key> <new-pr-url>` will **refuse** rather than
|
|
145
|
+
overwrite: a doc already `implemented` with a different `implementedIn` URL is left untouched
|
|
146
|
+
and the command reports the conflict (`src/cli/markImplemented.ts`) instead of silently
|
|
147
|
+
replacing provenance. That refusal is correct, not a bug to route around — never hand-edit the
|
|
148
|
+
frontmatter to force it through. Surface the conflict to the human instead: they decide whether
|
|
149
|
+
the new PR supersedes the recorded one (and re-run `mark-implemented` themselves, or ask you to,
|
|
150
|
+
once they've decided) or whether the existing link should stand.
|
|
151
|
+
|
|
152
|
+
## 4. Gaps: propose, never decide
|
|
153
|
+
|
|
154
|
+
Mid-implementation you will hit things the doc doesn't answer — a field's edge case, an
|
|
155
|
+
undocumented ordering, a contradiction with adjacent code. The discipline:
|
|
156
|
+
|
|
157
|
+
- **Stop that thread and surface it.** State precisely what's unspecified, the options, and
|
|
158
|
+
your recommendation. The human resolves it — at the model, where the resolution lands as an
|
|
159
|
+
answered open question or a small ratified delta alongside your fix, so the decision is
|
|
160
|
+
recorded instead of buried in an implementation diff.
|
|
161
|
+
- **How a delta is ratified on a doc that never shipped** (it is `ready-to-implement` with
|
|
162
|
+
`ratifiedBy` set): once the human has answered, the doc changes by `em slice reratify
|
|
163
|
+
<model>.em <slice-key>` (bumps `version:`, clears the old sign-off, leaves `status` alone),
|
|
164
|
+
the answer is written into the doc, and the human re-signs with `em slice ratify <model>.em
|
|
165
|
+
<slice-key> --by <name>` — on a slice owning a `public` element both commands also need
|
|
166
|
+
`--meaning-unchanged` or `--contract-change "<why>"` (MIL-238). That is the human's step, not
|
|
167
|
+
yours — you never run `ratify`, and
|
|
168
|
+
the doc is not ratified again until they do; resume the build after that.
|
|
169
|
+
- **Never edit the ratified doc to record your own answer**, and never quietly pick a behavior
|
|
170
|
+
a business person could have an opinion on. Silent divergence is the failure mode the whole
|
|
171
|
+
conformance loop exists to catch — don't manufacture it.
|
|
172
|
+
- Purely technical choices with no behavioral surface (private naming, idiomatic structure,
|
|
173
|
+
which assertion library) are yours — **within the constitution's rules** (§2); anything
|
|
174
|
+
observable in behavior, data, or contract is not. If no constitution exists (or its
|
|
175
|
+
`ratifiedBy` is empty), surface that to the human and do not proceed on unilateral style or
|
|
176
|
+
stack decisions for a first slice: run the constitution step (§7) first.
|
|
177
|
+
|
|
178
|
+
## 5. Definition of done
|
|
179
|
+
|
|
180
|
+
**The unit is the slice doc: one slice doc = one PR.** A doc that `covers:` another slice (an
|
|
181
|
+
automation's to-do-list view and its reaction, MIL-121) is one spec, not two — it ships in one
|
|
182
|
+
PR, and `mark-implemented` runs for both keys against the same URL. A read model is one doc,
|
|
183
|
+
even when a `view X again` clause repeats it across later positions on the timeline (MIL-208):
|
|
184
|
+
the later instance is a **continuation** of the slice holding `X`'s first declaration, not a
|
|
185
|
+
spec unit of its own — no doc, no status, no ratification, no PR of its own. Its behavior
|
|
186
|
+
belongs in the originating doc's `## Scenarios` (one scenario per event the later instance
|
|
187
|
+
feeds), not a doc of its own; `em export --slice <originating-key>` lists the full union of
|
|
188
|
+
events the read model consumes across every position via `alsoReads` (§2). Never fold multiple
|
|
189
|
+
slice docs' implementations into one PR because they touch the same read model, ship together,
|
|
190
|
+
or seem small — see §10.
|
|
191
|
+
|
|
192
|
+
- The PR description cites exactly one slice doc (plus its `covers:` keys, if any) and lists
|
|
193
|
+
that doc's invariants alongside the tests that cover them.
|
|
194
|
+
- Every `INV-<MNEMONIC>-n` invariant has at least one test that cites its ID — checked mechanically by
|
|
195
|
+
`em coverage <model>.em --slice <slice-key> --tests <dir> --strict` (MIL-130, MIL-255); run it
|
|
196
|
+
before merge rather than eyeballing citations by hand. `--slice` is what makes this check the
|
|
197
|
+
slice under build: the default form, `em coverage <model>.em --tests <dir>`, counts only slices
|
|
198
|
+
already flipped to `implemented` (MIL-207), and your slice is still `ready-to-implement` until
|
|
199
|
+
the §6 flip — so the default form reports it `inScope: false`, checks nothing, and exits 0. It
|
|
200
|
+
is a regression check for shipped slices, not the definition-of-done check. (`--include-ready`
|
|
201
|
+
is no substitute: it counts every ratified slice, so `--strict` fails on slices nobody has
|
|
202
|
+
started.) A continuation key resolves to its originating slice's doc. If it exits 1 with "not in scope", the slice's doc is not `ready-to-implement`/`implemented` — nothing was checked, so stop and surface it rather than treating the run as a pass.
|
|
203
|
+
- Every scenario in `## Scenarios (Given / When / Then)` exists as a passing test; rejection
|
|
204
|
+
scenarios assert the doc's named rejection reason.
|
|
205
|
+
- Alternate/error flows (idempotency included) are covered by tests.
|
|
206
|
+
- The build and full test suite are green; the model still validates (`em validate` in CI —
|
|
207
|
+
you didn't touch the `.em`, so this only fails if something else broke).
|
|
208
|
+
- Nothing between the slice doc and the code was committed as a source of truth (see §9 —
|
|
209
|
+
work containers are ephemeral; generated or symlinked specs are renderings).
|
|
210
|
+
|
|
211
|
+
## 6. At merge: the lifecycle flip
|
|
212
|
+
|
|
213
|
+
The PR being merged here is the one doc's PR (§5) — its description cites exactly this slice doc
|
|
214
|
+
(plus any `covers:` keys) and nothing else, which is what makes the flip below unambiguous: one
|
|
215
|
+
PR, one `implementedIn` URL, applied to every key that PR's doc covers.
|
|
216
|
+
|
|
217
|
+
When the PR merges, exactly **two** frontmatter fields change on the slice doc:
|
|
218
|
+
|
|
219
|
+
```yaml
|
|
220
|
+
status: implemented
|
|
221
|
+
implementedIn: <PR or commit URL>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
This is supply-loop mechanics, not ratification — it's the one edit an implementing agent makes
|
|
225
|
+
to a slice doc, and it's why `em ledger` deliberately excludes these two fields from what
|
|
226
|
+
counts as content. **Do not bump `version:`** — versions bump only when a delta is ratified;
|
|
227
|
+
a bump here is a ledger defect.
|
|
228
|
+
|
|
229
|
+
`em slice mark-implemented <model>.em <slice-key> <pr-url>` does the flip for you (MIL-103) —
|
|
230
|
+
resolves the doc via the same note-binding join `--slice-ready` uses, is idempotent on a re-run
|
|
231
|
+
with the same URL, and refuses (never silently overwrites) if the doc is already `implemented`
|
|
232
|
+
with a different URL. Prefer it over hand-editing the doc's frontmatter.
|
|
233
|
+
|
|
234
|
+
Then, if the project keeps a model README (from `../../../shared/templates/model-readme.md`), run
|
|
235
|
+
`em slice index <model-name>.em` so its generated Slices table reflects the new status and
|
|
236
|
+
link — never hand-edit that table. The `implementedIn` link is what the `conform` phase later
|
|
237
|
+
uses to anchor drift-checking — leaving it empty blinds the loop.
|
|
238
|
+
|
|
239
|
+
## 7. Before the first slice: the constitution
|
|
240
|
+
|
|
241
|
+
The first time this project's slices reach implementation — or any time §2 finds no constitution,
|
|
242
|
+
or one whose `ratifiedBy` is still empty — **stop and run this short conversation before writing
|
|
243
|
+
code.** It happens once per project, not once per slice.
|
|
244
|
+
|
|
245
|
+
Start from the template the skill bundle ships,
|
|
246
|
+
`../../../shared/templates/constitution.md`. Each of its five sections opens with the
|
|
247
|
+
question to ask; ask them **conversationally, one section at a time**, and write the answers into
|
|
248
|
+
the document as you go — never fill a section by guessing, by reading the codebase and inferring
|
|
249
|
+
"what they probably do", or by pasting the template's own examples. Unanswerable questions get
|
|
250
|
+
parked in the document as open items, exactly like a slice doc's Open Questions:
|
|
251
|
+
|
|
252
|
+
1. **Stack and architectural shape** — languages/runtimes, frameworks, the architectural pattern,
|
|
253
|
+
where a slice's code lives, and the routing table: which implementation skill or approach each
|
|
254
|
+
of the four slice patterns uses (for example, State Change slices → the `axon-*` skill set).
|
|
255
|
+
That table is what you obey in §2 when you read a slice's `pattern:`. This is also where the
|
|
256
|
+
**interface conventions** question gets asked — resource style, error/rejection mapping,
|
|
257
|
+
versioning, auth at the edge — so the shape of every endpoint the interface obligations
|
|
258
|
+
paragraph (§2) and the foundation step (§8) require is decided once, here, instead of
|
|
259
|
+
invented per slice.
|
|
260
|
+
2. **Code style** — formatter/linter, naming, module layout, and what "idiomatic" means here.
|
|
261
|
+
3. **Testing norms** — which test levels each pattern requires, where invariant and scenario
|
|
262
|
+
tests live, and the test-naming convention that lets `em coverage` trace `INV-<MNEMONIC>-n`
|
|
263
|
+
citations.
|
|
264
|
+
4. **NFR baselines** — authz model, PII handling, performance defaults, observability: the
|
|
265
|
+
standing defaults every slice inherits where its own `## Non-Functional Requirements` section
|
|
266
|
+
is silent.
|
|
267
|
+
5. **Review and merge norms** — who reviews, what blocks a merge, and who runs
|
|
268
|
+
`em slice mark-implemented` at merge (§6).
|
|
269
|
+
|
|
270
|
+
**A human ratifies it.** The answers are the project's, not yours — you drafted the wording, they
|
|
271
|
+
sign it off. In the em-native file that's the `ratifiedBy:`/`ratifiedOn:` frontmatter (a named
|
|
272
|
+
person and an ISO date, hand-filled — no `em` command writes this file, and an empty `ratifiedBy:`
|
|
273
|
+
means *draft*). In a spec-kit project it's that file's own `**Ratified**:` footer line — never add
|
|
274
|
+
frontmatter to spec-kit's document. Until it's ratified, treat it as a proposal: you may not
|
|
275
|
+
build a first slice on it.
|
|
276
|
+
|
|
277
|
+
**In a spec-kit project, merge — never duplicate.** The constitution IS
|
|
278
|
+
`.specify/memory/constitution.md`; em writes no second file and neither do you. Append em's five
|
|
279
|
+
sections to it under their own `##` headings, **leaving every existing section byte-untouched** —
|
|
280
|
+
including spec-kit's own `## Core Principles` and `## Governance`, and any principle a team
|
|
281
|
+
already wrote. If a heading of the same name is already there, add to it rather than replacing it,
|
|
282
|
+
and show the human the diff before writing. Two cautions: spec-kit's `/speckit.constitution`
|
|
283
|
+
command rewrites that whole file from its template, so run it (if at all) **before** this
|
|
284
|
+
conversation, never after — and never use it to author em's sections. If the file is still the
|
|
285
|
+
blank stock template (`[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`, … placeholders), say so: filling
|
|
286
|
+
spec-kit's own placeholders is the team's call, and em's sections go in alongside them either way.
|
|
287
|
+
|
|
288
|
+
`em status` will then report `constitution: present` for the model. That's the whole mechanical
|
|
289
|
+
check — em stores and locates this document, and never validates a word of it.
|
|
290
|
+
|
|
291
|
+
## 8. Foundation: contracts first
|
|
292
|
+
|
|
293
|
+
Once per project, before the first slice PR ever opens, land one **foundation PR** that turns
|
|
294
|
+
the model's events — and the cross-cutting shell the constitution names — into code, and
|
|
295
|
+
nothing else. Skip this and the failure is the same on every project that's skipped it: the
|
|
296
|
+
first slice PR ships fine, then the second one needs an event the first slice already defined
|
|
297
|
+
informally, and every PR after that either redefines it slightly differently or reaches into a
|
|
298
|
+
sibling slice's package to reuse it — the boundary the constitution drew is gone within a week.
|
|
299
|
+
|
|
300
|
+
1. **What it contains.** Every event `em export <model>.em` lists in `events[]`, each placed in
|
|
301
|
+
the home the constitution's "where a slice's code lives" rule assigns to its *emitting*
|
|
302
|
+
slice — not a separate shared "events" module, so nothing about where an event lives depends
|
|
303
|
+
on this PR existing rather than the constitution. Fields come verbatim from the slice docs'
|
|
304
|
+
Event tables, with types mapped per the constitution's stack conventions. Add the
|
|
305
|
+
cross-cutting shell the constitution names: shared ports, and the request/response boundary
|
|
306
|
+
and error mapping the interface obligations above (§2) plug their endpoints into. **No
|
|
307
|
+
handlers, no projections — contracts only.** Because: a handler or a projection belongs to
|
|
308
|
+
the slice that owns the behavior behind it; folding one into the foundation PR turns a shared
|
|
309
|
+
contract into a pre-empted slice.
|
|
310
|
+
2. **It merges before any slice PR opens.** Every slice branch is cut *after* the foundation PR
|
|
311
|
+
has landed on `main` — never from a commit that predates it, and never alongside an open,
|
|
312
|
+
unmerged foundation PR. Within an engagement, cut the slice branch from the base the
|
|
313
|
+
engagement plan names (`em engagement plan`); outside an engagement, from `main`. A slice PR
|
|
314
|
+
never carries foundation files. Because: a slice PR opened while the foundation is still in
|
|
315
|
+
review shows a diff dominated by files the slice didn't write and can't be held accountable
|
|
316
|
+
for, and its merge depends on someone else's review timeline instead of its own. The plan's
|
|
317
|
+
base is either `main` or `impl/<upstream>` (the one unmerged upstream slice this slice builds
|
|
318
|
+
on); either way it already contains the foundation.
|
|
319
|
+
|
|
320
|
+
2a. **While a dependent PR is open, the lower PR merges with a merge commit; squash is forbidden
|
|
321
|
+
in that state (it strands the dependent's history).** A PR is the *lower* one when another
|
|
322
|
+
open PR targets its branch as its base. Once no open PR depends on it, the project's usual
|
|
323
|
+
merge strategy applies. Because: a squash rewrites the lower branch's commits into one new
|
|
324
|
+
commit on `main`, so the dependent branch still carries the originals and its diff against
|
|
325
|
+
`main` shows them again — it then needs a hand rebase (`git rebase --onto main <old base
|
|
326
|
+
tip>`). A merge commit keeps the original commits: once the lower branch is merged and
|
|
327
|
+
deleted, the dependent is retargeted to `main` and its diff shrinks to its own commits with
|
|
328
|
+
no rebase.
|
|
329
|
+
|
|
330
|
+
3. **A slice never creates, edits, or reaches into another slice's code.** It *imports* events —
|
|
331
|
+
only events — from wherever the foundation placed them; a sibling slice's handlers, storage,
|
|
332
|
+
and other internals stay off limits. Because: the boundary the constitution drew only holds if
|
|
333
|
+
every slice actually stays inside it — a slice that quietly builds on a sibling's internals has
|
|
334
|
+
erased that boundary informally, one import at a time.
|
|
335
|
+
4. **A ratified delta that adds or changes an event re-runs this step for that event, first.**
|
|
336
|
+
Land the code change for the new or changed event — in its emitting slice's home, following
|
|
337
|
+
rule 1 — before the slice's delta PR opens, exactly as if it were the first pass. Because: the
|
|
338
|
+
same contract-before-consumer ordering that applies once per project applies again every time
|
|
339
|
+
the contract itself changes; an event isn't a stable shared type just because it was one
|
|
340
|
+
yesterday.
|
|
341
|
+
|
|
342
|
+
### Order of work
|
|
343
|
+
|
|
344
|
+
The foundation PR above answers most of "which slice next" by itself — once every event exists
|
|
345
|
+
as a contract, a read slice no longer has to wait for the write slice that will eventually
|
|
346
|
+
produce it. What's left is ordering the slice PRs against each other, and that ordering comes
|
|
347
|
+
from the dependency graph, not from where a slice sits on the timeline:
|
|
348
|
+
|
|
349
|
+
1. **Foundation first removes most ordering constraints.** With every event already landed as a
|
|
350
|
+
contract (rules 1–4 above), a slice's remaining dependency is on other *slices*, not on
|
|
351
|
+
events existing at all — that's what turns "order every slice against every other slice"
|
|
352
|
+
into the short, per-pattern list below.
|
|
353
|
+
2. **Then take dependency order from the graph, not the timeline.** Before starting a slice,
|
|
354
|
+
run `em query upstream <model>.em --of <slice's command-or-view ref>` — anything it returns
|
|
355
|
+
that's still `ready-to-implement` is a candidate to build first; `em query producers
|
|
356
|
+
<model>.em --event <name>` names the slices that own a specific event's producing commands
|
|
357
|
+
when you need to check one directly. Concretely, per pattern:
|
|
358
|
+
- **State Change** with no upstream is always startable — nothing but the foundation gates it.
|
|
359
|
+
- **State View** is startable as soon as the events it reads exist as contracts (the
|
|
360
|
+
foundation alone satisfies this), but build it *after* their producing slices have merged
|
|
361
|
+
when you can — its fixture tests then exercise real commands instead of hand-rolled event
|
|
362
|
+
fixtures.
|
|
363
|
+
- **Automation** goes after both the command it triggers and the to-do-list view it reads
|
|
364
|
+
(bound via `covers:` when the two are written as one doc) — a reaction can't be tested
|
|
365
|
+
against a command handler or a to-do list that doesn't exist yet.
|
|
366
|
+
- **Translation** goes after the command it triggers, same reasoning as an Automation's
|
|
367
|
+
triggered-command dependency.
|
|
368
|
+
3. **Timeline order is the ratification order, not the build order.** Ratifying slices in
|
|
369
|
+
timeline order is deliberate — it's the order stakeholders reason about the business process
|
|
370
|
+
in. Carrying that same order into implementation is the mistake this section exists to head
|
|
371
|
+
off: build order comes from the dependency graph above, and the two orders routinely
|
|
372
|
+
disagree.
|
|
373
|
+
|
|
374
|
+
## 9. Spec-kit projects: the SDD adapter
|
|
375
|
+
|
|
376
|
+
If the repository uses spec-kit (a `.specify/` directory exists), do not hand-author spec-kit
|
|
377
|
+
artifacts — allocate through **em-sdd-bridge**, redirect mode preferred:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
npx em-sdd-bridge@<pinned-version> <slice-key> --symlink
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
That allocates the feature branch and `specs/NNN-slug/` dir, runs the same readiness gates,
|
|
384
|
+
and drops `spec.md` as a **symlink to the slice doc** — the slice doc itself travels through
|
|
385
|
+
plan/tasks as FEATURE_SPEC. The rules that keep redirect mode safe:
|
|
386
|
+
|
|
387
|
+
- **Never run `/speckit.specify`.** The ratified slice *is* the spec; an interactive specify
|
|
388
|
+
session against a defined slice creates a second, unratified source of truth.
|
|
389
|
+
- **`/speckit.clarify` must never write into a slice doc.** Open questions resolve at the
|
|
390
|
+
model (that's what the readiness gate enforced); a ratified slice has nothing to clarify.
|
|
391
|
+
Projects using em-sdd-preset's overlays carry a mechanical guard for this — respect the
|
|
392
|
+
rule even where the guard isn't installed.
|
|
393
|
+
- `/speckit.plan` and `/speckit.tasks` may run against the slice doc directly; the preset's
|
|
394
|
+
redirect preambles map spec-kit's section vocabulary onto the slice doc's sections.
|
|
395
|
+
- **Emission fallback**: where redirect can't work (Windows checkouts without symlink
|
|
396
|
+
privileges, a toolchain that mutates its spec files), run the bridge without `--symlink` to
|
|
397
|
+
render `spec.md` from the slice doc. The generated file is a rendering — never hand-edit it;
|
|
398
|
+
regenerate it from the slice doc instead.
|
|
399
|
+
- Everything under `specs/NNN-*/` is an **ephemeral work container** — one per change effort,
|
|
400
|
+
discardable; the PR is the durable record of the effort, the slice doc the durable
|
|
401
|
+
definition of the behavior.
|
|
402
|
+
|
|
403
|
+
No spec-kit (or any SDD tool)? Implement straight from the slice doc — it already contains
|
|
404
|
+
everything a spec holds. Don't introduce an intermediate spec document of your own.
|
|
405
|
+
|
|
406
|
+
## 10. Never do
|
|
407
|
+
|
|
408
|
+
| Rule | Because |
|
|
409
|
+
|---|---|
|
|
410
|
+
| Never implement from a slice that fails `--slice-ready` | The gate is the handoff contract; bypassing it hands you unratified decisions |
|
|
411
|
+
| Never edit a ratified slice doc, except the two §6 fields at merge | Doc content is ratified; edits outside a session are unratified decisions |
|
|
412
|
+
| Never edit the `.em` model | Model edits are ratified decisions — propose, don't write |
|
|
413
|
+
| Never bump `version:` | Versions move only with ratified deltas; see `em ledger` |
|
|
414
|
+
| Never silently decide unspecified behavior | Silent divergence is the disease the conformance loop exists to catch |
|
|
415
|
+
| Never invent the house rules a first slice needs (stack, style, testing, NFR defaults) | They're the project's decision, ratified in the constitution — §7, not your judgment call |
|
|
416
|
+
| Never regenerate merged code from the model | Generated-then-owned: post-merge code belongs to its owners |
|
|
417
|
+
| Never commit an authored intermediate spec | The slice is the spec; anything between it and the code is a rendering |
|
|
418
|
+
| Never open a slice PR before the foundation PR has merged | The foundation is what makes an event a stable shared contract — a slice built ahead of it is building on a moving target (§8) |
|
|
419
|
+
| Never implement more than one slice doc in a PR | The PR is the durable record of one spec's implementation; `mark-implemented`, coverage, and conformance all key on one doc ↔ one `implementedIn` |
|
|
420
|
+
| Stay on your side of the seam: never edit another model's directory, slice docs or contract file | Another model's `public` element is its owners' decision; a needed change goes to them as a seam change request, not into your PR |
|
|
421
|
+
| Never hand-edit a generated contract (`contracts/*.tsp`) | It is derived from the model by `em api generate`; a hand edit is a contract change nobody ratified |
|
|
422
|
+
|
|
423
|
+
**Mirror image of the design write scope (MIL-236).** The design session never writes generated
|
|
424
|
+
contracts, SDD/spec artifacts (`specs/`, `.specify/`), implementation source, or a draft's
|
|
425
|
+
`version:`, and never reads code as evidence for a modeling decision (see
|
|
426
|
+
`../../../shared/reference/operating-principles.md`, "Write scope and evidence").
|
|
427
|
+
Implementation is the other side: implement reads them; design never writes them. You read the
|
|
428
|
+
contract and the constitution as inputs, work in code and (on spec-kit projects) the `specs/`
|
|
429
|
+
container per §9, and never write the model or its slice docs (except the two §6 fields at
|
|
430
|
+
merge).
|
|
431
|
+
|
|
432
|
+
## 11. Afterward: the loop closes
|
|
433
|
+
|
|
434
|
+
Implementation isn't the end of the slice's story. On a cadence — or whenever someone asks —
|
|
435
|
+
the `conform` phase checks implemented slices against the code, using the `implementedIn` link
|
|
436
|
+
you recorded, and reports drift for humans to rule on (see the `em:conform` skill's
|
|
437
|
+
`reference/conform.md`). Your two
|
|
438
|
+
duties to that future loop are already behind you if you followed this doc: an accurate
|
|
439
|
+
lifecycle flip, and zero silent decisions.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review
|
|
3
|
+
em-version: 1.14.0
|
|
4
|
+
description: >-
|
|
5
|
+
Use when starting em's live browser viewer (`em watch --serve`) so a team can watch a model
|
|
6
|
+
update in real time, or facilitating a SCHEDULED stakeholder walkthrough that steps through
|
|
7
|
+
slices one at a time in Review mode, capturing anything the room raises live as `issue "..."`
|
|
8
|
+
red notes. Drives `em`'s watch and review phases.
|
|
9
|
+
---
|
|
10
|
+
<!-- GENERATED FILE from .claude/skills/event-modeling-review/SKILL.md by scripts/build-plugin.ts — do not hand-edit; run npm run docs:generate -->
|
|
11
|
+
|
|
12
|
+
# Event Modeling — watch & review
|
|
13
|
+
|
|
14
|
+
## Phase: `watch` — live team view
|
|
15
|
+
|
|
16
|
+
Start the watcher with `--serve` in the background:
|
|
17
|
+
`em watch <model-name>.em -o <model-name>.svg --serve` (run_in_background). It re-renders on every
|
|
18
|
+
save and pushes an instant reload to the browser over Server-Sent Events. Tell the user to open the
|
|
19
|
+
URL it prints (e.g. `http://localhost:5173/?svg=<model-name>.svg`) and share their screen — updates
|
|
20
|
+
appear the moment you save, with no polling and no idle churn between edits.
|
|
21
|
+
|
|
22
|
+
The viewer navigates like a map — drag to pan, scroll/pinch to zoom, **Fit** to reset — and its
|
|
23
|
+
**Review mode** steps through slices one at a time (see the `review` phase below). A save that
|
|
24
|
+
fails to render never blanks the shared screen: the last good diagram stays up, an error banner
|
|
25
|
+
explains what went wrong, and the viewer recovers on its own at the next successful render.
|
|
26
|
+
|
|
27
|
+
## Phase: `review` — stakeholder walkthrough
|
|
28
|
+
|
|
29
|
+
Goal: step a real stakeholder review session through the model slice by slice, one slice
|
|
30
|
+
spotlighted at a time, with any open questions the room raises captured live as `issue "..."`
|
|
31
|
+
red notes.
|
|
32
|
+
|
|
33
|
+
**Trigger: a real stakeholder review session is on the calendar — a scheduled use, not
|
|
34
|
+
speculation.** Don't propose this phase proactively; it exists for facilitated reviews with
|
|
35
|
+
non-engineer stakeholders in the room, not routine model editing.
|
|
36
|
+
|
|
37
|
+
Start the same live server as `watch`: `em watch <model-name>.em -o <model-name>.svg --serve`
|
|
38
|
+
(run_in_background). Open the printed URL, click **Review mode** in the header, and share the
|
|
39
|
+
screen. Use Prev/Next (or the left/right arrow keys) to step through slices in declaration
|
|
40
|
+
order — each one pans/zooms into view with everything else dimmed, so the room's attention
|
|
41
|
+
tracks one slice at a time.
|
|
42
|
+
|
|
43
|
+
**When a State View slice is on screen, ask who reads it (MIL-215):** a person or client in the
|
|
44
|
+
room → the `ui` should draw it; another system → `public`; only an automation → nothing, it's
|
|
45
|
+
internal by design and needs no endpoint.
|
|
46
|
+
|
|
47
|
+
**Live capture:** when a stakeholder raises something unresolved, add `issue "..."` to the
|
|
48
|
+
relevant element in the `.em` file and save — exactly the same mechanism `em:conform`
|
|
49
|
+
uses for any other issue. The browser updates over the existing SSE push within moments, without
|
|
50
|
+
losing the current slice or resetting review mode.
|
|
51
|
+
|
|
52
|
+
Wrap-up: run `em validate --list-issues` to sweep everything captured during the session and
|
|
53
|
+
walk each one with the user, same as any open issue. Update the state file's Participants
|
|
54
|
+
section with who attended, and run `em state set-review <date>` to set the `Last stakeholder
|
|
55
|
+
review:` marker (mirrors `Last conformance:`).
|
|
56
|
+
|
|
57
|
+
**Per-slice outcome.** A slice whose open questions are all resolved in the room →
|
|
58
|
+
`em slice review <model>.em <key> --by <name>` (flips its doc to `status: reviewed` and records
|
|
59
|
+
`reviewedBy:`/`reviewedOn:`). Anything still open stays `draft` — the walkthrough doesn't decide
|
|
60
|
+
it, the next session or the open-questions list does.
|
|
61
|
+
|
|
62
|
+
**The facilitator never ratifies, never offers to ratify, and never suggests ratification in a
|
|
63
|
+
review session. Ratification is a separate human gate after review**
|
|
64
|
+
(docs/process.md#the-slice-lifecycle-gates). It is typically multi-person, routed through
|
|
65
|
+
CODEOWNERS on `slices/**`, and it is not this session's to run — `em slice ratify` will itself
|
|
66
|
+
refuse a doc that hasn't been through `em slice review`.
|
|
67
|
+
|
|
68
|
+
End of phase: state file's `Last stakeholder review:` marker updated, every walked slice whose
|
|
69
|
+
questions all closed moved to `status: reviewed`, every issue captured live triaged (resolved on the spot, moved to Open questions / parking lot, or left open on
|
|
70
|
+
purpose). Review doesn't chain to another phase — it's a recurring, scheduled activity like
|
|
71
|
+
`conform`, not a step in the discover → model → slice sequence.
|
|
72
|
+
|
|
73
|
+
Preconditions (tool check, model location) are the same as every other phase — see
|
|
74
|
+
`${CLAUDE_PLUGIN_ROOT}/shared/reference/operating-principles.md`.
|
package/dist/emit/typespec.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { NormalizedModel } from "../model/model.js";
|
|
2
|
-
import { RefsResult } from "../model/refs.js";
|
|
3
|
-
import { Diagnostic } from "../model/validate.js";
|
|
4
|
-
export declare const TYPESPEC_SCHEMA_VERSION = "1.0";
|
|
5
|
-
export interface TypeSpecResult {
|
|
6
|
-
/** TypeSpec source text, no trailing newline. */
|
|
7
|
-
text: string;
|
|
8
|
-
/** Same diagnostics `buildExport` would raise for this model (doc-join warnings, ref
|
|
9
|
-
* collisions, etc.) — the caller decides how to print/gate these, same posture as
|
|
10
|
-
* `buildExport`'s own `diagnostics` field. */
|
|
11
|
-
diagnostics: Diagnostic[];
|
|
12
|
-
/** Human-readable notes about fields whose em type string had no scalar mapping and fell
|
|
13
|
-
* back to `unknown` — informational only, never blocking (POC's "best-effort inference with
|
|
14
|
-
* a warning" choice — see the type-mapping section below). Empty when every included
|
|
15
|
-
* field's type mapped cleanly, or declared no type at all (an untyped field isn't a mapping
|
|
16
|
-
* failure — see `mapFieldType`). */
|
|
17
|
-
unmappedTypes: string[];
|
|
18
|
-
}
|
|
19
|
-
export declare const SCALAR_TYPE_MAP: Readonly<Record<string, string>>;
|
|
20
|
-
/**
|
|
21
|
-
* Build the `em typespec <file>` document: TypeSpec source text for a model's contract
|
|
22
|
-
* surface. Mirrors `buildExport`'s parameter contract exactly (same four inputs, same
|
|
23
|
-
* "already-validated, error-free model" precondition — the caller, cli.ts, applies the same
|
|
24
|
-
* refuse-on-error gate `em export` uses before calling this).
|
|
25
|
-
*/
|
|
26
|
-
export declare function buildTypeSpec(model: NormalizedModel, refs: RefsResult, diagnostics: Diagnostic[], source: string, path: string): TypeSpecResult;
|