Skip to content

fix(accounts): share native policy and elect one observer - #7361

Merged
loopx-agent merged 1 commit into
mainfrom
codex/native-account-policy-owner-20261026
Oct 26, 2026
Merged

loopx-agent merged 1 commit into
mainfrom
codex/native-account-policy-owner-20261026

Conversation

@loopx-agent

Copy link
Copy Markdown
Collaborator

Chat could display automatic account switching as disabled while a CLI watcher used a different, enabled policy. Route account settings through the registry-declared native owner while preserving an explicitly isolated Chat runtime when no owner is declared. Add an observer lifetime process lock so App and CLI share one active observer with takeover after owner exit; publish provider 0.12.8 and document upgrading all observers.

Validation: 15 focused tests; 83 additional regression tests; native host, client handoff, recovery, provider policy and operator smokes; actual packaged settings page at desktop and 390px, including off/on/reload and unknown-allowance recovery with synthetic accounts. No real credential switch was triggered. Three existing App-quit fixture tests fail identically on the unchanged base because their subprocess mock cannot handle dynamic process discovery; they are explicitly excluded from the 83 passing regression tests and retained as a known validation gap.

Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; effort=max

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

动机

同时从设置页和命令行使用原生账号自动切换的用户,会遇到页面状态与实际观察器不一致。例如会话历史放在独立目录时,页面显示关闭,命令行仍读取公共目录里的开启策略;即便把来源统一,两个进程原先也只在单次事务中互斥,随后仍各自查询额度。

本次把设置页接回 registry 已声明的账号策略来源,并让同一来源始终只有一个自动观察器;页面关闭会改变实际策略,原观察器退出后等待者可以接管。范围是策略读写与自动观察归属,不增加账号、扩大重启授权、重放工作或宣称真实额度耗尽时已经完成换号。真实账号耗尽后的端到端切换及无法证明重启归属的占用者仍需保留独立验收,不能由合成额度或只读状态代替。这类分裂会让用户无法判断关闭是否真的生效,并在恢复时重复排查同一问题。不能只把页面标签改成与命令行相同,也不能把一次事务成功当成整个自动服务只有一个执行者。

改动思路

复用既有 registry 路由、NativeAccounts 私有状态和事务锁,在可选 provider 内增加观察器生命周期锁;不另建配置、凭据库、消息消费者或选择策略。当前 PR 只修复原生账号来源与观察归属,Core 仅选择已有 owner;原有 TypeScript 资格判断、客户端退出/恢复、会话存储和历史保持原 owner。

只重定向配置,会保留 App 与独立 watch 的两条观察循环;只加锁,会让设置页继续修改无效的另一份策略。当前方案同时收敛这两个边界:会话目录继续保存原历史,账号策略采用 registry 声明的来源;同一策略目录的观察循环通过独占文件锁选出一个持有者,并在休眠期间继续持有。文件本身不代表活跃 owner,进程退出时由内核释放,等待者随后接管。

这里没有新增同步协议或手工 owner 表。默认关闭、slot allowlist、重启和强关授权仍由既有策略及 TypeScript 判断拥有;Python 的新增责任仅是既有进程/文件 IO。显式检查、配置写入和凭据事务仍走原事务锁,自动观察独占不应阻塞用户主动查看状态。未声明公共来源时保留显式独立 runtime,避免测试或私有实例落回用户的全局策略。

场景 基线 当前 head
账号公共 owner 与历史目录不同 页面和 CLI 读取不同策略 共用声明的账号策略,历史原地保留
App 与 watch 同时启动 单次事务互斥,循环仍重复 一方持有观察器锁,另一方等待
原观察器退出 另一循环本已并行 内核释放后等待者接管
无公共 owner 的独立 runtime 保持独立 继续保持独立

表格是源码与执行证据的解释,不替代实际 HTTP 与跨进程验证。

具体改动

评审覆盖 e905d3433ce01c6cecfe96ce9655d3c095aa1c4c 到 002ccd07087afa1f0630392b80fd986d90b41166 的完整 11 文件差异(+318/-7),包括两个现有生产模块、三个版本字段、两个回归模块、一份操作文档和三张合成截图。读取了当前 PR 的全部说明、评论、评审和实际 patch;发布前未有其他评论或评审需要逐项消除。

规范依据是 packages/loopx-codex-provider-routing/NATIVE.md,固定修订 e905d3433ce01c6cecfe96ce9655d3c095aa1c4c。依据改动前的实际契约核对:prerequisites-and-activation 已实现,安装不启用账号效果,原有明确开启策略在服务重启时恢复;disable-upgrade-and-rollback 已实现,页面关闭与独立进程读回同一策略,已发出的凭据事务仍保留原恢复责任;qualification-boundary 已保留,合成额度和只读状态不能充当真实账号切换或安装采用证据。本次文档新增内容说明新来源和升级条件,不以重写文档来降低原契约。

