fix(macos): preserve independent execution and Chat Codex homes - #5626
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=xhigh
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Exact head: 5626@7c0393ec0d2f3e246cc0282df6f5bade705cd6b6. Base: 2f68e3b835c3bfc0e3718373cdb6c72eea99291e.
动机
在 macOS 上让聊天服务与长期 worker 使用不同既有 Codex 目录的操作者。 基线安装或重启会把聊天目录同时写成执行目录,使 worker 的原会话 profile 检查失败;当前版本分别保留两项设置,升级未指定执行目录时无需重输原目录。 真实安装脚本、生成的 zsh 包装器和既有目录消费者对照证明分离配置可传递、重启保留且恢复原目录后 profile 检查通过。 本次不迁移会话、不复制凭据、不新增 Agent 权限,也不声明实际 launchd 登录恢复、真实模型多轮续跑或长期吞吐已验收。 实际登录服务恢复、Bot 发起 worker 续跑及两轮独立验收仍由已有运行时资格路径完成。
改动思路
聊天服务使用的 Codex 目录与执行 worker 使用的目录,都是操作者已经选择的宿主配置。旧安装器把聊天选择写到两个变量,破坏 worker 的既有 profile;本次在原解码器上增加变量和首次安装 fallback 参数,分别读取、保留和传递两项选择。沿用原 XML/shell 转义和旧 plist 读取,继续由既有会话 owner 判断能否恢复,没有新增权限或决定源。只查看配置字符串不够,因此我执行了真实安装脚本及其生成的 zsh 子进程,再检查实际 Chat 目录消费者和原 worker 的 profile digest。launchctl、curl 与上游模型边界为 fixture,未声称真实登录服务通过。
具体改动
完整三文件 +62/-10:安装器 +14/-9、已有 smoke +34/-1、双语集成文档 +14。默认安装无需增加参数;同时指定两项现有变量可分离目录,重启未指定执行目录时保留已安装值。显式改变执行目录只改变服务配置,原会话的 profile 围栏仍适用。
关键代码讲解
resolve_codex_home(scripts/macos-dashboard-launchagent.sh:213):明确变量优先,其次读取已安装字段或旧 shell export,最后采用首次安装 fallback;只用 shlex 解码旧命令,不执行旧命令,拒绝相对目录。write_plists(同文件:250,调用:279–281):先解析两个目录再写 plist;分别生成 CODEX_HOME 与 LOOPX_CHAT_CODEX_HOME 的环境和值,原状态服务参数和写 API opt-in 分支保持不变。- smoke
main(examples/macos-dashboard-launchagent-status-smoke.py):加入不同目录、含空格路径、无参数重启、真实 wrapper child 和无覆盖拒绝;沿用临时 HOME/fake launchctl,补充已有回归而非新建演示框架。
规范按 同一份已接受集成契约 docs/integrations/session-runtime-control-plane-adapter.md @ 2f68e3b835c3bfc0e3718373cdb6c72eea99291e 判断;不以本 PR 新增文档自行证明规范:
Managed Codex home ownership (implemented):implemented,独立目录传输、原会话 profile 保留及错目录拒绝已核验。including older shell-export plists:implemented,旧 shell-only 输入在两版保持相同 child 行为,损坏 plist 拒绝并保留字节。changing this variable is not a session-migration command:implemented,主动换执行目录不能恢复原绑定;恢复原目录后 profile 检查通过,没有复制或迁移会话。interrupted task recovery rate:deferred,实际登录/Bot 发起 worker、两轮独立验收及重复计算指标仍属已有 R2/S4 运行时资格,不把本次桥接烟测算成全部完成。
对主干的风险
同一输入经冻结基线和当前 head 各执行12个场景,共24个观测。四个不同目录场景——初次选择、无参数重启、仅改 Chat、仅改执行端——基线均导致原预期 worker profile 拒绝,当前均传递正确目录。普通默认、Chat-only 首装、相同目录及旧 shell-only 四组的完整 child 结果相同;有效样本的 status plist 字节相同。额外反向核验显示:主动选择其他执行目录仍拒绝原 worker 绑定,恢复原目录接受,未把 transport 修复变成身份绕过。相对执行目录和损坏 plist 在 head 均在替换前拒绝。
110项相关 pytest 通过,LaunchAgent smoke、当前 Chat bundle 构建/校验、Ruff、bash -n、diff hygiene、开发 advisory 后的完整 semantic-vocabulary smoke 通过。按完整三文件运行风险 premerge:4个直接检查及18项选中检查通过,1项既有 maintainability advisory 保留;基线完整源快照和当前 head 的完整归一化报告相等,均为未改的 goal_topic_runtime.py any_count56超过49。该债务不能称为已修,也不扩大本 PR 来调整 ceiling。首次测试有5项因 worktree 中上一版构建包的 source manifest 过期而失败;生成当前 head 包后原110项通过,未放宽断言/预算。构建另有现存 npm 依赖告警;本 PR 没改 lockfile/依赖,不宣称全库安全扫描完成。
本修改没有新增 optional capability;现有 write API 开关仍按原 smoke 的开/关路径执行,状态 plist 对照保持相同,不影响 Goal quota、claim/lease 或注册 Agent。Frontend/Lark 配置 owner 未改变,原 CLI 安装入口仍可操作,不需要新 UI 开关。相关 #5543 也修改同一安装器的解释器、registry 和 workspace transport;集成时要保留两组修复,当前没有宣称两 PR 已组合验证。实际 launchd、真实模型或 Bot 新 dispatch、安装升级及长期 throughput 未执行;无 CI 查询/轮询/等待,也未更改活跃服务或账户。
我的整体评价
APPROVE,无当前阻塞 finding。delivery 为 justified_increment:long_horizon 与 user_experience 在本次受影响路径均 improved,证据是正确目录跨重启保留和原身份围栏拒绝/恢复,而非 PR 数或测试数。它减少了已复现的“升级后 worker 换错目录、需要人恢复”的中断成本;速度或长期产出提升仍是预期,未给出未经测量的百分比。62行新增对应完整有界修复,参数化原解码器已做邻域简化;旧持久化 plist 是真实消费者,保留单一解码路径合理,另加通用框架或无关 TS 重写没有当前价值。语义复用现有变量和身份 owner,局部路径解析不创建共享 vocabulary。控制面/运行时变更由维护者合并,APPROVE 和原生 ready 都不授予自合并权。
English verdict: APPROVE - 5626@7c0393ec0d2f3e246cc0282df6f5bade705cd6b6; independent execution/Chat homes survive installation and restart, original profile rejection/recovery remains intact. 12 paired installer cases,110 related tests, LaunchAgent smoke and bounded risk checks pass; inherited maintainability advisory retained. Actual launchd/model continuity and sustained efficiency remain unqualified; no CI consulted; maintainer merge required.
|
This pull request has merge conflicts with Choose the remote for the base repository, not an out-of-date fork. git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEADFor a same-repository clone whose Keep the DCO |
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; model=gpt-6.1-sol; provider=OpenAI; declaration_source=runtime_reported; reasoning_effort=xhigh
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机
在 macOS 登录服务中沿用已有 worker 会话、同时给聊天端选择另一配置目录的用户。 升级或只修改聊天目录时,旧安装器会把 worker 的执行目录一起改掉,原会话配置检查因此拒绝恢复;修复后两端分别保留各自目录,重启不需要重新输入已知配置。 真实安装器、生成的 zsh 子进程和独立安装包已验证:不同目录可保存、重启和恢复,错误执行目录仍被拒绝,恢复原目录后检查通过。
此 PR 修复主干冲突与服务配置传递;真实 launchd、Bot/付费模型和两轮完整工作恢复仍未测,R2/S4 与 SQLite 默认/升级及 Python 退役的完整验收继续保持开放。
改动思路
复用现有 macOS 安装器、plist 解码和 shell/XML quoting,以及 Chat 目录捕获与 worker session profile(会话配置身份)检查。一个既有 resolver 分别读取聊天与执行设置,再由同一个 writer 生成持久字段与子进程 export;用户的独立目录选择无法从另一端推导,因此不是多写一份需要手工同步的状态。遗漏执行选择时读当前服务记录,新安装才采用聊天目录。旧 shell-only plist 仍有真实升级调用方,继续只解码而不执行其内容。
普通 install/restart 仍走原入口。先解析目录、registry、工作区和当前 runtime identity,再写服务描述;子进程接收原有自定义 registry 与工作区参数。实际 profile 检查的 owner 未移动,也没有新调度器、Python eligibility owner、credential copy 或会话迁移。选择错误 execution home 时保留拒绝,按原目录修正才能恢复;这样验证的是有用恢复,非仅新增 blocker。
具体改动
当前精确 head e82c394f5d69255226aa4dc6c1feee4078e95e1f,固定 main 基线 03794d7b0edb323a52c8aec05c9be24c27f4f5cc。原 head 7c0393ec0d2f3e246cc0282df6f5bade705cd6b6 已有评审,但不继承其批准;本轮正常 merge main、解决两个安装器/测试冲突,保留当前 interpreter、registry、workspace 与 runtime identity 边界。完整当前 PR 三文件69+/11-,远端 whole diff 与已验证本地 diff 的路径、hunk 和内容相同,只有 index hash 显示长度不同;GitHub patch 格式只展示原普通提交,不能代表 merge 冲突解决后的最终内容。
依据为 docs/integrations/session-runtime-control-plane-adapter.md,固定 revision 03794d7b0edb323a52c8aec05c9be24c27f4f5cc:接受前的相同规范。Managed Codex home ownership implemented:Chat 捕获与 session mismatch 仍在原 owner 强制;including older shell-export plists implemented:独立绑定、遗漏重启和旧 shell upgrade 由真实安装器验证;changing this variable is not a session-migration command implemented:错误 execution home 拒绝旧 worker,原目录恢复接受,未更改 session/store/auth;interrupted task recovery rate deferred:实际服务与两轮 R2/S4 仍由既有验收承担,不用合成 host 或测试数关闭它。
关键代码讲解
resolve_codex_home(scripts/macos-dashboard-launchagent.sh:279)从显式变量、已安装 exact field 或旧 export 取该目录;旧 descriptor 用 shlex 解码,拒绝相对路径,返回展开后的绝对路径。复用一个解析 owner,没有两个平行 resolver。write_plists(scripts/macos-dashboard-launchagent.sh:316)分别解析LOOPX_CHAT_CODEX_HOME与CODEX_HOME,生成独立 export/EnvironmentVariables;保留 main 的 console-script interpreter、custom registry、workspace 参数及写前 runtime identity 校验。服务配置选择没有授予执行其它会话的权限。- 既有 durable smoke 更新了错误的“Chat 总是覆盖 execution”预期,实际执行生成的 zsh wrapper,断言两个 home、自定义 registry、带空格/命令替换字符的工作区参数完整到达子进程,且未执行命令替换。相对 execution home 和 malformed plist 保持写前拒绝;docs 以双语披露默认改变和非迁移边界。
对主干的风险
没有当前阻塞发现。最强反例是“plist 字符串正确,真正的子进程却丢失 registry/workspace 或仍覆盖原 worker home”。固定12场景逐项经过真实安装器、zsh、Chat capture 和 worker digest/fence;四个独立 home 场景在 main 都拒绝原配置,在 head 都接受。默认、仅 Chat、新建相同 home、旧 shell 的完整 child 观察和 status plist 字节保持一致;新增 Chat plist 的 execution 字段是明确披露的持久变化,没有把整个 plist 假称 byte parity。改到错误 execution home 仍拒绝原绑定,恢复原目录后接受;invalid input 不覆盖原服务。
同组验证在 noneditable wheel 重复,子进程从 site-packages 导入真实消费者,不靠源码目录遮蔽。201项源码 Chat/home/Turn/delegation 回归、57项 wheel Chat/home 测试、官方当前 Chat/wheel 构建、tsc、scoped Ruff、bash syntax 和 diff 检查通过。原生 CQ cqr_e131d9c13d36d568487a 对此 exact scope pass;canary premerge 4direct/19selected、零 blocking failures/manual holds,使用选定 worktree Python。没有查远端 CI。
一项 ratchet 仍红,保留为原生 inherited advisory:不可变 base 与 head 的完整 JSON 除根目录外完全相同,包含 goal_topic_runtime.py Any 56>49、quota handler statements 96>90、goal_boundary decision points 63>60,未修改这些文件、ceiling 或断言。最初未带 tracked census 的 archive 漏掉债务,未当作 baseline 证明;随后用同一 Git tree 的独立私有 index,才逐项复现失败。早期 CQ 结果因字段预算/引用范围被拒绝,修正序列化后才获当前有效 receipt,拒绝结果没有当成功记账。
launchctl、HTTP/upstream model 是 fixture;没有改动真实 LaunchAgents、账户、Bot 或现有 worker。并发 installer 与真实长期 R2/S4 仍未测,未新增并发保证。已有 store、session migration/rollback 和旧 plist 读取能力继续保留;恢复依赖正确原目录,不靠删除 profile fence 或复制凭据。三个公开路径及 review 文本不含私有状态、日志或本机路径。回滚可 revert 此代码,不重写历史会话。
语义与 CI 对齐
这是披露的既有 installer 默认修复,无新增 feature-off capability;配置字段的可用性不等于授权。现有 provider environment vocabulary 与 typed session identity owner 被复用,没有新通用 actor lifecycle。absolute/plist/profile 拒绝是 machine-enforced,文档是纠正与范围说明,未把硬准入说成建议。通用 Goal/Turn obligation 没有混入 Codex 产品词。
changed advisory 在 full semantic-vocabulary checker 之前执行,两者均完成;空 advisory 不覆盖动态 construction。formal scanner 自己保留未证明的 producer 与跨 runtime 边界,不被当作全局语义等价证明。关闭/普通路径用完整 consumer/status parity 和负例补充,而非 green CI 或符号计数。
我的整体评价
APPROVE,justified_increment:long_horizon improved,遗漏重启和目录更改不再使既有会话走错配置;user_experience improved,保存已知独立选择、错误输入可纠正,没有新增操作页面或额外确认。完整真实服务、SQLite 默认升级、Python 退役及 Goal 均未据此收尾。
Future-facing pass 已应用:复用单一 resolver,保留实际旧 descriptor 解码与 session fence,扩展现有真实 wrapper 测试而非平行测试框架。代码规模与这个可复现恢复问题相称。最新 host 记录提供 Reviewer 来源,active_turn_verified=true 只描述该观察,不证明 backend weights 或赋予权限。运行时变更仍由维护者合并;作者 COMMENTED 结论不是 GitHub 独立批准,也不是 merge authority。
English verdict: APPROVE - e82c394; real installer/zsh and source/noneditable-wheel consumers preserve independent homes and main registry/workspace transport, with wrong-profile refusal/restoration intact. 201 source and57 wheel cases, paired12-case observations and native4/19 gates cover this bounded repair; independently reproduced baseline ratchet debt and live R2/S4 gaps remain explicit.
A macOS Chat service may resume workers from an execution
CODEX_HOMEdifferent from its Chat app-server home. Previously selectingLOOPX_CHAT_CODEX_HOMEoverwrote both values, so existing worker profiles no longer matched. The installer now persists them independently, preserves omitted values on upgrade/restart, and keeps session-profile refusal in force.Latest main is incorporated with a signed normal merge. Its selected-distribution interpreter, custom registry, workspace arguments, and runtime-identity checks remain; no force-push or parallel launcher is introduced.
Specification And Acceptance
Basis: the existing PR's independent service-home repair and managed home ownership / upgrade preservation, read at the unchanged main revision before repair.
Scope And Continuation
Three files: the existing host installer, its durable smoke, and the integration contract. One resolver serves both existing settings. Old plist decoding remains because supported upgrades still call it; removing Python adapters is not a reason to lose that recovery path. This repair is complete within this scope; broader host qualification remains with the existing R2/S4 owner. No frontend operation or authority provider is added; this does not qualify canonical SQLite as the release default.
Validation
Tested head:
e82c394f5d69255226aa4dc6c1feee4078e95e1f; base:03794d7b0edb323a52c8aec05c9be24c27f4f5cc. Finished; synthetic/public fixtures.uv run --extra test python examples/macos-dashboard-launchagent-status-smoke.pypassed, including actual generated zsh wrapper, literal workspace arguments, invalid-home refusal and inherited retention/registry/identity checks.uv run --extra test python -m pytest tests/test_chat_codex_home.py tests/test_chat_agent.py tests/test_loopx_turn_executor.py tests/test_local_delegation.py -q: 201 passed. The installed wheel's Chat/home suite: 57 passed, imported from site-packages outside the checkout.UI impact: none; existing installer settings are repaired, with no new product screen. Runtime merge remains maintainer-owned.