@zintrust/workers 0.1.27

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 (178) hide show
  1. package/README.md +861 -0
  2. package/dist/AnomalyDetection.d.ts +102 -0
  3. package/dist/AnomalyDetection.js +321 -0
  4. package/dist/AutoScaler.d.ts +127 -0
  5. package/dist/AutoScaler.js +425 -0
  6. package/dist/BroadcastWorker.d.ts +21 -0
  7. package/dist/BroadcastWorker.js +24 -0
  8. package/dist/CanaryController.d.ts +103 -0
  9. package/dist/CanaryController.js +380 -0
  10. package/dist/ChaosEngineering.d.ts +79 -0
  11. package/dist/ChaosEngineering.js +216 -0
  12. package/dist/CircuitBreaker.d.ts +106 -0
  13. package/dist/CircuitBreaker.js +374 -0
  14. package/dist/ClusterLock.d.ts +90 -0
  15. package/dist/ClusterLock.js +385 -0
  16. package/dist/ComplianceManager.d.ts +177 -0
  17. package/dist/ComplianceManager.js +556 -0
  18. package/dist/DatacenterOrchestrator.d.ts +133 -0
  19. package/dist/DatacenterOrchestrator.js +404 -0
  20. package/dist/DeadLetterQueue.d.ts +122 -0
  21. package/dist/DeadLetterQueue.js +539 -0
  22. package/dist/HealthMonitor.d.ts +42 -0
  23. package/dist/HealthMonitor.js +301 -0
  24. package/dist/MultiQueueWorker.d.ts +89 -0
  25. package/dist/MultiQueueWorker.js +277 -0
  26. package/dist/NotificationWorker.d.ts +21 -0
  27. package/dist/NotificationWorker.js +23 -0
  28. package/dist/Observability.d.ts +153 -0
  29. package/dist/Observability.js +530 -0
  30. package/dist/PluginManager.d.ts +123 -0
  31. package/dist/PluginManager.js +392 -0
  32. package/dist/PriorityQueue.d.ts +117 -0
  33. package/dist/PriorityQueue.js +244 -0
  34. package/dist/ResourceMonitor.d.ts +164 -0
  35. package/dist/ResourceMonitor.js +605 -0
  36. package/dist/SLAMonitor.d.ts +110 -0
  37. package/dist/SLAMonitor.js +274 -0
  38. package/dist/WorkerFactory.d.ts +193 -0
  39. package/dist/WorkerFactory.js +1507 -0
  40. package/dist/WorkerInit.d.ts +85 -0
  41. package/dist/WorkerInit.js +223 -0
  42. package/dist/WorkerMetrics.d.ts +114 -0
  43. package/dist/WorkerMetrics.js +509 -0
  44. package/dist/WorkerRegistry.d.ts +145 -0
  45. package/dist/WorkerRegistry.js +319 -0
  46. package/dist/WorkerShutdown.d.ts +61 -0
  47. package/dist/WorkerShutdown.js +159 -0
  48. package/dist/WorkerVersioning.d.ts +107 -0
  49. package/dist/WorkerVersioning.js +300 -0
  50. package/dist/build-manifest.json +462 -0
  51. package/dist/config/workerConfig.d.ts +3 -0
  52. package/dist/config/workerConfig.js +19 -0
  53. package/dist/createQueueWorker.d.ts +23 -0
  54. package/dist/createQueueWorker.js +113 -0
  55. package/dist/dashboard/index.d.ts +1 -0
  56. package/dist/dashboard/index.js +1 -0
  57. package/dist/dashboard/types.d.ts +117 -0
  58. package/dist/dashboard/types.js +1 -0
  59. package/dist/dashboard/workers-api.d.ts +4 -0
  60. package/dist/dashboard/workers-api.js +638 -0
  61. package/dist/dashboard/workers-dashboard-ui.d.ts +3 -0
  62. package/dist/dashboard/workers-dashboard-ui.js +1026 -0
  63. package/dist/dashboard/workers-dashboard.d.ts +4 -0
  64. package/dist/dashboard/workers-dashboard.js +904 -0
  65. package/dist/helper/index.d.ts +5 -0
  66. package/dist/helper/index.js +10 -0
  67. package/dist/http/WorkerApiController.d.ts +38 -0
  68. package/dist/http/WorkerApiController.js +312 -0
  69. package/dist/http/WorkerController.d.ts +374 -0
  70. package/dist/http/WorkerController.js +1351 -0
  71. package/dist/http/middleware/CustomValidation.d.ts +92 -0
  72. package/dist/http/middleware/CustomValidation.js +270 -0
  73. package/dist/http/middleware/DatacenterValidator.d.ts +3 -0
  74. package/dist/http/middleware/DatacenterValidator.js +94 -0
  75. package/dist/http/middleware/EditWorkerValidation.d.ts +7 -0
  76. package/dist/http/middleware/EditWorkerValidation.js +55 -0
  77. package/dist/http/middleware/FeaturesValidator.d.ts +3 -0
  78. package/dist/http/middleware/FeaturesValidator.js +60 -0
  79. package/dist/http/middleware/InfrastructureValidator.d.ts +31 -0
  80. package/dist/http/middleware/InfrastructureValidator.js +226 -0
  81. package/dist/http/middleware/OptionsValidator.d.ts +3 -0
  82. package/dist/http/middleware/OptionsValidator.js +112 -0
  83. package/dist/http/middleware/PayloadSanitizer.d.ts +7 -0
  84. package/dist/http/middleware/PayloadSanitizer.js +42 -0
  85. package/dist/http/middleware/ProcessorPathSanitizer.d.ts +3 -0
  86. package/dist/http/middleware/ProcessorPathSanitizer.js +74 -0
  87. package/dist/http/middleware/QueueNameSanitizer.d.ts +3 -0
  88. package/dist/http/middleware/QueueNameSanitizer.js +45 -0
  89. package/dist/http/middleware/ValidateDriver.d.ts +7 -0
  90. package/dist/http/middleware/ValidateDriver.js +20 -0
  91. package/dist/http/middleware/VersionSanitizer.d.ts +3 -0
  92. package/dist/http/middleware/VersionSanitizer.js +25 -0
  93. package/dist/http/middleware/WorkerNameSanitizer.d.ts +3 -0
  94. package/dist/http/middleware/WorkerNameSanitizer.js +46 -0
  95. package/dist/http/middleware/WorkerValidationChain.d.ts +27 -0
  96. package/dist/http/middleware/WorkerValidationChain.js +185 -0
  97. package/dist/index.d.ts +46 -0
  98. package/dist/index.js +48 -0
  99. package/dist/routes/workers.d.ts +12 -0
  100. package/dist/routes/workers.js +81 -0
  101. package/dist/storage/WorkerStore.d.ts +45 -0
  102. package/dist/storage/WorkerStore.js +195 -0
  103. package/dist/type.d.ts +76 -0
  104. package/dist/type.js +1 -0
  105. package/dist/ui/router/ui.d.ts +3 -0
  106. package/dist/ui/router/ui.js +83 -0
  107. package/dist/ui/types/worker-ui.d.ts +229 -0
  108. package/dist/ui/types/worker-ui.js +5 -0
  109. package/package.json +53 -0
  110. package/src/AnomalyDetection.ts +434 -0
  111. package/src/AutoScaler.ts +654 -0
  112. package/src/BroadcastWorker.ts +34 -0
  113. package/src/CanaryController.ts +531 -0
  114. package/src/ChaosEngineering.ts +301 -0
  115. package/src/CircuitBreaker.ts +495 -0
  116. package/src/ClusterLock.ts +499 -0
  117. package/src/ComplianceManager.ts +815 -0
  118. package/src/DatacenterOrchestrator.ts +561 -0
  119. package/src/DeadLetterQueue.ts +733 -0
  120. package/src/HealthMonitor.ts +390 -0
  121. package/src/MultiQueueWorker.ts +431 -0
  122. package/src/NotificationWorker.ts +33 -0
  123. package/src/Observability.ts +696 -0
  124. package/src/PluginManager.ts +551 -0
  125. package/src/PriorityQueue.ts +351 -0
  126. package/src/ResourceMonitor.ts +769 -0
  127. package/src/SLAMonitor.ts +408 -0
  128. package/src/WorkerFactory.ts +2108 -0
  129. package/src/WorkerInit.ts +313 -0
  130. package/src/WorkerMetrics.ts +709 -0
  131. package/src/WorkerRegistry.ts +443 -0
  132. package/src/WorkerShutdown.ts +210 -0
  133. package/src/WorkerVersioning.ts +422 -0
  134. package/src/config/workerConfig.ts +25 -0
  135. package/src/createQueueWorker.ts +174 -0
  136. package/src/dashboard/index.ts +6 -0
  137. package/src/dashboard/types.ts +141 -0
  138. package/src/dashboard/workers-api.ts +785 -0
  139. package/src/dashboard/zintrust.svg +30 -0
  140. package/src/helper/index.ts +11 -0
  141. package/src/http/WorkerApiController.ts +369 -0
  142. package/src/http/WorkerController.ts +1512 -0
  143. package/src/http/middleware/CustomValidation.ts +360 -0
  144. package/src/http/middleware/DatacenterValidator.ts +124 -0
  145. package/src/http/middleware/EditWorkerValidation.ts +74 -0
  146. package/src/http/middleware/FeaturesValidator.ts +82 -0
  147. package/src/http/middleware/InfrastructureValidator.ts +295 -0
  148. package/src/http/middleware/OptionsValidator.ts +144 -0
  149. package/src/http/middleware/PayloadSanitizer.ts +52 -0
  150. package/src/http/middleware/ProcessorPathSanitizer.ts +86 -0
  151. package/src/http/middleware/QueueNameSanitizer.ts +55 -0
  152. package/src/http/middleware/ValidateDriver.ts +29 -0
  153. package/src/http/middleware/VersionSanitizer.ts +30 -0
  154. package/src/http/middleware/WorkerNameSanitizer.ts +56 -0
  155. package/src/http/middleware/WorkerValidationChain.ts +230 -0
  156. package/src/index.ts +98 -0
  157. package/src/routes/workers.ts +154 -0
  158. package/src/storage/WorkerStore.ts +240 -0
  159. package/src/type.ts +89 -0
  160. package/src/types/queue-monitor.d.ts +38 -0
  161. package/src/types/queue-redis.d.ts +38 -0
  162. package/src/ui/README.md +13 -0
  163. package/src/ui/components/JsonEditor.js +670 -0
  164. package/src/ui/components/JsonViewer.js +387 -0
  165. package/src/ui/components/WorkerCard.js +178 -0
  166. package/src/ui/components/WorkerExpandPanel.js +257 -0
  167. package/src/ui/components/fetcher.js +42 -0
  168. package/src/ui/components/sla-scorecard.js +32 -0
  169. package/src/ui/components/styles.css +30 -0
  170. package/src/ui/components/table-expander.js +34 -0
  171. package/src/ui/integration/worker-ui-integration.js +565 -0
  172. package/src/ui/router/ui.ts +99 -0
  173. package/src/ui/services/workerApi.js +240 -0
  174. package/src/ui/types/worker-ui.ts +283 -0
  175. package/src/ui/utils/jsonValidator.js +444 -0
  176. package/src/ui/workers/index.html +202 -0
  177. package/src/ui/workers/main.js +1781 -0
  178. package/src/ui/workers/styles.css +1350 -0
