Skip to content

fix(manager): recover non-SSH steward turns on concurrent registry sync and skip no-op global registry writes - #7879

Merged
huangruiteng merged 1 commit into
mainfrom
codex/steward-auth-scope-fix-20261102
Nov 2, 2026
Merged

huangruiteng merged 1 commit into
mainfrom
codex/steward-auth-scope-fix-20261102

Conversation

@loopx-agent

Copy link
Copy Markdown
Collaborator

Summary

  • Root-cause fix for manager_authorization_unavailable (当前连接的授权范围不可用) on non-Codex Steward turns:
    1. In collect_manager_turn_context (loopx/chat_manager_context.py), prepare_turn_context passes remote_evidence=True for non-CodexAppServerAdapter Steward endpoints (such as AntigravityAdapter / antigravity_ls). Even when the Steward channel had zero configured SSH remote sources (grants(runtime_root, channel_id) == []), not remote_evidence blocked the attempt == 1 local recollection whenever registry.global.json was touched mid-turn by a background worker. Gate the retry guard on actual configured SSH grants (inline_remote = bool(remote_evidence and grants(...))), and allow bound_steward (all_registered) turns to recollect once when a new Goal is registered mid-collection without mutating existing Goal instance identities.
    2. In merge_goal_entries and _merge_global_registry_payload (loopx/global_registry.py), preserve synced_at and updated_at when a routine loopx refresh-state sync does not change any Goal or Project entry, preventing redundant registry.global.json disk rewrites and sha256 revision churn across concurrent workers.
    3. Update test_trusted_manager_profile_rejects_endpoint_that_cannot_enforce_it in tests/test_chat_manager_context.py to match the Codex or Antigravity error message from feat(chat): support Antigravity (Gemini 4 Argon) as Steward and Chat executor #7832.

Verification

  • pytest tests/test_chat_manager_context.py tests/test_global_registry_write_serialization.py tests/test_native_steward_turn_host.py tests/test_antigravity_steward_adapter.py

…nc and skip no-op global registry writes

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.

1) 问题定义(为什么改、要解决什么)

  • 修复两项导致非 SSH Steward 会话(如 Antigravity 宿主管理会话)在并发后台同步时误报 external_authorization_changed 的根因:(1)collect_manager_turn_context 将所有 remote_evidence=True 调用一刀切禁止单次重试(即便当前会话并无 SSH 远程授权拨号开销),且未容忍 bound_steward 在单次采集中间新增受管 Goal 的单调扩张;(2)global_registry.py 在实质内容未变时每次同步均重写 synced_at 与 updated_at 时间戳,高频触发注册表文件变更。

2) 改动摘要(按模块分组)

  • 非 SSH Steward 并发重试与单调授权恢复 (loopx/chat_manager_context.py):仅当 remote_evidence 且存在真实 SSH grants 时才置 inline_remote = True;允许无 SSH 拨号的 bound_steward 在采样期间遇到单调 Goal 集合扩张或无实质变更的元数据刷新时重采样一次。
  • 全局注册表幂等时间戳保持 (loopx/global_registry.py):在 merge_goal_entries 与 _merge_global_registry_payload 中,若除 synced_at / updated_at 外的键值完全一致,则保留既有时间戳并跳过落盘重写。
  • 回归测试 (tests/test_chat_manager_context.py, tests/test_global_registry_write_serialization.py):新增并发注册表元数据触碰与新增 Goal 的重采样恢复测试,以及冗余同步不改写全局注册表文件(inode/mtime 不变)的回归测试。

3) 逐点审阅结论(架构、语义、正确性、测试、风险)

  • 安全与权限边界:set(before).issubset(set(after)) 且原 before 集合在新注册表下的 manager_authorization_scope_id_for_registry 严格等于 before_scope_id 时才允许重采样一次,既消除了后台 refresh-state 引发的误报,又严格保留了权限撤销(revocation)时的立即拒绝保证。

4) 建议修改项(分 P0/P1/P2,带文件路径和行号)

  • 无阻塞项。

5) 最终结论(Verdict)

Approved — ready to merge once CI completes (exact head 57631282a9dd2fab2477a628b8566f6901589e6b verified).

@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; reasoning_effort=max

动机 / Motivation

