driftdetect-dashboard 0.1.1 → 0.4.2

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.
@@ -4,6 +4,9 @@
4
4
  * Reads and parses data from the .drift/ folder structure.
5
5
  * Provides methods for accessing patterns, violations, files, and configuration.
6
6
  *
7
+ * OPTIMIZED: Uses DataLake for fast reads with pre-computed views.
8
+ * Falls back to direct file reading when lake data is unavailable.
9
+ *
7
10
  * @requirements 1.6 - THE Dashboard_Server SHALL read pattern and violation data from the existing `.drift/` folder structure
8
11
  * @requirements 8.1 - THE Dashboard_Server SHALL expose GET `/api/patterns` to list all patterns
9
12
  * @requirements 8.2 - THE Dashboard_Server SHALL expose GET `/api/patterns/:id` to get pattern details with locations
@@ -235,20 +238,105 @@ export interface DashboardContractStats {
235
238
  totalMismatches: number;
236
239
  mismatchesByType: Record<string, number>;
237
240
  }
241
+ /**
242
+ * A snapshot of a single pattern's state at a point in time
243
+ */
244
+ export interface PatternSnapshot {
245
+ patternId: string;
246
+ patternName: string;
247
+ category: PatternCategory;
248
+ confidence: number;
249
+ locationCount: number;
250
+ outlierCount: number;
251
+ complianceRate: number;
252
+ status: PatternStatus;
253
+ }
254
+ /**
255
+ * Category summary in a snapshot
256
+ */
257
+ export interface CategorySummary {
258
+ patternCount: number;
259
+ avgConfidence: number;
260
+ totalLocations: number;
261
+ totalOutliers: number;
262
+ complianceRate: number;
263
+ }
264
+ /**
265
+ * A full snapshot of all patterns at a point in time
266
+ */
267
+ export interface HistorySnapshot {
268
+ timestamp: string;
269
+ date: string;
270
+ patterns: PatternSnapshot[];
271
+ summary: {
272
+ totalPatterns: number;
273
+ avgConfidence: number;
274
+ totalLocations: number;
275
+ totalOutliers: number;
276
+ overallComplianceRate: number;
277
+ byCategory: Record<string, CategorySummary>;
278
+ };
279
+ }
280
+ /**
281
+ * A detected regression or improvement
282
+ */
283
+ export interface PatternTrend {
284
+ patternId: string;
285
+ patternName: string;
286
+ category: PatternCategory;
287
+ type: 'regression' | 'improvement' | 'stable';
288
+ metric: 'confidence' | 'compliance' | 'outliers';
289
+ previousValue: number;
290
+ currentValue: number;
291
+ change: number;
292
+ changePercent: number;
293
+ severity: 'critical' | 'warning' | 'info';
294
+ firstSeen: string;
295
+ details: string;
296
+ }
297
+ /**
298
+ * Aggregated trends for the dashboard
299
+ */
300
+ export interface TrendSummary {
301
+ period: '7d' | '30d' | '90d';
302
+ startDate: string;
303
+ endDate: string;
304
+ regressions: PatternTrend[];
305
+ improvements: PatternTrend[];
306
+ stable: number;
307
+ overallTrend: 'improving' | 'declining' | 'stable';
308
+ healthDelta: number;
309
+ categoryTrends: Record<string, {
310
+ trend: 'improving' | 'declining' | 'stable';
311
+ avgConfidenceChange: number;
312
+ complianceChange: number;
313
+ }>;
314
+ }
238
315
  export declare class DriftDataReader {
239
316
  private readonly driftDir;
240
317
  private readonly patternsDir;
318
+ private readonly dataLake;
319
+ private lakeInitialized;
241
320
  constructor(driftDir: string);
242
321
  /**
243
322
  * Get the drift directory path
244
323
  */
245
324
  get directory(): string;
325
+ /**
326
+ * Initialize the data lake (lazy initialization)
327
+ */
328
+ private initializeLake;
246
329
  /**
247
330
  * Get all patterns, optionally filtered
331
+ * OPTIMIZED: Uses DataLake pattern shards for fast category-based queries
248
332
  *
249
333
  * @requirements 8.1 - List all patterns
250
334
  */
251
335
  getPatterns(query?: PatternQuery): Promise<DashboardPattern[]>;
336
+ /**
337
+ * Get patterns from DataLake (optimized path)
338
+ */
339
+ private getPatternsFromLake;
252
340
  /**
253
341
  * Get a single pattern by ID with all locations
254
342
  *
@@ -265,9 +353,14 @@ export declare class DriftDataReader {
265
353
  getViolations(query?: ViolationQuery): Promise<DashboardViolation[]>;
266
354
  /**
267
355
  * Get dashboard statistics
356
+ * OPTIMIZED: Uses DataLake status view for instant response
268
357
  * @requirements 8.9 - GET `/api/stats` to get overview statistics
269
358
  */
270
359
  getStats(): Promise<DashboardStats>;
360
+ /**
361
+ * Convert StatusView from DataLake to DashboardStats
362
+ */
363
+ private statusViewToStats;
271
364
  /**
272
365
  * Get the file tree structure
273
366
  * @requirements 8.7 - GET `/api/files` to get the file tree
@@ -407,5 +500,23 @@ export declare class DriftDataReader {
407
500
  * Filter contracts based on query
408
501
  */
409
502
  private filterContracts;
503
+ /**
504
+ * Get trend summary for pattern regressions and improvements
505
+ * OPTIMIZED: Uses DataLake trends view for instant response
506
+ */
507
+ getTrends(period?: '7d' | '30d' | '90d'): Promise<TrendSummary | null>;
508
+ /**
509
+ * Convert TrendsView from DataLake to TrendSummary
510
+ * TrendsView has: generatedAt, period, overallTrend, healthDelta, regressions, improvements, stableCount, categoryTrends
511
+ */
512
+ private trendsViewToSummary;
513
+ /**
514
+ * Get historical snapshots for charting
515
+ */
516
+ getSnapshots(limit?: number): Promise<HistorySnapshot[]>;
517
+ /**
518
+ * Calculate trend summary between two snapshots
519
+ */
520
+ private calculateTrendSummary;
410
521
  }