@@ -0,0 +1,434 @@
1
+ /**
2
+ * Anomaly Detection
3
+ * Statistical anomaly detection with lightweight baselines
4
+ * Sealed namespace for immutability
5
+ */
6
+
7
+ import { ErrorFactory, Logger, generateUuid } from '@zintrust/core';
8
+ import { ResourceMonitor } from './ResourceMonitor';
9
+ import { WorkerMetrics, type MetricPoint, type MetricType } from './WorkerMetrics';
10
+
11
+ export interface IAnomalyConfig {
12
+ workerName: string;
13
+ metrics: MetricType[];
14
+ sensitivity: number; // 0-1 (higher = more sensitive)
15
+ learningPeriod: number; // Days to learn baseline
16
+ alertThreshold: number; // Confidence % to alert (0-1)
17
+ autoAdjust: boolean;
18
+ }
19
+
20
+ export interface IMetric {
21
+ metricType: MetricType;
22
+ value: number;
23
+ timestamp: Date;
24
+ }
25
+
26
+ export interface IAnomaly {
27
+ id: string;
28
+ timestamp: Date;
29
+ workerName: string;
30
+ metric: MetricType;
31
+ actual: number;
32
+ expected: number;
33
+ deviation: number;
34
+ confidence: number;
35
+ severity: 'low' | 'medium' | 'high' | 'critical';
36
+ possibleCauses: string[];
37
+ recommendations: string[];
38
+ }
39
+
40
+ export interface IPrediction {
41
+ workerName: string;
42
+ horizonHours: number;
43
+ riskScore: number;
44
+ expectedErrorRate: number;
45
+ summary: string;
46
+ }
47
+
48
+ export interface IRootCauseAnalysis {
49
+ anomalyId: string;
50
+ suspectedCauses: string[];
51
+ supportingSignals: Record<string, number>;
52
+ }
53
+
54
+ export interface IForecast {
55
+ workerName: string;
56
+ metric: MetricType;
57
+ horizonHours: number;
58
+ forecast: number;
59
+ confidence: number;
60
+ }
61
+
62
+ export interface IRecommendation {
63
+ action: string;
64
+ reason: string;
65
+ priority: 'low' | 'medium' | 'high';
66
+ }
67
+
68
+ type MetricStats = {
69
+ mean: number;
70
+ variance: number;
71
+ count: number;
72
+ updatedAt: Date;
73
+ };
74
+
75
+ const configs = new Map<string, IAnomalyConfig>();
76
+ const models = new Map<string, Map<MetricType, MetricStats>>();
77
+
78
+ const updateStats = (stats: MetricStats, value: number): MetricStats => {
79
+ const count = stats.count + 1;
80
+ const delta = value - stats.mean;
81
+ const mean = stats.mean + delta / count;
82
+ const delta2 = value - mean;
83
+ const variance = stats.variance + delta * delta2;
84
+
85
+ return {
86
+ mean,
87
+ variance,
88
+ count,
89
+ updatedAt: new Date(),
90
+ };
91
+ };
92
+
93
+ const buildStats = (values: number[]): MetricStats => {
94
+ if (values.length === 0) {
95
+ return { mean: 0, variance: 0, count: 0, updatedAt: new Date() };
96
+ }
97
+
98
+ let mean = 0;
99
+ let variance = 0;
100
+ let count = 0;
101
+
102
+ values.forEach((value) => {
103
+ const updated = updateStats({ mean, variance, count, updatedAt: new Date() }, value);
104
+ mean = updated.mean;
105
+ variance = updated.variance;
106
+ count = updated.count;
107
+ });
108
+
109
+ return { mean, variance, count, updatedAt: new Date() };
110
+ };
111
+
112
+ const getStdDev = (stats: MetricStats): number => {
113
+ if (stats.count <= 1) return 0;
114
+ return Math.sqrt(stats.variance / (stats.count - 1));
115
+ };
116
+
117
+ const getThreshold = (sensitivity: number): number => {
118
+ const clamped = Math.min(1, Math.max(0, sensitivity));
119
+ return Math.min(3, Math.max(1, 3 - clamped * 2));
120
+ };
121
+
122
+ const buildPossibleCauses = (metric: MetricType): string[] => {
123
+ switch (metric) {
124
+ case 'duration':
125
+ return ['Increased processing time', 'Downstream dependency latency'];
126
+ case 'errors':
127
+ return ['Increased failure rate', 'New error conditions'];
128
+ case 'cpu':
129
+ return ['Resource saturation', 'Inefficient processing logic'];
130
+ case 'memory':
131
+ return ['Memory leak risk', 'Increased payload size'];
132
+ case 'queue-size':
133
+ return ['Traffic spike', 'Worker throttling'];
134
+ default:
135
+ return ['Unexpected workload change'];
136
+ }
137
+ };
138
+
139
+ const buildRecommendations = (metric: MetricType): string[] => {
140
+ switch (metric) {
141
+ case 'duration':
142
+ return ['Review slow job traces', 'Scale worker concurrency temporarily'];
143
+ case 'errors':
144
+ return ['Inspect recent failures', 'Review circuit breaker events'];
145
+ case 'cpu':
146
+ return ['Add capacity or optimize processing', 'Monitor CPU hotspots'];
147
+ case 'memory':
148
+ return ['Inspect memory usage', 'Enable heap snapshots'];
149
+ default:
150
+ return ['Monitor trends and adjust thresholds'];
151
+ }
152
+ };
153
+
154
+ const selectSeverity = (zScore: number): IAnomaly['severity'] => {
155
+ if (zScore >= 3.5) return 'critical';
156
+ if (zScore >= 2.5) return 'high';
157
+ if (zScore >= 1.8) return 'medium';
158
+ return 'low';
159
+ };
160
+
161
+ const ensureConfig = (workerName: string): IAnomalyConfig => {
162
+ const config = configs.get(workerName);
163
+ if (!config) {
164
+ throw ErrorFactory.createNotFoundError(`Anomaly config not found for worker "${workerName}"`);
165
+ }
166
+ return config;
167
+ };
168
+
169
+ const ensureModelMap = (workerName: string): Map<MetricType, MetricStats> => {
170
+ let map = models.get(workerName);
171
+ if (!map) {
172
+ map = new Map();
173
+ models.set(workerName, map);
174
+ }
175
+ return map;
176
+ };
177
+
178
+ const mapPoints = (metric: MetricType, points: ReadonlyArray<MetricPoint>): IMetric[] =>
179
+ points.map((point) => ({
180
+ metricType: metric,
181
+ value: point.value,
182
+ timestamp: point.timestamp,
183
+ }));
184
+
185
+ /**
186
+ * Anomaly Detection - Sealed namespace
187
+ */
188
+ export const AnomalyDetection = Object.freeze({
189
+ /**
190
+ * Configure anomaly detection for a worker
191
+ */
192
+ configure(config: IAnomalyConfig): void {
193
+ configs.set(config.workerName, { ...config });
194
+ Logger.info(`Anomaly detection configured for ${config.workerName}`);
195
+ },
196
+
197
+ /**
198
+ * Train baseline model
199
+ */
200
+ trainModel(workerName: string, historicalData: IMetric[]): void {
201
+ const config = ensureConfig(workerName);
202
+ const modelMap = ensureModelMap(workerName);
203
+
204
+ const metrics = config.metrics;
205
+ metrics.forEach((metric) => {
206
+ const values = historicalData
207
+ .filter((item) => item.metricType === metric)
208
+ .map((item) => item.value);
209
+
210
+ modelMap.set(metric, buildStats(values));
211
+ });
212
+
213
+ Logger.info(`Anomaly model trained for ${workerName}`);
214
+ },
215
+
216
+ /**
217
+ * Update baseline model with recent data
218
+ */
219
+ updateModel(workerName: string, recentData: IMetric[]): void {
220
+ ensureConfig(workerName);
221
+ const modelMap = ensureModelMap(workerName);
222
+
223
+ recentData.forEach((item) => {
224
+ const current = modelMap.get(item.metricType) ?? {
225
+ mean: 0,
226
+ variance: 0,
227
+ count: 0,
228
+ updatedAt: new Date(),
229
+ };
230
+
231
+ modelMap.set(item.metricType, updateStats(current, item.value));
232
+ });
233
+ },
234
+
235
+ /**
236
+ * Detect anomalies for a worker
237
+ */
238
+ async detectAnomalies(workerName: string): Promise<IAnomaly[]> {
239
+ const config = ensureConfig(workerName);
240
+ const modelMap = ensureModelMap(workerName);
241
+
242
+ const range = {
243
+ start: new Date(Date.now() - 60 * 60 * 1000),
244
+ end: new Date(),
245
+ };
246
+
247
+ const results = await Promise.all(
248
+ config.metrics.map(async (metric) => {
249
+ const entry = await WorkerMetrics.query({
250
+ workerName,
251
+ metricType: metric,
252
+ granularity: 'hourly',
253
+ startDate: range.start,
254
+ endDate: range.end,
255
+ });
256
+
257
+ const points = entry.points;
258
+ if (points.length === 0) return null;
259
+
260
+ const stats = modelMap.get(metric) ?? buildStats(points.map((point) => point.value));
261
+ modelMap.set(metric, stats);
262
+
263
+ const latest = points.at(-1);
264
+ if (!latest) return null;
265
+
266
+ const stdDev = getStdDev(stats);
267
+ if (stdDev === 0) return null;
268
+
269
+ const zScore = Math.abs((latest.value - stats.mean) / stdDev);
270
+ const threshold = getThreshold(config.sensitivity);
271
+ const confidence = Math.min(1, zScore / threshold);
272
+
273
+ if (zScore < threshold || confidence < config.alertThreshold) return null;
274
+
275
+ return {
276
+ id: generateUuid(),
277
+ timestamp: latest.timestamp,
278
+ workerName,
279
+ metric,
280
+ actual: latest.value,
281
+ expected: stats.mean,
282
+ deviation: zScore,
283
+ confidence,
284
+ severity: selectSeverity(zScore),
285
+ possibleCauses: buildPossibleCauses(metric),
286
+ recommendations: buildRecommendations(metric),
287
+ } as IAnomaly;
288
+ })
289
+ );
290
+
291
+ return results.filter((item): item is IAnomaly => item !== null);
292
+ },
293
+
294
+ /**
295
+ * Predict failure risk for a worker
296
+ */
297
+ async predictFailure(workerName: string, horizonHours: number): Promise<IPrediction> {
298
+ ensureConfig(workerName);
299
+
300
+ const range = {
301
+ start: new Date(Date.now() - 24 * 60 * 60 * 1000),
302
+ end: new Date(),
303
+ };
304
+
305
+ const [errors, processed] = await Promise.all([
306
+ WorkerMetrics.aggregate({
307
+ workerName,
308
+ metricType: 'errors',
309
+ granularity: 'hourly',
310
+ startDate: range.start,
311
+ endDate: range.end,
312
+ }),
313
+ WorkerMetrics.aggregate({
314
+ workerName,
315
+ metricType: 'processed',
316
+ granularity: 'hourly',
317
+ startDate: range.start,
318
+ endDate: range.end,
319
+ }),
320
+ ]);
321
+
322
+ const errorRate = processed.total > 0 ? errors.total / processed.total : 0;
323
+ const riskScore = Math.min(1, errorRate * 5);
324
+
325
+ let summary = 'Low failure risk detected';
326
+ if (riskScore >= 0.8) {
327
+ summary = 'High failure risk detected';
328
+ } else if (riskScore >= 0.4) {
329
+ summary = 'Moderate failure risk detected';
330
+ }
331
+
332
+ return {
333
+ workerName,
334
+ horizonHours,
335
+ riskScore,
336
+ expectedErrorRate: errorRate,
337
+ summary,
338
+ };
339
+ },
340
+
341
+ /**
342
+ * Analyze root cause for an anomaly
343
+ */
344
+ analyzeRootCause(anomaly: IAnomaly): IRootCauseAnalysis {
345
+ const usage = ResourceMonitor.getCurrentUsage(anomaly.workerName);
346
+ const signals = {
347
+ cpu: usage.cpu,
348
+ memory: usage.memory.percent,
349
+ };
350
+
351
+ const suspected = [...anomaly.possibleCauses];
352
+ if (usage.cpu > 80) suspected.push('CPU saturation');
353
+ if (usage.memory.percent > 80) suspected.push('Memory pressure');
354
+
355
+ return {
356
+ anomalyId: anomaly.id,
357
+ suspectedCauses: suspected,
358
+ supportingSignals: signals,
359
+ };
360
+ },
361
+
362
+ /**
363
+ * Forecast a metric
364
+ */
365
+ async forecastMetric(workerName: string, metric: MetricType, hours: number): Promise<IForecast> {
366
+ ensureConfig(workerName);
367
+
368
+ const entry = await WorkerMetrics.query({
369
+ workerName,
370
+ metricType: metric,
371
+ granularity: 'hourly',
372
+ startDate: new Date(Date.now() - 24 * 60 * 60 * 1000),
373
+ endDate: new Date(),
374
+ });
375
+
376
+ const values = entry.points.map((point) => point.value);
377
+ const average = values.length > 0 ? values.reduce((sum, v) => sum + v, 0) / values.length : 0;
378
+
379
+ return {
380
+ workerName,
381
+ metric,
382
+ horizonHours: hours,
383
+ forecast: average,
384
+ confidence: values.length > 10 ? 0.7 : 0.4,
385
+ };
386
+ },
387
+
388
+ /**
389
+ * Generate recommendations for an anomaly
390
+ */
391
+ getRecommendations(anomaly: IAnomaly): IRecommendation[] {
392
+ return anomaly.recommendations.map((rec) => ({
393
+ action: rec,
394
+ reason: `Metric ${anomaly.metric} deviated from baseline`,
395
+ priority: anomaly.severity === 'critical' ? 'high' : 'medium',
396
+ }));
397
+ },
398
+
399
+ /**
400
+ * Attempt auto-remediation
401
+ */
402
+ autoRemediate(_anomaly: IAnomaly): boolean {
403
+ return false;
404
+ },
405
+
406
+ /**
407
+ * Helper: build training data from metrics
408
+ */
409
+ async buildTrainingData(workerName: string): Promise<IMetric[]> {
410
+ const config = ensureConfig(workerName);
411
+ const range = {
412
+ start: new Date(Date.now() - config.learningPeriod * 24 * 60 * 60 * 1000),
413
+ end: new Date(),
414
+ };
415
+
416
+ const batches = await Promise.all(
417
+ config.metrics.map(async (metric) => {
418
+ const entry = await WorkerMetrics.query({
419
+ workerName,
420
+ metricType: metric,
421
+ granularity: 'daily',
422
+ startDate: range.start,
423
+ endDate: range.end,
424
+ });
425
+
426
+ return mapPoints(metric, entry.points);
427
+ })
428
+ );
429
+
430
+ return batches.flat();
431
+ },
432
+ });
433
+
434
+ export default AnomalyDetection;