背景
#37 / #38 落地的 control-plane([DEVLOG_STAGE] / [DEVLOG_GATE] stdout 协议 + resolveGate)我们在 fork 上接了一层 Linear 中转、用真实 issue 全链路跑了多轮。协议本身工作得很好;但在「把人工回复投递回 agent」这一段,发现两个健壮性缺口,都在核心层:
缺口 1:codex(plain-stdin 引擎)收不到 gate 回复
一个 codex session 触发 gate 后,回复没有任何可达路径:
- 活进程写不进:codex 启动即
stdin.end(prompt)(一次性),writeGateResponse 的守卫发现 writableEnded 后直接丢弃回复,只记一条 warning;
- 重生不是恢复:
resolveGate 对死进程走 ensureProcess 重生,但 codex 的启动参数是 codex exec --json … -,没有任何 resume 参数 —— 重生的进程是全新会话,丢失全部上下文;
- 想恢复也没料:
sp.claudeSessionId = event.session_id 只在 claude-stream-json 解析路径里赋值,codex 事件解析器从不捕获 codex 自己的 thread/session id。
建议方向:捕获 codex 的 session/thread id(它的 JSON 事件流里有)→ 增加 codex exec resume <id> 启动路径 → plain-stdin 的 gate 投递改成「等进程退出 → 带回复 resume 重生」。
缺口 2:resolveGate 投递失败仍返回成功,且先清 gate 后验投递
resolveGate 的顺序是:resolveControlPlaneGate(先清掉 gate_status)→ 找/重生进程 → writeGateResponse。两种失败都会被吞掉并返回 {ok:true}:
ensureProcess 返回 null(重生失败)→ 跳过投递,照样返回成功;
writeGateResponse 写 stdin 失败(已关闭/异常)→ 只记 warning,照样返回成功。
结果:人的回复被消费、gate 已清、agent 永远没收到 —— 调用方完全无感。
建议方向(我们 fork 已这样修,可参考 loop2zero/DevLog@96ce529):先取得可用进程再清 gate;writeGateResponse 返回 boolean;投递失败时把 gate_status 原样恢复(sessions+tasks)并返回 {ok:false},让上层可以重试。
复现要点
任何 gate 流程 + 让原进程在 gate 期间死亡(或直接用 codex 引擎),然后调 resolveGate:观察返回值为 ok 但 agent 无任何动作。
来自 fork(loop2zero/DevLog,在 #37 协议之上做 Linear 中转)的真实运行发现。两个缺口都愿意出 PR,如果你对方向有偏好请说。
背景
#37 / #38 落地的 control-plane(
[DEVLOG_STAGE]/[DEVLOG_GATE]stdout 协议 +resolveGate)我们在 fork 上接了一层 Linear 中转、用真实 issue 全链路跑了多轮。协议本身工作得很好;但在「把人工回复投递回 agent」这一段,发现两个健壮性缺口,都在核心层:缺口 1:codex(plain-stdin 引擎)收不到 gate 回复
一个 codex session 触发 gate 后,回复没有任何可达路径:
stdin.end(prompt)(一次性),writeGateResponse的守卫发现writableEnded后直接丢弃回复,只记一条 warning;resolveGate对死进程走ensureProcess重生,但 codex 的启动参数是codex exec --json … -,没有任何 resume 参数 —— 重生的进程是全新会话,丢失全部上下文;sp.claudeSessionId = event.session_id只在 claude-stream-json 解析路径里赋值,codex 事件解析器从不捕获 codex 自己的 thread/session id。建议方向:捕获 codex 的 session/thread id(它的 JSON 事件流里有)→ 增加
codex exec resume <id>启动路径 → plain-stdin 的 gate 投递改成「等进程退出 → 带回复 resume 重生」。缺口 2:
resolveGate投递失败仍返回成功,且先清 gate 后验投递resolveGate的顺序是:resolveControlPlaneGate(先清掉gate_status)→ 找/重生进程 →writeGateResponse。两种失败都会被吞掉并返回{ok:true}:ensureProcess返回 null(重生失败)→ 跳过投递,照样返回成功;writeGateResponse写 stdin 失败(已关闭/异常)→ 只记 warning,照样返回成功。结果:人的回复被消费、gate 已清、agent 永远没收到 —— 调用方完全无感。
建议方向(我们 fork 已这样修,可参考 loop2zero/DevLog@96ce529):先取得可用进程再清 gate;
writeGateResponse返回 boolean;投递失败时把gate_status原样恢复(sessions+tasks)并返回{ok:false},让上层可以重试。复现要点
任何 gate 流程 + 让原进程在 gate 期间死亡(或直接用 codex 引擎),然后调
resolveGate:观察返回值为 ok 但 agent 无任何动作。来自 fork(
loop2zero/DevLog,在 #37 协议之上做 Linear 中转)的真实运行发现。两个缺口都愿意出 PR,如果你对方向有偏好请说。