411
522
  //# sourceMappingURL=drift-data-reader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"drift-data-reader.d.ts","sourceRoot":"","sources":["../../src/server/drift-data-reader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"drift-data-reader.d.ts","sourceRoot":"","sources":["../../src/server/drift-data-reader.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,9 @@
4
4
  * Reads and parses data from the .drift/ folder structure.
5
5
  * Provides methods for accessing patterns, violations, files, and configuration.
6
6
  *
7
+ * OPTIMIZED: Uses DataLake for fast reads with pre-computed views.
8
+ * Falls back to direct file reading when lake data is unavailable.
9
+ *
7
10
  * @requirements 1.6 - THE Dashboard_Server SHALL read pattern and violation data from the existing `.drift/` folder structure
8
11
  * @requirements 8.1 - THE Dashboard_Server SHALL expose GET `/api/patterns` to list all patterns
9
12
  * @requirements 8.2 - THE Dashboard_Server SHALL expose GET `/api/patterns/:id` to get pattern details with locations
@@ -14,6 +17,7 @@
14
17
  */
15
18
  import * as fs from 'node:fs/promises';
16
19
  import * as path from 'node:path';
20
+ import { createDataLake } from 'driftdetect-core';
17
21
  // ============================================================================
18
22
  // Constants
19
23
  // ============================================================================
