@milehimikey/em 1.6.1 → 1.7.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.
Files changed (92) hide show
  1. package/.claude/skills/event-modeling/SKILL.md +60 -12
  2. package/.claude/skills/event-modeling/reference/conform.md +30 -8
  3. package/.claude/skills/event-modeling/reference/em-dsl.md +139 -23
  4. package/.claude/skills/event-modeling/reference/extract.md +2 -1
  5. package/.claude/skills/event-modeling/reference/implement.md +172 -0
  6. package/.claude/skills/event-modeling/templates/conformance-report.md +15 -9
  7. package/.claude/skills/event-modeling/templates/model-readme.md +3 -3
  8. package/.claude/skills/event-modeling/templates/slice.md +70 -4
  9. package/.claude/skills/event-modeling/templates/state.md +6 -5
  10. package/README.md +1 -0
  11. package/dist/catalog/build.d.ts +5 -0
  12. package/dist/catalog/build.js +1 -3
  13. package/dist/catalog/build.js.map +1 -1
  14. package/dist/catalog/docJoin.d.ts +39 -0
  15. package/dist/catalog/docJoin.js +86 -0
  16. package/dist/catalog/docJoin.js.map +1 -0
  17. package/dist/catalog/driftSignal.d.ts +16 -0
  18. package/dist/catalog/driftSignal.js +24 -0
  19. package/dist/catalog/driftSignal.js.map +1 -0
  20. package/dist/catalog/frontmatterCoherenceValidate.d.ts +8 -0
  21. package/dist/catalog/frontmatterCoherenceValidate.js +52 -0
  22. package/dist/catalog/frontmatterCoherenceValidate.js.map +1 -0
  23. package/dist/catalog/lineageValidate.d.ts +9 -0
  24. package/dist/catalog/lineageValidate.js +161 -0
  25. package/dist/catalog/lineageValidate.js.map +1 -0
  26. package/dist/catalog/readSliceDoc.d.ts +2 -0
  27. package/dist/catalog/readSliceDoc.js +21 -0
  28. package/dist/catalog/readSliceDoc.js.map +1 -0
  29. package/dist/catalog/sliceDoc.d.ts +94 -3
  30. package/dist/catalog/sliceDoc.js +157 -7
  31. package/dist/catalog/sliceDoc.js.map +1 -1
  32. package/dist/catalog/sliceReadyValidate.d.ts +11 -0
  33. package/dist/catalog/sliceReadyValidate.js +85 -0
  34. package/dist/catalog/sliceReadyValidate.js.map +1 -0
  35. package/dist/cli/diff-inputs.d.ts +20 -0
  36. package/dist/cli/diff-inputs.js +75 -18
  37. package/dist/cli/diff-inputs.js.map +1 -1
  38. package/dist/cli/ledgerCheck.d.ts +38 -0
  39. package/dist/cli/ledgerCheck.js +116 -0
  40. package/dist/cli/ledgerCheck.js.map +1 -0
  41. package/dist/cli/skillCheck.d.ts +18 -0
  42. package/dist/cli/skillCheck.js +63 -0
  43. package/dist/cli/skillCheck.js.map +1 -0
  44. package/dist/cli/skillSync.d.ts +22 -0
  45. package/dist/cli/skillSync.js +69 -0
  46. package/dist/cli/skillSync.js.map +1 -0
  47. package/dist/cli/skillVersionCheck.d.ts +32 -0
  48. package/dist/cli/skillVersionCheck.js +145 -0
  49. package/dist/cli/skillVersionCheck.js.map +1 -0
  50. package/dist/cli.d.ts +3 -1
  51. package/dist/cli.js +199 -32
  52. package/dist/cli.js.map +1 -1
  53. package/dist/emit/diffJson.d.ts +1 -1
  54. package/dist/emit/diffJson.js +18 -14
  55. package/dist/emit/diffJson.js.map +1 -1
  56. package/dist/emit/json.d.ts +10 -25
  57. package/dist/emit/json.js +70 -103
  58. package/dist/emit/json.js.map +1 -1
  59. package/dist/emit/ledgerJson.d.ts +5 -0
  60. package/dist/emit/ledgerJson.js +25 -0
  61. package/dist/emit/ledgerJson.js.map +1 -0
  62. package/dist/emit/skillCheckJson.d.ts +5 -0
  63. package/dist/emit/skillCheckJson.js +32 -0
  64. package/dist/emit/skillCheckJson.js.map +1 -0
  65. package/dist/model/diff.d.ts +44 -1
  66. package/dist/model/diff.js +51 -9
  67. package/dist/model/diff.js.map +1 -1
  68. package/dist/model/model.d.ts +1 -1
  69. package/dist/model/refs.d.ts +23 -0
  70. package/dist/model/refs.js +75 -0
  71. package/dist/model/refs.js.map +1 -0
  72. package/dist/model/rules.d.ts +252 -0
  73. package/dist/model/rules.js +253 -0
  74. package/dist/model/rules.js.map +1 -0
  75. package/dist/model/validate.d.ts +23 -1
  76. package/dist/model/validate.js +168 -47
  77. package/dist/model/validate.js.map +1 -1
  78. package/dist/parser/ast.d.ts +3 -2
  79. package/dist/parser/parser.js +23 -11
  80. package/dist/parser/parser.js.map +1 -1
  81. package/dist/pipeline.d.ts +9 -0
  82. package/dist/pipeline.js +4 -2
  83. package/dist/pipeline.js.map +1 -1
  84. package/dist/render/sliceStatus.js +1 -1
  85. package/dist/render/sliceStatus.js.map +1 -1
  86. package/dist/util/isMainModule.d.ts +14 -0
  87. package/dist/util/isMainModule.js +33 -0
  88. package/dist/util/isMainModule.js.map +1 -0
  89. package/dist/util/walkDir.d.ts +4 -0
  90. package/dist/util/walkDir.js +28 -0
  91. package/dist/util/walkDir.js.map +1 -0
  92. package/package.json +5 -2
