@unrdf/kgc-runtime 26.4.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.
- package/IMPLEMENTATION_SUMMARY.json +150 -0
- package/PLUGIN_SYSTEM_SUMMARY.json +149 -0
- package/README.md +98 -0
- package/TRANSACTION_IMPLEMENTATION.json +119 -0
- package/capability-map.md +93 -0
- package/docs/api-stability.md +269 -0
- package/docs/extensions/plugin-development.md +382 -0
- package/package.json +40 -0
- package/plugins/registry.json +35 -0
- package/src/admission-gate.mjs +414 -0
- package/src/api-version.mjs +373 -0
- package/src/atomic-admission.mjs +310 -0
- package/src/bounds.mjs +289 -0
- package/src/bulkhead-manager.mjs +280 -0
- package/src/capsule.mjs +524 -0
- package/src/crdt.mjs +361 -0
- package/src/enhanced-bounds.mjs +614 -0
- package/src/executor.mjs +73 -0
- package/src/freeze-restore.mjs +521 -0
- package/src/index.mjs +62 -0
- package/src/materialized-views.mjs +371 -0
- package/src/merge.mjs +472 -0
- package/src/plugin-isolation.mjs +392 -0
- package/src/plugin-manager.mjs +441 -0
- package/src/projections-api.mjs +336 -0
- package/src/projections-cli.mjs +238 -0
- package/src/projections-docs.mjs +300 -0
- package/src/projections-ide.mjs +278 -0
- package/src/receipt.mjs +340 -0
- package/src/rollback.mjs +258 -0
- package/src/saga-orchestrator.mjs +355 -0
- package/src/schemas.mjs +1330 -0
- package/src/storage-optimization.mjs +359 -0
- package/src/tool-registry.mjs +272 -0
- package/src/transaction.mjs +466 -0
- package/src/validators.mjs +485 -0
- package/src/work-item.mjs +449 -0
- package/templates/plugin-template/README.md +58 -0
- package/templates/plugin-template/index.mjs +162 -0
- package/templates/plugin-template/plugin.json +19 -0
- package/test/admission-gate.test.mjs +583 -0
- package/test/api-version.test.mjs +74 -0
- package/test/atomic-admission.test.mjs +155 -0
- package/test/bounds.test.mjs +341 -0
- package/test/bulkhead-manager.test.mjs +236 -0
- package/test/capsule.test.mjs +625 -0
- package/test/crdt.test.mjs +215 -0
- package/test/enhanced-bounds.test.mjs +487 -0
- package/test/freeze-restore.test.mjs +472 -0
- package/test/materialized-views.test.mjs +243 -0
- package/test/merge.test.mjs +665 -0
- package/test/plugin-isolation.test.mjs +109 -0
- package/test/plugin-manager.test.mjs +208 -0
- package/test/projections-api.test.mjs +293 -0
- package/test/projections-cli.test.mjs +204 -0
- package/test/projections-docs.test.mjs +173 -0
- package/test/projections-ide.test.mjs +230 -0
- package/test/receipt.test.mjs +295 -0
- package/test/rollback.test.mjs +132 -0
- package/test/saga-orchestrator.test.mjs +279 -0
- package/test/schemas.test.mjs +716 -0
- package/test/storage-optimization.test.mjs +503 -0
- package/test/tool-registry.test.mjs +341 -0
- package/test/transaction.test.mjs +189 -0
- package/test/validators.test.mjs +463 -0
- package/test/work-item.test.mjs +548 -0
- package/test/work-item.test.mjs.bak +548 -0
- package/var/kgc/test-atomic-log.json +519 -0
- package/var/kgc/test-cascading-log.json +145 -0
- package/vitest.config.mjs +18 -0
|
@@ -0,0 +1,716 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Comprehensive validation tests for KGC Runtime schemas
|
|
3
|
+
* @description Tests all schemas with valid/invalid inputs, edge cases, and defaults
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import {
|
|
8
|
+
ReceiptSchema,
|
|
9
|
+
RunCapsuleSchema,
|
|
10
|
+
ToolTraceEntrySchema,
|
|
11
|
+
BoundsSchema,
|
|
12
|
+
WorkItemSchema,
|
|
13
|
+
ProjectionManifestSchema,
|
|
14
|
+
KGCMarkdownSchema,
|
|
15
|
+
validateReceipt,
|
|
16
|
+
validateRunCapsule,
|
|
17
|
+
validateToolTraceEntry,
|
|
18
|
+
validateBounds,
|
|
19
|
+
validateWorkItem,
|
|
20
|
+
validateProjectionManifest,
|
|
21
|
+
validateKGCMarkdown,
|
|
22
|
+
} from '../src/schemas.mjs';
|
|
23
|
+
|
|
24
|
+
// =============================================================================
|
|
25
|
+
// Receipt Schema Tests
|
|
26
|
+
// =============================================================================
|
|
27
|
+
|
|
28
|
+
describe('ReceiptSchema', () => {
|
|
29
|
+
it('should validate a complete receipt', () => {
|
|
30
|
+
const receipt = {
|
|
31
|
+
version: '1.0.0',
|
|
32
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
33
|
+
timestamp: 1703001600000,
|
|
34
|
+
runId: 'run-2024-001',
|
|
35
|
+
actor: 'agent:orchestrator',
|
|
36
|
+
action: 'execute',
|
|
37
|
+
payload: { workflowId: 'wf-001', input: { x: 42 } },
|
|
38
|
+
result: {
|
|
39
|
+
success: true,
|
|
40
|
+
output: { y: 84 },
|
|
41
|
+
duration: 2314,
|
|
42
|
+
},
|
|
43
|
+
contentHash: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
|
|
44
|
+
previousHash: 'a1b2c3d4e5f67890123456789012345678901234567890123456789012345678',
|
|
45
|
+
signature: {
|
|
46
|
+
algorithm: 'ed25519',
|
|
47
|
+
publicKey: '0x1234567890abcdef',
|
|
48
|
+
value: '0xabcdef1234567890',
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const result = validateReceipt(receipt);
|
|
53
|
+
expect(result.success).toBe(true);
|
|
54
|
+
expect(result.data).toBeDefined();
|
|
55
|
+
expect(result.data.version).toBe('1.0.0');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should validate minimal receipt', () => {
|
|
59
|
+
const receipt = {
|
|
60
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
61
|
+
timestamp: 1703001600000,
|
|
62
|
+
runId: 'run-001',
|
|
63
|
+
actor: 'agent:test',
|
|
64
|
+
action: 'execute',
|
|
65
|
+
payload: {},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const result = validateReceipt(receipt);
|
|
69
|
+
expect(result.success).toBe(true);
|
|
70
|
+
expect(result.data.version).toBe('1.0.0'); // Default
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should reject invalid actor format', () => {
|
|
74
|
+
const receipt = {
|
|
75
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
76
|
+
timestamp: 1703001600000,
|
|
77
|
+
runId: 'run-001',
|
|
78
|
+
actor: 'invalid-actor', // Missing type prefix
|
|
79
|
+
action: 'execute',
|
|
80
|
+
payload: {},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const result = validateReceipt(receipt);
|
|
84
|
+
expect(result.success).toBe(false);
|
|
85
|
+
expect(result.errors.length).toBeGreaterThan(0);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should reject invalid UUID', () => {
|
|
89
|
+
const receipt = {
|
|
90
|
+
id: 'not-a-uuid',
|
|
91
|
+
timestamp: 1703001600000,
|
|
92
|
+
runId: 'run-001',
|
|
93
|
+
actor: 'agent:test',
|
|
94
|
+
action: 'execute',
|
|
95
|
+
payload: {},
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const result = validateReceipt(receipt);
|
|
99
|
+
expect(result.success).toBe(false);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should reject invalid SHA-256 hash', () => {
|
|
103
|
+
const receipt = {
|
|
104
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
105
|
+
timestamp: 1703001600000,
|
|
106
|
+
runId: 'run-001',
|
|
107
|
+
actor: 'agent:test',
|
|
108
|
+
action: 'execute',
|
|
109
|
+
payload: {},
|
|
110
|
+
contentHash: 'invalid-hash', // Not 64 hex chars
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const result = validateReceipt(receipt);
|
|
114
|
+
expect(result.success).toBe(false);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// =============================================================================
|
|
119
|
+
// ToolTraceEntry Schema Tests
|
|
120
|
+
// =============================================================================
|
|
121
|
+
|
|
122
|
+
describe('ToolTraceEntrySchema', () => {
|
|
123
|
+
it('should validate a complete tool trace entry', () => {
|
|
124
|
+
const entry = {
|
|
125
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
126
|
+
timestamp: 1703001600000,
|
|
127
|
+
toolName: 'Bash',
|
|
128
|
+
input: { command: 'npm test', timeout: 5000 },
|
|
129
|
+
output: { stdout: '✅ All tests passed', stderr: '', exitCode: 0 },
|
|
130
|
+
duration: 2314,
|
|
131
|
+
status: 'success',
|
|
132
|
+
parentId: null,
|
|
133
|
+
dependencies: [],
|
|
134
|
+
resources: {
|
|
135
|
+
cpuTime: 1200,
|
|
136
|
+
memoryPeak: 45678901,
|
|
137
|
+
ioBytes: 1024,
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const result = validateToolTraceEntry(entry);
|
|
142
|
+
expect(result.success).toBe(true);
|
|
143
|
+
expect(result.data.toolName).toBe('Bash');
|
|
144
|
+
expect(result.data.status).toBe('success');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should validate minimal trace entry', () => {
|
|
148
|
+
const entry = {
|
|
149
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
150
|
+
timestamp: 1703001600000,
|
|
151
|
+
toolName: 'Read',
|
|
152
|
+
input: { file_path: '/home/user/file.txt' },
|
|
153
|
+
duration: 10,
|
|
154
|
+
status: 'success',
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const result = validateToolTraceEntry(entry);
|
|
158
|
+
expect(result.success).toBe(true);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should validate error status with error details', () => {
|
|
162
|
+
const entry = {
|
|
163
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
164
|
+
timestamp: 1703001600000,
|
|
165
|
+
toolName: 'Bash',
|
|
166
|
+
input: { command: 'invalid-command' },
|
|
167
|
+
duration: 50,
|
|
168
|
+
status: 'error',
|
|
169
|
+
error: {
|
|
170
|
+
message: 'Command not found',
|
|
171
|
+
code: 'ENOENT',
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const result = validateToolTraceEntry(entry);
|
|
176
|
+
expect(result.success).toBe(true);
|
|
177
|
+
expect(result.data.error).toBeDefined();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// =============================================================================
|
|
182
|
+
// RunCapsule Schema Tests
|
|
183
|
+
// =============================================================================
|
|
184
|
+
|
|
185
|
+
describe('RunCapsuleSchema', () => {
|
|
186
|
+
it('should validate a complete run capsule', () => {
|
|
187
|
+
const capsule = {
|
|
188
|
+
id: 'run-2024-12-26-001',
|
|
189
|
+
version: '1.0.0',
|
|
190
|
+
startTime: 1703001600000,
|
|
191
|
+
endTime: 1703001620000,
|
|
192
|
+
status: 'completed',
|
|
193
|
+
input: {
|
|
194
|
+
task: 'Implement feature X',
|
|
195
|
+
parameters: { timeout: 5000 },
|
|
196
|
+
context: { workingDir: '/home/user/project' },
|
|
197
|
+
artifacts: [
|
|
198
|
+
{
|
|
199
|
+
type: 'file',
|
|
200
|
+
path: '/home/user/spec.md',
|
|
201
|
+
hash: 'abc1234567890def1234567890abc1234567890def1234567890abc123456789',
|
|
202
|
+
},
|
|
203
|
+
],
|
|
204
|
+
},
|
|
205
|
+
output: {
|
|
206
|
+
success: true,
|
|
207
|
+
results: { filesChanged: 5, testsAdded: 12 },
|
|
208
|
+
artifacts: [
|
|
209
|
+
{
|
|
210
|
+
type: 'file',
|
|
211
|
+
path: '/home/user/project/src/feature.mjs',
|
|
212
|
+
hash: 'def1234567890abc1234567890def1234567890abc1234567890def123456789',
|
|
213
|
+
size: 4567,
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
trace: [
|
|
218
|
+
{
|
|
219
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
220
|
+
timestamp: 1703001605000,
|
|
221
|
+
toolName: 'Bash',
|
|
222
|
+
input: { command: 'npm test' },
|
|
223
|
+
duration: 2000,
|
|
224
|
+
status: 'success',
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
bounds: {
|
|
228
|
+
maxFiles: 100,
|
|
229
|
+
maxBytes: 10485760,
|
|
230
|
+
maxOps: 1000,
|
|
231
|
+
maxRuntime: 300000,
|
|
232
|
+
},
|
|
233
|
+
actor: 'agent:backend-dev',
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const result = validateRunCapsule(capsule);
|
|
237
|
+
expect(result.success).toBe(true);
|
|
238
|
+
expect(result.data.status).toBe('completed');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should validate minimal run capsule', () => {
|
|
242
|
+
const capsule = {
|
|
243
|
+
id: 'run-001',
|
|
244
|
+
startTime: 1703001600000,
|
|
245
|
+
status: 'pending',
|
|
246
|
+
input: {
|
|
247
|
+
task: 'Simple task',
|
|
248
|
+
},
|
|
249
|
+
actor: 'agent:test',
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const result = validateRunCapsule(capsule);
|
|
253
|
+
expect(result.success).toBe(true);
|
|
254
|
+
expect(result.data.version).toBe('1.0.0'); // Default
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should validate failed run with error', () => {
|
|
258
|
+
const capsule = {
|
|
259
|
+
id: 'run-002',
|
|
260
|
+
startTime: 1703001600000,
|
|
261
|
+
endTime: 1703001605000,
|
|
262
|
+
status: 'failed',
|
|
263
|
+
input: { task: 'Failing task' },
|
|
264
|
+
output: {
|
|
265
|
+
success: false,
|
|
266
|
+
error: {
|
|
267
|
+
message: 'Test failed',
|
|
268
|
+
code: 'TEST_FAILURE',
|
|
269
|
+
recoverable: true,
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
actor: 'agent:test',
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
const result = validateRunCapsule(capsule);
|
|
276
|
+
expect(result.success).toBe(true);
|
|
277
|
+
expect(result.data.output.success).toBe(false);
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// =============================================================================
|
|
282
|
+
// Bounds Schema Tests
|
|
283
|
+
// =============================================================================
|
|
284
|
+
|
|
285
|
+
describe('BoundsSchema', () => {
|
|
286
|
+
it('should validate complete bounds with usage', () => {
|
|
287
|
+
const bounds = {
|
|
288
|
+
maxFiles: 100,
|
|
289
|
+
maxBytes: 10485760,
|
|
290
|
+
maxOps: 1000,
|
|
291
|
+
maxRuntime: 300000,
|
|
292
|
+
maxGraphRewrites: 50,
|
|
293
|
+
enforcementPolicy: 'strict',
|
|
294
|
+
warnings: {
|
|
295
|
+
filesThreshold: 0.8,
|
|
296
|
+
bytesThreshold: 0.9,
|
|
297
|
+
opsThreshold: 0.75,
|
|
298
|
+
runtimeThreshold: 0.9,
|
|
299
|
+
graphRewritesThreshold: 0.8,
|
|
300
|
+
},
|
|
301
|
+
currentUsage: {
|
|
302
|
+
files: 45,
|
|
303
|
+
bytes: 5242880,
|
|
304
|
+
ops: 500,
|
|
305
|
+
runtime: 120000,
|
|
306
|
+
graphRewrites: 20,
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
const result = validateBounds(bounds);
|
|
311
|
+
expect(result.success).toBe(true);
|
|
312
|
+
expect(result.data.enforcementPolicy).toBe('strict');
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('should apply defaults', () => {
|
|
316
|
+
const bounds = {};
|
|
317
|
+
|
|
318
|
+
const result = validateBounds(bounds);
|
|
319
|
+
expect(result.success).toBe(true);
|
|
320
|
+
expect(result.data.maxFiles).toBe(100);
|
|
321
|
+
expect(result.data.maxBytes).toBe(10 * 1024 * 1024);
|
|
322
|
+
expect(result.data.maxOps).toBe(1000);
|
|
323
|
+
expect(result.data.maxRuntime).toBe(300000);
|
|
324
|
+
expect(result.data.maxGraphRewrites).toBe(50);
|
|
325
|
+
expect(result.data.enforcementPolicy).toBe('strict');
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it('should reject invalid enforcement policy', () => {
|
|
329
|
+
const bounds = {
|
|
330
|
+
enforcementPolicy: 'invalid',
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
const result = validateBounds(bounds);
|
|
334
|
+
expect(result.success).toBe(false);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('should reject out-of-range values', () => {
|
|
338
|
+
const bounds = {
|
|
339
|
+
maxFiles: 100000, // Exceeds max of 10000
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const result = validateBounds(bounds);
|
|
343
|
+
expect(result.success).toBe(false);
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// =============================================================================
|
|
348
|
+
// WorkItem Schema Tests
|
|
349
|
+
// =============================================================================
|
|
350
|
+
|
|
351
|
+
describe('WorkItemSchema', () => {
|
|
352
|
+
it('should validate complete work item', () => {
|
|
353
|
+
const workItem = {
|
|
354
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
355
|
+
type: 'file_operation',
|
|
356
|
+
state: 'running',
|
|
357
|
+
priority: 75,
|
|
358
|
+
createdAt: 1703001600000,
|
|
359
|
+
startedAt: 1703001605000,
|
|
360
|
+
payload: {
|
|
361
|
+
operation: 'write',
|
|
362
|
+
path: '/home/user/file.txt',
|
|
363
|
+
content: 'Hello World',
|
|
364
|
+
},
|
|
365
|
+
dependencies: ['223e4567-e89b-12d3-a456-426614174000'],
|
|
366
|
+
retries: {
|
|
367
|
+
max: 3,
|
|
368
|
+
current: 0,
|
|
369
|
+
backoff: 'exponential',
|
|
370
|
+
delay: 1000,
|
|
371
|
+
},
|
|
372
|
+
timeout: 30000,
|
|
373
|
+
assignedTo: 'agent:worker-01',
|
|
374
|
+
progress: 0.5,
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
const result = validateWorkItem(workItem);
|
|
378
|
+
expect(result.success).toBe(true);
|
|
379
|
+
expect(result.data.state).toBe('running');
|
|
380
|
+
expect(result.data.priority).toBe(75);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('should validate minimal work item', () => {
|
|
384
|
+
const workItem = {
|
|
385
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
386
|
+
type: 'task',
|
|
387
|
+
state: 'queued',
|
|
388
|
+
createdAt: 1703001600000,
|
|
389
|
+
payload: {},
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
const result = validateWorkItem(workItem);
|
|
393
|
+
expect(result.success).toBe(true);
|
|
394
|
+
expect(result.data.priority).toBe(50); // Default
|
|
395
|
+
expect(result.data.timeout).toBe(30000); // Default
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
it('should validate failed work item with error', () => {
|
|
399
|
+
const workItem = {
|
|
400
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
401
|
+
type: 'computation',
|
|
402
|
+
state: 'failed',
|
|
403
|
+
createdAt: 1703001600000,
|
|
404
|
+
startedAt: 1703001605000,
|
|
405
|
+
completedAt: 1703001610000,
|
|
406
|
+
payload: { x: 42 },
|
|
407
|
+
error: {
|
|
408
|
+
message: 'Division by zero',
|
|
409
|
+
code: 'MATH_ERROR',
|
|
410
|
+
retryable: false,
|
|
411
|
+
},
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const result = validateWorkItem(workItem);
|
|
415
|
+
expect(result.success).toBe(true);
|
|
416
|
+
expect(result.data.state).toBe('failed');
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it('should reject invalid priority range', () => {
|
|
420
|
+
const workItem = {
|
|
421
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
422
|
+
type: 'task',
|
|
423
|
+
state: 'queued',
|
|
424
|
+
priority: 150, // Exceeds max of 100
|
|
425
|
+
createdAt: 1703001600000,
|
|
426
|
+
payload: {},
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
const result = validateWorkItem(workItem);
|
|
430
|
+
expect(result.success).toBe(false);
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// =============================================================================
|
|
435
|
+
// ProjectionManifest Schema Tests
|
|
436
|
+
// =============================================================================
|
|
437
|
+
|
|
438
|
+
describe('ProjectionManifestSchema', () => {
|
|
439
|
+
it('should validate complete projection manifest', () => {
|
|
440
|
+
const manifest = {
|
|
441
|
+
version: '1.0.0',
|
|
442
|
+
surfaces: {
|
|
443
|
+
cli: {
|
|
444
|
+
commands: [
|
|
445
|
+
{
|
|
446
|
+
name: 'run',
|
|
447
|
+
description: 'Execute a workflow',
|
|
448
|
+
aliases: ['r'],
|
|
449
|
+
options: [
|
|
450
|
+
{
|
|
451
|
+
name: 'file',
|
|
452
|
+
type: 'string',
|
|
453
|
+
required: true,
|
|
454
|
+
description: 'Workflow file path',
|
|
455
|
+
},
|
|
456
|
+
],
|
|
457
|
+
examples: ['kgc run workflow.yml'],
|
|
458
|
+
},
|
|
459
|
+
],
|
|
460
|
+
},
|
|
461
|
+
docs: {
|
|
462
|
+
generator: 'typedoc',
|
|
463
|
+
outputDir: './docs',
|
|
464
|
+
includes: ['**/*.mjs'],
|
|
465
|
+
theme: 'default',
|
|
466
|
+
},
|
|
467
|
+
ide: {
|
|
468
|
+
lsp: {
|
|
469
|
+
enabled: true,
|
|
470
|
+
port: 9000,
|
|
471
|
+
features: ['completion', 'hover', 'goto'],
|
|
472
|
+
},
|
|
473
|
+
snippets: [
|
|
474
|
+
{
|
|
475
|
+
prefix: 'run',
|
|
476
|
+
body: 'RunCapsuleSchema.parse({ ... })',
|
|
477
|
+
description: 'Create run capsule',
|
|
478
|
+
},
|
|
479
|
+
],
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
const result = validateProjectionManifest(manifest);
|
|
485
|
+
expect(result.success).toBe(true);
|
|
486
|
+
expect(result.data.surfaces.cli).toBeDefined();
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it('should validate minimal manifest', () => {
|
|
490
|
+
const manifest = {
|
|
491
|
+
surfaces: {},
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
const result = validateProjectionManifest(manifest);
|
|
495
|
+
expect(result.success).toBe(true);
|
|
496
|
+
expect(result.data.version).toBe('1.0.0'); // Default
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it('should validate API surface', () => {
|
|
500
|
+
const manifest = {
|
|
501
|
+
surfaces: {
|
|
502
|
+
api: {
|
|
503
|
+
type: 'rest',
|
|
504
|
+
baseUrl: 'https://api.example.com',
|
|
505
|
+
endpoints: [
|
|
506
|
+
{
|
|
507
|
+
path: '/runs',
|
|
508
|
+
method: 'POST',
|
|
509
|
+
auth: 'bearer',
|
|
510
|
+
},
|
|
511
|
+
],
|
|
512
|
+
versioning: {
|
|
513
|
+
strategy: 'url',
|
|
514
|
+
current: '1.0.0',
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
const result = validateProjectionManifest(manifest);
|
|
521
|
+
expect(result.success).toBe(true);
|
|
522
|
+
});
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
// =============================================================================
|
|
526
|
+
// KGCMarkdown Schema Tests
|
|
527
|
+
// =============================================================================
|
|
528
|
+
|
|
529
|
+
describe('KGCMarkdownSchema', () => {
|
|
530
|
+
it('should validate complete markdown document', () => {
|
|
531
|
+
const doc = {
|
|
532
|
+
type: 'document',
|
|
533
|
+
frontMatter: {
|
|
534
|
+
title: 'KGC Example',
|
|
535
|
+
version: '1.0.0',
|
|
536
|
+
author: 'Test Author',
|
|
537
|
+
date: new Date('2024-12-26'),
|
|
538
|
+
ontology: ['http://schema.org/'],
|
|
539
|
+
tags: ['example', 'test'],
|
|
540
|
+
},
|
|
541
|
+
children: [
|
|
542
|
+
{
|
|
543
|
+
type: 'heading',
|
|
544
|
+
level: 1,
|
|
545
|
+
content: 'Introduction',
|
|
546
|
+
id: 'intro',
|
|
547
|
+
metadata: {},
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
type: 'paragraph',
|
|
551
|
+
content: 'This is a paragraph.',
|
|
552
|
+
metadata: {},
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
type: 'fenced-block',
|
|
556
|
+
language: 'javascript',
|
|
557
|
+
attributes: { executable: true },
|
|
558
|
+
content: 'console.log("Hello");',
|
|
559
|
+
executable: true,
|
|
560
|
+
metadata: {},
|
|
561
|
+
},
|
|
562
|
+
],
|
|
563
|
+
metadata: {},
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
const result = validateKGCMarkdown(doc);
|
|
567
|
+
expect(result.success).toBe(true);
|
|
568
|
+
expect(result.data.children.length).toBe(3);
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
it('should validate minimal document', () => {
|
|
572
|
+
const doc = {
|
|
573
|
+
type: 'document',
|
|
574
|
+
children: [
|
|
575
|
+
{
|
|
576
|
+
type: 'paragraph',
|
|
577
|
+
content: 'Simple paragraph',
|
|
578
|
+
metadata: {},
|
|
579
|
+
},
|
|
580
|
+
],
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
const result = validateKGCMarkdown(doc);
|
|
584
|
+
expect(result.success).toBe(true);
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
it('should validate list node', () => {
|
|
588
|
+
const doc = {
|
|
589
|
+
type: 'document',
|
|
590
|
+
children: [
|
|
591
|
+
{
|
|
592
|
+
type: 'list',
|
|
593
|
+
ordered: false,
|
|
594
|
+
items: ['Item 1', 'Item 2', 'Item 3'],
|
|
595
|
+
metadata: {},
|
|
596
|
+
},
|
|
597
|
+
],
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
const result = validateKGCMarkdown(doc);
|
|
601
|
+
expect(result.success).toBe(true);
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it('should validate table node', () => {
|
|
605
|
+
const doc = {
|
|
606
|
+
type: 'document',
|
|
607
|
+
children: [
|
|
608
|
+
{
|
|
609
|
+
type: 'table',
|
|
610
|
+
headers: ['Column 1', 'Column 2'],
|
|
611
|
+
rows: [
|
|
612
|
+
['A', 'B'],
|
|
613
|
+
['C', 'D'],
|
|
614
|
+
],
|
|
615
|
+
alignment: ['left', 'right'],
|
|
616
|
+
metadata: {},
|
|
617
|
+
},
|
|
618
|
+
],
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
const result = validateKGCMarkdown(doc);
|
|
622
|
+
expect(result.success).toBe(true);
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
it('should reject invalid heading level', () => {
|
|
626
|
+
const doc = {
|
|
627
|
+
type: 'document',
|
|
628
|
+
children: [
|
|
629
|
+
{
|
|
630
|
+
type: 'heading',
|
|
631
|
+
level: 7, // Invalid, max is 6
|
|
632
|
+
content: 'Invalid heading',
|
|
633
|
+
metadata: {},
|
|
634
|
+
},
|
|
635
|
+
],
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
const result = validateKGCMarkdown(doc);
|
|
639
|
+
expect(result.success).toBe(false);
|
|
640
|
+
});
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
// =============================================================================
|
|
644
|
+
// Integration Tests - Schema Composition
|
|
645
|
+
// =============================================================================
|
|
646
|
+
|
|
647
|
+
describe('Schema Integration', () => {
|
|
648
|
+
it('should compose RunCapsule with ToolTraceEntry and Receipt', () => {
|
|
649
|
+
const trace1 = {
|
|
650
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
651
|
+
timestamp: 1703001600000,
|
|
652
|
+
toolName: 'Bash',
|
|
653
|
+
input: { command: 'npm test' },
|
|
654
|
+
duration: 2000,
|
|
655
|
+
status: 'success',
|
|
656
|
+
};
|
|
657
|
+
|
|
658
|
+
const trace2 = {
|
|
659
|
+
id: '223e4567-e89b-12d3-a456-426614174000',
|
|
660
|
+
timestamp: 1703001602000,
|
|
661
|
+
toolName: 'Write',
|
|
662
|
+
input: { file_path: '/home/user/file.txt', content: 'test' },
|
|
663
|
+
duration: 50,
|
|
664
|
+
status: 'success',
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
const receipt = {
|
|
668
|
+
id: '550e8400-e29b-41d4-a716-446655440000',
|
|
669
|
+
timestamp: 1703001610000,
|
|
670
|
+
runId: 'run-001',
|
|
671
|
+
actor: 'agent:test',
|
|
672
|
+
action: 'execute',
|
|
673
|
+
payload: {},
|
|
674
|
+
result: { success: true },
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
const capsule = {
|
|
678
|
+
id: 'run-001',
|
|
679
|
+
startTime: 1703001600000,
|
|
680
|
+
endTime: 1703001610000,
|
|
681
|
+
status: 'completed',
|
|
682
|
+
input: { task: 'Test task' },
|
|
683
|
+
output: { success: true, results: {} },
|
|
684
|
+
trace: [trace1, trace2],
|
|
685
|
+
actor: 'agent:test',
|
|
686
|
+
receipt,
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
const result = validateRunCapsule(capsule);
|
|
690
|
+
expect(result.success).toBe(true);
|
|
691
|
+
expect(result.data.trace.length).toBe(2);
|
|
692
|
+
expect(result.data.receipt).toBeDefined();
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
it('should compose WorkItem with Bounds', () => {
|
|
696
|
+
const bounds = {
|
|
697
|
+
maxFiles: 50,
|
|
698
|
+
maxBytes: 5242880,
|
|
699
|
+
maxOps: 500,
|
|
700
|
+
maxRuntime: 60000,
|
|
701
|
+
maxGraphRewrites: 25,
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
const workItem = {
|
|
705
|
+
id: '123e4567-e89b-12d3-a456-426614174000',
|
|
706
|
+
type: 'bounded_task',
|
|
707
|
+
state: 'running',
|
|
708
|
+
createdAt: 1703001600000,
|
|
709
|
+
payload: { bounds },
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
const result = validateWorkItem(workItem);
|
|
713
|
+
expect(result.success).toBe(true);
|
|
714
|
+
expect(result.data.payload.bounds.maxFiles).toBe(50);
|
|
715
|
+
});
|
|
716
|
+
});
|