Module hotspots
Expand description
Hotspot ranking analysis. cognitive_health is on [0, 100] (higher = healthier);
percentile_rank is on [0, 1]; the score formula combines them so unhealthy +
frequently-changed + complex files rank highest. Output range is [0, 10]:
hotspot_score(entity) = percentile_rank(revisions)
× percentile_rank(cognitive_complexity)
× (100 − cognitive_health) / 4Why divide by 4 (not 10)? cognitive_health is computed inline as
100 × (1 − 0.40 × normalize(cognitive)), so its empirical range is
[60, 100] — the 0.40 weight bounds the deduction. That makes
(100 − cognitive_health) ∈ [0, 40]; multiplied by two percent ranks (each
in [0, 1]) the unscaled product caps at 40. Dividing by 4 lands the
score in the documented [0, 10] range and matches the CodeScene
convention that ≈10 ⇒ "on fire".
Earlier divisor history: the original (10 − cognitive_health) / 10 produced
NEGATIVE scores (cognitive_health is [0, 100], not [0, 10]). The previous
fix (100 − cognitive_health) / 10 kept the sign positive but capped output at
4.0 instead of 10.0 — so the documented [0, 10] scale was never
reached and “on fire” was unreachable. The current / 4.0 closes that
documented-range-vs-math drift.
cognitive_health is the hotspots analysis’s own inline structural proxy,
computed from cognitive complexity only — it is deliberately NOT the
code-health analysis’s composite score. The churn / fragmentation /
coupling inputs that feed the code-health composite are not reused here:
hotspots is the lightweight “what to look at first” ranking, whose
cognitive_health proxy is bounded to [60, 100], while code-health
is the deeper analysis whose composite spans the full [0, 100]. The same
file can read healthy here and unhealthy there — they measure different
things, which is why this field is named cognitive_health and not
code_health.
Research basis: see docs/research-foundations.md entry “hotspots”
(Tornhill, Software Design X-Rays, 2018; McCabe, IEEE TSE 1976
— cyclomatic complexity; Campbell / SonarSource 2018 — cognitive
complexity formalisation; Coleman et al., IEEE Computer 1994 +
SEI 1997 variant — Maintainability Index).
mi (Maintainability Index, SEI variant) is computed by the vendored
codelore-rca fork of Mozilla rust-code-analysis at ingest. We pull
the file-level value by joining entities and filtering to
kind = 'unit' — that’s the rust-code-analysis convention for the
root space (file/module level), whose cumulative Halstead /
Cyclomatic / SLOC inputs produce the file’s MI per Coleman 1994.
Per-function MIs are also in complexity_metrics but averaging them
is mathematically unsound (MI is non-linear in its inputs).
Structs§
Constants§
Functions§
- apply_
hotspot_ anchor - Additive corpus-anchor post-pass: fill
hotspot_score_anchoredon each row whose language the active calibration corpus covers. A pure post-pass — it reads only the corpus and the per-pathpr_rev, never mutating the shipped fields — so a run without an active artifact leaves every row unchanged. - build_
inlined_ sql - Returns the SAME hotspots SQL with
?placeholders substituted for inline values — used by the Parquet writer, which routes throughDuckDB COPY ... TOand can’t accept bind parameters. Sharing the formula withbuild_sqleliminates the silent-drift risk between the two paths. - build_
sql - The
file_revschange source is resolved by routing the assembled SQL throughcrate::analyses::lineage::rewrite, which rewrites everyFROM changes/JOIN changestochanges_lineage/changes_bucketedwhen the corresponding flag is on.file_aiis deliberately EXEMPT: its{ai_src}placeholder resolves tochanges_lineage(canonical lineage) or rawchanges, neverchanges_bucketed— becauseai_pctjoinscommitson a realrevandchanges_bucketed’s synthetic date-stringrevwould never match, leavingai_pctNULL under--time-bucket.{cm_src}becomescomplexity_metricsorcomplexity_metrics_grouped(peranalyses::grouped_complexity).{file_mi_cte}swaps thefile_miCTE body between theentities-join (raw paths) form and the pre-baked-from-grouped form — the entities join can’t be reused post-grouping becauseentities.pathis never rewritten byapply_grouping, so the rolled-upmimust come straight fromcomplexity_metrics_grouped.mi. - run_
hotspots - run_
hotspots_ anchored run_hotspotswith the additive corpus anchor applied. The entry the CSV / JSON / markdown surfaces and thehotspot_anchored_maxgate use; kept distinct fromrun_hotspotsso the SPA payload and the internal consumers (refactoring-targets, finding-overlap, change-context, …) stay byte-identical — the anchor is a report / gate reading, not a core field.