通过非 Codex endpoint 使用已绑定 Steward,恰逢后台刷新或注册新 Goal 的用户。 原来同一公开并发 fixture 在 registry metadata touch 或新增已授权 Goal 后都失去上下文;当前 head 在无 SSH 读取时重读一次并返回当前授权证据,同时保持真正 scope/instance 变化的拒绝。 同一实际 collector/registry 入口的三项回归在 base 均失败、head 均通过;六项追加反例证明换实例、撤销、加 Goal 同时换旧实例、持续抖动和非绑定范围新增均拒绝。66 + 92 个相关测试通过。 不增加 Steward 权限、自动恢复模型工作或跨主机一致性保证;不以读上下文成功推断已完成业务工作。

改动思路 / Approach

实际远端预算属于已有 SSH evidence owner,不能由调用者的 remote_evidence 意图代替。重试仍在当前 collector 内并复用原 scope fingerprint;时间戳抑制复用已持锁的 registry reducer 和实际 payload 相等判断。 两个既有生产边界的局部修复:有界上下文重收集和无变化 global registry 同步。没有新 provider、状态或 frontend 流程。 只增加无条件重试会重复 SSH 拨号并放宽权限竞态;只去掉时间戳也不能恢复真实新 Goal 注册。当前一组修复在同一已证实并发触发链上收口,不引入调度器、缓存或新的重试 framework。 正向路径从 collect_manager_turn_context / sync_project_registry_to_global 进入既有 owner,metadata touch 与新 Goal 两例均恢复;另一个真实 registry 例在 no-op 保持字节,随后改变 objective 仍发生真实写入;异常路径保留 既有 scope resolver/typed source grant 与 external_authorization_changed,六项反例按预期拒绝;既有 inline SSH suite 断言仅一次 dial/collection,权限拒绝不进入模型。本次完整审查当前 head,没有继承先前模板审查的通过结论。

具体改动 / Changes

4 paths +155/-3;两个生产文件的小分支调整,两份现有测试增加竞态/无变化写入回归并同步既有 endpoint 错误文案。 Core/source grants 决定谁能看哪些 Goal;collector 只重读合法当前来源,SSH owner 保留拨号预算;global registry reducer 判断实际内容变化。 无新 schema、闭集状态、Actor 生命周期或授权 vocabulary;时间戳仍为既有 observation 字段,不创建第二份 progress。

关键代码讲解

  • collect_manager_turn_context:收集并校验一次 manager Turn 的当前证据。 实际 grants 才占用 inline remote budget;绑定 Steward 可在旧身份不变时按当前授权重收集一次。 输入为当前 session、scope resolver、registry/runtime,关键条件是最多两次本地收集;旧 Goal 必须全部存在且身份 fingerprint 不变;SSH 不重复读取。scope/instance 改变和第二次竞态返回 external_authorization_changed

  • merge_goal_entries:合并已有 Goal 路由与内容。 除 synced_at 外完全相同才保留旧 synced_at。 输入为existing and incoming Goal entries,关键条件是真正 objective/route/metadata 改变仍产生不同 payload;collision/replacement 规则保持。原冲突与写入拒绝不变

  • _merge_global_registry_payload:组装持锁 reducer 的目标 payload。 除 updated_at 外完全相同才保留原 updated_at,既有写入比较才可判断 no-op。 输入为完整 existing/merged project/Goal payload,关键条件是不丢 concurrent update,不把内容变更当作时间戳变化。原 writer/locking recovery owner

规格为 docs/reference/protocols/manager-evidence-and-continuity-v0.md,spec_revision 867615e2c3aa2a32516a71d46f11a20d6fcb3289;Global conversation initialization、A bounded portfolio with explicit coverage 和 One service, scoped continuity 要求读取当前授权来源、声明覆盖,并在来源竞态中有界恢复而不扩大权限。

  • Global conversation initialization:implemented。每轮从当前授权 registry 读取并绑定正确 Goal 身份;chat prose 不成为 inventory。 对应 collect_manager_turn_context;base/head concurrent registry probe + six scope cases。
  • A bounded portfolio with explicit coverage:implemented。来源变化可有界重读,真正权限/身份变化不能被假装为普通 metadata。 对应 manager_authorization_scope_id_for_registry;replacement/revocation/continued-churn cases。
  • One service, scoped continuity:implemented。复用原 scope/authority;远端 budget 不因本地重收集而重新开始。 对应 inline_remote guard + existing SSH evidence owner;66 manager/registry tests including inline SSH single-dial refusal。