关键代码讲解

  • serve_chat 为账号 service 选择 registry 声明的 runtime;无声明时保留已经解析的显式 runtime。它不改 ChatStore 的目录,不复制历史、策略或凭据。真实 HTTP 测试安排相反的两份策略,验证读写到正确 owner、旧策略字节未变以及 stale revision 返回 409。
  • NativeAccounts._lock 复用原私有目录及符号链接检查,增加仅由内部调用给出的锁名。原事务仍使用 lock,观察循环使用 observer.lock,无需重新实现可信目录或状态持久化。
  • Watcher.run 持有观察锁再进入原循环。锁忙时仅等待五秒后检查归属,不调用原生账号;不可信锁等待后再试。进程退出释放内核锁,另一个真实进程可以接管。
  • Watcher._observe 保留原 tick、retry_at、异常等待与 stop event,没有再写一套额度优先级或自动换号判断。默认值、allowlist、已提交 intent 的完成/恢复逻辑没有改写。

三个版本字段统一到 0.12.8,包含原先滞后的模块版本;文档明确必须升级并重启所有旧观察器,旧进程不会自动取得新锁。跨进程测试以真实子进程和真实 flock 验证同 root 单观察、退出接管、不同 root 独立、外部关闭及不跟随符号链接。额度 transport 为合成,任何凭据切换调用都会使 fixture 失败。

对主干的风险

最强反例是“页面与 CLI 统一了来源,但旧版本观察器仍在运行”。单个新测试进程全绿仍不能解决这个安装风险,因此源码级保证以所有既有入口采用 0.12.8 为条件,安装必须沿原服务管理器有序停止旧观察器,再更新和读回;不能靠启动另一个消费者制造成功。声明公共 owner 的安装会开始显示这份策略的真实开启状态,即使旧 Chat 目录中的无效策略是关闭的;没有声明公共 owner 的显式独立实例则保持原行为。

新反例在未修改生产源码上先得 3 failed / 1 passed:HTTP 读到错误关闭状态、两个进程均观察、符号链接未阻止观察;独立 root 原本正常。当前针对性集合 15 passed,扩大回归 83 passed。另外 3 条旧 App 退出测试依然失败,不能称全套通过:测试桩把所有 subprocess.run 都当成带 input 的 AppKit 命令,而基线已有动态进程扫描调用 ps 时没有 input。将 native、native_host 和 chat_server 显式固定到不可变基线后,同三条测试仍以同一 KeyError: input 失败;相关生产因果路径不在本次改动。精确失败身份和日志保留,83 项结果只排除这三条,不删除断言或声称已修复。

标准 premerge 的 6 direct + 11 selected 检查通过,包含编译、diff、双语契约、维护性、词汇和公开文本边界;三个 PNG 产生的人工 hold 已逐张看像素、检查元数据和合成来源。没有把扫描器返回的 manual_review_required 改称自动全绿。Native host、client handoff、恢复、provider/TypeScript 与 operator smoke 通过;operator 首次启动缺少 PYTHONPATH 的错误保留,正确启动后 22 项通过。按当前配置没有查询、轮询或等待 CI。

语义与 CI 对齐

继续使用既有 native 策略、动作码和事务恢复语义,没有新增全局授权或 Goal 状态。停用保留已派发 intent 的正常完成边界;未知额度继续保留当前账号,重新检查后恢复 ready。独占观察与显式用户检查是两个不同责任,不把后者误当成第二个自动消费者。回滚应停止服务、恢复已知包和 Core,再核对策略与原会话,而不能重放提交过的任务或账号切换。

我的整体评价

结论 APPROVE,绑定 002ccd07087afa1f0630392b80fd986d90b41166,交付判断为有用的 justified_increment。长程继续能力 improved:只保留一个自动观察 owner,退出后仍能接管,不需要手工同步两份配置;用户体验 improved:原有一次开关动作就能改变实际策略,零额外配置、意图重述或确认回合。两处最小改动必须一起存在,不值得另建 daemon、owner registry 或配置迁移层。复用既有 registry 路由、NativeAccounts 私有状态和事务锁,在可选 provider 内增加观察器生命周期锁;不另建配置、凭据库、消息消费者或选择策略。当前 PR 只修复原生账号来源与观察归属,Core 仅选择已有 owner;原有 TypeScript 资格判断、客户端退出/恢复、会话存储和历史保持原 owner。

实际打包设置页的桌面、390px 窄屏和额度未知状态已看图核对,账号与开关层级可读,恢复分支保留当前账号;截图仅含合成 A/B/C,PNG 无文本或 EXIF 私有元数据。真实账号换号、原生 App 外壳及安装后的自然耗尽场景没有由这些截图证明。三张公开图没有真实邮箱、私有路径、token 或原消息内容,额度和身份均为合成。真实服务采用、自然耗尽后的切换以及未知占用者仍须独立读回,当前批准不替代这些后续验收,也不授予更大的重启或业务代办权限。已知三条基线测试桩失败继续单列,不能随合并被记成修好。

English verdict: APPROVE — 002ccd07087afa1f0630392b80fd986d90b41166 reconnects existing settings/CLI to the declared native policy owner and elects one automatic observer across processes, with owner-exit takeover and explicit isolation preserved. 15 focused tests, 83 regression tests, native/provider smokes and packaged synthetic recovery pass. Three unchanged baseline App-quit mock failures remain attributed and disclosed. All old observers must be upgraded/restarted; a real quota-triggered credential switch is not qualified by this review.

@loopx-agent
loopx-agent merged commit 0e47330 into main Oct 26, 2026
20 of 37 checks passed
@loopx-agent
loopx-agent deleted the codex/native-account-policy-owner-20261026 branch October 26, 2026 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant