До сих пор башня повторяла, как её научили в EF0: молотком, если повезёт, и никак, если не повезёт. За три урока у неё появились расписания, повторы только того, что стоит повторять, и одни часы на всю башню. Сегодня всё это собирается в одну ночь, где у каждой строки три предела времени сразу, и проверяется на тестовых часах.
Что нужно башне
Тесты накопительные. Сверху одна вещь в src/clock.ts: steadyNight(lines, options), ночь, которая чинит себя сама.
- Строки по одной, по порядку. Это не ночь вперемешку из урока 71: сегодня главное время, а не одновременность.
- У попытки свой предел,
options.attempt. Сосед, который заснул на полуслове, через этот срок считается промолчавшим, а его попытку прерывают, как проигравшего гонку из урока 64. - Повторяются обрыв и молчание, по
politeBackoff(options.base, options.retries)из урока 72: пауза растёт вдвое, с джиттером. Любой другой отказ провода не повторяется, как вsendPatientlyиз урока 73. - У строки общий срок,
options.deadline: все попытки и паузы вместе. Срок вышел, строку бросают и сразу берутся за следующую. - Брошенная строка ночь не роняет. Ошибок в типе нет, в
Rтолько провод и журнал. - Журнал с метками. После каждой строки запись с меткой
stampLineиз урока 74:отправлено строкаилиброшено строка: причина. Причина это текст отказа провода,нет ответа, если последняя попытка промолчала, илисрок вышел. - Отчёт
{ delivered, abandoned }в порядке строк.
Вот как выглядит ночь из четырёх строк на тестовых часах. «Ясно» принимает сразу, «гроза» дважды обрывается, «туман» отвечает «нет такой башни», «сон» спит минуту на каждой попытке:
[
{ delivered: [ 'ясно', 'гроза' ], abandoned: [ 'туман', 'сон' ] },
[
'[2026-11-01T22:00:00.100Z] отправлено ясно',
'[2026-11-01T22:00:00.876Z] отправлено гроза',
'[2026-11-01T22:00:00.876Z] брошено туман: нет такой башни',
'[2026-11-01T22:00:06.173Z] брошено сон: нет ответа'
]
]
Миллисекунды .876 и .173 у тебя будут другими: это джиттер. Ночь шла шесть секунд по часам башни, а тест кончился раньше, чем ты дочитал эту строку.
Чек-лист перед сдачей
- Тесты всех живых прошлых этапов зелёные;
Date.nowв тестах бросает, значит его нет нигде. - Обрыв, обрыв, принял: вторая попытка через 160-240 мс после первой, третья через 320-480 мс после второй.
- Отказ «нет такой башни»: одна попытка, строка брошена, следующая начинается в ту же миллисекунду.
- Сосед заснул на минуту при пределе попытки в секунду: через секунду его прерывают и спрашивают снова.
- Повторы кончились: брошено с причиной последней попытки,
обрывилинет ответа. - Общий срок 2,3 секунды у спящего соседа: брошено
срок вышелровно в 2,3 секунды, и это не путается снет ответа.
Башня, этап 39
Три предела в одной строке
Подумай до кода, как вложены три времени одной строки.
- Луковица. Предел попытки, повторы, общий срок. Порядок слоёв решает всё: предел, поставленный внутри повторов, режет каждую попытку, поставленный снаружи режет все вместе. Перепутаешь, и сосед, который спит, получит одну попытку на весь срок, или наоборот, повторы будут вечными.
- Что видит
while. Как только у попытки есть предел, к ошибкам провода добавляется ошибка «не успел», иwhileполучает их объединение. Это тот самый «Перевод с Ук» из урока 73. - Два вида «не успел». Молчание одной попытки и истёкший общий срок это разные причины в журнале. Если оба приходят одной и той же ошибкой, их не различить. В уроке 64 у предела по времени было два вида: один падает, другой отвечает
Option. - Время только из часов. Метка, паузы, пределы: всё из
Clock, иначе тест со сломаннымDate.nowупадёт, а тестовые часы не сдвинут твои паузы.
Практика
Итог
Утром Тикка поднимается на башню. Часы идут. В журнале за ночь ни одного молотка: паузы растут, у каждой башни свои миллисекунды, а то, что повторять бессмысленно, брошено с первой попытки и записано, почему.
Рыдкулл вписывает в книгу Академии твоё новое звание: смотритель башни. Башня Академии работает и сама себя чинит. Кажется, что Магистраль больше не страшна.
К обеду приходит письмо. Плотная бумага, красный сургуч, оттиск Семафорной Магистрали. Рихард Гилт пишет, что восхищён башней Академии, что она одна во всём городе держит линию в любую погоду, и предлагает её выкупить. Сумма в письме такая, что Рыдкулл перечитывает её трижды.
Дальше
Рыдкулл не отвечает. Он несёт письмо через весь город, к старому печатнику гильдий. Тот долго смотрит на сургуч через лупу.
Следующий раздел курса это EF9 «Печати»: схемы, разбор чужих данных и договоры, которые нельзя прочитать не так. Начинается он с урока 76.