@principal-ai/principal-view-cli 0.2.4 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -181,100 +181,100 @@ ${chalk.bold('Validation:')}
181
181
  ${chalk.bold.cyan('Execution Format (.otel.json)')}
182
182
  ${chalk.dim('═'.repeat(70))}
183
183
 
184
- Execution files contain captured OTEL spans from test runs or production code.
185
- These files are exported by your test infrastructure and used for visualization
184
+ Execution files use the ${chalk.bold('standard OTLP (OpenTelemetry Protocol) JSON format')}.
185
+ These files are exported by OpenTelemetry SDK and used for visualization
186
186
  and validation against canvas schemas.
187
187
 
188
188
  ${chalk.bold('File Location:')}
189
189
  ${chalk.yellow('__executions__/')}${chalk.dim('<feature-name>.otel.json')}
190
- ${chalk.dim('(auto-generated by test infrastructure)')}
190
+ ${chalk.dim('(auto-generated by test infrastructure with OpenTelemetry SDK)')}
191
191
 
192
192
  ${chalk.bold('IMPORTANT:')} __executions__/ directory must be committed to git!
193
193
 
194
- ${chalk.bold('File Structure:')}
194
+ ${chalk.bold('File Structure (OTLP JSON Format):')}
195
195
  ${chalk.dim('┌────────────────────────────────────────────────────────────────────┐')}
