agentic-qe 2.7.2 → 2.7.4

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 (132) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/README.md +1 -1
  3. package/dist/agents/AccessibilityAllyAgent.d.ts +0 -7
  4. package/dist/agents/AccessibilityAllyAgent.d.ts.map +1 -1
  5. package/dist/agents/AccessibilityAllyAgent.js +0 -15
  6. package/dist/agents/AccessibilityAllyAgent.js.map +1 -1
  7. package/dist/agents/ApiContractValidatorAgent.js +4 -4
  8. package/dist/agents/ApiContractValidatorAgent.js.map +1 -1
  9. package/dist/agents/BaseAgent.d.ts +2 -0
  10. package/dist/agents/BaseAgent.d.ts.map +1 -1
  11. package/dist/agents/BaseAgent.js +43 -41
  12. package/dist/agents/BaseAgent.js.map +1 -1
  13. package/dist/agents/CodeComplexityAnalyzerAgent.d.ts +0 -8
  14. package/dist/agents/CodeComplexityAnalyzerAgent.d.ts.map +1 -1
  15. package/dist/agents/CodeComplexityAnalyzerAgent.js +0 -15
  16. package/dist/agents/CodeComplexityAnalyzerAgent.js.map +1 -1
  17. package/dist/agents/CodeIntelligenceAgent.d.ts +0 -1
  18. package/dist/agents/CodeIntelligenceAgent.d.ts.map +1 -1
  19. package/dist/agents/CodeIntelligenceAgent.js +0 -2
  20. package/dist/agents/CodeIntelligenceAgent.js.map +1 -1
  21. package/dist/agents/DeploymentReadinessAgent.d.ts.map +1 -1
  22. package/dist/agents/DeploymentReadinessAgent.js +30 -30
  23. package/dist/agents/DeploymentReadinessAgent.js.map +1 -1
  24. package/dist/agents/FlakyTestHunterAgent.d.ts +0 -10
  25. package/dist/agents/FlakyTestHunterAgent.d.ts.map +1 -1
  26. package/dist/agents/FlakyTestHunterAgent.js +10 -20
  27. package/dist/agents/FlakyTestHunterAgent.js.map +1 -1
  28. package/dist/agents/FleetCommanderAgent.d.ts.map +1 -1
  29. package/dist/agents/FleetCommanderAgent.js +28 -28
  30. package/dist/agents/FleetCommanderAgent.js.map +1 -1
  31. package/dist/agents/LearningAgent.js +1 -1
  32. package/dist/agents/LearningAgent.js.map +1 -1
  33. package/dist/agents/PerformanceTesterAgent.d.ts.map +1 -1
  34. package/dist/agents/PerformanceTesterAgent.js +25 -25
  35. package/dist/agents/PerformanceTesterAgent.js.map +1 -1
  36. package/dist/agents/ProductionIntelligenceAgent.d.ts.map +1 -1
  37. package/dist/agents/ProductionIntelligenceAgent.js +20 -20
  38. package/dist/agents/ProductionIntelligenceAgent.js.map +1 -1
  39. package/dist/agents/QXPartnerAgent.d.ts +0 -8
  40. package/dist/agents/QXPartnerAgent.d.ts.map +1 -1
  41. package/dist/agents/QXPartnerAgent.js +0 -15
  42. package/dist/agents/QXPartnerAgent.js.map +1 -1
  43. package/dist/agents/QualityAnalyzerAgent.d.ts +0 -7
  44. package/dist/agents/QualityAnalyzerAgent.d.ts.map +1 -1
  45. package/dist/agents/QualityAnalyzerAgent.js +0 -16
  46. package/dist/agents/QualityAnalyzerAgent.js.map +1 -1
  47. package/dist/agents/RegressionRiskAnalyzerAgent.d.ts.map +1 -1
  48. package/dist/agents/RegressionRiskAnalyzerAgent.js +18 -18
  49. package/dist/agents/RegressionRiskAnalyzerAgent.js.map +1 -1
  50. package/dist/agents/RequirementsValidatorAgent.d.ts.map +1 -1
  51. package/dist/agents/RequirementsValidatorAgent.js +21 -21
  52. package/dist/agents/RequirementsValidatorAgent.js.map +1 -1
  53. package/dist/agents/SecurityScannerAgent.d.ts.map +1 -1
  54. package/dist/agents/SecurityScannerAgent.js +38 -38
  55. package/dist/agents/SecurityScannerAgent.js.map +1 -1
  56. package/dist/agents/TestDataArchitectAgent.d.ts.map +1 -1
  57. package/dist/agents/TestDataArchitectAgent.js +29 -29
  58. package/dist/agents/TestDataArchitectAgent.js.map +1 -1
  59. package/dist/agents/TestExecutorAgent.d.ts +0 -7
  60. package/dist/agents/TestExecutorAgent.d.ts.map +1 -1
  61. package/dist/agents/TestExecutorAgent.js +35 -51
  62. package/dist/agents/TestExecutorAgent.js.map +1 -1
  63. package/dist/agents/TestGeneratorAgent.d.ts +0 -7
  64. package/dist/agents/TestGeneratorAgent.d.ts.map +1 -1
  65. package/dist/agents/TestGeneratorAgent.js +0 -16
  66. package/dist/agents/TestGeneratorAgent.js.map +1 -1
  67. package/dist/agents/adapters/AgentLLMAdapter.d.ts.map +1 -1
  68. package/dist/agents/adapters/AgentLLMAdapter.js +5 -4
  69. package/dist/agents/adapters/AgentLLMAdapter.js.map +1 -1
  70. package/dist/agents/adapters/CoordinatorAdapter.d.ts.map +1 -1
  71. package/dist/agents/adapters/CoordinatorAdapter.js +2 -1
  72. package/dist/agents/adapters/CoordinatorAdapter.js.map +1 -1
  73. package/dist/agents/n8n/N8nAPIClient.d.ts.map +1 -1
  74. package/dist/agents/n8n/N8nAPIClient.js +3 -2
  75. package/dist/agents/n8n/N8nAPIClient.js.map +1 -1
  76. package/dist/agents/n8n/N8nAuditPersistence.d.ts.map +1 -1
  77. package/dist/agents/n8n/N8nAuditPersistence.js +2 -1
  78. package/dist/agents/n8n/N8nAuditPersistence.js.map +1 -1
  79. package/dist/agents/n8n/N8nBaseAgent.js +1 -1
  80. package/dist/agents/n8n/N8nBaseAgent.js.map +1 -1
  81. package/dist/agents/n8n/N8nComplianceValidatorAgent.js +1 -1
  82. package/dist/agents/n8n/N8nComplianceValidatorAgent.js.map +1 -1
  83. package/dist/agents/n8n/N8nMonitoringValidatorAgent.js +1 -1
  84. package/dist/agents/n8n/N8nMonitoringValidatorAgent.js.map +1 -1
  85. package/dist/agents/n8n/N8nReplayabilityTesterAgent.js +1 -1
  86. package/dist/agents/n8n/N8nReplayabilityTesterAgent.js.map +1 -1
  87. package/dist/agents/n8n/N8nSecurityAuditorAgent.js +1 -1
  88. package/dist/agents/n8n/N8nSecurityAuditorAgent.js.map +1 -1
  89. package/dist/agents/pool/AgentPool.d.ts.map +1 -1
  90. package/dist/agents/pool/AgentPool.js +2 -1
  91. package/dist/agents/pool/AgentPool.js.map +1 -1
  92. package/dist/agents/pool/QEAgentPoolFactory.d.ts.map +1 -1
  93. package/dist/agents/pool/QEAgentPoolFactory.js +2 -1
  94. package/dist/agents/pool/QEAgentPoolFactory.js.map +1 -1
  95. package/dist/core/memory/HNSWVectorMemory.js +1 -1
  96. package/dist/learning/QLearning.d.ts +101 -1
  97. package/dist/learning/QLearning.d.ts.map +1 -1
  98. package/dist/learning/QLearning.js +168 -0
  99. package/dist/learning/QLearning.js.map +1 -1
  100. package/dist/mcp/server-instructions.d.ts +1 -1
  101. package/dist/mcp/server-instructions.js +1 -1
  102. package/dist/persistence/migrations/all-migrations.d.ts.map +1 -1
  103. package/dist/persistence/migrations/all-migrations.js +44 -1
  104. package/dist/persistence/migrations/all-migrations.js.map +1 -1
  105. package/dist/planning/GOAPPlanner.d.ts +42 -0
  106. package/dist/planning/GOAPPlanner.d.ts.map +1 -1
  107. package/dist/planning/GOAPPlanner.js +153 -1
  108. package/dist/planning/GOAPPlanner.js.map +1 -1
  109. package/dist/planning/PlanLearning.d.ts +184 -0
  110. package/dist/planning/PlanLearning.d.ts.map +1 -0
  111. package/dist/planning/PlanLearning.js +527 -0
  112. package/dist/planning/PlanLearning.js.map +1 -0
  113. package/dist/planning/PlanSimilarity.d.ts +148 -0
  114. package/dist/planning/PlanSimilarity.d.ts.map +1 -0
  115. package/dist/planning/PlanSimilarity.js +464 -0
  116. package/dist/planning/PlanSimilarity.js.map +1 -0
  117. package/dist/planning/execution/PlanExecutor.d.ts +101 -2
  118. package/dist/planning/execution/PlanExecutor.d.ts.map +1 -1
  119. package/dist/planning/execution/PlanExecutor.js +587 -14
  120. package/dist/planning/execution/PlanExecutor.js.map +1 -1
  121. package/dist/planning/index.d.ts +2 -0
  122. package/dist/planning/index.d.ts.map +1 -1
  123. package/dist/planning/index.js +15 -4
  124. package/dist/planning/index.js.map +1 -1
  125. package/dist/planning/integration/GOAPQualityGateIntegration.d.ts +6 -0
  126. package/dist/planning/integration/GOAPQualityGateIntegration.d.ts.map +1 -1
  127. package/dist/planning/integration/GOAPQualityGateIntegration.js +7 -0
  128. package/dist/planning/integration/GOAPQualityGateIntegration.js.map +1 -1
  129. package/dist/planning/types.d.ts +2 -0
  130. package/dist/planning/types.d.ts.map +1 -1
  131. package/dist/planning/types.js.map +1 -1
  132. package/package.json +1 -1
