agentic-qe 1.9.4 → 2.1.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.
Files changed (262) hide show
  1. package/.claude/agents/qe-api-contract-validator.md +95 -1336
  2. package/.claude/agents/qe-chaos-engineer.md +152 -1211
  3. package/.claude/agents/qe-code-complexity.md +144 -707
  4. package/.claude/agents/qe-coverage-analyzer.md +147 -743
  5. package/.claude/agents/qe-deployment-readiness.md +143 -1496
  6. package/.claude/agents/qe-flaky-test-hunter.md +132 -1529
  7. package/.claude/agents/qe-fleet-commander.md +12 -12
  8. package/.claude/agents/qe-performance-tester.md +150 -886
  9. package/.claude/agents/qe-production-intelligence.md +155 -1396
  10. package/.claude/agents/qe-quality-analyzer.md +6 -6
  11. package/.claude/agents/qe-quality-gate.md +151 -648
  12. package/.claude/agents/qe-regression-risk-analyzer.md +132 -1150
  13. package/.claude/agents/qe-requirements-validator.md +149 -932
  14. package/.claude/agents/qe-security-scanner.md +157 -797
  15. package/.claude/agents/qe-test-data-architect.md +96 -1365
  16. package/.claude/agents/qe-test-executor.md +8 -8
  17. package/.claude/agents/qe-test-generator.md +145 -1540
  18. package/.claude/agents/qe-visual-tester.md +153 -1257
  19. package/.claude/agents/qx-partner.md +248 -0
  20. package/.claude/agents/subagents/qe-code-reviewer.md +40 -136
  21. package/.claude/agents/subagents/qe-coverage-gap-analyzer.md +40 -480
  22. package/.claude/agents/subagents/qe-data-generator.md +41 -125
  23. package/.claude/agents/subagents/qe-flaky-investigator.md +55 -411
  24. package/.claude/agents/subagents/qe-integration-tester.md +53 -141
  25. package/.claude/agents/subagents/qe-performance-validator.md +54 -130
  26. package/.claude/agents/subagents/qe-security-auditor.md +56 -114
  27. package/.claude/agents/subagents/qe-test-data-architect-sub.md +57 -548
  28. package/.claude/agents/subagents/qe-test-implementer.md +58 -551
  29. package/.claude/agents/subagents/qe-test-refactorer.md +65 -722
  30. package/.claude/agents/subagents/qe-test-writer.md +63 -726
  31. package/.claude/skills/accessibility-testing/SKILL.md +144 -692
  32. package/.claude/skills/agentic-quality-engineering/SKILL.md +176 -529
  33. package/.claude/skills/api-testing-patterns/SKILL.md +180 -560
  34. package/.claude/skills/brutal-honesty-review/SKILL.md +113 -603
  35. package/.claude/skills/bug-reporting-excellence/SKILL.md +116 -517
  36. package/.claude/skills/chaos-engineering-resilience/SKILL.md +127 -72
  37. package/.claude/skills/cicd-pipeline-qe-orchestrator/SKILL.md +209 -404
  38. package/.claude/skills/code-review-quality/SKILL.md +158 -608
  39. package/.claude/skills/compatibility-testing/SKILL.md +148 -38
  40. package/.claude/skills/compliance-testing/SKILL.md +132 -63
  41. package/.claude/skills/consultancy-practices/SKILL.md +114 -446
  42. package/.claude/skills/context-driven-testing/SKILL.md +117 -381
  43. package/.claude/skills/contract-testing/SKILL.md +176 -141
  44. package/.claude/skills/database-testing/SKILL.md +137 -130
  45. package/.claude/skills/exploratory-testing-advanced/SKILL.md +160 -629
  46. package/.claude/skills/holistic-testing-pact/SKILL.md +140 -188
  47. package/.claude/skills/localization-testing/SKILL.md +145 -33
  48. package/.claude/skills/mobile-testing/SKILL.md +132 -448
  49. package/.claude/skills/mutation-testing/SKILL.md +147 -41
  50. package/.claude/skills/performance-testing/SKILL.md +200 -546
  51. package/.claude/skills/quality-metrics/SKILL.md +164 -519
  52. package/.claude/skills/refactoring-patterns/SKILL.md +132 -699
  53. package/.claude/skills/regression-testing/SKILL.md +120 -926
  54. package/.claude/skills/risk-based-testing/SKILL.md +157 -660
  55. package/.claude/skills/security-testing/SKILL.md +199 -538
  56. package/.claude/skills/sherlock-review/SKILL.md +163 -699
  57. package/.claude/skills/shift-left-testing/SKILL.md +161 -465
  58. package/.claude/skills/shift-right-testing/SKILL.md +161 -519
  59. package/.claude/skills/six-thinking-hats/SKILL.md +175 -1110
  60. package/.claude/skills/skills-manifest.json +683 -0
  61. package/.claude/skills/tdd-london-chicago/SKILL.md +131 -448
  62. package/.claude/skills/technical-writing/SKILL.md +103 -154
  63. package/.claude/skills/test-automation-strategy/SKILL.md +166 -772
  64. package/.claude/skills/test-data-management/SKILL.md +126 -910
  65. package/.claude/skills/test-design-techniques/SKILL.md +179 -89
  66. package/.claude/skills/test-environment-management/SKILL.md +136 -91
  67. package/.claude/skills/test-reporting-analytics/SKILL.md +169 -92
  68. package/.claude/skills/testability-scoring/README.md +71 -0
  69. package/.claude/skills/testability-scoring/SKILL.md +245 -0
  70. package/.claude/skills/testability-scoring/resources/templates/config.template.js +84 -0
  71. package/.claude/skills/testability-scoring/resources/templates/testability-scoring.spec.template.js +532 -0
  72. package/.claude/skills/testability-scoring/scripts/generate-html-report.js +1007 -0
  73. package/.claude/skills/testability-scoring/scripts/run-assessment.sh +70 -0
  74. package/.claude/skills/visual-testing-advanced/SKILL.md +155 -78
  75. package/.claude/skills/xp-practices/SKILL.md +151 -587
  76. package/CHANGELOG.md +110 -0
  77. package/README.md +55 -21
  78. package/dist/agents/QXPartnerAgent.d.ts +146 -0
  79. package/dist/agents/QXPartnerAgent.d.ts.map +1 -0
  80. package/dist/agents/QXPartnerAgent.js +1831 -0
  81. package/dist/agents/QXPartnerAgent.js.map +1 -0
  82. package/dist/agents/index.d.ts +1 -0
  83. package/dist/agents/index.d.ts.map +1 -1
  84. package/dist/agents/index.js +82 -2
  85. package/dist/agents/index.js.map +1 -1
  86. package/dist/agents/lifecycle/AgentLifecycleManager.d.ts.map +1 -1
  87. package/dist/agents/lifecycle/AgentLifecycleManager.js +34 -31
  88. package/dist/agents/lifecycle/AgentLifecycleManager.js.map +1 -1
  89. package/dist/cli/commands/debug/agent.d.ts.map +1 -1
  90. package/dist/cli/commands/debug/agent.js +19 -6
  91. package/dist/cli/commands/debug/agent.js.map +1 -1
  92. package/dist/cli/commands/debug/health-check.js +20 -7
  93. package/dist/cli/commands/debug/health-check.js.map +1 -1
  94. package/dist/cli/commands/init-claude-md-template.d.ts +1 -0
  95. package/dist/cli/commands/init-claude-md-template.d.ts.map +1 -1
  96. package/dist/cli/commands/init-claude-md-template.js +18 -3
  97. package/dist/cli/commands/init-claude-md-template.js.map +1 -1
  98. package/dist/cli/commands/workflow/cancel.d.ts.map +1 -1
  99. package/dist/cli/commands/workflow/cancel.js +4 -3
  100. package/dist/cli/commands/workflow/cancel.js.map +1 -1
  101. package/dist/cli/commands/workflow/list.d.ts.map +1 -1
  102. package/dist/cli/commands/workflow/list.js +4 -3
  103. package/dist/cli/commands/workflow/list.js.map +1 -1
  104. package/dist/cli/commands/workflow/pause.d.ts.map +1 -1
  105. package/dist/cli/commands/workflow/pause.js +4 -3
  106. package/dist/cli/commands/workflow/pause.js.map +1 -1
  107. package/dist/cli/init/claude-config.d.ts.map +1 -1
  108. package/dist/cli/init/claude-config.js +3 -8
  109. package/dist/cli/init/claude-config.js.map +1 -1
  110. package/dist/cli/init/claude-md.d.ts.map +1 -1
  111. package/dist/cli/init/claude-md.js +44 -2
  112. package/dist/cli/init/claude-md.js.map +1 -1
  113. package/dist/cli/init/database-init.js +1 -1
  114. package/dist/cli/init/index.d.ts.map +1 -1
  115. package/dist/cli/init/index.js +13 -6
  116. package/dist/cli/init/index.js.map +1 -1
  117. package/dist/cli/init/skills.d.ts.map +1 -1
  118. package/dist/cli/init/skills.js +2 -1
  119. package/dist/cli/init/skills.js.map +1 -1
  120. package/dist/core/SwarmCoordinator.d.ts +180 -0
  121. package/dist/core/SwarmCoordinator.d.ts.map +1 -0
  122. package/dist/core/SwarmCoordinator.js +473 -0
  123. package/dist/core/SwarmCoordinator.js.map +1 -0
  124. package/dist/core/memory/AgentDBIntegration.d.ts +24 -6
  125. package/dist/core/memory/AgentDBIntegration.d.ts.map +1 -1
  126. package/dist/core/memory/AgentDBIntegration.js +66 -10
  127. package/dist/core/memory/AgentDBIntegration.js.map +1 -1
  128. package/dist/core/memory/UnifiedMemoryCoordinator.d.ts +341 -0
  129. package/dist/core/memory/UnifiedMemoryCoordinator.d.ts.map +1 -0
  130. package/dist/core/memory/UnifiedMemoryCoordinator.js +986 -0
  131. package/dist/core/memory/UnifiedMemoryCoordinator.js.map +1 -0
  132. package/dist/core/memory/index.d.ts +5 -0
  133. package/dist/core/memory/index.d.ts.map +1 -1
  134. package/dist/core/memory/index.js +23 -1
  135. package/dist/core/memory/index.js.map +1 -1
  136. package/dist/core/metrics/MetricsAggregator.d.ts +228 -0
  137. package/dist/core/metrics/MetricsAggregator.d.ts.map +1 -0
  138. package/dist/core/metrics/MetricsAggregator.js +482 -0
  139. package/dist/core/metrics/MetricsAggregator.js.map +1 -0
  140. package/dist/core/metrics/index.d.ts +5 -0
  141. package/dist/core/metrics/index.d.ts.map +1 -0
  142. package/dist/core/metrics/index.js +11 -0
  143. package/dist/core/metrics/index.js.map +1 -0
  144. package/dist/core/optimization/SwarmOptimizer.d.ts +190 -0
  145. package/dist/core/optimization/SwarmOptimizer.d.ts.map +1 -0
  146. package/dist/core/optimization/SwarmOptimizer.js +648 -0
  147. package/dist/core/optimization/SwarmOptimizer.js.map +1 -0
  148. package/dist/core/optimization/index.d.ts +9 -0
  149. package/dist/core/optimization/index.d.ts.map +1 -0
  150. package/dist/core/optimization/index.js +25 -0
  151. package/dist/core/optimization/index.js.map +1 -0
  152. package/dist/core/optimization/types.d.ts +53 -0
  153. package/dist/core/optimization/types.d.ts.map +1 -0
  154. package/dist/core/optimization/types.js +6 -0
  155. package/dist/core/optimization/types.js.map +1 -0
  156. package/dist/core/orchestration/AdaptiveScheduler.d.ts +190 -0
  157. package/dist/core/orchestration/AdaptiveScheduler.d.ts.map +1 -0
  158. package/dist/core/orchestration/AdaptiveScheduler.js +460 -0
  159. package/dist/core/orchestration/AdaptiveScheduler.js.map +1 -0
  160. package/dist/core/orchestration/PriorityQueue.d.ts +54 -0
  161. package/dist/core/orchestration/PriorityQueue.d.ts.map +1 -0
  162. package/dist/core/orchestration/PriorityQueue.js +122 -0
  163. package/dist/core/orchestration/PriorityQueue.js.map +1 -0
  164. package/dist/core/orchestration/WorkflowOrchestrator.d.ts +189 -0
  165. package/dist/core/orchestration/WorkflowOrchestrator.d.ts.map +1 -0
  166. package/dist/core/orchestration/WorkflowOrchestrator.js +845 -0
  167. package/dist/core/orchestration/WorkflowOrchestrator.js.map +1 -0
  168. package/dist/core/orchestration/index.d.ts +7 -0
  169. package/dist/core/orchestration/index.d.ts.map +1 -0
  170. package/dist/core/orchestration/index.js +11 -0
  171. package/dist/core/orchestration/index.js.map +1 -0
  172. package/dist/core/orchestration/types.d.ts +96 -0
  173. package/dist/core/orchestration/types.d.ts.map +1 -0
  174. package/dist/core/orchestration/types.js +6 -0
  175. package/dist/core/orchestration/types.js.map +1 -0
  176. package/dist/core/recovery/CircuitBreaker.d.ts +176 -0
  177. package/dist/core/recovery/CircuitBreaker.d.ts.map +1 -0
  178. package/dist/core/recovery/CircuitBreaker.js +382 -0
  179. package/dist/core/recovery/CircuitBreaker.js.map +1 -0
  180. package/dist/core/recovery/RecoveryOrchestrator.d.ts +186 -0
  181. package/dist/core/recovery/RecoveryOrchestrator.d.ts.map +1 -0
  182. package/dist/core/recovery/RecoveryOrchestrator.js +476 -0
  183. package/dist/core/recovery/RecoveryOrchestrator.js.map +1 -0
  184. package/dist/core/recovery/RetryStrategy.d.ts +127 -0
  185. package/dist/core/recovery/RetryStrategy.d.ts.map +1 -0
  186. package/dist/core/recovery/RetryStrategy.js +314 -0
  187. package/dist/core/recovery/RetryStrategy.js.map +1 -0
  188. package/dist/core/recovery/index.d.ts +8 -0
  189. package/dist/core/recovery/index.d.ts.map +1 -0
  190. package/dist/core/recovery/index.js +27 -0
  191. package/dist/core/recovery/index.js.map +1 -0
  192. package/dist/core/skills/DependencyResolver.d.ts +99 -0
  193. package/dist/core/skills/DependencyResolver.d.ts.map +1 -0
  194. package/dist/core/skills/DependencyResolver.js +260 -0
  195. package/dist/core/skills/DependencyResolver.js.map +1 -0
  196. package/dist/core/skills/DynamicSkillLoader.d.ts +96 -0
  197. package/dist/core/skills/DynamicSkillLoader.d.ts.map +1 -0
  198. package/dist/core/skills/DynamicSkillLoader.js +353 -0
  199. package/dist/core/skills/DynamicSkillLoader.js.map +1 -0
  200. package/dist/core/skills/ManifestGenerator.d.ts +114 -0
  201. package/dist/core/skills/ManifestGenerator.d.ts.map +1 -0
  202. package/dist/core/skills/ManifestGenerator.js +449 -0
  203. package/dist/core/skills/ManifestGenerator.js.map +1 -0
  204. package/dist/core/skills/index.d.ts +9 -0
  205. package/dist/core/skills/index.d.ts.map +1 -0
  206. package/dist/core/skills/index.js +24 -0
  207. package/dist/core/skills/index.js.map +1 -0
  208. package/dist/core/skills/types.d.ts +118 -0
  209. package/dist/core/skills/types.d.ts.map +1 -0
  210. package/dist/core/skills/types.js +7 -0
  211. package/dist/core/skills/types.js.map +1 -0
  212. package/dist/core/transport/QUICTransport.d.ts +320 -0
  213. package/dist/core/transport/QUICTransport.d.ts.map +1 -0
  214. package/dist/core/transport/QUICTransport.js +711 -0
  215. package/dist/core/transport/QUICTransport.js.map +1 -0
  216. package/dist/core/transport/index.d.ts +40 -0
  217. package/dist/core/transport/index.d.ts.map +1 -0
  218. package/dist/core/transport/index.js +46 -0
  219. package/dist/core/transport/index.js.map +1 -0
  220. package/dist/core/transport/quic-loader.d.ts +123 -0
  221. package/dist/core/transport/quic-loader.d.ts.map +1 -0
  222. package/dist/core/transport/quic-loader.js +293 -0
  223. package/dist/core/transport/quic-loader.js.map +1 -0
  224. package/dist/core/transport/quic.d.ts +154 -0
  225. package/dist/core/transport/quic.d.ts.map +1 -0
  226. package/dist/core/transport/quic.js +214 -0
  227. package/dist/core/transport/quic.js.map +1 -0
  228. package/dist/mcp/server.d.ts +9 -9
  229. package/dist/mcp/server.d.ts.map +1 -1
  230. package/dist/mcp/server.js +1 -2
  231. package/dist/mcp/server.js.map +1 -1
  232. package/dist/mcp/services/AgentRegistry.d.ts.map +1 -1
  233. package/dist/mcp/services/AgentRegistry.js +4 -1
  234. package/dist/mcp/services/AgentRegistry.js.map +1 -1
  235. package/dist/types/index.d.ts +2 -1
  236. package/dist/types/index.d.ts.map +1 -1
  237. package/dist/types/index.js +2 -0
  238. package/dist/types/index.js.map +1 -1
  239. package/dist/types/qx.d.ts +429 -0
  240. package/dist/types/qx.d.ts.map +1 -0
  241. package/dist/types/qx.js +71 -0
  242. package/dist/types/qx.js.map +1 -0
  243. package/dist/visualization/api/RestEndpoints.js +2 -2
  244. package/dist/visualization/api/RestEndpoints.js.map +1 -1
  245. package/dist/visualization/api/WebSocketServer.d.ts +44 -0
  246. package/dist/visualization/api/WebSocketServer.d.ts.map +1 -1
  247. package/dist/visualization/api/WebSocketServer.js +144 -23
  248. package/dist/visualization/api/WebSocketServer.js.map +1 -1
  249. package/dist/visualization/core/DataTransformer.d.ts +10 -0
  250. package/dist/visualization/core/DataTransformer.d.ts.map +1 -1
  251. package/dist/visualization/core/DataTransformer.js +60 -5
  252. package/dist/visualization/core/DataTransformer.js.map +1 -1
  253. package/dist/visualization/emit-event.d.ts +75 -0
  254. package/dist/visualization/emit-event.d.ts.map +1 -0
  255. package/dist/visualization/emit-event.js +213 -0
  256. package/dist/visualization/emit-event.js.map +1 -0
  257. package/dist/visualization/index.d.ts +1 -0
  258. package/dist/visualization/index.d.ts.map +1 -1
  259. package/dist/visualization/index.js +7 -1
  260. package/dist/visualization/index.js.map +1 -1
  261. package/docs/reference/skills.md +63 -1
  262. package/package.json +16 -58
