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,345 @@
1
+ /**
2
+ * Regression Trend Analyzer
3
+ *
4
+ * Analyzes metric trends to predict potential regressions.
5
+ * Uses linear regression and change point detection.
6
+ */
7
+ /**
8
+ * Regression Trend Analyzer class
9
+ */
10
+ export class RegressionTrendAnalyzer {
11
+ /**
12
+ * Analyze trend for a metric
13
+ */
14
+ analyzeTrend(data, windowMs) {
15
+ if (data.length < 3) {
16
+ return null;
17
+ }
18
+ const analysis = this.linearRegression(data);
19
+ const direction = this.getTrendDirection(analysis.slope);
20
+ const strength = Math.abs(analysis.rSquared);
21
+ // Project future value
22
+ const projected = this.projectTrend(data, analysis);
23
+ return {
24
+ metric: data[0].metadata?.metric || 'unknown',
25
+ direction,
26
+ strength,
27
+ projected,
28
+ dataPoints: data.length,
29
+ regressions: 0 // Will be populated by detector
30
+ };
31
+ }
32
+ /**
33
+ * Perform linear regression on time series
34
+ */
35
+ linearRegression(data) {
36
+ const n = data.length;
37
+ if (n < 2) {
38
+ return {
39
+ slope: 0,
40
+ intercept: data[0]?.value || 0,
41
+ rSquared: 0,
42
+ significant: false,
43
+ direction: 'stable',
44
+ project: () => 0
45
+ };
46
+ }
47
+ // Normalize timestamps to start from 0
48
+ const baseTime = data[0].timestamp;
49
+ let sumX = 0;
50
+ let sumY = 0;
51
+ let sumXY = 0;
52
+ let sumXX = 0;
53
+ let sumYY = 0;
54
+ for (const point of data) {
55
+ const x = (point.timestamp - baseTime) / 1000; // Convert to seconds
56
+ const y = point.value;
57
+ sumX += x;
58
+ sumY += y;
59
+ sumXY += x * y;
60
+ sumXX += x * x;
61
+ sumYY += y * y;
62
+ }
63
+ const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
64
+ const intercept = (sumY - slope * sumX) / n;
65
+ // Calculate R²
66
+ const meanY = sumY / n;
67
+ let ssTotal = 0;
68
+ let ssResidual = 0;
69
+ for (const point of data) {
70
+ const x = (point.timestamp - baseTime) / 1000;
71
+ const y = point.value;
72
+ const predicted = slope * x + intercept;
73
+ ssTotal += Math.pow(y - meanY, 2);
74
+ ssResidual += Math.pow(y - predicted, 2);
75
+ }
76
+ const rSquared = ssTotal > 0 ? 1 - ssResidual / ssTotal : 0;
77
+ // Determine significance (simplified)
78
+ const significant = rSquared > 0.7 && Math.abs(slope) > 0.001;
79
+ const direction = Math.abs(slope) < 0.001 ? 'stable'
80
+ : slope > 0 ? 'increasing'
81
+ : 'decreasing';
82
+ return {
83
+ slope,
84
+ intercept,
85
+ rSquared,
86
+ significant,
87
+ direction,
88
+ project: (ms) => {
89
+ const x = ms / 1000;
90
+ return slope * x + intercept;
91
+ }
92
+ };
93
+ }
94
+ /**
95
+ * Detect change points in time series
96
+ */
97
+ detectChangePoints(data, minSegmentSize = 5) {
98
+ if (data.length < minSegmentSize * 2) {
99
+ return [];
100
+ }
101
+ const changePoints = [];
102
+ const values = data.map(d => d.value);
103
+ // Use simplified CUSUM-like approach
104
+ let maxChange = 0;
105
+ let maxIndex = 0;
106
+ for (let i = minSegmentSize; i < values.length - minSegmentSize; i++) {
107
+ const before = values.slice(0, i);
108
+ const after = values.slice(i);
109
+ const beforeMean = before.reduce((a, b) => a + b, 0) / before.length;
110
+ const afterMean = after.reduce((a, b) => a + b, 0) / after.length;
111
+ const magnitude = Math.abs(afterMean - beforeMean);
112
+ if (magnitude > maxChange) {
113
+ maxChange = magnitude;
114
+ maxIndex = i;
115
+ }
116
+ }
117
+ if (maxChange > 0) {
118
+ const splitIdx = maxIndex;
119
+ const before = values.slice(0, splitIdx);
120
+ const after = values.slice(splitIdx);
121
+ changePoints.push({
122
+ index: splitIdx,
123
+ timestamp: data[splitIdx].timestamp,
124
+ beforeMean: before.reduce((a, b) => a + b, 0) / before.length,
125
+ afterMean: after.reduce((a, b) => a + b, 0) / after.length,
126
+ magnitude: maxChange,
127
+ pValue: this.estimatePValue(maxChange, before.length, after.length)
128
+ });
129
+ }
130
+ return changePoints;
131
+ }
132
+ /**
133
+ * Estimate p-value for change point
134
+ */
135
+ estimatePValue(magnitude, n1, n2) {
136
+ // Simplified estimation using t-distribution approximation
137
+ const pooledStd = Math.sqrt((magnitude * magnitude) / (1 / n1 + 1 / n2));
138
+ const tStat = magnitude / (pooledStd || 1);
139
+ // Rough p-value approximation
140
+ return Math.max(0.001, 1 - Math.min(1, tStat / 5));
141
+ }
142
+ /**
143
+ * Project trend forward
144
+ */
145
+ projectTrend(data, analysis) {
146
+ if (!analysis.significant) {
147
+ return undefined;
148
+ }
149
+ // Project 7 days forward
150
+ const weekMs = 7 * 24 * 60 * 60 * 1000;
151
+ return analysis.project(weekMs);
152
+ }
153
+ /**
154
+ * Get trend direction for reporting
155
+ */
156
+ getTrendDirection(slope) {
157
+ if (Math.abs(slope) < 0.001) {
158
+ return 'stable';
159
+ }
160
+ // Note: For some metrics (like latency), increasing is bad
161
+ // For others (like coverage), increasing is good
162
+ // This is simplified - should consider metric type
163
+ return slope > 0 ? 'degrading' : 'improving';
164
+ }
165
+ /**
166
+ * Calculate time until threshold breach
167
+ */
168
+ calculateTimeToThreshold(data, threshold, isIncreasingBad) {
169
+ const analysis = this.linearRegression(data);
170
+ if (!analysis.significant || Math.abs(analysis.slope) < 0.00001) {
171
+ return null;
172
+ }
173
+ const currentValue = data[data.length - 1].value;
174
+ // Determine if we're moving toward threshold
175
+ const movingTowardBad = isIncreasingBad
176
+ ? analysis.slope > 0
177
+ : analysis.slope < 0;
178
+ if (!movingTowardBad) {
179
+ return null; // Not moving toward threshold
180
+ }
181
+ // Calculate time to reach threshold
182
+ // slope is in units per second, so we need to convert
183
+ const diff = isIncreasingBad
184
+ ? threshold - currentValue
185
+ : currentValue - threshold;
186
+ if (diff <= 0) {
187
+ return 0; // Already at/beyond threshold
188
+ }
189
+ // Convert: slope (units/sec) to time needed (ms)
190
+ // time_ms = (diff / slope) * 1000
191
+ const timeToThreshold = (diff / Math.abs(analysis.slope)) * 1000;
192
+ return Math.max(0, timeToThreshold);
193
+ }
194
+ /**
195
+ * Compare two periods for regression
196
+ */
197
+ comparePeriods(baseline, current, metric) {
198
+ if (baseline.length === 0 || current.length === 0) {
199
+ return null;
200
+ }
201
+ const baselineMean = baseline.reduce((sum, p) => sum + p.value, 0) / baseline.length;
202
+ const currentMean = current.reduce((sum, p) => sum + p.value, 0) / current.length;
203
+ const absoluteChange = currentMean - baselineMean;
204
+ const percentChange = baselineMean !== 0
205
+ ? (absoluteChange / baselineMean) * 100
206
+ : 0;
207
+ // Determine if regression based on metric type
208
+ const type = this.inferType(metric);
209
+ const direction = this.isRegressionDirection(type, absoluteChange);
210
+ if (!direction) {
211
+ return null;
212
+ }
213
+ // Calculate significance using t-test
214
+ const baselineVariance = baseline.reduce((sum, p) => sum + Math.pow(p.value - baselineMean, 2), 0) / baseline.length;
215
+ const currentVariance = current.reduce((sum, p) => sum + Math.pow(p.value - currentMean, 2), 0) / current.length;
216
+ const pooledStd = Math.sqrt(((baseline.length - 1) * baselineVariance + (current.length - 1) * currentVariance) /
217
+ (baseline.length + current.length - 2));
218
+ const tStat = absoluteChange / (pooledStd * Math.sqrt(1 / baseline.length + 1 / current.length) || 1);
219
+ const pValue = 2 * (1 - this.normalCDF(Math.abs(tStat)));
220
+ // Severity based on percent change and significance
221
+ let severity;
222
+ if (Math.abs(percentChange) > 50 && pValue < 0.01) {
223
+ severity = 'critical';
224
+ }
225
+ else if (Math.abs(percentChange) > 20 && pValue < 0.05) {
226
+ severity = 'major';
227
+ }
228
+ else if (Math.abs(percentChange) > 10) {
229
+ severity = 'moderate';
230
+ }
231
+ else {
232
+ severity = 'minor';
233
+ }
234
+ return {
235
+ id: `regression_${Date.now()}_${metric.replace(/\W/g, '_')}`,
236
+ runId: current[current.length - 1].runId,
237
+ baselineRunId: baseline[baseline.length - 1].runId,
238
+ type,
239
+ severity,
240
+ status: 'detected',
241
+ metricName: metric,
242
+ baselineValue: baselineMean,
243
+ currentValue: currentMean,
244
+ absoluteChange,
245
+ percentChange,
246
+ significance: pValue,
247
+ confidence: 1 - pValue,
248
+ direction: absoluteChange > 0 ? 'worse' : 'better',
249
+ affectedComponent: metric,
250
+ gate: 'unknown',
251
+ suggestions: [
252
+ `Review changes between ${new Date(baseline[0].timestamp).toISOString()} and ${new Date(current[0].timestamp).toISOString()}`,
253
+ `${percentChange > 0 ? 'Increased' : 'Decreased'} by ${Math.abs(percentChange).toFixed(1)}%`
254
+ ],
255
+ timestamp: Date.now()
256
+ };
257
+ }
258
+ /**
259
+ * Infer regression type from metric name
260
+ */
261
+ inferType(metric) {
262
+ if (metric.includes('duration') || metric.includes('latency') || metric.includes('time')) {
263
+ return 'performance';
264
+ }
265
+ if (metric.includes('coverage')) {
266
+ return 'coverage';
267
+ }
268
+ if (metric.includes('flaky') || metric.includes('stability')) {
269
+ return 'reliability';
270
+ }
271
+ if (metric.includes('security') || metric.includes('vulnerability')) {
272
+ return 'security';
273
+ }
274
+ return 'quality';
275
+ }
276
+ /**
277
+ * Check if change direction indicates regression
278
+ */
279
+ isRegressionDirection(type, change) {
280
+ // For performance, reliability: increase is bad
281
+ if (type === 'performance' || type === 'reliability') {
282
+ return change > 0;
283
+ }
284
+ // For coverage: decrease is bad
285
+ if (type === 'coverage') {
286
+ return change < 0;
287
+ }
288
+ // Default: increase is bad
289
+ return change > 0;
290
+ }
291
+ /**
292
+ * Normal CDF approximation
293
+ */
294
+ normalCDF(x) {
295
+ const a1 = 0.254829592;
296
+ const a2 = -0.284496736;
297
+ const a3 = 1.421413741;
298
+ const a4 = -1.453152027;
299
+ const a5 = 1.061405429;
300
+ const p = 0.3275911;
301
+ const sign = x < 0 ? -1 : 1;
302
+ x = Math.abs(x) / Math.sqrt(2);
303
+ const t = 1.0 / (1.0 + p * x);
304
+ const y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
305
+ return 0.5 * (1.0 + sign * y);
306
+ }
307
+ /**
308
+ * Get trend description
309
+ */
310
+ getTrendDescription(trend) {
311
+ const percentStrength = Math.round(trend.strength * 100);
312
+ switch (trend.direction) {
313
+ case 'degrading':
314
+ return `Degrading (${percentStrength}% confidence)`;
315
+ case 'improving':
316
+ return `Improving (${percentStrength}% confidence)`;
317
+ default:
318
+ return `Stable (${percentStrength}% confidence)`;
319
+ }
320
+ }
321
+ /**
322
+ * Format time to threshold
323
+ */
324
+ formatTimeToThreshold(ms) {
325
+ if (ms < 0)
326
+ return 'Already breached';
327
+ if (ms === 0)
328
+ return 'At threshold';
329
+ const days = Math.floor(ms / (24 * 60 * 60 * 1000));
330
+ const hours = Math.floor((ms % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
331
+ if (days > 0) {
332
+ return `${days} day${days > 1 ? 's' : ''}`;
333
+ }
334
+ if (hours > 0) {
335
+ return `${hours} hour${hours > 1 ? 's' : ''}`;
336
+ }
337
+ return '< 1 hour';
338
+ }
339
+ }
340
+ /**
341
+ * Create a regression trend analyzer
342
+ */
343
+ export function createRegressionTrendAnalyzer() {
344
+ return new RegressionTrendAnalyzer();
345
+ }
@@ -0,0 +1,222 @@
1
+ /**
2
+ * QA360 Regression Detection Module
3
+ *
4
+ * Types for detecting performance and quality regressions.
5
+ * Uses statistical analysis to identify significant changes in metrics.
6
+ */
7
+ /**
8
+ * Regression types
9
+ */
10
+ export type RegressionType = 'performance' | 'quality' | 'coverage' | 'reliability' | 'security' | 'api_breaking' | 'custom';
11
+ /**
12
+ * Regression severity
13
+ */
14
+ export type RegressionSeverity = 'info' | 'minor' | 'moderate' | 'major' | 'critical';
15
+ /**
16
+ * Regression status
17
+ */
18
+ export type RegressionStatus = 'detected' | 'investigating' | 'confirmed' | 'false_positive' | 'resolved' | 'ignored';
19
+ /**
20
+ * Regression detection result
21
+ */
22
+ export interface RegressionDetection {
23
+ /** Unique identifier */
24
+ id: string;
25
+ /** Run ID where regression was detected */
26
+ runId: string;
27
+ /** Baseline run ID for comparison */
28
+ baselineRunId: string;
29
+ /** Regression type */
30
+ type: RegressionType;
31
+ /** Severity level */
32
+ severity: RegressionSeverity;
33
+ /** Status */
34
+ status: RegressionStatus;
35
+ /** Metric name that regressed */
36
+ metricName: string;
37
+ /** Baseline value */
38
+ baselineValue: number;
39
+ /** Current value */
40
+ currentValue: number;
41
+ /** Absolute change */
42
+ absoluteChange: number;
43
+ /** Percentage change */
44
+ percentChange: number;
45
+ /** Statistical significance (p-value) */
46
+ significance: number;
47
+ /** Confidence (0-1) */
48
+ confidence: number;
49
+ /** Direction (worse = degradation, better = improvement) */
50
+ direction: 'worse' | 'better' | 'neutral';
51
+ /** Affected component/test */
52
+ affectedComponent: string;
53
+ /** Gate where detected */
54
+ gate: string;
55
+ /** Context information */
56
+ context?: {
57
+ file?: string;
58
+ line?: number;
59
+ test?: string;
60
+ endpoint?: string;
61
+ [key: string]: unknown;
62
+ };
63
+ /** Suggested actions */
64
+ suggestions: string[];
65
+ /** Related commits */
66
+ commits?: string[];
67
+ /** Detection timestamp */
68
+ timestamp: number;
69
+ /** Notes */
70
+ notes?: string;
71
+ }
72
+ /**
73
+ * Regression threshold configuration
74
+ */
75
+ export interface RegressionThreshold {
76
+ /** Metric name */
77
+ metric: string;
78
+ /** Maximum allowed regression (percentage) */
79
+ maxRegression: number;
80
+ /** Minimum change to trigger alert (absolute) */
81
+ minDelta: number;
82
+ /** Statistical significance threshold (p-value) */
83
+ significanceLevel: number;
84
+ /** Direction to monitor */
85
+ direction: 'increase' | 'decrease' | 'both';
86
+ /** Regression severity if threshold exceeded */
87
+ severity: RegressionSeverity;
88
+ }
89
+ /**
90
+ * Regression configuration
91
+ */
92
+ export interface RegressionConfig {
93
+ /** Enable regression detection */
94
+ enabled: boolean;
95
+ /** Automatic detection on each run */
96
+ autoDetect: boolean;
97
+ /** Baseline window (number of runs to average) */
98
+ baselineWindow: number;
99
+ /** Minimum data points for statistical analysis */
100
+ minDataPoints: number;
101
+ /** Statistical method */
102
+ method: 'zscore' | 'ttest' | 'mannwhitney' | 'percentile';
103
+ /** Thresholds by metric type */
104
+ thresholds: {
105
+ performance: RegressionThreshold[];
106
+ quality: RegressionThreshold[];
107
+ coverage: RegressionThreshold[];
108
+ reliability: RegressionThreshold[];
109
+ security: RegressionThreshold[];
110
+ };
111
+ /** Alert configuration */
112
+ alerts: {
113
+ enabled: boolean;
114
+ onNewRegression: boolean;
115
+ onSeverity: RegressionSeverity[];
116
+ };
117
+ /** Ignore patterns (metrics to ignore) */
118
+ ignorePatterns: string[];
119
+ }
120
+ /**
121
+ * Time series data point
122
+ */
123
+ export interface TimeSeriesPoint {
124
+ timestamp: number;
125
+ value: number;
126
+ runId: string;
127
+ metadata?: Record<string, unknown>;
128
+ }
129
+ /**
130
+ * Statistical test result
131
+ */
132
+ export interface StatisticalTest {
133
+ /** Test name */
134
+ test: string;
135
+ /** P-value */
136
+ pValue: number;
137
+ /** Is significant? */
138
+ significant: boolean;
139
+ /** Test statistic */
140
+ statistic: number;
141
+ /** Confidence interval */
142
+ confidenceInterval?: {
143
+ lower: number;
144
+ upper: number;
145
+ };
146
+ }
147
+ /**
148
+ * Regression trend analysis
149
+ */
150
+ export interface RegressionTrend {
151
+ /** Metric name */
152
+ metric: string;
153
+ /** Current trend direction */
154
+ direction: 'improving' | 'degrading' | 'stable';
155
+ /** Trend strength (0-1) */
156
+ strength: number;
157
+ /** Projected value (if trend continues) */
158
+ projected?: number;
159
+ /** Time to threshold (if degrading) */
160
+ timeToThreshold?: number;
161
+ /** Data points analyzed */
162
+ dataPoints: number;
163
+ /** Regression detections in trend */
164
+ regressions: number;
165
+ }
166
+ /**
167
+ * Regression report
168
+ */
169
+ export interface RegressionReport {
170
+ /** Report ID */
171
+ id: string;
172
+ /** Report timestamp */
173
+ timestamp: number;
174
+ /** Comparison period */
175
+ period: {
176
+ start: number;
177
+ end: number;
178
+ baselineStart: number;
179
+ baselineEnd: number;
180
+ };
181
+ /** Detected regressions */
182
+ regressions: RegressionDetection[];
183
+ /** Summary statistics */
184
+ summary: {
185
+ total: number;
186
+ bySeverity: Record<RegressionSeverity, number>;
187
+ byType: Record<RegressionType, number>;
188
+ new: number;
189
+ resolved: number;
190
+ ongoing: number;
191
+ };
192
+ /** Overall health status */
193
+ healthStatus: 'healthy' | 'warning' | 'critical';
194
+ }
195
+ /**
196
+ * Baseline data
197
+ */
198
+ export interface Baseline {
199
+ /** Metric name */
200
+ metric: string;
201
+ /** Average value */
202
+ mean: number;
203
+ /** Standard deviation */
204
+ stdDev: number;
205
+ /** Minimum value */
206
+ min: number;
207
+ /** Maximum value */
208
+ max: number;
209
+ /** Percentiles */
210
+ percentiles: {
211
+ p50: number;
212
+ p90: number;
213
+ p95: number;
214
+ p99: number;
215
+ };
216
+ /** Sample size */
217
+ sampleSize: number;
218
+ /** Calculated from run IDs */
219
+ runIds: string[];
220
+ /** Baseline timestamp */
221
+ timestamp: number;
222
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * QA360 Regression Detection Module
3
+ *
4
+ * Types for detecting performance and quality regressions.
5
+ * Uses statistical analysis to identify significant changes in metrics.
6
+ */
7
+ export {};
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Regression Vault Integration
3
+ *
4
+ * Integrates regression data storage and retrieval with the Evidence Vault.
5
+ */
6
+ import type { Database } from 'sqlite3';
7
+ import type { RegressionDetection } from './types.js';
8
+ /**
9
+ * Regression Vault class
10
+ */
11
+ export declare class RegressionVault {
12
+ private db;
13
+ private dbRun;
14
+ private dbAll;
15
+ private dbGet;
16
+ constructor(db: Database);
17
+ /**
18
+ * Initialize regression tables
19
+ */
20
+ initialize(): Promise<void>;
21
+ /**
22
+ * Store a regression detection
23
+ */
24
+ storeRegression(regression: RegressionDetection): Promise<void>;
25
+ /**
26
+ * Store multiple regressions
27
+ */
28
+ storeRegressions(regressions: RegressionDetection[]): Promise<void>;
29
+ /**
30
+ * Get regressions by run ID
31
+ */
32
+ getRegressionsByRun(runId: string): Promise<RegressionDetection[]>;
33
+ /**
34
+ * Get regressions by type
35
+ */
36
+ getRegressionsByType(type: string, limit?: number): Promise<RegressionDetection[]>;
37
+ /**
38
+ * Get regressions by severity
39
+ */
40
+ getRegressionsBySeverity(severity: string, limit?: number): Promise<RegressionDetection[]>;
41
+ /**
42
+ * Get regressions by status
43
+ */
44
+ getRegressionsByStatus(status: string, limit?: number): Promise<RegressionDetection[]>;
45
+ /**
46
+ * Get recent regressions
47
+ */
48
+ getRecentRegressions(limit?: number): Promise<RegressionDetection[]>;
49
+ /**
50
+ * Get regressions for a metric
51
+ */
52
+ getRegressionsByMetric(metricName: string, limit?: number): Promise<RegressionDetection[]>;
53
+ /**
54
+ * Update regression status
55
+ */
56
+ updateRegressionStatus(id: string, status: RegressionDetection['status'], notes?: string): Promise<void>;
57
+ /**
58
+ * Store regression snapshot
59
+ */
60
+ storeSnapshot(runId: string, metricName: string, value: number, baselineValue?: number): Promise<void>;
61
+ /**
62
+ * Get metric history for trend analysis
63
+ */
64
+ getMetricHistory(metricName: string, limit?: number): Promise<Array<{
65
+ runId: string;
66
+ value: number;
67
+ timestamp: number;
68
+ }>>;
69
+ /**
70
+ * Get regression statistics
71
+ */
72
+ getStatistics(): Promise<{
73
+ total: number;
74
+ bySeverity: Record<string, number>;
75
+ byType: Record<string, number>;
76
+ byStatus: Record<string, number>;
77
+ recent: number;
78
+ }>;
79
+ /**
80
+ * Delete old regressions
81
+ */
82
+ deleteOldRegressions(olderThanMs: number): Promise<number>;
83
+ /**
84
+ * Map database rows to RegressionDetection objects
85
+ */
86
+ private mapRowsToDetections;
87
+ }