Merge branch 'feat/dds-ack-limit'

lct-11: срок решения на пульте ДДС из снимка сервера
This commit is contained in:
GGlamer 2026-09-26 23:01:15 +03:00 • committed by GitHub
commit 02c86e457d
8 changed files with 134 additions and 21 deletions

View file

@ -337,7 +337,9 @@ async def _handle(session_id: UUID, state, event) -> None:
# первого своего действия: отмечаться ему по нему же (lct-33).
hub.to_station(session_id, StationState(snapshot=state.station_snapshot()))
hub.to_observers(session_id, KioState(kio=state.kio))
hub.to_observers(session_id, TimerTick(timers=state.timers.snapshot()))
tick = TimerTick(timers=state.timers.snapshot())
hub.to_observers(session_id, tick)
hub.to_station(session_id, tick)
case "call.resolve":
# Курсант закрывает вызов не карточкой. Отдельное действие, а не

View file

@ -328,7 +328,11 @@ class SessionHub:
# Keep the pending count and countdown live even while
# the active dispatcher card is being handled.
self.to_station(session_id, StationState(snapshot=state.station_snapshot()))
self.broadcast(session_id, TimerTick(timers=state.timers.snapshot()))
tick = TimerTick(timers=state.timers.snapshot())
self.broadcast(session_id, tick)
# Срок первичного решения пульт берёт отсюда: после передачи
# из 112 без очереди ДДС лимит преподавателя больше нигде не виден.
self.to_station(session_id, tick)
except asyncio.CancelledError:
raise

View file

@ -0,0 +1,44 @@
"""Такт таймеров доходит до АРМ ДДС: пульт строит срок решения по снимку сервера."""
import asyncio
from pathlib import Path
from uuid import uuid4
from app.domain.events import Exercise, SessionMode, TimerTick
from app.domain.timers import TimerCode
from app.scenarios.loader import load_file
from app.session import hub as hub_module
from app.session.hub import SessionHub
from app.session.state import SessionState
LIBRARY = Path(__file__).resolve().parents[2] / "scenarios"
async def test_station_receives_dds_ack_with_configured_limit_after_handoff(monkeypatch):
"""Передача из 112 без очереди ДДС: `queue_cards` пуст, и лимит решения,
настроенный преподавателем, пульт видит только в `timer.tick`."""
monkeypatch.setattr(hub_module, "TICK_SECONDS", 0.01)
scenario = load_file(LIBRARY / "fire-apartment-l2.yaml", LIBRARY)
state = SessionState(
session_id=uuid4(), scenario_id=scenario.id, scenario_title=scenario.title,
level=scenario.level.value, mode=SessionMode.TRAINING,
exercise=Exercise.CARD, handoff_to_dds=True, scenario=scenario,
)
state.timers.limits[TimerCode.DDS_ACK] = 45_000
state.on_event("dds.dispatch")
state.dispatch()
local_hub = SessionHub()
local_hub.register(state)
with local_hub.station(state.session_id) as station:
local_hub.start_ticker(state.session_id)
try:
async with asyncio.timeout(1):
while not isinstance(event := await station.get(), TimerTick):
pass
finally:
local_hub.stop_ticker(state.session_id)
ack = next(timer for timer in event.timers if timer.code is TimerCode.DDS_ACK)
assert ack.limit_ms == 45_000
assert not ack.stopped