@@ -0,0 +1,1831 @@
1
+ "use strict";
2
+ /**
3
+ * QXPartnerAgent - Quality Experience (QX) Analysis Agent
4
+ *
5
+ * QX = Marriage between QA (Quality Advocacy) and UX (User Experience)
6
+ * Goal: Co-create Quality Experience for everyone associated with the product
7
+ *
8
+ * Based on: https://talesoftesting.com/quality-experienceqx-co-creating-quality-experience-for-everyone-associated-with-the-product/
9
+ *
10
+ * Key Capabilities:
11
+ * - Problem understanding and analysis (Rule of Three)
12
+ * - User needs vs Business needs analysis
13
+ * - Oracle problem detection and resolution
14
+ * - Comprehensive impact analysis (visible & invisible)
15
+ * - UX testing heuristics application
16
+ * - Integration with testability scoring
17
+ * - Contextual recommendations generation
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.QXPartnerAgent = void 0;
21
+ const BaseAgent_1 = require("./BaseAgent");
22
+ const types_1 = require("../types");
23
+ const playwright_1 = require("playwright");
24
+ const qx_1 = require("../types/qx");
25
+ class ConsoleLogger {
26
+ info(message, ...args) {
27
+ console.log(`[INFO] ${message}`, ...args);
28
+ }
29
+ warn(message, ...args) {
30
+ console.warn(`[WARN] ${message}`, ...args);
31
+ }
32
+ error(message, ...args) {
33
+ console.error(`[ERROR] ${message}`, ...args);
34
+ }
35
+ debug(message, ...args) {
36
+ console.debug(`[DEBUG] ${message}`, ...args);
37
+ }
38
+ }
39
+ class QXPartnerAgent extends BaseAgent_1.BaseAgent {
40
+ constructor(config) {
41
+ const baseConfig = {
42
+ type: types_1.QEAgentType.QX_PARTNER,
43
+ capabilities: QXPartnerAgent.getDefaultCapabilities(),
44
+ context: config.context,
45
+ memoryStore: config.memoryStore,
46
+ eventBus: config.eventBus,
47
+ enableLearning: true // Enable learning for adaptive QX analysis
48
+ };
49
+ super(baseConfig);
50
+ this.logger = new ConsoleLogger();
51
+ this.browser = null;
52
+ this.page = null;
53
+ this.config = {
54
+ analysisMode: config.analysisMode || 'full',
55
+ heuristics: config.heuristics || {
56
+ enabledHeuristics: Object.values(qx_1.QXHeuristic),
57
+ minConfidence: 0.7,
58
+ enableCompetitiveAnalysis: false
59
+ },
60
+ integrateTestability: config.integrateTestability ?? true,
61
+ testabilityScoringPath: config.testabilityScoringPath || '.claude/skills/testability-scoring',
62
+ detectOracleProblems: config.detectOracleProblems ?? true,
63
+ minOracleSeverity: config.minOracleSeverity || 'medium',
64
+ collaboration: config.collaboration || {
65
+ coordinateWithUX: true,
66
+ coordinateWithQA: true,
67
+ shareWithQualityAnalyzer: true
68
+ },
69
+ outputFormat: config.outputFormat || 'json',
70
+ thresholds: config.thresholds || {
71
+ minQXScore: 70,
72
+ minProblemClarity: 60,
73
+ minUserNeedsAlignment: 70,
74
+ minBusinessAlignment: 70
75
+ }
76
+ };
77
+ }
78
+ /**
79
+ * Get default capabilities for QX Partner Agent
80
+ */
81
+ static getDefaultCapabilities() {
82
+ return [
83
+ {
84
+ name: 'qx-analysis',
85
+ version: '1.0.0',
86
+ description: 'Comprehensive QX (Quality Experience) analysis combining QA and UX perspectives'
87
+ },
88
+ {
89
+ name: 'oracle-problem-detection',
90
+ version: '1.0.0',
91
+ description: 'Detect and resolve oracle problems when quality criteria are unclear'
92
+ },
93
+ {
94
+ name: 'ux-heuristics',
95
+ version: '1.0.0',
96
+ description: 'Apply UX testing heuristics for comprehensive analysis'
97
+ },
98
+ {
99
+ name: 'impact-analysis',
100
+ version: '1.0.0',
101
+ description: 'Analyze visible and invisible impacts of design changes'
102
+ },
103
+ {
104
+ name: 'balance-finder',
105
+ version: '1.0.0',
106
+ description: 'Find balance between user experience and business needs'
107
+ },
108
+ {
109
+ name: 'testability-integration',
110
+ version: '1.0.0',
111
+ description: 'Integrate with testability scoring for combined insights'
112
+ }
113
+ ];
114
+ }
115
+ /**
116
+ * Initialize QX analysis components
117
+ */
118
+ async initializeComponents() {
119
+ try {
120
+ this.logger.info(`QXPartnerAgent ${this.agentId.id} initializing components`);
121
+ // Initialize heuristics engine
122
+ this.heuristicsEngine = new QXHeuristicsEngine(this.config.heuristics);
123
+ this.logger.info('QX Heuristics Engine initialized');
124
+ // Initialize oracle problem detector
125
+ if (this.config.detectOracleProblems) {
126
+ this.oracleDetector = new OracleDetector(this.config.minOracleSeverity || 'medium');
127
+ this.logger.info('Oracle Problem Detector initialized');
128
+ }
129
+ // Initialize impact analyzer
130
+ this.impactAnalyzer = new ImpactAnalyzer();
131
+ this.logger.info('Impact Analyzer initialized');
132
+ // Validate testability scoring integration
133
+ if (this.config.integrateTestability) {
134
+ await this.validateTestabilityScoringAvailability();
135
+ }
136
+ // Setup collaboration channels
137
+ if (this.config.collaboration) {
138
+ await this.setupCollaborationChannels();
139
+ }
140
+ this.logger.info(`QXPartnerAgent ${this.agentId.id} components initialized successfully`);
141
+ }
142
+ catch (error) {
143
+ this.logger.error(`Failed to initialize QXPartnerAgent components:`, error);
144
+ throw new Error(`Component initialization failed: ${error.message}`);
145
+ }
146
+ }
147
+ /**
148
+ * Load QX knowledge and historical patterns
149
+ */
150
+ async loadKnowledge() {
151
+ try {
152
+ this.logger.info('Loading QX knowledge base');
153
+ // Load historical QX analyses
154
+ const historicalQX = await this.retrieveSharedMemory(types_1.QEAgentType.QX_PARTNER, 'historical-qx-analyses');
155
+ if (historicalQX) {
156
+ this.logger.info('Loaded historical QX analyses');
157
+ await this.storeMemory('qx-history', historicalQX);
158
+ }
159
+ // Load oracle problem patterns
160
+ const oraclePatterns = await this.retrieveMemory('oracle-patterns');
161
+ if (oraclePatterns) {
162
+ this.logger.info('Loaded oracle problem patterns');
163
+ }
164
+ else {
165
+ await this.initializeDefaultOraclePatterns();
166
+ }
167
+ // Load UX heuristics knowledge
168
+ const heuristicsKnowledge = await this.retrieveMemory('heuristics-knowledge');
169
+ if (heuristicsKnowledge) {
170
+ this.logger.info('Loaded UX heuristics knowledge');
171
+ }
172
+ // Load collaboration insights from other agents
173
+ if (this.config.collaboration?.coordinateWithUX) {
174
+ const uxInsights = await this.retrieveSharedMemory(types_1.QEAgentType.VISUAL_TESTER, 'ux-insights');
175
+ if (uxInsights) {
176
+ this.logger.info('Loaded UX agent insights');
177
+ }
178
+ }
179
+ if (this.config.collaboration?.coordinateWithQA) {
180
+ const qaInsights = await this.retrieveSharedMemory(types_1.QEAgentType.QUALITY_ANALYZER, 'qa-insights');
181
+ if (qaInsights) {
182
+ this.logger.info('Loaded QA agent insights');
183
+ }
184
+ }
185
+ this.logger.info('QX knowledge loaded successfully');
186
+ }
187
+ catch (error) {
188
+ this.logger.warn(`Failed to load some QX knowledge:`, error);
189
+ // Continue with default knowledge
190
+ }
191
+ }
192
+ /**
193
+ * Clean up QX analysis resources
194
+ */
195
+ async cleanup() {
196
+ try {
197
+ this.logger.info(`QXPartnerAgent ${this.agentId.id} cleaning up resources`);
198
+ // Close browser if open
199
+ if (this.page) {
200
+ await this.page.close();
201
+ this.page = null;
202
+ }
203
+ if (this.browser) {
204
+ await this.browser.close();
205
+ this.browser = null;
206
+ }
207
+ // Save current QX analysis state
208
+ await this.saveQXState();
209
+ // Store learned patterns
210
+ await this.saveOraclePatterns();
211
+ await this.saveHeuristicsInsights();
212
+ // Share insights with collaborating agents
213
+ if (this.config.collaboration) {
214
+ await this.shareCollaborationInsights();
215
+ }
216
+ this.logger.info(`QXPartnerAgent ${this.agentId.id} cleanup completed`);
217
+ }
218
+ catch (error) {
219
+ this.logger.error(`Error during QXPartnerAgent cleanup:`, error);
220
+ throw new Error(`Cleanup failed: ${error.message}`);
221
+ }
222
+ }
223
+ /**
224
+ * Perform QX analysis task
225
+ */
226
+ async performTask(task) {
227
+ const params = task.payload;
228
+ const taskType = params.type;
229
+ this.logger.info(`Performing QX task: ${taskType} for target: ${params.target}`);
230
+ switch (taskType) {
231
+ case qx_1.QXTaskType.FULL_ANALYSIS:
232
+ return await this.performFullQXAnalysis(params);
233
+ case qx_1.QXTaskType.ORACLE_DETECTION:
234
+ return await this.detectOracleProblems(params);
235
+ case qx_1.QXTaskType.BALANCE_ANALYSIS:
236
+ return await this.analyzeUserBusinessBalance(params);
237
+ case qx_1.QXTaskType.IMPACT_ANALYSIS:
238
+ return await this.performImpactAnalysis(params);
239
+ case qx_1.QXTaskType.APPLY_HEURISTIC:
240
+ return await this.applySpecificHeuristic(params);
241
+ case qx_1.QXTaskType.GENERATE_RECOMMENDATIONS:
242
+ return await this.generateQXRecommendations(params);
243
+ case qx_1.QXTaskType.INTEGRATE_TESTABILITY:
244
+ return await this.integrateTestabilityScoring(params);
245
+ default:
246
+ throw new Error(`Unsupported QX task type: ${taskType}`);
247
+ }
248
+ }
249
+ // ============================================================================
250
+ // QX Analysis Methods
251
+ // ============================================================================
252
+ /**
253
+ * Perform comprehensive QX analysis
254
+ */
255
+ async performFullQXAnalysis(params) {
256
+ const startTime = Date.now();
257
+ const target = params.target;
258
+ this.logger.info(`Starting full QX analysis for: ${target}`);
259
+ // 1. Collect context
260
+ const context = await this.collectQXContext(target, params.params?.context);
261
+ // 2. Analyze problem
262
+ const problemAnalysis = await this.analyzeProblem(context);
263
+ // 3. Analyze user needs
264
+ const userNeeds = await this.analyzeUserNeeds(context, problemAnalysis);
265
+ // 4. Analyze business needs
266
+ const businessNeeds = await this.analyzeBusinessNeeds(context, problemAnalysis);
267
+ // 5. Detect oracle problems
268
+ const oracleProblems = this.config.detectOracleProblems
269
+ ? await this.detectOracleProblemsFromContext(context, userNeeds, businessNeeds)
270
+ : [];
271
+ // 6. Perform impact analysis
272
+ const impactAnalysis = await this.analyzeImpact(context, problemAnalysis);
273
+ // 7. Apply heuristics
274
+ const heuristics = await this.applyAllHeuristics(context, problemAnalysis, userNeeds, businessNeeds);
275
+ // 8. Integrate testability (if enabled)
276
+ const testabilityIntegration = this.config.integrateTestability
277
+ ? await this.integrateTestabilityScoring(params)
278
+ : undefined;
279
+ // 9. Generate recommendations
280
+ const recommendations = await this.generateRecommendations(problemAnalysis, userNeeds, businessNeeds, oracleProblems, impactAnalysis, heuristics, testabilityIntegration);
281
+ // 10. Calculate overall score
282
+ const overallScore = this.calculateOverallQXScore(problemAnalysis, userNeeds, businessNeeds, impactAnalysis, heuristics);
283
+ const grade = this.scoreToGrade(overallScore);
284
+ const analysis = {
285
+ overallScore,
286
+ grade,
287
+ timestamp: new Date(),
288
+ target,
289
+ problemAnalysis,
290
+ userNeeds,
291
+ businessNeeds,
292
+ oracleProblems,
293
+ impactAnalysis,
294
+ heuristics,
295
+ recommendations,
296
+ testabilityIntegration,
297
+ context
298
+ };
299
+ // Store analysis in memory
300
+ await this.storeMemory(`qx-analysis:${target}`, analysis);
301
+ const duration = Date.now() - startTime;
302
+ this.logger.info(`QX analysis completed in ${duration}ms. Score: ${overallScore}/100 (${grade})`);
303
+ return analysis;
304
+ }
305
+ /**
306
+ * Collect QX context from target using Playwright
307
+ */
308
+ async collectQXContext(target, additionalContext) {
309
+ this.logger.debug(`Collecting QX context for: ${target}`);
310
+ try {
311
+ // Launch browser if not already running
312
+ if (!this.browser) {
313
+ this.logger.debug('Launching browser...');
314
+ this.browser = await playwright_1.chromium.launch({
315
+ headless: true,
316
+ timeout: 30000, // 30 second timeout for launch
317
+ args: [
318
+ '--no-sandbox',
319
+ '--disable-setuid-sandbox',
320
+ '--disable-dev-shm-usage',
321
+ '--disable-accelerated-2d-canvas',
322
+ '--no-first-run',
323
+ '--no-zygote',
324
+ '--single-process', // Important for containers
325
+ '--disable-gpu'
326
+ ]
327
+ });
328
+ }
329
+ // Create new page
330
+ this.page = await this.browser.newPage();
331
+ this.logger.debug(`Navigating to ${target}...`);
332
+ // Navigate to target with timeout - try quick load first
333
+ try {
334
+ await this.page.goto(target, { waitUntil: 'commit', timeout: 15000 });
335
+ }
336
+ catch (navError) {
337
+ this.logger.warn(`Quick navigation failed, trying basic load: ${navError}`);
338
+ // Fallback: just navigate without waiting
339
+ await this.page.goto(target, { waitUntil: 'commit', timeout: 10000 });
340
+ }
341
+ // Wait a bit for some content to load
342
+ await this.page.waitForTimeout(1000);
343
+ this.logger.debug('Extracting page context...');
344
+ // Extract page context WITH ACTUAL CONTENT for contextual analysis
345
+ const pageContext = await this.page.evaluate(() => {
346
+ const countElements = (selector) => document.querySelectorAll(selector).length;
347
+ const getText = (selector, limit = 5) => Array.from(document.querySelectorAll(selector)).slice(0, limit).map(el => el.textContent?.trim() || '').filter(t => t.length > 0);
348
+ // Extract navigation items for context understanding
349
+ const navItems = getText('nav a, nav button, [role="navigation"] a');
350
+ const headings = {
351
+ h1: getText('h1', 3),
352
+ h2: getText('h2', 5),
353
+ h3: getText('h3', 5)
354
+ };
355
+ // Extract form purposes from labels/placeholders
356
+ const formPurposes = Array.from(document.querySelectorAll('form')).map(form => {
357
+ const labels = Array.from(form.querySelectorAll('label, input[placeholder]')).slice(0, 3);
358
+ return labels.map(el => el.placeholder || el.textContent?.trim() || '').filter(t => t.length > 0).join(', ');
359
+ });
360
+ // Extract button purposes
361
+ const buttonPurposes = getText('button, [role="button"], input[type="submit"]', 10);
362
+ // Extract link context (first 20 meaningful links)
363
+ const linkTexts = getText('a[href]:not([href="#"]):not([href=""])', 20);
364
+ // Extract main content snippets for purpose understanding
365
+ const mainContent = document.querySelector('main, article, [role="main"]');
366
+ const contentSnippet = mainContent?.textContent?.trim().substring(0, 300) || '';
367
+ return {
368
+ title: document.title,
369
+ url: window.location.href,
370
+ viewport: {
371
+ width: window.innerWidth,
372
+ height: window.innerHeight
373
+ },
374
+ content: {
375
+ headings,
376
+ navigationItems: navItems,
377
+ buttonPurposes,
378
+ formPurposes,
379
+ linkTexts,
380
+ mainContentSnippet: contentSnippet
381
+ },
382
+ elements: {
383
+ total: document.querySelectorAll('*').length,
384
+ buttons: countElements('button, [role="button"], input[type="button"], input[type="submit"]'),
385
+ forms: countElements('form'),
386
+ inputs: countElements('input, textarea, select'),
387
+ links: countElements('a'),
388
+ headings: {
389
+ h1: countElements('h1'),
390
+ h2: countElements('h2'),
391
+ h3: countElements('h3')
392
+ },
393
+ images: countElements('img'),
394
+ videos: countElements('video'),
395
+ iframes: countElements('iframe')
396
+ },
397
+ semantic: {
398
+ hasNav: countElements('nav') > 0,
399
+ hasHeader: countElements('header') > 0,
400
+ hasFooter: countElements('footer') > 0,
401
+ hasMain: countElements('main') > 0,
402
+ hasAside: countElements('aside') > 0,
403
+ hasArticle: countElements('article') > 0,
404
+ hasSection: countElements('section') > 0
405
+ },
406
+ accessibility: {
407
+ ariaLabels: countElements('[aria-label]'),
408
+ ariaDescriptions: countElements('[aria-describedby]'),
409
+ altTexts: Array.from(document.querySelectorAll('img')).filter(img => img.hasAttribute('alt')).length,
410
+ totalImages: countElements('img'),
411
+ landmarkRoles: countElements('[role="banner"], [role="navigation"], [role="main"], [role="complementary"], [role="contentinfo"]'),
412
+ focusableElements: countElements('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])')
413
+ },
414
+ errors: {
415
+ consoleErrors: window.__errors || [],
416
+ hasErrorMessages: countElements('.error, [role="alert"], .alert-danger, .text-danger') > 0
417
+ },
418
+ meta: {
419
+ description: document.querySelector('meta[name="description"]')?.content || '',
420
+ keywords: document.querySelector('meta[name="keywords"]')?.content || '',
421
+ viewport: document.querySelector('meta[name="viewport"]')?.content || ''
422
+ }
423
+ };
424
+ });
425
+ // Capture performance metrics
426
+ const performanceMetrics = await this.page.evaluate(() => {
427
+ const perf = performance.getEntriesByType('navigation')[0];
428
+ return {
429
+ loadTime: perf?.loadEventEnd - perf?.fetchStart || 0,
430
+ domReady: perf?.domContentLoadedEventEnd - perf?.fetchStart || 0,
431
+ firstPaint: performance.getEntriesByType('paint').find(e => e.name === 'first-paint')?.startTime || 0
432
+ };
433
+ });
434
+ const context = {
435
+ url: target,
436
+ title: pageContext.title,
437
+ domMetrics: {
438
+ totalElements: pageContext.elements.total,
439
+ interactiveElements: pageContext.elements.buttons + pageContext.elements.inputs + pageContext.elements.links,
440
+ forms: pageContext.elements.forms,
441
+ inputs: pageContext.elements.inputs,
442
+ buttons: pageContext.elements.buttons,
443
+ semanticStructure: pageContext.semantic
444
+ },
445
+ accessibility: {
446
+ ariaLabelsCount: pageContext.accessibility.ariaLabels,
447
+ altTextsCoverage: pageContext.accessibility.totalImages > 0
448
+ ? (pageContext.accessibility.altTexts / pageContext.accessibility.totalImages) * 100
449
+ : 100,
450
+ focusableElementsCount: pageContext.accessibility.focusableElements,
451
+ landmarkRoles: pageContext.accessibility.landmarkRoles
452
+ },
453
+ performance: performanceMetrics,
454
+ errorIndicators: pageContext.errors,
455
+ metadata: pageContext.meta,
456
+ custom: additionalContext || {}
457
+ };
458
+ // Close page but keep browser for potential reuse
459
+ await this.page.close();
460
+ this.page = null;
461
+ // Store context for later retrieval
462
+ await this.storeMemory(`qx-context:${target}`, context);
463
+ this.logger.debug('Context collection completed successfully');
464
+ return context;
465
+ }
466
+ catch (error) {
467
+ this.logger.error(`Failed to collect QX context: ${error}`);
468
+ // Clean up on error
469
+ if (this.page) {
470
+ try {
471
+ await this.page.close();
472
+ }
473
+ catch (e) {
474
+ // Ignore close errors
475
+ }
476
+ this.page = null;
477
+ }
478
+ // Return minimal context on error
479
+ return {
480
+ url: target,
481
+ custom: additionalContext || {},
482
+ error: error instanceof Error ? error.message : String(error)
483
+ };
484
+ }
485
+ }
486
+ /**
487
+ * Detect domain-specific failure modes based on site type
488
+ */
489
+ detectDomainSpecificFailures(context, title, description, complexity) {
490
+ const failures = [];
491
+ const titleLower = title.toLowerCase();
492
+ const descLower = description.toLowerCase();
493
+ const forms = context.domMetrics?.forms || 0;
494
+ const interactiveElements = context.domMetrics?.interactiveElements || 0;
495
+ // E-commerce / Travel Booking sites
496
+ if (titleLower.includes('hotel') || titleLower.includes('booking') || titleLower.includes('travel') ||
497
+ titleLower.includes('shop') || titleLower.includes('store') || titleLower.includes('buy') ||
498
+ descLower.includes('book') || descLower.includes('reservation') || descLower.includes('hotel')) {
499
+ failures.push({
500
+ description: 'Search and filter complexity may overwhelm users with too many options',
501
+ severity: 'medium',
502
+ likelihood: 'likely'
503
+ });
504
+ failures.push({
505
+ description: 'Booking/checkout flow friction points may cause cart abandonment',
506
+ severity: 'high',
507
+ likelihood: 'likely'
508
+ });
509
+ failures.push({
510
+ description: 'Price transparency issues or hidden fees may erode user trust',
511
+ severity: 'high',
512
+ likelihood: 'possible'
513
+ });
514
+ if (complexity === 'complex') {
515
+ failures.push({
516
+ description: 'Multi-step booking process may lose users if progress is not clearly indicated',
517
+ severity: 'medium',
518
+ likelihood: 'likely'
519
+ });
520
+ }
521
+ }
522
+ // Content/Blog/Magazine sites
523
+ else if (titleLower.includes('blog') || titleLower.includes('article') || titleLower.includes('news') ||
524
+ titleLower.includes('magazine') || titleLower.includes('testers') || titleLower.includes('testing')) {
525
+ failures.push({
526
+ description: 'Content discoverability - users may struggle to find relevant articles without robust search',
527
+ severity: 'medium',
528
+ likelihood: 'likely'
529
+ });
530
+ failures.push({
531
+ description: 'Reading experience on mobile devices may not be optimized for long-form content',
532
+ severity: 'medium',
533
+ likelihood: 'possible'
534
+ });
535
+ failures.push({
536
+ description: 'Archive navigation complexity may overwhelm readers looking for specific topics',
537
+ severity: 'low',
538
+ likelihood: 'possible'
539
+ });
540
+ }
541
+ // SaaS / Web Applications
542
+ else if (titleLower.includes('dashboard') || titleLower.includes('app') || titleLower.includes('platform') ||
543
+ interactiveElements > 50) {
544
+ failures.push({
545
+ description: 'Complex workflows may confuse new users without proper onboarding',
546
+ severity: 'medium',
547
+ likelihood: 'likely'
548
+ });
549
+ failures.push({
550
+ description: 'Data visualization and information density may cause cognitive overload',
551
+ severity: 'medium',
552
+ likelihood: 'possible'
553
+ });
554
+ failures.push({
555
+ description: 'Error messages may not provide actionable recovery steps',
556
+ severity: 'medium',
557
+ likelihood: 'likely'
558
+ });
559
+ }
560
+ // Form-heavy sites
561
+ else if (forms > 0) {
562
+ failures.push({
563
+ description: 'Form validation errors may not be clearly communicated to users',
564
+ severity: 'medium',
565
+ likelihood: 'likely'
566
+ });
567
+ failures.push({
568
+ description: 'Required field indicators may not be consistently applied',
569
+ severity: 'low',
570
+ likelihood: 'possible'
571
+ });
572
+ failures.push({
573
+ description: 'Form submission failure recovery path may not be clear',
574
+ severity: 'medium',
575
+ likelihood: 'possible'
576
+ });
577
+ }
578
+ // Return only the most relevant failures (max 5)
579
+ return failures.slice(0, 5);
580
+ }
581
+ /**
582
+ * Analyze problem using Rule of Three and complexity assessment
583
+ */
584
+ async analyzeProblem(context) {
585
+ this.logger.debug('Analyzing problem');
586
+ const title = context.title || 'Untitled page';
587
+ const description = context.metadata?.description || '';
588
+ const hasError = context.errorIndicators?.hasErrorMessages || false;
589
+ let problemStatement = `Evaluate quality experience of "${title}"`;
590
+ if (description) {
591
+ problemStatement += ` - ${description.substring(0, 100)}`;
592
+ }
593
+ const totalElements = context.domMetrics?.totalElements || 0;
594
+ const interactiveElements = context.domMetrics?.interactiveElements || 0;
595
+ const forms = context.domMetrics?.forms || 0;
596
+ let complexity;
597
+ if (totalElements > 500 || interactiveElements > 50 || forms > 3) {
598
+ complexity = 'complex';
599
+ }
600
+ else if (totalElements > 200 || interactiveElements > 20 || forms > 1) {
601
+ complexity = 'moderate';
602
+ }
603
+ else {
604
+ complexity = 'simple';
605
+ }
606
+ const breakdown = [];
607
+ if (context.domMetrics?.semanticStructure?.hasNav)
608
+ breakdown.push('Navigation structure');
609
+ if (forms > 0)
610
+ breakdown.push(`Form interactions (${forms} forms)`);
611
+ if (interactiveElements > 0)
612
+ breakdown.push(`User interactions (${interactiveElements} elements)`);
613
+ if (context.accessibility)
614
+ breakdown.push('Accessibility compliance');
615
+ if (context.performance)
616
+ breakdown.push('Performance metrics');
617
+ const potentialFailures = [];
618
+ if (!context.domMetrics?.semanticStructure?.hasMain) {
619
+ potentialFailures.push({
620
+ description: 'Missing main content landmark - users may struggle to find primary content',
621
+ severity: 'medium',
622
+ likelihood: 'likely'
623
+ });
624
+ }
625
+ if (context.accessibility && (context.accessibility.altTextsCoverage || 0) < 80) {
626
+ potentialFailures.push({
627
+ description: 'Poor image alt text coverage - screen reader users affected',
628
+ severity: 'high',
629
+ likelihood: 'very-likely'
630
+ });
631
+ }
632
+ if (hasError) {
633
+ potentialFailures.push({
634
+ description: 'Visible error messages detected - potential usability issues',
635
+ severity: 'medium',
636
+ likelihood: 'likely'
637
+ });
638
+ }
639
+ if (context.performance && (context.performance.loadTime || 0) > 3000) {
640
+ potentialFailures.push({
641
+ description: 'Slow load time - user frustration and abandonment risk',
642
+ severity: 'high',
643
+ likelihood: 'very-likely'
644
+ });
645
+ }
646
+ if (!context.metadata?.viewport) {
647
+ potentialFailures.push({
648
+ description: 'Missing viewport meta tag - mobile responsiveness issues',
649
+ severity: 'medium',
650
+ likelihood: 'possible'
651
+ });
652
+ }
653
+ // ENHANCED: Add domain-specific failure modes based on site type and context
654
+ const domainFailures = this.detectDomainSpecificFailures(context, title, description, complexity);
655
+ potentialFailures.push(...domainFailures);
656
+ // Rule of Three: Ensure at least 3 failure modes are identified
657
+ if (potentialFailures.length < 3) {
658
+ // Add generic contextual failures for complex sites
659
+ if (complexity === 'complex') {
660
+ if (potentialFailures.length < 3) {
661
+ potentialFailures.push({
662
+ description: 'Complex interaction flows may confuse first-time users',
663
+ severity: 'medium',
664
+ likelihood: 'possible'
665
+ });
666
+ }
667
+ if (potentialFailures.length < 3) {
668
+ potentialFailures.push({
669
+ description: 'Multiple interactive elements increase cognitive load',
670
+ severity: 'low',
671
+ likelihood: 'possible'
672
+ });
673
+ }
674
+ if (potentialFailures.length < 3) {
675
+ potentialFailures.push({
676
+ description: 'Error recovery paths may not be clear in complex workflows',
677
+ severity: 'medium',
678
+ likelihood: 'possible'
679
+ });
680
+ }
681
+ }
682
+ }
683
+ let clarityScore = 50;
684
+ if (title && title !== 'Untitled page')
685
+ clarityScore += 15;
686
+ if (description)
687
+ clarityScore += 15;
688
+ if (breakdown.length >= 3)
689
+ clarityScore += 10;
690
+ if (context.domMetrics?.semanticStructure?.hasMain)
691
+ clarityScore += 10;
692
+ clarityScore = Math.min(100, clarityScore);
693
+ return {
694
+ problemStatement,
695
+ complexity,
696
+ breakdown,
697
+ potentialFailures,
698
+ clarityScore
699
+ };
700
+ }
701
+ /**
702
+ * Analyze user needs
703
+ */
704
+ async analyzeUserNeeds(context, problemAnalysis) {
705
+ this.logger.debug('Analyzing user needs');
706
+ const needs = [];
707
+ const challenges = [];
708
+ const semantic = context.domMetrics?.semanticStructure;
709
+ const accessibility = context.accessibility;
710
+ const interactiveElements = context.domMetrics?.interactiveElements || 0;
711
+ const forms = context.domMetrics?.forms || 0;
712
+ // Must-have features (critical for basic functionality)
713
+ if (semantic?.hasNav) {
714
+ needs.push({ description: 'Clear navigation to find content', priority: 'must-have', addressed: true });
715
+ }
716
+ else {
717
+ challenges.push('Missing navigation structure - users cannot easily explore site');
718
+ needs.push({ description: 'Clear navigation to find content', priority: 'must-have', addressed: false });
719
+ }
720
+ if (interactiveElements > 0) {
721
+ needs.push({ description: 'Interactive elements for engagement', priority: 'must-have', addressed: true });
722
+ }
723
+ if (accessibility && (accessibility.focusableElementsCount || 0) > 0) {
724
+ needs.push({ description: 'Keyboard navigation support', priority: 'must-have', addressed: true });
725
+ }
726
+ else {
727
+ challenges.push('Limited keyboard navigation - inaccessible to some users');
728
+ needs.push({ description: 'Keyboard navigation support', priority: 'must-have', addressed: false });
729
+ }
730
+ // Should-have features (important for good UX)
731
+ if (semantic?.hasHeader) {
732
+ needs.push({ description: 'Consistent page header for orientation', priority: 'should-have', addressed: true });
733
+ }
734
+ if (semantic?.hasFooter) {
735
+ needs.push({ description: 'Footer with supporting information', priority: 'should-have', addressed: true });
736
+ }
737
+ if (accessibility && (accessibility.altTextsCoverage || 0) > 50) {
738
+ needs.push({ description: 'Image descriptions for screen readers', priority: 'should-have', addressed: true });
739
+ }
740
+ else if (accessibility && (accessibility.altTextsCoverage || 0) < 50) {
741
+ challenges.push('Poor alt text coverage - images not accessible');
742
+ needs.push({ description: 'Image descriptions for screen readers', priority: 'should-have', addressed: false });
743
+ }
744
+ if (context.performance && (context.performance.loadTime || 0) < 3000) {
745
+ needs.push({ description: 'Fast page load time', priority: 'should-have', addressed: true });
746
+ }
747
+ else if (context.performance && (context.performance.loadTime || 0) >= 3000) {
748
+ challenges.push('Slow load time - user frustration risk');
749
+ needs.push({ description: 'Fast page load time', priority: 'should-have', addressed: false });
750
+ }
751
+ // Nice-to-have features (enhancements)
752
+ if (semantic?.hasAside) {
753
+ needs.push({ description: 'Supplementary content sections', priority: 'nice-to-have', addressed: true });
754
+ }
755
+ if (accessibility && (accessibility.landmarkRoles || 0) > 3) {
756
+ needs.push({ description: 'Rich ARIA landmarks for navigation', priority: 'nice-to-have', addressed: true });
757
+ }
758
+ if (forms > 0) {
759
+ needs.push({ description: 'Form interactions for user input', priority: 'nice-to-have', addressed: true });
760
+ }
761
+ // Determine suitability
762
+ const addressedMustHaves = needs.filter(n => n.priority === 'must-have' && n.addressed).length;
763
+ const totalMustHaves = needs.filter(n => n.priority === 'must-have').length;
764
+ let suitability;
765
+ if (challenges.length === 0 && addressedMustHaves >= 3) {
766
+ suitability = 'excellent';
767
+ }
768
+ else if (challenges.length <= 1 && addressedMustHaves >= 2) {
769
+ suitability = 'good';
770
+ }
771
+ else if (challenges.length <= 2 && addressedMustHaves >= 2) {
772
+ suitability = 'adequate';
773
+ }
774
+ else {
775
+ suitability = 'poor';
776
+ }
777
+ // Calculate alignment score
778
+ let alignmentScore = 40;
779
+ alignmentScore += addressedMustHaves * 10;
780
+ alignmentScore += needs.filter(n => n.priority === 'should-have' && n.addressed).length * 5;
781
+ alignmentScore += needs.filter(n => n.priority === 'nice-to-have' && n.addressed).length * 2;
782
+ alignmentScore -= challenges.length * 8;
783
+ alignmentScore = Math.max(0, Math.min(100, alignmentScore));
784
+ return {
785
+ needs,
786
+ suitability,
787
+ challenges,
788
+ alignmentScore
789
+ };
790
+ }
791
+ /**
792
+ * Analyze business needs
793
+ */
794
+ async analyzeBusinessNeeds(context, problemAnalysis) {
795
+ this.logger.debug('Analyzing business needs');
796
+ const forms = context.domMetrics?.forms || 0;
797
+ const interactiveElements = context.domMetrics?.interactiveElements || 0;
798
+ const performance = context.performance;
799
+ const hasErrors = context.errorIndicators?.hasErrorMessages || false;
800
+ let primaryGoal;
801
+ let kpisAffected = [];
802
+ if (forms > 2) {
803
+ primaryGoal = 'business-ease'; // Conversion focus leans business
804
+ kpisAffected = ['Form completion rate', 'Lead generation', 'User sign-ups'];
805
+ }
806
+ else if (interactiveElements > 30) {
807
+ primaryGoal = 'user-experience'; // Engagement focus leans UX
808
+ kpisAffected = ['Time on site', 'Click-through rate', 'User engagement'];
809
+ }
810
+ else {
811
+ primaryGoal = 'balanced';
812
+ kpisAffected = ['Content consumption', 'Bounce rate', 'Page views'];
813
+ }
814
+ const crossTeamImpact = [];
815
+ if (forms > 0) {
816
+ crossTeamImpact.push({
817
+ team: 'Marketing',
818
+ impactType: 'positive',
819
+ description: 'Form conversion optimization needed'
820
+ });
821
+ crossTeamImpact.push({
822
+ team: 'Development',
823
+ impactType: 'neutral',
824
+ description: 'Form validation and submission handling'
825
+ });
826
+ }
827
+ if (context.accessibility && (context.accessibility.altTextsCoverage || 0) < 100) {
828
+ crossTeamImpact.push({
829
+ team: 'Content',
830
+ impactType: 'negative',
831
+ description: 'Image alt text creation required'
832
+ });
833
+ }
834
+ if (performance && (performance.loadTime || 0) > 2000) {
835
+ crossTeamImpact.push({
836
+ team: 'Engineering',
837
+ impactType: 'negative',
838
+ description: 'Performance optimization needed'
839
+ });
840
+ }
841
+ if (problemAnalysis.complexity === 'complex') {
842
+ crossTeamImpact.push({
843
+ team: 'QA',
844
+ impactType: 'neutral',
845
+ description: 'Comprehensive testing strategy required'
846
+ });
847
+ }
848
+ let compromisesUX = false;
849
+ if (hasErrors) {
850
+ compromisesUX = true;
851
+ }
852
+ if (context.accessibility && (context.accessibility.altTextsCoverage || 0) < 50) {
853
+ compromisesUX = true;
854
+ }
855
+ if (performance && (performance.loadTime || 0) > 4000) {
856
+ compromisesUX = true;
857
+ }
858
+ const impactsKPIs = kpisAffected.length > 0;
859
+ let alignmentScore = 50;
860
+ if (kpisAffected.length > 0)
861
+ alignmentScore += 15;
862
+ if (crossTeamImpact.length > 0)
863
+ alignmentScore += 10;
864
+ if (!compromisesUX)
865
+ alignmentScore += 20;
866
+ if (impactsKPIs)
867
+ alignmentScore += 5;
868
+ alignmentScore = Math.min(100, alignmentScore);
869
+ return {
870
+ primaryGoal,
871
+ kpisAffected,
872
+ crossTeamImpact,
873
+ compromisesUX,
874
+ impactsKPIs,
875
+ alignmentScore
876
+ };
877
+ }
878
+ /**
879
+ * Detect oracle problems from analysis context
880
+ */
881
+ async detectOracleProblemsFromContext(context, userNeeds, businessNeeds) {
882
+ if (!this.oracleDetector) {
883
+ return [];
884
+ }
885
+ return this.oracleDetector.detect(context, userNeeds, businessNeeds);
886
+ }
887
+ /**
888
+ * Perform impact analysis
889
+ */
890
+ async analyzeImpact(context, problemAnalysis) {
891
+ if (!this.impactAnalyzer) {
892
+ throw new Error('Impact analyzer not initialized');
893
+ }
894
+ return this.impactAnalyzer.analyze(context, problemAnalysis);
895
+ }
896
+ /**
897
+ * Apply all enabled heuristics
898
+ */
899
+ async applyAllHeuristics(context, problemAnalysis, userNeeds, businessNeeds) {
900
+ if (!this.heuristicsEngine) {
901
+ throw new Error('Heuristics engine not initialized');
902
+ }
903
+ return this.heuristicsEngine.applyAll(context, problemAnalysis, userNeeds, businessNeeds);
904
+ }
905
+ /**
906
+ * Generate QX recommendations
907
+ */
908
+ async generateRecommendations(problemAnalysis, userNeeds, businessNeeds, oracleProblems, impactAnalysis, heuristics, _testabilityIntegration) {
909
+ const recommendations = [];
910
+ let priorityCounter = 1;
911
+ // Oracle problems (highest priority - match manual report structure)
912
+ for (const problem of oracleProblems) {
913
+ const impactScore = problem.severity === 'critical' ? 90 : problem.severity === 'high' ? 80 : problem.severity === 'medium' ? 60 : 40;
914
+ const impactPct = Math.round((impactScore / 100) * 30); // Up to 30% impact
915
+ recommendations.push({
916
+ principle: 'Oracle Problem',
917
+ recommendation: `Resolve: ${problem.description}`,
918
+ severity: problem.severity,
919
+ impact: impactScore,
920
+ effort: problem.severity === 'critical' || problem.severity === 'high' ? 'high' : 'medium',
921
+ priority: priorityCounter++,
922
+ category: 'qa',
923
+ impactPercentage: impactPct,
924
+ estimatedEffort: problem.severity === 'critical' ? 'High - Critical issue' : problem.severity === 'high' ? 'High' : 'Medium'
925
+ });
926
+ }
927
+ // Problem clarity
928
+ if (problemAnalysis.clarityScore < (this.config.thresholds?.minProblemClarity || 70)) {
929
+ const gap = 70 - problemAnalysis.clarityScore;
930
+ recommendations.push({
931
+ principle: 'Problem Understanding',
932
+ recommendation: 'Improve problem statement clarity with detailed breakdown of failure modes and user scenarios',
933
+ severity: gap > 25 ? 'high' : 'medium',
934
+ impact: Math.round(gap * 1.2),
935
+ effort: 'medium',
936
+ priority: priorityCounter++,
937
+ category: 'qx',
938
+ impactPercentage: Math.round((gap / 70) * 20),
939
+ estimatedEffort: 'Medium - Requires stakeholder workshops'
940
+ });
941
+ }
942
+ // User needs alignment (match manual report priority)
943
+ if (userNeeds.alignmentScore < (this.config.thresholds?.minUserNeedsAlignment || 75)) {
944
+ const gap = 75 - userNeeds.alignmentScore;
945
+ const impactPct = Math.min(35, Math.round((gap / 75) * 100));
946
+ recommendations.push({
947
+ principle: 'User Needs Alignment',
948
+ recommendation: `Improve user needs coverage from ${userNeeds.alignmentScore}/100 to at least 75/100`,
949
+ severity: gap > 20 ? 'high' : 'medium',
950
+ impact: Math.round(gap * 0.9),
951
+ effort: gap > 25 ? 'high' : 'medium',
952
+ priority: priorityCounter++,
953
+ category: 'ux',
954
+ impactPercentage: impactPct,
955
+ estimatedEffort: gap > 25 ? 'High - Major UX redesign' : 'Medium - UX improvements'
956
+ });
957
+ }
958
+ // Heuristic-specific high-impact recommendations
959
+ const lowScoringHeuristics = heuristics
960
+ .filter(h => h.score < 70)
961
+ .sort((a, b) => a.score - b.score)
962
+ .slice(0, 5); // Top 5 worst
963
+ lowScoringHeuristics.forEach(heuristic => {
964
+ const impactScore = 75 - heuristic.score;
965
+ const impactPct = Math.round((impactScore / 75) * 25);
966
+ if (heuristic.recommendations.length > 0 && heuristic.heuristicType) {
967
+ recommendations.push({
968
+ principle: this.formatHeuristicName(heuristic.heuristicType),
969
+ recommendation: heuristic.recommendations[0],
970
+ severity: heuristic.score < 50 ? 'high' : 'medium',
971
+ impact: impactScore,
972
+ effort: heuristic.score < 40 ? 'high' : 'medium',
973
+ priority: priorityCounter++,
974
+ category: heuristic.category,
975
+ impactPercentage: impactPct,
976
+ estimatedEffort: heuristic.score < 40 ? 'High - Significant work required' : 'Medium'
977
+ });
978
+ }
979
+ });
980
+ // High-impact issues from heuristics
981
+ heuristics.forEach(heuristic => {
982
+ if (!heuristic.heuristicType)
983
+ return;
984
+ heuristic.issues
985
+ .filter(issue => issue.severity === 'critical' || issue.severity === 'high')
986
+ .slice(0, 1) // One per heuristic
987
+ .forEach(issue => {
988
+ const impactScore = Math.min(85, 100 - heuristic.score);
989
+ const impactPct = Math.round((impactScore / 100) * 22);
990
+ recommendations.push({
991
+ principle: this.formatHeuristicName(heuristic.heuristicType),
992
+ recommendation: issue.description,
993
+ severity: issue.severity,
994
+ impact: impactScore,
995
+ effort: issue.severity === 'critical' ? 'high' : 'medium',
996
+ priority: priorityCounter++,
997
+ category: heuristic.category,
998
+ impactPercentage: impactPct,
999
+ estimatedEffort: issue.severity === 'critical' ? 'High - Critical fix' : 'Medium'
1000
+ });
1001
+ });
1002
+ });
1003
+ // Business-user balance
1004
+ const balanceDiff = Math.abs(userNeeds.alignmentScore - businessNeeds.alignmentScore);
1005
+ if (balanceDiff > 15) {
1006
+ const impactPct = Math.round((balanceDiff / 100) * 20);
1007
+ const favorsUser = userNeeds.alignmentScore > businessNeeds.alignmentScore;
1008
+ recommendations.push({
1009
+ principle: 'User-Business Balance',
1010
+ recommendation: favorsUser
1011
+ ? 'Strengthen business value metrics while maintaining user experience quality'
1012
+ : 'Enhance user experience focus to balance business-centric approach',
1013
+ severity: balanceDiff > 30 ? 'high' : 'medium',
1014
+ impact: Math.round(balanceDiff * 0.75),
1015
+ effort: 'medium',
1016
+ priority: priorityCounter++,
1017
+ category: 'qx',
1018
+ impactPercentage: impactPct,
1019
+ estimatedEffort: 'Medium - Requires stakeholder alignment'
1020
+ });
1021
+ }
1022
+ // Business needs (if misaligned)
1023
+ if (businessNeeds.alignmentScore < (this.config.thresholds?.minBusinessAlignment || 70)) {
1024
+ const gap = 70 - businessNeeds.alignmentScore;
1025
+ recommendations.push({
1026
+ principle: 'Business Alignment',
1027
+ recommendation: 'Improve alignment with business KPIs and objectives',
1028
+ severity: gap > 25 ? 'high' : 'medium',
1029
+ impact: Math.round(gap * 0.7),
1030
+ effort: 'medium',
1031
+ priority: priorityCounter++,
1032
+ category: 'qx',
1033
+ impactPercentage: Math.round((gap / 70) * 18),
1034
+ estimatedEffort: 'Medium - Business stakeholder review'
1035
+ });
1036
+ }
1037
+ // Sort by impact percentage and limit to top 10
1038
+ const sorted = recommendations
1039
+ .sort((a, b) => (b.impactPercentage || 0) - (a.impactPercentage || 0))
1040
+ .slice(0, 10);
1041
+ // Reassign priorities
1042
+ sorted.forEach((rec, idx) => {
1043
+ rec.priority = idx + 1;
1044
+ });
1045
+ return sorted;
1046
+ }
1047
+ formatHeuristicName(heuristic) {
1048
+ return heuristic
1049
+ .split('-')
1050
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
1051
+ .join(' ');
1052
+ }
1053
+ /**
1054
+ * Calculate overall QX score
1055
+ */
1056
+ calculateOverallQXScore(problemAnalysis, userNeeds, businessNeeds, impactAnalysis, heuristics) {
1057
+ // Weighted average of all components
1058
+ const weights = {
1059
+ problem: 0.20,
1060
+ userNeeds: 0.25,
1061
+ businessNeeds: 0.20,
1062
+ impact: 0.15,
1063
+ heuristics: 0.20
1064
+ };
1065
+ const heuristicsAvg = heuristics.length > 0
1066
+ ? heuristics.reduce((sum, h) => sum + h.score, 0) / heuristics.length
1067
+ : 70;
1068
+ const impactScore = Math.max(0, 100 - impactAnalysis.overallImpactScore);
1069
+ const score = problemAnalysis.clarityScore * weights.problem +
1070
+ userNeeds.alignmentScore * weights.userNeeds +
1071
+ businessNeeds.alignmentScore * weights.businessNeeds +
1072
+ impactScore * weights.impact +
1073
+ heuristicsAvg * weights.heuristics;
1074
+ return Math.round(score);
1075
+ }
1076
+ /**
1077
+ * Convert score to grade
1078
+ */
1079
+ scoreToGrade(score) {
1080
+ if (score >= 90)
1081
+ return 'A';
1082
+ if (score >= 80)
1083
+ return 'B';
1084
+ if (score >= 70)
1085
+ return 'C';
1086
+ if (score >= 60)
1087
+ return 'D';
1088
+ return 'F';
1089
+ }
1090
+ /**
1091
+ * Detect oracle problems (separate task)
1092
+ */
1093
+ async detectOracleProblems(params) {
1094
+ const context = await this.collectQXContext(params.target, params.params?.context);
1095
+ const problemAnalysis = await this.analyzeProblem(context);
1096
+ const userNeeds = await this.analyzeUserNeeds(context, problemAnalysis);
1097
+ const businessNeeds = await this.analyzeBusinessNeeds(context, problemAnalysis);
1098
+ return this.detectOracleProblemsFromContext(context, userNeeds, businessNeeds);
1099
+ }
1100
+ /**
1101
+ * Analyze user vs business balance
1102
+ */
1103
+ async analyzeUserBusinessBalance(params) {
1104
+ const context = await this.collectQXContext(params.target, params.params?.context);
1105
+ const problemAnalysis = await this.analyzeProblem(context);
1106
+ const userNeeds = await this.analyzeUserNeeds(context, problemAnalysis);
1107
+ const businessNeeds = await this.analyzeBusinessNeeds(context, problemAnalysis);
1108
+ return {
1109
+ userNeeds,
1110
+ businessNeeds,
1111
+ balance: {
1112
+ favorsUser: userNeeds.alignmentScore > businessNeeds.alignmentScore,
1113
+ favorsBusiness: businessNeeds.alignmentScore > userNeeds.alignmentScore,
1114
+ isBalanced: Math.abs(userNeeds.alignmentScore - businessNeeds.alignmentScore) < 10,
1115
+ recommendation: this.getBalanceRecommendation(userNeeds, businessNeeds)
1116
+ }
1117
+ };
1118
+ }
1119
+ getBalanceRecommendation(userNeeds, businessNeeds) {
1120
+ const diff = userNeeds.alignmentScore - businessNeeds.alignmentScore;
1121
+ if (Math.abs(diff) < 10) {
1122
+ return 'Good balance between user and business needs';
1123
+ }
1124
+ else if (diff > 0) {
1125
+ return 'Consider business objectives more to achieve better balance';
1126
+ }
1127
+ else {
1128
+ return 'Consider user needs more to achieve better balance';
1129
+ }
1130
+ }
1131
+ /**
1132
+ * Perform impact analysis (separate task)
1133
+ */
1134
+ async performImpactAnalysis(params) {
1135
+ const context = await this.collectQXContext(params.target, params.params?.context);
1136
+ const problemAnalysis = await this.analyzeProblem(context);
1137
+ return this.analyzeImpact(context, problemAnalysis);
1138
+ }
1139
+ /**
1140
+ * Apply specific heuristic
1141
+ */
1142
+ async applySpecificHeuristic(params) {
1143
+ if (!params.params?.heuristic) {
1144
+ throw new Error('Heuristic parameter is required');
1145
+ }
1146
+ const context = await this.collectQXContext(params.target, params.params?.context);
1147
+ const problemAnalysis = await this.analyzeProblem(context);
1148
+ const userNeeds = await this.analyzeUserNeeds(context, problemAnalysis);
1149
+ const businessNeeds = await this.analyzeBusinessNeeds(context, problemAnalysis);
1150
+ if (!this.heuristicsEngine) {
1151
+ throw new Error('Heuristics engine not initialized');
1152
+ }
1153
+ return this.heuristicsEngine.apply(params.params.heuristic, context, problemAnalysis, userNeeds, businessNeeds);
1154
+ }
1155
+ /**
1156
+ * Generate QX recommendations (separate task)
1157
+ */
1158
+ async generateQXRecommendations(params) {
1159
+ const analysis = await this.performFullQXAnalysis(params);
1160
+ return analysis.recommendations;
1161
+ }
1162
+ /**
1163
+ * Integrate with testability scoring
1164
+ */
1165
+ async integrateTestabilityScoring(_params) {
1166
+ if (!this.config.integrateTestability) {
1167
+ return undefined;
1168
+ }
1169
+ this.logger.debug('Integrating with testability scoring');
1170
+ // In real implementation, this would invoke the testability-scoring skill
1171
+ // For now, return a placeholder structure
1172
+ const integration = {
1173
+ qxRelation: [
1174
+ 'Testability affects QX through observability and controllability',
1175
+ 'High testability scores typically correlate with better QX scores'
1176
+ ],
1177
+ combinedInsights: [
1178
+ 'Consider testability principles in QX analysis',
1179
+ 'Low observability impacts both testing and user experience'
1180
+ ]
1181
+ };
1182
+ return integration;
1183
+ }
1184
+ // ============================================================================
1185
+ // Helper Methods
1186
+ // ============================================================================
1187
+ async validateTestabilityScoringAvailability() {
1188
+ this.logger.debug('Validating testability scoring availability');
1189
+ // In real implementation, check if the skill exists and is accessible
1190
+ }
1191
+ async setupCollaborationChannels() {
1192
+ this.logger.debug('Setting up collaboration channels');
1193
+ if (this.config.collaboration?.coordinateWithUX) {
1194
+ this.logger.info('Collaboration with UX agents enabled');
1195
+ }
1196
+ if (this.config.collaboration?.coordinateWithQA) {
1197
+ this.logger.info('Collaboration with QA agents enabled');
1198
+ }
1199
+ }
1200
+ async initializeDefaultOraclePatterns() {
1201
+ const defaultPatterns = {
1202
+ patterns: [
1203
+ 'Revenue vs User Experience conflict',
1204
+ 'Technical constraints vs User expectations',
1205
+ 'Business deadlines vs Quality requirements'
1206
+ ]
1207
+ };
1208
+ await this.storeMemory('oracle-patterns', defaultPatterns);
1209
+ }
1210
+ async saveQXState() {
1211
+ // Save current state for future reference
1212
+ const state = {
1213
+ lastAnalysis: new Date(),
1214
+ analysisCount: this.performanceMetrics.tasksCompleted
1215
+ };
1216
+ await this.storeMemory('qx-state', state);
1217
+ }
1218
+ async saveOraclePatterns() {
1219
+ // Save learned oracle patterns
1220
+ const patterns = await this.retrieveMemory('oracle-patterns');
1221
+ if (patterns) {
1222
+ await this.storeSharedMemory(types_1.QEAgentType.QX_PARTNER, 'oracle-patterns', patterns);
1223
+ }
1224
+ }
1225
+ async saveHeuristicsInsights() {
1226
+ // Save heuristics insights for other agents
1227
+ const insights = await this.retrieveMemory('heuristics-knowledge');
1228
+ if (insights) {
1229
+ await this.storeSharedMemory(types_1.QEAgentType.QX_PARTNER, 'heuristics-insights', insights);
1230
+ }
1231
+ }
1232
+ async shareCollaborationInsights() {
1233
+ if (this.config.collaboration?.shareWithQualityAnalyzer) {
1234
+ const qxInsights = await this.retrieveMemory('qx-state');
1235
+ if (qxInsights) {
1236
+ await this.storeSharedMemory(types_1.QEAgentType.QUALITY_ANALYZER, 'qx-insights', qxInsights);
1237
+ }
1238
+ }
1239
+ }
1240
+ async onPreInitialization() {
1241
+ this.logger.info(`QXPartnerAgent initializing in ${this.config.analysisMode} mode`);
1242
+ }
1243
+ async onPostInitialization() {
1244
+ this.logger.info(`QXPartnerAgent ready for QX analysis`);
1245
+ }
1246
+ }
1247
+ exports.QXPartnerAgent = QXPartnerAgent;
1248
+ // ============================================================================
1249
+ // Helper Classes
1250
+ // ============================================================================
1251
+ /**
1252
+ * QX Heuristics Engine
1253
+ */
1254
+ class QXHeuristicsEngine {
1255
+ constructor(config) {
1256
+ this.config = config;
1257
+ }
1258
+ async applyAll(_context, _problemAnalysis, _userNeeds, _businessNeeds) {
1259
+ const results = [];
1260
+ for (const heuristic of this.config.enabledHeuristics) {
1261
+ const result = await this.apply(heuristic, _context, _problemAnalysis, _userNeeds, _businessNeeds);
1262
+ results.push(result);
1263
+ }
1264
+ return results;
1265
+ }
1266
+ async apply(heuristic, context, problemAnalysis, userNeeds, businessNeeds) {
1267
+ const category = this.getHeuristicCategory(heuristic);
1268
+ const findings = [];
1269
+ const issues = [];
1270
+ const recommendations = [];
1271
+ let score = 75; // Base score
1272
+ // Apply specific heuristic logic based on type
1273
+ switch (heuristic) {
1274
+ case qx_1.QXHeuristic.CONSISTENCY_ANALYSIS:
1275
+ if (context.domMetrics?.semanticStructure?.hasHeader && context.domMetrics?.semanticStructure?.hasFooter) {
1276
+ score = 85;
1277
+ findings.push('Consistent page structure with header and footer');
1278
+ }
1279
+ else {
1280
+ score = 60;
1281
+ recommendations.push('Add consistent header/footer structure');
1282
+ }
1283
+ break;
1284
+ case qx_1.QXHeuristic.INTUITIVE_DESIGN:
1285
+ const hasNav = context.domMetrics?.semanticStructure?.hasNav;
1286
+ const focusable = context.accessibility?.focusableElementsCount || 0;
1287
+ if (hasNav && focusable > 10) {
1288
+ score = 82;
1289
+ findings.push('Intuitive navigation and interaction design');
1290
+ }
1291
+ else {
1292
+ score = 55;
1293
+ issues.push({ description: 'Navigation or interaction patterns unclear', severity: 'medium' });
1294
+ }
1295
+ break;
1296
+ case qx_1.QXHeuristic.EXACTNESS_AND_CLARITY:
1297
+ // Visual hierarchy and clarity (Design category)
1298
+ score = 70;
1299
+ const hasSemanticStructure = context.domMetrics?.semanticStructure;
1300
+ const structureScore = [
1301
+ hasSemanticStructure?.hasHeader,
1302
+ hasSemanticStructure?.hasMain,
1303
+ hasSemanticStructure?.hasNav,
1304
+ hasSemanticStructure?.hasFooter
1305
+ ].filter(Boolean).length;
1306
+ score = 50 + (structureScore * 10);
1307
+ if (structureScore >= 3) {
1308
+ findings.push('Strong visual hierarchy with semantic HTML elements');
1309
+ }
1310
+ else if (structureScore >= 2) {
1311
+ findings.push('Moderate visual hierarchy - some semantic elements present');
1312
+ recommendations.push('Add more semantic HTML5 elements for clarity');
1313
+ }
1314
+ else {
1315
+ issues.push({ description: 'Weak visual hierarchy - missing semantic structure', severity: 'high' });
1316
+ recommendations.push('Implement semantic HTML5: header, nav, main, footer');
1317
+ }
1318
+ // Title and description clarity
1319
+ if (context.metadata?.description && context.metadata.description.length > 20) {
1320
+ score += 10;
1321
+ findings.push('Page has descriptive metadata');
1322
+ }
1323
+ break;
1324
+ case qx_1.QXHeuristic.USER_FEELINGS_IMPACT:
1325
+ // Comprehensive user feelings analysis (Interaction + Accessibility)
1326
+ const altCoverage = context.accessibility?.altTextsCoverage || 0;
1327
+ const loadTime = context.performance?.loadTime || 0;
1328
+ const ariaLabels = context.accessibility?.ariaLabelsCount || 0;
1329
+ const focusableElements = context.accessibility?.focusableElementsCount || 0;
1330
+ score = 60; // Base
1331
+ // Accessibility impact on feelings (35% weight)
1332
+ if (altCoverage >= 90) {
1333
+ score += 20;
1334
+ findings.push('Excellent accessibility (90%+ alt coverage) creates inclusive, positive experience');
1335
+ }
1336
+ else if (altCoverage >= 70) {
1337
+ score += 12;
1338
+ findings.push('Good accessibility creates generally positive user feelings');
1339
+ }
1340
+ else if (altCoverage < 50) {
1341
+ score -= 15;
1342
+ issues.push({ description: 'Poor accessibility (<50% alt coverage) frustrates users with disabilities', severity: 'high' });
1343
+ recommendations.push('Improve alt text coverage to at least 80% for better accessibility');
1344
+ }
1345
+ // ARIA support impact
1346
+ if (ariaLabels > 5) {
1347
+ score += 8;
1348
+ findings.push('Strong ARIA labeling enhances screen reader experience');
1349
+ }
1350
+ // Performance impact on feelings (35% weight)
1351
+ if (loadTime < 1500) {
1352
+ score += 15;
1353
+ findings.push('Very fast load time (<1.5s) delights users');
1354
+ }
1355
+ else if (loadTime < 2500) {
1356
+ score += 8;
1357
+ findings.push('Fast load time enhances user satisfaction');
1358
+ }
1359
+ else if (loadTime > 4000) {
1360
+ score -= 20;
1361
+ issues.push({ description: 'Very slow load time (>4s) causes significant frustration', severity: 'critical' });
1362
+ recommendations.push('Optimize page load time - target under 2.5 seconds');
1363
+ }
1364
+ else if (loadTime > 3000) {
1365
+ score -= 12;
1366
+ issues.push({ description: 'Slow load time causes user frustration', severity: 'high' });
1367
+ }
1368
+ // Error visibility impact (15% weight)
1369
+ if (context.errorIndicators?.hasErrorMessages) {
1370
+ score -= 12;
1371
+ issues.push({ description: 'Visible errors reduce user confidence and satisfaction', severity: 'high' });
1372
+ recommendations.push('Review and fix visible error messages');
1373
+ }
1374
+ // Interaction capability (15% weight)
1375
+ if (focusableElements > 20) {
1376
+ score += 5;
1377
+ findings.push('Rich interactive elements provide user control and engagement');
1378
+ }
1379
+ else if (focusableElements < 5) {
1380
+ score -= 8;
1381
+ issues.push({ description: 'Limited interactivity may feel restrictive', severity: 'medium' });
1382
+ }
1383
+ score = Math.max(20, Math.min(100, score));
1384
+ break;
1385
+ case qx_1.QXHeuristic.GUI_FLOW_IMPACT:
1386
+ const interactiveElements = context.domMetrics?.interactiveElements || 0;
1387
+ const forms = context.domMetrics?.forms || 0;
1388
+ if (interactiveElements > 20) {
1389
+ score = 75;
1390
+ findings.push(`${interactiveElements} interactive elements provide user control`);
1391
+ }
1392
+ if (forms > 0) {
1393
+ findings.push(`${forms} forms impact user input flows`);
1394
+ score = Math.min(100, score + 10);
1395
+ }
1396
+ if (interactiveElements === 0) {
1397
+ score = 30;
1398
+ issues.push({ description: 'Limited user interaction capability', severity: 'high' });
1399
+ }
1400
+ break;
1401
+ case qx_1.QXHeuristic.CROSS_FUNCTIONAL_IMPACT:
1402
+ score = 70;
1403
+ if (context.accessibility && (context.accessibility.altTextsCoverage || 0) < 100) {
1404
+ findings.push('Content team needed for alt text creation');
1405
+ }
1406
+ if (context.performance && (context.performance.loadTime || 0) > 2000) {
1407
+ findings.push('Engineering team needed for performance optimization');
1408
+ }
1409
+ if (problemAnalysis.complexity === 'complex') {
1410
+ findings.push('QA team needed for comprehensive testing');
1411
+ }
1412
+ score = 70 + (findings.length * 5);
1413
+ break;
1414
+ case qx_1.QXHeuristic.DATA_DEPENDENT_IMPACT:
1415
+ if (context.domMetrics?.forms && context.domMetrics.forms > 0) {
1416
+ score = 75;
1417
+ findings.push(`${context.domMetrics.forms} forms depend on backend data processing`);
1418
+ }
1419
+ else {
1420
+ score = 50;
1421
+ findings.push('Limited data-dependent features');
1422
+ }
1423
+ break;
1424
+ case qx_1.QXHeuristic.PROBLEM_UNDERSTANDING:
1425
+ score = problemAnalysis.clarityScore;
1426
+ if (problemAnalysis.clarityScore > 80) {
1427
+ findings.push('Problem is well-defined');
1428
+ }
1429
+ else {
1430
+ issues.push({ description: 'Problem clarity needs improvement', severity: 'medium' });
1431
+ }
1432
+ findings.push(...problemAnalysis.breakdown);
1433
+ break;
1434
+ case qx_1.QXHeuristic.RULE_OF_THREE:
1435
+ score = problemAnalysis.potentialFailures.length >= 3 ? 85 : 60;
1436
+ findings.push(`${problemAnalysis.potentialFailures.length} potential failure modes identified`);
1437
+ if (problemAnalysis.potentialFailures.length < 3) {
1438
+ recommendations.push('Identify at least 3 potential failure modes');
1439
+ }
1440
+ break;
1441
+ case qx_1.QXHeuristic.PROBLEM_COMPLEXITY:
1442
+ score = problemAnalysis.complexity === 'simple' ? 90 :
1443
+ problemAnalysis.complexity === 'moderate' ? 75 : 60;
1444
+ findings.push(`Problem complexity: ${problemAnalysis.complexity}`);
1445
+ break;
1446
+ case qx_1.QXHeuristic.USER_NEEDS_IDENTIFICATION:
1447
+ score = userNeeds.alignmentScore;
1448
+ findings.push(`${userNeeds.needs.length} user needs identified`);
1449
+ const mustHave = userNeeds.needs.filter(n => n.priority === 'must-have').length;
1450
+ findings.push(`${mustHave} must-have features`);
1451
+ if (userNeeds.challenges.length > 0) {
1452
+ issues.push({ description: `${userNeeds.challenges.length} user need challenges found`, severity: 'medium' });
1453
+ }
1454
+ break;
1455
+ case qx_1.QXHeuristic.USER_NEEDS_SUITABILITY:
1456
+ score = userNeeds.suitability === 'excellent' ? 95 :
1457
+ userNeeds.suitability === 'good' ? 80 :
1458
+ userNeeds.suitability === 'adequate' ? 65 : 45;
1459
+ findings.push(`User needs suitability: ${userNeeds.suitability}`);
1460
+ break;
1461
+ case qx_1.QXHeuristic.USER_NEEDS_VALIDATION:
1462
+ const addressedNeeds = userNeeds.needs.filter(n => n.addressed).length;
1463
+ score = userNeeds.needs.length > 0 ? (addressedNeeds / userNeeds.needs.length) * 100 : 50;
1464
+ findings.push(`${addressedNeeds}/${userNeeds.needs.length} needs validated and addressed`);
1465
+ break;
1466
+ case qx_1.QXHeuristic.BUSINESS_NEEDS_IDENTIFICATION:
1467
+ score = businessNeeds.alignmentScore;
1468
+ findings.push(`Primary goal: ${businessNeeds.primaryGoal}`);
1469
+ findings.push(`${businessNeeds.kpisAffected.length} KPIs affected`);
1470
+ findings.push(`${businessNeeds.crossTeamImpact.length} cross-team impacts`);
1471
+ break;
1472
+ case qx_1.QXHeuristic.USER_VS_BUSINESS_BALANCE:
1473
+ const balanceScore = 100 - Math.abs(userNeeds.alignmentScore - businessNeeds.alignmentScore);
1474
+ score = balanceScore;
1475
+ if (balanceScore > 80) {
1476
+ findings.push('Good balance between user and business needs');
1477
+ }
1478
+ else {
1479
+ issues.push({ description: 'Imbalance between user and business priorities', severity: 'medium' });
1480
+ recommendations.push('Align user and business objectives more closely');
1481
+ }
1482
+ break;
1483
+ case qx_1.QXHeuristic.KPI_IMPACT_ANALYSIS:
1484
+ score = businessNeeds.impactsKPIs ? 85 : 50;
1485
+ findings.push(`KPIs impacted: ${businessNeeds.kpisAffected.join(', ')}`);
1486
+ if (businessNeeds.compromisesUX) {
1487
+ issues.push({ description: 'Business ease compromises user experience', severity: 'high' });
1488
+ score -= 20;
1489
+ }
1490
+ break;
1491
+ case qx_1.QXHeuristic.ORACLE_PROBLEM_DETECTION:
1492
+ // This is handled separately, score based on whether we can detect issues
1493
+ score = 75;
1494
+ findings.push('Oracle problem detection capability active');
1495
+ break;
1496
+ case qx_1.QXHeuristic.WHAT_MUST_NOT_CHANGE:
1497
+ score = 80;
1498
+ if (context.domMetrics?.semanticStructure?.hasMain) {
1499
+ findings.push('Main content structure is immutable');
1500
+ }
1501
+ if (context.accessibility && (context.accessibility.focusableElementsCount || 0) > 0) {
1502
+ findings.push('Keyboard navigation support must be maintained');
1503
+ }
1504
+ break;
1505
+ case qx_1.QXHeuristic.SUPPORTING_DATA_ANALYSIS:
1506
+ score = 75;
1507
+ const hasData = (context.domMetrics?.forms || 0) > 0 || (context.domMetrics?.interactiveElements || 0) > 20;
1508
+ if (hasData) {
1509
+ score = 82;
1510
+ findings.push('Sufficient data points for informed decision-making');
1511
+ }
1512
+ else {
1513
+ score = 60;
1514
+ issues.push({ description: 'Limited data for comprehensive analysis', severity: 'medium' });
1515
+ recommendations.push('Collect more user interaction data');
1516
+ }
1517
+ break;
1518
+ case qx_1.QXHeuristic.COMPETITIVE_ANALYSIS:
1519
+ score = 70; // Baseline - actual comparison would need competitor data
1520
+ findings.push('Competitive analysis capability available');
1521
+ if (context.domMetrics?.semanticStructure?.hasNav && context.domMetrics?.interactiveElements && context.domMetrics.interactiveElements > 15) {
1522
+ score = 78;
1523
+ findings.push('Navigation and interaction patterns follow industry standards');
1524
+ }
1525
+ else {
1526
+ recommendations.push('Compare interaction patterns with leading competitors');
1527
+ }
1528
+ break;
1529
+ case qx_1.QXHeuristic.DOMAIN_INSPIRATION:
1530
+ score = 72;
1531
+ const hasModernElements = context.accessibility && (context.accessibility.ariaLabelsCount || 0) > 0;
1532
+ if (hasModernElements) {
1533
+ score = 80;
1534
+ findings.push('Modern accessibility patterns show domain inspiration');
1535
+ }
1536
+ else {
1537
+ recommendations.push('Research domain-specific design patterns and best practices');
1538
+ }
1539
+ break;
1540
+ case qx_1.QXHeuristic.INNOVATIVE_SOLUTIONS:
1541
+ score = 65; // Most sites are conventional
1542
+ const hasAdvancedFeatures = (context.accessibility?.landmarkRoles || 0) > 3;
1543
+ if (hasAdvancedFeatures) {
1544
+ score = 75;
1545
+ findings.push('Advanced accessibility features show innovative thinking');
1546
+ }
1547
+ else {
1548
+ recommendations.push('Explore innovative UX patterns to differentiate experience');
1549
+ }
1550
+ break;
1551
+ case qx_1.QXHeuristic.COUNTER_INTUITIVE_DESIGN:
1552
+ score = 85; // High score means few counter-intuitive elements (good)
1553
+ const confusingNav = !context.domMetrics?.semanticStructure?.hasNav && (context.domMetrics?.interactiveElements || 0) > 10;
1554
+ const poorStructure = !context.domMetrics?.semanticStructure?.hasHeader && !context.domMetrics?.semanticStructure?.hasFooter;
1555
+ if (confusingNav) {
1556
+ score = 45;
1557
+ issues.push({ description: 'Navigation structure may be counter-intuitive', severity: 'high' });
1558
+ recommendations.push('Add semantic navigation elements');
1559
+ }
1560
+ if (poorStructure) {
1561
+ score -= 15;
1562
+ issues.push({ description: 'Page structure lacks expected header/footer', severity: 'medium' });
1563
+ }
1564
+ if (score > 75) {
1565
+ findings.push('No counter-intuitive design patterns detected');
1566
+ }
1567
+ break;
1568
+ case qx_1.QXHeuristic.SUPPORTING_DATA_ANALYSIS:
1569
+ score = 70;
1570
+ if (context.performance)
1571
+ findings.push('Performance data available');
1572
+ if (context.accessibility)
1573
+ findings.push('Accessibility metrics available');
1574
+ if (context.domMetrics)
1575
+ findings.push('DOM structure data available');
1576
+ score = 60 + (findings.length * 10);
1577
+ break;
1578
+ case qx_1.QXHeuristic.COMPETITIVE_ANALYSIS:
1579
+ score = 65;
1580
+ findings.push('Competitive analysis capability available');
1581
+ recommendations.push('Compare with competitor sites for benchmarking');
1582
+ break;
1583
+ case qx_1.QXHeuristic.DOMAIN_INSPIRATION:
1584
+ score = 70;
1585
+ findings.push('Consider best practices from similar domains');
1586
+ break;
1587
+ case qx_1.QXHeuristic.INNOVATIVE_SOLUTIONS:
1588
+ score = 68;
1589
+ findings.push('Opportunity for innovative UX solutions');
1590
+ break;
1591
+ case qx_1.QXHeuristic.COUNTER_INTUITIVE_DESIGN:
1592
+ score = 75;
1593
+ findings.push('No counter-intuitive design patterns detected');
1594
+ break;
1595
+ default:
1596
+ // Generic heuristic evaluation based on category
1597
+ if (category === 'user-needs') {
1598
+ score = userNeeds.alignmentScore;
1599
+ }
1600
+ else if (category === 'business-needs') {
1601
+ score = businessNeeds.alignmentScore;
1602
+ }
1603
+ else if (category === 'problem') {
1604
+ score = problemAnalysis.clarityScore;
1605
+ }
1606
+ break;
1607
+ }
1608
+ return {
1609
+ name: heuristic,
1610
+ heuristicType: heuristic,
1611
+ category,
1612
+ applied: true,
1613
+ score: Math.min(100, Math.max(0, score)),
1614
+ findings,
1615
+ issues,
1616
+ recommendations
1617
+ };
1618
+ }
1619
+ getHeuristicCategory(heuristic) {
1620
+ if (heuristic.includes('problem'))
1621
+ return 'problem';
1622
+ if (heuristic.includes('user'))
1623
+ return 'user-needs';
1624
+ if (heuristic.includes('business'))
1625
+ return 'business-needs';
1626
+ if (heuristic.includes('oracle') || heuristic.includes('balance'))
1627
+ return 'balance';
1628
+ if (heuristic.includes('impact'))
1629
+ return 'impact';
1630
+ if (heuristic.includes('competitive') || heuristic.includes('inspiration'))
1631
+ return 'creativity';
1632
+ return 'design';
1633
+ }
1634
+ }
1635
+ /**
1636
+ * Oracle Problem Detector
1637
+ */
1638
+ class OracleDetector {
1639
+ constructor(minSeverity) {
1640
+ this.minSeverity = minSeverity;
1641
+ }
1642
+ detect(context, userNeeds, businessNeeds) {
1643
+ const problems = [];
1644
+ // Check for user vs business conflicts
1645
+ if (Math.abs(userNeeds.alignmentScore - businessNeeds.alignmentScore) > 20) {
1646
+ problems.push({
1647
+ type: 'user-vs-business',
1648
+ description: 'Significant gap between user needs and business objectives',
1649
+ severity: 'high',
1650
+ stakeholders: ['Users', 'Business'],
1651
+ resolutionApproach: [
1652
+ 'Gather supporting data from both perspectives',
1653
+ 'Facilitate discussion between stakeholders',
1654
+ 'Find compromise solutions that address both needs'
1655
+ ]
1656
+ });
1657
+ }
1658
+ // Check for missing information
1659
+ if (userNeeds.challenges.length > 0 || businessNeeds.compromisesUX) {
1660
+ problems.push({
1661
+ type: 'unclear-criteria',
1662
+ description: 'Quality criteria unclear due to conflicting information',
1663
+ severity: 'medium',
1664
+ missingInfo: userNeeds.challenges,
1665
+ resolutionApproach: [
1666
+ 'Collect missing information from stakeholders',
1667
+ 'Define clear acceptance criteria'
1668
+ ]
1669
+ });
1670
+ }
1671
+ // ENHANCED: Detect contextual oracle problems even for well-built sites
1672
+ const titleLower = (context.title || '').toLowerCase();
1673
+ const descLower = (context.metadata?.description || '').toLowerCase();
1674
+ // E-commerce/Travel booking: Conversion vs UX quality
1675
+ if (titleLower.includes('hotel') || titleLower.includes('booking') || titleLower.includes('travel') ||
1676
+ titleLower.includes('shop') || titleLower.includes('store') || descLower.includes('book')) {
1677
+ if (businessNeeds.kpisAffected.some(k => k.toLowerCase().includes('conversion') || k.toLowerCase().includes('engagement'))) {
1678
+ problems.push({
1679
+ type: 'user-vs-business',
1680
+ description: 'Potential conflict between conversion optimization (business) and user experience quality (user trust)',
1681
+ severity: 'medium',
1682
+ stakeholders: ['Marketing', 'Product', 'Users'],
1683
+ resolutionApproach: [
1684
+ 'A/B test aggressive vs. subtle conversion tactics',
1685
+ 'Measure both conversion rate and user satisfaction metrics',
1686
+ 'Balance urgency messaging with transparent communication'
1687
+ ]
1688
+ });
1689
+ }
1690
+ // Price transparency oracle
1691
+ problems.push({
1692
+ type: 'unclear-criteria',
1693
+ description: 'Unclear criteria for price display timing - when to show fees, taxes, and final price',
1694
+ severity: 'medium',
1695
+ stakeholders: ['Users', 'Legal', 'Business'],
1696
+ resolutionApproach: [
1697
+ 'Define regulatory compliance requirements for price display',
1698
+ 'Balance business desire for competitive base pricing vs user need for full price transparency',
1699
+ 'Establish clear standards for fee disclosure timing'
1700
+ ]
1701
+ });
1702
+ }
1703
+ // Content sites: Quality vs. Quantity
1704
+ if (titleLower.includes('blog') || titleLower.includes('article') || titleLower.includes('news') ||
1705
+ titleLower.includes('magazine') || titleLower.includes('testing')) {
1706
+ problems.push({
1707
+ type: 'user-vs-business',
1708
+ description: 'Content depth (user need) vs. publication frequency (business engagement goals) trade-off',
1709
+ severity: 'low',
1710
+ stakeholders: ['Readers', 'Content Team', 'Editorial'],
1711
+ resolutionApproach: [
1712
+ 'Define content quality standards and acceptance criteria',
1713
+ 'Balance editorial calendar with quality thresholds',
1714
+ 'Consider mix of in-depth and quick-read content formats'
1715
+ ]
1716
+ });
1717
+ }
1718
+ // Complex sites: Technical constraints
1719
+ if ((context.domMetrics?.totalElements || 0) > 500 || (context.domMetrics?.interactiveElements || 0) > 50) {
1720
+ problems.push({
1721
+ type: 'technical-constraint',
1722
+ description: 'Platform technical limitations may restrict advanced UX features or accessibility enhancements',
1723
+ severity: 'low',
1724
+ stakeholders: ['Development', 'Product', 'Users'],
1725
+ resolutionApproach: [
1726
+ 'Evaluate platform capabilities and constraints',
1727
+ 'Prioritize features based on user impact vs. implementation complexity',
1728
+ 'Consider gradual enhancement approach'
1729
+ ]
1730
+ });
1731
+ }
1732
+ return problems.filter(p => this.meetsMinimumSeverity(p.severity));
1733
+ }
1734
+ meetsMinimumSeverity(severity) {
1735
+ const severityLevels = ['low', 'medium', 'high', 'critical'];
1736
+ const minIndex = severityLevels.indexOf(this.minSeverity);
1737
+ const currentIndex = severityLevels.indexOf(severity);
1738
+ return currentIndex >= minIndex;
1739
+ }
1740
+ }
1741
+ /**
1742
+ * Impact Analyzer
1743
+ */
1744
+ class ImpactAnalyzer {
1745
+ async analyze(context, problemAnalysis) {
1746
+ const guiFlowEndUser = [];
1747
+ const guiFlowInternal = [];
1748
+ const userFeelings = [];
1749
+ const performance = [];
1750
+ const security = [];
1751
+ const immutableRequirements = [];
1752
+ // Analyze visible impacts
1753
+ const interactiveElements = context.domMetrics?.interactiveElements || 0;
1754
+ const forms = context.domMetrics?.forms || 0;
1755
+ if (interactiveElements > 0) {
1756
+ guiFlowEndUser.push(`${interactiveElements} interactive elements affect user journey`);
1757
+ }
1758
+ if (forms > 0) {
1759
+ guiFlowEndUser.push(`${forms} forms impact user input flows`);
1760
+ }
1761
+ // User feelings based on quality metrics
1762
+ const altCoverage = context.accessibility?.altTextsCoverage || 0;
1763
+ if (altCoverage > 80) {
1764
+ userFeelings.push('Positive - Good accessibility creates inclusive experience');
1765
+ }
1766
+ else if (altCoverage < 50) {
1767
+ userFeelings.push('Frustrated - Poor accessibility excludes some users');
1768
+ }
1769
+ const loadTime = context.performance?.loadTime || 0;
1770
+ if (loadTime > 3000) {
1771
+ userFeelings.push('Impatient - Slow load time causes frustration');
1772
+ }
1773
+ else if (loadTime < 2000) {
1774
+ userFeelings.push('Satisfied - Fast load time enhances experience');
1775
+ }
1776
+ if (context.errorIndicators?.hasErrorMessages) {
1777
+ userFeelings.push('Confused - Visible errors reduce confidence');
1778
+ }
1779
+ // Analyze invisible impacts
1780
+ if (loadTime > 2000) {
1781
+ performance.push(`Load time ${loadTime}ms impacts user retention`);
1782
+ }
1783
+ if (!context.metadata?.viewport) {
1784
+ performance.push('Missing viewport tag affects mobile performance');
1785
+ }
1786
+ // Immutable requirements
1787
+ if (context.domMetrics?.semanticStructure?.hasMain) {
1788
+ immutableRequirements.push('Must maintain main content accessibility');
1789
+ }
1790
+ if (context.accessibility && (context.accessibility.focusableElementsCount || 0) > 0) {
1791
+ immutableRequirements.push('Must support keyboard navigation');
1792
+ }
1793
+ if (problemAnalysis.complexity === 'complex') {
1794
+ immutableRequirements.push('Must maintain system stability with complex interactions');
1795
+ }
1796
+ // Calculate impact scores
1797
+ let visibleScore = 50;
1798
+ if (guiFlowEndUser.length > 0)
1799
+ visibleScore += 15;
1800
+ if (userFeelings.some(f => f.includes('Positive') || f.includes('Satisfied')))
1801
+ visibleScore += 20;
1802
+ if (userFeelings.some(f => f.includes('Frustrated') || f.includes('Confused')))
1803
+ visibleScore -= 15;
1804
+ visibleScore = Math.max(0, Math.min(100, visibleScore));
1805
+ let invisibleScore = 50;
1806
+ if (performance.length === 0)
1807
+ invisibleScore += 20;
1808
+ if (security.length === 0)
1809
+ invisibleScore += 10;
1810
+ invisibleScore = Math.max(0, Math.min(100, invisibleScore));
1811
+ const overallImpactScore = Math.round((visibleScore + invisibleScore) / 2);
1812
+ return {
1813
+ visible: {
1814
+ guiFlow: {
1815
+ forEndUser: guiFlowEndUser,
1816
+ forInternalUser: guiFlowInternal
1817
+ },
1818
+ userFeelings,
1819
+ score: visibleScore
1820
+ },
1821
+ invisible: {
1822
+ performance,
1823
+ security,
1824
+ score: invisibleScore
1825
+ },
1826
+ immutableRequirements,
1827
+ overallImpactScore
1828
+ };
1829
+ }
1830
+ }
1831
+ //# sourceMappingURL=QXPartnerAgent.js.map