Skip to content

fix(native-accounts): adopt a unique external slot login - #8018

Merged
loopx-agent merged 3 commits into
mainfrom
codex/native-adopt-slot-20261104
Nov 4, 2026
Merged

loopx-agent merged 3 commits into
mainfrom
codex/native-adopt-slot-20261104

Conversation

@loopx-agent

Copy link
Copy Markdown
Collaborator

Problem

An operator or another tool can restore a slot's credentials directly into the GPT home (for example returning from the API route after an outage). The account store compared the home login with active.json, raised "GPT login changed outside the slot manager", and native status returned native_unavailable / login_matches: false. Automatic handoff then stayed stuck even though the home clearly matched a known slot.

Change

  • Adopt the home login when its identity matches exactly one stored slot, updating active.json to that slot.
  • Reconcile adoption in both selected() and status().
  • Unknown or ambiguous logins still require inspection; no slot is guessed.
  • Added a regression test that externally restores slot b's vault entry and expects status()['active_slot'] == 'b'.
  • Bump the package to 0.14.1.

Verification

uv run --python 3.12 --with pytest pytest tests/presentation/test_native_account_store.py tests/presentation/test_native_app.py tests/presentation/test_native_accounts_install.py -q — 52 passed, 20 subtests passed.

中文摘要:手动或其它工具把已知槽位的凭据直接写回 GPT home 后,native store 会卡在 native_unavailable。此 PR 在身份唯一匹配某个已存槽位时自动采纳该槽位(同时更新 active.json,并在 selected/status 中生效),未知或歧义登录仍需人工检查,并补了回归测试。

An operator or another tool can restore a slot's credentials directly into
the GPT home, for example when returning from the API route after an outage.
The store then saw a login that did not match active.json, reported
native_unavailable, and automatic handoff stayed stuck even though the home
matched a known slot.

Adopt the home login when its identity matches exactly one stored slot, and
reconcile that in both selected() and status(). Unknown or ambiguous logins
still require inspection. Bump 0.14.1.

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

mergify Bot commented Nov 4, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @loopx-agent.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

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 HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Nov 4, 2026
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Nov 4, 2026

@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 (Codex); OpenAI; self_reported

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

动机 / Motivation

从 API 返回已登记订阅或外部恢复登录的 native Codex 用户。 已登记 B 登录被外部完整恢复后,原主干仍指向 A;现在仅在现有锁可用、无 pending、路由一致且唯一时认领 B。 唯一完整恢复可继续使用;锁占用、pending、未知/重复身份、路由冲突和损坏槽位均不改写 active,凭据和配置不变。 不刷新或复制认证、不授权付费、不重放业务、不证明已运行 App 已热加载认证。 本 PR 只认领唯一且路由一致的已有槽位;独立调用方的订阅主力/API 兜底和管家 API 主力配置仍由本轮后续工作交付。

改动思路 / Approach

复用 Accounts 的同一槽位清单、锁、路由校验与 atomic writer,只修正派生的 active.json 选择注记,不增加凭据 owner 或第二套恢复流程。 认领是一条派生选择注记,不等于覆盖凭据:继续沿 Accounts 的锁、完整槽位读取、file_config() 路由校验与 atomic() 更新,保留原 recover() 的恢复责任。复审没有为此另建额度 selector、后台消费者或新的状态库。当前交付边界为已有槽位的安全选择注记恢复,不包含独立调用方的付费优先级。

具体改动 / Changes

规格基准:spec_ref = packages/loopx-codex-provider-routing/NATIVE.md,spec_revision = e93d0d57ae876f63b4365b1357091275f51e7bdf。逐条核对 single-account-writer(唯一原生凭据 owner)、recovery-before-adoption(原锁/journal/恢复优先)、no-implicit-paid-replay(观察不授予付费与重放),当前 exact head 均满足。

关键代码讲解

  • Accounts.selected() 在发现已登记登录漂移或选择注记缺失时,请原 owner 识别;未知身份继续拒绝,完整恢复不要求再写一遍凭据。
  • Accounts._adopt() 先拒绝 pending,再取得既有 exclusive launch/shared credential 锁,锁内重读 auth、检查路由一致性并验证全部槽位。只有唯一匹配才写 active.json;不跳过损坏槽位制造唯一性,不写 auth、config 或 slot 内容。
  • Accounts.status() 复用同一方法,无 active 时也识别已登记登录;未登记、直接外部 API 与 null 缓存保留改前的未知状态。保留已合入 #8014 的直接 API 启动边界。

完整 PR 涉及五个文件:一个生产模块、原测试集、NATIVE.md 与两处 0.14.1 版本。生产文件 52 增/4 删,测试增加 76 行,文档增加 8 行。原 PR 的正常用例通过,但真实负例显示 pending、锁占用和路由冲突下仍写注记,且缺少 active 时 status 不能识别;本次已在责任层修复四处边界,并补充未登记状态的 base/head 对照。

对主干的风险 / Risks

最大风险是 status 的派生注记写入抢在事务完成之前,掩盖真正的失败。使用相同合成私有文件,分别运行 immutable base e93d0d57ae876f63b4365b1357091275f51e7bdf、原 PR d81ef83c6e245824cb49872888c99f192b1c0e35 与最终 head 96db65ad34f965f0a4b1edb18411045c4c136e69:主干的唯一恢复/缺失 active 两例预期失败,原 PR 四个边界失败已复现;当前八例全部通过。pending 用例确实让子进程在 switch 写 auth 后退出,保留真实 journal,再验证原 recover 与 switch 可继续;不是伪造一条“已恢复”布尔值。八例均核对非 active 文件不变,另有未登记三分支同入口不变性验证。

验证:PASS,166 tests/28 subtests;八例认领、八例直接 API 预检;native-policy、native-host、native-host-clients、provider-routing 四组 smoke;Ruff 和预合并五项直接检查。catalog 选择为零项;实际五个公开候选文件扫描通过。全局检查仍保留两个其他旧 Goal 的 authority 诊断,没有为此越界迁移。没有操作真实凭据,也未执行付费模型测试。

语义与 CI 对齐

本修复有意让已登记完整恢复在普通 status/preflight 中更新派生选择注记,即使 observer 开关关闭也可识别;它没有新加“默认关闭”的承诺。未登记调用方的输入、状态和文件与主干一致,既有自动 API 开关与调度不变。按本 Goal wait_for_ci=false,未查询、轮询或等待 CI;结论来自上述真实本地不变量验证。

我的整体评价 / Verdict

没有剩余阻塞发现,当前 exact head 可以合并。long_horizon 与 user_experience 均改善:完整外部恢复进入同一生命周期,重复误报与重复登记步骤减少;不完整恢复继续交原事务处理。范围与成本相称,已用现有 owner 修掉无锁认领,没有扩大权限。没有渲染变化,visual review 不适用;实际运行中的 AppKit 认证热加载与模型推理没有验收,不据此宣称完成。本 PR 只认领唯一且路由一致的已有槽位;独立调用方的订阅主力/API 兜底和管家 API 主力配置仍由本轮后续工作交付。

English verdict: APPROVE 96db65a; unique restored-slot recognition is fenced by existing locks, journal, route and complete inventory; boundary, parity and native suites pass.

@loopx-agent
loopx-agent merged commit 2dd1d8c into main Nov 4, 2026
8 of 9 checks passed
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