Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | 200x 200x 200x 8x 14x 206x 206x 206x 14x 8x 8x 14x 14x 8x 8x 8x 8x 14x 14x 22x 22x 22x 22x 18x 18x 14x 12x 12x 17x 14x 13x 13x 17x 14x 3x 11x 8x 7x 4x 18x 14x 22x 12x 7x 22x 16x 11x 8x 16x 2x 8x 22x 10x 22x 14x | import { calculateProductivityImpact, ToolName } from '@aiready/core';
import type { ToolScoringOutput, CostConfig } from '@aiready/core';
import type { ConsistencyIssue } from './types';
/**
* Calculate AI Readiness Score for code consistency (0-100).
*
* @param issues - Array of detected consistency issues.
* @param totalFilesAnalyzed - Total number of files scanned.
* @param costConfig - Optional configuration for productivity cost calculation.
* @returns Standardized scoring output for the consistency tool.
* @lastUpdated 2026-03-18
*/
export function calculateConsistencyScore(
issues: ConsistencyIssue[],
totalFilesAnalyzed: number,
costConfig?: Partial<CostConfig>
): ToolScoringOutput {
// Parameter reserved for future configuration; reference to avoid lint warnings
void costConfig;
const criticalIssues = issues.filter((i) => i.severity === 'critical').length;
const majorIssues = issues.filter((i) => i.severity === 'major').length;
const minorIssues = issues.filter((i) => i.severity === 'minor').length;
const totalIssues = issues.length;
// Issue density penalty (0-50 points)
// Ideal: 0 issues/file = 0 penalty
// Acceptable: <1 issue/file = 10 penalty
// High: 1-3 issues/file = 10-40 penalty
// Critical: >3 issues/file = 40-50 penalty
const issuesPerFile =
totalFilesAnalyzed > 0 ? totalIssues / totalFilesAnalyzed : 0;
const densityPenalty = Math.min(50, issuesPerFile * 15);
// Weighted severity penalty (0-50 points)
// Each critical: 10 points
// Each major: 3 points
// Each minor: 0.5 points
const weightedCount =
criticalIssues * 10 + majorIssues * 3 + minorIssues * 0.5;
const avgWeightedIssuesPerFile =
totalFilesAnalyzed > 0 ? weightedCount / totalFilesAnalyzed : 0;
const severityPenalty = Math.min(50, avgWeightedIssuesPerFile * 2);
// Calculate final score
const rawScore = 100 - densityPenalty - severityPenalty;
const score = Math.max(0, Math.min(100, Math.round(rawScore)));
// Build factors array
const factors: ToolScoringOutput['factors'] = [
{
name: 'Issue Density',
impact: -Math.round(densityPenalty),
description: `${issuesPerFile.toFixed(2)} issues per file ${issuesPerFile < 1 ? '(excellent)' : issuesPerFile < 3 ? '(acceptable)' : '(high)'}`,
},
];
if (criticalIssues > 0) {
const criticalImpact = Math.min(30, criticalIssues * 10);
factors.push({
name: 'Critical Issues',
impact: -criticalImpact,
description: `${criticalIssues} critical consistency issue${criticalIssues > 1 ? 's' : ''} (high AI confusion risk)`,
});
}
if (majorIssues > 0) {
const majorImpact = Math.min(20, Math.round(majorIssues * 3));
factors.push({
name: 'Major Issues',
impact: -majorImpact,
description: `${majorIssues} major issue${majorIssues > 1 ? 's' : ''} (moderate AI confusion risk)`,
});
}
if (minorIssues > 0 && minorIssues >= totalFilesAnalyzed) {
const minorImpact = -Math.round(minorIssues * 0.5);
factors.push({
name: 'Minor Issues',
impact: minorImpact,
description: `${minorIssues} minor issue${minorIssues > 1 ? 's' : ''} (slight AI confusion risk)`,
});
}
// Generate recommendations
const recommendations: ToolScoringOutput['recommendations'] = [];
if (criticalIssues > 0) {
const estimatedImpact = Math.min(30, criticalIssues * 10);
recommendations.push({
action:
'Fix critical naming/pattern inconsistencies (highest AI confusion risk)',
estimatedImpact,
priority: 'high',
});
}
if (majorIssues > 5) {
const estimatedImpact = Math.min(15, Math.round(majorIssues / 2));
recommendations.push({
action: 'Standardize naming conventions across codebase',
estimatedImpact,
priority: 'medium',
});
}
if (issuesPerFile > 3) {
recommendations.push({
action:
'Establish and enforce coding style guide to reduce inconsistencies',
estimatedImpact: 12,
priority: 'medium',
});
}
if (totalIssues > 20 && minorIssues / totalIssues > 0.7) {
recommendations.push({
action: 'Enable linter/formatter to automatically fix minor style issues',
estimatedImpact: 8,
priority: 'low',
});
}
// Calculate business value metrics
const productivityImpact = calculateProductivityImpact(issues);
return {
toolName: ToolName.NamingConsistency,
score,
rawMetrics: {
totalIssues,
criticalIssues,
majorIssues,
minorIssues,
issuesPerFile: Math.round(issuesPerFile * 100) / 100,
avgWeightedIssuesPerFile:
Math.round(avgWeightedIssuesPerFile * 100) / 100,
// Business value metrics
estimatedDeveloperHours: productivityImpact.totalHours,
},
factors,
recommendations,
};
}
|