196
196
  ${chalk.dim('│')} { ${chalk.dim('│')}
197
- ${chalk.dim('│')} ${chalk.green('"exportedAt"')}: "2025-01-21T10:30:00.000Z", ${chalk.dim('// ISO timestamp')} ${chalk.dim('│')}
198
- ${chalk.dim('│')} ${chalk.green('"serviceName"')}: "my-service", ${chalk.dim('// Service name')} ${chalk.dim('│')}
199
- ${chalk.dim('│')} ${chalk.green('"spanCount"')}: 5, ${chalk.dim('// Total spans')} ${chalk.dim('│')}
200
- ${chalk.dim('│')} ${chalk.green('"spans"')}: [ ${chalk.dim('│')}
197
+ ${chalk.dim('│')} ${chalk.green('"resourceSpans"')}: [ ${chalk.dim('// OTLP root structure')} ${chalk.dim('│')}
201
198
  ${chalk.dim('│')} { ${chalk.dim('│')}
202
- ${chalk.dim('│')} ${chalk.yellow('"traceId"')}: "4bf92f3577b34da6...", ${chalk.dim('// 32 hex chars')} ${chalk.dim('│')}
203
- ${chalk.dim('│')} ${chalk.yellow('"spanId"')}: "00f067aa0ba902b7", ${chalk.dim('// 16 hex chars')} ${chalk.dim('│')}
204
- ${chalk.dim('│')} ${chalk.yellow('"parentSpanId"')}: "abc123...", ${chalk.dim('// Parent span (null for root)')} ${chalk.dim('│')}
205
- ${chalk.dim('│')} ${chalk.yellow('"name"')}: "test:feature-name", ${chalk.dim('// Span name')} ${chalk.dim('│')}
206
- ${chalk.dim('│')} ${chalk.yellow('"kind"')}: "INTERNAL", ${chalk.dim('// Span kind')} ${chalk.dim('│')}
207
- ${chalk.dim('│')} ${chalk.yellow('"startTime"')}: 1703548800000, ${chalk.dim('// Unix ms')} ${chalk.dim('│')}
208
- ${chalk.dim('│')} ${chalk.yellow('"endTime"')}: 1703548800050, ${chalk.dim('// Unix ms')} ${chalk.dim('│')}
209
- ${chalk.dim('│')} ${chalk.yellow('"duration"')}: 50, ${chalk.dim('// Duration in ms')} ${chalk.dim('│')}
210
- ${chalk.dim('│')} ${chalk.yellow('"attributes"')}: { ${chalk.dim('// Event attributes')} ${chalk.dim('│')}
211
- ${chalk.dim('│')} "input.size": 42, ${chalk.dim('│')}
212
- ${chalk.dim('│')} "output.success": true ${chalk.dim('│')}
213
- ${chalk.dim('│')} }, ${chalk.dim('│')}
214
- ${chalk.dim('│')} ${chalk.yellow('"status"')}: { ${chalk.dim('│')}
215
- ${chalk.dim('│')} "code": "OK" ${chalk.dim('// OK, ERROR, UNSET')} ${chalk.dim('│')}
216
- ${chalk.dim('│')} }, ${chalk.dim('│')}
217
- ${chalk.dim('│')} ${chalk.yellow('"events"')}: [] ${chalk.dim('// Optional span events')} ${chalk.dim('│')}
199
+ ${chalk.dim('│')} ${chalk.yellow('"resource"')}: { ${chalk.dim('│')}
200
+ ${chalk.dim('│')} ${chalk.cyan('"attributes"')}: [ ${chalk.dim('│')}
201
+ ${chalk.dim('│')} { "key": "service.name", "value": { "stringValue": "..." }} ${chalk.dim('│')}
202
+ ${chalk.dim('│')} ] ${chalk.dim('│')}
203
+ ${chalk.dim('│')} }, ${chalk.dim('│')}
204
+ ${chalk.dim('│')} ${chalk.yellow('"scopeSpans"')}: [ ${chalk.dim('│')}
205
+ ${chalk.dim('│')} { ${chalk.dim('│')}
206
+ ${chalk.dim('│')} ${chalk.cyan('"scope"')}: { "name": "...", "version": "..." }, ${chalk.dim('│')}
207
+ ${chalk.dim('│')} ${chalk.cyan('"spans"')}: [ ${chalk.dim('│')}
208
+ ${chalk.dim('│')} { ${chalk.dim('│')}
209
+ ${chalk.dim('│')} "traceId": "4bf92f3577b34da6...", ${chalk.dim('// 32 hex chars')} ${chalk.dim('│')}
210
+ ${chalk.dim('│')} "spanId": "00f067aa0ba902b7", ${chalk.dim('// 16 hex chars')} ${chalk.dim('│')}
211
+ ${chalk.dim('│')} "name": "test:feature-name", ${chalk.dim('// Span name')} ${chalk.dim('│')}
212
+ ${chalk.dim('│')} "kind": 0, ${chalk.dim('// 0=INTERNAL')} ${chalk.dim('│')}
213
+ ${chalk.dim('│')} "startTimeUnixNano": "1703...", ${chalk.dim('// Unix nanoseconds')} ${chalk.dim('│')}
214
+ ${chalk.dim('│')} "endTimeUnixNano": "1703...", ${chalk.dim('// Unix nanoseconds')} ${chalk.dim('│')}
215
+ ${chalk.dim('│')} "attributes": [ ${chalk.dim('// Key-value pairs')} ${chalk.dim('│')}
216
+ ${chalk.dim('│')} { "key": "input.size", "value": { "intValue": 42 } } ${chalk.dim('│')}
217
+ ${chalk.dim('│')} ], ${chalk.dim('│')}
218
+ ${chalk.dim('│')} "events": [ ${chalk.dim('// Span events')} ${chalk.dim('│')}
219
+ ${chalk.dim('│')} { ${chalk.dim('│')}
220
+ ${chalk.dim('│')} "timeUnixNano": "1703...", ${chalk.dim('│')}
221
+ ${chalk.dim('│')} "name": "validation.started", ${chalk.dim('│')}
222
+ ${chalk.dim('│')} "attributes": [...] ${chalk.dim('│')}
223
+ ${chalk.dim('│')} } ${chalk.dim('│')}
224
+ ${chalk.dim('│')} ] ${chalk.dim('│')}
225
+ ${chalk.dim('│')} } ${chalk.dim('│')}
226
+ ${chalk.dim('│')} ] ${chalk.dim('│')}
227
+ ${chalk.dim('│')} } ${chalk.dim('│')}
228
+ ${chalk.dim('│')} ] ${chalk.dim('│')}
218
229
  ${chalk.dim('│')} } ${chalk.dim('│')}
219
230
  ${chalk.dim('│')} ] ${chalk.dim('│')}
220
231
  ${chalk.dim('│')} } ${chalk.dim('│')}
221
232
  ${chalk.dim('└────────────────────────────────────────────────────────────────────┘')}
222
233
 
223
- ${chalk.bold('Field Descriptions:')}
234
+ ${chalk.bold('OTLP Format Details:')}
224
235
 
225
- ${chalk.cyan('exportedAt')} ${chalk.dim('(string, required)')}
226
- ISO 8601 timestamp when the file was exported
236
+ ${chalk.cyan('resourceSpans')} ${chalk.dim('(array, required)')}
237
+ Root array containing resource-grouped spans
227
238
 
228
- ${chalk.cyan('serviceName')} ${chalk.dim('(string, required)')}
229
- Name of the service/test suite that generated these spans
239
+ ${chalk.cyan('resource.attributes')} ${chalk.dim('(array)')}
240
+ Metadata about the service (e.g., service.name)
230
241
 
231
- ${chalk.cyan('spanCount')} ${chalk.dim('(number, required)')}
232
- Total number of spans in this execution
242
+ ${chalk.cyan('scopeSpans')} ${chalk.dim('(array, required)')}
243
+ Instrumentation scope-grouped spans
233
244
 
234
245
  ${chalk.cyan('spans')} ${chalk.dim('(array, required)')}
235
- Array of span objects containing OTEL trace data
236
-
237
- ${chalk.bold('Span Object Fields:')}
238
-
239
- ${chalk.cyan('traceId')} ${chalk.dim('(string, 32 hex chars)')}
240
- Unique identifier for the entire trace
241
-
242
- ${chalk.cyan('spanId')} ${chalk.dim('(string, 16 hex chars)')}
243
- Unique identifier for this specific span
244
-
245
- ${chalk.cyan('parentSpanId')} ${chalk.dim('(string | null)')}
246
- Parent span ID, or null for root span
247
-
248
- ${chalk.cyan('name')} ${chalk.dim('(string)')}
249
- Descriptive name for the operation
250
-
251
- ${chalk.cyan('kind')} ${chalk.dim('(string)')}
252
- Span kind: INTERNAL, CLIENT, SERVER, PRODUCER, CONSUMER
253
-
254
- ${chalk.cyan('startTime')} ${chalk.dim('(number)')}
255
- Unix timestamp in milliseconds when span started
256
-
257
- ${chalk.cyan('endTime')} ${chalk.dim('(number)')}
258
- Unix timestamp in milliseconds when span ended
259
-
260
- ${chalk.cyan('duration')} ${chalk.dim('(number)')}
261
- Duration in milliseconds (endTime - startTime)
262
-
263
- ${chalk.cyan('attributes')} ${chalk.dim('(object)')}
264
- Key-value pairs of event attributes (validated against canvas schema)
265
-
266
- ${chalk.cyan('status')} ${chalk.dim('(object)')}
267
- Status code (OK, ERROR, UNSET) and optional message
268
-
269
- ${chalk.cyan('events')} ${chalk.dim('(array)')}
270
- Optional array of timestamped events within the span
246
+ Array of span objects with OTLP structure
247
+
248
+ ${chalk.bold('Span Fields (OTLP Standard):')}
249
+
250
+ ${chalk.cyan('traceId')} ${chalk.dim('(string)')} - Unique trace identifier (32 hex chars)
251
+ ${chalk.cyan('spanId')} ${chalk.dim('(string)')} - Unique span identifier (16 hex chars)
252
+ ${chalk.cyan('parentSpanId')} ${chalk.dim('(string, optional)')} - Parent span ID
253
+ ${chalk.cyan('name')} ${chalk.dim('(string)')} - Operation name
254
+ ${chalk.cyan('kind')} ${chalk.dim('(number)')} - 0=UNSPECIFIED, 1=INTERNAL, 2=SERVER, 3=CLIENT, 4=PRODUCER, 5=CONSUMER
255
+ ${chalk.cyan('startTimeUnixNano')} ${chalk.dim('(string)')} - Start time in Unix nanoseconds
256
+ ${chalk.cyan('endTimeUnixNano')} ${chalk.dim('(string)')} - End time in Unix nanoseconds
257
+ ${chalk.cyan('attributes')} ${chalk.dim('(array)')} - Key-value pairs: [{ key, value: { stringValue|intValue|... } }]
258
+ ${chalk.cyan('events')} ${chalk.dim('(array)')} - Span events with timestamps and attributes
259
+ ${chalk.cyan('status')} ${chalk.dim('(object)')} - Status: { code: 1=OK, 2=ERROR }
260
+
261
+ ${chalk.bold('Attribute Value Format:')}
262
+ { "stringValue": "..." } ${chalk.dim('// For strings')}
263
+ { "intValue": 42 } ${chalk.dim('// For integers')}
264
+ { "doubleValue": 3.14 } ${chalk.dim('// For floats')}
265
+ { "boolValue": true } ${chalk.dim('// For booleans')}
271
266
 
272
267
  ${chalk.bold('Generation:')}
273
- Set up test infrastructure with OTEL exporters that write to __executions__/
274
- See: docs/guides/adding-opentelemetry-to-tests.md
268
+ Use OpenTelemetry SDK with OTLP JSON exporter
269
+ Example: @opentelemetry/sdk-trace-node + InMemorySpanExporter
270
+ See: tests/otel-setup.ts in the add-skill repository
275
271
 
276
272
  ${chalk.bold('Validation:')}
277
273
  ${chalk.cyan('npx @principal-ai/principal-view-cli validate-execution <file>')}
274
+
275
+ ${chalk.bold('Resources:')}
276
+ OTLP Spec: https://opentelemetry.io/docs/specs/otlp/
277
+ OpenTelemetry JS: https://github.com/open-telemetry/opentelemetry-js
278
278
  `,
279
279
  examples: `
280
280
  ${chalk.bold.cyan('Complete File Examples')}
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqrCpC,wBAAgB,qBAAqB,IAAI,OAAO,CAiI/C"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0sCpC,wBAAgB,qBAAqB,IAAI,OAAO,CAiI/C"}
@@ -667,21 +667,40 @@ function validateCanvas(canvas, filePath, library, repositoryPath) {
667
667
  });
