docs: датасет заказчика — разбор, расшифровка билетов, ревизия карточек

Получены первичные данные, названные в ТЗ: памятка по АРМ-112, классификатор
происшествий на 1283 кода и 32 экзаменационных билета. Файлы в docs/spec/source/
под гитом: документ, на который ссылается норматив, должен приезжать вместе с кодом.

Что изменилось по существу:

- Норматив подтверждения карточки был 4 секунды со ссылкой на ГОСТ, где этого числа
  нет. Памятка и ТЗ независимо называют 30 секунд — исправлено в domain/timers.py
  с правильной ссылкой (ПП РФ № 1931), в контракте и в generated.ts.
- Оператор в боевом АРМ-112 службу не выбирает: он проставляет признаки, а список
  оповещения из 5–11 служб считается по ЕКП. Наше поле dds моделирует не ту работу.
- Сторона ДДС описана памяткой подробнее, чем реализована: девять статусов
  реагирования автоматом, семь статусов карточки, обязательные комментарии
  к отказам и таксономия ошибок с примерами.
- 96 учебных вызовов из билетов расшифрованы слово в слово в docs/spec/TICKETS.md;
  сложность в них делается адресом и профильностью, а не сюжетом.

Документы: DATASET.md, TICKETS.md, правки NORMATIVES.md (НПА, ЕКП, статусы),
GAP.md (пункты 13–15), TZ.md (предположение «датасета не будет» не подтвердилось).

Карточки: новые 32–36 (классификатор, статусы реагирования, билеты, уточнение
адреса, непрофильные вызовы); в девятнадцати существующих — раздел «Датасет»
с расхождениями, включая выполненные: lct-01 моделирует не ту карточку КИО,
lct-12 сравнивает адрес так, что уточнивший его курсант получает расхождение
с эталоном, lct-10 не содержит трёх блоков боевого АРМ.
This commit is contained in:
Ivan Gerasimov 2026-09-19 19:42:48 +03:00
commit ed0b13f060
6 changed files with 19 additions and 6 deletions

View file

@ -440,7 +440,7 @@ class CardReceived(BaseModel):
class CardAck(BaseModel):
"""Останавливает норматив `dds_ack` (≤ 4 с)."""
"""Останавливает норматив `dds_ack` (≤ 30 с)."""
type: Literal["card.ack"] = "card.ack"

View file

@ -55,7 +55,12 @@ NORMATIVES: dict[TimerCode, Normative] = {
code=TimerCode.DDS_NOTIFY, title="Оповещение ДДС", limit_ms=60_000
),
TimerCode.DDS_ACK: Normative(
code=TimerCode.DDS_ACK, title="Подтверждение получения карточки", limit_ms=4_000
# 30 секунд — ПП РФ № 1931 и памятка АРМ-112, а не ГОСТ: до получения
# датасета здесь стояло 4 секунды, взятые по догадке (docs/spec/DATASET.md).
code=TimerCode.DDS_ACK,
title="Подтверждение получения карточки",
limit_ms=30_000,
ref="ПП РФ № 1931",
),
TimerCode.ZONE_CHECK: Normative(
code=TimerCode.ZONE_CHECK, title="Проверка зоны ответственности", limit_ms=30_000

View file

@ -1,7 +1,9 @@
"""make llm-check: один запрос к LLM, чтобы убедиться, что ключ и адрес рабочие.
Ключ берётся из backend/.env и никуда не печатается. Запускать там, где есть
сеть до провайдера: из WSL под VPN российские адреса недоступны.
Ключ берётся из backend/.env и никуда не печатается. Провайдер отвечает с машины
разработки напрямую; таймаут почти всегда означает не отказ провайдера, а окружение —
VPN-туннель или песочница, через которые российские адреса не проходят. Поэтому
проверять отсюда, а не из обёрток, и с той машины, на которой пойдёт занятие.
"""
import sys
@ -46,7 +48,8 @@ def main() -> int:
)
except httpx.HTTPError as exc:
print(f"\nсеть: {type(exc).__name__} — до провайдера не достучались.")
print("Проверь, что российские адреса идут мимо VPN.")
print("Это чаще про окружение, чем про провайдера: проверь, что российские")
print("адреса идут мимо VPN, и повтори с самой машины стенда.")
return 2
elapsed = time.monotonic() - started