# Правила для модулей индикаторов

Эти рекомендации распространяются на все файлы в `ioc_checker/iocs`. Они описывают,
как добавлять новые модули индикаторов, использовать существующие абстракции и чего
следует избегать.

## Общие принципы
- Соблюдаем ООП: каждый тип индикатора — отдельный dataclass с `value`, `kinds`
  и вычисляемым свойством `category`.
- Логирование, комментарии, строки интерфейса — **только на русском языке**.
- Не плодим проверки типов и дополнительные валидации: считаем данные корректными.
- Храним «сырые» входные значения без нормализаций в классе, все преобразования
  делаем в анализе или при парсинге.
- Используем готовые утилиты из `analysis.py` (например, `IndicatorVerdict`,
  `default_verdict`, `build_kaspersky_zone_verdict`) вместо дублирования.
- Все строки для `reasons` держим в одном месте как константы (см.
  `reason_texts.py`) и используем их из кода через ссылки.

## Структура нового индикатора
1. Создаём модуль либо расширяем существующий, добавляя dataclass-наследник
   `IndicatorAnalysisMixin`.
2. Определяем:
   - поле `value` (строковое представление индикатора) и `kinds` (множество
     лейблов из парсера);
   - свойство `category`, возвращающее строку категории (`ip`, `url`, `domain`,
     `hash` и т.д.);
   - метод `analysis(self, features: Mapping[str, Any] | None, **kwargs)`, который
     принимает фичи провайдеров и возвращает словарь с `status`, `features`,
     `verdicts`, `reasons`.
3. Внизу файла объявляем `build_patterns(normalize)` и возвращаем набор
   `PatternDefinition` для поиска индикаторов в тексте: регулярка, фабрика
   создания датакласса, список `kinds`, функция нормализации.
4. При работе с моделями или дополнительными файлами кэшируем загруженные
   артефакты в модульных переменных (см. доменный классификатор) и логируем
   загрузку.

## Паттерны
- Разделяем обязанности: парсинг (`build_patterns`) только создаёт объекты,
  бизнес-логика живёт в `analysis`.
- Используем константы и общие правила (пороги из `settings.analysis`,
  вспомогательные функции) вместо хардкода.
- Возвращаем вердикты единообразно: массив `verdicts` и отдельный список
  `reasons` с пояснениями без вложения причин в сами вердикты.
- При работе с фичами провайдеров передаем их как есть и минимально изменяем,
  расширяя только необходимыми полями, чтобы не ломать кэширование.

## Антипаттерны
- Не смешиваем сетевые вызовы или построение фич провайдеров внутри индикаторов:
  анализ опирается на уже готовые фичи.
- Не дублируем определения вердиктов и дефолтных ответов — используем
  `IndicatorVerdict` и `default_verdict`.
- Не добавляем избыточных try/except вокруг каждого шага: ловим только там,
  где нужно логировать и продолжать выполнение.
- Не оставляем комментарии и сообщения на английском и не вводим проверки типов
  ради «надёжности».