@@ -89,9 +93,15 @@ function generateViolationId(patternId, outlier) {
89
93
  export class DriftDataReader {
90
94
  driftDir;
91
95
  patternsDir;
96
+ dataLake;
97
+ lakeInitialized = false;
92
98
  constructor(driftDir) {
93
99
  this.driftDir = driftDir;
94
100
  this.patternsDir = path.join(driftDir, PATTERNS_DIR);
101
+ // Initialize DataLake for optimized reads
102
+ // rootDir is the parent of .drift/
103
+ const rootDir = path.dirname(driftDir);
104
+ this.dataLake = createDataLake({ rootDir });
95
105
  }
96
106
  /**
97
107
  * Get the drift directory path
@@ -99,14 +109,42 @@ export class DriftDataReader {
99
109
  get directory() {
100
110
  return this.driftDir;
101
111
  }
112
+ /**
113
+ * Initialize the data lake (lazy initialization)
114
+ */
115
+ async initializeLake() {
116
+ if (this.lakeInitialized)
117
+ return true;
118
+ try {
119
+ await this.dataLake.initialize();
120
+ this.lakeInitialized = true;
121
+ return true;
122
+ }
123
+ catch {
124
+ return false;
125
+ }
126
+ }
102
127
  /**
103
128
  * Get all patterns, optionally filtered
129
+ * OPTIMIZED: Uses DataLake pattern shards for fast category-based queries
104
130
  *
105
131
  * @requirements 8.1 - List all patterns
106
132
  */
107
133
  async getPatterns(query) {
134
+ // OPTIMIZATION: Try DataLake first for fast reads
135
+ if (await this.initializeLake()) {
136
+ try {
137
+ const lakePatterns = await this.getPatternsFromLake(query);
138
+ if (lakePatterns && lakePatterns.length > 0) {
139
+ return lakePatterns;
140
+ }
141
+ }
142
+ catch {
143
+ // Fall through to direct file reading
144
+ }
145
+ }
146
+ // Fallback: Read patterns from all status directories
108
147
  const patterns = [];
109
- // Read patterns from all status directories
110
148
  for (const status of STATUS_DIRS) {
111
149
  const statusDir = path.join(this.patternsDir, status);
112
150
  if (!(await fileExists(statusDir))) {
@@ -140,6 +178,56 @@ export class DriftDataReader {
140
178
  // Apply filters if provided
141
179
  return this.filterPatterns(patterns, query);
142
180
  }
181
+ /**
182
+ * Get patterns from DataLake (optimized path)
183
+ */
184
+ async getPatternsFromLake(query) {
185
+ try {
186
+ // Build query options for DataLake
187
+ const queryOptions = {
188
+ limit: 1000, // Get all patterns
189
+ };
190
+ if (query?.category) {
191
+ queryOptions.categories = [query.category];
192
+ }
193
+ if (query?.status && query.status !== 'all') {
194
+ queryOptions.status = query.status;
195
+ }
196
+ if (query?.minConfidence !== undefined) {
197
+ queryOptions.minConfidence = query.minConfidence;
198
+ }
199
+ if (query?.search) {
200
+ queryOptions.search = query.search;
201
+ }
202
+ const result = await this.dataLake.query.getPatterns(queryOptions);
203
+ if (result.items.length === 0 && result.total === 0) {
204
+ return null; // No data in lake, fall back to files
205
+ }
206
+ // Convert lake PatternSummary to DashboardPattern
207
+ return result.items.map(p => ({
208
+ id: p.id,
209
+ name: p.name,
210
+ category: p.category,
211
+ subcategory: p.subcategory,
212
+ status: p.status,
213
+ description: '', // PatternSummary doesn't include description
214
+ confidence: {
215
+ score: p.confidence,
216
+ level: p.confidenceLevel,
217
+ },
218
+ locationCount: p.locationCount,
219
+ outlierCount: p.outlierCount,
220
+ severity: p.severity || (p.outlierCount > 0 ? 'warning' : 'info'),
221
+ metadata: {
222
+ firstSeen: new Date().toISOString(),
223
+ lastSeen: new Date().toISOString(),
224
+ },
225
+ }));
226
+ }
227
+ catch {
228
+ return null;
229
+ }
230
+ }
143
231
  /**
144
232
  * Get a single pattern by ID with all locations
145
233
  *
@@ -224,9 +312,23 @@ export class DriftDataReader {
224
312
  }
225
313
  /**
226
314
  * Get dashboard statistics
315
+ * OPTIMIZED: Uses DataLake status view for instant response
227
316
  * @requirements 8.9 - GET `/api/stats` to get overview statistics
228
317
  */
229
318
  async getStats() {
319
+ // OPTIMIZATION: Try DataLake status view first (instant)
320
+ if (await this.initializeLake()) {
321
+ try {
322
+ const statusView = await this.dataLake.query.getStatus();
323
+ if (statusView) {
324
+ return this.statusViewToStats(statusView);
325
+ }
326
+ }
327
+ catch {
328
+ // Fall through to direct file reading
329
+ }
330
+ }
331
+ // Fallback: Compute from raw pattern files
230
332
  const patterns = await this.getPatterns();
231
333
  const violations = await this.getViolations();
232
334
  // Count patterns by status
@@ -304,6 +406,42 @@ export class DriftDataReader {
304
406
  lastScan,
305
407
  };
306
408
  }
409
+ /**
410
+ * Convert StatusView from DataLake to DashboardStats
411
+ */
412
+ statusViewToStats(view) {
413
+ return {
414
+ healthScore: view.health.score,
415
+ patterns: {
416
+ total: view.patterns.total,
417
+ byStatus: {
418
+ discovered: view.patterns.discovered,
419
+ approved: view.patterns.approved,
420
+ ignored: view.patterns.ignored,
421
+ },
422
+ byCategory: view.patterns.byCategory,
423
+ },
424
+ violations: {
425
+ total: view.issues.critical + view.issues.warnings,
426
+ bySeverity: {
427
+ error: view.issues.critical,
428
+ warning: view.issues.warnings,
429
+ info: 0,
430
+ hint: 0,
431
+ },
432
+ },
433
+ files: {
434
+ // StatusView doesn't track files, estimate from patterns
435
+ total: 0,
436
+ scanned: view.lastScan.filesScanned,
437
+ },
438
+ detectors: {
439
+ active: Object.keys(view.patterns.byCategory).length,
440
+ total: Object.keys(view.patterns.byCategory).length,
441
+ },
442
+ lastScan: view.lastScan.timestamp || null,
443
+ };
444
+ }
307
445
  /**
308
446
  * Get the file tree structure
309
447
  * @requirements 8.7 - GET `/api/files` to get the file tree
@@ -1147,5 +1285,266 @@ export class DriftDataReader {
1147
1285
  return true;
1148
1286
  });
1149
1287
  }
1288
+ // ==========================================================================
1289
+ // Trend / History Methods
1290
+ // ==========================================================================
1291
+ /**
1292
+ * Get trend summary for pattern regressions and improvements
1293
+ * OPTIMIZED: Uses DataLake trends view for instant response
1294
+ */
1295
+ async getTrends(period = '7d') {
1296
+ // OPTIMIZATION: Try DataLake trends view first
1297
+ if (await this.initializeLake()) {
1298
+ try {
1299
+ const trendsView = await this.dataLake.views.getTrendsView();
1300
+ if (trendsView) {
1301
+ return this.trendsViewToSummary(trendsView, period);
1302
+ }
1303
+ }
1304
+ catch {
1305
+ // Fall through to direct file reading
1306
+ }
1307
+ }
1308
+ // Fallback: Read from history snapshots directly
1309
+ const historyDir = path.join(this.driftDir, 'history', 'snapshots');
1310
+ if (!(await fileExists(historyDir))) {
1311
+ return null;
1312
+ }
1313
+ const days = period === '7d' ? 7 : period === '30d' ? 30 : 90;
1314
+ const now = new Date();
1315
+ const startDate = new Date(now);
1316
+ startDate.setDate(startDate.getDate() - days);
1317
+ // Get snapshots
1318
+ const files = await fs.readdir(historyDir);
1319
+ const jsonFiles = files.filter(f => f.endsWith('.json')).sort();
1320
+ if (jsonFiles.length < 2) {
1321
+ return null; // Need at least 2 snapshots to calculate trends
1322
+ }
1323
+ // Get latest and comparison snapshot
1324
+ const latestFile = jsonFiles[jsonFiles.length - 1];
1325
+ const latestContent = await fs.readFile(path.join(historyDir, latestFile), 'utf-8');
1326
+ const latestSnapshot = JSON.parse(latestContent);
1327
+ // Find snapshot closest to start date
1328
+ const startDateStr = startDate.toISOString().split('T')[0];
1329
+ let comparisonFile = jsonFiles[0];
1330
+ for (const file of jsonFiles) {
1331
+ const fileDate = file.replace('.json', '');
1332
+ if (fileDate <= startDateStr) {
1333
+ comparisonFile = file;
1334
+ }
1335
+ else {
1336
+ break;
1337
+ }
1338
+ }
1339
+ const comparisonContent = await fs.readFile(path.join(historyDir, comparisonFile), 'utf-8');
1340
+ const comparisonSnapshot = JSON.parse(comparisonContent);
1341
+ // Calculate trends
1342
+ return this.calculateTrendSummary(latestSnapshot, comparisonSnapshot, period);
1343
+ }
1344
+ /**
1345
+ * Convert TrendsView from DataLake to TrendSummary
1346
+ * TrendsView has: generatedAt, period, overallTrend, healthDelta, regressions, improvements, stableCount, categoryTrends
1347
+ */
1348
+ trendsViewToSummary(view, period) {
1349
+ // Calculate date range from period
1350
+ const now = new Date();
1351
+ const days = period === '7d' ? 7 : period === '30d' ? 30 : 90;
1352
+ const startDate = new Date(now);
1353
+ startDate.setDate(startDate.getDate() - days);
1354
+ // Convert TrendItem[] to PatternTrend[]
1355
+ const regressions = (view.regressions || []).map(r => ({
1356
+ patternId: r.patternId,
1357
+ patternName: r.patternName,
1358
+ category: r.category,
1359
+ type: 'regression',
1360
+ metric: r.metric,
1361
+ previousValue: r.previousValue,
1362
+ currentValue: r.currentValue,
1363
+ change: r.change,
1364
+ changePercent: r.previousValue > 0 ? (r.change / r.previousValue) * 100 : 0,
1365
+ severity: r.severity,
1366
+ firstSeen: view.generatedAt,
1367
+ details: `${r.metric} changed from ${r.previousValue} to ${r.currentValue}`,
1368
+ }));
1369
+ const improvements = (view.improvements || []).map(i => ({
1370
+ patternId: i.patternId,
1371
+ patternName: i.patternName,
1372
+ category: i.category,
1373
+ type: 'improvement',
1374
+ metric: i.metric,
1375
+ previousValue: i.previousValue,
1376
+ currentValue: i.currentValue,
1377
+ change: i.change,
1378
+ changePercent: i.previousValue > 0 ? (i.change / i.previousValue) * 100 : 0,
1379
+ severity: i.severity,
1380
+ firstSeen: view.generatedAt,
1381
+ details: `${i.metric} improved from ${i.previousValue} to ${i.currentValue}`,
1382
+ }));
1383
+ // Convert CategoryTrend to TrendSummary format
1384
+ const categoryTrends = {};
1385
+ for (const [category, trend] of Object.entries(view.categoryTrends || {})) {
1386
+ categoryTrends[category] = {
1387
+ trend: trend.trend,
1388
+ avgConfidenceChange: trend.avgConfidenceChange,
1389
+ complianceChange: trend.complianceChange,
1390
+ };
1391
+ }
1392
+ return {
1393
+ period,
1394
+ startDate: startDate.toISOString().split('T')[0],
1395
+ endDate: now.toISOString().split('T')[0],
1396
+ regressions,
1397
+ improvements,
1398
+ stable: view.stableCount || 0,
1399
+ overallTrend: view.overallTrend,
1400
+ healthDelta: view.healthDelta || 0,
1401
+ categoryTrends,
1402
+ };
1403
+ }
1404
+ /**
1405
+ * Get historical snapshots for charting
1406
+ */
1407
+ async getSnapshots(limit = 30) {
1408
+ const historyDir = path.join(this.driftDir, 'history', 'snapshots');
1409
+ if (!(await fileExists(historyDir))) {
1410
+ return [];
1411
+ }
1412
+ const files = await fs.readdir(historyDir);
1413
+ const jsonFiles = files.filter(f => f.endsWith('.json')).sort().slice(-limit);
1414
+ const snapshots = [];
1415
+ for (const file of jsonFiles) {
1416
+ try {
1417
+ const content = await fs.readFile(path.join(historyDir, file), 'utf-8');
1418
+ snapshots.push(JSON.parse(content));
1419
+ }
1420
+ catch (error) {
1421
+ console.error(`Error reading snapshot ${file}:`, error);
1422
+ }
1423
+ }
1424
+ return snapshots;
1425
+ }
1426
+ /**
1427
+ * Calculate trend summary between two snapshots
1428
+ */
1429
+ calculateTrendSummary(current, previous, period) {
1430
+ const regressions = [];
1431
+ const improvements = [];
1432
+ const previousMap = new Map(previous.patterns.map(p => [p.patternId, p]));
1433
+ // Thresholds
1434
+ const CONFIDENCE_THRESHOLD = 0.05;
1435
+ const COMPLIANCE_THRESHOLD = 0.10;
1436
+ const OUTLIER_THRESHOLD = 3;
1437
+ for (const currentPattern of current.patterns) {
1438
+ const prevPattern = previousMap.get(currentPattern.patternId);
1439
+ if (!prevPattern)
1440
+ continue;
1441
+ // Check confidence change
1442
+ const confidenceChange = currentPattern.confidence - prevPattern.confidence;
1443
+ if (Math.abs(confidenceChange) >= CONFIDENCE_THRESHOLD) {
1444
+ const trend = {
1445
+ patternId: currentPattern.patternId,
1446
+ patternName: currentPattern.patternName,
1447
+ category: currentPattern.category,
1448
+ type: confidenceChange < 0 ? 'regression' : 'improvement',
1449
+ metric: 'confidence',
1450
+ previousValue: prevPattern.confidence,
1451
+ currentValue: currentPattern.confidence,
1452
+ change: confidenceChange,
1453
+ changePercent: (confidenceChange / prevPattern.confidence) * 100,
1454
+ severity: confidenceChange <= -0.15 ? 'critical' : confidenceChange < 0 ? 'warning' : 'info',
1455
+ firstSeen: previous.timestamp,
1456
+ details: `Confidence ${confidenceChange < 0 ? 'dropped' : 'improved'} from ${(prevPattern.confidence * 100).toFixed(0)}% to ${(currentPattern.confidence * 100).toFixed(0)}%`,
1457
+ };
1458
+ if (trend.type === 'regression') {
1459
+ regressions.push(trend);
1460
+ }
1461
+ else {
1462
+ improvements.push(trend);
1463
+ }
1464
+ }
1465
+ // Check compliance change
1466
+ const complianceChange = currentPattern.complianceRate - prevPattern.complianceRate;
1467
+ if (Math.abs(complianceChange) >= COMPLIANCE_THRESHOLD) {
1468
+ const trend = {
1469
+ patternId: currentPattern.patternId,
1470
+ patternName: currentPattern.patternName,
1471
+ category: currentPattern.category,
1472
+ type: complianceChange < 0 ? 'regression' : 'improvement',
1473
+ metric: 'compliance',
1474
+ previousValue: prevPattern.complianceRate,
1475
+ currentValue: currentPattern.complianceRate,
1476
+ change: complianceChange,
1477
+ changePercent: prevPattern.complianceRate > 0 ? (complianceChange / prevPattern.complianceRate) * 100 : 0,
1478
+ severity: complianceChange <= -0.20 ? 'critical' : complianceChange < 0 ? 'warning' : 'info',
1479
+ firstSeen: previous.timestamp,
1480
+ details: `Compliance ${complianceChange < 0 ? 'dropped' : 'improved'} from ${(prevPattern.complianceRate * 100).toFixed(0)}% to ${(currentPattern.complianceRate * 100).toFixed(0)}%`,
1481
+ };
1482
+ if (trend.type === 'regression') {
1483
+ regressions.push(trend);
1484
+ }
1485
+ else {
1486
+ improvements.push(trend);
1487
+ }
1488
+ }
1489
+ // Check outlier increase
1490
+ const outlierChange = currentPattern.outlierCount - prevPattern.outlierCount;
1491
+ if (outlierChange >= OUTLIER_THRESHOLD) {
1492
+ regressions.push({
1493
+ patternId: currentPattern.patternId,
1494
+ patternName: currentPattern.patternName,
1495
+ category: currentPattern.category,
1496
+ type: 'regression',
1497
+ metric: 'outliers',
1498
+ previousValue: prevPattern.outlierCount,
1499
+ currentValue: currentPattern.outlierCount,
1500
+ change: outlierChange,
1501
+ changePercent: prevPattern.outlierCount > 0 ? (outlierChange / prevPattern.outlierCount) * 100 : 100,
1502
+ severity: outlierChange >= 10 ? 'critical' : 'warning',
1503
+ firstSeen: previous.timestamp,
1504
+ details: `${outlierChange} new outliers (${prevPattern.outlierCount} → ${currentPattern.outlierCount})`,
1505
+ });
1506
+ }
1507
+ }
1508
+ // Calculate category trends
1509
+ const categoryTrends = {};
1510
+ const categories = new Set([
1511
+ ...Object.keys(current.summary.byCategory),
1512
+ ...Object.keys(previous.summary.byCategory),
1513
+ ]);
1514
+ for (const category of categories) {
1515
+ const currentCat = current.summary.byCategory[category];
1516
+ const prevCat = previous.summary.byCategory[category];
1517
+ if (currentCat && prevCat) {
1518
+ const avgConfidenceChange = currentCat.avgConfidence - prevCat.avgConfidence;
1519
+ const complianceChange = currentCat.complianceRate - prevCat.complianceRate;
1520
+ categoryTrends[category] = {
1521
+ trend: avgConfidenceChange > 0.02 ? 'improving'
1522
+ : avgConfidenceChange < -0.02 ? 'declining'
1523
+ : 'stable',
1524
+ avgConfidenceChange,
1525
+ complianceChange,
1526
+ };
1527
+ }
1528
+ }
1529
+ // Calculate overall trend
1530
+ const healthDelta = current.summary.overallComplianceRate - previous.summary.overallComplianceRate;
1531
+ const overallTrend = healthDelta > 0.02 ? 'improving'
1532
+ : healthDelta < -0.02 ? 'declining'
1533
+ : 'stable';
1534
+ // Count stable patterns
1535
+ const changedPatternIds = new Set([...regressions, ...improvements].map(t => t.patternId));
1536
+ const stableCount = current.patterns.filter(p => !changedPatternIds.has(p.patternId)).length;
1537
+ return {
1538
+ period,
1539
+ startDate: previous.date,
1540
+ endDate: current.date,
1541
+ regressions,
1542
+ improvements,
1543
+ stable: stableCount,
1544
+ overallTrend,
1545
+ healthDelta,
1546
+ categoryTrends,
1547
+ };
1548
+ }
1150
1549
  }
1151
1550
  //# sourceMappingURL=drift-data-reader.js.map