lct-hack/backend/app/scoring/taxonomy.py
Ivan Gerasimov fadfa3e479 lct-16 и половина lct-19: разбор, отчёт, внешний монитор, эталон
Эталонный диалог собирается кодом из фактов и чек-листа: написанный
руками, он разошёлся бы с фактами при первой же правке сценария,
и курсанта оштрафовали бы за правильный ответ.

Отчёт: метрики фактом против норматива со ссылкой, отметка E1 на каждый
недобытый факт с эталонным вопросом, расхождение самооценки — что
курсант заметил сам, чего не заметил, что отметил зря. Не заметил —
самое ценное для разбора.

Внешний монитор — не отдельное приложение, а другой режим отрисовки тех
же событий: крупный таймер опроса, ход разговора, карточка, после оценки
разбор на весь экран.

Коррекция преподавателем сохраняет автооценку рядом: видно, что
скорректировано и кем.

Найдено: все метрики весили одинаково, и курсант, не задавший ни одного
вопроса, но заполнивший карточку руками, получал 87 из 100. Предварительные
веса (полнота опроса — 4) дают 74; окончательные утверждает методист,
вопрос записан в DEBRIEF.md.
2026-09-17 21:32:12 +03:00

44 lines
2.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Какая метрика каким кодом ошибки и какой компетенцией размечается.
Это методика, а не вычисление: таблица читается глазами и сверяется
с docs/product/METHODOLOGY.md. Считает метрики gost.py, сюда он только смотрит.
"""
from app.domain.taxonomy import Competency, ErrorCode
#: Метрика → (код ошибки при провале, компетенция радара).
METRIC_MAP: dict[str, tuple[ErrorCode, Competency]] = {
"answer_time": (ErrorCode.E3, Competency.INTAKE),
"callback": (ErrorCode.E3, Competency.INTAKE),
"checklist_completeness": (ErrorCode.E1, Competency.INTERVIEW),
"interview_time": (ErrorCode.E3, Competency.NORMS),
"incident_type": (ErrorCode.E2, Competency.ROUTING),
"dds_choice": (ErrorCode.E2, Competency.ROUTING),
"address": (ErrorCode.E5, Competency.CARD),
"victims_count": (ErrorCode.E5, Competency.CARD),
"required_fields": (ErrorCode.E5, Competency.CARD),
}
#: Вес метрики в детерминированной оценке.
#:
#: **Предварительные значения, требуют утверждения методистом.** Без весов все
#: метрики равны, и курсант, не задавший ни одного вопроса, но заполнивший
#: карточку руками, получает 87 из 100: «ответ за секунду» стоит столько же,
#: сколько «добыл все обязательные факты». Опрос — то, ради чего существует
#: тренажёр, поэтому он весит больше всего.
METRIC_WEIGHTS: dict[str, float] = {
"checklist_completeness": 4.0,
"incident_type": 2.0,
"dds_choice": 2.0,
"address": 2.0,
"required_fields": 2.0,
"interview_time": 1.5,
"victims_count": 1.0,
"answer_time": 1.0,
"callback": 1.0,
}
#: Вес детерминированного слоя в итоговой оценке. Остальное — LLM-судья
#: на мягкие критерии (E4), и не больше (docs/arch/BACKEND.md).
DETERMINISTIC_WEIGHT = 0.6
JUDGE_WEIGHT = 0.4