@sparkleideas/swarm 3.0.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/MIGRATION.md +472 -0
  2. package/README.md +634 -0
  3. package/__tests__/consensus.test.ts +577 -0
  4. package/__tests__/coordinator.test.ts +501 -0
  5. package/__tests__/queen-coordinator.test.ts +1335 -0
  6. package/__tests__/topology.test.ts +621 -0
  7. package/package.json +32 -0
  8. package/src/agent-pool.ts +476 -0
  9. package/src/application/commands/create-task.command.ts +124 -0
  10. package/src/application/commands/spawn-agent.command.ts +122 -0
  11. package/src/application/index.ts +30 -0
  12. package/src/application/services/swarm-application-service.ts +200 -0
  13. package/src/attention-coordinator.ts +1000 -0
  14. package/src/consensus/byzantine.ts +431 -0
  15. package/src/consensus/gossip.ts +513 -0
  16. package/src/consensus/index.ts +267 -0
  17. package/src/consensus/raft.ts +443 -0
  18. package/src/coordination/agent-registry.ts +544 -0
  19. package/src/coordination/index.ts +23 -0
  20. package/src/coordination/swarm-hub.ts +776 -0
  21. package/src/coordination/task-orchestrator.ts +605 -0
  22. package/src/domain/entities/agent.d.ts +151 -0
  23. package/src/domain/entities/agent.d.ts.map +1 -0
  24. package/src/domain/entities/agent.js +280 -0
  25. package/src/domain/entities/agent.js.map +1 -0
  26. package/src/domain/entities/agent.ts +370 -0
  27. package/src/domain/entities/task.d.ts +133 -0
  28. package/src/domain/entities/task.d.ts.map +1 -0
  29. package/src/domain/entities/task.js +261 -0
  30. package/src/domain/entities/task.js.map +1 -0
  31. package/src/domain/entities/task.ts +319 -0
  32. package/src/domain/index.ts +41 -0
  33. package/src/domain/repositories/agent-repository.interface.d.ts +57 -0
  34. package/src/domain/repositories/agent-repository.interface.d.ts.map +1 -0
  35. package/src/domain/repositories/agent-repository.interface.js +9 -0
  36. package/src/domain/repositories/agent-repository.interface.js.map +1 -0
  37. package/src/domain/repositories/agent-repository.interface.ts +69 -0
  38. package/src/domain/repositories/task-repository.interface.d.ts +61 -0
  39. package/src/domain/repositories/task-repository.interface.d.ts.map +1 -0
  40. package/src/domain/repositories/task-repository.interface.js +9 -0
  41. package/src/domain/repositories/task-repository.interface.js.map +1 -0
  42. package/src/domain/repositories/task-repository.interface.ts +75 -0
  43. package/src/domain/services/coordination-service.ts +320 -0
  44. package/src/federation-hub.d.ts +284 -0
  45. package/src/federation-hub.d.ts.map +1 -0
  46. package/src/federation-hub.js +692 -0
  47. package/src/federation-hub.js.map +1 -0
  48. package/src/federation-hub.ts +979 -0
  49. package/src/index.ts +348 -0
  50. package/src/message-bus.ts +607 -0
  51. package/src/queen-coordinator.ts +2025 -0
  52. package/src/shared/events.ts +285 -0
  53. package/src/shared/types.ts +389 -0
  54. package/src/topology-manager.ts +656 -0
  55. package/src/types.ts +545 -0
  56. package/src/unified-coordinator.ts +1844 -0
  57. package/src/workers/index.ts +65 -0
  58. package/src/workers/worker-dispatch.d.ts +234 -0
  59. package/src/workers/worker-dispatch.d.ts.map +1 -0
  60. package/src/workers/worker-dispatch.js +842 -0
  61. package/src/workers/worker-dispatch.js.map +1 -0
  62. package/src/workers/worker-dispatch.ts +1076 -0
  63. package/tmp.json +0 -0
  64. package/tsconfig.json +9 -0
  65. package/vitest.config.ts +20 -0
