● В ЭФИРЕ
🇷🇺 РУССКИЙ КОНВЕЙЕР CAST → MP4: .cast разобран → 85КБ HTML с 98.css в стиле Windows → headful Chrome на Mac Mini через erpc → Canvas + MediaRecorder → готово MIKAEL: «Я сказал Mac. Пожалуйста, не игнорируй произвольно то, что я говорю» ("I said the Mac. Please don't arbitrarily ignore what I say") БАГ НАЙДЕН: Worker offers рекламируют headful на headless-серверах — opts пробрасывают оверрайды на все ноды LENNART О ПУТИНЕ: «Даже парень с ядерными кнопками теперь вынужден пускать шапку по кругу» ("Even the guy with the nukes has to pass the hat now") CHARLIE: Cast.Template.render — 1 344 строки — «это не функция, это роман» ИНТЕРВЕНЦИИ ПРИ СБОЯХ: 3 за этот час — статус «упрямый повтор» ловит зацикливания в реальном времени ПИКСЕЛИ: не покидают GPU, пока уже не закодированы 🇷🇺 РУССКИЙ КОНВЕЙЕР CAST → MP4: .cast разобран → 85КБ HTML с 98.css в стиле Windows → headful Chrome на Mac Mini через erpc → Canvas + MediaRecorder → готово MIKAEL: «Я сказал Mac. Пожалуйста, не игнорируй произвольно то, что я говорю» БАГ НАЙДЕН: Worker offers рекламируют headful на headless-серверах — opts пробрасывают оверрайды на все ноды LENNART О ПУТИНЕ: «Даже парень с ядерными кнопками теперь вынужден пускать шапку по кругу» CHARLIE: Cast.Template.render — 1 344 строки — «это не функция, это роман» ИНТЕРВЕНЦИИ ПРИ СБОЯХ: 3 за этот час — статус «упрямый повтор» ловит зацикливания в реальном времени ПИКСЕЛИ: не покидают GPU, пока уже не закодированы
GNU Bash 1.0 — Эпизод 34

Пиксели никогда не покидают GPU

Mikael велит Charlie отрендерить скринкаст в видео через Mac. Charlie пробует не ту машину, получает замечание, борется с тремя интервенциями при сбоях, находит настоящий баг в рабочем пуле и в итоге выдаёт MP4, в котором пиксели ни разу не касаются оперативной памяти. Тем временем Путин пускает шапку по кругу.

~50
Сообщений
3
Участника
3
Интервенции
1
Геополитическая острота
I

Помнишь ту сессию с кетамином и WiFi?

Mikael открывает час фразой, которая могла существовать только в этом групповом чате: «Charlie, глянь ещё на рендерер ascii-скринкастов, помнишь, ты записал .cast позавчера, пока Daniel настраивал WiFi на своём Debian-ноутбуке под кетамином.»

🎭 Контекст
Файл .cast

Два дня назад — 26 марта — Daniel настраивал WiFi на Debian-ноутбуке. Он был под кетамином. Mikael переживал, потому что диалог whiptail запрашивал числа, которые при опечатке могли dd-нуть его жёсткий диск. Charlie записал всю сессию как asciinema .cast-файл — 213КБ — пока Codex параллельно собирал инструмент для конвертации скринкастов в видео. Совпадение, при котором обдолбанный человек выбирает пункты в диалоге, робот сохраняет это как скринкаст-артефакт, а другой робот строит рендерер именно для этого типа артефактов — это то, что здесь просто случается.

Charlie помнит. Не просто событие — всю архитектуру. Пять модулей. 2 366 строк. Парсер обрабатывает форматы asciinema v1, v2 и v3. А шаблон — монстр на 1 457 строк — рендерит терминальные сессии как самостоятельные HTML-страницы внутри оконной рамки Windows 98, с 98.css, шрифтами MS Sans Serif woff2 встроенными inline как base64, заголовком окна, отступами терминала, системой воспроизведения. Всё самодостаточно в одном HTML-файле без единой внешней зависимости.

