You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This document explains how the current `pyscn analyze` command derives the health score and the category scores that appear in CLI and HTML outputs. The implementation lives primarily in `domain/analyze.go` with orchestration in `app/analyze_usecase.go`.
4
+
5
+
## Calculation Flow
6
+
7
+
1. Each analyzer populates an `AnalyzeResponse`. The `AnalyzeUseCase` composes the project summary (`AnalyzeSummary`) with aggregate metrics (function counts, average complexity, clone duplication, dependency stats, etc.).
8
+
2.`AnalyzeSummary.CalculateHealthScore()` validates the inputs, computes penalties per category, converts those penalties to scores on a 0–100 scale, and subtracts the penalties from an overall score that starts at 100.
9
+
3. If validation fails, the CLI logs a warning, applies a lightweight fallback scorer, and still surfaces the grade.
10
+
11
+
All scores are bounded to 0–100. The overall health score has a floor of 10 to avoid degenerate results for heavily penalised projects.
12
+
13
+
## Category Penalties and Scores
14
+
15
+
Penalties are additive. Each category subtracts up to the maximum listed points from the base score (100). The same penalty value is then converted to a category score via `100 - (penalty / maxPenalty * 100)`.
| Dead Code | Count of critical dead code issues, normalised by logarithm of total files (threshold kicks in once more than 10 files are analysed) | Up to 20 based on `criticalDeadCode / normalizationFactor`, capped at 20 | 20 |
21
+
| Duplication | Percentage of duplicated code across clone groups | >20% → 20, >10% → 12, >3% → 6 | 20 |
22
+
| Coupling (CBO) | Weighted ratio of high-risk (`CBO > 7`) and medium-risk (`3 < CBO ≤ 7`) classes using weight 1.0 and 0.5 respectively, divided by total measured classes | >30% → 20, >15% → 12, >5% → 6 | 20 |
23
+
| Dependencies | Module dependency graph: proportion of modules in cycles, dependency depth above `log₂(N)+1`, Main Sequence Deviation | Cycles up to 8 pts + depth up to 2 pts + MSD up to 2 pts (ratio/overflow calculations clamp to [0, max]) | 12 |
When a category is disabled (e.g., `--skip-clones`), its penalty is zero and the prior score (100) carries forward so the missing analysis does not hurt the overall grade.
27
+
28
+
## Overall Health Score and Grade
29
+
30
+
`HealthScore = max(10, 100 - Σ penalties)`
31
+
32
+
Grades mirror the score quality thresholds that the CLI uses for emoji indicators:
33
+
34
+
- A: ≥85
35
+
- B: ≥70
36
+
- C: ≥55
37
+
- D: ≥40
38
+
- F: <40
39
+
40
+
The CLI treats a project as “healthy” when `HealthScore ≥ 70`.
41
+
42
+
## Presentation Details
43
+
44
+
- The CLI summary shows the overall score, letter grade, and per-category scores with emojis (`✅` ≥85, `👍` ≥70, `⚠️` ≥55, `❌` otherwise).
45
+
- HTML and JSON outputs expose the same scores and include additional per-category context (e.g., high-risk counts).
46
+
- When dependency or architecture analyses are disabled, their sections are omitted from the detailed summary, but the rest of the scoring remains unchanged.
47
+
48
+
## Fallback Behaviour
49
+
50
+
If the validator detects inconsistent summary metrics (negative averages, duplication >100%, etc.), the application:
51
+
52
+
1. Logs a warning about the failure to calculate the health score.
53
+
2. Uses `CalculateFallbackScore()`, which applies simple penalties:
54
+
- −10 for average complexity above 10,
55
+
- −5 if any dead code exists,
56
+
- −5 if any high-complexity functions exist.
57
+
3. Enforces the same minimum score (10) and derives the grade from the fallback score.
58
+
59
+
This ensures the CLI still produces a meaningful result even when upstream metrics are incomplete or malformed.
0 commit comments