@@ -0,0 +1,252 @@
1
+ import type { Diagnostic, Severity } from "./validate.js";
2
+ export interface RuleDef {
3
+ severity: Severity;
4
+ /** Short human title for a generated table row — not the dynamic per-instance `message`. */
5
+ title: string;
6
+ /** Static, generation-ready fix hint (e.g. "Split them into separate slices."). */
7
+ fix: string;
8
+ /** docs/validation.md H3 anchor this rule nests under, when one exists and covers >1 rule. */
9
+ docAnchor?: string;
10
+ /** True for the 4 `--slice-ready`-only codes (src/catalog/sliceReadyValidate.ts, MIL-87). */
11
+ optIn?: true;
12
+ }
13
+ export declare const RULES: {
14
+ readonly "grid-collision": {
15
+ readonly severity: "error";
16
+ readonly title: "Band collision";
17
+ readonly fix: "Split the colliding elements into separate slices.";
18
+ };
19
+ readonly "automation-shares-slice-with-command": {
20
+ readonly severity: "warning";
21
+ readonly title: "Automation shares slice with its command";
22
+ readonly fix: "Put the triggered command in the next slice.";
23
+ };
24
+ readonly "ui-shares-slice-with-automation": {
25
+ readonly severity: "warning";
26
+ readonly title: "`ui` shares slice with a reaction, no command";
27
+ readonly fix: "Move the `ui` to the read-model slice, or to the slice with the command this triggers.";
28
+ };
29
+ readonly "both-ends-of-a-flow/command-no-event": {
30
+ readonly severity: "warning";
31
+ readonly title: "Command without event";
32
+ readonly fix: "Add the event this command records.";
33
+ readonly docAnchor: "both-ends-of-a-flow";
34
+ };
35
+ readonly "view-no-source": {
36
+ readonly severity: "warning";
37
+ readonly title: "Read model without source";
38
+ readonly fix: "Add `from \"Event\"`, or place the view in a slice with an event.";
39
+ };
40
+ readonly "view-from-unresolved": {
41
+ readonly severity: "error";
42
+ readonly title: "Unknown event source";
43
+ readonly fix: "Fix the `from` reference to name an existing event.";
44
+ };
45
+ readonly "view-from-future-event": {
46
+ readonly severity: "error";
47
+ readonly title: "Backward timeline (view reads a future event)";
48
+ readonly fix: "Move the source to a later `view X again` instance.";
49
+ };
50
+ readonly "fields-completeness/view-field-no-source": {
51
+ readonly severity: "warning";
52
+ readonly title: "View field with no source";
53
+ readonly fix: "Add the field to a source event, or remove it from the view.";
54
+ readonly docAnchor: "fields-completeness";
55
+ };
56
+ readonly "fields-completeness/event-field-no-source": {
57
+ readonly severity: "warning";
58
+ readonly title: "Event field not from a command";
59
+ readonly fix: "Add the field to a command in the slice, or remove it from the event.";
60
+ readonly docAnchor: "fields-completeness";
61
+ };
62
+ readonly "reaction-from-unresolved": {
63
+ readonly severity: "error";
64
+ readonly title: "Unknown read-model source";
65
+ readonly fix: "Project the event into a view first, or fix the `from` reference.";
66
+ };
67
+ readonly "reaction-from-future-view": {
68
+ readonly severity: "error";
69
+ readonly title: "Backward timeline (reaction reads a future view)";
70
+ readonly fix: "Declare the view in or before the reaction's slice.";
71
+ };
72
+ readonly "view-again-without-earlier": {
73
+ readonly severity: "error";
74
+ readonly title: "`again` without an earlier declaration";
75
+ readonly fix: "Declare the view plainly the first time it appears.";
76
+ };
77
+ readonly "both-ends-of-a-flow/command-untriggered": {
78
+ readonly severity: "warning";
79
+ readonly title: "Command with no trigger";
80
+ readonly fix: "Add a `ui` in this slice, or a reaction in the previous slice.";
81
+ readonly docAnchor: "both-ends-of-a-flow";
82
+ };
83
+ readonly "both-ends-of-a-flow/view-unconsumed": {
84
+ readonly severity: "warning";
85
+ readonly title: "Read model with no consumer";
86
+ readonly fix: "Add a `ui` or reaction that consumes it, or drop this instance.";
87
+ readonly docAnchor: "both-ends-of-a-flow";
88
+ };
89
+ readonly "both-ends-of-a-flow/event-unread": {
90
+ readonly severity: "warning";
91
+ readonly title: "Event nobody reads";
92
+ readonly fix: "Project it into a view, or reconsider recording it.";
93
+ readonly docAnchor: "both-ends-of-a-flow";
94
+ };
95
+ readonly "both-ends-of-a-flow/event-unproduced": {
96
+ readonly severity: "warning";
97
+ readonly title: "Event with no producing command";
98
+ readonly fix: "Add the command that records it, or an explicit arrow from one.";
99
+ readonly docAnchor: "both-ends-of-a-flow";
100
+ };
101
+ readonly "both-ends-of-a-flow/ui-unbacked": {
102
+ readonly severity: "warning";
103
+ readonly title: "`ui` with no read model or command";
104
+ readonly fix: "Add a `view` it displays, or the command it triggers.";
105
+ readonly docAnchor: "both-ends-of-a-flow";
106
+ };
107
+ readonly "arrow-backward": {
108
+ readonly severity: "error";
109
+ readonly title: "Backward arrow";
110
+ readonly fix: "Restructure so the target comes later.";
111
+ };
112
+ readonly "connection-legality/illegal-pair": {
113
+ readonly severity: "error";
114
+ readonly title: "Illegal connection";
115
+ readonly fix: "Only ui→command→event→view→ui and view→reaction→command are legal — the message names the missing step.";
116
+ readonly docAnchor: "connection-legality";
117
+ };
118
+ readonly "arrow-unresolved-source": {
119
+ readonly severity: "error";
120
+ readonly title: "Arrow source unresolved";
121
+ readonly fix: "Fix the arrow's source name.";
122
+ };
123
+ readonly "arrow-unresolved-target": {
124
+ readonly severity: "error";
125
+ readonly title: "Arrow target unresolved";
126
+ readonly fix: "Fix the arrow's target name.";
127
+ };
128
+ readonly "open-issue": {
129
+ readonly severity: "warning";
130
+ readonly title: "Open issue";
131
+ readonly fix: "Resolve the question, then remove the `issue` clause.";
132
+ };
133
+ readonly "duplicate-name": {
134
+ readonly severity: "warning";
135
+ readonly title: "Duplicate name";
136
+ readonly fix: "Rename one of the duplicates.";
137
+ };
138
+ readonly "translation-name-collision": {
139
+ readonly severity: "warning";
140
+ readonly title: "Translation name reused for different producers";
141
+ readonly fix: "Use a distinct name per producer to avoid confusion.";
142
+ };
143
+ readonly "duplicate-type-name": {
144
+ readonly severity: "warning";
145
+ readonly title: "Duplicate type name";
146
+ readonly fix: "Rename one of the duplicate `type` declarations.";
147
+ };
148
+ readonly "type-cycle": {
149
+ readonly severity: "error";
150
+ readonly title: "Cyclic type reference";
151
+ readonly fix: "Break the cycle, or route the self/mutual reference through an array.";
152
+ };
153
+ readonly "lineage-ref-malformed": {
154
+ readonly severity: "error";
155
+ readonly title: "Malformed lineage ref";
156
+ readonly fix: "Fix the value to `<slice-key>@v<N>`, or remove it.";
157
+ readonly docAnchor: "lineage";
158
+ };
159
+ readonly "lineage-ref-cycle": {
160
+ readonly severity: "error";
161
+ readonly title: "Lineage cycle";
162
+ readonly fix: "Break the cycle — a slice can't be its own ancestor.";
163
+ readonly docAnchor: "lineage";
164
+ };
165
+ readonly "lineage-forward-dangling": {
166
+ readonly severity: "error";
167
+ readonly title: "Dangling forward lineage ref";
168
+ readonly fix: "Fix the key, or remove the stale successor.";
169
+ readonly docAnchor: "lineage";
170
+ };
171
+ readonly "lineage-version-impossible": {
172
+ readonly severity: "error";
173
+ readonly title: "Impossible lineage version";
174
+ readonly fix: "Fix the referenced version, or ratify the target slice first.";
175
+ readonly docAnchor: "lineage";
176
+ };
177
+ readonly "frontmatter-coherence-implemented-without-link": {
178
+ readonly severity: "warning";
179
+ readonly title: "Implemented without a link";
180
+ readonly fix: "Add `implementedIn` once the slice ships.";
181
+ readonly docAnchor: "frontmatter-coherence";
182
+ };
183
+ readonly "binding-missing-file": {
184
+ readonly severity: "warning";
185
+ readonly title: "Doc binding points at a missing file";
186
+ readonly fix: "Create the slice doc, or fix the `note` path.";
187
+ };
188
+ readonly "frontmatter-invalid": {
189
+ readonly severity: "warning";
190
+ readonly title: "Invalid or missing frontmatter";
191
+ readonly fix: "Add the required frontmatter keys, or add a frontmatter block.";
192
+ };
193
+ readonly "duplicate-slice-name": {
194
+ readonly severity: "warning";
195
+ readonly title: "Duplicate slice name";
196
+ readonly fix: "Rename the slice so its export key is unique.";
197
+ };
198
+ readonly "duplicate-element-ref": {
199
+ readonly severity: "warning";
200
+ readonly title: "Duplicate element ref";
201
+ readonly fix: "Rename the element so its export ref is unique.";
202
+ };
203
+ readonly "duplicate-type-ref": {
204
+ readonly severity: "warning";
205
+ readonly title: "Duplicate type ref";
206
+ readonly fix: "Rename the type so its export ref is unique.";
207
+ };
208
+ readonly "slice-ready-unknown-slice": {
209
+ readonly severity: "error";
210
+ readonly title: "Unknown --slice-ready key";
211
+ readonly fix: "Pass a valid export key that exists in this model.";
212
+ readonly docAnchor: "slice-readiness";
213
+ readonly optIn: true;
214
+ };
215
+ readonly "slice-ready-no-doc-bound": {
216
+ readonly severity: "warning";
217
+ readonly title: "No doc bound";
218
+ readonly fix: "Bind a slice doc via `note \"slices/<key>.md\"`.";
219
+ readonly docAnchor: "slice-readiness";
220
+ readonly optIn: true;
221
+ };
222
+ readonly "slice-ready-status-not-ready": {
223
+ readonly severity: "warning";
224
+ readonly title: "Not ready-to-implement";
225
+ readonly fix: "Set `status: ready-to-implement`.";
226
+ readonly docAnchor: "slice-readiness";
227
+ readonly optIn: true;
228
+ };
229
+ readonly "slice-ready-open-questions-unchecked": {
230
+ readonly severity: "warning";
231
+ readonly title: "Unchecked Open Questions";
232
+ readonly fix: "Check off the remaining Open Questions.";
233
+ readonly docAnchor: "slice-readiness";
234
+ readonly optIn: true;
235
+ };
236
+ };
237
+ export type RuleCode = keyof typeof RULES;
238
+ /** Build one diagnostic, severity looked up from the registry — the per-instance `message`
239
+ * (and optional `line`/`refs`) is all a call site supplies. Throws on an unregistered code:
240
+ * a typo here is a bug in the validator itself, not a model-quality finding, so it fails loud
241
+ * rather than shipping a diagnostic with no matching rule doc. */
242
+ export declare function makeDiag(code: RuleCode, extra: {
243
+ message: string;
244
+ line?: number;
245
+ refs?: string[];
246
+ }): Diagnostic;
247
+ /** `diags.push(makeDiag(...))`, spelled as one call — the common case at every validator site. */
248
+ export declare function pushDiag(diags: Diagnostic[], code: RuleCode, extra: {
249
+ message: string;
250
+ line?: number;
251
+ refs?: string[];
252
+ }): void;
@@ -0,0 +1,253 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // The single declarative registry of every diagnostic `code` `em validate` (and its fs-aware
3
+ // siblings in src/catalog/) can emit — severity, a short human title, and a static "fix" hint,
4
+ // separate from the dynamic per-instance `message` each call site still writes inline (MIL-92).
5
+ //
6
+ // This exists so the skill's own reference docs can be *generated* from the same source the
7
+ // tool executes (scripts/generate-skill-docs.ts) instead of hand-copied and left to drift —
8
+ // the failure mode MIL-86 hit once already. `pushDiag`/`makeDiag` are the enforcement
9
+ // mechanism: severity is looked up here, never hand-typed a second time at the call site, so a
10
+ // code and its severity can't silently disagree, and a code used but never registered throws
11
+ // immediately rather than shipping an undocumented rule.
12
+ //
13
+ // `optIn: true` marks the 4 codes `em validate --slice-ready <key>` adds (MIL-87) — never part
14
+ // of a plain `em validate` run, excluded from the generated base rule reference.
15
+ export const RULES = {
16
+ "grid-collision": {
17
+ severity: "error",
18
+ title: "Band collision",
19
+ fix: "Split the colliding elements into separate slices.",
20
+ },
21
+ "automation-shares-slice-with-command": {
22
+ severity: "warning",
23
+ title: "Automation shares slice with its command",
24
+ fix: "Put the triggered command in the next slice.",
25
+ },
26
+ "ui-shares-slice-with-automation": {
27
+ severity: "warning",
28
+ title: "`ui` shares slice with a reaction, no command",
29
+ fix: "Move the `ui` to the read-model slice, or to the slice with the command this triggers.",
30
+ },
31
+ "both-ends-of-a-flow/command-no-event": {
32
+ severity: "warning",
33
+ title: "Command without event",
34
+ fix: "Add the event this command records.",
35
+ docAnchor: "both-ends-of-a-flow",
36
+ },
37
+ "view-no-source": {
38
+ severity: "warning",
39
+ title: "Read model without source",
40
+ fix: 'Add `from "Event"`, or place the view in a slice with an event.',
41
+ },
42
+ "view-from-unresolved": {
43
+ severity: "error",
44
+ title: "Unknown event source",
45
+ fix: "Fix the `from` reference to name an existing event.",
46
+ },
47
+ "view-from-future-event": {
48
+ severity: "error",
49
+ title: "Backward timeline (view reads a future event)",
50
+ fix: "Move the source to a later `view X again` instance.",
51
+ },
52
+ "fields-completeness/view-field-no-source": {
53
+ severity: "warning",
54
+ title: "View field with no source",
55
+ fix: "Add the field to a source event, or remove it from the view.",
56
+ docAnchor: "fields-completeness",
57
+ },
58
+ "fields-completeness/event-field-no-source": {
59
+ severity: "warning",
60
+ title: "Event field not from a command",
61
+ fix: "Add the field to a command in the slice, or remove it from the event.",
62
+ docAnchor: "fields-completeness",
63
+ },
64
+ "reaction-from-unresolved": {
65
+ severity: "error",
66
+ title: "Unknown read-model source",
67
+ fix: "Project the event into a view first, or fix the `from` reference.",
68
+ },
69
+ "reaction-from-future-view": {
70
+ severity: "error",
71
+ title: "Backward timeline (reaction reads a future view)",
72
+ fix: "Declare the view in or before the reaction's slice.",
73
+ },
74
+ "view-again-without-earlier": {
75
+ severity: "error",
76
+ title: "`again` without an earlier declaration",
77
+ fix: "Declare the view plainly the first time it appears.",
78
+ },
79
+ "both-ends-of-a-flow/command-untriggered": {
80
+ severity: "warning",
81
+ title: "Command with no trigger",
82
+ fix: "Add a `ui` in this slice, or a reaction in the previous slice.",
83
+ docAnchor: "both-ends-of-a-flow",
84
+ },
85
+ "both-ends-of-a-flow/view-unconsumed": {
86
+ severity: "warning",
87
+ title: "Read model with no consumer",
88
+ fix: "Add a `ui` or reaction that consumes it, or drop this instance.",
89
+ docAnchor: "both-ends-of-a-flow",
90
+ },
91
+ "both-ends-of-a-flow/event-unread": {
92
+ severity: "warning",
93
+ title: "Event nobody reads",
94
+ fix: "Project it into a view, or reconsider recording it.",
95
+ docAnchor: "both-ends-of-a-flow",
96
+ },
97
+ "both-ends-of-a-flow/event-unproduced": {
98
+ severity: "warning",
99
+ title: "Event with no producing command",
100
+ fix: "Add the command that records it, or an explicit arrow from one.",
101
+ docAnchor: "both-ends-of-a-flow",
102
+ },
103
+ "both-ends-of-a-flow/ui-unbacked": {
104
+ severity: "warning",
105
+ title: "`ui` with no read model or command",
106
+ fix: "Add a `view` it displays, or the command it triggers.",
107
+ docAnchor: "both-ends-of-a-flow",
108
+ },
109
+ "arrow-backward": {
110
+ severity: "error",
111
+ title: "Backward arrow",
112
+ fix: "Restructure so the target comes later.",
113
+ },
114
+ "connection-legality/illegal-pair": {
115
+ severity: "error",
116
+ title: "Illegal connection",
117
+ fix: "Only ui→command→event→view→ui and view→reaction→command are legal — the message names the missing step.",
118
+ docAnchor: "connection-legality",
119
+ },
120
+ "arrow-unresolved-source": {
121
+ severity: "error",
122
+ title: "Arrow source unresolved",
123
+ fix: "Fix the arrow's source name.",
124
+ },
125
+ "arrow-unresolved-target": {
126
+ severity: "error",
127
+ title: "Arrow target unresolved",
128
+ fix: "Fix the arrow's target name.",
129
+ },
130
+ "open-issue": {
131
+ severity: "warning",
132
+ title: "Open issue",
133
+ fix: "Resolve the question, then remove the `issue` clause.",
134
+ },
135
+ "duplicate-name": {
136
+ severity: "warning",
137
+ title: "Duplicate name",
138
+ fix: "Rename one of the duplicates.",
139
+ },
140
+ "translation-name-collision": {
141
+ severity: "warning",
142
+ title: "Translation name reused for different producers",
143
+ fix: "Use a distinct name per producer to avoid confusion.",
144
+ },
145
+ "duplicate-type-name": {
146
+ severity: "warning",
147
+ title: "Duplicate type name",
148
+ fix: "Rename one of the duplicate `type` declarations.",
149
+ },
150
+ "type-cycle": {
151
+ severity: "error",
152
+ title: "Cyclic type reference",
153
+ fix: "Break the cycle, or route the self/mutual reference through an array.",
154
+ },
155
+ "lineage-ref-malformed": {
156
+ severity: "error",
157
+ title: "Malformed lineage ref",
158
+ fix: "Fix the value to `<slice-key>@v<N>`, or remove it.",
159
+ docAnchor: "lineage",
160
+ },
161
+ "lineage-ref-cycle": {
162
+ severity: "error",
163
+ title: "Lineage cycle",
164
+ fix: "Break the cycle — a slice can't be its own ancestor.",
165
+ docAnchor: "lineage",
166
+ },
167
+ "lineage-forward-dangling": {
168
+ severity: "error",
169
+ title: "Dangling forward lineage ref",
170
+ fix: "Fix the key, or remove the stale successor.",
171
+ docAnchor: "lineage",
172
+ },
173
+ "lineage-version-impossible": {
174
+ severity: "error",
175
+ title: "Impossible lineage version",
176
+ fix: "Fix the referenced version, or ratify the target slice first.",
177
+ docAnchor: "lineage",
178
+ },
179
+ "frontmatter-coherence-implemented-without-link": {
180
+ severity: "warning",
181
+ title: "Implemented without a link",
182
+ fix: "Add `implementedIn` once the slice ships.",
183
+ docAnchor: "frontmatter-coherence",
184
+ },
185
+ "binding-missing-file": {
186
+ severity: "warning",
187
+ title: "Doc binding points at a missing file",
188
+ fix: "Create the slice doc, or fix the `note` path.",
189
+ },
190
+ "frontmatter-invalid": {
191
+ severity: "warning",
192
+ title: "Invalid or missing frontmatter",
193
+ fix: "Add the required frontmatter keys, or add a frontmatter block.",
194
+ },
195
+ "duplicate-slice-name": {
196
+ severity: "warning",
197
+ title: "Duplicate slice name",
198
+ fix: "Rename the slice so its export key is unique.",
199
+ },
200
+ "duplicate-element-ref": {
201
+ severity: "warning",
202
+ title: "Duplicate element ref",
203
+ fix: "Rename the element so its export ref is unique.",
204
+ },
205
+ "duplicate-type-ref": {
206
+ severity: "warning",
207
+ title: "Duplicate type ref",
208
+ fix: "Rename the type so its export ref is unique.",
209
+ },
210
+ "slice-ready-unknown-slice": {
211
+ severity: "error",
212
+ title: "Unknown --slice-ready key",
213
+ fix: "Pass a valid export key that exists in this model.",
214
+ docAnchor: "slice-readiness",
215
+ optIn: true,
216
+ },
217
+ "slice-ready-no-doc-bound": {
218
+ severity: "warning",
219
+ title: "No doc bound",
220
+ fix: 'Bind a slice doc via `note "slices/<key>.md"`.',
221
+ docAnchor: "slice-readiness",
222
+ optIn: true,
223
+ },
224
+ "slice-ready-status-not-ready": {
225
+ severity: "warning",
226
+ title: "Not ready-to-implement",
227
+ fix: "Set `status: ready-to-implement`.",
228
+ docAnchor: "slice-readiness",
229
+ optIn: true,
230
+ },
231
+ "slice-ready-open-questions-unchecked": {
232
+ severity: "warning",
233
+ title: "Unchecked Open Questions",
234
+ fix: "Check off the remaining Open Questions.",
235
+ docAnchor: "slice-readiness",
236
+ optIn: true,
237
+ },
238
+ };
239
+ /** Build one diagnostic, severity looked up from the registry — the per-instance `message`
240
+ * (and optional `line`/`refs`) is all a call site supplies. Throws on an unregistered code:
241
+ * a typo here is a bug in the validator itself, not a model-quality finding, so it fails loud
242
+ * rather than shipping a diagnostic with no matching rule doc. */
243
+ export function makeDiag(code, extra) {
244
+ const rule = RULES[code];
245
+ if (!rule)
246
+ throw new Error(`makeDiag: unknown rule code "${code}" — register it in src/model/rules.ts`);
247
+ return { severity: rule.severity, code, ...extra };
248
+ }
249
+ /** `diags.push(makeDiag(...))`, spelled as one call — the common case at every validator site. */
250
+ export function pushDiag(diags, code, extra) {
251
+ diags.push(makeDiag(code, extra));
252
+ }
253
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/model/rules.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,35 @@
1
1
  import { Grid } from "../layout/grid.js";
