lct-22: пульт директив — преподаватель ведёт ситуацию

Мягкие директивы перекрывают дугу сценария и применяются со следующей
реплики: разговор не дёргается от того, что преподаватель что-то нажал.
Жёсткие правят ситуацию — обрыв связи рвёт звук тем же механизмом, что
перебивание, и запускает норматив обратного дозвона; второй пострадавший
правит эталон; неточный адрес снимает раскрытый факт, и оператор обязан
переспросить.

Своя копия сценария на занятие: директивы правят факты и эталон, а
сценарий был общим на библиотеку — правка в одной группе протекла бы во
все остальные. Тест проверяет, что библиотека не изменилась.

Свободный текст честно отказывает: офлайн-дерево предгенерировано,
произвольную фразу взять неоткуда, и преподаватель видит это на пульте.

Ни одна директива не трогает карточку курсанта — он управляет ситуацией,
а не работой обучаемого.

Занятие теперь собирается целиком и только потом регистрируется:
наблюдатель мог увидеть его без слот-автомата и звонящего.
This commit is contained in:
Ivan Gerasimov 2026-09-17 21:38:43 +03:00
commit 57f4c858b6
13 changed files with 317 additions and 23 deletions

View file

@ -28,6 +28,7 @@ export interface ObservedSession {
notes: Map<string, string>;
ended: boolean;
report: SessionReport | null;
error: string | null;
}
export function useObserve(sessionId: string | null): ObservedSession {
@ -43,6 +44,7 @@ export function useObserve(sessionId: string | null): ObservedSession {
const [notes, setNotes] = useState<Map<string, string>>(new Map());
const [ended, setEnded] = useState(false);
const [report, setReport] = useState<SessionReport | null>(null);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!sessionId) return;
@ -82,6 +84,9 @@ export function useObserve(sessionId: string | null): ObservedSession {
case "session.ended":
setEnded(true);
break;
case "error":
setError(event.message);
break;
case "score.ready":
void fetch(`/api/sessions/${sessionId}/report`)
.then((response) => (response.ok ? response.json() : null))
@ -94,5 +99,5 @@ export function useObserve(sessionId: string | null): ObservedSession {
return () => channel.close();
}, [sessionId]);
return { status, title, mode, trainee, card, requiredFields, transcript, timers, hintsUsed, notes, ended, report };
return { status, title, mode, trainee, card, requiredFields, transcript, timers, hintsUsed, notes, ended, report, error };
}