对主干的风险 / Risks

最强风险是为了修复过度阻塞而把真实撤销/换实例当成 metadata,或在重复收集时重置远端拨号预算。 为区分修复与无效测试,我对不可变 base/head 执行相同输入:base 三项实际回归均失败:本地竞态不恢复、无变化同步仍写入;head 三项均通过;六项 scope 对照符合预期,66 + 92 tests passed。仅验证新增 Goal 的 happy path 会漏掉身份替换。我额外执行了新增+替换、撤销、非绑定新增和持续抖动;它们均不能借这个恢复分支取得上下文。 全局 all_registered 覆盖来自既有绑定/source-grant owner;我同时验证非绑定新增不扩权,旧 instance 可变字段不能逃逸,正常授权新增重读后得到实际可用证据。

  • PASSED:same current production regression cases base/head — PASS:base3失败、head3通过
  • PASSED:66 manager/registry tests + six extra scope cases — PASS:相反方向拒绝保持
  • PASSED:pytest tests/test_native_steward_turn_host.py tests/test_antigravity_steward_adapter.py — PASS:92 passed,synthetic native peers/transport,不调用真实模型
  • PASSED:python -m py_compile loopx/chat_manager_context.py loopx/global_registry.py; full changed-line review — PASS:编译通过;whitespace 诊断单独披露为非阻塞清理

语义与 CI 对齐

沿用现有 typed conversation_scope/source_grants 与 canonical identity。没有用 prose substring 判断权限,没有新增 claimed lifecycle。 无 SSH grants、非绑定 scope、缺失/撤销 source 和已配置 SSH 的反方向均验证;未配置远端时不启动 SSH,原 restricted profile 与 authority 默认不变。 独立证据覆盖当前 changed invariant;远端 CI 的其他状态与合并 readiness 另行保留,没有把检查颜色当作正确性证明。 source collector、typed runtime、真实临时 registry 与宿主测试路径已执行;测试通过注入一次并发写制造竞态,SSH 只用失败 runner,未访问用户主机或真实模型。未宣称安装 App 或真实外网 SSH 资格。 非阻塞清理:git diff --check 报告两份新增测试末尾多余空行,建议顺手清理;没有把该诊断记为通过,合并 readiness 仍应独立执行。

我的整体评价 / Verdict

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

APPROVE:当前完整 diff 在所声明边界内达到 goal_achieved;long_horizon 为 preserved,保留真实权限、scope 和单次远端预算;本地竞态可恢复,减少一次人为重问,但没有声称长程任务效果或端到端性能已经测量。 user_experience 为 improved,零 SSH grant 的授权 Steward 可从常见刷新竞态恢复到可用上下文,旧身份/撤销等错误继续明确拒绝。 检查了既有 Steward prepare-turn 与 Chat 错误回读 owner;未改 UI 布局/入口/设置,visual_review not_applicable。 实际远端预算属于已有 SSH evidence owner,不能由调用者的 remote_evidence 意图代替。重试仍在当前 collector 内并复用原 scope fingerprint;时间戳抑制复用已持锁的 registry reducer 和实际 payload 相等判断。 两个既有生产边界的局部修复:有界上下文重收集和无变化 global registry 同步。没有新 provider、状态或 frontend 流程。 已把意图布尔值改为实际 grants 判断,并在既有 reducer 消除无内容写入;没有增加重复恢复 helper。更广泛 registry/host 重构不属于当前竞态修复。 不把本次 review 当作合并授权。

English verdict: APPROVE — 57631282a9dd2fab2477a628b8566f6901589e6b; the bounded local retry recovers harmless registry races without relaxing identity, revocation or SSH-budget checks; unchanged registry syncs preserve bytes. 66 manager/registry tests + 92 native-host/Antigravity tests + base/head race probes + six scope counterfactuals pass.

@huangruiteng
huangruiteng merged commit 4250a94 into main Nov 2, 2026
26 of 37 checks passed
@huangruiteng
huangruiteng deleted the codex/steward-auth-scope-fix-20261102 branch November 2, 2026 17:30
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.

2 participants