2
2
  import { Element, NormalizedModel } from "./model.js";
3
+ import type { RefsResult } from "./refs.js";
3
4
  export type Severity = "error" | "warning";
4
5
  export interface Diagnostic {
5
6
  severity: Severity;
7
+ /** Stable, CI-matchable rule identifier (MIL-91) — the contract; `message` is prose and may
8
+ * be reworded freely. One code per distinct rule; nested under a docs/validation.md H3
9
+ * anchor (`both-ends-of-a-flow/...`, `fields-completeness/...`, `connection-legality/...`)
10
+ * where one exists and covers more than one rule. */
11
+ code: string;
6
12
  message: string;
7
13
  line?: number;
14
+ /** Export-stable refs/keys (from `computeRefs()`) of every entity this diagnostic concerns —
15
+ * 0, 1, or more (e.g. a duplicate-name collision concerns two elements). Omitted, not `[]`,
16
+ * at sites with no specific entity to point at. Never a second identifier scheme — always
17
+ * sourced from the same `RefsResult` `em export`/`em diff` use. */
18
+ refs?: string[];
8
19
  }
9
- export declare function validate(model: NormalizedModel, grid: Grid): Diagnostic[];
20
+ export declare function validate(model: NormalizedModel, grid: Grid, refs: RefsResult): Diagnostic[];
10
21
  export declare function hasErrors(diags: Diagnostic[]): boolean;
11
22
  /** Pretty one-line diagnostic for terminal output. */
12
23
  export declare function formatDiagnostic(d: Diagnostic): string;
24
+ /** JSON-shaped diagnostic — `line`/`refs` widened to explicit `null`/`[]`, same convention
25
+ * every other optional export field uses. Shared by `em export` (`emit/json.ts`) and `em
26
+ * diff --json` (`emit/diffJson.ts`, which spreads `{ side, ...serializeDiagnostic(d) }`) so
27
+ * the shape is defined once, next to the `Diagnostic` type it serializes. */
28
+ export declare function serializeDiagnostic(d: Diagnostic): {
29
+ severity: Severity;
30
+ code: string;
31
+ message: string;
32
+ line: number | null;
33
+ refs: string[];
34
+ };
13
35
  export type { Element };