Skip to content

Commit 3b366de

Browse files
authored
Merge pull request #5144 from loopx-project/codex/managed-host-process-supervision
fix(turn): supervise managed Host process lifetimes in TypeScript
2 parents 0943b03 + 0d9de02 commit 3b366de

17 files changed

Lines changed: 847 additions & 109 deletions

‎docs/architecture/rfcs/STATUS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ appendix may keep dated history, but no dated log heading may precede it.
5858
| [RFC: Research Exploration Control Plane v0](research-exploration-control-plane-v0.md) | Accepted | none | — |
5959
| [RFC: Semantic Vocabulary Convergence and Commit-Time Drift Checks (v0)](semantic-vocabulary-convergence-v0.md) | Accepted | none | [5 entries](ledger/semantic-vocabulary-convergence-v0/) |
6060
| [RFC: Shared Goal Alignment and Governed Amendment Protocol (v0)](shared-goal-alignment-and-governed-amendment-v0.md) | Accepted | none | [2 entries](ledger/shared-goal-alignment-and-governed-amendment-v0/) |
61-
| [RFC: LoopX Shared Control-Plane Authority and Pluggable State Providers (v0)](shared-goal-authority-state-provider-v0.md) | Accepted | none | [20 entries](ledger/shared-goal-authority-state-provider-v0/) |
61+
| [RFC: LoopX Shared Control-Plane Authority and Pluggable State Providers (v0)](shared-goal-authority-state-provider-v0.md) | Accepted | none | [22 entries](ledger/shared-goal-authority-state-provider-v0/) |
6262
| [RFC: Single-Owner Local Daemon (v0)](single-owner-local-daemon-v0.md) | Accepted | none | — |
6363
| [RFC: TypeScript Control-Plane Migration Direction v0](typescript-control-plane-migration-v0.md) | Accepted | none | [12 entries](ledger/typescript-control-plane-migration-v0/) |
6464

