Распечатка Магистрали лежит у Рыдкулла на столе с урока 36. Пустой catch {} и «успешно» после него. За раздел ты разобрал её по строчке: у промиса в типе нет ошибки, ошибку можно назвать по тегу, кроме ошибок бывают дефекты, а причина провала знает обо всех сразу. Сегодня ночью башня T-1 пройдёт ту же ночь, что и Магистраль, и запишет всё, что Магистраль проглотила бы.
Что нужно башне
Проверяется всё, что башня умеет с первого этапа: тесты накопительные. Сверху две вещи в src/tower.ts.
processNight(tower, lines), ночь целиком. Строки разбираются все, ни одна не теряется: этоdecodeAllиз урока 42, и каждая ошибка разбора идёт в отчёт по своему тегу. Из разобранных кадров дубли отбрасываются по ключуkeyOfиз урока 44, первый кадр с ключом идёт в работу, повтор только считается. Каждый кадр проходитcheckFrameиrespond, и его исход башня разбирает по причинам, как в уроке 41: успех идёт в счёт исходов, ошибка дела в счёт своего тега, призрак ещё и в список призраков, а дефект это сбой.- Ошибок в типе нет.
processNightотвечаетEffect<NightReport>: каждая ошибка уже записана в отчёт, поэтому падать ночи нечем. Тип это проверяет, и Ринцвальд не сможет «на всякий случай» оставить вEхотя бы одну. - Сбой одного кадра не роняет ночь. Зависимость башни может бросить прямо при сборке шага, ещё до того, как квитанция запущена. Такой бросок должен стать дефектом этого кадра, а не всей ночи; для этого шаг собирают внутри
Effect.suspend. summary(report), сводка ночи одной строкой для Рыдкулла. Текст дословно в заказе.
Имя Tower.processNight для журнала Гекса, точный вид NightReport и правила счёта описаны в заказе.
Чек-лист перед сдачей
- Тесты всех прошлых этапов зелёные.
- На ночи из десяти строк сумма обработанных, ошибок, дублей и сбоев равна десяти. Ни одна строка не пропала и ни одна не посчитана дважды.
- В
errorsтолько те теги, что встретились. Нулей для остальных нет. - Повтор кадра не уходит в
checkFrameи не шлёт ответ второй раз. sent.has, который бросает на одном кадре, даёт один сбой, а остальные кадры ночи обработаны.- Убери
Effect.suspendи посмотри, что станет с ночью из пункта 5. Потом верни. expectTypeOf(processNight).returnsровноEffect.Effect<NightReport>. Если вEчто-то осталось, ты где-то не записал ошибку.
Башня, этап 11
Последний заказ раздела: башня, которая проходит ночь сама и утром отдаёт честный отчёт. После него Академии есть что положить рядом с распечаткой Магистрали.
Та же ночь на Магистрали
Пока ты пишешь, Ринцвальд прогоняет ту же ночь через код Магистрали. Ему интересно, чей отчёт окажется зеленее.
declare const relay: (frame: string) => Promise<void>;
export const send = async (frame: string): Promise<string> => {
try {
await relay(frame);
} catch {}
return 'успешно';
};
Десять строк провода, десять ответов «успешно». Что бы ни сделал relay: принял кадр, отказал, бросил на мусоре, ответил на призрак, отправил чужой кадр по чужому маршруту. Функция не может сказать ничего другого, ответ записан в ней до того, как пришёл первый кадр.
А вот та же ночь через башню, с проводом, который рвётся на кадрах для T-9:
import { Effect } from 'effect';
import { processNight, summary, type Tower } from './tower';
const night = [
'T-3->T-1|5|Text|%D0%B3%D1%80%D0%BE%D0%B7%D0%B0',
'T-3->T-1|5|Text|%D0%B3%D1%80%D0%BE%D0%B7%D0%B0',
'мусор',
'T-7->T-1|41|Ack|40',
'T-7->T-1|42|Ack|1',
'T-3->T-2|6|Ping|',
'T-9->T-1|7|Ping|',
'T-3->T-1|8|Lost|3',
'T-1->T-2|9|Smoke|',
'T-5->T-1|10|Ping|',
];
const tower: Tower = {
send: async (line) => {
if (line.includes('T-9')) throw new Error('обрыв');
},
sent: new Set([1, 2]),
};
console.log(summary(await Effect.runPromise(processNight(tower, night))));
обработано 4, ошибок 5, призраков 1, дублей 1, сбоев 0
Пять ошибок, которые Магистраль проглотила бы, и у каждой есть имя: мусор на проводе, неизвестный тег Smoke, призрак, подтвердивший кадр 40, который никто не посылал, кадр для T-2, пришедший к нам, и провод, не принявший ответ для T-9. Плюс дубль, на который башня не ответила второй раз.
Сюжетный квест
Это первая из трёх улик квеста «Проглоченная ошибка Гилта». Вторая ждёт в боссе ретранслятора, третья в боссе честного Почтамта. Найдёшь все три, и на дашборде квест раскроется: кредиты и сундук.
Практика
Итог
Утром Рыдкулл читает сводку дважды. Потом достаёт распечатку Магистрали и кладёт отчёт башни рядом, строка к строке: десять «успешно» слева, пять ошибок по именам справа.
Обе бумаги Рыдкулл убирает в одну папку. Улика закрыта: ошибки на Магистрали не исчезали, их прятали, и теперь это видно на одной ночи. Ранга за этот раздел нет. Рыдкулл говорит, что магистр получается не за одну ночь.
Дальше
Рыдкулл перечитывает код башни и загибает пальцы.
У двери стоит Сундук. Он ходит за тобой с урока 02 и в подвале Гекса уже показал, что умеет носить то, что просят свитки. Сундук лязгает крышкой, но не открывается: того, что башне нужно, внутри пока нет.
Следующий раздел курса это EF5 «Сундук»: сервисы, слои и то, как башня перестаёт таскать зависимости руками. Начинается он с урока 47.