Перейти к содержимому

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 ГиБ памяти. Go 1.27.1, Node.js 24.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 для каждого размера данных.

ИзмерениеНативное GoNode.js
Подготовка в управляющей программе до старта процесса0,129 / 0,2540,132 / 0,279
Запуск процесса → сообщение о готовности21,36 / 30,1162,50 / 83,09
Подготовка + запуск + один обмен с 64 байтами + выход + очистка39,87 / 51,2985,32 / 114,10
Установленный IPC, данные 64 байта, запрос → ответ0,0403 / 0,08310,0405 / 0,0925
Установленный IPC, данные 4 096 байт, запрос → ответ0,0574 / 0,13060,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 не подтверждает непроверенные реализации и не распространяет результаты опытов за пределы базового варианта на процессах.

Диаграмма

Перетаскивайте схему · + / − — масштаб · 0 — целиком · Esc — закрытьПеремещайте и увеличивайте схему двумя пальцами

100%