Планировщик узла переносим: из 224 строк мира в нём пять, а решений 219 — и они печатаются во все восемь целей
В базе знаний стояло: «вторая половина узла — таблица процессов с планировщиком, 219 строк кода — этим приёмом не берётся: она не решает о мире, она ЕСТЬ планировщик». Утверждение проверено счётом и оказалось неверным.
Счёт. flang/conc/distributed.mjs, строки 380–683 — 224 строки кода. Мира в них ПЯТЬ: setImmediate (558), setTimeout (493, 494, 623) и два чтения часов (507, 583). Остальные 219 — решения: кто готов бежать, влезет ли письмо в ящик, куда вернуть отложенное, кому уходит отказ.
Где на самом деле проходит граница. «Есть планировщик» — свойство не КОДА, а того, кто ДЕРЖИТ УПРАВЛЕНИЕ. У планировщика ровно две вещи, которых в языке нет: чтение часов (это мир) и вызов обработчика по имени (это не мир, а граница языка: передать функцию туда, где она приезжает данными, flang не умеет, — та же причина, по которой цикл поручений принадлежит хозяину). Убери эти две — и останутся решения.
Отсюда устройство, ровно как у слоя связи: на входе состояние узла и то, ЧТО СЛУЧИЛОСЬ, на выходе новое состояние и ВЕЛЕНИЯ. Обработчика планировщик не зовёт, а ВЕЛИТ позвать, и его ответ приезжает следующим событием.
Чем подтверждено. flang/conc/scheduler.flang — 506 строк, 305 кода, мира ноль; 7 событий хозяина, 6 велений хозяину, одна функция «Шаг узла». flang/test/planirovshchik-celi.test.mjs: 384 состояния узла (полный перебор пяти признаков своего процесса и двух признаков представителя) × 22 события = 8468 вопросов каждой цели, 67 744 сверки, расхождений 0, все восемь целей собраны настоящим тулчейном. Ветка vypusk/uzel-vezde, коммит 41050ddc.
Изъятие: убрать из «Ящик полон» слагаемое «в лёте» — краснеет один пример и все восемь целей разом.
Что из этого следует дальше. Рантайм цели можно ПЕЧАТАТЬ. Вывод старой заметки «узел — это не программа на языке, это часть рантайма цели» остаётся верным; новое в том, что эта часть рантайма пишется на flang один раз, а не семь раз руками.
Чем ограничено. Надзор (перезапуск упавшего, порог отказов, передача выше) в этот модуль НЕ перенесён. Он уже выражен на flang в flang/self/conc.flang, и второй его текст был бы вторым источником правды. Отказ процесса здесь заканчивается велением «Уронить процесс» — узел говорит надзору, а не решает за него. Порождения процессов на ходу тоже нет: у распределённого узла размещение объявлено заранее.
Связано: a-decision-about-the-world-is-portable-even-when-the-world-is-not, a-message-payload-travels-as-a-ticket-not-as-a-value, a-node-cannot-be-an-ordinary-program-because-of-the-literal-addressee, cikl-porucheniy-prinadlezhit-hozyainu-a-ne-yazyku