@auto-engineer/pipeline 1.113.0 → 1.114.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @auto-engineer/pipeline@1.113.0 build /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
2
+ > @auto-engineer/pipeline@1.114.0 build /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
3
3
  > tsc && tsx ../../scripts/fix-esm-imports.ts
4
4
 
5
5
  Fixed ESM imports in dist/
@@ -1,5 +1,5 @@
1
1
 
2
- > @auto-engineer/pipeline@1.112.2 test /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
2
+ > @auto-engineer/pipeline@1.113.0 test /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
3
3
  > vitest run --reporter=dot
4
4
 
5
5
 
@@ -9,6 +9,6 @@
9
9
 
10
10
   Test Files  42 passed (42)
11
11
   Tests  582 passed (582)
12
-  Start at  01:38:58
13
-  Duration  48.37s (transform 10.59s, setup 0ms, collect 21.13s, tests 40.11s, environment 55ms, prepare 33.75s)
12
+  Start at  05:52:09
13
+  Duration  42.70s (transform 8.47s, setup 0ms, collect 17.61s, tests 35.30s, environment 29ms, prepare 29.72s)
14
14
 
@@ -1,4 +1,4 @@
1
1
 
2
- > @auto-engineer/pipeline@1.112.2 type-check /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
2
+ > @auto-engineer/pipeline@1.113.0 type-check /home/runner/work/auto-engineer/auto-engineer/packages/pipeline
3
3
  > tsc --noEmit
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @auto-engineer/pipeline
2
2
 