‎docs/architecture/rfcs/STATUS.zh-CN.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
| [RFC:研究型探索控制面 v0](research-exploration-control-plane-v0.zh-CN.md) | 已接受 | 无 | — |
5656
| [RFC:语义词表收敛与提交期漂移检查(v0)](semantic-vocabulary-convergence-v0.zh-CN.md) | 已接受 | 无 | [5 条](ledger/semantic-vocabulary-convergence-v0/) |
5757
| [RFC:共享 Goal 对齐与受治理 Amendment 协议(v0)](shared-goal-alignment-and-governed-amendment-v0.zh-CN.md) | 已接受 | 无 | [2 条](ledger/shared-goal-alignment-and-governed-amendment-v0/) |
58-
| [RFC:LoopX 共享控制面权威与可插拔状态 Provider(v0)](shared-goal-authority-state-provider-v0.zh-CN.md) | 已接受 | 无 | [20 条](ledger/shared-goal-authority-state-provider-v0/) |
58+
| [RFC:LoopX 共享控制面权威与可插拔状态 Provider(v0)](shared-goal-authority-state-provider-v0.zh-CN.md) | 已接受 | 无 | [22 条](ledger/shared-goal-authority-state-provider-v0/) |
5959
| [RFC: Single-Owner Local Daemon (v0)](single-owner-local-daemon-v0.md) | 已接受 | none | — |
6060
| [RFC:LoopX 控制面 TypeScript 渐进迁移方向 v0](typescript-control-plane-migration-v0.zh-CN.md) | 已接受 | 无 | [12 条](ledger/typescript-control-plane-migration-v0/) |
6161

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Local defaults: managed Host supervision and reconciled delivery plan
2+
3+
- Baseline: `fd96e5e25`, audited September 27, 2026.
4+
- Outcome: overall roadmap S2/S4/R5, shared authority external-execution closure,
5+
TS replacement-first migration. No provider or capability is introduced.
6+
- This replaces the **remaining delivery estimate**, not the historical evidence,
7+
in the September 24 reconciliation. The recovery slice proposed in
8+
[#5140](https://github.com/loopx-project/loopx/pull/5140) is still open.
9+
- [中文](2026-09-27-host-supervision.zh-CN.md).
10+
11+
## Count deliveries, not architectural headings
12+
13+
Complete-source transport/assembly, transaction capture, canonical pagination,
14+
File v1 automatic backup/upgrade and Python prototype retirement are already on
15+
main. #5013, #5063, #5102 and #5105 are not future work. Two promoted Goals prove
16+
those particular cutovers, not every execution, migration or recovery boundary.
17+
18+
The old “three packages” and #5140's “three PRs afterwards” were too coarse for
19+
execution protection. An actual subprocess reproduction shows the missing
20+
prerequisite: generic Host timeout kills only its leader, while Codex cleanup
21+
returns early after the leader exits. Both can leave descendants doing work.
22+
Deleting a lease or rejecting a later result does not stop that process.
23+
24+
The current **four newly planned deliveries include this PR**:
25+
26+
| Delivery | Observable exit and Python retirement |
27+
| --- | --- |
28+
| **1. Managed subprocess supervision (this PR)** | Generic command and Codex CLI share one TS lifecycle through timeout, caller loss, pipe drain and process-group termination. Retire their separate Python termination/thread-reader implementations. This closes the process component, not the lease component below. |
29+
| **2. Authority-bound execution interval** | Connect the existing provider-neutral lease owner to actual execution: current proof before start, bounded renewal, cancellation on expiry/reclaim/revocation, and uncertain-effect recovery. Reclaim must not silently overlap an old executor. Test with real processes and File/SQLite; explicitly qualify attached Hosts without cancellation. Remove replaced Python decisions rather than create a second lease store. |
30+
| **3. Whole-Goal migration and fenced recovery integration** | Adopt #5140 recovery and #5054 source retirement; cover source drain, reviewed cutover, retained command consumers, projection readback and rollback after later writes. Inventory existing callers before adding writers. Delete legacy decisions only when their actual callers have moved. |
31+
| **4. Default onboarding and bounded Python retirement** | New-Goal creation, settings, CLI, packaged frontend and Lark select the qualified local profile consistently. Existing Goals have explicit upgrade, backup and recovery. Remove remaining replaced Python business writers, retaining necessary rendering and Host IO adapters. |
32+
33+
**Three planned new PRs remain after this one.** This is a scoped delivery plan,
34+
not an unconditional total or proof that lease supervision has shipped. It is
35+
one additional execution slice compared with #5140's proposed estimate; the
36+
reproduction above is the reason, and this PR does not subtract the uncompleted
37+
lease row. If another slice is needed, amend its named row and evidence.
38+
39+
Separately, existing open PRs are #5140 (recovery/audit), #5054 (old Todo event
40+
retirement and supervisor logging), and #4931 (SQLite receipt-proof encoding).
41+
Thus the integration inventory is **six named PR deliveries for the File route**
42+
(this + three planned + #5140 + #5054), or **seven for the SQLite route** including
43+
#4931. These counts include already implemented open PRs; they do not mean six
44+
or seven new implementations. #5140's SQLite batch proof read complements #4931;
45+
neither small-suite success qualifies D2. New defects discovered by qualification
46+
can still require changes, so there is no justified guaranteed PR total today.
47+
48+
D1 consumer parity, profile-specific D2 capacity/recovery/soak and D3 cohort
49+
cutover remain acceptance work, not invented PR allocations. The audited #4224
50+
1 MiB report still fails receipt p95 (269.03 ms / 50 ms) and scan-100 p95
51+
(801.81 ms / 250 ms); this process change cannot fix or certify those metrics.
52+
PostgreSQL retains its separate authenticated transport, tenant/identity,
53+
cross-host execution, pooling/failover and operations qualification. Local
54+
process cleanup is reusable across providers because it does not read their
55+
physical layouts or create authority.
56+
57+
## Ownership and neighboring work
58+
59+
`control_plane/turn_driver/host_process.ts` owns the managed process lifetime;
60+
its private bridge treats the Python owner's control-pipe EOF as cancellation.
61+
Python adapts transient output, Codex sessions and typed results. Existing
62+
`turn run-once` callers adopt this automatically; no new CLI option, configuration
63+
editor, capability registration, frontend or Lark surface is needed. Attached
64+
App sessions and in-process DSH adapters do not pass through this subprocess
65+
owner and are not represented as newly protected.
66+
67+
#5141 fences Host state by GoalRef, while #5142 preserves effect uncertainty in
68+
Turn error readback. Neither replaces process supervision. Integration must
69+
retain their admission checks before launching and their recovery observations;
70+
this PR changes neither GoalRef authority nor settlement semantics.
71+
72+
[Operational behavior and limits](../../../../reference/protocols/loopx-turn-v0.md#managed-host-process-lifetime).
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# 本地默认切换:受管 Host 进程监督与交付重估
2+
3+
- 基线:`fd96e5e25`,2026-09-27 核对。
4+
- 目标:总路线 S2/S4/R5、shared authority 外部执行闭环、TS 替换式迁移。
5+
不新增 provider 或 capability。
6+
- 本文替换 9 月 24 日清单的**剩余交付估算**,不改写历史证据。
7+
[#5140](https://github.com/loopx-project/loopx/pull/5140) 的恢复切片仍未合入。
8+
- [English](2026-09-27-host-supervision.md)。
9+
10+
## 数交付,不数架构标题
11+
12+
完整来源传输与组装、事务捕获、canonical 分页、File v1 自动备份升级、Python
13+
原型退役已在 main。#5013、#5063、#5102、#5105 不再计入待开发。两个已晋升 Goal
14+
证明的是那两次切换,不代表全部执行、迁移、恢复边界已完成。
15+
16+
旧的“三个大包”以及 #5140 的“之后三个 PR”对执行保护估得过粗。真实子进程复现
17+
发现前置缺口:通用 Host 超时只杀主进程;Codex 清理在主进程退出后直接返回;
18+
两者都可能遗留继续工作的后代。删除租约或拒绝最终结果不能让这些进程停止。
19+
20+
当前规划的**四个新增交付包含本 PR**:
21+
22+
| 交付 | 可观察退出条件与 Python 退役 |
23+
| --- | --- |
24+
| **1. 受管子进程监督(本 PR)** | 通用命令与 Codex CLI 共用 TS 生命周期,覆盖超时、调用方消失、管道排空和进程组终止;删除各自的 Python 终止及读线程实现。完成进程部分,不冒称下行租约部分已完成。 |
25+
| **2. 权威约束的执行区间** | 把现有 provider-neutral 租约 owner 接到实际执行:启动前当前证明、执行中有界续约、到期/回收/撤权取消、不确定效果恢复。回收不能静默重叠旧执行器。真实进程与 File/SQLite 验证;附着式 Host 无取消能力时明确支持边界。替换 Python 决策,不另建租约存储。 |
26+
| **3. 整 Goal 迁移与带 fence 的恢复闭环** | 接入 #5140 恢复与 #5054 来源退役;覆盖来源排空、已审切换、保留命令消费者、投影读回及存在后续写入时的回退。先盘点 caller,再决定是否需要 writer;只有真实 caller 已迁移才删除旧决策。 |
27+
| **4. 默认入口与有界 Python 清理** | 新 Goal、设置、CLI、打包前端、Lark 一致选择合格的本地 profile;旧 Goal 有显式升级、备份、恢复。删除已替代 Python 业务 writer,保留必要渲染与 Host IO adapter。 |
28+
29+
**本 PR 之后仍规划三个新增 PR。** 这是有具体边界的计划,不是保证总数,也不代表
30+
租约监督已经交付。相比 #5140 的提案,明确多拆一个进程切片,原因是上面的复现;
31+
不能用本 PR 抵扣未完成的租约行。后续若再拆,必须修改具体行并给出证据。
32+
33+
既有在途 PR 另计:#5140 恢复/审计、#5054 旧 Todo 事件退役与 supervisor 日志、
34+
#4931 SQLite 回执证明编码。因此 **File 路线的已知合入清单为六项**(本次 + 三项
35+
待开发 + #5140 + #5054),**SQLite 路线加入 #4931 后为七项**。这里包含已经实现
36+
但没合入的 PR,绝不是还要新写六七个。#5140 的 SQLite 批量证明读取与 #4931
37+
互补;小规模测试通过不能代替 D2。资格验证仍可能发现需修改的缺陷,因此不能
38+
承诺无条件总 PR 数。
39+
40+
D1 消费者一致性、各 profile 的 D2 容量/恢复/soak、D3 cohort 切换是验收工作,
41+
不能凭空折算 PR。核对的 #4224 1 MiB 报告仍有 receipt p95 269.03ms / 50ms、
42+
scan-100 p95 801.81ms / 250ms 未通过,本次进程改造不能修复或认证这些指标。
43+
PostgreSQL 的认证传输、tenant/identity、跨 Host 执行、连接池/故障切换、运维
44+
资格仍是独立中期路径。本地进程清理不读取 provider 物理布局、不产生权威,
45+
因此各 provider 可以复用。
46+
47+
## 归属与邻近工作
48+
49+
`control_plane/turn_driver/host_process.ts` 拥有进程生命周期,私有 bridge 将 Python
50+
调用方控制管道 EOF 视为取消。Python 适配瞬时输出、Codex 会话、typed result。
51+
现有 `turn run-once` 自动接入,无新 CLI 参数、配置编辑器、capability、前端或
52+
Lark 界面。附着式 App 会话与进程内 DSH adapter 不经过此子进程 owner,不宣称
53+
它们因此得到保护。
54+
55+
#5141 用 GoalRef 约束 Host 状态;#5142 保留 Turn 错误读回中的效果不确定性。
56+
两者不能替代进程监督。集成时要保留启动前准入和恢复观察,本 PR 不修改 GoalRef
57+
权限或 settlement 语义。
58+
59+
[操作行为和限制](../../../../reference/protocols/loopx-turn-v0.md#managed-host-process-lifetime)。

‎docs/architecture/rfcs/shared-goal-authority-state-provider-v0.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ existing #5054/#4931 and D2/D3 evidence remain separate. This is not a guarantee
3636
count of future defect repairs.
3737
[Current inventory, rationale and exits](ledger/shared-goal-authority-state-provider-v0/2026-09-27-recovery-audit.md).
3838

39+
Managed Host supervision lands in the same window as a separate delivered slice:
40+
one TS supervisor now owns generic command and Codex CLI process lifetimes, so
41+
authority-bound execution stays open rather than closing here, and the old three
42+
architectural packages remain a pointer instead of a decrementing PR counter.
43+
Its named plan, changed estimate and boundaries are recorded separately.
44+
[Named plan, changed estimate and boundaries](ledger/shared-goal-authority-state-provider-v0/2026-09-27-host-supervision.md).
45+
3946
File retained-state storage now reuses the existing TS checkpoint/delta codec,
4047
stacked on #5063's verified read cache and RPC budgets. Original revisions,
4148
receipts and full historical projections survive the physical format upgrade.

‎docs/architecture/rfcs/shared-goal-authority-state-provider-v0.zh-CN.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ PR:本次恢复切片、外部执行区间保护、整 Goal 激活/回退集
3030
缺失证据另列,不能保证最终缺陷修复数量。
3131
[当前清单、依据及退出条件](ledger/shared-goal-authority-state-provider-v0/2026-09-27-recovery-audit.zh-CN.md)。
3232

33+
同一窗口另有已交付的进程监督切片:通用命令与 Codex CLI 的进程生命周期改由
34+
一个 TS supervisor 承担,因此执行中租约约束仍开放,不由本次关闭;旧“三个
35+
架构包”仍是指针,不是递减 PR 计数器。该切片的逐项计划、估算变化与边界单列。
36+
[核对的逐项计划、估算变化与边界](ledger/shared-goal-authority-state-provider-v0/2026-09-27-host-supervision.zh-CN.md)。
37+
3338
## Todo 事件路径退役(2026-09-25)
3439

3540
PR #5054 将原先的事件 writer 捕获方案改为删除这条实验性 Todo 来源。

‎docs/architecture/rfcs/typescript-control-plane-migration-v0.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,13 @@ existing #5054/#4931 and D2/D3 evidence remain separate. This is not a guarantee
4141
count of future defect repairs.
4242
[Current inventory, rationale and exits](ledger/shared-goal-authority-state-provider-v0/2026-09-27-recovery-audit.md).
4343

44+
Managed Host supervision lands in the same window as a separate delivered slice:
45+
one TS supervisor now owns generic command and Codex CLI process lifetimes, so
46+
authority-bound execution stays open rather than closing here, and the old three
47+
architectural packages remain a pointer instead of a decrementing PR counter.
48+
Its named plan, changed estimate and boundaries are recorded separately.
49+
[Named plan, changed estimate and boundaries](ledger/shared-goal-authority-state-provider-v0/2026-09-27-host-supervision.md).
50+
4451
## Native authority qualification and prototype retirement (2026-09-26)
4552

4653
The coverage-only Python coordination executor, head codec, File provider and

‎docs/architecture/rfcs/typescript-control-plane-migration-v0.zh-CN.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ PR:本次恢复切片、外部执行区间保护、整 Goal 激活/回退集
3636
缺失证据另列,不能保证最终缺陷修复数量。
3737
[当前清单、依据及退出条件](ledger/shared-goal-authority-state-provider-v0/2026-09-27-recovery-audit.zh-CN.md)。
3838

39+
同一窗口另有已交付的进程监督切片:通用命令与 Codex CLI 的进程生命周期改由
40+
一个 TS supervisor 承担,因此执行中租约约束仍开放,不由本次关闭;旧“三个
41+
架构包”仍是指针,不是递减 PR 计数器。该切片的逐项计划、估算变化与边界单列。
42+
[核对的逐项计划、估算变化与边界](ledger/shared-goal-authority-state-provider-v0/2026-09-27-host-supervision.zh-CN.md)。
43+
3944
## Todo 事件路径退役(2026-09-25)
4045

4146
PR #5054 将原先的事件 writer 捕获方案改为删除这条实验性 Todo 来源。

‎docs/reference/protocols/loopx-turn-v0.md‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,48 @@ dedicated typed result channel; passing `trae chat` directly as the adapter is
253253
not sufficient. Check the installed CLI's help and pin the qualified command
254254
shape because flags and headless behavior may vary by version.
255255

256+
### Managed Host Process Lifetime
257+
258+
The generic command executor and built-in Codex CLI adapter now share a TS
259+
process supervisor. Existing `turn run-once` commands need no new option. Node
260+
uses the same supported-version discovery as the control-plane runtime; the
261+
private request stream is limited to 8 MiB and is not a durable protocol.
262+
263+
A Host leader exiting, its output pipes closing and its descendants stopping
264+
are distinct observations. On POSIX, LoopX starts a dedicated process group,
265+
sends TERM and escalates to KILL after 300 ms, **including when the leader has
266+
already exited**. Normal result return also cleans up leftover group members.
267+
Host commands must not use that group to launch intended persistent services.
268+
Windows retains Python command-launch compatibility (including batch entrypoints)
269+
through a transport-only relay, then attempts tree termination before killing
270+
the leader. Windows uses best-effort process-tree cleanup; this delivery does not claim
271+
POSIX-equivalent cancellation or Windows qualification.
272+
273+
Timeout, output-consumer failure and loss of the owning Python process trigger
274+
cleanup. The control pipe remains open for the job lifetime; EOF cancels work.
275+
After leader exit, output drain is bounded (normally two seconds), rather than
276+
waiting indefinitely for inherited pipes. Generic stdout is capped at its
277+
existing 12,000-byte result budget while streaming. Codex output is consumed
278+
transiently with LF-framed records capped at 1,048,576 characters and a finite
279+
set of failure categories; an oversized record makes diagnostic observation
280+
incomplete. UTF-8 characters split across byte chunks remain intact. Raw Host
281+
output is not written to LoopX state.
282+
283+
Generic results require complete output and zero exit status. Codex retains its
284+
existing separate typed result-file contract: incomplete diagnostics do not
285+
invent a failure category, and a validated result file remains usable. Timeout
286+
still preserves the observed opaque session for the existing retry path. No
287+
process observation certifies Todo completion, refunds spend or rolls back an
288+
external effect; independent validation and settlement keep their owners.
289+
290+
This is **process supervision, not execution authority or a sandbox**. It does
291+
not renew provider leases, prevent stale remote side effects, cancel attached
292+
App sessions, or supervise in-process DSH execution. Descendants that escape the
293+
process group and killing the supervisor itself with SIGKILL are outside this
294+
boundary. Caller death can precede cleanup; the local lane lock alone cannot
295+
certify no overlap with a replacement executor. Authority-bound renewal,
296+
revocation and uncertain-effect recovery remain a separate delivery.
297+
256298
### Repeatable Codex CLI Qualification
257299

258300
The repository includes an opt-in end-to-end qualification that creates an

0 commit comments

Comments
 (0)