668
668
  }
669
669
  }
670
- // Validate that all source files exist (if repository path is provided)
671
- if (Array.isArray(nodePv.sources) && repositoryPath) {
670
+ // Validate source file paths
671
+ if (Array.isArray(nodePv.sources)) {
672
672
  nodePv.sources.forEach((source, sourceIndex) => {
673
673
  if (typeof source === 'string') {
674
- // Remove glob patterns (* characters) to get the base path
675
- const cleanPath = source.replace(/\*/g, '');
676
- const fullPath = resolve(repositoryPath, cleanPath);
677
- if (!existsSync(fullPath)) {
674
+ // Check for glob patterns
675
+ if (/[*?[\]{}]/.test(source)) {
678
676
  issues.push({
679
677
  type: 'error',
680
- message: `Node "${nodeLabel}" references non-existent source file: ${source}`,
678
+ message: `Node "${nodeLabel}" has glob pattern in sources: ${source}`,
681
679
  path: `${nodePath}.pv.sources[${sourceIndex}]`,
682
- suggestion: `Verify the file path is correct relative to repository root: ${repositoryPath}`,
680
+ suggestion: 'Use exact file paths only. Glob patterns (*, ?, [], {}) are not supported in sources.',
683
681
  });
684
682
  }
683
+ // Check for line number suffix (e.g., "file.ts:123")
684
+ if (/:\d+$/.test(source)) {
685
+ issues.push({
686
+ type: 'error',
687
+ message: `Node "${nodeLabel}" has line number suffix in sources: ${source}`,
688
+ path: `${nodePath}.pv.sources[${sourceIndex}]`,
689
+ suggestion: 'Remove line number suffix. Use exact file paths only (e.g., "src/file.ts" not "src/file.ts:123").',
690
+ });
691
+ }
692
+ // Validate that source file exists (if repository path is provided)
693
+ if (repositoryPath) {
694
+ const fullPath = resolve(repositoryPath, source);
695
+ if (!existsSync(fullPath)) {
696
+ issues.push({
697
+ type: 'error',
698
+ message: `Node "${nodeLabel}" references non-existent source file: ${source}`,
699
+ path: `${nodePath}.pv.sources[${sourceIndex}]`,
700
+ suggestion: `Verify the file path is correct relative to repository root: ${repositoryPath}`,
701
+ });
702
+ }
703
+ }
685
704
  }
686
705
  });
687
706
  }
package/dist/index.cjs CHANGED
@@ -229048,19 +229048,36 @@ function validateCanvas(canvas, filePath, library, repositoryPath) {
229048
229048
  });
229049
229049
  }
