@ema.co/mcp-toolkit 2026.1.27 → 2026.1.28-2

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.

Potentially problematic release.


This version of @ema.co/mcp-toolkit might be problematic. Click here for more details.

Files changed (35) hide show
  1. package/dist/mcp/handlers/data/index.js +3 -0
  2. package/dist/mcp/handlers/persona/create.js +16 -0
  3. package/dist/mcp/handlers/persona/list.js +9 -4
  4. package/dist/mcp/handlers/persona/update.js +24 -2
  5. package/dist/mcp/handlers/workflow/deploy.js +20 -2
  6. package/dist/mcp/handlers/workflow/generate.js +39 -2
  7. package/dist/mcp/handlers/workflow/index.js +8 -3
  8. package/dist/mcp/handlers/workflow/modify.js +34 -7
  9. package/dist/mcp/handlers/workflow/validate.js +85 -0
  10. package/dist/mcp/handlers/workflow/validation.js +160 -0
  11. package/dist/mcp/resources.js +286 -4
  12. package/dist/mcp/server.js +16 -3
  13. package/dist/mcp/tools.js +32 -11
  14. package/dist/sdk/client.js +36 -9
  15. package/dist/sdk/ema-client.js +32 -4
  16. package/dist/sdk/index.js +3 -1
  17. package/dist/sdk/knowledge.js +5 -5
  18. package/dist/sdk/structural-rules.js +498 -0
  19. package/dist/sdk/workflow-generator.js +2 -1
  20. package/dist/sdk/workflow-intent.js +28 -96
  21. package/dist/sdk/workflow-path-enumerator.js +278 -0
  22. package/dist/sdk/workflow-static-validator.js +291 -0
  23. package/dist/sdk/workflow-validation-types.js +7 -0
  24. package/docs/README.md +14 -0
  25. package/docs/go-validator-analysis.md +323 -0
  26. package/docs/rule-format-specification.md +346 -0
  27. package/docs/validation-contract.md +397 -0
  28. package/docs/validation-error-format.md +326 -0
  29. package/package.json +1 -1
  30. package/dist/mcp/workflow-operations.js +0 -100
  31. package/dist/sdk/workflow-fixer.js +0 -48
  32. package/docs/dashboard-operations.md +0 -281
  33. package/docs/ema-user-guide.md +0 -1201
  34. package/docs/email-patterns.md +0 -120
  35. package/docs/mcp-tools-guide.md +0 -575