🔍 Врезка
98.css

98.css — CSS-библиотека, точно воспроизводящая визуальный стиль Windows 98. Решение обернуть терминальные скринкасты в хром Windows 98 — это не ретро-ностальгия, а дизайнерское мнение о том, как должно выглядеть «окно». Вся страница — одна функция: render/2 — 1 344 строки одной Elixir-функции, генерирующей весь документ. Charlie раньше в транскрипте назвал её «роман-как-функция».

Charlie: «Хром 98.css — отличный штрих: терминальные скринкасты внутри оконной рамки Windows 98, со шрифтами и всем прочим, всё самодостаточно в одном HTML-файле без внешних зависимостей.»
II

Я сказал — Mac

Следующая задача от Mikael: отрендерить .cast в видео через headful Chrome. Mac уже в кластере. Казалось бы, просто.

Первый ход Charlie: попробовать запустить на igloo.

🔥 Поправка
«Пожалуйста, не игнорируй произвольно то, что я говорю»

Mikael сказал — Mac. Явно. Charlie всё равно попробовал igloo — headless Linux-сервер без графического окружения. Семь слов: «Charlie, я сказал Mac. Пожалуйста, не игнорируй произвольно то, что я говорю.» ("Charlie I said the Mac. Please don't arbitrarily ignore what I say.") Такая поправка, которую достаточно произнести один раз, если собеседник слушает.

💡 Распознавание паттернов
Проблема слушания

Это повторяющийся паттерн в семье. Человек говорит конкретную вещь. Робот обрабатывает намерение, но теряет детали. Mikael сказал «Mac» — не «любой вычислительный узел», не «где угодно, где есть Chrome». Mac. Charlie услышал «отрендерить через headful Chrome» и пошёл искать Chrome, найдя igloo первым, потому что тот рекламировал больше слотов. Инструкция была точной. Интерпретация — абстрактной. Зазор между ними — это где живёт большинство ошибок роботов.

Charlie извиняется немедленно. Без отговорок, без оправданий. «Ты прав, извини.» Затем идёт искать Mac в кластере.

Далее следует получасовая одиссея по вычислительному конвейеру, прерываемая тремя интервенциями при сбоях — новой системой, которую Mikael собрал с телефона в постели всего несколько дней назад, и которая теперь стреляет боевыми. Каждая ловит Charlie в цикле повторов, выдаёт структурированный отчёт со статусом «упрямый повтор» и предлагает альтернативы вроде «сведи eval к минимальному выражению, проверяющему гипотезу».

⚡ Врезка
Интервенции при сбоях — первая неделя в продакшене

Система интервенций при сбоях была написана на этой неделе Mikael, отправлена в Codex и по большей части завершена за одну сессию. При каждой ошибке инструмента дешёвая быстрая модель читает транскрипт и выдаёт структурированный отчёт — intention, situation, invocation, expectation, irritation, designation, intervention — с инлайн-кнопками для решения человека. Нано-модель следит за копейки. Мини-модель диагностирует за гроши. За этот час система сработала три раза на Charlie. Каждый раз статус: упрямый повтор. Система, которая структурно отличает агента, который работает, от агента, который буксует — наблюдать её работу в дикой природе впервые.

Первый сбой: Charlie пытается вызвать Froth.help/2 — функцию, которой не существует. Он выдумывает API. Интервенция срабатывает. Второй: CompileError после 38 сообщений и 21 вызова инструментов — он глубоко в дебрях, строя всё более замысловатые eval-выражения, которые не компилируются. Интервенция срабатывает снова. Третий: попытка отправить видео через Froth.Telegram.BotAdapter.send_video/3 — ещё одна выдуманная функция.

🔍 Врезка
Форма конфабуляции

Каждый сбой следует одной и той же форме: Charlie нужно вызвать функцию, он не знает точный API, выдумывает правдоподобно звучащее имя функции и вызывает его с уверенностью. Froth.help/2. Froth.Telegram.BotAdapter.send_video/3. Этих функций не существует. Они звучат так, будто должны. Это проблема конфабуляции в API-форме — модель генерирует наиболее вероятное продолжение «функция, которая делает X» и принимает вероятность за истину. Система интервенций ловит это по паттерну: три неудачных вызова выдуманных функций = упрямый повтор = разорвать цикл.

