qa360 1.4.5 → 2.0.1

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 (209) hide show
  1. package/README.md +1 -1
  2. package/dist/commands/ai.d.ts +41 -0
  3. package/dist/commands/ai.js +499 -0
  4. package/dist/commands/ask.js +12 -12
  5. package/dist/commands/coverage.d.ts +8 -0
  6. package/dist/commands/coverage.js +252 -0
  7. package/dist/commands/explain.d.ts +27 -0
  8. package/dist/commands/explain.js +630 -0
  9. package/dist/commands/flakiness.d.ts +73 -0
  10. package/dist/commands/flakiness.js +435 -0
  11. package/dist/commands/generate.d.ts +66 -0
  12. package/dist/commands/generate.js +438 -0
  13. package/dist/commands/init.d.ts +56 -9
  14. package/dist/commands/init.js +217 -10
  15. package/dist/commands/monitor.d.ts +27 -0
  16. package/dist/commands/monitor.js +225 -0
  17. package/dist/commands/ollama.d.ts +40 -0
  18. package/dist/commands/ollama.js +301 -0
  19. package/dist/commands/pack.d.ts +37 -9
  20. package/dist/commands/pack.js +240 -141
  21. package/dist/commands/regression.d.ts +8 -0
  22. package/dist/commands/regression.js +340 -0
  23. package/dist/commands/repair.d.ts +26 -0
  24. package/dist/commands/repair.js +307 -0
  25. package/dist/commands/retry.d.ts +43 -0
  26. package/dist/commands/retry.js +275 -0
  27. package/dist/commands/run.d.ts +8 -3
  28. package/dist/commands/run.js +45 -31
  29. package/dist/commands/slo.d.ts +8 -0
  30. package/dist/commands/slo.js +327 -0
  31. package/dist/core/adapters/playwright-native-api.d.ts +183 -0
  32. package/dist/core/adapters/playwright-native-api.js +461 -0
  33. package/dist/core/adapters/playwright-ui.d.ts +7 -0
  34. package/dist/core/adapters/playwright-ui.js +29 -1
  35. package/dist/core/ai/anthropic-provider.d.ts +50 -0
  36. package/dist/core/ai/anthropic-provider.js +211 -0
  37. package/dist/core/ai/deepseek-provider.d.ts +81 -0
  38. package/dist/core/ai/deepseek-provider.js +254 -0
  39. package/dist/core/ai/index.d.ts +60 -0
  40. package/dist/core/ai/index.js +18 -0
  41. package/dist/core/ai/llm-client.d.ts +45 -0
  42. package/dist/core/ai/llm-client.js +7 -0
  43. package/dist/core/ai/mock-provider.d.ts +49 -0
  44. package/dist/core/ai/mock-provider.js +121 -0
  45. package/dist/core/ai/ollama-provider.d.ts +78 -0
  46. package/dist/core/ai/ollama-provider.js +192 -0
  47. package/dist/core/ai/openai-provider.d.ts +48 -0
  48. package/dist/core/ai/openai-provider.js +188 -0
  49. package/dist/core/ai/provider-factory.d.ts +160 -0
  50. package/dist/core/ai/provider-factory.js +269 -0
  51. package/dist/core/auth/api-key-provider.d.ts +16 -0
  52. package/dist/core/auth/api-key-provider.js +63 -0
  53. package/dist/core/auth/aws-iam-provider.d.ts +35 -0
  54. package/dist/core/auth/aws-iam-provider.js +177 -0
  55. package/dist/core/auth/azure-ad-provider.d.ts +15 -0
  56. package/dist/core/auth/azure-ad-provider.js +99 -0
  57. package/dist/core/auth/basic-auth-provider.d.ts +26 -0
  58. package/dist/core/auth/basic-auth-provider.js +111 -0
  59. package/dist/core/auth/gcp-adc-provider.d.ts +27 -0
  60. package/dist/core/auth/gcp-adc-provider.js +126 -0
  61. package/dist/core/auth/index.d.ts +238 -0
  62. package/dist/core/auth/index.js +82 -0
  63. package/dist/core/auth/jwt-provider.d.ts +19 -0
  64. package/dist/core/auth/jwt-provider.js +160 -0
  65. package/dist/core/auth/manager.d.ts +84 -0
  66. package/dist/core/auth/manager.js +230 -0
  67. package/dist/core/auth/oauth2-provider.d.ts +17 -0
  68. package/dist/core/auth/oauth2-provider.js +114 -0
  69. package/dist/core/auth/totp-provider.d.ts +31 -0
  70. package/dist/core/auth/totp-provider.js +134 -0
  71. package/dist/core/auth/ui-login-provider.d.ts +26 -0
  72. package/dist/core/auth/ui-login-provider.js +198 -0
  73. package/dist/core/cache/index.d.ts +7 -0
  74. package/dist/core/cache/index.js +6 -0
  75. package/dist/core/cache/lru-cache.d.ts +203 -0
  76. package/dist/core/cache/lru-cache.js +397 -0
  77. package/dist/core/coverage/analyzer.d.ts +101 -0
  78. package/dist/core/coverage/analyzer.js +415 -0
  79. package/dist/core/coverage/collector.d.ts +74 -0
  80. package/dist/core/coverage/collector.js +459 -0
  81. package/dist/core/coverage/config.d.ts +37 -0
  82. package/dist/core/coverage/config.js +156 -0
  83. package/dist/core/coverage/index.d.ts +11 -0
  84. package/dist/core/coverage/index.js +15 -0
  85. package/dist/core/coverage/types.d.ts +267 -0
  86. package/dist/core/coverage/types.js +6 -0
  87. package/dist/core/coverage/vault.d.ts +95 -0
  88. package/dist/core/coverage/vault.js +405 -0
  89. package/dist/core/dashboard/assets.d.ts +6 -0
  90. package/dist/core/dashboard/assets.js +690 -0
  91. package/dist/core/dashboard/index.d.ts +6 -0
  92. package/dist/core/dashboard/index.js +5 -0
  93. package/dist/core/dashboard/server.d.ts +72 -0
  94. package/dist/core/dashboard/server.js +354 -0
  95. package/dist/core/dashboard/types.d.ts +70 -0
  96. package/dist/core/dashboard/types.js +5 -0
  97. package/dist/core/discoverer/index.d.ts +115 -0
  98. package/dist/core/discoverer/index.js +250 -0
  99. package/dist/core/flakiness/index.d.ts +228 -0
  100. package/dist/core/flakiness/index.js +384 -0
  101. package/dist/core/generation/code-formatter.d.ts +111 -0
  102. package/dist/core/generation/code-formatter.js +307 -0
  103. package/dist/core/generation/code-generator.d.ts +144 -0
  104. package/dist/core/generation/code-generator.js +293 -0
  105. package/dist/core/generation/generator.d.ts +40 -0
  106. package/dist/core/generation/generator.js +76 -0
  107. package/dist/core/generation/index.d.ts +30 -0
  108. package/dist/core/generation/index.js +28 -0
  109. package/dist/core/generation/pack-generator.d.ts +107 -0
  110. package/dist/core/generation/pack-generator.js +416 -0
  111. package/dist/core/generation/prompt-builder.d.ts +132 -0
  112. package/dist/core/generation/prompt-builder.js +672 -0
  113. package/dist/core/generation/source-analyzer.d.ts +213 -0
  114. package/dist/core/generation/source-analyzer.js +657 -0
  115. package/dist/core/generation/test-optimizer.d.ts +117 -0
  116. package/dist/core/generation/test-optimizer.js +328 -0
  117. package/dist/core/generation/types.d.ts +214 -0
  118. package/dist/core/generation/types.js +4 -0
  119. package/dist/core/index.d.ts +23 -1
  120. package/dist/core/index.js +39 -0
  121. package/dist/core/pack/validator.js +31 -1
  122. package/dist/core/pack-v2/index.d.ts +9 -0
  123. package/dist/core/pack-v2/index.js +8 -0
  124. package/dist/core/pack-v2/loader.d.ts +62 -0
  125. package/dist/core/pack-v2/loader.js +231 -0
  126. package/dist/core/pack-v2/migrator.d.ts +56 -0
  127. package/dist/core/pack-v2/migrator.js +455 -0
  128. package/dist/core/pack-v2/validator.d.ts +61 -0
  129. package/dist/core/pack-v2/validator.js +577 -0
  130. package/dist/core/regression/detector.d.ts +107 -0
  131. package/dist/core/regression/detector.js +497 -0
  132. package/dist/core/regression/index.d.ts +9 -0
  133. package/dist/core/regression/index.js +11 -0
  134. package/dist/core/regression/trend-analyzer.d.ts +102 -0
  135. package/dist/core/regression/trend-analyzer.js +345 -0
  136. package/dist/core/regression/types.d.ts +222 -0
  137. package/dist/core/regression/types.js +7 -0
  138. package/dist/core/regression/vault.d.ts +87 -0
  139. package/dist/core/regression/vault.js +289 -0
  140. package/dist/core/repair/engine/fixer.d.ts +24 -0
  141. package/dist/core/repair/engine/fixer.js +226 -0
  142. package/dist/core/repair/engine/suggestion-engine.d.ts +18 -0
  143. package/dist/core/repair/engine/suggestion-engine.js +187 -0
  144. package/dist/core/repair/index.d.ts +10 -0
  145. package/dist/core/repair/index.js +13 -0
  146. package/dist/core/repair/repairer.d.ts +90 -0
  147. package/dist/core/repair/repairer.js +284 -0
  148. package/dist/core/repair/types.d.ts +91 -0
  149. package/dist/core/repair/types.js +6 -0
  150. package/dist/core/repair/utils/error-analyzer.d.ts +28 -0
  151. package/dist/core/repair/utils/error-analyzer.js +264 -0
  152. package/dist/core/retry/flakiness-integration.d.ts +60 -0
  153. package/dist/core/retry/flakiness-integration.js +228 -0
  154. package/dist/core/retry/index.d.ts +14 -0
  155. package/dist/core/retry/index.js +16 -0
  156. package/dist/core/retry/retry-engine.d.ts +80 -0
  157. package/dist/core/retry/retry-engine.js +296 -0
  158. package/dist/core/retry/types.d.ts +178 -0
  159. package/dist/core/retry/types.js +52 -0
  160. package/dist/core/retry/vault.d.ts +77 -0
  161. package/dist/core/retry/vault.js +304 -0
  162. package/dist/core/runner/e2e-helpers.d.ts +102 -0
  163. package/dist/core/runner/e2e-helpers.js +153 -0
  164. package/dist/core/runner/phase3-runner.d.ts +101 -2
  165. package/dist/core/runner/phase3-runner.js +559 -24
  166. package/dist/core/self-healing/assertion-healer.d.ts +97 -0
  167. package/dist/core/self-healing/assertion-healer.js +371 -0
  168. package/dist/core/self-healing/engine.d.ts +122 -0
  169. package/dist/core/self-healing/engine.js +538 -0
  170. package/dist/core/self-healing/index.d.ts +10 -0
  171. package/dist/core/self-healing/index.js +11 -0
  172. package/dist/core/self-healing/selector-healer.d.ts +103 -0
  173. package/dist/core/self-healing/selector-healer.js +372 -0
  174. package/dist/core/self-healing/types.d.ts +152 -0
  175. package/dist/core/self-healing/types.js +6 -0
  176. package/dist/core/slo/config.d.ts +107 -0
  177. package/dist/core/slo/config.js +360 -0
  178. package/dist/core/slo/index.d.ts +11 -0
  179. package/dist/core/slo/index.js +15 -0
  180. package/dist/core/slo/sli-calculator.d.ts +92 -0
  181. package/dist/core/slo/sli-calculator.js +364 -0
  182. package/dist/core/slo/slo-tracker.d.ts +148 -0
  183. package/dist/core/slo/slo-tracker.js +379 -0
  184. package/dist/core/slo/types.d.ts +281 -0
  185. package/dist/core/slo/types.js +7 -0
  186. package/dist/core/slo/vault.d.ts +102 -0
  187. package/dist/core/slo/vault.js +427 -0
  188. package/dist/core/tui/index.d.ts +7 -0
  189. package/dist/core/tui/index.js +6 -0
  190. package/dist/core/tui/monitor.d.ts +92 -0
  191. package/dist/core/tui/monitor.js +271 -0
  192. package/dist/core/tui/renderer.d.ts +33 -0
  193. package/dist/core/tui/renderer.js +218 -0
  194. package/dist/core/tui/types.d.ts +63 -0
  195. package/dist/core/tui/types.js +5 -0
  196. package/dist/core/types/pack-v2.d.ts +425 -0
  197. package/dist/core/types/pack-v2.js +8 -0
  198. package/dist/core/vault/index.d.ts +116 -0
  199. package/dist/core/vault/index.js +400 -5
  200. package/dist/core/watch/index.d.ts +7 -0
  201. package/dist/core/watch/index.js +6 -0
  202. package/dist/core/watch/watch-mode.d.ts +213 -0
  203. package/dist/core/watch/watch-mode.js +389 -0
  204. package/dist/index.js +68 -68
  205. package/dist/utils/config.d.ts +5 -0
  206. package/dist/utils/config.js +136 -0
  207. package/package.json +5 -1
  208. package/dist/core/adapters/playwright-api.d.ts +0 -82
  209. package/dist/core/adapters/playwright-api.js +0 -264
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Smart Retry Engine
3
+ *
4
+ * Core retry logic with multiple strategies and adaptive behavior.
5
+ */
6
+ import { DEFAULT_RETRY_CONFIG, RetryStrategy } from './types.js';
7
+ /**
8
+ * Smart Retry Engine
9
+ */
10
+ export class SmartRetryEngine {
11
+ config;
12
+ constructor(config = {}) {
13
+ this.config = { ...DEFAULT_RETRY_CONFIG, ...config };
14
+ }
15
+ /**
16
+ * Execute a test with retry logic
17
+ */
18
+ async executeWithRetry(testId, executor, context) {
19
+ const startTime = Date.now();
20
+ const attempts = [];
21
+ let lastError;
22
+ let stopReason = 'max_retries';
23
+ // Adjust strategy based on flakiness if adaptive
24
+ const effectiveStrategy = this.getEffectiveStrategy(this.config.strategy, context?.flakinessScore, context?.patternType);
25
+ for (let attempt = 1; attempt <= this.config.maxRetries + 1; attempt++) {
26
+ // Calculate delay before this attempt
27
+ const delayMs = attempt === 1 ? 0 : this.calculateDelay(attempt, effectiveStrategy);
28
+ // Apply delay if not first attempt
29
+ if (delayMs > 0) {
30
+ await this.delay(delayMs);
31
+ }
32
+ const attemptStartTime = Date.now();
33
+ let attemptSuccess = false;
34
+ let errorType;
35
+ let errorMessage;
36
+ let shouldStop = false;
37
+ try {
38
+ await executor();
39
+ attemptSuccess = true;
40
+ stopReason = 'success';
41
+ }
42
+ catch (error) {
43
+ const err = error;
44
+ errorType = err.constructor?.name || 'Error';
45
+ errorMessage = err.message;
46
+ // Check if error is non-retriable
47
+ if (this.isNonRetriableError(errorType, errorMessage)) {
48
+ stopReason = 'unrecoverable';
49
+ lastError = err;
50
+ shouldStop = true;
51
+ }
52
+ // Check if we should retry on assertion failure
53
+ if (!shouldStop && !this.config.retryOnAssertionFailure && this.isAssertionError(errorType, errorMessage)) {
54
+ stopReason = 'unrecoverable';
55
+ lastError = err;
56
+ shouldStop = true;
57
+ }
58
+ // Check if we should retry on timeout
59
+ if (!shouldStop && !this.config.retryOnTimeout && this.isTimeoutError(errorType, errorMessage)) {
60
+ stopReason = 'unrecoverable';
61
+ lastError = err;
62
+ shouldStop = true;
63
+ }
64
+ if (!shouldStop) {
65
+ lastError = err;
66
+ }
67
+ }
68
+ const attemptDuration = Date.now() - attemptStartTime;
69
+ // Always record the attempt
70
+ attempts.push({
71
+ attemptNumber: attempt,
72
+ success: attemptSuccess,
73
+ durationMs: attemptDuration,
74
+ errorType,
75
+ errorMessage,
76
+ delayMs,
77
+ timestamp: attemptStartTime
78
+ });
79
+ if (attemptSuccess || shouldStop) {
80
+ break;
81
+ }
82
+ // Check overall timeout
83
+ if (this.config.overallTimeoutMs) {
84
+ const elapsed = Date.now() - startTime;
85
+ if (elapsed + this.config.maxDelayMs > this.config.overallTimeoutMs) {
86
+ stopReason = 'timeout';
87
+ break;
88
+ }
89
+ }
90
+ }
91
+ const totalDuration = Date.now() - startTime;
92
+ const success = attempts.some(a => a.success);
93
+ const successfulAttempt = attempts.find(a => a.success)?.attemptNumber;
94
+ return {
95
+ testId,
96
+ success,
97
+ totalAttempts: attempts.length,
98
+ successfulAttempt,
99
+ attempts,
100
+ totalDurationMs: totalDuration,
101
+ strategy: effectiveStrategy,
102
+ stopReason
103
+ };
104
+ }
105
+ /**
106
+ * Get retry recommendation based on flakiness and pattern
107
+ */
108
+ getRetryRecommendation(params) {
109
+ const { flakinessScore = 100, patternType, errorType, errorCount = 1, recentAttempts = 0 } = params;
110
+ // Non-retriable errors should not be retried
111
+ if (errorType && this.isNonRetriableError(errorType)) {
112
+ return {
113
+ shouldRetry: false,
114
+ strategy: RetryStrategy.NONE,
115
+ maxRetries: 0,
116
+ initialDelayMs: 0,
117
+ confidence: 0.95,
118
+ reason: `Error type "${errorType}" is not retriable`
119
+ };
120
+ }
121
+ // High flakiness score (reliable tests) -> fewer retries
122
+ if (flakinessScore >= 90) {
123
+ return {
124
+ shouldRetry: false,
125
+ strategy: RetryStrategy.NONE,
126
+ maxRetries: 0,
127
+ initialDelayMs: 0,
128
+ confidence: 0.9,
129
+ reason: 'Test is highly reliable (Legendary/Solid), retry not recommended'
130
+ };
131
+ }
132
+ // Medium flakiness -> conservative retry
133
+ if (flakinessScore >= 75) {
134
+ return {
135
+ shouldRetry: true,
136
+ strategy: RetryStrategy.FIXED,
137
+ maxRetries: 2,
138
+ initialDelayMs: 1000,
139
+ confidence: 0.75,
140
+ reason: 'Test is occasionally flaky (Good), conservative retry recommended'
141
+ };
142
+ }
143
+ // Low flakiness -> adaptive retry
144
+ if (flakinessScore >= 50) {
145
+ return {
146
+ shouldRetry: true,
147
+ strategy: RetryStrategy.ADAPTIVE,
148
+ maxRetries: 3,
149
+ initialDelayMs: 1000,
150
+ confidence: 0.85,
151
+ reason: 'Test is often flaky (Shaky), adaptive retry recommended',
152
+ pattern: patternType
153
+ };
154
+ }
155
+ // Very low flakiness -> intelligent retry
156
+ return {
157
+ shouldRetry: true,
158
+ strategy: RetryStrategy.INTELLIGENT,
159
+ maxRetries: 5,
160
+ initialDelayMs: 2000,
161
+ confidence: 0.9,
162
+ reason: 'Test is very flaky (Unstable), aggressive retry with pattern analysis',
163
+ pattern: patternType
164
+ };
165
+ }
166
+ /**
167
+ * Calculate delay before retry attempt
168
+ */
169
+ calculateDelay(attemptNumber, strategy) {
170
+ const baseDelay = this.config.initialDelayMs;
171
+ switch (strategy) {
172
+ case RetryStrategy.FIXED:
173
+ return this.applyJitter(baseDelay);
174
+ case RetryStrategy.LINEAR:
175
+ const linearDelay = baseDelay * (attemptNumber - 1) * this.config.backoffMultiplier;
176
+ return this.applyJitter(Math.min(linearDelay, this.config.maxDelayMs));
177
+ case RetryStrategy.EXPONENTIAL:
178
+ const expDelay = baseDelay * Math.pow(this.config.backoffMultiplier, attemptNumber - 1);
179
+ return this.applyJitter(Math.min(expDelay, this.config.maxDelayMs));
180
+ case RetryStrategy.ADAPTIVE:
181
+ // Start with exponential, but reduce if attempts are high
182
+ const adaptiveDelay = baseDelay * Math.pow(this.config.backoffMultiplier, Math.min(attemptNumber - 1, 3));
183
+ return this.applyJitter(Math.min(adaptiveDelay, this.config.maxDelayMs));
184
+ case RetryStrategy.INTELLIGENT:
185
+ // Use pattern-based delay calculation
186
+ return this.getIntelligentDelay(attemptNumber);
187
+ case RetryStrategy.NONE:
188
+ default:
189
+ return 0;
190
+ }
191
+ }
192
+ /**
193
+ * Get effective strategy based on context
194
+ */
195
+ getEffectiveStrategy(configuredStrategy, flakinessScore, patternType) {
196
+ // If explicitly set to none, respect it
197
+ if (configuredStrategy === RetryStrategy.NONE) {
198
+ return RetryStrategy.NONE;
199
+ }
200
+ // Adaptive strategy adjusts based on flakiness
201
+ if (configuredStrategy === RetryStrategy.ADAPTIVE && flakinessScore !== undefined) {
202
+ if (flakinessScore >= 90)
203
+ return RetryStrategy.NONE;
204
+ if (flakinessScore >= 75)
205
+ return RetryStrategy.FIXED;
206
+ if (flakinessScore >= 50)
207
+ return RetryStrategy.LINEAR;
208
+ return RetryStrategy.EXPONENTIAL;
209
+ }
210
+ // Intelligent strategy considers patterns
211
+ if (configuredStrategy === RetryStrategy.INTELLIGENT && patternType) {
212
+ // Timing issues -> exponential backoff
213
+ if (patternType.includes('timing'))
214
+ return RetryStrategy.EXPONENTIAL;
215
+ // External dependency -> linear with longer delays
216
+ if (patternType.includes('external'))
217
+ return RetryStrategy.LINEAR;
218
+ // Selector issues -> fixed delay (usually resolves quickly)
219
+ if (patternType.includes('selector'))
220
+ return RetryStrategy.FIXED;
221
+ // Race condition -> exponential with jitter
222
+ if (patternType.includes('race'))
223
+ return RetryStrategy.EXPONENTIAL;
224
+ }
225
+ return configuredStrategy;
226
+ }
227
+ /**
228
+ * Calculate intelligent delay based on common patterns
229
+ */
230
+ getIntelligentDelay(attemptNumber) {
231
+ // Timing issues: exponential backoff starting at 2s
232
+ if (attemptNumber === 1)
233
+ return 2000;
234
+ if (attemptNumber === 2)
235
+ return 3000;
236
+ if (attemptNumber === 3)
237
+ return 5000;
238
+ return 8000;
239
+ }
240
+ /**
241
+ * Apply jitter to delay to avoid thundering herd
242
+ */
243
+ applyJitter(delayMs) {
244
+ if (this.config.jitterFactor === 0)
245
+ return delayMs;
246
+ const jitter = delayMs * this.config.jitterFactor * (Math.random() * 2 - 1);
247
+ return Math.max(0, Math.round(delayMs + jitter));
248
+ }
249
+ /**
250
+ * Check if error type is non-retriable
251
+ */
252
+ isNonRetriableError(errorType, errorMessage) {
253
+ return this.config.nonRetriableErrors.some(nonRetriable => errorType.includes(nonRetriable) ||
254
+ (errorMessage && errorMessage.includes(nonRetriable)));
255
+ }
256
+ /**
257
+ * Check if error is an assertion failure
258
+ */
259
+ isAssertionError(errorType, errorMessage) {
260
+ return errorType.toLowerCase().includes('assertion') ||
261
+ errorType === 'AssertionError' ||
262
+ errorType === 'ExpectFailError' ||
263
+ Boolean(errorMessage && errorMessage.toLowerCase().includes('assertion'));
264
+ }
265
+ /**
266
+ * Check if error is a timeout
267
+ */
268
+ isTimeoutError(errorType, errorMessage) {
269
+ return errorType.toLowerCase().includes('timeout') ||
270
+ Boolean(errorMessage && errorMessage.toLowerCase().includes('timeout'));
271
+ }
272
+ /**
273
+ * Delay for specified milliseconds
274
+ */
275
+ delay(ms) {
276
+ return new Promise(resolve => setTimeout(resolve, ms));
277
+ }
278
+ /**
279
+ * Update retry configuration
280
+ */
281
+ updateConfig(config) {
282
+ this.config = { ...this.config, ...config };
283
+ }
284
+ /**
285
+ * Get current configuration
286
+ */
287
+ getConfig() {
288
+ return { ...this.config };
289
+ }
290
+ }
291
+ /**
292
+ * Create a smart retry engine
293
+ */
294
+ export function createSmartRetryEngine(config) {
295
+ return new SmartRetryEngine(config);
296
+ }
@@ -0,0 +1,178 @@
1
+ /**
2
+ * QA360 Smart Retry Module (F8)
3
+ *
4
+ * Intelligent retry strategies based on flakiness scoring and pattern detection.
5
+ * Completes the flakiness system: Detection → Scoring → Quarantine → Smart Retry
6
+ *
7
+ * @module retry
8
+ */
9
+ /**
10
+ * Retry strategy types
11
+ */
12
+ export declare enum RetryStrategy {
13
+ /** No retry - fail immediately */
14
+ NONE = "none",
15
+ /** Fixed delay between retries */
16
+ FIXED = "fixed",
17
+ /** Linear backoff (delay increases linearly) */
18
+ LINEAR = "linear",
19
+ /** Exponential backoff (delay doubles each retry) */
20
+ EXPONENTIAL = "exponential",
21
+ /** Adaptive retry based on flakiness score */
22
+ ADAPTIVE = "adaptive",
23
+ /** Intelligent retry based on pattern detection */
24
+ INTELLIGENT = "intelligent"
25
+ }
26
+ /**
27
+ * Retry attempt result
28
+ */
29
+ export interface RetryAttempt {
30
+ /** Attempt number (1-indexed) */
31
+ attemptNumber: number;
32
+ /** Whether the attempt succeeded */
33
+ success: boolean;
34
+ /** Duration in milliseconds */
35
+ durationMs: number;
36
+ /** Error type if failed */
37
+ errorType?: string;
38
+ /** Error message if failed */
39
+ errorMessage?: string;
40
+ /** Delay before this attempt in ms */
41
+ delayMs: number;
42
+ /** Timestamp of attempt */
43
+ timestamp: number;
44
+ }
45
+ /**
46
+ * Retry result
47
+ */
48
+ export interface RetryResult {
49
+ /** Test identifier */
50
+ testId: string;
51
+ /** Whether any retry attempt succeeded */
52
+ success: boolean;
53
+ /** Total number of attempts */
54
+ totalAttempts: number;
55
+ /** Successful attempt number (0 if none) */
56
+ successfulAttempt?: number;
57
+ /** All retry attempts */
58
+ attempts: RetryAttempt[];
59
+ /** Total duration including delays */
60
+ totalDurationMs: number;
61
+ /** Strategy used */
62
+ strategy: RetryStrategy;
63
+ /** Reason for stopping retries */
64
+ stopReason: 'success' | 'max_retries' | 'timeout' | 'unrecoverable';
65
+ }
66
+ /**
67
+ * Retry configuration
68
+ */
69
+ export interface RetryConfig {
70
+ /** Maximum number of retry attempts */
71
+ maxRetries: number;
72
+ /** Initial delay in milliseconds */
73
+ initialDelayMs: number;
74
+ /** Maximum delay in milliseconds */
75
+ maxDelayMs: number;
76
+ /** Timeout for each attempt */
77
+ attemptTimeoutMs: number;
78
+ /** Overall timeout including retries */
79
+ overallTimeoutMs?: number;
80
+ /** Retry strategy */
81
+ strategy: RetryStrategy;
82
+ /** Multiplier for exponential/linear backoff */
83
+ backoffMultiplier: number;
84
+ /** Jitter for backoff (0-1) to avoid thundering herd */
85
+ jitterFactor: number;
86
+ /** Whether to retry on timeout */
87
+ retryOnTimeout: boolean;
88
+ /** Whether to retry on assertion failures */
89
+ retryOnAssertionFailure: boolean;
90
+ /** Error types that should not be retried */
91
+ nonRetriableErrors: string[];
92
+ /** Adaptive retry: minimum flakiness score to enable retries */
93
+ adaptiveMinFlakinessScore?: number;
94
+ /** Intelligent retry: enable pattern-based retry */
95
+ enablePatternBasedRetry?: boolean;
96
+ }
97
+ /**
98
+ * Default retry configuration
99
+ */
100
+ export declare const DEFAULT_RETRY_CONFIG: Required<Omit<RetryConfig, 'nonRetriableErrors' | 'adaptiveMinFlakinessScore' | 'enablePatternBasedRetry'>> & {
101
+ nonRetriableErrors: string[];
102
+ adaptiveMinFlakinessScore?: number;
103
+ enablePatternBasedRetry?: boolean;
104
+ };
105
+ /**
106
+ * Flakiness-based retry recommendation
107
+ */
108
+ export interface RetryRecommendation {
109
+ /** Whether retry is recommended */
110
+ shouldRetry: boolean;
111
+ /** Suggested retry strategy */
112
+ strategy: RetryStrategy;
113
+ /** Suggested max retries */
114
+ maxRetries: number;
115
+ /** Suggested initial delay */
116
+ initialDelayMs: number;
117
+ /** Confidence in recommendation (0-1) */
118
+ confidence: number;
119
+ /** Reason for recommendation */
120
+ reason: string;
121
+ /** Specific pattern detected that informs retry */
122
+ pattern?: string;
123
+ }
124
+ /**
125
+ * Retry history record for vault storage
126
+ */
127
+ export interface RetryHistoryRecord {
128
+ id: number;
129
+ run_id: string;
130
+ test_id: string;
131
+ test_name: string;
132
+ gate: string;
133
+ strategy: RetryStrategy;
134
+ max_retries: number;
135
+ actual_attempts: number;
136
+ success: boolean;
137
+ successful_attempt: number | null;
138
+ total_duration_ms: number;
139
+ stop_reason: string;
140
+ error_type: string | null;
141
+ error_message: string | null;
142
+ flakiness_score: number | null;
143
+ pattern_type: string | null;
144
+ timestamp: number;
145
+ }
146
+ /**
147
+ * Retry statistics
148
+ */
149
+ export interface RetryStatistics {
150
+ /** Total retries attempted */
151
+ totalRetries: number;
152
+ /** Total tests that were retried */
153
+ testsRetried: number;
154
+ /** Tests that passed after retry */
155
+ recoveredTests: number;
156
+ /** Tests that failed all retries */
157
+ failedTests: number;
158
+ /** Recovery rate (percentage) */
159
+ recoveryRate: number;
160
+ /** Average attempts per retried test */
161
+ avgAttemptsPerTest: number;
162
+ /** Time spent retrying (ms) */
163
+ totalRetryTimeMs: number;
164
+ /** Breakdown by strategy */
165
+ byStrategy: Record<RetryStrategy, {
166
+ attempts: number;
167
+ successes: number;
168
+ avgDurationMs: number;
169
+ }>;
170
+ /** Breakdown by error type */
171
+ byErrorType: Record<string, number>;
172
+ /** Breakdown by flakiness score */
173
+ byFlakinessScore: {
174
+ low: number;
175
+ medium: number;
176
+ high: number;
177
+ };
178
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * QA360 Smart Retry Module (F8)
3
+ *
4
+ * Intelligent retry strategies based on flakiness scoring and pattern detection.
5
+ * Completes the flakiness system: Detection → Scoring → Quarantine → Smart Retry
6
+ *
7
+ * @module retry
8
+ */
9
+ /**
10
+ * Retry strategy types
11
+ */
12
+ export var RetryStrategy;
13
+ (function (RetryStrategy) {
14
+ /** No retry - fail immediately */
15
+ RetryStrategy["NONE"] = "none";
16
+ /** Fixed delay between retries */
17
+ RetryStrategy["FIXED"] = "fixed";
18
+ /** Linear backoff (delay increases linearly) */
19
+ RetryStrategy["LINEAR"] = "linear";
20
+ /** Exponential backoff (delay doubles each retry) */
21
+ RetryStrategy["EXPONENTIAL"] = "exponential";
22
+ /** Adaptive retry based on flakiness score */
23
+ RetryStrategy["ADAPTIVE"] = "adaptive";
24
+ /** Intelligent retry based on pattern detection */
25
+ RetryStrategy["INTELLIGENT"] = "intelligent";
26
+ })(RetryStrategy || (RetryStrategy = {}));
27
+ /**
28
+ * Default retry configuration
29
+ */
30
+ export const DEFAULT_RETRY_CONFIG = {
31
+ maxRetries: 3,
32
+ initialDelayMs: 1000,
33
+ maxDelayMs: 30000,
34
+ attemptTimeoutMs: 30000,
35
+ overallTimeoutMs: 120000,
36
+ strategy: RetryStrategy.ADAPTIVE,
37
+ backoffMultiplier: 2,
38
+ jitterFactor: 0.1,
39
+ retryOnTimeout: false,
40
+ retryOnAssertionFailure: false,
41
+ nonRetriableErrors: [
42
+ 'OutOfMemoryError',
43
+ 'StackOverflowError',
44
+ 'SecurityError',
45
+ 'PermissionDenied',
46
+ 'InvalidArgument',
47
+ 'ValidationError',
48
+ 'SyntaxError'
49
+ ],
50
+ adaptiveMinFlakinessScore: 75,
51
+ enablePatternBasedRetry: true
52
+ };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Retry Vault Integration
3
+ *
4
+ * Stores retry history and statistics in the Evidence Vault.
5
+ */
6
+ import type { Database } from 'sqlite3';
7
+ import type { RetryResult, RetryHistoryRecord, RetryStatistics } from './types.js';
8
+ import { RetryStrategy } from './types.js';
9
+ /**
10
+ * Retry Vault class
11
+ */
12
+ export declare class RetryVault {
13
+ private db;
14
+ private dbRun;
15
+ private dbAll;
16
+ private dbGet;
17
+ constructor(db: Database);
18
+ /**
19
+ * Initialize retry tables
20
+ */
21
+ initialize(): Promise<void>;
22
+ /**
23
+ * Store retry result
24
+ */
25
+ storeRetryResult(runId: string, result: RetryResult, context?: {
26
+ testName?: string;
27
+ gate?: string;
28
+ flakinessScore?: number;
29
+ patternType?: string;
30
+ }): Promise<number>;
31
+ /**
32
+ * Get retry history for a test
33
+ */
34
+ getRetryHistory(testId: string, limit?: number): Promise<RetryHistoryRecord[]>;
35
+ /**
36
+ * Get retry history for a run
37
+ */
38
+ getRetryHistoryForRun(runId: string): Promise<RetryHistoryRecord[]>;
39
+ /**
40
+ * Get retry statistics
41
+ */
42
+ getStatistics(days?: number): Promise<RetryStatistics>;
43
+ /**
44
+ * Get strategy performance
45
+ */
46
+ getStrategyPerformance(days?: number): Promise<Array<{
47
+ strategy: RetryStrategy;
48
+ date: string;
49
+ attempts: number;
50
+ successes: number;
51
+ successRate: number;
52
+ avgDurationMs: number;
53
+ }>>;
54
+ /**
55
+ * Get most retried tests
56
+ */
57
+ getMostRetriedTests(limit?: number, days?: number): Promise<Array<{
58
+ testId: string;
59
+ testName: string;
60
+ gate: string;
61
+ retryCount: number;
62
+ recoveryRate: number;
63
+ avgAttempts: number;
64
+ }>>;
65
+ /**
66
+ * Update daily statistics
67
+ */
68
+ private updateStatistics;
69
+ /**
70
+ * Map database rows to RetryHistoryRecord objects
71
+ */
72
+ private mapRowsToRecords;
73
+ /**
74
+ * Delete old retry history
75
+ */
76
+ deleteOldHistory(olderThanMs: number): Promise<number>;
77
+ }