lct-hack/backend/app/domain/taxonomy.py
Ivan Gerasimov 7b7dd38e9f каркас: домен, генерация типов фронта, стенд и карточки задач
Контракт в коде: КИО по нормативу, 43 события WS по шести союзам направлений,
таймеры ГОСТ, таксономия E1–E6, шесть компетенций радара. make types гоняет
их через JSON Schema в generated.ts, тест ловит забытую регенерацию.

Стенд: docker compose postgres + backend, health отвечает, база досягаема
из контейнера бэкенда. Makefile не врёт — нереализованные цели падают
и называют карточку, которая их закроет.

frontend/.npmrc: под WSL2 npm install зависает на дефолтных 15 сокетах.
2026-09-15 19:35:03 +03:00

114 lines
3.8 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.

"""Таксономия ошибок E1–E6 и компетенции.
Методика: docs/product/METHODOLOGY.md#таксономия-ошибок
Правило: каждая отметка несёт код и обоснование. Отметок без объяснения
не появляется ни в одном интерфейсе.
"""
from datetime import datetime
from enum import StrEnum
from pydantic import BaseModel
class ErrorCode(StrEnum):
E1 = "E1"
E2 = "E2"
E3 = "E3"
E4 = "E4"
E5 = "E5"
E6 = "E6"
class FindingSource(StrEnum):
"""Кто выставил отметку. `judge` — единственный недетерминированный источник."""
SLOTS = "slots"
GROUND_TRUTH = "ground_truth"
TIMERS = "timers"
KIO = "kio"
CHAIN = "chain"
JUDGE = "judge"
INSTRUCTOR = "instructor"
class ErrorSpec(BaseModel):
code: ErrorCode
title: str
detail: str
source: FindingSource
ERRORS: dict[ErrorCode, ErrorSpec] = {
ErrorCode.E1: ErrorSpec(
code=ErrorCode.E1,
title="Пропущенный факт",
detail="Обязательный вопрос не прозвучал, факт не добыт",
source=FindingSource.SLOTS,
),
ErrorCode.E2: ErrorSpec(
code=ErrorCode.E2,
title="Неверная классификация или маршрутизация",
detail="Тип происшествия или ДДС определены неверно",
source=FindingSource.GROUND_TRUTH,
),
ErrorCode.E3: ErrorSpec(
code=ErrorCode.E3,
title="Нарушение временного норматива",
detail="Опрос дольше 75 с, ДДС не оповещена за 60 с и т. д.",
source=FindingSource.TIMERS,
),
ErrorCode.E4: ErrorSpec(
code=ErrorCode.E4,
title="Коммуникативная ошибка",
detail="Тон, эмпатия, управление диалогом, лишние вопросы, игнорирование паники",
source=FindingSource.JUDGE,
),
ErrorCode.E5: ErrorSpec(
code=ErrorCode.E5,
title="Неполнота карточки",
detail="Обязательные поля КИО пусты или заполнены неверно",
source=FindingSource.KIO,
),
ErrorCode.E6: ErrorSpec(
code=ErrorCode.E6,
title="Неверное завершение",
detail="Карточка ушла в ДДС непригодной, снятие с контроля до подтверждения",
source=FindingSource.CHAIN,
),
}
class Competency(StrEnum):
"""Шесть осей радара. Проекция уже посчитанных метрик, без пересчёта весов."""
INTAKE = "intake"
INTERVIEW = "interview"
CARD = "card"
ROUTING = "routing"
NORMS = "norms"
COMMUNICATION = "communication"
COMPETENCY_LABELS: dict[Competency, str] = {
Competency.INTAKE: "Приём вызова",
Competency.INTERVIEW: "Опрос и добыча фактов",
Competency.CARD: "Заполнение КИО",
Competency.ROUTING: "Классификация и маршрутизация",
Competency.NORMS: "Соблюдение нормативов",
Competency.COMMUNICATION: "Коммуникация в стрессе",
}
class Finding(BaseModel):
"""Отметка в разборе. `fact` и `norm` — то самое обоснование."""
code: ErrorCode
source: FindingSource
summary: str
fact: str
norm: str | None = None
ref: str | None = None
competency: Competency | None = None
transcript_ref: str | None = None
at: datetime | None = None