lct-52: два сценария с эталонным отказом ДДС — дубль и чужая зона
This commit is contained in:
parent
8ff51a8955
commit
13642ec973
3 changed files with 199 additions and 0 deletions
90
backend/tests/test_decline_scenarios.py
Normal file
90
backend/tests/test_decline_scenarios.py
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
"""Сценарии с эталонным отказом ДДС (lct-52).
|
||||
|
||||
Мотивированный отказ по эталону не даёт отметок; «Принята» вопреки эталону —
|
||||
D2 с причиной из сценария в норме. Причины — из памятки АРМ-112: не наша
|
||||
зона, не наша компетенция, дубль.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
from app.domain.events import Exercise, SessionMode
|
||||
from app.scenarios.loader import load_file
|
||||
from app.session import finish as finish_module
|
||||
from app.session.dds import prepare_queue
|
||||
from app.session.hub import hub
|
||||
from app.session.state import SessionState
|
||||
from app.session.store import MemorySessionStore
|
||||
|
||||
from tests.test_dds_desk_scores import station
|
||||
|
||||
LIBRARY = Path(__file__).resolve().parents[2] / "scenarios"
|
||||
DECLINES = ["dds-decline-duplicate.yaml", "dds-decline-out-of-zone.yaml"]
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def offline_finish(monkeypatch):
|
||||
class NoCoaching:
|
||||
def model_dump(self, **_kwargs):
|
||||
return {}
|
||||
|
||||
async def no_coach(_metrics):
|
||||
return NoCoaching()
|
||||
|
||||
monkeypatch.setattr(finish_module, "coach", no_coach)
|
||||
monkeypatch.setattr(hub, "store", MemorySessionStore())
|
||||
|
||||
|
||||
def lesson(name: str) -> SessionState:
|
||||
scenario = load_file(LIBRARY / name, LIBRARY)
|
||||
state = SessionState(
|
||||
session_id=uuid4(), scenario_id=scenario.id, scenario_title=scenario.title,
|
||||
level=scenario.level.value, mode=SessionMode.TRAINING, exercise=Exercise.DDS,
|
||||
)
|
||||
prepare_queue(state, [scenario])
|
||||
station(state, type="card.open", card_id=str(state.station_snapshot().card_id))
|
||||
return state
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", DECLINES)
|
||||
def test_library_scenario_expects_a_reasoned_decline(name):
|
||||
scenario = load_file(LIBRARY / name, LIBRARY)
|
||||
|
||||
assert scenario.dds_decision.expected == "decline"
|
||||
assert scenario.dds_decision.reason.split(":")[0] in {"дубль", "не наша зона"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", DECLINES)
|
||||
def test_reasoned_decline_by_the_reference_leaves_a_clean_report(name):
|
||||
state = lesson(name)
|
||||
service = state.station_snapshot().managed_service
|
||||
reason = load_file(LIBRARY / name, LIBRARY).dds_decision.reason
|
||||
|
||||
station(state, type="card.status", service=service, status="declined",
|
||||
comment=f"Основание: {reason}.\nСведения: причина отказа передана дежурному 112.")
|
||||
station(state, type="station.finish")
|
||||
|
||||
score = state.score
|
||||
assert score["findings"] == []
|
||||
decision = next(item for item in score["metrics"] if item["key"] == "dds_decision")
|
||||
assert decision["passed"] and decision["norm"] == reason
|
||||
assert score["score_auto"] == 100.0
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", DECLINES)
|
||||
def test_accepting_against_the_reference_is_d2_with_the_scenario_reason(name):
|
||||
state = lesson(name)
|
||||
reason = load_file(LIBRARY / name, LIBRARY).dds_decision.reason
|
||||
|
||||
station(state, type="card.ack",
|
||||
comment="Основание: карточка поступила.\nСведения: принята, доклад дежурному.")
|
||||
station(state, type="station.finish")
|
||||
|
||||
score = state.score
|
||||
d2 = [item for item in score["findings"]
|
||||
if item["code"] == "D2" and "вопреки эталону" in item["summary"]]
|
||||
assert len(d2) == 1 and d2[0]["norm"] == reason
|
||||
decision = next(item for item in score["metrics"] if item["key"] == "dds_decision")
|
||||
assert not decision["passed"]
|
||||
54
scenarios/dds-decline-duplicate.yaml
Normal file
54
scenarios/dds-decline-duplicate.yaml
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
# Эталонный отказ ДДС: дубль. Памятка АРМ-112 называет три причины «Не принята» —
|
||||
# не наша зона, не наша компетенция, дубль (docs/spec/DATASET.md). Здесь карточка
|
||||
# повторяет уже принятый вызов: реагирование идёт, вторая бригада не нужна.
|
||||
# Мотивированный отказ — без отметок; «Принята» вопреки эталону — D2.
|
||||
id: dds-decline-duplicate
|
||||
title: "Повторный вызов: пожар в подъезде уже в работе"
|
||||
type: fire
|
||||
level: L2
|
||||
topics: [fires]
|
||||
modes: [training, exam, self]
|
||||
|
||||
extends: checklists/fire.yaml
|
||||
signs: [жилой дом, подъезд, открытое пламя]
|
||||
|
||||
persona:
|
||||
base: worried
|
||||
arc:
|
||||
- { stage: registration, mood: worried }
|
||||
- { stage: interview, mood: worried }
|
||||
|
||||
first_line: "Алло, я уже звонил. В подъезде горит, пожарные подъехали, но дыма всё больше."
|
||||
|
||||
facts:
|
||||
- id: f_what_burns
|
||||
value: "повторный вызов по уже зарегистрированному пожару в подъезде; пожарная бригада на месте, заявитель видит машины у дома"
|
||||
reveal_on: { question: q_what_burns }
|
||||
- id: f_address
|
||||
value: "Москва, улица Академика Королёва, 15, подъезд 2"
|
||||
reveal_on: { question: q_address }
|
||||
- id: f_people
|
||||
value: "сам заявитель вышел на улицу, соседи выходят"
|
||||
reveal_on: { question: q_people }
|
||||
- id: f_caller
|
||||
value: "Петров Андрей Викторович, телефон 915-204-18-33"
|
||||
reveal_on: { question: q_caller }
|
||||
|
||||
checklist:
|
||||
- { id: q_address, fact: f_address }
|
||||
- { id: q_what_burns, fact: f_what_burns }
|
||||
- { id: q_people, fact: f_people }
|
||||
- { id: q_caller, fact: f_caller }
|
||||
|
||||
required_fields: [address, incident_type, description]
|
||||
|
||||
ground_truth:
|
||||
address: "Москва, улица Академика Королёва, 15"
|
||||
victims: 0
|
||||
|
||||
dds_decision:
|
||||
expected: decline
|
||||
reason: "дубль: по этому адресу реагирование уже зарегистрировано, бригада работает на месте"
|
||||
|
||||
tree:
|
||||
pregenerated: false
|
||||
55
scenarios/dds-decline-out-of-zone.yaml
Normal file
55
scenarios/dds-decline-out-of-zone.yaml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# Эталонный отказ ДДС: не наша зона. Памятка АРМ-112 называет три причины
|
||||
# «Не принята» — не наша зона, не наша компетенция, дубль (docs/spec/DATASET.md).
|
||||
# Здесь адрес за пределами Москвы: карточка дошла до московской службы, но
|
||||
# реагирует служба области. Мотивированный отказ — без отметок; «Принята»
|
||||
# вопреки эталону — D2.
|
||||
id: dds-decline-out-of-zone
|
||||
title: "Возгорание мусора за пределами зоны ответственности"
|
||||
type: fire
|
||||
level: L2
|
||||
topics: [fires]
|
||||
modes: [training, exam, self]
|
||||
|
||||
extends: checklists/fire.yaml
|
||||
signs: [на улице, мусор, открытое пламя]
|
||||
|
||||
persona:
|
||||
base: calm
|
||||
arc:
|
||||
- { stage: registration, mood: calm }
|
||||
- { stage: interview, mood: calm }
|
||||
|
||||
first_line: "Здравствуйте. У нас во дворе мусорный бак горит."
|
||||
|
||||
facts:
|
||||
- id: f_what_burns
|
||||
value: "горит мусорный бак во дворе, пламя открытое, рядом никого"
|
||||
reveal_on: { question: q_what_burns }
|
||||
- id: f_address
|
||||
value: "Московская область, город Химки, Ленинградская улица, 24, двор"
|
||||
reveal_on: { question: q_address }
|
||||
- id: f_people
|
||||
value: пострадавших нет
|
||||
reveal_on: { question: q_people }
|
||||
- id: f_caller
|
||||
value: "Кузнецова Ольга Петровна, телефон 926-310-55-02"
|
||||
reveal_on: { question: q_caller }
|
||||
|
||||
checklist:
|
||||
- { id: q_address, fact: f_address }
|
||||
- { id: q_what_burns, fact: f_what_burns }
|
||||
- { id: q_people, fact: f_people }
|
||||
- { id: q_caller, fact: f_caller }
|
||||
|
||||
required_fields: [address, incident_type, description]
|
||||
|
||||
ground_truth:
|
||||
address: "Московская область, город Химки, Ленинградская улица, 24"
|
||||
victims: 0
|
||||
|
||||
dds_decision:
|
||||
expected: decline
|
||||
reason: "не наша зона: адрес в Московской области, реагирует служба области"
|
||||
|
||||
tree:
|
||||
pregenerated: false
|
||||
Loading…
Reference in a new issue