Explorar o código

docs(subprocess): record the Windows duplex pipe requirement

Tianyi Cui hai 2 semanas
pai
achega
c45d722d7b

+ 2 - 2
.agents/notes/implemented/architecture/2026-09-11-subprocess-control-pipe.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-09-11-subprocess-control-pipe.md
-2026-09-11-subprocess-control-pipe.md: b9c58842961ff96ebfd6d3f9d8be9545ff5a79e0
-2026-09-11-subprocess-control-pipe.zh.md: 10539fd783363e068abf7f15bc0579efd29e95e6
+2026-09-11-subprocess-control-pipe.md: 54fbd8b42ddd5db9e06cde16eadb8d4753b7bbe0
+2026-09-11-subprocess-control-pipe.zh.md: 891bbc17e0638c5ab8e4002f993a9bc06940cfd4

+ 4 - 0
.agents/notes/implemented/architecture/2026-09-11-subprocess-control-pipe.md

@@ -14,12 +14,16 @@ Ordinary subprocess requests optionally set `stdio.control: 'pipe'` and receive
 
 POSIX launchers preserve fd 7 across exec. Windows ordinary Job and restricted-token launchers place the pipe at slot 7 in the CRT startup descriptor table, preserve standard handles, and leave slots 3–6 closed in the payload. Each wrapper closes its carrier after transferring ownership. Handle inheritance is enabled only around process creation. This channel grants no host capability: the child remains untrusted, and every host tool request requires its usual dispatch and approval checks.
 
+Control pipes use Node's `overlapped` stdio disposition, which equals `pipe` on POSIX and creates Windows handles with `FILE_FLAG_OVERLAPPED`. Reads and writes can then proceed independently, including a child sending its first message before the host sends anything.
+
 The filesystem and subprocess services remain replaceable together by remote providers. Neither the public handle nor its request exposes a host path, process identifier, execution-world flag, or transport negotiation catalogue. Terminal allocation remains asynchronous and does not gain an extra descriptor.
 
 ## Alternatives considered
 
 **Stdout framing.** Native code and ordinary `process.stdout.write` can emit arbitrary bytes, so protocol integrity would depend on intercepting program output.
 
+**Synchronous Windows pipes.** A blocking read on an inherited synchronous pipe can prevent a concurrent write on the same handle from progressing. A parent-first echo does not expose this deadlock; child-first readiness and teardown require overlapped handles.
+
 **Node IPC.** The Windows process supervisor already uses a private IPC channel. Coupling payload requests to that management protocol would expose supervisor operations and complicate remote transport.
 
 **A late Windows descriptor replacement.** Replacing fd 7 after Node starts can overwrite an internal descriptor. The CRT startup table reserves it before runtime initialization and keeps the child API identical across hosts.

+ 4 - 0
.agents/notes/implemented/architecture/2026-09-11-subprocess-control-pipe.zh.md

@@ -14,12 +14,16 @@ Status: implemented
 
 POSIX 启动器在 exec 时保留 fd 7。Windows 普通 Job 与受限令牌启动器把管道放入 CRT 启动描述符表的槽 7,保留标准句柄,并让负载中的槽 3–6 保持关闭。每层包装器在转移所有权后关闭自身承载端。句柄继承仅在进程创建期间启用。该通道不授予任何宿主能力:子进程仍不可信,每次宿主工具请求都需要通常的分发与审批检查。
 
+控制管道使用 Node 的 `overlapped` stdio 处置方式:它在 POSIX 上等同于 `pipe`,在 Windows 上创建带有 `FILE_FLAG_OVERLAPPED` 的句柄。因此读写可以独立进行,包括子进程在宿主发送任何内容前发出第一条消息。
+
 文件系统与 subprocess 服务仍可由远程提供方成对替换。公共句柄和请求均不公开宿主路径、进程标识、执行世界标志或传输协商目录。终端分配保持异步,且不增加额外描述符。
 
 ## 考虑过的替代方案
 
 **Stdout 分帧。** 原生代码和普通 `process.stdout.write` 可以输出任意字节,因此协议完整性将依赖于拦截程序输出。
 
+**同步 Windows 管道。** 继承的同步管道上的阻塞读取可能阻止同一句柄上的并发写入继续执行。宿主先发送的回显无法暴露该死锁;子进程先报告就绪以及拆卸都需要重叠 I/O 句柄。
+
 **Node IPC。** Windows 进程监督器已经使用私有 IPC 通道。把负载请求耦合到该管理协议会暴露监督器操作,并使远程传输复杂化。
 
 **在 Windows 启动后替换描述符。** Node 启动后替换 fd 7 可能覆盖内部描述符。CRT 启动表在运行时初始化前保留它,并保持各宿主的子进程 API 一致。