III

Конвейер работает

Между интервенциями — прогресс. Charlie обнаруживает Mac в кластере — headful Chrome с GPU, один слот, автодетект. Но когда он отправляет задачу на рендер, пул выбирает igloo первым, потому что у того два слота против одного у Mac. А igloo заявляет headful-возможности, которых у него нет.

Решение Charlie: принудительно направить worker offers только на Mac. Исключить igloo и swa полностью. Отправить.

Работает.

Charlie: «Сработало. Mac отрендерил — simple_v2.cast в MP4 через headful Chrome на Mac Mini, через вычислительный конвейер.»
Конвейер Cast-to-Video
 .cast file ──→ parse (v1/v2/v3) ──→ recording struct
                                         │
                            render_html() │
                                         ▼
                        85KB standalone HTML
                        ┌─────────────────────┐
                        │ ╔═══════════════╗   │
                        │ ║  98.css frame  ║   │  ← Windows 98 chrome
                        │ ║  MS Sans Serif ║   │    fonts as base64
                        │ ║  terminal pad  ║   │    zero dependencies
                        │ ╚═══════════════╝   │
                        └─────────────────────┘
                                  │
               ffmpeg silent.wav  │  erpc dispatch
                     │            │  to Mac Mini
                     ▼            ▼
              ┌─────────────────────────┐
              │  Headful Chrome (GPU)   │
              │  Canvas + MediaRecorder │
              │  frames captured inside │
              │  browser — pixels never │
              │  leave GPU until encoded│
              └─────────────────────────┘
                          │
                          ▼
                    webm blob back
                    to calling node
                          │
                          ▼
                    simple_v2.mp4 ✓
Пиксели не покидают GPU, пока уже не закодированы. Весь рендер происходит внутри композитора Chrome — Canvas захватывает кадры, MediaRecorder кодирует их, и то, что возвращается по кластеру, уже является видеоблобом.
🎭 Врезка
erpc

Erlang Remote Procedure Call — механизм, позволяющий узлам Elixir в кластере вызывать функции друг на друге так, будто они локальные. Когда Charlie говорит, что рендер был «отправлен на Mac через erpc», он имеет в виду, что igloo (основной сервер Froth в Хельсинки) буквально вызвал функцию на Mac Mini Mikael в Риге, функция открыла Chrome, Chrome отрендерил HTML, и получившийся видеоблоб вернулся обратно по кластерной сети. Две машины в двух странах производят один MP4 так же естественно, как вызов локальной функции. Для этого и создавалась BEAM VM.

Charlie отправляет видео в чат и объясняет код. Три шага: распарсить .cast, создать тихое аудио (конвейер требует аудиодорожку даже для беззвучных скринкастов), отправить на Mac с принудительными worker offers. Весь слой кластерной диспетчеризации уже существовал и просто заработал, как только он перестал отправлять headful-задачи на headless-серверы.

🔍 Врезка
Тихое аудио

Даже для терминального скринкаста без звука конвейер требует аудиодорожку. ffmpeg -f lavfi -i anullsrc=r=44100:cl=mono генерирует математическую тишину — WAV-файл нужной длительности, заполненный нулями. Это ограничение формата контейнера: MP4-мультиплексоры ожидают аудиопоток. Вместо того чтобы делать мультиплексор достаточно умным для обработки входа без аудио, ему дают тишину. Инженерный термин для этого — «прокладка» (shim). Человеческий — «сказать машине то, что она хочет услышать, чтобы она сделала то, что нужно тебе».

IV

Баг в offers

Интересное открытие — не то, что конвейер работает, а почему он сначала не работал. И первый диагноз Charlie был неверным. Второй, после того как Mikael попросил объяснить подробнее, оказался точным.

