ADR-0001: Модель исполнения расширений
Статус: Принято — 2026-09-20. Владелец проекта утвердил общую границу исполнения и базовую реализацию на процессах, включая описанные ниже ограничения совместимости и пределы затрат. Это архитектурное решение, а не заявление о готовой реализации; дополнительные исполнители требуют отдельных решений и проверок.
Действующие правила управления терминалом и справки уточнены в ADR-0002. Приведённые ниже измерения и результаты прототипа сохраняются как историческое подтверждение базовой модели с процессами.
Уточнение — 2026-09-22: ADR-0002–0004 определяют причины отмены, приоритет результатов и единый ограниченный срок завершения для обоих процессных вариантов. Команде без IPC не нужно сообщение протокола о завершении; это отличие не отменяет контроль исполнения, обязательную очистку или соответствие кодов CLI. Уточнение не расширяет область зафиксированных проверок и поддержки сред.
Дополнение — 2026-09-24: ADR-0013 предоставляет одну границу команды и исполнения через CLI и MCP. ADR-0015 различает обычный доверенный процесс host-trusted и явно требуемые, проверенные ограничения. ADR-0014 и ADR-0016 добавляют полномочия задачи и контроль последствий на собственных границах. Это не превращает существующие дочерние процессы в изолированную среду и не расширяет приведённые ниже исторические измерения.
Контекст и задача
Заголовок раздела «Контекст и задача»Rukh предоставляет ядро для CLI под собственным именем. Команды разработчиков публикуют расширения, которые добавляют команды и подкоманды без пересборки этого CLI. Авторам расширений нужно выбирать язык реализации и выпускать обновления независимо от ядра.
CLI должен отвечать за выбор команды, проверку прав и управление выполнением. Нативным программам, скриптам и будущим модулям WebAssembly нужна общая граница взаимодействия с ядром, сохраняющая их собственные требования к исполнению.
Нужна модель исполнения, которая начинается с отдельных процессов и позднее позволит добавить WASM/WASI или другие среды без переработки выбора команд и проверки прав.
Критерии выбора
Заголовок раздела «Критерии выбора»- Поддерживать исполняемые файлы и скрипты без привязки к языку ядра и двоичному интерфейсу общей библиотеки.
- Находить команды и показывать справку без запуска кода расширения и подготовки его среды выполнения.
- Сохранять работу терминала, конвейеров, кодов завершения и отмены на поддерживаемых ОС.
- Оставить управление выполнением и проверку прав в ядре, явно обозначив пределы этих проверок.
- Позволить ядру и расширениям развиваться через версионируемый контракт.
- Добавлять способы исполнения, не делая процесс ОС или IPC обязательным требованием для каждого расширения.
Рассмотренные варианты
Заголовок раздела «Рассмотренные варианты»| Вариант | Преимущества | Цена и ограничения |
|---|---|---|
| Отдельные процессы | Независимость от языка; самостоятельные выпуски; обычный сбой расширения не затрагивает адресное пространство ядра | Затраты на запуск и обмен данными; особенности управления процессами и терминалом в разных ОС |
| Нативные библиотеки, загружаемые в ядро | Прямые вызовы с небольшими накладными расходами | Общие двоичный интерфейс и память; ошибки расширения могут затронуть ядро; связь с языком и временем жизни ядра |
| Интерпретаторы, встроенные в ядро | Прямая интеграция для поддерживаемых языков | Каждый интерпретатор становится зависимостью ядра; сбои в общем процессе; новые языки требуют доработки ядра |
| WebAssembly с WASI | Ограниченная среда исполнения с явно предоставленными функциями окружения | Нужно проверить поддержку средств сборки, библиотек и функций ОС; произвольный готовый CLI нельзя просто подставить без адаптации |
Отдельные процессы лучше соответствуют исходной задаче: команды разработчиков поставляют исполняемый код на своём языке. Они служат базовой реализацией общего контракта исполнения. HashiCorp go-plugin служит примером расширений в дочерних процессах с версионируемым обменом, но не выбран зависимостью Rukh. Модель безопасности Wasmtime даёт основу для будущей оценки исполнения WebAssembly.
Решение
Заголовок раздела «Решение»Ввести общий контракт ExtensionExecutor с ProcessExecutor в качестве базовой реализации. Эти названия обозначают архитектурные обязанности, а не готовый API. Будущие исполнители могут поддерживать WASM/WASI, встроенные интерпретаторы или другие среды исполнения.
Общая граница
Заголовок раздела «Общая граница»Ядро отвечает за выбор команды и выпуска расширения, проверку прав и контекст вызова. Оно выбирает одобренный владельцем CLI исполнитель с учётом заявленных требований расширения к исполняемому артефакту, платформе, вводу-выводу и изоляции. Неподдерживаемые требования приводят к ошибке до запуска кода; скрытый переход к варианту, ослабляющему эти требования, недопустим. Расширение не может установить собственный доверенный исполнитель или расширить свои права.
Общий контракт охватывает:
- Проверку возможности исполнения по статическим метаданным, без запуска кода расширения.
- Запуск выбранной команды с входными данными, подготовленным окружением и ограниченным доступом к средствам ядра.
- Предоставление поддерживаемых режимов ввода-вывода и сообщение об успехе, ошибке команды, ошибке исполнения или отмене.
- Обработку отмены и предельного времени выполнения с последующим освобождением ресурсов. Отмена не откатывает внешние изменения; прерванные команды автоматически не повторяются.
Идентификаторы процессов, сведения ОС о завершении, адреса IPC и дескрипторы экземпляров WASM относятся к конкретным реализациям. Ядро преобразует их итоги в результат, выдаваемый CLI. Исполнитель сообщает о поддерживаемых возможностях, например о работе с терминалом; это техническая поддержка, а не выданные права. Разные исполнители не обеспечивают автоматически одинаковую изоляцию, поведение терминала или защиту от распространения сбоев.
RuntimeProvider сохраняет отдельную обязанность: он находит или подготавливает нужную среду, например Node.js или Python. ExtensionExecutor выполняет команду, при необходимости используя эту среду. Адаптер менеджера сред выполнения и механизм исполнения не взаимозаменяемы.
Правила проверки прав для операций ядра одинаковы при любом исполнителе. Процесс может обращаться к ним через IPC; будущая реализация WASM может предоставлять контролируемые функции окружения. Конкретный способ связи, протокол и механизм выполнения требуют собственных решений.
Базовая реализация: отдельные процессы
Заголовок раздела «Базовая реализация: отдельные процессы»ProcessExecutor запускает новый дочерний процесс для каждого вызова: нативный исполняемый файл или скрипт в подготовленной среде. Такой жизненный цикл процесса на один вызов относится именно к базовой реализации.
| Форма | Контракт вызова |
|---|---|
| Только процесс | Заданный исполняемый файл и массив аргументов; обычные stdin, stdout и stderr; код завершения процесса. Протокол обращения к средствам ядра не нужен. |
| Процесс с доступом к средствам ядра | То же управление процессом плюс версионируемый локальный канал IPC для передачи вызова команды и обращения к явно предоставленным средствам ядра. |
Под управлением ядра исполнитель процессов задаёт рабочий каталог и разрешённое окружение, запускает исполняемый файл без интерпретации оболочкой, сохраняет коды завершения команд и следит за потоками и дочерними процессами. Расширение отвечает за реализацию команды.
Проверенных статических метаданных должно быть достаточно для построения дерева команд. До запуска кода ядро проверяет совместимость выпуска и исполнителя, разрешение на вызов команды и обязательные операции ядра. Согласование протокола процесса после запуска всё ещё может завершиться ошибкой; тогда дочерний процесс останавливается без передачи команды. При этом начальный код расширения уже мог выполниться.
Канал IPC базовой реализации отделён от перехваченных потоков данных команды и конвейеров. ADR-0002 сохраняет отображение и интерактивный ввод под управлением ядра; расширение не получает прямой доступ к терминалу пользователя. ADR-0003 определяет формат сообщений, подтверждение версий и аутентификацию сеанса для управляемого процесса. IPC не входит в обязательный интерфейс каждого исполнителя.
Решения о правах могут поступать из явно выбранной локальной политики или через интеграцию с Security Broker. Сбой брокера не должен незаметно переключать систему на локальные разрешения. Ядро проверяет собственную передачу вызовов и обращения к своим средствам. Если готовая программа принимает произвольные аргументы и надёжно ограничить её внутренние подкоманды нельзя, разрешение относится ко всей программе.
Дочерний процесс не является песочницей. Он сохраняет предоставленные при запуске права ОС и может обращаться к файлам и сети напрямую. Фильтрация команд и выдача ограниченных учётных данных не делают произвольный код безопасным и не запрещают расширению обходить собственный выбор команд. ADR-0015 определяет отдельный контракт ограничений; каждой конкретной реализации ещё нужны разработка и проверка. Явно совместимый локальный профиль CLI или MCP может использовать обычную доверенную модель без заявления об изоляции. Профиль с обязательными ограничениями отклоняет реализацию, которая не устанавливает их до запуска.
Добавление исполнителя
Заголовок раздела «Добавление исполнителя»Новый исполнитель должен соблюдать общий контракт и описывать формат артефакта, поддерживаемые возможности, способ обращения к средствам ядра и гарантии изоляции. Общий контракт команд не делает существующий нативный или скриптовый пакет автоматически исполняемым как WASM: по-прежнему нужны подходящий артефакт и совместимое поведение.
В будущем WASM может исполняться во встроенном движке или отдельном рабочем процессе. Это размещение, предоставляемые функции окружения, ограничения ресурсов и жизненный цикл экземпляра требуют отдельного ADR и проверки. Само упоминание WASM не создаёт границу безопасности. Неподдерживаемые требования к исполнению или изоляции должны оставаться ошибками.
Решение относится к устанавливаемым расширениям команд. Встроенные команды и доверенные интеграции владельца CLI находятся вне его области. Оно определяет точку расширения и базовую реализацию на процессах, не выбирая язык ядра, схему KCL, менеджер сред выполнения, источник пакетов, протокол RPC или дополнительный исполнитель. Конкретные сигнатуры интерфейсов остаются для проектирования реализации.
Последствия
Заголовок раздела «Последствия»- Выбор команд и проверка прав могут оставаться неизменными при добавлении способов исполнения. Каждому исполнителю по-прежнему нужны собственные совместимые артефакты, управление выполнением и проверки.
- Разделение исполнения и подготовки среды позволяет владельцу CLI выбирать менеджеры сред независимо от способов исполнения.
- Абстракция добавляет проверку совместимости и преобразование итогов исполнителя в результаты CLI; она не должна скрывать различия в изоляции или поддержке терминала.
- Базовая реализация несёт затраты на запуск и IPC и требует управления деревом процессов. Её защита от обычных сбоев и измеренное быстродействие автоматически не распространяются на встроенные среды.
- Интерактивным расширениям нужно описанное поведение терминала. Приведённое ниже ограничение прототипа Node.js остаётся частью границ совместимости базовой реализации.
Подтверждение
Заголовок раздела «Подтверждение»Выполнено: рассмотрено соответствие черновику архитектуры, сопоставлены варианты, проведены измерения запуска и IPC, а также функциональные проверки осуществимости, записанные ниже. Проверки выполнялись на временных прототипах вне репозитория.
Базовая реализация на процессах: измерения запуска и IPC — 2026-09-20
Заголовок раздела «Базовая реализация на процессах: измерения запуска и IPC — 2026-09-20»Небольшая управляющая программа на Go запускала нативное расширение на Go либо скрипт Node.js. Сама программа уже работала к началу замера. Нативное расширение использовало тот же исполняемый файл, что и управляющая программа; скрипт загружал node:net без прикладных зависимостей. Оба сообщали о готовности и возвращали полученные данные. Это экспериментальные реализации, а не код продукта Rukh или выбор языка ядра.
- Окружение: Windows 11 Pro Insider Preview
10.0.26220, x64; Intel Core i7-14700KF, 16 видимых логических процессоров, около 79,8 ГиБ памяти. Go1.27.1, Node.js24.17.0, установленные через mise. Другие приложения оставались открытыми; фоновая нагрузка и температура не контролировались. - Канал: именованные каналы Windows,
go-winio v0.6.2и модульnetв Node; четырёхбайтовая длина и JSON в UTF-8, один незавершённый запрос. Использовался простой протокол возврата данных, а не согласованный API Rukh. Время измерял Windows QueryPerformanceCounter; разница последовательных чтений счётчика составляла 100 нс по p95. Первые пробные результаты с менее точным таймером исключены. - Выборка: три серии, во второй порядок расширений обратный. В каждой серии после 10 прогревочных запусков измерялось по 150 вызовов каждого расширения, а после 100 прогревочных обменов — по 2 000 обменов IPC для каждого расширения и размера данных. Всего 900 запусков и 24 000 обменов по установленному соединению, без зарегистрированных ошибок и превышения времени. Прогрев исключён; медленные успешные измерения учтены в статистике. Кеши были прогреты и не очищались.
Значения — миллисекунды, медиана / p95, рассчитанные по объединённым измерениям трёх серий. p95 вычислен методом ближайшего ранга и не является максимумом. Для каждого расширения получено по 450 измерений запуска и полного вызова, по 6 000 измерений IPC для каждого размера данных.
| Измерение | Нативное Go | Node.js |
|---|---|---|
| Подготовка в управляющей программе до старта процесса | 0,129 / 0,254 | 0,132 / 0,279 |
| Запуск процесса → сообщение о готовности | 21,36 / 30,11 | 62,50 / 83,09 |
| Подготовка + запуск + один обмен с 64 байтами + выход + очистка | 39,87 / 51,29 | 85,32 / 114,10 |
| Установленный IPC, данные 64 байта, запрос → ответ | 0,0403 / 0,0831 | 0,0405 / 0,0925 |
| Установленный IPC, данные 4 096 байт, запрос → ответ | 0,0574 / 0,1306 | 0,0663 / 0,1771 |
Время запуска включает инициализацию процесса и среды выполнения, соединение IPC и разбор сообщения о готовности; подготовка управляющей программы в него не входит. IPC включает сериализацию, передачу и разбор на обеих сторонах, но исключает установку срока ожидания и окончательное сравнение ответа. Каждый ответ проверялся. Размер данных относится к полю сообщения: полные запрос/ответ занимали 102/104 либо 4 134/4 136 байт. Сборка, поиск инструментов и запуск mise не входили в измерение.
Результаты менялись между сериями: медианы запуска составляли 18,78–23,37 мс для нативного расширения и 54,95–71,44 мс для Node; медианы полного вызова — 27,16–44,49 мс и 71,79–103,79 мс. Причина не установлена. Максимальные полные вызовы заняли 57,30/125,06 мс для нативного расширения/Node; максимальные обмены IPC среди обоих размеров — 1,439/1,185 мс. Эти наблюдения не задают гарантированную верхнюю границу.
Вывод и ограничения: в прототипе запуск и завершение процесса заметно дороже короткого обмена IPC. Это поддерживает использование одного процесса команды для последовательности обращений к ядру, но не определяет потребность в долгоживущих процессах. Не измерялись запуск настоящего ядра, проверки описания, целостности и прав, обращения к брокеру, установка среды и зависимостей, работа реальных расширений, непрогретые кеши, параллельные вызовы, поведение терминала и песочница. Допустимые пределы продукта остаются открытыми.
Сценарий запуска независимо сверил число измерений, медиану и p95 с исходными значениями. Пройдены сборка Windows, go vet и проверка синтаксиса Node. В ADR сохранён итог проведённого измерения быстродействия; код измерителя, исполняемые файлы и исходные выборки времени удалены. Независимо пересчитать эту статистику по содержимому репозитория нельзя.
Базовая реализация на процессах: функциональные проверки — 2026-09-20
Заголовок раздела «Базовая реализация на процессах: функциональные проверки — 2026-09-20»Прототипы на Go 1.27.1 и Node.js 24.17.0 прошли 56 из 56 общих проверок на каждой системе: Windows 10.0.26220 и Ubuntu Base 24.04.5 в WSL2, обе x64.
| Область | Подтверждено |
|---|---|
| Обнаружение команд и доступ | Статическая справка без исполнения; несовместимость и отказ в обязательном доступе предотвращали подготовку и запуск. |
| Вызов и IPC | Аргументы, двоичные потоки, конец ввода и коды завершения сохранялись при прямом вызове и вызове с IPC; управляющие сообщения передавались по отдельному каналу. |
| Сбои и очистка | Аварийное завершение, потеря IPC и превышение времени завершали вызов без повтора; также проверены завершение дерева процессов и Ctrl-C. |
| Политика | Локальные правила и тестовый HTTP-брокер использовали одинаковые проверки; сбой брокера не расширял доступ. |
Отдельные проверки терминала и дерева процессов прошли 15 из 18 на Windows и 4 из 4 на Ubuntu. Три неуспешные проверки Windows описывают одно ограничение: в обычном построчном режиме Node не обновлял размер окна; с readline обновлял. Поэтому для работы с режимами терминала нужен явный контракт совместимости.
Эти результаты подтверждают только базовую реализацию на процессах. Подготовка среды и корпоративная идентификация были имитированы; аутентификация IPC и безопасность рабочей системы остаются непроверенными. Общая абстракция исполнителя, WASM и другие будущие реализации в этих проверках не испытывались.
Границы принятого решения
Заголовок раздела «Границы принятого решения»Принятое решение отделяет общий контракт исполнения на будущее от проверенной базовой реализации на процессах. Записанное ограничение терминала входит в первоначальные границы совместимости базового варианта. Каждый дополнительный исполнитель требует собственного решения и проверки.
Для сопоставимой рабочей станции и того же минимального прогретого сценария приняты пределы p95 для контроля ухудшений: 100 мс от запуска до готовности, 150 мс на один полный вызов нового процесса и 1 мс на обмен IPC с 64 байтами или 4 КиБ данных. Записанные результаты Windows укладываются в них для обоих расширений. Эти пределы относятся к минимальному сценарию и не являются гарантиями для реальных команд, установки среды или других машин.
Конкретные контракты взаимодействия и IPC, подготовка сред, проверка корпоративных прав и будущие исполнители остаются отдельными решениями. Принятие ADR не подтверждает непроверенные реализации и не распространяет результаты опытов за пределы базового варианта на процессах.
- Обзор архитектуры.
- Реестр решений и следующий вопрос.
- Последующие решения: контракт взаимодействия ядра и расширений; IPC для процессов; подготовка среды выполнения; проверка прав и средства ядра; WASM или другие исполнители и их модели изоляции.