ADR-0003: IPC процессов и проверка подлинности сеанса
Статус: Принято — 2026-09-21. Владелец проекта утвердил устройство IPC процессов, базовые ограничения и зафиксированную область проверок, сохранив известное превышение времени запуска Python. Принятие определяет архитектуру, а не готовый протокол или завершённую реализацию продукта.
Уточнение — 2026-09-22: соответствие кодов завершения относится ко всем процессным вызовам, включая команды без IPC; реализовывать протокол им не требуется. Ниже явно определены причины отмены и единый срок остановки. Исторические измерения и проверки сохранены; уточнённые случаи требуют дополнительных проверок соответствия.
Уточнение — 2026-09-24: приняты дополнения для единой модели CLI/MCP и агентного использования по ADR-0013 и ADR-0014–0016. Исходная дата принятия и исторические проверки сохранены; новые требования не объявляются реализованными или проверенными.
Контекст и задача
Заголовок раздела «Контекст и задача»ADR-0001 устанавливает отдельные процессы как базовый способ исполнения. ADR-0002 определяет вызов, операции ядра, управление терминалом и завершение независимо от транспорта. Управляемому процессу нужен конкретный канал, который сохраняет эти правила при разных языках реализации.
Решение касается процессов, которые ядро запускает и контролирует для одного вызова. Обычным командам, работающим только как процессы, этот протокол не нужен. Удалённые расширения, постоянно работающие процессы, доверие к реестрам, схема KCL и установка сред исполнения находятся вне его области. Будущие исполнители, включая WASM, могут реализовать правила ADR-0002 без IPC процессов.
Критерии выбора
Заголовок раздела «Критерии выбора»- Отделить управляющие сообщения от входных и выходных данных команды.
- Связать канал с процессом, который запустило ядро, не доверяя заявленному имени или ID вызова.
- Поддержать разные языки с помощью небольших адаптеров с явными правилами для каждой платформы.
- Ограничить память, ожидание и очистку ресурсов; сохранить возможность отмены под нагрузкой.
- Сохранить правила доступа, единственный итоговый результат и отсутствие автоматических повторов действий.
Рассмотренные варианты
Заголовок раздела «Рассмотренные варианты»| Вариант | Преимущество | Ограничение |
|---|---|---|
| Сообщения внутри stdin/stdout | Привычные API потоков | Конфликт с конвейерами, перенаправлением байтов и независимым управлением |
| Уже соединённый канал, наследуемый только нужным процессом | Нет публичного адреса подключения и прикладного обмена для проверки подлинности | Требуется проверенная передача дескрипторов для каждой среды исполнения |
| Локальный слушающий канал с новым секретом доступа для каждого запуска | Привычные API подключения к сокетам | Добавляет гонки подключений, передачу секрета, взаимную проверку подлинности и правила целостности канала |
| Локальный TCP с готовым протоколом проверки подлинности | Широкая поддержка библиотеками | Добавляет настройку сети и управление секретами доступа к задаче локального дочернего процесса |
Решение
Заголовок раздела «Решение»Используется один закрытый, уже соединённый байтовый канал на вызов с ограниченным профилем JSON-RPC 2.0. Ядро создаёт оба конца до запуска расширения и передаёт этому процессу только конец расширения. Владение этим дескриптором ОС устанавливает границу сеанса; подтверждающие сообщения устанавливают совместимость. Повторное подключение, повторное использование сеанса и автоматический переход к слушающему каналу отсутствуют.
Канал и владение
Заголовок раздела «Канал и владение»Каналы разделяют данные команды, управление и отображение. Ни один из них не передаёт расширению управление терминалом.
| Платформа | Подготовка канала |
|---|---|
| Unix-подобные системы | Соединённая пара сокетов AF_UNIX / SOCK_STREAM, без пути в файловой системе и слушающего сокета |
| Windows | Пара концов локального именованного канала в байтовом режиме, соединённая ядром до запуска; обязательны новое имя, явная DACL, запрет удалённых клиентов, создание первого экземпляра и nMaxInstances=1 |
В Windows временное имя относится только к подготовке: дочерний процесс получает подключённый дескриптор, а не адрес для подключения. Перед передачей конца ядро проверяет, что оба подключённых конца принадлежат создаваемому им каналу; неожиданное подключение прерывает подготовку. Оно не оставляет доступного экземпляра для другого клиента и никогда не разъединяет и не использует этот канал повторно для нового сеанса. Подключённый серверный дескриптор остаётся открытым как конец ядра; после подготовки нет ожидания нового подключения. Байтовый режим не добавляет границ сообщений со стороны ОС. Создание каналов Windows, управление доступом к каналам.
Средство запуска явно разрешает передать через границу процесса только нужные стандартные потоки и управляющий конец расширения. Сразу после успешного запуска оно закрывает свою копию конца расширения, а при ошибке — все концы. Адаптер расширения запрещает дальнейшее наследование до запуска обработчиков расширения. В Unix это требует явного управления закрытием дескрипторов при exec; в Windows — явного списка наследуемых дескрипторов с безопасной обработкой одновременных запусков в приложении, использующем ядро как библиотеку. Это обязанности средства запуска, а не указания, выполнение которых оставлено авторам команд. Наследование дескрипторов Windows.
Нативному коду, Node.js, Python и Lua нужен проверенный адаптер для выбранной среды исполнения и платформы. Числовой дескриптор Windows не является переносимым файловым дескриптором; нельзя обещать, что fd 3 работает везде. Адаптеру может понадобиться небольшой нативный модуль. Неподдерживаемая передача или асинхронный ввод-вывод — известная ошибка совместимости до запуска, а не повод переключиться на stdout или TCP. Поставщик среды исполнения предоставляет окружение; одобренные средство запуска и адаптер устанавливают этот канал.
В Windows оба конца используют overlapped I/O — асинхронные операции ОС. Чтение и запись имеют отдельные состояния и события завершения; ожидающее чтение не должно блокировать запись. Средство контроля может отменить незавершённый ввод-вывод и соблюсти срок остановки. В эталонном опыте синхронные операции с общим дескриптором останавливали обмен; отдельных потоков чтения и записи оказалось недостаточно. Асинхронные операции с каналами Windows.
Контроль процесса устанавливается до разрешения исполнения кода расширения. В Windows средство запуска создаёт процесс приостановленным, включает его в Job Object с завершением при закрытии и запретом выхода из группы, затем возобновляет начальный поток. Ошибка на любом шаге останавливает приостановленный процесс и закрывает канал; invoke не передаётся. Дескриптор группы не наследуется. Очистка охватывает процессы внутри этой группы, а не работу, переданную внешним службам. Группы процессов Windows.
Область проверки указана явно; это не обещание поддержки сред исполнения в готовом продукте:
| Платформа и адаптер | Зафиксированные результаты |
|---|---|
| Windows 11 x64, нативный Go 1.27.1 | Реальная передача канала, кадры, вызов и проверки очистки |
Windows 11 x64, Python 3.14.7 с адаптером Win32 через ctypes | Реальная передача канала, а также сценарии операций ядра, проверки прав и сбоев жизненного цикла |
| Node.js, Lua и адаптеры для остальных платформ | Нужны собственная реализация и те же проверки соответствия до объявления поддержки |
Идентичность сеанса и подтверждение
Заголовок раздела «Идентичность сеанса и подтверждение»До запуска ядро закрепляет вид вызова, каноническую команду, выпуск расширения, контракт и контекст доступа. Новый ID сеанса обозначает канал внутри этого вызова. Оба ID служат для сопоставления данных, а не являются секретами или разрешениями. Расширение определяет ядро как другую сторону своего унаследованного конца канала; ядро определяет запущенное расширение как другую сторону конца, который оставило у себя. Ни одна сторона не принимает замену канала, предложенную в сообщении.
Это подтверждает владение запущенным сеансом, но не издателя, безопасность расширения или вошедшего пользователя. Выбранный артефакт и точка входа по-прежнему требуют установленных проверок доверия. Код, способный изучать или изменять процессы, похищать дескрипторы либо намеренно делиться своим концом канала, находится вне этой защиты. Дочерний процесс не является изолированной средой. Сведения ОС об участнике соединения могут помогать диагностике или проверкам подготовки, но PID создателя заранее соединённой пары не доказывает идентичность дочернего процесса.
Обмен подтверждает уже выбранный контракт. Он не согласует переход на менее строгий вариант. Диаграмма показывает порядок запуска в Windows; другая платформа должна установить равноценный контроль до исполнения обработчиков.
Версия протокола связи и формат кадров выбираются по проверенным объявлениям до запуска, затем подтверждаются вместе с версией взаимодействия и обязательными возможностями. Ядро передаёт только необходимый расширению контекст; доверенные сведения об идентичности и области доступа остаются в ядре. До подтверждения допустимы только initialize и ответ на него. Отмена на этом этапе закрывает канал и начинает остановку процесса без запроса cancel. Во время инициализации не должны запускаться обработчик расширения, запрос к средству ядра или запрос интерфейса. Доверенный адаптер обеспечивает это правило для расширений, соблюдающих контракт; IPC не является барьером ОС против вредоносного кода запуска.
После подтверждения сам канал определяет закреплённый контекст сеанса и вызова. Если сообщение повторяет поле сеанса или вызова, его значение должно точно совпадать с этим контекстом; выбрать другой контекст через него нельзя. Несовпадение — ошибка протокола.
Известная несовместимость даёт rejected до запуска любого кода расширения. Фактическая ошибка создания канала, передачи дескриптора или запуска даёт execution_failed. Несовпадение, некорректный ответ или истечение отдельного срока инициализации после запуска дают execution_failed без invoke, если отмена вызова ещё не принята. Истечение срока самого вызова принимает deadline_exceeded, в том числе во время инициализации. На один сеанс приходится один вызов; execute не может превратиться в describe или наоборот.
Формат кадров и представление значений
Заголовок раздела «Формат кадров и представление значений»Каждый кадр — четырёхбайтовая беззнаковая длина полезной нагрузки с порядком байтов от старшего к младшему, за которой следует ровно столько байтов UTF-8 с одним объектом JSON. Чтение и запись могут делить или объединять кадры. В этом протоколе нет разделителя, сжатия, пакетного массива или двоичного вложения вне основного канала. Байты команды остаются в отдельных потоках данных.
Получатель проверяет длину до выделения памяти под полезную нагрузку, читает кадр в пределах фиксированного срока и проверяет полный объект до передачи обработчику. Отклоняются некорректный UTF-8, повторяющиеся ключи, недопустимые скалярные значения Unicode, BOM, превышение глубины вложенности и неконечные числа. Схемы полей отклоняют неизвестные поля, влияющие на полномочия. Совместимость JSON требует явных числовых границ: целые числа должны находиться в диапазоне от -(2^53 - 1) до 2^53 - 1; десятичные значения следуют объявленному представлению binary64. Большие точные целые или точные десятичные значения требуют явно объявленного строкового кодирования, без неявного преобразования. Значения, которые выбранная схема не может представить, отклоняются до передачи обработчику. Стандарт JSON.
Для управляемого execute полезная нагрузка содержит уже разобранные типизированные входные данные и ID явно переданных параметров, без второго представления argv. describe передаёт свой отдельный запрос справки, а не обязательные аргументы исполнения; stdin закрыт, интерфейс запрещён, доступны только отдельно разрешённые операции чтения. Структурированное дополнение входит в сообщение о завершении. Перехваченный вывод процесса не становится содержимым справки.
Согласованные результаты команд и внешние адаптеры — 2026-09-24
Заголовок раздела «Согласованные результаты команд и внешние адаптеры — 2026-09-24»ADR-0013 определяет необязательную возможность command-result/1. Совместимые версии взаимодействия и процессного варианта должны явно поддерживать её в статических возможностях и подтверждении инициализации. При её выборе для execute существующий ответ rukh.invoke содержит объявленный commandResult вместе с отчётом завершения; новое незапрошенное сообщение результата не вводится. Возможность задаёт схему, обязательность и пределы дополнительного поля. Без согласованной поддержки это поле недопустимо, а не игнорируется как неизвестное. Прежние принятые варианты и зафиксированные проверки не меняются. До использования реализация должна объявить совместимую версию с этой возможностью; принятие не присваивает нереализованную версию передачи и не означает, что старые адаптеры принимают новые поля.
Данные, метаданные и обрамление вместе соблюдают меньшие пределы ADR-0003 и ADR-0013. Неверный результат предотвращает обычный успех с тем же приоритетом отмены, согласованием выхода и ограниченной очисткой. describe сохраняет отдельные данные справки. Значимый для прав контекст задачи и действия остаётся в ядре; повторное поле или обращение расширения к операции его не заменяет.
Канал MCP приложения — внешний интерфейс клиента, а не этот сеанс процесса. Он не наследует закрытый конец канала расширения и не направляет исходные сообщения MCP в rukh.call. Ядро преобразует допущенный запрос в один существующий вызов foreground. Отмена и потеря MCP поступают владельцу жизненного цикла; доставка результата клиенту никогда не повторяет invoke или защищаемое действие. Диагностика и потоки процесса отделены от обоих протоколов управления.
Запросы, ответы и события
Заголовок раздела «Запросы, ответы и события»Используются объекты JSON-RPC 2.0 с именованными параметрами и строковыми ID запросов. Ответ содержит ровно одно из полей result или error. Этот профиль исключает пакеты запросов и не использует зарезервированное пространство имён rpc.. JSON-RPC предоставляет сопоставление запросов и ответов и общий формат ошибок; жизненный цикл, проверка прав и правила доставки остаются ответственностью Rukh. Спецификация JSON-RPC.
| Сообщение | Направление и форма | Значение |
|---|---|---|
rukh.initialize | Ядро → расширение, запрос | Подтвердить закреплённый сеанс, версии, возможности и ограничения |
rukh.invoke | Ядро → расширение, один запрос | Передать execute или describe; ответ на него — единственное сообщение о завершении |
rukh.call | Расширение → ядро, запрос | Вызвать зарегистрированную операцию с её версией и проверенными входными данными |
rukh.ui.event | Ядро → расширение, запрос с подтверждением | Передать разрешённое событие интерфейса с представлением, версией состояния и порядковым номером события |
rukh.log | Расширение → ядро, уведомление | Передать ограниченную диагностическую запись; доставка не гарантируется |
rukh.cancel | Ядро → расширение, запрос | Сообщить об отмене; подтверждение не откладывает остановку и не доказывает её |
rukh.close | Ядро → расширение, запрос | Завершить штатное закрытие управляющего канала после сообщения о завершении |
И succeeded, и command_failed являются нормальными результатами invoke, содержащими сообщение о завершении. Ответ JSON-RPC с ошибкой на invoke обозначает сбой передачи запроса или протокола, а не обычную ошибку команды, и приводит к execution_failed, если результат ещё не определяется принятой отменой.
Чтение продолжается, пока обработчики ожидают результат. Ожидание invoke не должно блокировать вложенный call, ответ на него, событие интерфейса или отмену. Один механизм записи с ограниченной очередью последовательно передаёт кадры в каждом направлении; обработчики не могут перемежать их байты.
ID запросов используют префиксы направления и возрастающие без пропусков счётчики, например c:1 и e:1, назначаемые в порядке передачи. Повторное использование запрещено. Повтор, пропуск или уменьшение ID запроса — ошибка протокола: нельзя выполнять действие или отправлять второй ответ с этим ID. Ответы могут приходить не по порядку и должны соответствовать ожидающему запросу. Неизвестный будущий ID или ID неверного направления — ошибка протокола. Ответ на ранее выданный запрос, ожидание которого уже завершено, отбрасывается и учитывается как запоздалый; он не может восстановить запрос или повторить действие. Счётчики и ограниченная таблица ожидающих запросов позволяют не хранить неограниченную историю. ID invoke отслеживается до закрытия: второе сообщение о завершении — ошибка протокола, а не обычный запоздалый ответ.
Идентичность операции, версия и проверенные входные данные выбирают зарегистрированный обработчик ядра. Ядро определяет фактическое действие и ресурс, затем проверяет принадлежащий ядру контекст непосредственно перед защищённым действием. Поля сообщения не могут подменить субъект, выпуск или разрешения. Локальная политика и настроенный брокер используют одинаковые проверки; отказ брокера никогда не включает переход к локальной политике. Обычный отказ в операции возвращает типизированную ошибку операции и не требует закрытия исправного сеанса.
Ядро задаёт сроки запросов операций и интерфейса в пределах времени, отведённого вызову. Другая сторона может запросить более короткий относительный срок, но не продлить его с помощью своих часов. Отмена и закрытие используют отдельный фиксированный срок завершения, в том числе после истечения срока вызова; они никогда не продлевают время исполнения. Потеря ответа оставляет возможность того, что внешнее действие уже выполнено: сопоставление запросов не обеспечивает откат или исполнение ровно один раз. Ни запрос, ни команда, ни внешнее действие не повторяются автоматически.
Нагрузка, журнал и события интерфейса
Заголовок раздела «Нагрузка, журнал и события интерфейса»Ниже закреплены базовые ограничения этого протокола. Эталонные проверки охватывают отказ на границах, перегрузку и сокращённые сроки в тестах; они не устанавливают оптимальную ёмкость готовой реализации. Ядро может ужесточить ограничения при выборе совместимого профиля; другая сторона не может их увеличить. Заранее известные обязательные размеры проверяются до запуска. Подтверждение закрепляет действующие ограничения для данного сеанса. Более высокие пределы требуют отдельно объявленного и проверенного профиля.
| Ресурс | Базовое ограничение |
|---|---|
| Полезная нагрузка JSON | 1 MiB на кадр; 16 KiB для инициализации, отмены, закрытия или обычной записи журнала |
| Структура JSON | Глубина 32; суммарно 4 096 полей объектов и элементов массивов на кадр |
| Ожидающие запросы операций и интерфейса | 64 на направление, отдельно от единственного вызова и запросов жизненного цикла |
| Очередь отправки | 128 кадров или 4 MiB, в зависимости от того, что достигнуто раньше; включает записи журнала в очереди |
| Резервная очередь жизненного цикла | Дополнительные 8 кадров / 128 KiB для отмены, закрытия и ответов на них |
| Приём обычных записей журнала | 100 записей и 1 MiB в секунду; превышение отбрасывается и учитывается |
| Инициализация | 5 секунд с запуска процесса, но не позднее срока вызова |
| Неполный кадр / заблокированная запись кадра | 2 секунды с первого принятого байта / начала записи; продвижение не сбрасывает таймер |
| Завершение | Один срок в 5 секунд с перехода к завершению, включая не более 2 секунд добровольной остановки, затем принудительное завершение и очистку; таймеры не перезапускаются |
Отсутствие обмена допустимо при ожидании ввода пользователя или долгой операции в пределах срока вызова. Неполный кадр не считается отсутствием обмена. Нужно резервировать ресурсы обработки для сообщений жизненного цикла и соблюдать срок кадра даже при потоке записей журнала; приоритет не может прервать байты, которые уже записываются. Рост очередей и затраты на разбор должны оставаться ограниченными. Если управление больше не может продвигаться, сеанс завершается с ошибкой, а процесс останавливается средствами контроля исполнения.
Владелец закрепляет один срок остановки по монотонным часам при первом переходе к завершению: по подтверждению завершения работы, завершающей ошибке, отказу или принятой отмене. Для команды без IPC подтверждением служит наблюдаемый выход процесса. Последующая отмена, ошибка, close, аудит, передача вывода и очистка дочерних процессов используют оставшееся время; ни один этап не начинает новые пять секунд. Добровольная остановка заканчивается не позднее двух секунд после первого перехода или раньше, если это требует общий срок. Если этот интервал уже использован, отмена может сразу перейти к принудительной остановке. По истечении срока ядро закрывает контекст и фиксирует незавершённую работу, не ожидая ОС или доверенный обработчик бесконечно. Неподтверждённая остановка либо обязательная очистка исключают успех и при необходимости сохраняют защитные ссылки на ресурсы. Само назначение срока не позволяет принудительно прервать произвольный доверенный код внутри процесса; адаптер должен обеспечить ограниченную по времени границу либо объявить эту гарантию неподдерживаемой.
Некорректное содержимое обычной записи журнала или превышение частоты записей приводит к учитываемому отбрасыванию, а не к ошибке команды. Некорректный формат кадра, состояние сеанса или разрыв управляющего канала — ошибка протокола. Ядро добавляет доверенные метаданные журнала и направляет диагностику отдельно от stdout. Обязательный аудит использует путь защищённой операции, а не rukh.log; его сбой может предотвратить действие или успешный результат.
События интерфейса не являются уведомлениями журнала с допустимой потерей. Подтверждение означает проверенный приём в ограниченную упорядоченную очередь, а не завершение внешнего действия. Устаревшая версия состояния, отсутствие подтверждения или заполненная очередь закрывают затронутое взаимодействие с определённой ошибкой; после неопределённого подтверждения события не повторяются. Объединять можно только явно заменяемые обновления отображения. Секретный ввод передаётся только предназначенной для него операции и никогда не копируется в журналы или диагностические дампы содержимого. Глобальная отмена остаётся под управлением ядра.
Завершение и ошибки транспорта
Заголовок раздела «Завершение и ошибки транспорта»Диаграмма состояний относится к транспорту. Достижение Closed само по себе не устанавливает успешность вызова.
Корректное сообщение о завершении немедленно прекращает приём новых операций ядра и запросов интерфейса. Ядро завершает или отменяет уже принятую работу в пределах оставшегося срока завершения, отправляет close и ожидает подтверждения. Адаптер отправляет это подтверждение полностью, закрывает свой конец и завершает процесс. EOF ожидается только после корректного подтверждения закрытия; более ранний EOF не может заменить сообщение о завершении или доказать успех. При уже принятой отмене закрытие канала относится к остановке и не может поменять результат обратно на успех или ошибку.
Ядро по-прежнему проверяет нормальное завершение процесса и его соответствие сообщению, дочитывает перехваченный вывод или ограничивает его обработку, завершает обязательный аудит и освобождает ресурсы. Сообщение об успехе требует нулевого кода выхода; сообщение об ошибке команды — нормального выхода с ненулевым кодом, причём любой явно сообщённый код должен совпадать с фактическим. Отсутствующие, повторные или противоречивые сообщения, аварийное завершение и сбой обязательной очистки исключают успех. Дочерние процессы, удерживающие унаследованный поток, не могут продлевать окончательное завершение бесконечно.
Отмена, принятая до фиксации окончательного результата, имеет приоритет над поздним результатом. Сохраняется первая принятая причина из ADR-0002: user_request, owner_shutdown или deadline_exceeded. Ядро немедленно прекращает приём запросов и переходит к ограниченной по времени остановке, не ожидая подтверждения расширения и не перезапуская срок. Последующие источники отмены и ошибки протокола, аудита или очистки остаются диагностикой. Срок вызова проверяется до фиксации: его истечение во время завершения принимает отмену, если более ранняя причина ещё не определяет результат. Истечение самого срока остановки означает ошибку исполнения, а не новую причину отмены. Срок отдельного запроса возвращает определённую для него ошибку операции; ошибка кадров или управления завершает вызов с ошибкой. EOF на stdin по-прежнему означает исчерпание входных данных, а не отмену.
| Наблюдение | Последствие для вызова |
|---|---|
| Известная несовместимость способа связи или требований к ресурсам до исполнения кода расширения | rejected |
| Несовпадение при инициализации, повреждённый кадр, ранний EOF IPC или потеря управления после запуска | execution_failed, если отмена ещё не была принята |
| Корректное сообщение и соответствующий ему нормальный выход, все обязательные действия завершения выполнены | succeeded или command_failed, согласно сообщению |
| Отмена принята до окончательной фиксации результата | cancelled; сохраняются причина и диагностика очистки |
| Обычная запись журнала отброшена или запоздал обычный ответ на запрос, ожидание которого уже завершено | Учесть это, не меняя результат только по этой причине |
Неожиданное закрытие никогда не создаёт новое соединение и не передаёт команду повторно. Ядро сообщает об ошибке или неопределённом результате операции, не утверждая, что её внешние последствия отменены. Сохраняется первоначальная ошибка транспорта: последующий разрыв канала при принудительной очистке не должен её скрывать. Уже принятая отмена по-прежнему имеет приоритет.
Это решение закрепляет коды завершения CLI для управляемых вызовов и команд без IPC; типизированные результаты ADR-0002 остаются основными. Команде без IPC не нужны сообщение о завершении или подтверждение протокола: используются штатный выход процесса, обработка потоков и обязательное завершение. Отсутствие сеанса IPC не отменяет общие причины отмены и срок остановки:
| Тип результата | Код завершения CLI |
|---|---|
succeeded | 0 |
command_failed | Наблюдаемый ненулевой код штатного выхода процесса; сообщение управляемой команды должно ему соответствовать |
rejected, execution_failed | 125; тип результата и причина ошибки различаются отдельно |
cancelled, user_request | 130 |
cancelled, owner_shutdown | 130 |
cancelled, deadline_exceeded | 124 |
Код процесса Windows не обрезается до восьми бит: в проверках сохраняется 74565. Адаптер платформы отдельно записывает исходный статус процесса; принудительное или аварийное завершение не становится command_failed только из-за совпадения числа с кодом команды. На платформах с меньшим диапазоном нормальных кодов проверяется этот диапазон; завершение сигналом учитывается отдельно. Команда тоже может вернуть 124, 125 или 130, поэтому одно число никогда не определяет тип результата.
Последствия
Заголовок раздела «Последствия»Решение связывает проверку подлинности с локальным запуском процесса и позволяет обойтись без нового криптографического протокола. Команды и интеграции сред исполнения могут использовать разные языки при общей модели кадров и жизненного цикла. Отображение в терминале, разрешения и обязательный аудит остаются под управлением ядра.
Цена — поддержка адаптера для каждого сочетания среды исполнения и платформы, вместо обещания, что любая стандартная библиотека сможет использовать произвольный унаследованный дескриптор. Поддержка удалённого соединения, фонового процесса или повторного подключения из этого решения не следует. Если реальные адаптеры не смогут сохранить эти гарантии, выбор канала нужно пересмотреть явно, а не незаметно включать режим с меньшими ограничениями.
Подтверждение
Заголовок раздела «Подтверждение»Проверки уточнения 2026-09-24 ещё не выполнены. Требуется подтвердить общий путь CLI/MCP, отказ при неподдерживаемой возможности результата, текущую привязку профиля и задачи, пределы данных, отсутствие повторов и разделение каналов в пределах ответственности этого ADR. Исторические результаты ниже на эти дополнения не распространяются.
Эталонные проверки — 2026-09-21
Заголовок раздела «Эталонные проверки — 2026-09-21»Воспроизводимый опыт в validation/adr-0003/ (mise run ipc-check): 126 из 126 проверок пройдены на Windows 11 x64 10.0.26220, с Go 1.27.1 и Python 3.14.7 через mise. Управляющая сторона написана на Python и использует настоящие вызовы Win32; расширения представлены нативной программой и скриптом. Это новые результаты для наследуемого канала, отдельно от прежних опытов ADR-0001/0002.
| Пункт подтверждения | Полученный результат |
|---|---|
| Канал и адаптеры | Оба адаптера получили настоящий соединённый дескриптор и запретили дальнейшее наследование. Проверены принадлежность концов и отказ в новом подключении. Посторонние наследуемые дескрипторы не передавались; ошибки запуска и включения в Job Object освобождали ресурсы без вызова кода расширения. После повторных прогретых запусков и отказов число дескрипторов не росло. |
| Кадры и нагрузка | Прошли побайтовая передача, разделение UTF-8, объединённые кадры, границы чисел и структуры, повторные ключи и ID, ответы не по порядку и обмен в обе стороны. Некорректные данные отклонялись обоими адаптерами и ядром. Байтовые потоки оставались раздельными; проверены границы очередей, отбрасывание журнала и отмена при непрерывном потоке записей. Зависшая операция чтения/записи и неполный кадр не приводили к бесконечному ожиданию. |
| Сеанс и права | Неверные сеанс, контракт или обязательные возможности предотвращали вызов. Запрос до подтверждения не попадал обработчику. Локальная политика и заглушка брокера по HTTP использовали одну проверку действия; отказ, некорректный ответ брокера, подмена контекста и выход за область доступа не расширяли права. |
| Завершение и сбои | Для отсутствующего, повторного и противоречивого результата, раннего EOF, аварии, отмены, истечения срока, потери ответа, отказа приёма события интерфейса и сбоя обязательного аудита получены определённые результаты. Потеря ответа после учтённого действия не повторяла его. После завершения новые действия запрещались; не отвечающий на отмену дочерний процесс останавливался вместе с группой. Полные коды выхода Windows сохранялись. |
| Производительность и закреплённые правила | Ниже измерены полный цикл эталонного адаптера и обращения через протокол. В решении определены пределы ресурсов, асинхронный ввод-вывод, контроль до возобновления процесса, сохранение первой ошибки и коды CLI. Запуск Python пока превышает ориентир. |
Подробные сценарии прав, перегрузки, аудита и интерфейса используют Python; нативные проверки охватывают транспорт и базовый жизненный цикл. Аудит, внешние действия и события терминала представлены управляемыми примерами, а не постоянным хранилищем, настоящими внешними действиями или физическим терминалом. Проверки ёмкости совмещают реальные каналы и модель заблокированной записи. Результаты подтверждают осуществимость этого ограниченного прототипа, а не полное соответствие готовой реализации или поддержку неуказанных адаптеров.
Измерения полного адаптера
Заголовок раздела «Измерения полного адаптера»Три серии, во второй порядок расширений обратный. Для каждого расширения после прогрева получены 150 полных запусков и 3 000 обменов IPC для каждого размера данных: всего 300 запусков и 12 000 измеренных обменов, без неуспешных замеров. Кэши были прогреты; фоновая нагрузка не контролировалась. Go использовал Windows QueryPerformanceCounter, Python — свой высокоточный счётчик. Пробные замеры с недостаточной точностью исключены. Исходные значения сохраняются локально в .generated/adr-0003/measurements.json.
Значения — медиана / p95 в миллисекундах, p95 рассчитан методом ближайшего ранга. Последний столбец сохраняет ориентиры ADR-0001 для минимального прогретого сценария; они не превращаются в гарантии готового продукта.
| Измерение | Нативное расширение Go | Расширение Python | Предел p95 из ADR-0001 |
|---|---|---|---|
| Запуск процесса → проверенное подтверждение | 24,852 / 31,074 | 141,955 / 166,002 | 100 |
| Подготовка канала + подтверждение + одна операция + закрытие + выход + очистка | 45,697 / 47,338 | 156,766 / 185,434 | 150 |
| Установленный IPC, данные 64 байта, проверенный запрос → ответ | 0,162 / 0,258 | 0,189 / 0,297 | 1 |
| Установленный IPC, данные 4 096 байт, проверенный запрос → ответ | 0,211 / 0,333 | 0,233 / 0,373 | 1 |
IPC включает проверку JSON, кадры, локальную проверку прав и вызов обработчика; полный запуск — одну такую операцию и подтверждённое закрытие. Размер относится к полю данных, а не ко всему кадру. Запуск самого ядра, установка среды, сетевой брокер, полезная работа команды и холодный кэш исключены. p95 не является максимумом: наибольшие обмены заняли 2,135 мс для Go и 1,233 мс для Python. Максимумы полного запуска — 61,726 и 203,874 мс соответственно.
Вывод: наследуемый канал работоспособен; нативный вариант укладывается во все четыре ориентира. Установленный IPC укладывается в предел для обоих расширений. Python функционально работает в проверенных сценариях, но превышает пределы запуска и полного вызова. Опыт не разделяет затраты интерпретатора, загрузки адаптера и запуска средствами ОС, поэтому приписывать превышение только транспорту нельзя. Пределы производительности не повышены.
Принятая область и оставшаяся работа
Заголовок раздела «Принятая область и оставшаяся работа»Владелец проекта принял ADR-0003 2026-09-21 с зафиксированным превышением времени запуска и полного вызова Python. Это известное ограничение не препятствует принятию архитектуры IPC. Ориентиры производительности ADR-0001 сохраняются; принятие не устанавливает повышенный предел для Python и не объявляет эти проверки пройденными.
Начальные результаты относятся к указанным выше эталонным адаптерам Go и Python на Windows. Дополнительные сочетания платформ и сред требуют своего адаптера и прогона проверок до объявления поддержки. Уменьшение стоимости запуска Python и повторное измерение остаются работой по реализации. Эталонные проверки не подтверждают готовность SDK, внешнего хранилища аудита или настоящего интерфейса терминала.
Уточнение от 2026-09-22 дополнительно требует проверить оба процессных варианта при закрытии владельца, гонках причин отмены, истечении срока вызова во время завершения, общем невозобновляемом сроке остановки и неполной очистке. Исторические запуски не заявляют такой дополнительной области; эти случаи не запускались по уточнённому контракту.