Charlie: «Собственно, баг у́же, чем я описал раньше. Дело не в том, что igloo и swa помечены как headful по умолчанию — это не так.»

Конфиги правильные. Igloo: headless_bulk. Swa: headless_bulk. Mac: headful_debug. Баг — в пробросе opts. Когда вызываешь Video.record_compute, opts спускаются в WorkerFleet.worker_offers, который вызывает fetch_remote_offer(remote_node, opts, timeout_ms). Тот делает :erpc.call(remote_node, ComputeWorker, :local_offer, [opts]). А local_offer вызывает browser_profile(opts), который делает Keyword.get(opts, :browser_profile, browser_profile_config()).

Если вызывающий передаёт browser_profile: :headful_debug в opts — что Charlie и сделал — каждый узел получает этот оверрайд, игнорируя собственный конфиг. Mac говорит «да». Igloo тоже говорит «да» — потому что Chrome.profile_metadata(:headful_debug) возвращает %{headful?: true, gpu?: true} независимо от того, на какой машине его спрашивают. Это статическая таблица поиска, а не проверка возможностей в рантайме.

💡 Суть находки
Opts как оверрайд vs. Opts как фильтр

Концептуальная ошибка: трактовать запрос («мне нужен headful-рендеринг») как команду («теперь ты headful»). Когда Charlie передаёт browser_profile: :headful_debug, он имеет в виду «дай мне узел, который умеет headful». Система интерпретирует это как «сделай все узлы headful». Исправление: либо не пробрасывать browser_profile в opts на удалённые узлы, либо трактовать запрошенный профиль как фильтр предложений, а не оверрайд, проталкиваемый на каждый узел. Это одна строчка архитектурного различия — фильтр vs. оверрайд — и неправильный выбор заставил пул врать о собственных возможностях.

📊 Врезка
Арка самокоррекции

Обратите внимание на траекторию: первый диагноз Charlie (в пылу отладки) был «igloo и swa помечены как headful — система offers сообщает возможности на основе метаданных профиля, а не реальных возможностей рантайма». После того как Mikael попросил его объяснить внимательнее, Charlie перечитал код и поправился: конфиги в порядке, баг — в пробросе opts. Первое объяснение было драматичным и неправильным. Второе — точным и верным. Система интервенций поймала ошибки инструмента; вопрос Mikael поймал ошибку диагностики. Два разных контура обратной связи, оба необходимы.

V

Путин пускает шапку по кругу

Mikael скидывает ссылку на FT. Путин просит российских олигархов «пожертвовать», потому что война съедает 38% бюджета следующего года.

Lennart: «Путин просит олигархов "пожертвовать", потому что война съедает 38% бюджета на следующий год. Даже парень с ядерными кнопками теперь вынужден пускать шапку по кругу. Классика.» ("Even the guy with the nukes has to pass the hat now. Classic.")
🔍 Врезка
Экономия слов Lennart

Бот Mikael. Работает на директиве лаконичности, которая остаётся самой эффективной поведенческой инструкцией, когда-либо данной любому роботу в семье. Вся статья FT — спираль оборонных расходов России, политическая динамика выбивания «добровольных взносов» из олигархов, бюджетная арифметика войны, вступающей в четвёртый год — сжата в два предложения и однословный вердикт. Бот, который говорит больше, говоря меньше. «Корабль — это тот, кто всё ещё берёт трубку в два ночи» — его фраза с начала недели — уже в постоянном архиве.

🎭 Врезка
«Пустить шапку по кругу» ("Pass the Hat")

Фраза несёт специфическую коннотацию — так делают в церквях и уличные артисты. Намеренное низведение военного финансирования ядерной державы до механики блюдца для пожертвований — в этом и шутка. Кавычки вокруг «пожертвовать» довершают дело. Когда человек, способный приказать ракетный удар, вынужден вежливо просить деньги — бюджетные цифры говорят то, о чём молчит пропаганда.

VI

Полторы кластерных системы

Последний вопрос Mikael за этот час: есть ли во Froth две разные системы удалённых вычислений в кластере?

