Раздел 46 · Effect: Тихая Академия

Босс: башня, которая чинит себя сама

middle-senior~80 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

До сих пор башня повторяла, как её научили в 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 у тебя будут другими: это джиттер. Ночь шла шесть секунд по часам башни, а тест кончился раньше, чем ты дочитал эту строку.

Чек-лист перед сдачей

  1. Тесты всех живых прошлых этапов зелёные; Date.now в тестах бросает, значит его нет нигде.
  2. Обрыв, обрыв, принял: вторая попытка через 160-240 мс после первой, третья через 320-480 мс после второй.
  3. Отказ «нет такой башни»: одна попытка, строка брошена, следующая начинается в ту же миллисекунду.
  4. Сосед заснул на минуту при пределе попытки в секунду: через секунду его прерывают и спрашивают снова.
  5. Повторы кончились: брошено с причиной последней попытки, обрыв или нет ответа.
  6. Общий срок 2,3 секунды у спящего соседа: брошено срок вышел ровно в 2,3 секунды, и это не путается с нет ответа.

Башня, этап 39

Три предела в одной строке

Подумай до кода, как вложены три времени одной строки.

  • Луковица. Предел попытки, повторы, общий срок. Порядок слоёв решает всё: предел, поставленный внутри повторов, режет каждую попытку, поставленный снаружи режет все вместе. Перепутаешь, и сосед, который спит, получит одну попытку на весь срок, или наоборот, повторы будут вечными.
  • Что видит while. Как только у попытки есть предел, к ошибкам провода добавляется ошибка «не успел», и while получает их объединение. Это тот самый «Перевод с Ук» из урока 73.
  • Два вида «не успел». Молчание одной попытки и истёкший общий срок это разные причины в журнале. Если оба приходят одной и той же ошибкой, их не различить. В уроке 64 у предела по времени было два вида: один падает, другой отвечает Option.
  • Время только из часов. Метка, паузы, пределы: всё из Clock, иначе тест со сломанным Date.now упадёт, а тестовые часы не сдвинут твои паузы.

Практика

Итог

Утром Тикка поднимается на башню. Часы идут. В журнале за ночь ни одного молотка: паузы растут, у каждой башни свои миллисекунды, а то, что повторять бессмысленно, брошено с первой попытки и записано, почему.

Рыдкулл вписывает в книгу Академии твоё новое звание: смотритель башни. Башня Академии работает и сама себя чинит. Кажется, что Магистраль больше не страшна.

К обеду приходит письмо. Плотная бумага, красный сургуч, оттиск Семафорной Магистрали. Рихард Гилт пишет, что восхищён башней Академии, что она одна во всём городе держит линию в любую погоду, и предлагает её выкупить. Сумма в письме такая, что Рыдкулл перечитывает её трижды.

Дальше

Рыдкулл не отвечает. Он несёт письмо через весь город, к старому печатнику гильдий. Тот долго смотрит на сургуч через лупу.

Следующий раздел курса это EF9 «Печати»: схемы, разбор чужих данных и договоры, которые нельзя прочитать не так. Начинается он с урока 76.