3
+ ## 1.114.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`9570b75`](https://github.com/BeOnAuto/auto-engineer/commit/9570b75c9312b6b714e8be89960a5ee7de2d8d48) Thanks [@github-actions[bot]](https://github.com/github-actions%5Bbot%5D)! - - **global**: imrpoves ui generation pipeline
8
+ - **component-implementor-react**: rewrite pipeline with parallel gen, fix loops, and evaluation
9
+ - **component-implementor-react**: add test-generation agent
10
+ - **component-implementor-react**: add test-fix agent and loop
11
+ - **component-implementor-react**: add evaluation agent
12
+
13
+ ### Patch Changes
14
+
15
+ - [`cae4cf2`](https://github.com/BeOnAuto/auto-engineer/commit/cae4cf2f82d363ea696bd6cf9f10d5d35364659f) Thanks [@SamHatoum](https://github.com/SamHatoum)! - - Removed internal planning files from the repository
16
+
17
+ - Updated dependencies [[`9570b75`](https://github.com/BeOnAuto/auto-engineer/commit/9570b75c9312b6b714e8be89960a5ee7de2d8d48), [`cae4cf2`](https://github.com/BeOnAuto/auto-engineer/commit/cae4cf2f82d363ea696bd6cf9f10d5d35364659f)]:
18
+ - @auto-engineer/file-store@1.114.0
19
+ - @auto-engineer/message-bus@1.114.0
20
+
3
21
  ## 1.113.0
4
22
 
5
23
  ### Minor Changes
package/package.json CHANGED
@@ -14,8 +14,8 @@
14
14
  "get-port": "^7.1.0",
15
15
  "jose": "^5.9.6",
16
16
  "nanoid": "^5.0.0",
17
- "@auto-engineer/file-store": "1.113.0",
18
- "@auto-engineer/message-bus": "1.113.0"
17
+ "@auto-engineer/file-store": "1.114.0",
18
+ "@auto-engineer/message-bus": "1.114.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/cors": "^2.8.17",
@@ -24,7 +24,7 @@
24
24
  "publishConfig": {
25
25
  "access": "public"
26
26
  },
27
- "version": "1.113.0",
27
+ "version": "1.114.0",
28
28
  "scripts": {
29
29
  "build": "tsc && tsx ../../scripts/fix-esm-imports.ts",
30
30
  "test": "vitest run --reporter=dot",
package/ketchup-plan.md DELETED
@@ -1,1269 +0,0 @@
1
- # Pipeline Package - Ketchup Plan
2
-
3
- ## TODO
4
-
5
- ### Fix Settled Node Labels and Event Routing (Bursts 107-112)
6
-
7
- - [x] Burst 107: processSettledHandler uses descriptor.label for graph node [depends: none]
8
- - [x] Burst 108: bridge filters commands by sourceEventTypes [depends: none]
9
- - [x] Burst 109: builder sets sourceEventTypes from emit chain event type [depends: none]
10
- - [x] Burst 110: Add label and sourceEventTypes to descriptor and builder (merged into 107+109)
11
- - [x] Burst 111: Add source event filtering to bridge (merged into 108)
12
- - [x] Burst 112: Thread source event type through pipeline server [depends: 110, 111]
13
-
14
- ### Graph Rendering Fix (Burst 106)
15
-
16
- - [ ] Burst 106: Show source commands whose events are listened to by the pipeline [depends: none]
17
-
18
- ### Phase 11: 100% Test Coverage (Bursts 93-102)
19
-
20
- **Goal**: Achieve 100% test coverage by testing uncovered code or removing dead code.
21
-
22
- **Current Coverage**: 96.53% lines, 97.13% branches, 94.94% functions
23
-
24
- ---
25
-
26
- #### Burst 93: Exclude barrel exports from coverage
27
-
28
- | Value | Remove false positives from coverage report |
29
- | Approach | Change `src/index.ts` to `src/**/index.ts` in vitest.config.ts |
30
- | Size | S |
31
-
32
- ---
33
-
34
- #### Burst 94: Test config/pipeline-config.ts
35
-
36
- | Value | 0% → 100% coverage for config module |
37
- | Approach | Test pipelineConfig() identity fn and loadPipelineConfig() with mocked loader |
38
- | Size | M |
39
-
40
- ```typescript
41
- it('should return config unchanged', () => {
42
- const config = { plugins: [], pipeline: mockPipeline };
43
- expect(pipelineConfig(config)).toBe(config);
44
- });
45
-
46
- it('should load plugins and adapt handlers', async () => {
47
- const config = { plugins: ['./test-plugin'], pipeline: mockPipeline };
48
- const result = await loadPipelineConfig(config, '/workspace');
49
- expect(result.handlers).toBeDefined();
50
- expect(result.pipeline).toBe(mockPipeline);
51
- });
52
- ```
53
-
54
- ---
55
-
56
- #### Burst 95: Test filter-graph.ts addEdgeIfNew (lines 63-69)
57
-
58
- | Value | Cover duplicate edge scenario |
59
- | Approach | Test graph with duplicate edges when maintainEdges=true |
60
- | Size | S |
61
-
62
- ```typescript
63
- it('should deduplicate edges when reconnecting', () => {
64
- const graph = {
65
- nodes: [{ id: 'a', type: 'command', label: 'A' }, { id: 'b', type: 'event', label: 'B' }, { id: 'c', type: 'command', label: 'C' }],
66
- edges: [{ from: 'a', to: 'b' }, { from: 'a', to: 'b' }] // Duplicate
67
- };
68
- const result = filterGraph(graph, { excludeTypes: [], maintainEdges: true });
69
- // Edges should be deduplicated
70
- });
71
- ```
72
-
73
- ---
74
-
75
- #### Burst 96: Test await-tracker-projection.ts null document errors (lines 48-49, 60-61)
76
-
77
- | Value | Cover error paths |
78
- | Approach | Test evolve() throws when applying events to null document |
79
- | Size | S |
80
-
81
- ```typescript
82
- it('should throw when applying AwaitItemCompleted to null', () => {
83
- expect(() => evolve(null, { type: 'AwaitItemCompleted', data: { correlationId: 'c1', key: 'k', result: {} } }))
84
- .toThrow('Cannot apply AwaitItemCompleted to null document');
85
- });
86
-
87
- it('should throw when applying AwaitCompleted to null', () => {
88
- expect(() => evolve(null, { type: 'AwaitCompleted', data: { correlationId: 'c1' } }))
89
- .toThrow('Cannot apply AwaitCompleted to null document');
90
- });
91
- ```
92
-
93
- ---
94
-
95
- #### Burst 97: Remove or test phased-executor.ts getActiveSessionCount (lines 99-101)
96
-
97
- | Value | Remove dead code or add test |
98
- | Approach | Check if used; if not, remove; if used, test |
99
- | Size | S |
100
-
101
- ---
102
-
103
- #### Burst 98: Test pipeline-runtime.ts fallback path (line 46)
104
-
105
- | Value | Cover when ctx.startPhased is undefined |
106
- | Approach | Call handleEvent with context missing startPhased |
107
- | Size | S |
108
-
109
- ```typescript
110
- it('should fallback to executeForEachPhasedHandler when ctx.startPhased undefined', async () => {
111
- const ctx = { correlationId: 'c1', emit: vi.fn(), sendCommand: vi.fn() }; // No startPhased
112
- await runtime.handleEvent(event, ctx);
113
- expect(ctx.sendCommand).toHaveBeenCalled(); // Fallback dispatched commands
114
- });
115
- ```
116
-
117
- ---
118
-
119
- #### Burst 99: Remove or test settled-tracker.ts getRegisteredHandlerCount (lines 62-63)
120
-
121
- | Value | Remove dead code or add test |
122
- | Approach | Check if used; if not, remove; if used, test |
123
- | Size | S |
124
-
125
- ---
126
-
127
- #### Burst 100: Test sse-manager.ts clientCount getter (lines 14-15)
128
-
129
- | Value | Cover getter or remove if dead |
130
- | Approach | Check usage; test or remove |
131
- | Size | S |
132
-
133
- ```typescript
134
- it('should return client count', () => {
135
- const manager = new SSEManager();
136
- expect(manager.clientCount).toBe(0);
137
- manager.addClient('c1', mockResponse);
138
- expect(manager.clientCount).toBe(1);
139
- });
140
- ```
141
-
142
- ---
143
-
144
- #### Burst 101: Test pipeline-read-model.ts line 79 branch
145
-
146
- | Value | Cover endedCount === 0 with no pending items |
147
- | Approach | Create scenario where items exist but all are running then all complete to idle |
148
- | Size | S |
149
-
150
- ---
151
-
152
- #### Burst 102: Final verification - run coverage, all at 100%
153
-
154
- | Value | Confirm 100% coverage achieved |
155
- | Approach | Run pnpm test:coverage, verify all thresholds pass |
156
- | Size | S |
157
-
158
- ---
159
-
160
- ### Phase 10: SQLite Event Store Persistence (Bursts 88-92)
161
-
162
- **Goal**: Replace in-memory event store with SQLite for persistence. Events survive restarts; projections rebuilt from event stream on startup.
163
-
164
- **Current State**:
165
- ```
166
- In-Memory EventStore → In-Memory Projections → Lost on restart
167
- ```
168
-
169
- **Target State**:
170
- ```
171
- SQLite EventStore → Consumer → In-Memory Projections (rebuilt on startup)
172
- ```
173
-
174
- ---
175
-
176
- #### Burst 88: Async createPipelineEventStore with config
177
-
178
- | Value | Enable async initialization and configurable file path |
179
- | Approach | Make createPipelineEventStore async, accept optional config |
180
- | Size | S |
181
-
182
- ```typescript
183
- it('should create event store with default config', async () => {
184
- const context = await createPipelineEventStore();
185
- expect(context.eventStore).toBeDefined();
186
- expect(context.readModel).toBeDefined();
187
- await context.close();
188
- });
189
-
190
- it('should accept custom fileName config', async () => {
191
- const context = await createPipelineEventStore({ fileName: ':memory:' });
192
- expect(context.eventStore).toBeDefined();
193
- await context.close();
194
- });
195
- ```
196
-
197
- ---
198
-
199
- #### Burst 89: SQLite event store with schema auto-migration
200
-
201
- | Value | Events persist to SQLite file |
202
- | Approach | Replace getInMemoryEventStore with getSQLiteEventStore |
203
- | Size | M |
204
-
205
- ```typescript
206
- it('should persist events to SQLite', async () => {
207
- const context = await createPipelineEventStore({ fileName: ':memory:' });
208
- await context.eventStore.appendToStream('test-stream', [
209
- { type: 'TestEvent', data: { value: 42 } }
210
- ]);
211
- const stream = await context.eventStore.readStream('test-stream');
212
- expect(stream.events).toHaveLength(1);
213
- await context.close();
214
- });
215
- ```
216
-
217
- ---
218
-
219
- #### Burst 90: Consumer replays events to projections
220
-
221
- | Value | Projections rebuilt from event stream on startup |
222
- | Approach | Consumer with projection-updater processor from BEGINNING |
223
- | Size | M |
224
-
225
- ```typescript
226
- it('should replay events to projections on startup', async () => {
227
- const context = await createPipelineEventStore({ fileName: ':memory:' });
228
- await context.eventStore.appendToStream('pipeline-c1', [
229
- { type: 'ItemStatusChanged', data: { correlationId: 'c1', commandType: 'Cmd', itemKey: 'k1', requestId: 'r1', status: 'running', attemptCount: 1 } }
230
- ]);
231
- // Allow consumer to process
232
- await new Promise(resolve => setTimeout(resolve, 50));
233
- const item = await context.readModel.getItemStatus('c1', 'Cmd', 'k1');
234
- expect(item?.status).toBe('running');
235
- await context.close();
236
- });
237
- ```
238
-
239
- ---
240
-
241
- #### Burst 91: close() stops and closes consumer
242
-
243
- | Value | Clean shutdown without resource leaks |
244
- | Approach | Call consumer.stop() and consumer.close() in close() |
245
- | Size | S |
246
-
247
- ```typescript
248
- it('should stop consumer on close', async () => {
249
- const context = await createPipelineEventStore({ fileName: ':memory:' });
250
- await context.close();
251
- // No error means success - consumer stopped cleanly
252
- });
253
- ```
254
-
255
- ---
256
-
257
- #### Burst 92: PipelineServer uses async factory
258
-
259
- | Value | Server initializes SQLite event store |
260
- | Approach | Static PipelineServer.create() factory, configurable fileName |
261
- | Size | M |
262
- | Files | `src/server/pipeline-server.ts` |
263
-
264
- ```typescript
265
- it('should create server with async event store initialization', async () => {
266
- const server = await PipelineServer.create({ port: 0 });
267
- expect(server.port).toBeGreaterThan(0);
268
- await server.stop();
269
- });
270
- ```
271
-
272
- ---
273
-
274
- ### Phase 9: Remove Dual Caches - Pure Event Sourcing (Bursts 71-87)
275
-
276
- **Goal**: Remove `nodeStatusCache` and `itemStatusCache` from PipelineServer. All runtime state derived from Emmett projections via `PipelineReadModel`.
277
-
278
- **Current State** (dual source of truth):
279
-
280
- ```
281
- Commands → Cache (mutable) + Emmett Events → Projections
282
- ↓ ↓
283
- Used for lookups Also stores same data
284
- ```
285
-
286
- **Target State** (single source of truth):
287
-
288
- ```
289
- Commands → Emmett Events → Projections → ReadModel queries
290
- ```
291
-
292
- ---
293
-
294
- #### Burst 71: Add getNodeStatus query (test)
295
-
296
- | Value | Query node status from projection |
297
- | Approach | `getNodeStatus(correlationId, commandName)` returns status or null |
298
- | Size | S |
299
-
300
- ```typescript
301
- it("should return null when no node status exists", async () => {
302
- const result = await readModel.getNodeStatus("c1", "CreateUser");
303
- expect(result).toBeNull();
304
- });
305
-
306
- it("should return node status from NodeStatus collection", async () => {
307
- const collection =
308
- database.collection<WithId<NodeStatusDocument>>("NodeStatus");
309
- await collection.insertOne({
310
- _id: "ns-c1-CreateUser",
311
- correlationId: "c1",
312
- commandName: "CreateUser",
313
- status: "running",
314
- pendingCount: 1,
315
- endedCount: 0,
316
- });
317
-
318
- const result = await readModel.getNodeStatus("c1", "CreateUser");
319
- expect(result).toEqual({
320
- correlationId: "c1",
321
- commandName: "CreateUser",
322
- status: "running",
323
- pendingCount: 1,
324
- endedCount: 0,
325
- });
326
- });
327
- ```
328
-
329
- ---
330
-
331
- #### Burst 72: Add getNodeStatus query (implement)
332
-
333
- | Value | Can query node status from projection |
334
- | Approach | Query NodeStatus collection with filter |
335
- | Size | S |
336
- | Files | `src/store/pipeline-read-model.ts` |
337
-
338
- ---
339
-
340
- #### Burst 73: Add getItemStatus query (test)
341
-
342
- | Value | Query item status from projection |
343
- | Approach | `getItemStatus(correlationId, commandType, itemKey)` returns ItemStatusDocument or null |
344
- | Size | S |
345
-
346
- ```typescript
347
- it("should return null when no item status exists", async () => {
348
- const result = await readModel.getItemStatus("c1", "CreateUser", "item1");
349
- expect(result).toBeNull();
350
- });
351
-
352
- it("should return item status from ItemStatus collection", async () => {
353
- const collection =
354
- database.collection<WithId<ItemStatusDocument>>("ItemStatus");
355
- await collection.insertOne({
356
- _id: "is-c1-CreateUser-item1",
357
- correlationId: "c1",
358
- commandType: "CreateUser",
359
- itemKey: "item1",
360
- currentRequestId: "r1",
361
- status: "running",
362
- attemptCount: 1,
363
- });
364
-
365
- const result = await readModel.getItemStatus("c1", "CreateUser", "item1");
366
- expect(result).toMatchObject({
367
- correlationId: "c1",
368
- commandType: "CreateUser",
369
- itemKey: "item1",
370
- attemptCount: 1,
371
- });
372
- });
373
- ```
374
-
375
- ---
376
-
377
- #### Burst 74: Add getItemStatus query (implement)
378
-
379
- | Value | Can query item status from projection |
380
- | Approach | Query ItemStatus collection with filter |
381
- | Size | S |
382
- | Files | `src/store/pipeline-read-model.ts` |
383
-
384
- ---
385
-
386
- #### Burst 75: Replace previousStatus lookup (test)
387
-
388
- | Value | Get previousStatus from projection instead of cache |
389
- | Approach | Verify `updateNodeStatus` emits correct previousStatus |
390
- | Size | M |
391
-
392
- Existing tests should pass with projection-based previousStatus lookup.
393
-
394
- ---
395
-
396
- #### Burst 76: Replace previousStatus lookup (implement)
397
-
398
- | Value | Remove nodeStatusCache usage in updateNodeStatus |
399
- | Approach | Query `readModel.getNodeStatus()` for previousStatus |
400
- | Size | M |
401
- | Files | `src/server/pipeline-server.ts` lines 468-478 |
402
-
403
- ```typescript
404
- private async updateNodeStatus(correlationId: string, commandName: string, status: NodeStatus): Promise<void> {
405
- const existing = await this.eventStoreContext.readModel.getNodeStatus(correlationId, commandName);
406
- const previousStatus: NodeStatus = existing?.status ?? 'idle';
407
- await this.emitNodeStatusChanged(correlationId, commandName, status, previousStatus);
408
- await this.broadcastNodeStatusChanged(correlationId, commandName, status, previousStatus);
409
- }
410
- ```
411
-
412
- ---
413
-
414
- #### Burst 77: Replace hasCorrelation check (test)
415
-
416
- | Value | Detect new correlationId via projection |
417
- | Approach | Test that PipelineRunStarted is emitted only for new correlationIds |
418
- | Size | M |
419
-
420
- Existing broadcast tests should pass with projection-based detection.
421
-
422
- ---
423
-
424
- #### Burst 78: Replace hasCorrelation check (implement)
425
-
426
- | Value | Remove nodeStatusCache.has() check |
427
- | Approach | Use `readModel.hasCorrelation()` instead |
428
- | Size | M |
429
- | Files | `src/server/pipeline-server.ts` line 874 |
430
-
431
- ```typescript
432
- const isNewCorrelationId =
433
- !(await this.eventStoreContext.readModel.hasCorrelation(
434
- command.correlationId
435
- ));
436
- ```
437
-
438
- ---
439
-
440
- #### Burst 79: Replace item creation/update logic (test)
441
-
442
- | Value | Get/create item status from projection |
443
- | Approach | Test item creation with correct attemptCount from projection |
444
- | Size | M |
445
-
446
- ```typescript
447
- it("should increment attemptCount on retry", async () => {
448
- // First command creates item with attemptCount=1
449
- // Second command (same itemKey) should have attemptCount=2
450
- });
451
- ```
452
-
453
- ---
454
-
455
- #### Burst 80: Replace item creation/update logic (implement)
456
-
457
- | Value | Remove itemStatusCache from getOrCreateItemStatus |
458
- | Approach | Query projection for existing item, derive attemptCount |
459
- | Size | M |
460
- | Files | `src/server/pipeline-server.ts` lines 520-565 |
461
-
462
- ```typescript
463
- private async getOrCreateItemStatus(
464
- correlationId: string,
465
- commandType: string,
466
- itemKey: string,
467
- requestId: string,
468
- ): Promise<{ attemptCount: number }> {
469
- const existing = await this.eventStoreContext.readModel.getItemStatus(correlationId, commandType, itemKey);
470
- const attemptCount = (existing?.attemptCount ?? 0) + 1;
471
-
472
- await this.emitItemStatusChanged(
473
- correlationId,
474
- commandType,
475
- itemKey,
476
- requestId,
477
- 'running',
478
- attemptCount,
479
- );
480
-
481
- return { attemptCount };
482
- }
483
- ```
484
-
485
- ---
486
-
487
- #### Burst 81: Replace item update logic (test)
488
-
489
- | Value | Update item status via events only |
490
- | Approach | Test item status update emits event with correct data |
491
- | Size | S |
492
-
493
- Existing tests should pass with event-only updates.
494
-
495
- ---
496
-
497
- #### Burst 82: Replace item update logic (implement)
498
-
499
- | Value | Remove itemStatusCache from updateItemStatus |
500
- | Approach | Query projection for currentRequestId and attemptCount, emit event |
501
- | Size | S |
502
- | Files | `src/server/pipeline-server.ts` lines 567-591 |
503
-
504
- ```typescript
505
- private async updateItemStatus(
506
- correlationId: string,
507
- commandType: string,
508
- itemKey: string,
509
- status: 'running' | 'success' | 'error',
510
- ): Promise<void> {
511
- const existing = await this.eventStoreContext.readModel.getItemStatus(correlationId, commandType, itemKey);
512
- if (existing !== null) {
513
- await this.emitItemStatusChanged(
514
- correlationId,
515
- commandType,
516
- itemKey,
517
- existing.currentRequestId,
518
- status,
519
- existing.attemptCount,
520
- );
521
- }
522
- }
523
- ```
524
-
525
- ---
526
-
527
- #### Burst 83: Remove nodeStatusCache field
528
-
529
- | Value | Single source of truth |
530
- | Approach | Delete the field declaration |
531
- | Size | S |
532
- | Files | `src/server/pipeline-server.ts` line 465 |
533
-
534
- ---
535
-
536
- #### Burst 84: Remove itemStatusCache field
537
-
538
- | Value | Single source of truth |
539
- | Approach | Delete the field declaration |
540
- | Size | S |
541
- | Files | `src/server/pipeline-server.ts` line 466 |
542
-
543
- ---
544
-
545
- #### Burst 85: Remove ItemStatus interface (if unused)
546
-
547
- | Value | Clean up dead code |
548
- | Approach | Delete if no longer referenced |
549
- | Size | S |
550
- | Files | `src/server/pipeline-server.ts` lines 44-51 |
551
-
552
- ---
553
-
554
- #### Burst 86: Remove latestCorrelationId field
555
-
556
- | Value | Derive from LatestRunProjection |
557
- | Approach | Query LatestRun projection instead |
558
- | Size | S |
559
- | Files | `src/server/pipeline-server.ts` lines 67, 877 |
560
-
561
- ---
562
-
563
- #### Burst 87: Final verification and cleanup
564
-
565
- | Value | All tests pass, no dual state |
566
- | Approach | Run full test suite, verify 100% coverage |
567
- | Size | M |
568
-
569
- **Success Criteria:**
570
-
571
- 1. ✅ `nodeStatusCache` field removed
572
- 2. ✅ `itemStatusCache` field removed
573
- 3. ✅ `ItemStatus` interface removed (if unused)
574
- 4. ✅ `latestCorrelationId` derived from projection
575
- 5. ✅ All state queries go through `PipelineReadModel`
576
- 6. ✅ All tests pass with 100% coverage
577
- 7. ✅ No mutable Maps tracking runtime state in PipelineServer
578
-
579
- ---
580
-
581
- ### Phase 3: Phased Execution Pattern (Bursts 27-34)
582
-
583
- #### Burst 27: ForEachBuilder Interface & TriggerBuilder.forEach()
584
-
585
- | Value | Entry point to phased execution pattern |
586
- | Approach | TriggerBuilder.forEach() returns ForEachBuilder |
587
- | Size | S |
588
-
589
- ```typescript
590
- it("should return ForEachBuilder from TriggerBuilder.forEach()", () => {
591
- type ItemsEvent = { data: { items: Array<{ id: string }> } };
592
- const builder = define("test")
593
- .on("ItemsReady")
594
- .forEach((e: ItemsEvent) => e.data.items);
595
-
596
- expect(builder).toBeDefined();
597
- expect(typeof builder.groupInto).toBe("function");
598
- });
599
- ```
600
-
601
- ---
602
-
603
- #### Burst 28: ForEachBuilder.groupInto() with phases
604
-
605
- | Value | Define execution phases for items |
606
- | Approach | groupInto() accepts phase names and classifier |
607
- | Size | M |
608
-
609
- ```typescript
610
- it("should configure phases with groupInto()", () => {
611
- type Item = { id: string; type: "critical" | "normal" };
612
- const pipeline = define("test")
613
- .on("ItemsReady")
614
- .forEach((e: { data: { items: Item[] } }) => e.data.items)
615
- .groupInto(["critical", "normal"], (item: Item) => item.type)
616
- .process("ProcessItem", (item: Item) => ({ itemId: item.id }))
617
- .build();
618
-
619
- const handler = pipeline.descriptor.handlers[0] as ForEachPhasedDescriptor;
620
- expect(handler.phases).toEqual(["critical", "normal"]);
621
- });
622
- ```
623
-
624
- ---
625
-
626
- #### Burst 29: PhasedBuilder.process() with emit factory
627
-
628
- | Value | Define command emission for each item |
629
- | Approach | process() accepts commandType and data factory |
630
- | Size | S |
631
-
632
- ```typescript
633
- it("should configure emitFactory with process()", () => {
634
- type Item = { id: string };
635
- const pipeline = define("test")
636
- .on("ItemsReady")
637
- .forEach((e: { data: { items: Item[] } }) => e.data.items)
638
- .groupInto(["phase1"], () => "phase1")
639
- .process("ProcessItem", (item: Item) => ({ itemId: item.id }))
640
- .build();
641
-
642
- const handler = pipeline.descriptor.handlers[0] as ForEachPhasedDescriptor;
643
- expect(typeof handler.emitFactory).toBe("function");
644
- });
645
- ```
646
-
647
- ---
648
-
649
- #### Burst 30: PhasedBuilder.stopOnFailure()
650
-
651
- | Value | Configure failure behavior |
652
- | Approach | stopOnFailure() sets flag in descriptor |
653
- | Size | S |
654
-
655
- ```typescript
656
- it("should set stopOnFailure flag", () => {
657
- const pipeline = define("test")
658
- .on("ItemsReady")
659
- .forEach((e: { data: { items: unknown[] } }) => e.data.items)
660
- .groupInto(["phase1"], () => "phase1")
661
- .process("ProcessItem", () => ({}))
662
- .stopOnFailure()
663
- .build();
664
-
665
- const handler = pipeline.descriptor.handlers[0] as ForEachPhasedDescriptor;
666
- expect(handler.stopOnFailure).toBe(true);
667
- });
668
- ```
669
-
670
- ---
671
-
672
- #### Burst 31: PhasedBuilder.onComplete()
673
-
674
- | Value | Configure completion events |
675
- | Approach | onComplete() sets success/failure event types |
676
- | Size | M |
677
-
678
- ```typescript
679
- it("should configure completion events", () => {
680
- type Item = { id: string };
681
- const pipeline = define("test")
682
- .on("ItemsReady")
683
- .forEach((e: { data: { items: Item[] } }) => e.data.items)
684
- .groupInto(["phase1"], () => "phase1")
685
- .process("ProcessItem", (item: Item) => ({ itemId: item.id }))
686
- .onComplete({
687
- success: "AllItemsProcessed",
688
- failure: "ProcessingFailed",
689
- itemKey: (e: { data: { itemId: string } }) => e.data.itemId,
690
- })
691
- .build();
692
-
693
- const handler = pipeline.descriptor.handlers[0] as ForEachPhasedDescriptor;
694
- expect(handler.completion.successEvent).toBe("AllItemsProcessed");
695
- expect(handler.completion.failureEvent).toBe("ProcessingFailed");
696
- });
697
- ```
698
-
699
- ---
700
-
701
- #### Burst 32: Chaining from PhasedBuilder
702
-
703
- | Value | Continue pipeline definition after phased |
704
- | Approach | PhasedBuilder returns to chain |
705
- | Size | S |
706
-
707
- ```typescript
708
- it("should chain on() from PhasedBuilder", () => {
709
- const pipeline = define("test")
710
- .on("ItemsReady")
711
- .forEach((e: { data: { items: unknown[] } }) => e.data.items)
712
- .groupInto(["phase1"], () => "phase1")
713
- .process("ProcessItem", () => ({}))
714
- .onComplete({ success: "Done", failure: "Failed", itemKey: () => "" })
715
- .on("Done")
716
- .emit("Notify", {})
717
- .build();
718
-
719
- expect(pipeline.descriptor.handlers).toHaveLength(2);
720
- });
721
- ```
722
-
723
- ---
724
-
725
- #### Burst 33: Default stopOnFailure behavior
726
-
727
- | Value | Sensible defaults |
728
- | Approach | stopOnFailure defaults to false |
729
- | Size | S |
730
-
731
- ```typescript
732
- it("should default stopOnFailure to false", () => {
733
- const pipeline = define("test")
734
- .on("ItemsReady")
735
- .forEach((e: { data: { items: unknown[] } }) => e.data.items)
736
- .groupInto(["phase1"], () => "phase1")
737
- .process("ProcessItem", () => ({}))
738
- .onComplete({ success: "Done", failure: "Failed", itemKey: () => "" })
739
- .build();
740
-
741
- const handler = pipeline.descriptor.handlers[0] as ForEachPhasedDescriptor;
742
- expect(handler.stopOnFailure).toBe(false);
743
- });
744
- ```
745
-
746
- ---
747
-
748
- #### Burst 34: Phase 3 Integration Test
749
-
750
- | Value | Validate complete phased pipeline |
751
- | Approach | Integration test with realistic scenario |
752
- | Size | M |
753
-
754
- ```typescript
755
- it("should create complete phased execution pipeline", () => {
756
- type Component = { path: string; priority: "high" | "medium" | "low" };
757
- type ComponentEvent = { data: { components: Component[] } };
758
-
759
- const pipeline = define("component-processor")
760
- .version("1.0.0")
761
- .description("Process components in priority phases")
762
- .on("ComponentsGenerated")
763
- .when((e: ComponentEvent) => e.data.components.length > 0)
764
- .forEach((e: ComponentEvent) => e.data.components)
765
- .groupInto(["high", "medium", "low"], (c: Component) => c.priority)
766
- .process("ImplementComponent", (c: Component) => ({
767
- componentPath: c.path,
768
- }))
769
- .stopOnFailure()
770
- .onComplete({
771
- success: "AllComponentsImplemented",
772
- failure: "ComponentImplementationFailed",
773
- itemKey: (e: { data: { componentPath: string } }) => e.data.componentPath,
774
- })
775
- .build();
776
-
777
- expect(pipeline.descriptor.name).toBe("component-processor");
778
- const handler = pipeline.descriptor.handlers[0] as ForEachPhasedDescriptor;
779
- expect(handler.type).toBe("foreach-phased");
780
- expect(handler.phases).toEqual(["high", "medium", "low"]);
781
- expect(handler.stopOnFailure).toBe(true);
782
- });
783
- ```
784
-
785
- ---
786
-
787
- ### Phase 4: Custom Handlers (Bursts 35-37)
788
-
789
- #### Burst 35: TriggerBuilder.handle() basic
790
-
791
- | Value | Escape hatch for imperative logic |
792
- | Approach | handle() accepts async handler function |
793
- | Size | S |
794
-
795
- ```typescript
796
- it("should capture custom handler", () => {
797
- const handler = async (e: { data: unknown }) => {
798
- console.log(e);
799
- };
800
- const pipeline = define("test").on("CustomEvent").handle(handler).build();
801
-
802
- const desc = pipeline.descriptor.handlers[0] as CustomHandlerDescriptor;
803
- expect(desc.type).toBe("custom");
804
- expect(desc.handler).toBe(handler);
805
- });
806
- ```
807
-
808
- ---
809
-
810
- #### Burst 36: handle() with declaredEmits
811
-
812
- | Value | Graph introspection support |
813
- | Approach | Optional second param for declared emits |
814
- | Size | S |
815
-
816
- ```typescript
817
- it("should capture declaredEmits for graph introspection", () => {
818
- const pipeline = define("test")
819
- .on("CustomEvent")
820
- .handle(async () => {}, { emits: ["EventA", "EventB"] })
821
- .build();
822
-
823
- const desc = pipeline.descriptor.handlers[0] as CustomHandlerDescriptor;
824
- expect(desc.declaredEmits).toEqual(["EventA", "EventB"]);
825
- });
826
- ```
827
-
828
- ---
829
-
830
- #### Burst 37: Phase 4 Integration & Chaining
831
-
832
- | Value | Complete custom handler support |
833
- | Approach | Chaining from handle() |
834
- | Size | S |
835
-
836
- ```typescript
837
- it("should chain on() from handle()", () => {
838
- const pipeline = define("test")
839
- .on("EventA")
840
- .handle(async () => {})
841
- .on("EventB")
842
- .emit("CommandB", {})
843
- .build();
844
-
845
- expect(pipeline.descriptor.handlers).toHaveLength(2);
846
- });
847
- ```
848
-
849
- ---
850
-
851
- ### Phase 5: Graph Extraction (Bursts 38-42)
852
-
853
- #### Burst 38: GraphIR type definition
854
-
855
- | Value | Intermediate representation for visualization |
856
- | Approach | Define nodes and edges types |
857
- | Size | S |
858
-
859
- ```typescript
860
- it("should define GraphIR with nodes and edges", () => {
861
- const graph: GraphIR = {
862
- nodes: [
863
- { id: "evt:Start", type: "event", label: "Start" },
864
- { id: "cmd:Process", type: "command", label: "Process" },
865
- ],
866
- edges: [{ from: "evt:Start", to: "cmd:Process", label: "triggers" }],
867
- };
868
- expect(graph.nodes).toHaveLength(2);
869
- });
870
- ```
871
-
872
- ---
873
-
874
- #### Burst 39: Pipeline.toGraph() basic
875
-
876
- | Value | Extract graph from pipeline |
877
- | Approach | toGraph() method on Pipeline |
878
- | Size | M |
879
-
880
- ```typescript
881
- it("should extract graph from emit handler", () => {
882
- const pipeline = define("test").on("Start").emit("Process", {}).build();
883
-
884
- const graph = pipeline.toGraph();
885
- expect(graph.nodes.some((n) => n.id === "evt:Start")).toBe(true);
886
- expect(graph.nodes.some((n) => n.id === "cmd:Process")).toBe(true);
887
- });
888
- ```
889
-
890
- ---
891
-
892
- #### Burst 40: toGraph() with run-await handlers
893
-
894
- | Value | Graph extraction for scatter-gather |
895
- | Approach | Include await relationships |
896
- | Size | M |
897
-
898
- ---
899
-
900
- #### Burst 41: toGraph() with foreach-phased handlers
901
-
902
- | Value | Graph extraction for phased execution |
903
- | Approach | Include phase groupings |
904
- | Size | M |
905
-
906
- ---
907
-
908
- #### Burst 42: toGraph() with custom handlers
909
-
910
- | Value | Graph extraction using declaredEmits |
911
- | Approach | Use declaredEmits for edges |
912
- | Size | S |
913
-
914
- ---
915
-
916
- ### Phase 6: Cloud Abstractions (Bursts 43-48)
917
-
918
- (Deferred - interfaces only, no runtime implementation yet)
919
-
920
- ---
921
-
922
- ### Phase 7: Pipeline Runtime (Bursts 49-54)
923
-
924
- (Deferred - requires Phase 6 abstractions)
925
-
926
- ---
927
-
928
- ## DONE
929
-
930
- ### Phase 13: PipelineRunCompleted Event (Bursts 107-112) ✅
931
-
932
- - [x] Burst 107: Create QuiescenceTracker class with increment/decrement/isQuiescent (f4bc85c4)
933
- - [x] Burst 108: Add debounce logic to QuiescenceTracker with configurable delay (411129cb)
934
- - [x] Burst 109-111: Wire QuiescenceTracker into PipelineServer, emit PipelineRunCompleted (0011d83b)
935
- - [x] Burst 112: Verify quiescence tracking handles retries naturally (bb928573)
936
-
937
- ---
938
-
939
- ### Command Concurrency Control (Bursts CG-1 to CG-8) ✅
940
-
941
- - [x] Burst CG-1: Gate registration + passthrough (d0a733c8)
942
- - [x] Burst CG-2: Cancel-in-progress (a6f2f3dc)
943
- - [x] Burst CG-3: Queue enqueue + drain + FIFO (852f4f2b)
944
- - [x] Burst CG-4: PipelineContext signal + server wiring (6f1ba55e)
945
- - [x] Burst CG-5: processCommand integration (49b44544)
946
- - [x] Burst CG-6: Cancel-in-progress through server (acf1064d)
947
- - [x] Burst CG-7: Queue + dispatch paths through server (7a8a4bd3)
948
- - [x] Burst CG-8: Config-level concurrency wiring (b5db28a1)
949
-
950
- ---
951
-
952
- ### V2 Engine Internal Swap ✅
953
-
954
- - [x] Burst V2-1: Add processKeyed/getState/resetInstance to WorkflowProcessor [depends: none] (d7b0fbc6)
955
- - [x] Burst V2-2: V2RuntimeBridge — settled path [depends: V2-1] (867c844a)
956
- - [x] Burst V2-3: V2RuntimeBridge — phased path [depends: V2-1] (985add45)
957
- - [x] Burst V2-4: Wire bridge into PipelineServer [depends: V2-2, V2-3] (df6e6fcf)
958
- - [x] Burst V2-5+V2-6: Remove v1 runtime classes and update exports [depends: V2-4] (98b1025c)
959
-
960
- ---
961
-
962
- ### Phase 12: Consistent Non-Blocking Dispatch (Bursts 103-105) ✅
963
-
964
- - [x] Burst 103: Add `await` to `startPhased` call in pipeline-runtime.ts (e9b391f4)
965
- - [x] Burst 104: Make `sendCommand` non-blocking in pipeline-server.ts (2309cf5b)
966
- - [x] Burst 105: Fix phased executor race condition in countPendingInPhase (03f4f951)
967
-
968
- ---
969
-
970
- ### Phase 8: CLI Integration (Bursts 67-70) ✅
971
-
972
- Burst 67-70 complete. E2E tests validate CLI parity.
973
-
974
- ### Burst 69-70: E2E Tests for CLI Parity
975
-
976
- Implemented:
977
-
978
- - 8 E2E tests validating endpoint compatibility
979
- - Tests for `/registry`, `/pipeline`, `/sessions`, `/messages`, `/stats`, `/command`
980
- - Tests for command execution and event routing through pipeline
981
- - Tests for pipeline chain with multiple handlers
982
-
983
- All 99 tests pass with 100% coverage.
984
-
985
- ---
986
-
987
- ### Burst 67-68: Enhanced /pipeline Response
988
-
989
- Implemented:
990
-
991
- - Added `folds: []` to `/registry` response
992
- - Added `commandToEvents` mapping from command handlers
993
- - Added `eventToCommand` mapping from pipeline handlers
994
- - Added `PipelineNode` shape with `id`, `name`, `title`, `status`
995
- - 4 new tests for response shapes
996
-
997
- All 91 tests pass with 100% coverage.
998
-
999
- ---
1000
-
1001
- ### Burst 53-54: AwaitTracker
1002
-
1003
- Implemented:
1004
-
1005
- - `AwaitTracker` class for scatter-gather completion tracking
1006
- - `startAwaiting()` to register pending keys
1007
- - `markComplete()` to mark individual keys as done
1008
- - `isComplete()` to check if all keys are done
1009
- - `getResults()` to collect results and clear tracking
1010
- - 7 tests for await tracking functionality
1011
- - Exported from package index
1012
-
1013
- All 87 tests pass with 100% coverage.
1014
-
1015
- ---
1016
-
1017
- ### Burst 55-66: PipelineServer
1018
-
1019
- Implemented:
1020
-
1021
- - `PipelineServer` class with HTTP endpoints
1022
- - `/health`, `/registry`, `/pipeline`, `/messages`, `/sessions`, `/stats` endpoints
1023
- - `POST /command` with command handler validation and 404 for unknown commands
1024
- - Event routing through registered pipelines
1025
- - Custom handler context support (emit, sendCommand)
1026
- - Command handlers returning multiple events
1027
- - Integration test for complete workflow
1028
- - 16 tests for server functionality
1029
- - Exports added to public API
1030
-
1031
- All 80 tests pass with 100% coverage.
1032
-
1033
- ---
1034
-
1035
- ### Burst 51-52: Run-await and ForEach-phased Runtime
1036
-
1037
- Implemented:
1038
-
1039
- - `handleEvent()` for run-await handlers with command dispatch
1040
- - Data factory support in static run-await commands
1041
- - ForEach-phased item processing with phase ordering
1042
- - Custom handler receives PipelineContext
1043
-
1044
- All 80 tests pass with 100% coverage.
1045
-
1046
- ---
1047
-
1048
- ### Burst 45-50: PipelineRuntime Core
1049
-
1050
- Implemented:
1051
-
1052
- - `PipelineRuntime` class with descriptor and handler index
1053
- - `getHandlersForEvent()` for O(1) handler lookup by event type
1054
- - `getMatchingHandlers()` with predicate filtering
1055
- - `handleEvent()` for emit and custom handlers
1056
- - Data factory resolution for emit handlers
1057
- - 7 tests for runtime functionality
1058
-
1059
- All 59 tests pass with 100% coverage.
1060
-
1061
- ---
1062
-
1063
- ### Burst 43-44: PipelineContext & RuntimeConfig
1064
-
1065
- Implemented:
1066
-
1067
- - `PipelineContext` interface with `emit()`, `sendCommand()`, `correlationId`
1068
- - `RuntimeConfig` interface with optional `defaultTimeout`
1069
- - 4 tests for context/config types
1070
-
1071
- ---
1072
-
1073
- ### Burst 38-42: Phase 5 Graph Extraction
1074
-
1075
- Implemented:
1076
-
1077
- - `GraphIR` type with `nodes` and `edges` arrays
1078
- - `GraphNode` with `id`, `type` ('event' | 'command'), `label`
1079
- - `GraphEdge` with `from`, `to`, optional `label`
1080
- - `Pipeline.toGraph()` method for all handler types
1081
- - Emit handler graph extraction
1082
- - Run-await handler graph extraction with success/failure events
1083
- - Foreach-phased handler graph extraction with completion events
1084
- - Custom handler graph extraction using `declaredEmits`
1085
- - Node deduplication
1086
- - 9 tests for graph functionality
1087
-
1088
- All 46 tests pass with 100% coverage.
1089
-
1090
- ---
1091
-
1092
- ### Burst 35-37: Phase 4 Custom Handlers
1093
-
1094
- Implemented:
1095
-
1096
- - `TriggerBuilder.handle()` with async handler function
1097
- - `handle()` with `declaredEmits` option for graph introspection
1098
- - `HandleChain` for chaining `on()` and `build()`
1099
- - 3 tests for custom handler functionality
1100
-
1101
- All 37 tests pass with 100% coverage.
1102
-
1103
- ---
1104
-
1105
- ### Burst 27-34: Phase 3 Phased Execution Pattern
1106
-
1107
- Implemented:
1108
-
1109
- - `TriggerBuilder.forEach()` returns `ForEachBuilder`
1110
- - `ForEachBuilder.groupInto()` with phase classifier
1111
- - `PhasedBuilder.process()` with emit factory
1112
- - `PhasedChain.stopOnFailure()` optional flag
1113
- - `PhasedChain.onComplete()` with success/failure events
1114
- - `PhasedTerminal` for chaining
1115
- - Integration test with complete phased pipeline
1116
-
1117
- All 34 tests pass with 100% coverage.
1118
-
1119
- ---
1120
-
1121
- ### Burst 19-26: Phase 2 Scatter-Gather Pattern
1122
-
1123
- Implemented:
1124
-
1125
- - `TriggerBuilder.run()` returns `RunBuilder`
1126
- - `run()` accepts static `CommandDispatch[]` or factory function
1127
- - `RunBuilder.awaitAll()` with key extractor and optional timeout
1128
- - `GatherBuilder.onSuccess()` with `SuccessContext`
1129
- - `GatherBuilder.onFailure()` with `FailureContext`
1130
- - Chaining: `on()` and `build()` from `GatherBuilder`
1131
- - Integration test with complete scatter-gather pipeline
1132
-
1133
- New types added:
1134
-
1135
- - `SuccessContext<T>` - results, duration, triggerEvent
1136
- - `FailureContext<T>` - failures, successes, triggerEvent
1137
- - `GatherEventConfig<T>` - eventType, dataFactory
1138
-
1139
- All 26 tests pass with 100% coverage.
1140
-
1141
- ---
1142
-
1143
- ### Burst 13, 15, 18: Remaining Phase 1 features
1144
-
1145
- - emit() with data factory
1146
- - when() predicate for conditional execution
1147
- - Integration test with complete pipeline
1148
-
1149
- All Phase 1 tests pass with 100% coverage.
1150
-
1151
- ---
1152
-
1153
- ### Burst 6-12, 14, 16, 17: Builder API (batched)
1154
-
1155
- Implemented:
1156
-
1157
- - define() entry point
1158
- - version() and description()
1159
- - build() returns frozen Pipeline
1160
- - on() returns TriggerBuilder
1161
- - emit() with static data
1162
- - EmitChain.build() captures handler
1163
- - Parallel emit() chain
1164
- - EmitChain.on() continues chain
1165
- - key() named extractors
1166
-
1167
- All tests pass with 100% coverage.
1168
-
1169
- ---
1170
-
1171
- ### Burst 5: PipelineDescriptor Type
1172
-
1173
- | Value | Pipeline structure definition |
1174
- | Approach | Interface with metadata + handlers array |
1175
- | Size | S |
1176
-
1177
- ```typescript
1178
- it("should create PipelineDescriptor", () => {
1179
- const descriptor: PipelineDescriptor = {
1180
- name: "test-pipeline",
1181
- version: "1.0.0",
1182
- keys: new Map(),
1183
- handlers: [],
1184
- };
1185
- expect(descriptor.name).toBe("test-pipeline");
1186
- });
1187
- ```
1188
-
1189
- ---
1190
-
1191
- ### Burst 4: dispatch() Helper
1192
-
1193
- | Value | Ergonomic CommandDispatch creation |
1194
- | Approach | Simple factory function |
1195
- | Size | S |
1196
-
1197
- ```typescript
1198
- it("should create CommandDispatch via dispatch()", () => {
1199
- const cmd = dispatch("CheckTests", { targetDirectory: "./src" });
1200
- expect(cmd).toEqual({
1201
- commandType: "CheckTests",
1202
- data: { targetDirectory: "./src" },
1203
- });
1204
- });
1205
- ```
1206
-
1207
- ---
1208
-
1209
- ### Burst 3: CommandDispatch Type
1210
-
1211
- | Value | Dispatch instruction type |
1212
- | Approach | Simple interface with commandType + data |
1213
- | Size | S |
1214
-
1215
- ```typescript
1216
- it("should create CommandDispatch with static data", () => {
1217
- const cmd: CommandDispatch = {
1218
- commandType: "CheckTests",
1219
- data: { targetDirectory: "./src", scope: "slice" },
1220
- };
1221
- expect(cmd).toEqual({
1222
- commandType: "CheckTests",
1223
- data: { targetDirectory: "./src", scope: "slice" },
1224
- });
1225
- });
1226
-
1227
- it("should create CommandDispatch with data factory", () => {
1228
- const cmd: CommandDispatch = {
1229
- commandType: "ImplementSlice",
1230
- data: (e) => ({ slicePath: e.data.path }),
1231
- };
1232
- const event: Event = { type: "SliceGenerated", data: { path: "./slice" } };
1233
- const resolved = typeof cmd.data === "function" ? cmd.data(event) : cmd.data;
1234
- expect(resolved).toEqual({ slicePath: "./slice" });
1235
- });
1236
- ```
1237
-
1238
- ---
1239
-
1240
- ### Burst 2: Core Types
1241
-
1242
- | Value | Foundation types |
1243
- | Approach | Re-export message-bus types + add pipeline types |
1244
- | Size | S |
1245
-
1246
- ```typescript
1247
- it("should re-export Command and Event from message-bus", () => {
1248
- const cmd: Command = { type: "Test", data: {} };
1249
- const evt: Event = { type: "TestDone", data: {} };
1250
- expect(cmd.type).toBe("Test");
1251
- expect(evt.type).toBe("TestDone");
1252
- });
1253
- ```
1254
-
1255
- ---
1256
-
1257
- ### Burst 1: Package Scaffold
1258
-
1259
- | Value | Foundation for all work |
1260
- | Approach | Copy patterns from `@auto-engineer/id` |
1261
- | Size | S |
1262
-
1263
- **Files:**
1264
-
1265
- - `package.json` - deps: `@auto-engineer/message-bus: workspace:*`
1266
- - `tsconfig.json` - extends base, composite: true
1267
- - `tsconfig.test.json` - includes \*.specs.ts
1268
- - `vitest.config.ts` - 100% coverage thresholds
1269
- - `src/index.ts` - empty export