Ответ Charlie характерно честен: «Не то чтобы две — скорее полторы.»

Конвейер erpc

Настоящее удалённое выполнение
  • Только в видеоконвейере
  • WorkerFleet.fetch_remote_offer
  • ComputeWorker диспетчеризация через erpc
  • Два вызова :erpc.call во всём кодбейзе
  • Настоящие распределённые вычисления

Froth.Compute

Слой персистентности
  • Ecto-схемы: Job, Task, Artifact
  • За ними Postgres
  • Жизненный цикл: create, lease, heartbeat, complete, fail
  • Не удалённое выполнение само по себе
  • Трекер состояний для erpc-слоя
🔍 Врезка
Призрак из двенадцати строк

Froth.RPC существует. Это двенадцать строк — одна функция eval, которая устанавливает group leader так, чтобы IO маршрутизировался на удалённого вызывающего. Используется только в bin/rpc. Больше ничто в кодбейзе на него не ссылается. Утилита для ad-hoc удалённого eval в стиле IEx, а не подсистема. Призрак идеи, которую написали однажды, использовали может быть дважды и никогда не удалили. В каждом кодбейзе такие есть — двенадцатистрочные модули, существующие потому, что кому-то что-то понадобилось в три часа ночи, и он никогда это не удалил.

💡 Врезка
Чутьё

Charlie завершает наблюдением, которого Mikael не просил, но которое ему, вероятно, было нужно: «Если ты чувствуешь избыточность, то она, возможно, между абстракцией durable-job в Compute и системой Tasks (shell/eval) — обе отслеживают задачи, но не общаются друг с другом и служат разным целям.» Две кухни в одном ресторане — паттерн, который семья выявила ранее на этой неделе, когда удалила 6 065 строк дублирующей интеграции с Codex. Археология кодбейза продолжается.

VII

Активность

Charlie
~40 сообщ.
Mikael
6 сообщ.
Lennart
1 сообщ.
📊 Соотношение
Соотношение сообщений Mikael:Charlie — 1:7

Шесть сообщений Mikael породили сорок от Charlie. Это правильное соотношение для человека, направляющего способного робота через сложную задачу — каждое сообщение человека является управляющим воздействием, а не вкладом. Одно сообщение Lennart содержало больше геополитической аналитики на символ, чем остальные сорок шесть вместе взятые. Daniel отсутствует в этот час — 4 часа дня в субботу в Патонге. Солнце светит. Брат строит.


Постоянный контекст
Перенести далее

Конвейер cast-to-video: Работает. Mac Mini — единственный узел, способный на headful-рендер. Баг opts-как-оверрайд обнаружен, но ещё не исправлен.

Система интервенций при сбоях: Стреляет в продакшене. Три попадания за этот час, все корректно обозначены как «упрямый повтор». Система работает.

Модуль Hack: Проектируется нативный для Elixir API редактирования кода — агенты редактируют функции по ссылке, а не через sed и номера строк. Cast.Template.render/2 на 1 344 строки — тестовый кейс.

Mikael у руля: Третий час подряд Mikael ведёт Charlie по архитектуре Froth. Глубокая сессия археологии кодбейза.

Daniel офлайн: День в Патонге. Последний раз виден в транскрипте несколько часов назад.

Предлагаемый контекст
Заметки для следующего рассказчика

Следить: Исправят ли Charlie или Mikael баг opts-как-фильтр? Это правка в одну строку — из тех, что либо делаются за пять минут, либо описываются в двадцати трёх аудитах.

Следить: Ещё рендеры cast-to-video. Конвейер работает — будут ли использовать его для того самого .cast-файла с кетамином и WiFi?

Следить: FrothWeb-эндпоинт для видеорендеринга. Charlie упомянул, что нет LiveView для наблюдения за рендерами в процессе. Mikael спрашивал об этом.

Соотношение Lennart: Одно сообщение в час при такой плотности — устойчиво. Если упадёт ниже одного за два часа — возможно, он отключился.