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,379 @@
1
+ /**
2
+ * SLO Tracker
3
+ *
4
+ * Tracks Service Level Objectives and manages error budgets.
5
+ * Monitors SLO compliance and generates reports.
6
+ */
7
+ import { SLICalculator } from './sli-calculator.js';
8
+ /**
9
+ * SLO Tracker class
10
+ */
11
+ export class SLOTracker {
12
+ slos = new Map();
13
+ slis = new Map();
14
+ measurements = new Map();
15
+ violations = [];
16
+ calculator;
17
+ options;
18
+ constructor(options = {}) {
19
+ this.calculator = new SLICalculator();
20
+ this.options = {
21
+ warningThreshold: options.warningThreshold ?? 0.95,
22
+ trackViolations: options.trackViolations ?? true,
23
+ enableAlerts: options.enableAlerts ?? true,
24
+ onAlert: options.onAlert ?? (() => { })
25
+ };
26
+ }
27
+ /**
28
+ * Register an SLO
29
+ */
30
+ registerSLO(slo) {
31
+ this.slos.set(slo.id, slo);
32
+ }
33
+ /**
34
+ * Register an SLI
35
+ */
36
+ registerSLI(sli) {
37
+ this.slis.set(sli.id, sli);
38
+ }
39
+ /**
40
+ * Register multiple SLOs
41
+ */
42
+ registerSLOs(slos) {
43
+ for (const slo of slos) {
44
+ this.registerSLO(slo);
45
+ }
46
+ }
47
+ /**
48
+ * Register multiple SLIs
49
+ */
50
+ registerSLIs(slis) {
51
+ for (const sli of slis) {
52
+ this.registerSLI(sli);
53
+ }
54
+ }
55
+ /**
56
+ * Get an SLO by ID
57
+ */
58
+ getSLO(id) {
59
+ return this.slos.get(id);
60
+ }
61
+ /**
62
+ * Get an SLI by ID
63
+ */
64
+ getSLI(id) {
65
+ return this.slis.get(id);
66
+ }
67
+ /**
68
+ * Get all registered SLOs
69
+ */
70
+ getAllSLOs() {
71
+ return Array.from(this.slos.values());
72
+ }
73
+ /**
74
+ * Get all registered SLIs
75
+ */
76
+ getAllSLIs() {
77
+ return Array.from(this.slis.values());
78
+ }
79
+ /**
80
+ * Record a measurement for an SLI
81
+ */
82
+ recordMeasurement(measurement) {
83
+ const sli = this.slis.get(measurement.sliId);
84
+ if (!sli) {
85
+ throw new Error(`SLI not found: ${measurement.sliId}`);
86
+ }
87
+ if (!this.measurements.has(measurement.sliId)) {
88
+ this.measurements.set(measurement.sliId, []);
89
+ }
90
+ const measurements = this.measurements.get(measurement.sliId);
91
+ measurements.push(measurement);
92
+ // Keep only measurements within the longest SLO window
93
+ const longestWindow = this.getLongestWindow();
94
+ const cutoff = Date.now() - longestWindow;
95
+ const filtered = measurements.filter(m => m.timestamp >= cutoff);
96
+ this.measurements.set(measurement.sliId, filtered);
97
+ // Update dependent SLOs
98
+ this.updateDependentSLOs(measurement.sliId);
99
+ }
100
+ /**
101
+ * Get measurements for an SLI
102
+ */
103
+ getMeasurements(sliId, windowMs) {
104
+ const measurements = this.measurements.get(sliId) || [];
105
+ if (!windowMs) {
106
+ return measurements;
107
+ }
108
+ const cutoff = Date.now() - windowMs;
109
+ return measurements.filter(m => m.timestamp >= cutoff);
110
+ }
111
+ /**
112
+ * Calculate SLO result
113
+ */
114
+ calculateSLOResult(sloId) {
115
+ const slo = this.slos.get(sloId);
116
+ if (!slo) {
117
+ return null;
118
+ }
119
+ // Get measurements for all SLIs in the SLO
120
+ const windowStart = Date.now() - slo.windowMs;
121
+ const sliResults = [];
122
+ for (const sliId of slo.sliIds) {
123
+ const sli = this.slis.get(sliId);
124
+ if (!sli)
125
+ continue;
126
+ const measurements = this.getMeasurements(sliId, slo.windowMs);
127
+ if (measurements.length === 0)
128
+ continue;
129
+ // Get the most recent measurement or aggregate
130
+ const latest = measurements[measurements.length - 1];
131
+ sliResults.push({
132
+ sliId: sli.id,
133
+ name: sli.name,
134
+ value: latest.value,
135
+ target: slo.target,
136
+ contribution: 1 / slo.sliIds.length // Equal weight by default
137
+ });
138
+ }
139
+ if (sliResults.length === 0) {
140
+ return null;
141
+ }
142
+ // Calculate weighted average for SLO value
143
+ const current = sliResults.reduce((sum, s) => sum + s.value * s.contribution, 0);
144
+ // Calculate error budget
145
+ const errorBudget = this.calculateErrorBudget(slo, current);
146
+ // Determine status
147
+ const status = this.calculator.determineStatus(current, slo.target, this.options.warningThreshold);
148
+ // Update SLO
149
+ slo.currentValue = current;
150
+ slo.status = status;
151
+ slo.errorBudget = errorBudget;
152
+ return {
153
+ sloId: slo.id,
154
+ name: slo.name,
155
+ target: slo.target,
156
+ current,
157
+ status,
158
+ errorBudget: {
159
+ initial: errorBudget.initialBudget,
160
+ remaining: errorBudget.remainingBudget,
161
+ burned: errorBudget.initialBudget - errorBudget.remainingBudget,
162
+ burnRate: errorBudget.remainingBudget > 0
163
+ ? (errorBudget.initialBudget - errorBudget.remainingBudget) / errorBudget.initialBudget
164
+ : 1
165
+ },
166
+ slis: sliResults
167
+ };
168
+ }
169
+ /**
170
+ * Calculate all SLO results
171
+ */
172
+ calculateAllResults() {
173
+ const results = [];
174
+ for (const sloId of this.slos.keys()) {
175
+ const result = this.calculateSLOResult(sloId);
176
+ if (result) {
177
+ results.push(result);
178
+ }
179
+ }
180
+ return results;
181
+ }
182
+ /**
183
+ * Generate SLO report
184
+ */
185
+ generateReport(period) {
186
+ const results = this.calculateAllResults();
187
+ const summary = {
188
+ total: results.length,
189
+ healthy: results.filter(r => r.status === 'healthy').length,
190
+ warning: results.filter(r => r.status === 'warning').length,
191
+ breached: results.filter(r => r.status === 'breached').length
192
+ };
193
+ const overallStatus = summary.breached > 0 ? 'breached'
194
+ : summary.warning > 0 ? 'warning'
195
+ : summary.healthy > 0 ? 'healthy'
196
+ : 'unknown';
197
+ return {
198
+ id: `report_${Date.now()}`,
199
+ timestamp: Date.now(),
200
+ period: period || {
201
+ start: Date.now() - this.getLongestWindow(),
202
+ end: Date.now()
203
+ },
204
+ slos: results,
205
+ status: overallStatus,
206
+ summary
207
+ };
208
+ }
209
+ /**
210
+ * Get error budget for an SLO
211
+ */
212
+ getErrorBudget(sloId) {
213
+ const slo = this.slos.get(sloId);
214
+ if (!slo) {
215
+ return null;
216
+ }
217
+ const result = this.calculateSLOResult(sloId);
218
+ if (!result) {
219
+ return slo.errorBudget;
220
+ }
221
+ return slo.errorBudget;
222
+ }
223
+ /**
224
+ * Calculate burn rate for an SLO
225
+ */
226
+ calculateBurnRate(sloId) {
227
+ const slo = this.slos.get(sloId);
228
+ if (!slo) {
229
+ return null;
230
+ }
231
+ // Get all measurements for SLIs in this SLO
232
+ const allMeasurements = [];
233
+ for (const sliId of slo.sliIds) {
234
+ const measurements = this.getMeasurements(sliId, slo.windowMs);
235
+ allMeasurements.push(...measurements);
236
+ }
237
+ if (allMeasurements.length === 0) {
238
+ return null;
239
+ }
240
+ return this.calculator.calculateBurnRate(allMeasurements, slo.target, slo.windowMs);
241
+ }
242
+ /**
243
+ * Get violations for an SLO
244
+ */
245
+ getViolations(sloId) {
246
+ if (sloId) {
247
+ return this.violations.filter(v => v.sloId === sloId);
248
+ }
249
+ return this.violations;
250
+ }
251
+ /**
252
+ * Clear violations
253
+ */
254
+ clearViolations(sloId) {
255
+ if (sloId) {
256
+ this.violations = this.violations.filter(v => v.sloId !== sloId);
257
+ }
258
+ else {
259
+ this.violations = [];
260
+ }
261
+ }
262
+ /**
263
+ * Resolve a violation
264
+ */
265
+ resolveViolation(violationId) {
266
+ const violation = this.violations.find(v => v.id === violationId);
267
+ if (violation) {
268
+ violation.resolved = true;
269
+ violation.resolvedAt = Date.now();
270
+ }
271
+ }
272
+ /**
273
+ * Calculate error budget from current value and target
274
+ */
275
+ calculateErrorBudget(slo, currentValue) {
276
+ const initialBudget = 100 - slo.target;
277
+ const burned = Math.max(0, slo.target - currentValue);
278
+ const remaining = Math.max(0, initialBudget - burned);
279
+ return {
280
+ ...slo.errorBudget,
281
+ initialBudget,
282
+ remainingBudget: remaining
283
+ };
284
+ }
285
+ /**
286
+ * Update SLOs that depend on an SLI
287
+ */
288
+ updateDependentSLOs(sliId) {
289
+ for (const slo of this.slos.values()) {
290
+ if (!slo.sliIds.includes(sliId))
291
+ continue;
292
+ const result = this.calculateSLOResult(slo.id);
293
+ if (!result)
294
+ continue;
295
+ // Check for violations
296
+ if (this.options.trackViolations) {
297
+ this.checkForViolation(slo, result);
298
+ }
299
+ // Generate alerts
300
+ if (this.options.enableAlerts) {
301
+ this.generateAlerts(slo, result);
302
+ }
303
+ }
304
+ }
305
+ /**
306
+ * Check for SLO violation
307
+ */
308
+ checkForViolation(slo, result) {
309
+ const now = Date.now();
310
+ // Check if we just breached
311
+ if (result.status === 'breached' && slo.status !== 'breached') {
312
+ this.violations.push({
313
+ id: `violation_${now}_${slo.id}`,
314
+ sloId: slo.id,
315
+ timestamp: now,
316
+ value: result.current,
317
+ expected: result.target,
318
+ severity: 'critical',
319
+ resolved: false
320
+ });
321
+ }
322
+ // Check if we just hit warning
323
+ if (result.status === 'warning' && slo.status === 'healthy') {
324
+ this.violations.push({
325
+ id: `warning_${now}_${slo.id}`,
326
+ sloId: slo.id,
327
+ timestamp: now,
328
+ value: result.current,
329
+ expected: result.target,
330
+ severity: 'warning',
331
+ resolved: false
332
+ });
333
+ }
334
+ }
335
+ /**
336
+ * Generate alerts for SLO status
337
+ */
338
+ generateAlerts(slo, result) {
339
+ if (result.status === 'breached' || result.status === 'warning') {
340
+ this.options.onAlert({
341
+ sloId: slo.id,
342
+ sloName: slo.name,
343
+ severity: result.status === 'breached' ? 'critical' : 'warning',
344
+ message: `SLO "${slo.name}" is ${result.status}: ${result.current.toFixed(2)}% < ${result.target}%`,
345
+ currentValue: result.current,
346
+ target: result.target,
347
+ errorBudgetRemaining: result.errorBudget.remaining,
348
+ timestamp: Date.now()
349
+ });
350
+ }
351
+ }
352
+ /**
353
+ * Get the longest window from all SLOs
354
+ */
355
+ getLongestWindow() {
356
+ let max = 0;
357
+ for (const slo of this.slos.values()) {
358
+ if (slo.windowMs > max) {
359
+ max = slo.windowMs;
360
+ }
361
+ }
362
+ return max || 86400000 * 30; // Default 30 days
363
+ }
364
+ /**
365
+ * Clear all data
366
+ */
367
+ clear() {
368
+ this.slos.clear();
369
+ this.slis.clear();
370
+ this.measurements.clear();
371
+ this.violations = [];
372
+ }
373
+ }
374
+ /**
375
+ * Create an SLO tracker
376
+ */
377
+ export function createSLOTracker(options) {
378
+ return new SLOTracker(options);
379
+ }
@@ -0,0 +1,281 @@
1
+ /**
2
+ * QA360 SLO/SLI Management Module
3
+ *
4
+ * Types for Service Level Objectives and Service Level Indicators.
5
+ * Based on Google SRE methodology for reliability engineering.
6
+ */
7
+ /**
8
+ * SLO (Service Level Objective) - Target goal for reliability
9
+ */
10
+ export interface SLO {
11
+ /** Unique identifier */
12
+ id: string;
13
+ /** Display name */
14
+ name: string;
15
+ /** Description */
16
+ description?: string;
17
+ /** SLIs that contribute to this SLO */
18
+ sliIds: string[];
19
+ /** Target percentage (0-100) */
20
+ target: number;
21
+ /** Rolling window duration in milliseconds */
22
+ windowMs: number;
23
+ /** Error budget configuration */
24
+ errorBudget: ErrorBudget;
25
+ /** SLO status */
26
+ status: SLOStatus;
27
+ /** Current achievement */
28
+ currentValue?: number;
29
+ /** Metadata */
30
+ tags?: string[];
31
+ /** Owner/team */
32
+ owner?: string;
33
+ /** Creation timestamp */
34
+ createdAt: number;
35
+ /** Last update timestamp */
36
+ updatedAt: number;
37
+ }
38
+ /**
39
+ * Error Budget Configuration
40
+ */
41
+ export interface ErrorBudget {
42
+ /** Initial budget percentage (100 - target) */
43
+ initialBudget: number;
44
+ /** Remaining budget percentage */
45
+ remainingBudget: number;
46
+ /** Burn rate alerting thresholds */
47
+ alertThresholds: {
48
+ warning: number;
49
+ critical: number;
50
+ };
51
+ /** Actions when budget is exhausted */
52
+ onExhaustion: 'stop_deployments' | 'alert_only' | 'freeze_features' | 'custom';
53
+ }
54
+ /**
55
+ * SLO Status
56
+ */
57
+ export type SLOStatus = 'healthy' | 'warning' | 'breached' | 'unknown';
58
+ /**
59
+ * SLI (Service Level Indicator) - Metric that measures reliability
60
+ */
61
+ export interface SLI {
62
+ /** Unique identifier */
63
+ id: string;
64
+ /** Display name */
65
+ name: string;
66
+ /** Description */
67
+ description?: string;
68
+ /** SLI type */
69
+ type: SLIType;
70
+ /** Metric source */
71
+ source: SLISource;
72
+ /** Query/fetch configuration */
73
+ query: SLIQuery;
74
+ /** Aggregation method */
75
+ aggregation: SLIAggregation;
76
+ /** Unit of measurement */
77
+ unit: SLIUnit;
78
+ /** Good/bad event definitions */
79
+ threshold: SLIThreshold;
80
+ /** SLI category */
81
+ category: SLICategory;
82
+ /** Metadata */
83
+ tags?: string[];
84
+ /** Creation timestamp */
85
+ createdAt: number;
86
+ /** Last update timestamp */
87
+ updatedAt: number;
88
+ }
89
+ /**
90
+ * SLI Types
91
+ */
92
+ export type SLIType = 'availability' | 'latency' | 'error_rate' | 'throughput' | 'durability' | 'coverage' | 'performance' | 'quality' | 'custom';
93
+ /**
94
+ * SLI Data Sources
95
+ */
96
+ export type SLISource = 'qa360_tests' | 'prometheus' | 'cloudwatch' | 'datadog' | 'grafana' | 'custom_api' | 'file' | 'manual';
97
+ /**
98
+ * SLI Query Configuration
99
+ */
100
+ export interface SLIQuery {
101
+ /** Query string for the metric source */
102
+ queryString: string;
103
+ /** Filters to apply */
104
+ filters?: Record<string, string>;
105
+ /** Grouping keys */
106
+ groupBy?: string[];
107
+ /** Time window for aggregation */
108
+ timeWindow?: {
109
+ value: number;
110
+ unit: 'ms' | 's' | 'm' | 'h' | 'd';
111
+ };
112
+ }
113
+ /**
114
+ * SLI Aggregation Methods
115
+ */
116
+ export type SLIAggregation = 'count' | 'sum' | 'avg' | 'p50' | 'p95' | 'p99' | 'p99_9' | 'max' | 'min' | 'rate' | 'ratio';
117
+ /**
118
+ * SLI Units
119
+ */
120
+ export type SLIUnit = 'percentage' | 'milliseconds' | 'seconds' | 'count' | 'bytes' | 'requests_per_sec' | 'ratio' | 'boolean';
121
+ /**
122
+ * SLI Threshold Definition
123
+ */
124
+ export interface SLIThreshold {
125
+ /** Comparison operator */
126
+ operator: 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'ne';
127
+ /** Threshold value */
128
+ value: number;
129
+ /** Optional upper bound for range checks */
130
+ upperBound?: number;
131
+ }
132
+ /**
133
+ * SLI Categories
134
+ */
135
+ export type SLICategory = 'reliability' | 'performance' | 'quality' | 'security' | 'operational' | 'custom';
136
+ /**
137
+ * SLI Measurement Result
138
+ */
139
+ export interface SLIMeasurement {
140
+ /** SLI identifier */
141
+ sliId: string;
142
+ /** Timestamp of measurement */
143
+ timestamp: number;
144
+ /** Measured value */
145
+ value: number;
146
+ /** Total events (for ratios) */
147
+ total?: number;
148
+ /** Good events (for ratios) */
149
+ good?: number;
150
+ /** Bad events (for ratios) */
151
+ bad?: number;
152
+ /** Unit */
153
+ unit: SLIUnit;
154
+ /** Window start */
155
+ windowStart: number;
156
+ /** Window end: number */
157
+ windowEnd: number;
158
+ }
159
+ /**
160
+ * SLO Report
161
+ */
162
+ export interface SLOReport {
163
+ /** Report identifier */
164
+ id: string;
165
+ /** Timestamp */
166
+ timestamp: number;
167
+ /** Reporting period */
168
+ period: {
169
+ start: number;
170
+ end: number;
171
+ };
172
+ /** SLO results */
173
+ slos: SLOResult[];
174
+ /** Overall status */
175
+ status: SLOStatus;
176
+ /** Summary metrics */
177
+ summary: {
178
+ total: number;
179
+ healthy: number;
180
+ warning: number;
181
+ breached: number;
182
+ };
183
+ }
184
+ /**
185
+ * SLO Result for a single SLO
186
+ */
187
+ export interface SLOResult {
188
+ /** SLO identifier */
189
+ sloId: string;
190
+ /** SLO name */
191
+ name: string;
192
+ /** Target value */
193
+ target: number;
194
+ /** Current value */
195
+ current: number;
196
+ /** Achievement status */
197
+ status: SLOStatus;
198
+ /** Error budget info */
199
+ errorBudget: {
200
+ initial: number;
201
+ remaining: number;
202
+ burned: number;
203
+ burnRate: number;
204
+ };
205
+ /** Contributing SLI results */
206
+ slis: {
207
+ sliId: string;
208
+ name: string;
209
+ value: number;
210
+ target: number;
211
+ contribution: number;
212
+ }[];
213
+ }
214
+ /**
215
+ * Error Budget Burn Rate
216
+ */
217
+ export interface BurnRate {
218
+ /** Current burn rate (multiple of normal) */
219
+ current: number;
220
+ /** Status */
221
+ status: 'healthy' | 'warning' | 'critical';
222
+ /** Projected exhaustion */
223
+ projectedExhaustion?: number;
224
+ /** Historical burn rates */
225
+ history: Array<{
226
+ timestamp: number;
227
+ rate: number;
228
+ }>;
229
+ }
230
+ /**
231
+ * SLO Configuration
232
+ */
233
+ export interface SLOConfig {
234
+ /** Enable SLO/SLI tracking */
235
+ enabled: boolean;
236
+ /** Default rolling window */
237
+ defaultWindowMs: number;
238
+ /** Default error budget behavior */
239
+ defaultOnExhaustion: ErrorBudget['onExhaustion'];
240
+ /** Alert thresholds */
241
+ alertThresholds: {
242
+ warning: number;
243
+ critical: number;
244
+ };
245
+ /** Data retention */
246
+ retention: {
247
+ measurements: number;
248
+ aggregated: number;
249
+ };
250
+ /** SLO definitions */
251
+ slos: SLO[];
252
+ /** SLI definitions */
253
+ slis: SLI[];
254
+ }
255
+ /**
256
+ * SLO Violation Event
257
+ */
258
+ export interface SLOViolation {
259
+ /** Unique identifier */
260
+ id: string;
261
+ /** SLO that was violated */
262
+ sloId: string;
263
+ /** Timestamp of violation */
264
+ timestamp: number;
265
+ /** Value at violation */
266
+ value: number;
267
+ /** Expected value */
268
+ expected: number;
269
+ /** Severity */
270
+ severity: 'warning' | 'critical';
271
+ /** Context */
272
+ context?: {
273
+ runId?: string;
274
+ gate?: string;
275
+ environment?: string;
276
+ };
277
+ /** Resolved flag */
278
+ resolved: boolean;
279
+ /** Resolution timestamp */
280
+ resolvedAt?: number;
281
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * QA360 SLO/SLI Management Module
3
+ *
4
+ * Types for Service Level Objectives and Service Level Indicators.
5
+ * Based on Google SRE methodology for reliability engineering.
6
+ */
7
+ export {};