@@ -5,11 +5,12 @@
5
5
  * Executes remediation plans generated by GOAPQualityGateIntegration:
6
6
  * - Spawns agents for each action
7
7
  * - Executes actions in sequence with dependency ordering
8
- * - Records outcomes for learning (wires recordActionOutcome)
8
+ * - Records outcomes for learning via PlanLearning integration
9
9
  * - Handles failures with automatic replanning
10
+ * - Phase 6: Live agent execution with real world state updates
10
11
  *
11
12
  * @module planning/execution/PlanExecutor
12
- * @version 1.0.0
13
+ * @version 1.2.0 - Phase 6: Live Agent Execution
13
14
  */
14
15
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
16
  if (k2 === undefined) k2 = k;
@@ -50,6 +51,8 @@ exports.createPlanExecutor = createPlanExecutor;
50
51
  exports.executeQualityGateRemediation = executeQualityGateRemediation;
51
52
  const GOAPQualityGateIntegration_1 = require("../integration/GOAPQualityGateIntegration");
52
53
  const Logger_1 = require("../../utils/Logger");
54
+ const PlanLearning_1 = require("../PlanLearning");
55
+ const types_1 = require("../types");
53
56
  // Lazy import to avoid circular dependencies and reduce memory in tests
54
57
  let AgentRegistryModule = null;