229050
229050
  }
229051
- if (Array.isArray(nodePv.sources) && repositoryPath) {
229051
+ if (Array.isArray(nodePv.sources)) {
229052
229052
  nodePv.sources.forEach((source, sourceIndex) => {
229053
229053
  if (typeof source === "string") {
229054
- const cleanPath = source.replace(/\*/g, "");
229055
- const fullPath = (0, import_node_path5.resolve)(repositoryPath, cleanPath);
229056
- if (!(0, import_node_fs4.existsSync)(fullPath)) {
229054
+ if (/[*?[\]{}]/.test(source)) {
229057
229055
  issues.push({
229058
229056
  type: "error",
229059
- message: `Node "${nodeLabel}" references non-existent source file: ${source}`,
229057
+ message: `Node "${nodeLabel}" has glob pattern in sources: ${source}`,
229060
229058
  path: `${nodePath2}.pv.sources[${sourceIndex}]`,
229061
- suggestion: `Verify the file path is correct relative to repository root: ${repositoryPath}`
229059
+ suggestion: "Use exact file paths only. Glob patterns (*, ?, [], {}) are not supported in sources."
229062
229060
  });
229063
229061
  }
229062
+ if (/:\d+$/.test(source)) {
229063
+ issues.push({
229064
+ type: "error",
229065
+ message: `Node "${nodeLabel}" has line number suffix in sources: ${source}`,
229066
+ path: `${nodePath2}.pv.sources[${sourceIndex}]`,
229067
+ suggestion: 'Remove line number suffix. Use exact file paths only (e.g., "src/file.ts" not "src/file.ts:123").'
229068
+ });
229069
+ }
229070
+ if (repositoryPath) {
229071
+ const fullPath = (0, import_node_path5.resolve)(repositoryPath, source);
229072
+ if (!(0, import_node_fs4.existsSync)(fullPath)) {
229073
+ issues.push({
229074
+ type: "error",
229075
+ message: `Node "${nodeLabel}" references non-existent source file: ${source}`,
229076
+ path: `${nodePath2}.pv.sources[${sourceIndex}]`,
229077
+ suggestion: `Verify the file path is correct relative to repository root: ${repositoryPath}`
229078
+ });
229079
+ }
229080
+ }
229064
229081
  }
229065
229082
  });
229066
229083
  }
@@ -241308,100 +241325,100 @@ ${source_default.bold("Validation:")}
241308
241325
  ${source_default.bold.cyan("Execution Format (.otel.json)")}
241309
241326
  ${source_default.dim("\u2550".repeat(70))}
241310
241327
 
241311
- Execution files contain captured OTEL spans from test runs or production code.
241312
- These files are exported by your test infrastructure and used for visualization
241328
+ Execution files use the ${source_default.bold("standard OTLP (OpenTelemetry Protocol) JSON format")}.
241329
+ These files are exported by OpenTelemetry SDK and used for visualization
241313
241330
  and validation against canvas schemas.
241314
241331
 
241315
241332
  ${source_default.bold("File Location:")}
241316
241333
  ${source_default.yellow("__executions__/")}${source_default.dim("<feature-name>.otel.json")}
241317
- ${source_default.dim("(auto-generated by test infrastructure)")}
241334
+ ${source_default.dim("(auto-generated by test infrastructure with OpenTelemetry SDK)")}
241318
241335
 
241319
241336
  ${source_default.bold("IMPORTANT:")} __executions__/ directory must be committed to git!
241320
241337
 
241321
- ${source_default.bold("File Structure:")}
241338
+ ${source_default.bold("File Structure (OTLP JSON Format):")}
241322
241339
  ${source_default.dim("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510")}
241323
241340
  ${source_default.dim("\u2502")} { ${source_default.dim("\u2502")}
241324
- ${source_default.dim("\u2502")} ${source_default.green('"exportedAt"')}: "2025-01-21T10:30:00.000Z", ${source_default.dim("// ISO timestamp")} ${source_default.dim("\u2502")}
241325
- ${source_default.dim("\u2502")} ${source_default.green('"serviceName"')}: "my-service", ${source_default.dim("// Service name")} ${source_default.dim("\u2502")}
241326
- ${source_default.dim("\u2502")} ${source_default.green('"spanCount"')}: 5, ${source_default.dim("// Total spans")} ${source_default.dim("\u2502")}
241327
- ${source_default.dim("\u2502")} ${source_default.green('"spans"')}: [ ${source_default.dim("\u2502")}
241341
+ ${source_default.dim("\u2502")} ${source_default.green('"resourceSpans"')}: [ ${source_default.dim("// OTLP root structure")} ${source_default.dim("\u2502")}
241328
241342
  ${source_default.dim("\u2502")} { ${source_default.dim("\u2502")}
241329
- ${source_default.dim("\u2502")} ${source_default.yellow('"traceId"')}: "4bf92f3577b34da6...", ${source_default.dim("// 32 hex chars")} ${source_default.dim("\u2502")}
241330
- ${source_default.dim("\u2502")} ${source_default.yellow('"spanId"')}: "00f067aa0ba902b7", ${source_default.dim("// 16 hex chars")} ${source_default.dim("\u2502")}
241331
- ${source_default.dim("\u2502")} ${source_default.yellow('"parentSpanId"')}: "abc123...", ${source_default.dim("// Parent span (null for root)")} ${source_default.dim("\u2502")}
241332
- ${source_default.dim("\u2502")} ${source_default.yellow('"name"')}: "test:feature-name", ${source_default.dim("// Span name")} ${source_default.dim("\u2502")}
241333
- ${source_default.dim("\u2502")} ${source_default.yellow('"kind"')}: "INTERNAL", ${source_default.dim("// Span kind")} ${source_default.dim("\u2502")}
241334
- ${source_default.dim("\u2502")} ${source_default.yellow('"startTime"')}: 1703548800000, ${source_default.dim("// Unix ms")} ${source_default.dim("\u2502")}
241335
- ${source_default.dim("\u2502")} ${source_default.yellow('"endTime"')}: 1703548800050, ${source_default.dim("// Unix ms")} ${source_default.dim("\u2502")}
241336
- ${source_default.dim("\u2502")} ${source_default.yellow('"duration"')}: 50, ${source_default.dim("// Duration in ms")} ${source_default.dim("\u2502")}
241337
- ${source_default.dim("\u2502")} ${source_default.yellow('"attributes"')}: { ${source_default.dim("// Event attributes")} ${source_default.dim("\u2502")}
241338
- ${source_default.dim("\u2502")} "input.size": 42, ${source_default.dim("\u2502")}
241339
- ${source_default.dim("\u2502")} "output.success": true ${source_default.dim("\u2502")}
241340
- ${source_default.dim("\u2502")} }, ${source_default.dim("\u2502")}
241341
- ${source_default.dim("\u2502")} ${source_default.yellow('"status"')}: { ${source_default.dim("\u2502")}
241342
- ${source_default.dim("\u2502")} "code": "OK" ${source_default.dim("// OK, ERROR, UNSET")} ${source_default.dim("\u2502")}
241343
- ${source_default.dim("\u2502")} }, ${source_default.dim("\u2502")}
241344
- ${source_default.dim("\u2502")} ${source_default.yellow('"events"')}: [] ${source_default.dim("// Optional span events")} ${source_default.dim("\u2502")}
241343
+ ${source_default.dim("\u2502")} ${source_default.yellow('"resource"')}: { ${source_default.dim("\u2502")}
241344
+ ${source_default.dim("\u2502")} ${source_default.cyan('"attributes"')}: [ ${source_default.dim("\u2502")}
241345
+ ${source_default.dim("\u2502")} { "key": "service.name", "value": { "stringValue": "..." }} ${source_default.dim("\u2502")}
241346
+ ${source_default.dim("\u2502")} ] ${source_default.dim("\u2502")}
241347
+ ${source_default.dim("\u2502")} }, ${source_default.dim("\u2502")}
241348
+ ${source_default.dim("\u2502")} ${source_default.yellow('"scopeSpans"')}: [ ${source_default.dim("\u2502")}
241349
+ ${source_default.dim("\u2502")} { ${source_default.dim("\u2502")}
241350
+ ${source_default.dim("\u2502")} ${source_default.cyan('"scope"')}: { "name": "...", "version": "..." }, ${source_default.dim("\u2502")}
241351
+ ${source_default.dim("\u2502")} ${source_default.cyan('"spans"')}: [ ${source_default.dim("\u2502")}
241352
+ ${source_default.dim("\u2502")} { ${source_default.dim("\u2502")}
241353
+ ${source_default.dim("\u2502")} "traceId": "4bf92f3577b34da6...", ${source_default.dim("// 32 hex chars")} ${source_default.dim("\u2502")}
241354
+ ${source_default.dim("\u2502")} "spanId": "00f067aa0ba902b7", ${source_default.dim("// 16 hex chars")} ${source_default.dim("\u2502")}
241355
+ ${source_default.dim("\u2502")} "name": "test:feature-name", ${source_default.dim("// Span name")} ${source_default.dim("\u2502")}
241356
+ ${source_default.dim("\u2502")} "kind": 0, ${source_default.dim("// 0=INTERNAL")} ${source_default.dim("\u2502")}
241357
+ ${source_default.dim("\u2502")} "startTimeUnixNano": "1703...", ${source_default.dim("// Unix nanoseconds")} ${source_default.dim("\u2502")}
241358
+ ${source_default.dim("\u2502")} "endTimeUnixNano": "1703...", ${source_default.dim("// Unix nanoseconds")} ${source_default.dim("\u2502")}
241359
+ ${source_default.dim("\u2502")} "attributes": [ ${source_default.dim("// Key-value pairs")} ${source_default.dim("\u2502")}
241360
+ ${source_default.dim("\u2502")} { "key": "input.size", "value": { "intValue": 42 } } ${source_default.dim("\u2502")}
241361
+ ${source_default.dim("\u2502")} ], ${source_default.dim("\u2502")}
241362
+ ${source_default.dim("\u2502")} "events": [ ${source_default.dim("// Span events")} ${source_default.dim("\u2502")}
241363
+ ${source_default.dim("\u2502")} { ${source_default.dim("\u2502")}
241364
+ ${source_default.dim("\u2502")} "timeUnixNano": "1703...", ${source_default.dim("\u2502")}
241365
+ ${source_default.dim("\u2502")} "name": "validation.started", ${source_default.dim("\u2502")}
241366
+ ${source_default.dim("\u2502")} "attributes": [...] ${source_default.dim("\u2502")}
241367
+ ${source_default.dim("\u2502")} } ${source_default.dim("\u2502")}
241368
+ ${source_default.dim("\u2502")} ] ${source_default.dim("\u2502")}
241369
+ ${source_default.dim("\u2502")} } ${source_default.dim("\u2502")}
241370
+ ${source_default.dim("\u2502")} ] ${source_default.dim("\u2502")}
241371
+ ${source_default.dim("\u2502")} } ${source_default.dim("\u2502")}
241372
+ ${source_default.dim("\u2502")} ] ${source_default.dim("\u2502")}
241345
241373
  ${source_default.dim("\u2502")} } ${source_default.dim("\u2502")}
241346
241374
  ${source_default.dim("\u2502")} ] ${source_default.dim("\u2502")}
241347
241375
  ${source_default.dim("\u2502")} } ${source_default.dim("\u2502")}
241348
241376
  ${source_default.dim("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518")}
241349
241377
 
241350
- ${source_default.bold("Field Descriptions:")}
241378
+ ${source_default.bold("OTLP Format Details:")}
241351
241379
 
241352
- ${source_default.cyan("exportedAt")} ${source_default.dim("(string, required)")}
241353
- ISO 8601 timestamp when the file was exported
241380
+ ${source_default.cyan("resourceSpans")} ${source_default.dim("(array, required)")}
241381
+ Root array containing resource-grouped spans
241354
241382
 
241355
- ${source_default.cyan("serviceName")} ${source_default.dim("(string, required)")}
241356
- Name of the service/test suite that generated these spans
241383
+ ${source_default.cyan("resource.attributes")} ${source_default.dim("(array)")}
241384
+ Metadata about the service (e.g., service.name)
241357
241385
 
241358
- ${source_default.cyan("spanCount")} ${source_default.dim("(number, required)")}
241359
- Total number of spans in this execution
241386
+ ${source_default.cyan("scopeSpans")} ${source_default.dim("(array, required)")}
241387
+ Instrumentation scope-grouped spans
241360
241388
 
241361
241389
  ${source_default.cyan("spans")} ${source_default.dim("(array, required)")}
241362
- Array of span objects containing OTEL trace data
241363
-
241364
- ${source_default.bold("Span Object Fields:")}
241390
+ Array of span objects with OTLP structure
241365
241391
 
241366
- ${source_default.cyan("traceId")} ${source_default.dim("(string, 32 hex chars)")}
241367
- Unique identifier for the entire trace
241392
+ ${source_default.bold("Span Fields (OTLP Standard):")}
241368
241393
 
241369
- ${source_default.cyan("spanId")} ${source_default.dim("(string, 16 hex chars)")}
241370
- Unique identifier for this specific span
241394
+ ${source_default.cyan("traceId")} ${source_default.dim("(string)")} - Unique trace identifier (32 hex chars)
241395
+ ${source_default.cyan("spanId")} ${source_default.dim("(string)")} - Unique span identifier (16 hex chars)
241396
+ ${source_default.cyan("parentSpanId")} ${source_default.dim("(string, optional)")} - Parent span ID
241397
+ ${source_default.cyan("name")} ${source_default.dim("(string)")} - Operation name
241398
+ ${source_default.cyan("kind")} ${source_default.dim("(number)")} - 0=UNSPECIFIED, 1=INTERNAL, 2=SERVER, 3=CLIENT, 4=PRODUCER, 5=CONSUMER
241399
+ ${source_default.cyan("startTimeUnixNano")} ${source_default.dim("(string)")} - Start time in Unix nanoseconds
241400
+ ${source_default.cyan("endTimeUnixNano")} ${source_default.dim("(string)")} - End time in Unix nanoseconds
241401
+ ${source_default.cyan("attributes")} ${source_default.dim("(array)")} - Key-value pairs: [{ key, value: { stringValue|intValue|... } }]
241402
+ ${source_default.cyan("events")} ${source_default.dim("(array)")} - Span events with timestamps and attributes
241403
+ ${source_default.cyan("status")} ${source_default.dim("(object)")} - Status: { code: 1=OK, 2=ERROR }
241371
241404
 
241372
- ${source_default.cyan("parentSpanId")} ${source_default.dim("(string | null)")}
241373
- Parent span ID, or null for root span
241374
-
241375
- ${source_default.cyan("name")} ${source_default.dim("(string)")}
241376
- Descriptive name for the operation
241377
-
241378
- ${source_default.cyan("kind")} ${source_default.dim("(string)")}
241379
- Span kind: INTERNAL, CLIENT, SERVER, PRODUCER, CONSUMER
241380
-
241381
- ${source_default.cyan("startTime")} ${source_default.dim("(number)")}
241382
- Unix timestamp in milliseconds when span started
241383
-
241384
- ${source_default.cyan("endTime")} ${source_default.dim("(number)")}
241385
- Unix timestamp in milliseconds when span ended
241386
-
241387
- ${source_default.cyan("duration")} ${source_default.dim("(number)")}
241388
- Duration in milliseconds (endTime - startTime)
241389
-
241390
- ${source_default.cyan("attributes")} ${source_default.dim("(object)")}
241391
- Key-value pairs of event attributes (validated against canvas schema)
241392
-
241393
- ${source_default.cyan("status")} ${source_default.dim("(object)")}
241394
- Status code (OK, ERROR, UNSET) and optional message
241395
-
241396
- ${source_default.cyan("events")} ${source_default.dim("(array)")}
241397
- Optional array of timestamped events within the span
241405
+ ${source_default.bold("Attribute Value Format:")}
241406
+ { "stringValue": "..." } ${source_default.dim("// For strings")}
241407
+ { "intValue": 42 } ${source_default.dim("// For integers")}
241408
+ { "doubleValue": 3.14 } ${source_default.dim("// For floats")}
241409
+ { "boolValue": true } ${source_default.dim("// For booleans")}
241398
241410
 
241399
241411
  ${source_default.bold("Generation:")}
241400
- Set up test infrastructure with OTEL exporters that write to __executions__/
241401
- See: docs/guides/adding-opentelemetry-to-tests.md
241412
+ Use OpenTelemetry SDK with OTLP JSON exporter
241413
+ Example: @opentelemetry/sdk-trace-node + InMemorySpanExporter
241414
+ See: tests/otel-setup.ts in the add-skill repository
241402
241415
 
241403
241416
  ${source_default.bold("Validation:")}
241404
241417
  ${source_default.cyan("npx @principal-ai/principal-view-cli validate-execution <file>")}
241418
+
241419
+ ${source_default.bold("Resources:")}
241420
+ OTLP Spec: https://opentelemetry.io/docs/specs/otlp/
241421
+ OpenTelemetry JS: https://github.com/open-telemetry/opentelemetry-js
241405
241422
  `,
241406
241423
  examples: `
241407
241424
  ${source_default.bold.cyan("Complete File Examples")}