34 lines
1.6 KiB
Python
34 lines
1.6 KiB
Python
"""Радар шести компетенций.
|
||
|
||
Чистая проекция уже посчитанных метрик, без пересчёта весов: радар и оценка
|
||
всегда согласованы, и расхождение между ними невозможно по построению
|
||
(docs/product/METHODOLOGY.md#компетентная-модель).
|
||
"""
|
||
|
||
from app.domain.events import CompetencyScore, Metric
|
||
from app.domain.taxonomy import Competency
|
||
from app.scoring.taxonomy import METRIC_MAP
|
||
|
||
|
||
def radar(metrics: list[Metric]) -> list[CompetencyScore]:
|
||
"""Доля пройденного веса по каждой компетенции, 0–1.
|
||
|
||
Компетенция без метрик не рисуется нулём: «коммуникация» без судьи —
|
||
это «не оценивалось», а не «провалено».
|
||
"""
|
||
total: dict[Competency, float] = {}
|
||
passed: dict[Competency, float] = {}
|
||
for metric in metrics:
|
||
mapping = METRIC_MAP.get(metric.key)
|
||
if mapping is None:
|
||
continue
|
||
competency = mapping[1]
|
||
total[competency] = total.get(competency, 0.0) + metric.weight
|
||
credit = metric.credit if metric.credit is not None else float(metric.passed)
|
||
passed[competency] = passed.get(competency, 0.0) + metric.weight * credit
|
||
|
||
return [
|
||
CompetencyScore(competency=competency.value, value=round(passed.get(competency, 0.0) / weight, 3))
|
||
for competency in Competency
|
||
if (weight := total.get(competency))
|
||
]
|