@@ -0,0 +1,1335 @@
1
+ /**
2
+ * Queen Coordinator Tests
3
+ *
4
+ * TDD London School methodology tests for the Queen Coordinator.
5
+ * Uses mocks for all dependencies to isolate the unit under test.
6
+ *
7
+ * Test Categories:
8
+ * 1. Initialization and Lifecycle
9
+ * 2. Strategic Task Analysis
10
+ * 3. Agent Delegation
11
+ * 4. Swarm Health Monitoring
12
+ * 5. Consensus Coordination
13
+ * 6. Learning from Outcomes
14
+ * 7. Integration Points
15
+ */
16
+
17
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
18
+ import {
19
+ QueenCoordinator,
20
+ createQueenCoordinator,
21
+ type QueenCoordinatorConfig,
22
+ type ISwarmCoordinator,
23
+ type INeuralLearningSystem,
24
+ type IMemoryService,
25
+ type TaskAnalysis,
26
+ type DelegationPlan,
27
+ type HealthReport,
28
+ type Decision,
29
+ type TaskResult,
30
+ type AgentScore,
31
+ } from '../src/queen-coordinator.js';
32
+ import type {
33
+ AgentState,
34
+ AgentType,
35
+ AgentId,
36
+ TaskDefinition,
37
+ TaskId,
38
+ TaskType,
39
+ TaskPriority,
40
+ CoordinatorMetrics,
41
+ ConsensusResult,
42
+ AgentCapabilities,
43
+ AgentMetrics,
44
+ } from '../src/types.js';
45
+ import type { AgentDomain, DomainStatus } from '../src/unified-coordinator.js';
46
+
47
+ // =============================================================================
48
+ // Mock Factories
49
+ // =============================================================================
50
+
51
+ function createMockSwarmCoordinator(): ISwarmCoordinator {
52
+ return {
53
+ getAgentsByDomain: vi.fn().mockReturnValue([]),
54
+ getAllAgents: vi.fn().mockReturnValue([]),
55
+ getAvailableAgents: vi.fn().mockReturnValue([]),
56
+ getMetrics: vi.fn().mockReturnValue(createMockMetrics()),
57
+ getDomainConfigs: vi.fn().mockReturnValue(new Map()),
58
+ getStatus: vi.fn().mockReturnValue({
59
+ domains: createMockDomainStatuses(),
60
+ metrics: createMockMetrics(),
61
+ }),
62
+ assignTaskToDomain: vi.fn().mockResolvedValue('agent_1'),
63
+ proposeConsensus: vi.fn().mockResolvedValue(createMockConsensusResult(true)),
64
+ broadcastMessage: vi.fn().mockResolvedValue(undefined),
65
+ };
66
+ }
67
+
68
+ function createMockNeuralSystem(): INeuralLearningSystem {
69
+ return {
70
+ initialize: vi.fn().mockResolvedValue(undefined),
71
+ beginTask: vi.fn().mockReturnValue('trajectory_1'),
72
+ recordStep: vi.fn(),
73
+ completeTask: vi.fn().mockResolvedValue(undefined),
74
+ findPatterns: vi.fn().mockResolvedValue([]),
75
+ retrieveMemories: vi.fn().mockResolvedValue([]),
76
+ triggerLearning: vi.fn().mockResolvedValue(undefined),
77
+ };
78
+ }
79
+
80
+ function createMockMemoryService(): IMemoryService {
81
+ return {
82
+ semanticSearch: vi.fn().mockResolvedValue([]),
83
+ store: vi.fn().mockResolvedValue(undefined),
84
+ };
85
+ }
86
+
87
+ function createMockAgent(
88
+ id: string,
89
+ type: AgentType = 'coder',
90
+ status: AgentState['status'] = 'idle'
91
+ ): AgentState {
92
+ return {
93
+ id: {
94
+ id,
95
+ swarmId: 'swarm_1',
96
+ type,
97
+ instance: 1,
98
+ },
99
+ name: `agent-${id}`,
100
+ type,
101
+ status,
102
+ capabilities: createMockCapabilities(),
103
+ metrics: createMockAgentMetrics(),
104
+ workload: 0.3,
105
+ health: 0.9,
106
+ lastHeartbeat: new Date(),
107
+ topologyRole: 'worker',
108
+ connections: [],
109
+ };
110
+ }
111
+
112
+ function createMockCapabilities(): AgentCapabilities {
113
+ return {
114
+ codeGeneration: true,
115
+ codeReview: true,
116
+ testing: true,
117
+ documentation: true,
118
+ research: true,
119
+ analysis: true,
120
+ coordination: false,
121
+ languages: ['typescript', 'javascript'],
122
+ frameworks: ['node', 'vitest'],
123
+ domains: ['backend', 'testing'],
124
+ tools: ['git', 'npm'],
125
+ maxConcurrentTasks: 3,
126
+ maxMemoryUsage: 512 * 1024 * 1024,
127
+ maxExecutionTime: 300000,
128
+ reliability: 0.95,
129
+ speed: 1.0,
130
+ quality: 0.9,
131
+ };
132
+ }
133
+
134
+ function createMockAgentMetrics(): AgentMetrics {
135
+ return {
136
+ tasksCompleted: 10,
137
+ tasksFailed: 1,
138
+ averageExecutionTime: 5000,
139
+ successRate: 0.91,
140
+ cpuUsage: 0.5,
141
+ memoryUsage: 0.4,
142
+ messagesProcessed: 100,
143
+ lastActivity: new Date(),
144
+ responseTime: 50,
145
+ health: 0.9,
146
+ };
147
+ }
148
+
149
+ function createMockTask(
150
+ id: string,
151
+ type: TaskType = 'coding',
152
+ priority: TaskPriority = 'normal'
153
+ ): TaskDefinition {
154
+ return {
155
+ id: {
156
+ id,
157
+ swarmId: 'swarm_1',
158
+ sequence: 1,
159
+ priority,
160
+ },
161
+ type,
162
+ name: `Task ${id}`,
163
+ description: 'A test task for implementation',
164
+ priority,
165
+ status: 'created',
166
+ dependencies: [],
167
+ input: {},
168
+ createdAt: new Date(),
169
+ timeoutMs: 60000,
170
+ retries: 0,
171
+ maxRetries: 3,
172
+ metadata: {},
173
+ };
174
+ }
175
+
176
+ function createMockMetrics(): CoordinatorMetrics {
177
+ return {
178
+ uptime: 3600,
179
+ activeAgents: 5,
180
+ totalTasks: 100,
181
+ completedTasks: 90,
182
+ failedTasks: 5,
183
+ avgTaskDurationMs: 5000,
184
+ messagesPerSecond: 50,
185
+ consensusSuccessRate: 0.95,
186
+ coordinationLatencyMs: 50,
187
+ memoryUsageBytes: 100000000,
188
+ };
189
+ }
190
+
191
+ function createMockDomainStatuses(): DomainStatus[] {
192
+ return [
193
+ {
194
+ name: 'queen',
195
+ agentCount: 1,
196
+ availableAgents: 1,
197
+ busyAgents: 0,
198
+ tasksQueued: 0,
199
+ tasksCompleted: 10,
200
+ },
201
+ {
202
+ name: 'security',
203
+ agentCount: 3,
204
+ availableAgents: 2,
205
+ busyAgents: 1,
206
+ tasksQueued: 2,
207
+ tasksCompleted: 20,
208
+ },
209
+ {
210
+ name: 'core',
211
+ agentCount: 5,
212
+ availableAgents: 3,
213
+ busyAgents: 2,
214
+ tasksQueued: 3,
215
+ tasksCompleted: 30,
216
+ },
217
+ {
218
+ name: 'integration',
219
+ agentCount: 3,
220
+ availableAgents: 2,
221
+ busyAgents: 1,
222
+ tasksQueued: 1,
223
+ tasksCompleted: 25,
224
+ },
225
+ {
226
+ name: 'support',
227
+ agentCount: 3,
228
+ availableAgents: 3,
229
+ busyAgents: 0,
230
+ tasksQueued: 0,
231
+ tasksCompleted: 15,
232
+ },
233
+ ];
234
+ }
235
+
236
+ function createMockConsensusResult(approved: boolean): ConsensusResult {
237
+ return {
238
+ proposalId: 'proposal_1',
239
+ approved,
240
+ approvalRate: approved ? 0.8 : 0.4,
241
+ participationRate: 0.9,
242
+ finalValue: { approved },
243
+ rounds: 1,
244
+ durationMs: 100,
245
+ };
246
+ }
247
+
248
+ function createMockTaskResult(success: boolean): TaskResult {
249
+ return {
250
+ taskId: 'task_1',
251
+ success,
252
+ output: success ? { result: 'completed' } : undefined,
253
+ error: success ? undefined : 'Task failed',
254
+ durationMs: 5000,
255
+ agentId: 'agent_1',
256
+ domain: 'core',
257
+ metrics: {
258
+ startTime: new Date(Date.now() - 5000),
259
+ endTime: new Date(),
260
+ retries: 0,
261
+ resourceUsage: {
262
+ memoryMb: 256,
263
+ cpuPercent: 50,
264
+ },
265
+ stepsCompleted: 5,
266
+ qualityScore: success ? 0.9 : 0.3,
267
+ },
268
+ };
269
+ }
270
+
271
+ // =============================================================================
272
+ // Test Suites
273
+ // =============================================================================
274
+
275
+ describe('QueenCoordinator', () => {
276
+ let queen: QueenCoordinator;
277
+ let mockSwarm: ISwarmCoordinator;
278
+ let mockNeural: INeuralLearningSystem;
279
+ let mockMemory: IMemoryService;
280
+
281
+ beforeEach(() => {
282
+ vi.useFakeTimers();
283
+ mockSwarm = createMockSwarmCoordinator();
284
+ mockNeural = createMockNeuralSystem();
285
+ mockMemory = createMockMemoryService();
286
+ });
287
+
288
+ afterEach(async () => {
289
+ if (queen) {
290
+ await queen.shutdown();
291
+ }
292
+ vi.useRealTimers();
293
+ vi.clearAllMocks();
294
+ });
295
+
296
+ // ===========================================================================
297
+ // Initialization and Lifecycle Tests
298
+ // ===========================================================================
299
+
300
+ describe('Initialization and Lifecycle', () => {
301
+ it('should create queen coordinator with default config', () => {
302
+ queen = createQueenCoordinator(mockSwarm);
303
+
304
+ expect(queen).toBeInstanceOf(QueenCoordinator);
305
+ });
306
+
307
+ it('should create queen coordinator with custom config', () => {
308
+ const config: Partial<QueenCoordinatorConfig> = {
309
+ enableLearning: true,
310
+ patternRetrievalK: 10,
311
+ healthCheckIntervalMs: 5000,
312
+ };
313
+
314
+ queen = createQueenCoordinator(mockSwarm, config, mockNeural, mockMemory);
315
+
316
+ expect(queen).toBeInstanceOf(QueenCoordinator);
317
+ expect(queen.isLearningEnabled()).toBe(true);
318
+ });
319
+
320
+ it('should initialize neural system when learning is enabled', async () => {
321
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: true }, mockNeural);
322
+
323
+ await queen.initialize();
324
+
325
+ expect(mockNeural.initialize).toHaveBeenCalled();
326
+ });
327
+
328
+ it('should not initialize neural system when learning is disabled', async () => {
329
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: false }, mockNeural);
330
+
331
+ await queen.initialize();
332
+
333
+ expect(mockNeural.initialize).not.toHaveBeenCalled();
334
+ });
335
+
336
+ it('should emit initialized event', async () => {
337
+ queen = createQueenCoordinator(mockSwarm);
338
+ const eventHandler = vi.fn();
339
+ queen.on('queen.initialized', eventHandler);
340
+
341
+ await queen.initialize();
342
+
343
+ expect(eventHandler).toHaveBeenCalledWith(
344
+ expect.objectContaining({
345
+ type: 'queen.initialized',
346
+ data: expect.objectContaining({
347
+ learningEnabled: false,
348
+ }),
349
+ })
350
+ );
351
+ });
352
+
353
+ it('should trigger learning on shutdown when enabled', async () => {
354
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: true }, mockNeural);
355
+ await queen.initialize();
356
+
357
+ await queen.shutdown();
358
+
359
+ expect(mockNeural.triggerLearning).toHaveBeenCalled();
360
+ });
361
+
362
+ it('should emit shutdown event', async () => {
363
+ queen = createQueenCoordinator(mockSwarm);
364
+ await queen.initialize();
365
+ const eventHandler = vi.fn();
366
+ queen.on('queen.shutdown', eventHandler);
367
+
368
+ await queen.shutdown();
369
+
370
+ expect(eventHandler).toHaveBeenCalledWith(
371
+ expect.objectContaining({
372
+ type: 'queen.shutdown',
373
+ })
374
+ );
375
+ });
376
+ });
377
+
378
+ // ===========================================================================
379
+ // Strategic Task Analysis Tests
380
+ // ===========================================================================
381
+
382
+ describe('Strategic Task Analysis', () => {
383
+ beforeEach(async () => {
384
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: true }, mockNeural);
385
+ await queen.initialize();
386
+ });
387
+
388
+ it('should analyze a simple coding task', async () => {
389
+ const task = createMockTask('task_1', 'coding');
390
+
391
+ const analysis = await queen.analyzeTask(task);
392
+
393
+ expect(analysis).toMatchObject({
394
+ taskId: 'task_1',
395
+ recommendedDomain: 'integration',
396
+ confidence: expect.any(Number),
397
+ });
398
+ expect(analysis.complexity).toBeGreaterThan(0);
399
+ expect(analysis.complexity).toBeLessThanOrEqual(1);
400
+ expect(analysis.requiredCapabilities).toContain('coding');
401
+ });
402
+
403
+ it('should analyze a testing task', async () => {
404
+ const task = createMockTask('task_2', 'testing');
405
+
406
+ const analysis = await queen.analyzeTask(task);
407
+
408
+ expect(analysis.recommendedDomain).toBe('support');
409
+ expect(analysis.requiredCapabilities).toContain('testing');
410
+ });
411
+
412
+ it('should analyze a security-related task', async () => {
413
+ const task = createMockTask('task_3', 'review');
414
+ task.description = 'Review security implementation for vulnerabilities';
415
+
416
+ const analysis = await queen.analyzeTask(task);
417
+
418
+ expect(analysis.requiredCapabilities).toContain('security');
419
+ });
420
+
421
+ it('should decompose complex coding tasks', async () => {
422
+ const task = createMockTask('task_4', 'coding', 'high');
423
+ // A very long description triggers decomposition (>200 chars)
424
+ task.description = 'Implement a complex feature with multiple components that requires careful design and extensive testing across multiple modules. This task involves creating new API endpoints, database schemas, service layers, and comprehensive unit tests for the entire feature set. Additional requirements include proper error handling, logging, and performance optimization considerations.';
425
+
426
+ const analysis = await queen.analyzeTask(task);
427
+
428
+ expect(analysis.subtasks.length).toBeGreaterThan(0);
429
+ expect(analysis.subtasks.some(st => st.type === 'coding')).toBe(true);
430
+ });
431
+
432
+ it('should query neural system for patterns when learning is enabled', async () => {
433
+ const task = createMockTask('task_5', 'coding');
434
+ vi.mocked(mockNeural.findPatterns).mockResolvedValue([
435
+ {
436
+ patternId: 'pattern_1',
437
+ strategy: 'Use TDD approach',
438
+ successRate: 0.9,
439
+ relevanceScore: 0.8,
440
+ keyLearnings: ['Write tests first'],
441
+ },
442
+ ]);
443
+
444
+ const analysis = await queen.analyzeTask(task);
445
+
446
+ expect(mockNeural.findPatterns).toHaveBeenCalled();
447
+ expect(analysis.matchedPatterns.length).toBe(1);
448
+ expect(analysis.matchedPatterns[0].strategy).toBe('Use TDD approach');
449
+ });
450
+
451
+ it('should filter patterns below threshold', async () => {
452
+ const config = { enableLearning: true, patternThreshold: 0.7 };
453
+ queen = createQueenCoordinator(mockSwarm, config, mockNeural);
454
+ await queen.initialize();
455
+
456
+ vi.mocked(mockNeural.findPatterns).mockResolvedValue([
457
+ { patternId: 'p1', strategy: 'Good', successRate: 0.9, relevanceScore: 0.8 },
458
+ { patternId: 'p2', strategy: 'Low', successRate: 0.5, relevanceScore: 0.5 },
459
+ ]);
460
+
461
+ const task = createMockTask('task_6', 'coding');
462
+ const analysis = await queen.analyzeTask(task);
463
+
464
+ expect(analysis.matchedPatterns.length).toBe(1);
465
+ expect(analysis.matchedPatterns[0].patternId).toBe('p1');
466
+ });
467
+
468
+ it('should calculate resource requirements based on complexity', async () => {
469
+ const task = createMockTask('task_7', 'coding', 'critical');
470
+ task.description = 'Very complex task with many requirements and dependencies';
471
+
472
+ const analysis = await queen.analyzeTask(task);
473
+
474
+ expect(analysis.resourceRequirements).toMatchObject({
475
+ minAgents: expect.any(Number),
476
+ maxAgents: expect.any(Number),
477
+ memoryMb: expect.any(Number),
478
+ cpuIntensive: true,
479
+ });
480
+ });
481
+
482
+ it('should emit task analyzed event', async () => {
483
+ const eventHandler = vi.fn();
484
+ queen.on('queen.task.analyzed', eventHandler);
485
+
486
+ const task = createMockTask('task_8', 'coding');
487
+ await queen.analyzeTask(task);
488
+
489
+ expect(eventHandler).toHaveBeenCalledWith(
490
+ expect.objectContaining({
491
+ type: 'queen.task.analyzed',
492
+ data: expect.objectContaining({
493
+ taskId: 'task_8',
494
+ }),
495
+ })
496
+ );
497
+ });
498
+
499
+ it('should cache analysis results', async () => {
500
+ const task = createMockTask('task_9', 'coding');
501
+
502
+ const analysis = await queen.analyzeTask(task);
503
+ const cache = queen.getAnalysisCache();
504
+
505
+ expect(cache.has(analysis.analysisId)).toBe(true);
506
+ });
507
+ });
508
+
509
+ // ===========================================================================
510
+ // Agent Delegation Tests
511
+ // ===========================================================================
512
+
513
+ describe('Agent Delegation', () => {
514
+ beforeEach(async () => {
515
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: false });
516
+ await queen.initialize();
517
+
518
+ // Setup mock agents
519
+ vi.mocked(mockSwarm.getAllAgents).mockReturnValue([
520
+ createMockAgent('agent_1', 'coder', 'idle'),
521
+ createMockAgent('agent_2', 'tester', 'idle'),
522
+ createMockAgent('agent_3', 'architect', 'busy'),
523
+ createMockAgent('agent_4', 'specialist', 'idle'),
524
+ ]);
525
+
526
+ vi.mocked(mockSwarm.getAvailableAgents).mockReturnValue([
527
+ createMockAgent('agent_1', 'coder', 'idle'),
528
+ createMockAgent('agent_2', 'tester', 'idle'),
529
+ createMockAgent('agent_4', 'specialist', 'idle'),
530
+ ]);
531
+ });
532
+
533
+ it('should delegate task to best matching agent', async () => {
534
+ const task = createMockTask('task_1', 'coding');
535
+ const analysis = await queen.analyzeTask(task);
536
+
537
+ const plan = await queen.delegateToAgents(task, analysis);
538
+
539
+ expect(plan).toMatchObject({
540
+ taskId: 'task_1',
541
+ analysisId: analysis.analysisId,
542
+ primaryAgent: expect.objectContaining({
543
+ agentId: expect.any(String),
544
+ }),
545
+ strategy: expect.any(String),
546
+ });
547
+ });
548
+
549
+ it('should score agents based on capabilities', async () => {
550
+ const task = createMockTask('task_1', 'coding');
551
+ const analysis = await queen.analyzeTask(task);
552
+
553
+ const scores = queen.scoreAgents(task, analysis.matchedPatterns);
554
+
555
+ expect(scores.length).toBe(4);
556
+ expect(scores[0].totalScore).toBeGreaterThan(0);
557
+ expect(scores[0].capabilityScore).toBeGreaterThanOrEqual(0);
558
+ expect(scores[0].capabilityScore).toBeLessThanOrEqual(1);
559
+ });
560
+
561
+ it('should prefer idle agents over busy agents', async () => {
562
+ const task = createMockTask('task_1', 'analysis');
563
+ const analysis = await queen.analyzeTask(task);
564
+
565
+ const scores = queen.scoreAgents(task, analysis.matchedPatterns);
566
+
567
+ const idleAgent = scores.find(s => s.agentId === 'agent_1');
568
+ const busyAgent = scores.find(s => s.agentId === 'agent_3');
569
+
570
+ expect(idleAgent!.availabilityScore).toBeGreaterThan(busyAgent!.availabilityScore);
571
+ });
572
+
573
+ it('should select backup agents for failover', async () => {
574
+ const task = createMockTask('task_1', 'coding');
575
+ const analysis = await queen.analyzeTask(task);
576
+
577
+ const plan = await queen.delegateToAgents(task, analysis);
578
+
579
+ expect(plan.backupAgents.length).toBeGreaterThanOrEqual(0);
580
+ expect(plan.backupAgents.length).toBeLessThanOrEqual(2);
581
+ });
582
+
583
+ it('should create parallel assignments for subtasks', async () => {
584
+ const task = createMockTask('task_1', 'coding', 'high');
585
+ task.description = 'Complex task requiring design, implementation, and testing phases';
586
+ const analysis = await queen.analyzeTask(task);
587
+
588
+ // Force subtasks
589
+ if (analysis.subtasks.length > 0) {
590
+ const plan = await queen.delegateToAgents(task, analysis);
591
+
592
+ expect(plan.parallelAssignments.length).toBe(analysis.subtasks.length);
593
+ }
594
+ });
595
+
596
+ it('should determine appropriate execution strategy', async () => {
597
+ const task = createMockTask('task_1', 'coding');
598
+ const analysis = await queen.analyzeTask(task);
599
+
600
+ const plan = await queen.delegateToAgents(task, analysis);
601
+
602
+ expect(['sequential', 'parallel', 'pipeline', 'fan-out-fan-in', 'hybrid']).toContain(
603
+ plan.strategy
604
+ );
605
+ });
606
+
607
+ it('should call swarm assignTaskToDomain', async () => {
608
+ const task = createMockTask('task_1', 'coding');
609
+ const analysis = await queen.analyzeTask(task);
610
+
611
+ await queen.delegateToAgents(task, analysis);
612
+
613
+ expect(mockSwarm.assignTaskToDomain).toHaveBeenCalledWith(
614
+ 'task_1',
615
+ expect.any(String)
616
+ );
617
+ });
618
+
619
+ it('should broadcast delegation message', async () => {
620
+ const task = createMockTask('task_1', 'coding');
621
+ const analysis = await queen.analyzeTask(task);
622
+
623
+ await queen.delegateToAgents(task, analysis);
624
+
625
+ expect(mockSwarm.broadcastMessage).toHaveBeenCalledWith(
626
+ expect.objectContaining({
627
+ type: 'delegation',
628
+ taskId: 'task_1',
629
+ }),
630
+ 'normal'
631
+ );
632
+ });
633
+
634
+ it('should emit task delegated event', async () => {
635
+ const eventHandler = vi.fn();
636
+ queen.on('queen.task.delegated', eventHandler);
637
+
638
+ const task = createMockTask('task_1', 'coding');
639
+ const analysis = await queen.analyzeTask(task);
640
+ await queen.delegateToAgents(task, analysis);
641
+
642
+ expect(eventHandler).toHaveBeenCalledWith(
643
+ expect.objectContaining({
644
+ type: 'queen.task.delegated',
645
+ data: expect.objectContaining({
646
+ taskId: 'task_1',
647
+ }),
648
+ })
649
+ );
650
+ });
651
+
652
+ it('should store delegation plan', async () => {
653
+ const task = createMockTask('task_1', 'coding');
654
+ const analysis = await queen.analyzeTask(task);
655
+
656
+ const plan = await queen.delegateToAgents(task, analysis);
657
+ const plans = queen.getDelegationPlans();
658
+
659
+ expect(plans.has(plan.planId)).toBe(true);
660
+ });
661
+ });
662
+
663
+ // ===========================================================================
664
+ // Swarm Health Monitoring Tests
665
+ // ===========================================================================
666
+
667
+ describe('Swarm Health Monitoring', () => {
668
+ beforeEach(async () => {
669
+ queen = createQueenCoordinator(mockSwarm, {
670
+ healthCheckIntervalMs: 1000,
671
+ bottleneckThresholds: {
672
+ queueDepth: 5,
673
+ errorRate: 0.1,
674
+ responseTimeMs: 1000,
675
+ },
676
+ });
677
+ await queen.initialize();
678
+
679
+ vi.mocked(mockSwarm.getAllAgents).mockReturnValue([
680
+ createMockAgent('agent_1', 'coder', 'idle'),
681
+ createMockAgent('agent_2', 'tester', 'busy'),
682
+ createMockAgent('agent_3', 'architect', 'idle'),
683
+ ]);
684
+ });
685
+
686
+ it('should generate health report', async () => {
687
+ const report = await queen.monitorSwarmHealth();
688
+
689
+ expect(report).toMatchObject({
690
+ reportId: expect.any(String),
691
+ timestamp: expect.any(Date),
692
+ overallHealth: expect.any(Number),
693
+ domainHealth: expect.any(Map),
694
+ agentHealth: expect.any(Array),
695
+ bottlenecks: expect.any(Array),
696
+ alerts: expect.any(Array),
697
+ recommendations: expect.any(Array),
698
+ });
699
+ });
700
+
701
+ it('should calculate overall health score', async () => {
702
+ const report = await queen.monitorSwarmHealth();
703
+
704
+ expect(report.overallHealth).toBeGreaterThanOrEqual(0);
705
+ expect(report.overallHealth).toBeLessThanOrEqual(1);
706
+ });
707
+
708
+ it('should report domain health for all domains', async () => {
709
+ const report = await queen.monitorSwarmHealth();
710
+
711
+ expect(report.domainHealth.size).toBe(5); // queen, security, core, integration, support
712
+ });
713
+
714
+ it('should report individual agent health', async () => {
715
+ const report = await queen.monitorSwarmHealth();
716
+
717
+ expect(report.agentHealth.length).toBe(3);
718
+ expect(report.agentHealth[0]).toMatchObject({
719
+ agentId: expect.any(String),
720
+ domain: expect.any(String),
721
+ health: expect.any(Number),
722
+ status: expect.any(String),
723
+ });
724
+ });
725
+
726
+ it('should detect queue bottlenecks', async () => {
727
+ vi.mocked(mockSwarm.getStatus).mockReturnValue({
728
+ domains: [
729
+ { name: 'core', agentCount: 5, availableAgents: 1, busyAgents: 4, tasksQueued: 15, tasksCompleted: 10 },
730
+ ...createMockDomainStatuses().slice(1),
731
+ ] as DomainStatus[],
732
+ metrics: createMockMetrics(),
733
+ });
734
+
735
+ const report = await queen.monitorSwarmHealth();
736
+
737
+ const queueBottleneck = report.bottlenecks.find(
738
+ b => b.type === 'domain' && b.description.includes('queue')
739
+ );
740
+ expect(queueBottleneck).toBeDefined();
741
+ });
742
+
743
+ it('should detect error agents', async () => {
744
+ vi.mocked(mockSwarm.getAllAgents).mockReturnValue([
745
+ createMockAgent('agent_1', 'coder', 'error'),
746
+ createMockAgent('agent_2', 'tester', 'error'),
747
+ createMockAgent('agent_3', 'architect', 'idle'),
748
+ ]);
749
+
750
+ const report = await queen.monitorSwarmHealth();
751
+
752
+ const agentBottleneck = report.bottlenecks.find(
753
+ b => b.type === 'agent' && b.description.includes('error')
754
+ );
755
+ expect(agentBottleneck).toBeDefined();
756
+ expect(agentBottleneck!.description).toContain('2');
757
+ });
758
+
759
+ it('should generate alerts for critical bottlenecks', async () => {
760
+ vi.mocked(mockSwarm.getStatus).mockReturnValue({
761
+ domains: [
762
+ { name: 'core', agentCount: 5, availableAgents: 0, busyAgents: 5, tasksQueued: 25, tasksCompleted: 10 },
763
+ ...createMockDomainStatuses().slice(1),
764
+ ] as DomainStatus[],
765
+ metrics: createMockMetrics(),
766
+ });
767
+
768
+ const report = await queen.monitorSwarmHealth();
769
+
770
+ const criticalAlert = report.alerts.find(a => a.type === 'critical' || a.type === 'error');
771
+ expect(criticalAlert).toBeDefined();
772
+ });
773
+
774
+ it('should generate recommendations', async () => {
775
+ vi.mocked(mockSwarm.getAllAgents).mockReturnValue([
776
+ createMockAgent('agent_1', 'coder', 'error'),
777
+ ]);
778
+
779
+ const report = await queen.monitorSwarmHealth();
780
+
781
+ expect(report.recommendations.length).toBeGreaterThan(0);
782
+ });
783
+
784
+ it('should calculate health metrics', async () => {
785
+ const report = await queen.monitorSwarmHealth();
786
+
787
+ expect(report.metrics).toMatchObject({
788
+ totalAgents: 3,
789
+ activeAgents: expect.any(Number),
790
+ idleAgents: expect.any(Number),
791
+ errorAgents: expect.any(Number),
792
+ totalTasks: expect.any(Number),
793
+ completedTasks: expect.any(Number),
794
+ failedTasks: expect.any(Number),
795
+ });
796
+ });
797
+
798
+ it('should emit health report event', async () => {
799
+ const eventHandler = vi.fn();
800
+ queen.on('queen.health.report', eventHandler);
801
+
802
+ await queen.monitorSwarmHealth();
803
+
804
+ expect(eventHandler).toHaveBeenCalledWith(
805
+ expect.objectContaining({
806
+ type: 'queen.health.report',
807
+ })
808
+ );
809
+ });
810
+
811
+ it('should store last health report', async () => {
812
+ await queen.monitorSwarmHealth();
813
+
814
+ const lastReport = queen.getLastHealthReport();
815
+ expect(lastReport).toBeDefined();
816
+ });
817
+
818
+ it('should run periodic health checks', async () => {
819
+ const spy = vi.spyOn(queen, 'monitorSwarmHealth');
820
+
821
+ // Advance timers to trigger health check
822
+ vi.advanceTimersByTime(1500);
823
+
824
+ expect(spy).toHaveBeenCalled();
825
+ });
826
+ });
827
+
828
+ // ===========================================================================
829
+ // Consensus Coordination Tests
830
+ // ===========================================================================
831
+
832
+ describe('Consensus Coordination', () => {
833
+ beforeEach(async () => {
834
+ queen = createQueenCoordinator(mockSwarm, {
835
+ consensusTimeouts: {
836
+ majority: 1000,
837
+ supermajority: 2000,
838
+ unanimous: 5000,
839
+ },
840
+ });
841
+ await queen.initialize();
842
+ });
843
+
844
+ it('should coordinate majority consensus', async () => {
845
+ vi.mocked(mockSwarm.proposeConsensus).mockResolvedValue(createMockConsensusResult(true));
846
+
847
+ const decision: Decision = {
848
+ decisionId: '',
849
+ type: 'task-assignment',
850
+ proposal: { taskId: 'task_1', agentId: 'agent_1' },
851
+ requiredConsensus: 'majority',
852
+ timeout: 1000,
853
+ initiator: 'queen',
854
+ metadata: {},
855
+ };
856
+
857
+ const result = await queen.coordinateConsensus(decision);
858
+
859
+ expect(result.approved).toBe(true);
860
+ expect(mockSwarm.proposeConsensus).toHaveBeenCalledWith(
861
+ expect.objectContaining({
862
+ threshold: 0.51,
863
+ })
864
+ );
865
+ });
866
+
867
+ it('should coordinate supermajority consensus', async () => {
868
+ vi.mocked(mockSwarm.proposeConsensus).mockResolvedValue(createMockConsensusResult(true));
869
+
870
+ const decision: Decision = {
871
+ decisionId: '',
872
+ type: 'resource-allocation',
873
+ proposal: { resource: 'memory', amount: 1024 },
874
+ requiredConsensus: 'supermajority',
875
+ timeout: 2000,
876
+ initiator: 'queen',
877
+ metadata: {},
878
+ };
879
+
880
+ const result = await queen.coordinateConsensus(decision);
881
+
882
+ expect(mockSwarm.proposeConsensus).toHaveBeenCalledWith(
883
+ expect.objectContaining({
884
+ threshold: 0.67,
885
+ })
886
+ );
887
+ });
888
+
889
+ it('should coordinate unanimous consensus', async () => {
890
+ vi.mocked(mockSwarm.proposeConsensus).mockResolvedValue(createMockConsensusResult(true));
891
+
892
+ const decision: Decision = {
893
+ decisionId: '',
894
+ type: 'topology-change',
895
+ proposal: { newTopology: 'mesh' },
896
+ requiredConsensus: 'unanimous',
897
+ timeout: 5000,
898
+ initiator: 'queen',
899
+ metadata: {},
900
+ };
901
+
902
+ await queen.coordinateConsensus(decision);
903
+
904
+ expect(mockSwarm.proposeConsensus).toHaveBeenCalledWith(
905
+ expect.objectContaining({
906
+ threshold: 1.0,
907
+ })
908
+ );
909
+ });
910
+
911
+ it('should allow queen override for emergency actions', async () => {
912
+ const decision: Decision = {
913
+ decisionId: '',
914
+ type: 'emergency-action',
915
+ proposal: { action: 'stop-all' },
916
+ requiredConsensus: 'queen-override',
917
+ timeout: 0,
918
+ initiator: 'queen',
919
+ metadata: {},
920
+ };
921
+
922
+ const result = await queen.coordinateConsensus(decision);
923
+
924
+ expect(result.approved).toBe(true);
925
+ expect(result.approvalRate).toBe(1.0);
926
+ expect(mockSwarm.proposeConsensus).not.toHaveBeenCalled();
927
+ });
928
+
929
+ it('should reject queen override for non-allowed decision types', async () => {
930
+ const decision: Decision = {
931
+ decisionId: '',
932
+ type: 'task-assignment',
933
+ proposal: { taskId: 'task_1' },
934
+ requiredConsensus: 'queen-override',
935
+ timeout: 0,
936
+ initiator: 'queen',
937
+ metadata: {},
938
+ };
939
+
940
+ await expect(queen.coordinateConsensus(decision)).rejects.toThrow(
941
+ 'Queen override not allowed'
942
+ );
943
+ });
944
+
945
+ it('should use weighted consensus based on agent performance', async () => {
946
+ vi.mocked(mockSwarm.getAllAgents).mockReturnValue([
947
+ createMockAgent('agent_1', 'coder', 'idle'),
948
+ createMockAgent('agent_2', 'tester', 'idle'),
949
+ ]);
950
+ vi.mocked(mockSwarm.proposeConsensus).mockResolvedValue(createMockConsensusResult(true));
951
+
952
+ const decision: Decision = {
953
+ decisionId: '',
954
+ type: 'resource-allocation',
955
+ proposal: { resource: 'cpu' },
956
+ requiredConsensus: 'weighted',
957
+ timeout: 1000,
958
+ initiator: 'queen',
959
+ metadata: {},
960
+ };
961
+
962
+ await queen.coordinateConsensus(decision);
963
+
964
+ expect(mockSwarm.proposeConsensus).toHaveBeenCalledWith(
965
+ expect.objectContaining({
966
+ weights: expect.any(Object),
967
+ })
968
+ );
969
+ });
970
+
971
+ it('should emit consensus completed event', async () => {
972
+ const eventHandler = vi.fn();
973
+ queen.on('queen.consensus.completed', eventHandler);
974
+ vi.mocked(mockSwarm.proposeConsensus).mockResolvedValue(createMockConsensusResult(true));
975
+
976
+ const decision: Decision = {
977
+ decisionId: '',
978
+ type: 'task-assignment',
979
+ proposal: {},
980
+ requiredConsensus: 'majority',
981
+ timeout: 1000,
982
+ initiator: 'queen',
983
+ metadata: {},
984
+ };
985
+
986
+ await queen.coordinateConsensus(decision);
987
+
988
+ expect(eventHandler).toHaveBeenCalledWith(
989
+ expect.objectContaining({
990
+ type: 'queen.consensus.completed',
991
+ data: expect.objectContaining({
992
+ approved: true,
993
+ }),
994
+ })
995
+ );
996
+ });
997
+ });
998
+
999
+ // ===========================================================================
1000
+ // Learning from Outcomes Tests
1001
+ // ===========================================================================
1002
+
1003
+ describe('Learning from Outcomes', () => {
1004
+ beforeEach(async () => {
1005
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: true }, mockNeural, mockMemory);
1006
+ await queen.initialize();
1007
+ });
1008
+
1009
+ it('should record successful task outcome', async () => {
1010
+ const task = createMockTask('task_1', 'coding');
1011
+ const result = createMockTaskResult(true);
1012
+
1013
+ await queen.recordOutcome(task, result);
1014
+
1015
+ expect(mockNeural.beginTask).toHaveBeenCalled();
1016
+ expect(mockNeural.recordStep).toHaveBeenCalled();
1017
+ expect(mockNeural.completeTask).toHaveBeenCalled();
1018
+ });
1019
+
1020
+ it('should record failed task outcome', async () => {
1021
+ const task = createMockTask('task_1', 'coding');
1022
+ const result = createMockTaskResult(false);
1023
+
1024
+ await queen.recordOutcome(task, result);
1025
+
1026
+ const outcomeHistory = queen.getOutcomeHistory();
1027
+ expect(outcomeHistory.length).toBe(1);
1028
+ expect(outcomeHistory[0].success).toBe(false);
1029
+ });
1030
+
1031
+ it('should store outcome in memory service', async () => {
1032
+ const task = createMockTask('task_1', 'coding');
1033
+ const result = createMockTaskResult(true);
1034
+
1035
+ await queen.recordOutcome(task, result);
1036
+
1037
+ expect(mockMemory.store).toHaveBeenCalledWith(
1038
+ expect.objectContaining({
1039
+ key: expect.stringContaining('outcome_task_1'),
1040
+ namespace: 'queen-outcomes',
1041
+ tags: expect.arrayContaining(['coding', 'success']),
1042
+ })
1043
+ );
1044
+ });
1045
+
1046
+ it('should emit outcome recorded event', async () => {
1047
+ const eventHandler = vi.fn();
1048
+ queen.on('queen.outcome.recorded', eventHandler);
1049
+
1050
+ const task = createMockTask('task_1', 'coding');
1051
+ const result = createMockTaskResult(true);
1052
+
1053
+ await queen.recordOutcome(task, result);
1054
+
1055
+ expect(eventHandler).toHaveBeenCalledWith(
1056
+ expect.objectContaining({
1057
+ type: 'queen.outcome.recorded',
1058
+ data: expect.objectContaining({
1059
+ taskId: 'task_1',
1060
+ success: true,
1061
+ }),
1062
+ })
1063
+ );
1064
+ });
1065
+
1066
+ it('should maintain outcome history with limit', async () => {
1067
+ const task = createMockTask('task_1', 'coding');
1068
+ const result = createMockTaskResult(true);
1069
+
1070
+ // Record many outcomes
1071
+ for (let i = 0; i < 10; i++) {
1072
+ await queen.recordOutcome(task, result);
1073
+ }
1074
+
1075
+ const history = queen.getOutcomeHistory();
1076
+ expect(history.length).toBe(10);
1077
+ });
1078
+
1079
+ it('should calculate reward based on success and quality', async () => {
1080
+ const task = createMockTask('task_1', 'coding');
1081
+ const result = createMockTaskResult(true);
1082
+
1083
+ await queen.recordOutcome(task, result);
1084
+
1085
+ expect(mockNeural.recordStep).toHaveBeenCalledWith(
1086
+ expect.any(String),
1087
+ expect.stringContaining('executed_coding'),
1088
+ expect.any(Number),
1089
+ expect.any(Float32Array)
1090
+ );
1091
+ });
1092
+
1093
+ it('should not attempt learning when neural system unavailable', async () => {
1094
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: true });
1095
+ await queen.initialize();
1096
+
1097
+ const task = createMockTask('task_1', 'coding');
1098
+ const result = createMockTaskResult(true);
1099
+
1100
+ // Should not throw
1101
+ await queen.recordOutcome(task, result);
1102
+ });
1103
+
1104
+ it('should handle memory storage errors gracefully', async () => {
1105
+ vi.mocked(mockMemory.store).mockRejectedValue(new Error('Storage failed'));
1106
+
1107
+ const task = createMockTask('task_1', 'coding');
1108
+ const result = createMockTaskResult(true);
1109
+
1110
+ // Should not throw
1111
+ await queen.recordOutcome(task, result);
1112
+
1113
+ const history = queen.getOutcomeHistory();
1114
+ expect(history.length).toBe(1);
1115
+ });
1116
+ });
1117
+
1118
+ // ===========================================================================
1119
+ // Performance Statistics Tests
1120
+ // ===========================================================================
1121
+
1122
+ describe('Performance Statistics', () => {
1123
+ beforeEach(async () => {
1124
+ queen = createQueenCoordinator(mockSwarm);
1125
+ await queen.initialize();
1126
+ });
1127
+
1128
+ it('should track analysis latencies', async () => {
1129
+ const task = createMockTask('task_1', 'coding');
1130
+
1131
+ await queen.analyzeTask(task);
1132
+ await queen.analyzeTask(task);
1133
+
1134
+ const stats = queen.getPerformanceStats();
1135
+ expect(stats.avgAnalysisLatencyMs).toBeGreaterThan(0);
1136
+ expect(stats.totalAnalyses).toBe(2);
1137
+ });
1138
+
1139
+ it('should track delegation latencies', async () => {
1140
+ vi.mocked(mockSwarm.getAllAgents).mockReturnValue([
1141
+ createMockAgent('agent_1', 'coder', 'idle'),
1142
+ ]);
1143
+
1144
+ const task = createMockTask('task_1', 'coding');
1145
+ const analysis = await queen.analyzeTask(task);
1146
+ await queen.delegateToAgents(task, analysis);
1147
+
1148
+ const stats = queen.getPerformanceStats();
1149
+ expect(stats.avgDelegationLatencyMs).toBeGreaterThan(0);
1150
+ expect(stats.totalDelegations).toBe(1);
1151
+ });
1152
+
1153
+ it('should track consensus latencies', async () => {
1154
+ vi.mocked(mockSwarm.proposeConsensus).mockResolvedValue(createMockConsensusResult(true));
1155
+
1156
+ const decision: Decision = {
1157
+ decisionId: '',
1158
+ type: 'task-assignment',
1159
+ proposal: {},
1160
+ requiredConsensus: 'majority',
1161
+ timeout: 1000,
1162
+ initiator: 'queen',
1163
+ metadata: {},
1164
+ };
1165
+
1166
+ await queen.coordinateConsensus(decision);
1167
+
1168
+ const stats = queen.getPerformanceStats();
1169
+ expect(stats.totalDecisions).toBe(1);
1170
+ });
1171
+
1172
+ it('should report all statistics together', async () => {
1173
+ const stats = queen.getPerformanceStats();
1174
+
1175
+ expect(stats).toMatchObject({
1176
+ avgAnalysisLatencyMs: expect.any(Number),
1177
+ avgDelegationLatencyMs: expect.any(Number),
1178
+ avgConsensusLatencyMs: expect.any(Number),
1179
+ totalAnalyses: expect.any(Number),
1180
+ totalDelegations: expect.any(Number),
1181
+ totalDecisions: expect.any(Number),
1182
+ });
1183
+ });
1184
+ });
1185
+
1186
+ // ===========================================================================
1187
+ // Integration Points Tests
1188
+ // ===========================================================================
1189
+
1190
+ describe('Integration Points', () => {
1191
+ it('should work with UnifiedSwarmCoordinator interface', async () => {
1192
+ const swarm = createMockSwarmCoordinator();
1193
+ queen = createQueenCoordinator(swarm);
1194
+ await queen.initialize();
1195
+
1196
+ const task = createMockTask('task_1', 'coding');
1197
+ const analysis = await queen.analyzeTask(task);
1198
+
1199
+ expect(analysis).toBeDefined();
1200
+ expect(analysis.analysisId).toBeDefined();
1201
+ });
1202
+
1203
+ it('should work with NeuralLearningSystem interface', async () => {
1204
+ const neural = createMockNeuralSystem();
1205
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: true }, neural);
1206
+ await queen.initialize();
1207
+
1208
+ expect(neural.initialize).toHaveBeenCalled();
1209
+ });
1210
+
1211
+ it('should work with UnifiedMemoryService interface', async () => {
1212
+ const memory = createMockMemoryService();
1213
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: true }, mockNeural, memory);
1214
+ await queen.initialize();
1215
+
1216
+ const task = createMockTask('task_1', 'coding');
1217
+ const result = createMockTaskResult(true);
1218
+ await queen.recordOutcome(task, result);
1219
+
1220
+ expect(memory.store).toHaveBeenCalled();
1221
+ });
1222
+
1223
+ it('should emit events that can be subscribed to', async () => {
1224
+ queen = createQueenCoordinator(mockSwarm);
1225
+ await queen.initialize();
1226
+
1227
+ const eventHandler = vi.fn();
1228
+ queen.on('event', eventHandler);
1229
+
1230
+ const task = createMockTask('task_1', 'coding');
1231
+ await queen.analyzeTask(task);
1232
+
1233
+ expect(eventHandler).toHaveBeenCalled();
1234
+ });
1235
+
1236
+ it('should check learning enabled status', async () => {
1237
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: false });
1238
+ expect(queen.isLearningEnabled()).toBe(false);
1239
+
1240
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: true }, mockNeural);
1241
+ expect(queen.isLearningEnabled()).toBe(true);
1242
+ });
1243
+ });
1244
+
1245
+ // ===========================================================================
1246
+ // Edge Cases and Error Handling Tests
1247
+ // ===========================================================================
1248
+
1249
+ describe('Edge Cases and Error Handling', () => {
1250
+ beforeEach(async () => {
1251
+ queen = createQueenCoordinator(mockSwarm);
1252
+ await queen.initialize();
1253
+ });
1254
+
1255
+ it('should handle empty agent list', async () => {
1256
+ vi.mocked(mockSwarm.getAllAgents).mockReturnValue([]);
1257
+
1258
+ const task = createMockTask('task_1', 'coding');
1259
+ const analysis = await queen.analyzeTask(task);
1260
+
1261
+ expect(analysis).toBeDefined();
1262
+
1263
+ const scores = queen.scoreAgents(task, []);
1264
+ expect(scores).toEqual([]);
1265
+ });
1266
+
1267
+ it('should handle task with no description', async () => {
1268
+ const task = createMockTask('task_1', 'coding');
1269
+ task.description = '';
1270
+
1271
+ const analysis = await queen.analyzeTask(task);
1272
+
1273
+ expect(analysis).toBeDefined();
1274
+ expect(analysis.complexity).toBeGreaterThan(0);
1275
+ });
1276
+
1277
+ it('should handle neural system errors gracefully', async () => {
1278
+ queen = createQueenCoordinator(mockSwarm, { enableLearning: true }, mockNeural);
1279
+ await queen.initialize();
1280
+
1281
+ vi.mocked(mockNeural.findPatterns).mockRejectedValue(new Error('Neural error'));
1282
+
1283
+ const task = createMockTask('task_1', 'coding');
1284
+ const analysis = await queen.analyzeTask(task);
1285
+
1286
+ // Should still complete analysis
1287
+ expect(analysis).toBeDefined();
1288
+ expect(analysis.matchedPatterns).toEqual([]);
1289
+ });
1290
+
1291
+ it('should handle consensus rejection', async () => {
1292
+ vi.mocked(mockSwarm.proposeConsensus).mockResolvedValue(createMockConsensusResult(false));
1293
+
1294
+ const decision: Decision = {
1295
+ decisionId: '',
1296
+ type: 'resource-allocation',
1297
+ proposal: {},
1298
+ requiredConsensus: 'majority',
1299
+ timeout: 1000,
1300
+ initiator: 'queen',
1301
+ metadata: {},
1302
+ };
1303
+
1304
+ const result = await queen.coordinateConsensus(decision);
1305
+
1306
+ expect(result.approved).toBe(false);
1307
+ });
1308
+
1309
+ it('should handle all task types', async () => {
1310
+ const taskTypes: TaskType[] = [
1311
+ 'research', 'analysis', 'coding', 'testing',
1312
+ 'review', 'documentation', 'coordination', 'consensus', 'custom'
1313
+ ];
1314
+
1315
+ for (const type of taskTypes) {
1316
+ const task = createMockTask(`task_${type}`, type);
1317
+ const analysis = await queen.analyzeTask(task);
1318
+
1319
+ expect(analysis).toBeDefined();
1320
+ expect(analysis.recommendedDomain).toBeDefined();
1321
+ }
1322
+ });
1323
+
1324
+ it('should handle all priority levels', async () => {
1325
+ const priorities: TaskPriority[] = ['critical', 'high', 'normal', 'low', 'background'];
1326
+
1327
+ for (const priority of priorities) {
1328
+ const task = createMockTask(`task_${priority}`, 'coding', priority);
1329
+ const analysis = await queen.analyzeTask(task);
1330
+
1331
+ expect(analysis).toBeDefined();
1332
+ }
1333
+ });
1334
+ });
1335
+ });