55
58
  async function getAgentRegistryModule() {
@@ -70,6 +73,7 @@ const DEFAULT_CONFIG = {
70
73
  *
71
74
  * Bridges plan generation with actual agent execution.
72
75
  * Implements the OODA (Observe-Orient-Decide-Act) loop for plan execution.
76
+ * Integrates with PlanLearning for continuous improvement.
73
77
  */
74
78
  class PlanExecutor {
75
79
  constructor(db, integration, config = {}) {
@@ -77,10 +81,38 @@ class PlanExecutor {
77
81
  this.ownsRegistry = false; // Track if we created the registry
78
82
  this.db = db;
79
83
  this.integration = integration;
84
+ this.planLearning = new PlanLearning_1.PlanLearning(db);
80
85
  this.logger = Logger_1.Logger.getInstance();
81
86
  this.config = { ...DEFAULT_CONFIG, ...config };
87
+ this.currentWorldState = { ...types_1.DEFAULT_WORLD_STATE };
82
88
  // Registry is lazily initialized only when needed (not in dry-run mode)
83
89
  }
90
+ /**
91
+ * Get the PlanLearning instance for external access
92
+ */
93
+ getPlanLearning() {
94
+ return this.planLearning;
95
+ }
96
+ /**
97
+ * Update current world state (called by integration or externally)
98
+ */
99
+ updateWorldState(state) {
100
+ this.currentWorldState = {
101
+ ...this.currentWorldState,
102
+ ...state,
103
+ coverage: { ...this.currentWorldState.coverage, ...state.coverage },
104
+ quality: { ...this.currentWorldState.quality, ...state.quality },
105
+ fleet: { ...this.currentWorldState.fleet, ...state.fleet },
106
+ resources: { ...this.currentWorldState.resources, ...state.resources },
107
+ context: { ...this.currentWorldState.context, ...state.context }
108
+ };
109
+ }
110
+ /**
111
+ * Get current world state
112
+ */
113
+ getWorldState() {
114
+ return { ...this.currentWorldState };
115
+ }
84
116
  /**
85
117
  * Initialize registry only when needed for actual execution
86
118
  */
@@ -119,6 +151,11 @@ class PlanExecutor {
119
151
  actionResults: [],
120
152
  replanned: false
121
153
  };
154
+ // Track executed actions for learning (Phase 5 integration)
155
+ const executedActions = [];
156
+ // Initialize world state from metrics
157
+ this.initializeWorldStateFromMetrics(metrics, context);
158
+ const initialWorldState = this.getWorldState();
122
159
  this.logger.info('[PlanExecutor] Starting plan execution', {
123
160
  planId: plan.planId,
124
161
  actionCount: plan.actions.length,
@@ -132,17 +169,46 @@ class PlanExecutor {
132
169
  try {
133
170
  // Execute each action in sequence
134
171
  for (const action of currentPlan.actions) {
172
+ // Capture state before action
173
+ const stateBefore = this.getWorldState();
135
174
  const actionResult = await this.executeAction(action, context);
136
175
  result.actionResults.push(actionResult);
137
176
  result.actionsExecuted++;
177
+ // Phase 6: Capture state after action
178
+ // Use real output parsing in live mode, simulation in dry-run
179
+ let stateAfter;
180
+ if (this.config.dryRun) {
181
+ stateAfter = this.simulateActionEffects(stateBefore, action, actionResult.success);
182
+ }
183
+ else {
184
+ // Live mode: parse actual agent output for real measurements
185
+ stateAfter = this.updateWorldStateFromAgentOutput(action, actionResult.output, stateBefore);
186
+ // Fallback to simulation if no output parsed
187
+ if (JSON.stringify(stateAfter) === JSON.stringify(stateBefore)) {
188
+ stateAfter = this.simulateActionEffects(stateBefore, action, actionResult.success);
189
+ }
190
+ }
191
+ this.currentWorldState = stateAfter;
192
+ // Build ExecutedAction for learning
193
+ const executedAction = {
194
+ action: this.remediationActionToGOAPAction(action),
195
+ success: actionResult.success,
196
+ result: actionResult.output,
197
+ error: actionResult.error,
198
+ stateBefore,
199
+ stateAfter,
200
+ executionTimeMs: actionResult.durationMs,
201
+ agentId: actionResult.agentId
202
+ };
203
+ executedActions.push(executedAction);
138
204
  if (actionResult.success) {
139
205
  result.actionsSucceeded++;
140
- // Record success for learning
206
+ // Record success for learning (legacy + new)
141
207
  await this.integration.recordActionOutcome(action.id, true);
142
208
  }
143
209
  else {
144
210
  result.actionsFailed++;
145
- // Record failure for learning
211
+ // Record failure for learning (legacy + new)
146
212
  await this.integration.recordActionOutcome(action.id, false);
147
213
  if (!this.config.continueOnFailure) {
148
214
  this.logger.warn('[PlanExecutor] Action failed, attempting replan', {
@@ -204,6 +270,44 @@ class PlanExecutor {
204
270
  await this.updatePlanStatus(plan.planId, result.success ? 'completed' : 'failed', result.success, result.error);
205
271
  // Mark plan as completed via integration
206
272
  await this.integration.completePlan(plan.planId, result.success, result.error);
273
+ // Phase 5 & 6: Learn from execution and store signatures
274
+ if (executedActions.length > 0) {
275
+ try {
276
+ const goapPlan = this.remediationPlanToGOAPPlan(plan, initialWorldState);
277
+ // Learn from execution (Phase 5)
278
+ const learningOutcome = await this.planLearning.learnFromExecution(goapPlan, executedActions, result.success);
279
+ this.logger.info('[PlanExecutor] Learning from execution completed', {
280
+ planId: plan.planId,
281
+ actionsUpdated: learningOutcome.actionsUpdated,
282
+ qValueUpdates: learningOutcome.qValueUpdates
283
+ });
284
+ // Phase 6: Store plan signature for future reuse (only for successful executions)
285
+ if (result.success && !this.config.dryRun) {
286
+ try {
287
+ // Get PlanSimilarity from integration's planner
288
+ const planner = this.integration.getPlanner();
289
+ if (planner) {
290
+ planner.storePlanSignature(goapPlan, initialWorldState);
291
+ this.logger.info('[PlanExecutor] Plan signature stored for future reuse', {
292
+ planId: plan.planId,
293
+ actionCount: goapPlan.actions.length
294
+ });
295
+ }
296
+ }
297
+ catch (sigError) {
298
+ this.logger.warn('[PlanExecutor] Failed to store plan signature', {
299
+ error: sigError instanceof Error ? sigError.message : String(sigError)
300
+ });
301
+ }
302
+ }
303
+ }
304
+ catch (error) {
305
+ // Learning failure should not fail the execution
306
+ this.logger.warn('[PlanExecutor] Learning from execution failed', {
307
+ error: error instanceof Error ? error.message : String(error)
308
+ });
309
+ }
310
+ }
207
311
  this.logger.info('[PlanExecutor] Plan execution completed', {
208
312
  planId: plan.planId,
209
313
  success: result.success,
@@ -277,30 +381,61 @@ class PlanExecutor {
277
381
  }
278
382
  /**
279
383
  * Map GOAP agent type to MCP agent type
384
+ *
385
+ * GOAP actions use 'qe-*' prefixed agent types which need to be
386
+ * mapped to MCP types that AgentRegistry understands.
280
387
  */
281
388
  mapAgentType(goapAgentType) {
282
389
  const mapping = {
283
- // QE agents
390
+ // Core Testing Agents
284
391
  'qe-test-generator': 'test-generator',
285
392
  'qe-test-executor': 'test-executor',
393
+ 'qe-test-writer': 'test-generator', // Test writers use test-generator agent
394
+ 'qe-integration-tester': 'test-executor', // Integration tests use test-executor
395
+ // Coverage & Analysis Agents
286
396
  'qe-coverage-analyzer': 'coverage-analyzer',
397
+ 'qe-code-complexity': 'code-analyzer', // Maps to quality-analyzer
398
+ 'qe-code-intelligence': 'code-analyzer', // Maps to quality-analyzer
399
+ // Quality & Gate Agents
287
400
  'qe-quality-gate': 'quality-gate',
288
- 'qe-performance-tester': 'performance-tester',
401
+ 'qe-quality-analyzer': 'code-analyzer',
402
+ // Security Agents
289
403
  'qe-security-scanner': 'security-scanner',
404
+ // Performance Agents
405
+ 'qe-performance-tester': 'performance-tester',
406
+ // Specialized Testing Agents
290
407
  'qe-flaky-test-hunter': 'flaky-test-detector',
291
408
  'qe-regression-risk-analyzer': 'regression-analyzer',
409
+ 'qe-chaos-engineer': 'chaos-engineer',
410
+ 'qe-visual-tester': 'visual-tester',
411
+ // Strategic Planning Agents
292
412
  'qe-requirements-validator': 'requirements-validator',
413
+ 'qe-deployment-readiness': 'deployment-validator',
414
+ 'qe-production-intelligence': 'production-analyzer',
415
+ // Fleet & Orchestration Agents
293
416
  'qe-fleet-commander': 'fleet-commander',
294
- 'qe-chaos-engineer': 'chaos-engineer',
295
- // Legacy/simple mappings
417
+ // Data & Contract Agents
418
+ 'qe-test-data-architect': 'data-generator',
419
+ 'qe-api-contract-validator': 'contract-validator',
420
+ // Quality Experience (QX) Agent
421
+ 'qe-qx-partner': 'qx-partner',
422
+ // Accessibility Agent
423
+ 'qe-accessibility-ally': 'accessibility-ally',
424
+ // Legacy/simple mappings (for backward compatibility)
296
425
  'test-generator': 'test-generator',
297
426
  'test-executor': 'test-executor',
298
427
  'coverage-analyzer': 'coverage-analyzer',
299
428
  'quality-gate': 'quality-gate',
300
429
  'performance-tester': 'performance-tester',
301
- 'security-scanner': 'security-scanner'
430
+ 'security-scanner': 'security-scanner',
431
+ 'fleet-commander': 'fleet-commander',
432
+ 'chaos-engineer': 'chaos-engineer'
302
433
  };
303
- return mapping[goapAgentType] || 'quality-gate';
434
+ const mcpType = mapping[goapAgentType];
435
+ if (!mcpType) {
436
+ this.logger.warn(`[PlanExecutor] Unknown GOAP agent type: ${goapAgentType}, defaulting to quality-gate`);
437
+ }
438
+ return mcpType || 'quality-gate';
304
439
  }
305
440
  /**
306
441
  * Get capabilities for an action
@@ -319,12 +454,21 @@ class PlanExecutor {
319
454
  }
320
455
  /**
321
456
  * Create a task from a remediation action
457
+ *
458
+ * Maps GOAP action categories to structured task payloads that
459
+ * QE agents can understand and execute properly.
322
460
  */
323
461
  createTaskFromAction(action, context) {
462
+ const taskId = `task-${action.id}-${Date.now()}`;
463
+ const priority = context.criticality === 'critical' ? 1 : context.criticality === 'high' ? 3 : 5;
464
+ // Build category-specific payload
465
+ const categoryPayload = this.buildCategoryPayload(action, context);
324
466
  return {
325
- id: `task-${action.id}-${Date.now()}`,
326
- type: action.category,
467
+ id: taskId,
468
+ type: this.mapCategoryToTaskType(action.category),
469
+ taskType: this.mapCategoryToTaskType(action.category),
327
470
  payload: {
471
+ ...categoryPayload,
328
472
  actionId: action.id,
329
473
  actionName: action.name,
330
474
  description: action.description,
@@ -333,12 +477,441 @@ class PlanExecutor {
333
477
  buildId: context.buildId,
334
478
  environment: context.environment
335
479
  },
336
- priority: context.criticality === 'critical' ? 1 : context.criticality === 'high' ? 3 : 5,
480
+ priority,
337
481
  description: action.description || action.name,
338
482
  context: {
339
483
  source: 'goap-remediation',
340
- planAction: action.id
484
+ planAction: action.id,
485
+ goapCategory: action.category
486
+ },
487
+ requirements: this.buildRequirements(action)
488
+ };
489
+ }
490
+ /**
491
+ * Build category-specific payload for task execution
492
+ *
493
+ * Note: action.effects is string[] describing the state changes
494
+ */
495
+ buildCategoryPayload(action, context) {
496
+ const basePayload = {
497
+ actionId: action.id,
498
+ actionName: action.name
499
+ };
500
+ // Parse coverage target from effects if present
501
+ const coverageTarget = this.extractCoverageTarget(action.effects);
502
+ switch (action.category) {
503
+ case 'test':
504
+ return {
505
+ ...basePayload,
506
+ testType: this.inferTestType(action.id),
507
+ targetCoverage: coverageTarget,
508
+ runIntegration: action.id.includes('integration'),
509
+ runUnit: action.id.includes('unit') || !action.id.includes('integration')
510
+ };
511
+ case 'coverage':
512
+ return {
513
+ ...basePayload,
514
+ analysisType: 'gap-detection',
515
+ targetCoverage: coverageTarget,
516
+ includeUncovered: true
517
+ };
518
+ case 'security':
519
+ return {
520
+ ...basePayload,
521
+ scanType: this.inferSecurityScanType(action.id),
522
+ severityThreshold: action.id.includes('critical') ? 'critical' : 'high',
523
+ autoFix: action.id.includes('fix') || action.id.includes('remediate')
524
+ };
525
+ case 'performance':
526
+ return {
527
+ ...basePayload,
528
+ testType: this.inferPerformanceTestType(action.id),
529
+ durationSeconds: 60,
530
+ targetP95Ms: 200,
531
+ targetErrorRate: 0.01
532
+ };
533
+ case 'analysis':
534
+ return {
535
+ ...basePayload,
536
+ analysisDepth: 'full',
537
+ includeMetrics: true
538
+ };
539
+ case 'process':
540
+ return {
541
+ ...basePayload,
542
+ processType: 'quality-gate-evaluation',
543
+ environment: context.environment,
544
+ criticality: context.criticality
545
+ };
546
+ case 'fleet':
547
+ return {
548
+ ...basePayload,
549
+ fleetOperation: this.inferFleetOperation(action.id),
550
+ maxAgents: 10
551
+ };
552
+ default:
553
+ return basePayload;
554
+ }
555
+ }
556
+ /**
557
+ * Extract coverage target from effects array
558
+ */
559
+ extractCoverageTarget(effects) {
560
+ // Effects are strings like "coverage.line >= 80" or "Increase line coverage by 10%"
561
+ for (const effect of effects) {
562
+ const match = effect.match(/coverage.*?(\d+)/i);
563
+ if (match) {
564
+ return parseInt(match[1], 10);
341
565
  }
566
+ }
567
+ return 80; // Default target
568
+ }
569
+ /**
570
+ * Map action category to task type
571
+ */
572
+ mapCategoryToTaskType(category) {
573
+ const mapping = {
574
+ test: 'test-execution',
575
+ coverage: 'coverage-analysis',
576
+ security: 'security-scan',
577
+ performance: 'performance-test',
578
+ analysis: 'code-analysis',
579
+ process: 'process-evaluation',
580
+ fleet: 'fleet-management'
581
+ };
582
+ return mapping[category] || 'generic';
583
+ }
584
+ /**
585
+ * Infer test type from action ID
586
+ */
587
+ inferTestType(actionId) {
588
+ if (actionId.includes('unit'))
589
+ return 'unit';
590
+ if (actionId.includes('integration'))
591
+ return 'integration';
592
+ if (actionId.includes('e2e'))
593
+ return 'e2e';
594
+ if (actionId.includes('smoke'))
595
+ return 'smoke';
596
+ if (actionId.includes('regression'))
597
+ return 'regression';
598
+ return 'unit';
599
+ }
600
+ /**
601
+ * Infer security scan type from action ID
602
+ */
603
+ inferSecurityScanType(actionId) {
604
+ if (actionId.includes('sast'))
605
+ return 'sast';
606
+ if (actionId.includes('dast'))
607
+ return 'dast';
608
+ if (actionId.includes('dependency'))
609
+ return 'dependency';
610
+ if (actionId.includes('vulnerability'))
611
+ return 'vulnerability';
612
+ return 'comprehensive';
613
+ }
614
+ /**
615
+ * Infer performance test type from action ID
616
+ */
617
+ inferPerformanceTestType(actionId) {
618
+ if (actionId.includes('load'))
619
+ return 'load';
620
+ if (actionId.includes('stress'))
621
+ return 'stress';
622
+ if (actionId.includes('spike'))
623
+ return 'spike';
624
+ if (actionId.includes('soak'))
625
+ return 'soak';
626
+ if (actionId.includes('baseline'))
627
+ return 'baseline';
628
+ return 'load';
629
+ }
630
+ /**
631
+ * Infer fleet operation from action ID
632
+ */
633
+ inferFleetOperation(actionId) {
634
+ if (actionId.includes('spawn'))
635
+ return 'spawn';
636
+ if (actionId.includes('terminate'))
637
+ return 'terminate';
638
+ if (actionId.includes('scale'))
639
+ return 'scale';
640
+ if (actionId.includes('optimize'))
641
+ return 'optimize';
642
+ return 'manage';
643
+ }
644
+ /**
645
+ * Build requirements for task execution
646
+ */
647
+ buildRequirements(action) {
648
+ return {
649
+ timeout: action.estimatedDuration || 300000,
650
+ retries: 1,
651
+ expectedEffects: action.effects
652
+ };
653
+ }
654
+ // ============================================================================
655
+ // Phase 6: Live Execution with Real World State Updates
656
+ // ============================================================================
657
+ /**
658
+ * Parse agent output and update world state with real measurements
659
+ * This is called in live execution mode (not dry-run)
660
+ */
661
+ updateWorldStateFromAgentOutput(action, output, stateBefore) {
662
+ const stateAfter = JSON.parse(JSON.stringify(stateBefore));
663
+ if (!output)
664
+ return stateAfter;
665
+ // Parse output based on action category
666
+ switch (action.category) {
667
+ case 'test':
668
+ this.parseTestOutput(output, stateAfter);
669
+ break;
670
+ case 'coverage':
671
+ this.parseCoverageOutput(output, stateAfter);
672
+ break;
673
+ case 'security':
674
+ this.parseSecurityOutput(output, stateAfter);
675
+ break;
676
+ case 'performance':
677
+ this.parsePerformanceOutput(output, stateAfter);
678
+ break;
679
+ case 'analysis':
680
+ this.parseAnalysisOutput(output, stateAfter);
681
+ break;
682
+ default:
683
+ // For other categories, use simulation as fallback
684
+ break;
685
+ }
686
+ return stateAfter;
687
+ }
688
+ /**
689
+ * Parse test execution output
690
+ */
691
+ parseTestOutput(output, state) {
692
+ // Look for coverage data in output
693
+ if (output.coverage) {
694
+ state.coverage.line = output.coverage.line ?? output.coverage.linePercentage ?? state.coverage.line;
695
+ state.coverage.branch = output.coverage.branch ?? output.coverage.branchPercentage ?? state.coverage.branch;
696
+ state.coverage.function = output.coverage.function ?? output.coverage.functionPercentage ?? state.coverage.function;
697
+ state.coverage.measured = true;
698
+ }
699
+ // Look for test results
700
+ if (output.testResults || output.tests) {
701
+ const results = output.testResults || output.tests;
702
+ if (results.total && results.passed !== undefined) {
703
+ state.quality.testsPassing = (results.passed / results.total) * 100;
704
+ state.quality.testsMeasured = true;
705
+ }
706
+ }
707
+ // Handle simple pass rate
708
+ if (typeof output.passRate === 'number') {
709
+ state.quality.testsPassing = output.passRate;
710
+ state.quality.testsMeasured = true;
711
+ }
712
+ }
713
+ /**
714
+ * Parse coverage analysis output
715
+ */
716
+ parseCoverageOutput(output, state) {
717
+ if (output.coverage) {
718
+ state.coverage.line = output.coverage.line ?? state.coverage.line;
719
+ state.coverage.branch = output.coverage.branch ?? state.coverage.branch;
720
+ state.coverage.function = output.coverage.function ?? state.coverage.function;
721
+ state.coverage.measured = true;
722
+ }
723
+ // Handle gaps detected
724
+ if (output.gaps && Array.isArray(output.gaps)) {
725
+ // Store gap information for future actions
726
+ this.logger.debug('[PlanExecutor] Coverage gaps detected', { gapCount: output.gaps.length });
727
+ }
728
+ }
729
+ /**
730
+ * Parse security scan output
731
+ */
732
+ parseSecurityOutput(output, state) {
733
+ if (output.securityScore !== undefined) {
734
+ state.quality.securityScore = output.securityScore;
735
+ state.quality.securityMeasured = true;
736
+ }
737
+ // Calculate from vulnerabilities
738
+ if (output.vulnerabilities || output.summary) {
739
+ const summary = output.summary || output.vulnerabilities;
740
+ const critical = summary.critical ?? 0;
741
+ const high = summary.high ?? 0;
742
+ const medium = summary.medium ?? 0;
743
+ // Score: 100 - (critical*25 + high*10 + medium*5), clamped to 0-100
744
+ state.quality.securityScore = Math.max(0, Math.min(100, 100 - (critical * 25 + high * 10 + medium * 5)));
745
+ state.quality.securityMeasured = true;
746
+ }
747
+ }
748
+ /**
749
+ * Parse performance test output
750
+ */
751
+ parsePerformanceOutput(output, state) {
752
+ if (output.performanceScore !== undefined) {
753
+ state.quality.performanceScore = output.performanceScore;
754
+ state.quality.performanceMeasured = true;
755
+ }
756
+ // Calculate from error rate and latency
757
+ if (output.errorRate !== undefined || output.p95 !== undefined) {
758
+ const errorPenalty = (output.errorRate ?? 0) * 100;
759
+ const latencyPenalty = output.p95 && output.targetP95
760
+ ? Math.max(0, (output.p95 - output.targetP95) / output.targetP95 * 50)
761
+ : 0;
762
+ state.quality.performanceScore = Math.max(0, 100 - errorPenalty - latencyPenalty);
763
+ state.quality.performanceMeasured = true;
764
+ }
765
+ }
766
+ /**
767
+ * Parse code analysis output
768
+ */
769
+ parseAnalysisOutput(output, state) {
770
+ if (output.technicalDebt !== undefined) {
771
+ state.quality.technicalDebt = output.technicalDebt;
772
+ }
773
+ if (output.complexity !== undefined) {
774
+ state.quality.complexityMeasured = true;
775
+ }
776
+ }
777
+ // ============================================================================
778
+ // Phase 5: Learning Integration Helpers
779
+ // ============================================================================
780
+ /**
781
+ * Initialize world state from quality gate metrics
782
+ */
783
+ initializeWorldStateFromMetrics(metrics, context) {
784
+ // Calculate pass rate from test results
785
+ const testResults = metrics.testResults;
786
+ const testPassRate = testResults && testResults.total
787
+ ? ((testResults.passed ?? 0) / testResults.total) * 100
788
+ : 0;
789
+ // Calculate security score (inverse of vulnerability count)
790
+ const securitySummary = metrics.security?.summary;
791
+ const securityScore = securitySummary
792
+ ? Math.max(0, 100 - ((securitySummary.critical ?? 0) * 25 + (securitySummary.high ?? 0) * 10))
793
+ : 100;
794
+ // Calculate performance score from error rate
795
+ const performanceScore = metrics.performance?.errorRate !== undefined
796
+ ? Math.max(0, 100 - metrics.performance.errorRate * 100)
797
+ : 100;
798
+ // Map criticality to risk level
799
+ const riskLevelMap = {
800
+ low: 'low',
801
+ medium: 'medium',
802
+ high: 'high',
803
+ critical: 'critical'
804
+ };
805
+ const riskLevel = riskLevelMap[context.criticality || 'medium'] || 'medium';
806
+ // Estimate change size from changed files count
807
+ const changeSize = (context.changedFiles?.length ?? 0) <= 5 ? 'small' :
808
+ (context.changedFiles?.length ?? 0) <= 20 ? 'medium' : 'large';
809
+ this.currentWorldState = {
810
+ coverage: {
811
+ line: metrics.coverage?.linePercentage ?? metrics.coverage?.overallPercentage ?? 0,
812
+ branch: metrics.coverage?.branchPercentage ?? 0,
813
+ function: metrics.coverage?.functionPercentage ?? 0,
814
+ target: 80,
815
+ measured: metrics.coverage !== undefined
816
+ },
817
+ quality: {
818
+ testsPassing: testPassRate,
819
+ securityScore,
820
+ performanceScore,
821
+ technicalDebt: metrics.codeQuality?.technicalDebtDays ?? 0,
822
+ gateStatus: 'pending',
823
+ testsMeasured: testResults !== undefined,
824
+ securityMeasured: metrics.security !== undefined,
825
+ performanceMeasured: metrics.performance !== undefined
826
+ },
827
+ fleet: {
828
+ activeAgents: 0,
829
+ availableAgents: context.availableAgents || ['test-generator', 'coverage-analyzer', 'security-scanner'],
830
+ busyAgents: [],
831
+ agentTypes: {}
832
+ },
833
+ resources: {
834
+ timeRemaining: context.timeRemaining || 3600,
835
+ memoryAvailable: 4096,
836
+ parallelSlots: 4
837
+ },
838
+ context: {
839
+ environment: context.environment || 'development',
840
+ changeSize,
841
+ riskLevel,
842
+ previousFailures: context.previousFailures || 0
843
+ }
844
+ };
845
+ }
846
+ /**
847
+ * Simulate action effects on world state
848
+ */
849
+ simulateActionEffects(stateBefore, action, success) {
850
+ const stateAfter = JSON.parse(JSON.stringify(stateBefore));
851
+ if (!success)
852
+ return stateAfter;
853
+ // Parse effects and apply them
854
+ for (const effect of action.effects) {
855
+ // Effect format examples:
856
+ // "coverage.line >= 80" -> set coverage if action category is test/coverage
857
+ // "quality.testsPassing = true" -> set tests passing
858
+ // "quality.securityMeasured = true" -> mark security as measured
859
+ if (effect.includes('coverage') && action.category === 'test') {
860
+ // Simulate coverage improvement
861
+ stateAfter.coverage.line = Math.min(100, stateBefore.coverage.line + 10);
862
+ stateAfter.coverage.branch = Math.min(100, stateBefore.coverage.branch + 5);
863
+ stateAfter.coverage.measured = true;
864
+ }
865
+ if (effect.includes('testsPassing') || action.category === 'test') {
866
+ stateAfter.quality.testsPassing = Math.min(100, stateBefore.quality.testsPassing + 5);
867
+ stateAfter.quality.testsMeasured = true;
868
+ }
869
+ if (effect.includes('security') || action.category === 'security') {
870
+ stateAfter.quality.securityScore = Math.min(100, stateBefore.quality.securityScore + 10);
871
+ stateAfter.quality.securityMeasured = true;
872
+ }
873
+ if (effect.includes('performance') || action.category === 'performance') {
874
+ stateAfter.quality.performanceScore = Math.min(100, stateBefore.quality.performanceScore + 5);
875
+ stateAfter.quality.performanceMeasured = true;
876
+ }
877
+ if (effect.includes('gateStatus')) {
878
+ stateAfter.quality.gateStatus = 'passed';
879
+ stateAfter.quality.gateEvaluated = true;
880
+ }
881
+ }
882
+ return stateAfter;
883
+ }
884
+ /**
885
+ * Convert RemediationAction to GOAPAction for learning
886
+ */
887
+ remediationActionToGOAPAction(action) {
888
+ return {
889
+ id: action.id,
890
+ name: action.name,
891
+ description: action.description,
892
+ agentType: action.agentType,
893
+ preconditions: {}, // Preconditions were already checked during planning
894
+ effects: {}, // Effects are string[] in RemediationAction
895
+ cost: 1.0 / (action.successRate || 1.0), // Higher cost for lower success rate
896
+ durationEstimate: action.estimatedDuration,
897
+ successRate: action.successRate,
898
+ category: action.category
899
+ };
900
+ }
901
+ /**
902
+ * Convert RemediationPlan to GOAPPlan for learning
903
+ */
904
+ remediationPlanToGOAPPlan(plan, initialState) {
905
+ return {
906
+ id: plan.planId,
907
+ actions: plan.actions.map(a => this.remediationActionToGOAPAction(a)),
908
+ totalCost: plan.totalCost,
909
+ estimatedDuration: plan.estimatedDuration,
910
+ goalConditions: {
911
+ 'quality.gateStatus': { eq: 'passed' }
912
+ },
913
+ initialState,
914
+ status: 'executing'
342
915
  };
343
916
  }
344
917
  /**