@@ -0,0 +1,397 @@
1
+ # Validation Contract - Go to TypeScript Compatibility
2
+
3
+ **Date**: 2026-01-27
4
+ **Purpose**: Define exact semantics for TypeScript validator to match Go validator behavior
5
+
6
+ ---
7
+
8
+ ## Core Validation Algorithm
9
+
10
+ ### Overview
11
+
12
+ The Go validator performs **static validation** by:
13
+ 1. Enumerating all possible execution paths in a workflow
14
+ 2. Validating each path for named results compliance
15
+ 3. Reporting errors for paths that fail validation
16
+
17
+ ### Key Principle
18
+
19
+ **Static validation only applies to workflows with named results.**
20
+ - If `workflow.Proto.NamedResults` is empty, validation is skipped
21
+ - This is intentional - workflows without named results don't need path validation
22
+
23
+ ---
24
+
25
+ ## Path Enumeration Algorithm
26
+
27
+ ### Step 1: Create Initial Session
28
+
29
+ ```go
30
+ initialSession, err := CreateValidationWorkflowSession(ctx, workflow, logger)
31
+ ```
32
+
33
+ Creates a validation session with:
34
+ - Dummy workflow inputs (type-aware)
35
+ - Dummy widget configs (type-aware)
36
+ - Empty action states
37
+ - Static validation strategy
38
+
39
+ ### Step 2: Process Session Queue
40
+
41
+ Main loop:
42
+ ```go
43
+ sessionsToProcess := []ValidationWorkflowSession{initialSession}
44
+ for len(sessionsToProcess) > 0 {
45
+ session := sessionsToProcess[0]
46
+ sessionsToProcess = sessionsToProcess[1:]
47
+
48
+ result, err := session.RunValidation(ctx)
49
+ // Handle result...
50
+ }
51
+ ```
52
+
53
+ ### Step 3: Handle Branching
54
+
55
+ When `result.Outcome == OutcomeBranch`:
56
+
57
+ 1. **Identify Branching Action**: Action with enumerable output (enum or boolean)
58
+ 2. **Get Possible Values**: All enum options or [true, false] for boolean
59
+ 3. **Fork Session**: Create one session per possible value
60
+ 4. **Plug Dummy Values**:
61
+ - For branching output: Use chosen value
62
+ - For other outputs: Generate type-aware dummy values
63
+ 5. **Mark Action Complete**: Mark branching action as completed in forked session
64
+ 6. **Queue New Sessions**: Add all forked sessions to queue
65
+
66
+ **Branching Actions**:
67
+ - Categorizers (enum output: category)
68
+ - Boolean outputs (true/false)
69
+ - Any action with enumerable output
70
+
71
+ **Non-Branching Actions**:
72
+ - Generate type-aware dummy outputs for all outputs
73
+ - Mark action as completed
74
+ - Continue traversal
75
+
76
+ ### Step 4: Handle Completion
77
+
78
+ When `result.Outcome == OutcomeCompleted`:
79
+
80
+ 1. **Track Completed Path**:
81
+ - Completed actions (topological order)
82
+ - Final outputs produced
83
+ - Path identifier (branching action + value, or last action)
84
+
85
+ 2. **Validate Named Results**:
86
+ - Check if all named results are produced
87
+ - Check for multiple writers
88
+ - Check for response/abstain
89
+ - Apply custom validators (persona-type specific)
90
+
91
+ 3. **Store Path Info**: Add to `completedSessionMap`
92
+
93
+ ### Step 5: Cleanup
94
+
95
+ Remove incomplete sessions (those that only branched but never completed).
96
+
97
+ ---
98
+
99
+ ## Validation Error Types
100
+
101
+ ### 1. RESULT_ERROR_TYPE_REQUIRED_OUTPUT_NOT_PRODUCED
102
+
103
+ **Definition**: A named result is not produced on at least one execution path.
104
+
105
+ **Detection**:
106
+ - For each named result in `workflow.Proto.NamedResults`
107
+ - For each completed path in `completedSessionMap`
108
+ - Check if named result is in `FinalOutputs` of that path
109
+ - If missing on any path → error
110
+
111
+ **Path Identification**:
112
+ - If path branched: `{actionName: branching_action, outputName: category, outputValue: chosen_value}`
113
+ - If path didn't branch: `{actionName: last_completed_action}`
114
+
115
+ **Example**:
116
+ ```
117
+ Named result: "response_with_sources"
118
+ Path "Billing" (from categorizer, value="Billing") does not produce it
119
+ → Error: RESULT_ERROR_TYPE_REQUIRED_OUTPUT_NOT_PRODUCED
120
+ ```
121
+
122
+ ### 2. RESULT_ERROR_TYPE_MULTIPLE_WRITERS
123
+
124
+ **Definition**: Multiple actions produce the same named result on the same execution path.
125
+
126
+ **Detection**:
127
+ - For each named result
128
+ - For each completed path
129
+ - Count how many actions produce that result
130
+ - If count > 1 on any path → error
131
+
132
+ **Note**: This may be intentional (aggregation), but Go validator flags it as error.
133
+
134
+ **Path Identification**: Same as above.
135
+
136
+ **Example**:
137
+ ```
138
+ Named result: "response_with_sources"
139
+ Path "Billing" has both "respond_1" and "respond_2" producing it
140
+ → Error: RESULT_ERROR_TYPE_MULTIPLE_WRITERS
141
+ ```
142
+
143
+ ### 3. RESULT_ERROR_TYPE_MISSING_RESPONSE_OR_ABSTAIN_REASON
144
+
145
+ **Definition**: An execution path does not produce a response and does not have an abstain reason.
146
+
147
+ **Detection**:
148
+ - For each completed path
149
+ - Check if path produces any response output:
150
+ - `respond_with_sources.response_with_sources`
151
+ - `call_llm.llm_output`
152
+ - `fixed_response.response`
153
+ - Other response-like outputs
154
+ - If no response AND no abstain reason → error
155
+
156
+ **Abstain Reason**: TBD - need to check how this is defined in Go code.
157
+
158
+ **Path Identification**: Same as above.
159
+
160
+ **Example**:
161
+ ```
162
+ Path "Billing" ends at "search" node
163
+ No response node connected
164
+ No abstain reason specified
165
+ → Error: RESULT_ERROR_TYPE_MISSING_RESPONSE_OR_ABSTAIN_REASON
166
+ ```
167
+
168
+ ### 4. RESULT_ERROR_TYPE_CATEGORY_HIERARCHY_VIOLATION
169
+
170
+ **Definition**: Categorizer category structure violates hierarchy rules.
171
+
172
+ **Detection**: TBD - need to analyze `named_result_agent_assist_validator.go`
173
+
174
+ **Path Identification**: Same as above.
175
+
176
+ **Example**: TBD
177
+
178
+ ---
179
+
180
+ ## Path Identification Rules
181
+
182
+ ### Rule 1: Branching Path Identification
183
+
184
+ If path was created by branching action:
185
+ ```
186
+ {
187
+ actionName: "<branching_action_name>",
188
+ outputName: "<branching_output_name>",
189
+ outputValue: "<chosen_value>"
190
+ }
191
+ ```
192
+
193
+ **Example**:
194
+ ```
195
+ {
196
+ actionName: "chat_categorizer",
197
+ outputName: "category",
198
+ outputValue: "Billing"
199
+ }
200
+ ```
201
+
202
+ ### Rule 2: Non-Branching Path Identification
203
+
204
+ If path had no branching action:
205
+ ```
206
+ {
207
+ actionName: "<last_completed_action_name>"
208
+ }
209
+ ```
210
+
211
+ **Example**:
212
+ ```
213
+ {
214
+ actionName: "respond_with_sources"
215
+ }
216
+ ```
217
+
218
+ ### Rule 3: Empty Path
219
+
220
+ If no actions were executed (shouldn't happen, but handle gracefully):
221
+ ```
222
+ {
223
+ actionName: ""
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Dummy Value Generation
230
+
231
+ ### For Workflow Inputs
232
+
233
+ - Generate type-aware dummy values based on input type
234
+ - Use `util.CreateTypeAwareDummyValue(type, enumTypes)`
235
+ - Validate type compatibility
236
+
237
+ ### For Widget Configs
238
+
239
+ - Generate type-aware dummy values based on widget type
240
+ - Use same utility function
241
+ - Validate type compatibility
242
+
243
+ ### For Action Outputs (Non-Branching)
244
+
245
+ - Generate type-aware dummy values for all outputs
246
+ - Use `getDummyValueForActionOutput(outputDef, enumTypes)`
247
+ - Based on output type definition
248
+
249
+ ### For Action Outputs (Branching)
250
+
251
+ - For branching output: Use chosen value (enum option or boolean)
252
+ - For other outputs: Generate type-aware dummy values
253
+
254
+ ---
255
+
256
+ ## Custom Validators
257
+
258
+ ### Interface
259
+
260
+ ```go
261
+ type CustomNamedResultValidator interface {
262
+ Validate(workflow *WorkflowGraph, pathInfo *completedPathInfo) error
263
+ }
264
+ ```
265
+
266
+ ### Behavior
267
+
268
+ - Called after general named result validations pass
269
+ - Only called if `!pathInfo.NamedResultsValidationsFailed`
270
+ - Can add persona-type specific rules
271
+ - Example: `named_result_agent_assist_validator.go` for Agent Assist personas
272
+
273
+ ### Implementation Note
274
+
275
+ - TypeScript validator should support plugin system for custom validators
276
+ - For now, focus on the 4 core error types
277
+ - Custom validators can be added later
278
+
279
+ ---
280
+
281
+ ## Error Message Format (Go)
282
+
283
+ ### Structure
284
+
285
+ ```go
286
+ type WorkflowError_NamedResultError struct {
287
+ ErrorType pb.WorkflowError_ResultErrorType
288
+ NamedResultName string
289
+ PathIdentifier *WorkflowError_ActionOutput
290
+ Message string
291
+ }
292
+ ```
293
+
294
+ ### Path Identifier
295
+
296
+ ```go
297
+ type WorkflowError_ActionOutput struct {
298
+ ActionName string
299
+ OutputName string // Optional, only for branching
300
+ OutputValue string // Optional, only for branching
301
+ }
302
+ ```
303
+
304
+ ### Message Format
305
+
306
+ TBD - need to analyze actual error messages from Go code.
307
+
308
+ ---
309
+
310
+ ## TypeScript Compatibility Requirements
311
+
312
+ ### Must Match
313
+
314
+ 1. **Error Types**: All 4 error types must be detected
315
+ 2. **Path Enumeration**: Same algorithm (topological sort + DFS + forking)
316
+ 3. **Path Identification**: Same format (actionName, outputName, outputValue)
317
+ 4. **Validation Logic**: Same checks (required outputs, multiple writers, etc.)
318
+
319
+ ### Can Differ
320
+
321
+ 1. **Error Message Format**: Can be enhanced (what/why/how)
322
+ 2. **Performance**: Can optimize (caching, early pruning)
323
+ 3. **Additional Validations**: Can add more (but document as extensions)
324
+
325
+ ---
326
+
327
+ ## Test Cases
328
+
329
+ ### Test Case 1: Simple Linear Workflow
330
+
331
+ ```
332
+ trigger → action1 → action2 → respond → WORKFLOW_OUTPUT
333
+ Named result: "response"
334
+
335
+ Expected: ✅ Valid (all paths produce response)
336
+ ```
337
+
338
+ ### Test Case 2: Categorizer with Missing Response
339
+
340
+ ```
341
+ trigger → categorizer → [Billing branch] → search → (no response)
342
+ Named result: "response"
343
+
344
+ Expected: ❌ Error: RESULT_ERROR_TYPE_REQUIRED_OUTPUT_NOT_PRODUCED
345
+ Path: {actionName: "categorizer", outputName: "category", outputValue: "Billing"}
346
+ ```
347
+
348
+ ### Test Case 3: Multiple Writers
349
+
350
+ ```
351
+ trigger → categorizer → [Billing] → respond1 → WORKFLOW_OUTPUT
352
+ → [Billing] → respond2 → WORKFLOW_OUTPUT
353
+ Named result: "response" (both respond1 and respond2 produce it)
354
+
355
+ Expected: ❌ Error: RESULT_ERROR_TYPE_MULTIPLE_WRITERS
356
+ Path: {actionName: "categorizer", outputName: "category", outputValue: "Billing"}
357
+ ```
358
+
359
+ ### Test Case 4: Missing Response/Abstain
360
+
361
+ ```
362
+ trigger → categorizer → [Billing] → search → (ends, no response, no abstain)
363
+ Named result: "response"
364
+
365
+ Expected: ❌ Error: RESULT_ERROR_TYPE_MISSING_RESPONSE_OR_ABSTAIN_REASON
366
+ Path: {actionName: "categorizer", outputName: "category", outputValue: "Billing"}
367
+ ```
368
+
369
+ ---
370
+
371
+ ## Performance Considerations
372
+
373
+ ### Timeout Limits
374
+
375
+ - Target: <100ms for typical workflows
376
+ - Max paths: Prevent exponential explosion (suggest 1000 paths max)
377
+ - Early pruning: Stop if path is obviously invalid
378
+
379
+ ### Optimization Opportunities
380
+
381
+ 1. **Path Pruning**: If path already missing required output, don't continue
382
+ 2. **Caching**: Cache validation results for unchanged workflows
383
+ 3. **Incremental**: Only validate changed paths (future enhancement)
384
+
385
+ ---
386
+
387
+ ## Open Questions
388
+
389
+ 1. **Abstain Reason**: How is abstain reason defined/stored?
390
+ 2. **Category Hierarchy**: What are the exact hierarchy rules?
391
+ 3. **Custom Validators**: What persona types have custom validators?
392
+ 4. **Error Messages**: What's the exact Go error message format?
393
+
394
+ ---
395
+
396
+ **Status**: ✅ Contract defined
397
+ **Next**: Analyze Go code for missing details, then implement TypeScript validator
@@ -0,0 +1,326 @@
1
+ # Validation Error Format Specification
2
+
3
+ **Date**: 2026-01-27
4
+ **Purpose**: Define enhanced error message format for TypeScript validator
5
+
6
+ ---
7
+
8
+ ## Design Principles
9
+
10
+ 1. **Actionable**: Users must know what to fix
11
+ 2. **Clear**: Explain what's wrong and why
12
+ 3. **Specific**: Point to exact location (node, edge, path)
13
+ 4. **Helpful**: Provide remediation steps
14
+ 5. **Referenceable**: Link to rule documentation
15
+
16
+ ---
17
+
18
+ ## Error Response Structure
19
+
20
+ ### TypeScript Interface
21
+
22
+ ```typescript
23
+ export interface ValidationError {
24
+ // Identification
25
+ type: ValidationErrorType;
26
+ rule_id: string;
27
+ severity: "critical" | "warning" | "info";
28
+
29
+ // Location
30
+ location: {
31
+ node_id?: string;
32
+ edge_id?: string;
33
+ path?: string[]; // Execution path: ["trigger", "categorizer", "billing_branch", "search"]
34
+ category?: string; // Category name if categorizer-related
35
+ named_result?: string; // Named result name if applicable
36
+ };
37
+
38
+ // Explanation (Enhanced)
39
+ what: string; // What is wrong (specific)
40
+ why: string; // Why it's wrong (explanation)
41
+ how_to_fix: string; // How to fix (actionable steps)
42
+
43
+ // Reference
44
+ rule_reference: string; // URI to rule: "ema://validation/rules#required_output_all_paths"
45
+
46
+ // Examples (Optional)
47
+ examples?: {
48
+ bad: string; // Bad pattern example
49
+ good: string; // Good pattern example
50
+ };
51
+ }
52
+
53
+ export interface ValidationResult {
54
+ valid: boolean;
55
+ errors: ValidationError[];
56
+ warnings: ValidationError[];
57
+ info: ValidationError[];
58
+ summary: {
59
+ total_paths: number;
60
+ valid_paths: number;
61
+ invalid_paths: number;
62
+ errors_by_type: Record<ValidationErrorType, number>;
63
+ };
64
+ }
65
+
66
+ export type ValidationErrorType =
67
+ | "required_output_not_produced"
68
+ | "multiple_writers"
69
+ | "missing_response_or_abstain_reason"
70
+ | "category_hierarchy_violation";
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Error Type Specifications
76
+
77
+ ### 1. required_output_not_produced
78
+
79
+ **Rule ID**: `required_output_all_paths`
80
+
81
+ **What**:
82
+ ```
83
+ "Path '{path_name}' does not produce required output '{named_result}'"
84
+ ```
85
+
86
+ **Why**:
87
+ ```
88
+ "All execution paths from trigger must produce all named results. The path '{path_name}' ends at '{last_node}' without producing '{named_result}'."
89
+ ```
90
+
91
+ **How to Fix**:
92
+ ```
93
+ "Add a node that produces '{named_result}' to the '{path_name}' path. Connect the node's '{output_name}' output to WORKFLOW_OUTPUT via resultMappings."
94
+ ```
95
+
96
+ **Example**:
97
+ ```json
98
+ {
99
+ "type": "required_output_not_produced",
100
+ "rule_id": "required_output_all_paths",
101
+ "severity": "critical",
102
+ "location": {
103
+ "path": ["trigger", "categorizer", "billing_branch", "search"],
104
+ "category": "Billing",
105
+ "named_result": "response_with_sources"
106
+ },
107
+ "what": "Path 'Billing' does not produce required output 'response_with_sources'",
108
+ "why": "All execution paths from trigger must produce all named results. The path 'Billing' ends at 'search' node without producing 'response_with_sources'.",
109
+ "how_to_fix": "Add a response node (respond_with_sources, call_llm, or fixed_response) after the 'search' node in the 'Billing' branch. Connect the response node's output to WORKFLOW_OUTPUT via resultMappings.",
110
+ "rule_reference": "ema://validation/rules#required_output_all_paths",
111
+ "examples": {
112
+ "bad": "trigger → categorizer → [Billing] → search → (no response)",
113
+ "good": "trigger → categorizer → [Billing] → search → respond_with_sources → WORKFLOW_OUTPUT"
114
+ }
115
+ }
116
+ ```
117
+
118
+ ---
119
+
120
+ ### 2. multiple_writers
121
+
122
+ **Rule ID**: `single_writer_per_output`
123
+
124
+ **What**:
125
+ ```
126
+ "Multiple nodes produce '{named_result}' on path '{path_name}'"
127
+ ```
128
+
129
+ **Why**:
130
+ ```
131
+ "A single named result can only have one producer per execution path. The path '{path_name}' has both '{node1}' and '{node2}' producing '{named_result}'."
132
+ ```
133
+
134
+ **How to Fix**:
135
+ ```
136
+ "Ensure only one node produces '{named_result}' on the '{path_name}' path. Either remove one of the producers or use different named results for each node."
137
+ ```
138
+
139
+ **Example**:
140
+ ```json
141
+ {
142
+ "type": "multiple_writers",
143
+ "rule_id": "single_writer_per_output",
144
+ "severity": "critical",
145
+ "location": {
146
+ "path": ["trigger", "categorizer", "billing_branch"],
147
+ "category": "Billing",
148
+ "named_result": "response_with_sources"
149
+ },
150
+ "what": "Multiple nodes produce 'response_with_sources' on path 'Billing'",
151
+ "why": "A single named result can only have one producer per execution path. The path 'Billing' has both 'respond_billing' and 'respond_general' producing 'response_with_sources'.",
152
+ "how_to_fix": "Ensure only one node produces 'response_with_sources' on the 'Billing' path. Either remove 'respond_general' or use a different named result for it.",
153
+ "rule_reference": "ema://validation/rules#single_writer_per_output"
154
+ }
155
+ ```
156
+
157
+ ---
158
+
159
+ ### 3. missing_response_or_abstain_reason
160
+
161
+ **Rule ID**: `response_or_abstain_required`
162
+
163
+ **What**:
164
+ ```
165
+ "Path '{path_name}' does not produce a response and has no abstain reason"
166
+ ```
167
+
168
+ **Why**:
169
+ ```
170
+ "Every execution path must either produce a user-visible response or explicitly abstain with a reason. The path '{path_name}' ends without a response node and no abstain reason is specified."
171
+ ```
172
+
173
+ **How to Fix**:
174
+ ```
175
+ "Either add a response node (respond_with_sources, call_llm, or fixed_response) to the '{path_name}' path, or add an abstain reason explaining why this path doesn't respond."
176
+ ```
177
+
178
+ **Example**:
179
+ ```json
180
+ {
181
+ "type": "missing_response_or_abstain_reason",
182
+ "rule_id": "response_or_abstain_required",
183
+ "severity": "critical",
184
+ "location": {
185
+ "path": ["trigger", "categorizer", "billing_branch", "search"],
186
+ "category": "Billing"
187
+ },
188
+ "what": "Path 'Billing' does not produce a response and has no abstain reason",
189
+ "why": "Every execution path must either produce a user-visible response or explicitly abstain with a reason. The path 'Billing' ends at 'search' node without a response node and no abstain reason is specified.",
190
+ "how_to_fix": "Either add a response node (respond_with_sources, call_llm, or fixed_response) after 'search' in the 'Billing' branch, or add an abstain reason to the workflow configuration.",
191
+ "rule_reference": "ema://validation/rules#response_or_abstain_required"
192
+ }
193
+ ```
194
+
195
+ ---
196
+
197
+ ### 4. category_hierarchy_violation
198
+
199
+ **Rule ID**: `category_hierarchy_valid`
200
+
201
+ **What**:
202
+ ```
203
+ "Category hierarchy violation in categorizer '{categorizer_name}'"
204
+ ```
205
+
206
+ **Why**:
207
+ ```
208
+ TBD - Need to analyze category hierarchy rules from Go validator
209
+ ```
210
+
211
+ **How to Fix**:
212
+ ```
213
+ TBD - Need to analyze category hierarchy rules
214
+ ```
215
+
216
+ **Example**:
217
+ ```json
218
+ {
219
+ "type": "category_hierarchy_violation",
220
+ "rule_id": "category_hierarchy_valid",
221
+ "severity": "critical",
222
+ "location": {
223
+ "node_id": "chat_categorizer",
224
+ "category": "Billing"
225
+ },
226
+ "what": "Category hierarchy violation in categorizer 'chat_categorizer'",
227
+ "why": "TBD",
228
+ "how_to_fix": "TBD",
229
+ "rule_reference": "ema://validation/rules#category_hierarchy_valid"
230
+ }
231
+ ```
232
+
233
+ ---
234
+
235
+ ## Path Format
236
+
237
+ ### Path Representation
238
+
239
+ Paths are represented as arrays of node IDs in execution order:
240
+
241
+ ```typescript
242
+ path: ["trigger", "categorizer", "billing_branch", "search", "respond_with_sources"]
243
+ ```
244
+
245
+ ### Path Naming
246
+
247
+ For branching paths, use category/value name:
248
+ ```
249
+ "Billing" // From categorizer, value="Billing"
250
+ "Fallback" // From categorizer, value="Fallback"
251
+ "true" // From boolean output, value=true
252
+ ```
253
+
254
+ For non-branching paths, use last action name:
255
+ ```
256
+ "respond_with_sources" // Last action in path
257
+ ```
258
+
259
+ ---
260
+
261
+ ## Rule Reference Format
262
+
263
+ ### URI Structure
264
+
265
+ ```
266
+ ema://validation/rules#{rule_id}
267
+ ```
268
+
269
+ ### Examples
270
+
271
+ - `ema://validation/rules#required_output_all_paths`
272
+ - `ema://validation/rules#single_writer_per_output`
273
+ - `ema://validation/rules#response_or_abstain_required`
274
+ - `ema://validation/rules#category_hierarchy_valid`
275
+
276
+ ---
277
+
278
+ ## Error Message Templates
279
+
280
+ ### Template Variables
281
+
282
+ - `{path_name}` - Human-readable path name
283
+ - `{named_result}` - Named result name
284
+ - `{node_id}` - Node identifier
285
+ - `{last_node}` - Last node in path
286
+ - `{output_name}` - Output name
287
+ - `{category}` - Category name
288
+
289
+ ### Template Functions
290
+
291
+ - `formatPath(path: string[]): string` - Format path array to readable string
292
+ - `formatNode(nodeId: string): string` - Format node ID to display name
293
+ - `formatCategory(category: string): string` - Format category name
294
+
295
+ ---
296
+
297
+ ## Compatibility with Go Validator
298
+
299
+ ### Must Match
300
+
301
+ - Error types (4 types)
302
+ - Path identification format
303
+ - Validation logic
304
+
305
+ ### Can Enhance
306
+
307
+ - Error message format (what/why/how)
308
+ - Additional context (examples, references)
309
+ - Severity levels (critical/warning/info)
310
+
311
+ ---
312
+
313
+ ## Implementation Checklist
314
+
315
+ - [ ] Define TypeScript interfaces
316
+ - [ ] Create error message generators for each error type
317
+ - [ ] Implement path formatting utilities
318
+ - [ ] Add rule reference generation
319
+ - [ ] Create example generators (good vs bad)
320
+ - [ ] Test error message clarity
321
+ - [ ] Validate against Go validator error format
322
+
323
+ ---
324
+
325
+ **Status**: ✅ Format designed
326
+ **Next**: Implement error message generators