* Get robust date for a pattern (P90 percentile) to avoid "single file edit" skew * This means we take the date of the 10th percentile newest file. * For example, if there are 100 files, we take the 10th newest file's date. * This allows ~10% of legacy files to be edited without resetting t
(category: string, patternName: string)
| 393 | * This allows ~10% of legacy files to be edited without resetting the trend. |
| 394 | */ |
| 395 | private getRobustDate(category: string, patternName: string): Date | undefined { |
| 396 | const dates = this.patternFileDates.get(`${category}:${patternName}`); |
| 397 | if (!dates || dates.length === 0) return undefined; |
| 398 | |
| 399 | // Sort descending (newest first) |
| 400 | dates.sort((a, b) => b - a); |
| 401 | |
| 402 | // If few samples, trust the newest (not enough for stats) |
| 403 | if (dates.length < 5) return new Date(dates[0]); |
| 404 | |
| 405 | // Use 90th percentile (exclude top 10% outliers) |
| 406 | // For 100 files, P90 is index 10 (11th newest file) |
| 407 | // This allows ~10% of legacy files to be edited without resetting the trend |
| 408 | const p90Index = Math.floor(dates.length * 0.1); |
| 409 | return new Date(dates[p90Index]); |
| 410 | } |
| 411 | |
| 412 | getConsensus(category: string): PatternUsageStats[string] | null { |
| 413 | const categoryPatterns = this.patterns.get(category); |