Skip to content

fix(chat): preserve project identity in source scope resolution - #6905

Merged
huangruiteng merged 1 commit into
mainfrom
codex/project-recipient-source-20261020
Oct 19, 2026
Merged

huangruiteng merged 1 commit into
mainfrom
codex/project-recipient-source-20261020

Conversation

@loopx-agent

Copy link
Copy Markdown
Collaborator

A recovered project Session could fall back to a legacy manager scope when its channel, Goal or project context was inconsistent, allowing a context handoff to a registered Agent. The shared TypeScript owner now keeps explicit project identity within its existing boundary and returns unavailable before Inbox or return-route publication.

Both existing Python observation adapters preserve missing fields. Older manager calls without a Goal remain distinct from the explicit goal_id: null used by project Sessions. Exact project/steward bindings and normal Goal/manager scopes retain their behavior. This reuses the current classifier and publication owners; it adds no recipient protocol, queue or configuration.

Validation at 6e34ea6db9a821cf7b8e56dddb41a2afbc22e70f, base 242821068d6339ae7fd071798e49a9b0c5dd1e19:

  • Counterfactuals use disposable stored Sessions and separate Chat/coordination roots. The original production code fails six publication refusals; an incomplete candidate still fails four missing/null-context cases. Final coverage verifies ten refusals, no Inbox/route JSON changes, unchanged source Session/Turn, and the legacy missing-Goal positive case. Existing compatibility assertions were retained.
  • 175 source tests pass, covering actual context publication/return, manager evidence, ordinary-project HTTP, bindings and native steward. 100 tests pass in a fresh installed wheel outside every checkout; all 469 imported LoopX modules come from that wheel, and changed runtime assets match source hashes.
  • 64 shared TypeScript tests pass, along with dashboard typecheck, verified Chat bundle build, Ruff and all 17 configured strict-mypy targets. The final amend changes Python IO only; the tested TypeScript tree is unchanged.
  • The exact-head standard premerge passes all direct checks and ten selected canaries. A first attempt lacked root TypeScript development dependencies; the prescribed root install restored that check. The earlier failed compatibility candidate and setup-command failures remain recorded; no timeout, budget or gate was relaxed.

The change-quality receipt verifies this exact scope. The small related refactoring pass retains the single typed owner and removes null fabrication at the two existing IO boundaries; no additional abstraction is needed. All evidence is synthetic backend/package validation. This proposal is ready for independent review; live installation and the wider project-recipient/adoption/return journey remain separate acceptance.

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; model=gpt-6.1-sol; provider=OpenAI; declaration_source=runtime_reported; reasoning_effort=max

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

APPROVE — 本头完整五路径审阅及真实投递对照未发现阻塞项。 精确头为 6e34ea6db9a821cf7b8e56dddb41a2afbc22e70f;同一来源异常用例在基线错误放行,在当前头投递前拒绝。正常管家/Goal/项目与绑定来源另有阳性对照,未仅凭变得更严格就批准。

动机

在普通项目对话里工作、并通过现有入口向某个 Goal 传递上下文的用户,需要项目来源异常时仍受原来的范围限制。 例如一个恢复的项目会话保留项目身份,却错误带上 manager 频道;旧代码能把它当作管家并投递到项目范围外,本次在共享来源分类处拒绝这个不一致身份。 同一组真实本地存储与投递用例在不可变基线有10个错误放行和1个缺失/null混淆;本头全部通过,并确认拒绝发生在 Inbox、返回路由或原会话写入之前,正常项目和旧管家路径仍可用。 本次不增加项目权限、上下文目标、执行授权或新界面,不认证真实外部服务、模型效果和生产安装。

问题来自同一个恢复会话同时带着“项目来源”与不相符的频道/Goal。用户原本只在一个项目内交流,不应因 Host 恢复元数据不一致就变成更广范围的管家请求;反过来,合法旧管家缺少一个历史字段也不能被这次修复误伤。修复在已有分类与投递入口内完成,正常用户无需重新声明身份、补填项目信息或增加授权确认,未知身份则沿已有来源错误处理。

改动思路

来源分类继续由既有 TypeScript owner 决定;两个 Python 观察适配器只保留字段真实存在性。 当前 PR 只修复项目身份不一致时的错误扩大范围,保留合法管家、Goal、项目与已绑定来源的既有路径。

既有 resolveConversationScope 已集中决定普通项目、私人 Goal、管家与外部来源属于哪一种范围。本次在原项目分支失败处直接返回 unavailable,再拦住不能匹配类型身份的项目元数据;合法 bound steward 仍由其完整精确身份判断。两个 Python 适配器保留 Session 真正包含的字段,不通过 .get 把“旧数据没有 Goal 字段”变成“明确声明是 Goal-less 项目”。这些都是现有授权边界的输入准确性,不需要新 flag、版本分支、permission store 或第二个 Python 分类函数。

原始来源 本头结果
完整匹配的普通项目 保留 workspace 范围
项目 null / context 与 manager 或 Goal 频道冲突 unavailable,投递前拒绝
真正旧管家,未保存 goal_id 字段 保留原管家路径
合法 Goal / bound owner / steward 保留原当前来源与 grant 检查

具体改动

不可变代码 merge base 为 242821068d6339ae7fd071798e49a9b0c5dd1e19,完整差异 5路径 +98/-4。产品部分是共享 TypeScript scope 与两个薄观察适配器;其余是 typed 范围矩阵以及真实存储的投递回归。没有新增 UI、配置或调用者能力,原 Chat、项目及管家工具是现成 shipped entrypoints,本次修复会由这些入口直接采用。

关键代码讲解

  • resolveConversationScope:显式 goal_id:null 只有完整匹配的项目身份可用;不匹配即 unavailable,声明项目元数据也不能退回普通 manager/Goal 身份。
  • conversation_scope:只传递 Session 实际存在的字段,保留历史缺失 goal_id 与明确 null 的差别,不在适配器重做分类。
  • _source_context_grant:观察原来源/ingress 并将字段存在性原样交给共享 source-context owner;当前 target grant 仍在原写入前检查。

规格在实现前读取:spec_ref=docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md#ordinary-workspace-conversations-bounded-implementation-checkpoint,spec_revision=d4bb60c98c01ab840c5f971e3ca06e778b94a129。这是最新已接受的主干规格来源,与代码 counterfactual 的较早 merge base 分开记录。映射 ordinary-project-scope、source-change-fails-closed、shared-typed-owner、no-peer-execution-grant 均 implemented:项目身份不能退成 portfolio,当前来源变化需拒绝,TS 保持唯一范围 owner,交接上下文不授予执行权。本 PR未改这份规格,也没有用新测试文案替代原范围要求。

实际调用还经过原 manager_context.deliver、Goal lifetime 和 source-context target grant:先做规范来源观察与当前目标授权,然后才创建 Inbox 与原请求返回路由。因此只修一个展示 kind 并不足够,本轮沿完整投递入口验证了拒绝前后持久文件与 Session/Turn 不变。

对主干的风险

最强反例是项目来源依旧经另一适配器拿到广域 grant,或合法管家在“更严格”的修复下全部不可用。源码检查确认两个 Python入口都交给同一 TS owner,既有 source_context_authority 和 target-in-grant 检查在任何投递写入之前。项目上下文的稳定归属复用既有 typed project/steward context,而不是通过频道子串猜权限;未增加状态机枚举或并行兼容决策。

独立同输入对照从不可变 242821068d6339ae7fd071798e49a9b0c5dd1e19 导出生产源码,用当前未改动的11个回归用例运行;281个已导入 LoopX 模块全部验证来自 baseline。结果10个恢复项目 local/bound-owner 漂移用例均为 DID NOT RAISE,即错误允许真实投递;另1个明确 null 被错分为 owner_portfolio。当前头同组全通过:分别覆盖改频道、改 Goal、非法/缺失/null context,并断言拒绝前后 Inbox、roundtrip、原 Session 与 Turn 字节不变。基线夹具首次准备遗漏非跟踪 uv.lock、在运行生产代码前即停止;移除错误归档条目后才得到上述真正的反例,未修改产品或测试 oracle。

本头源码 197 Python passed,覆盖 roundtrip、管家跟踪、项目/普通项目、会话绑定及 native/bound-owner;另 44 TypeScript passed,包括现有 source grants 与 conversation bindings。缺失历史字段的合法旧管家仍可分类,明确 null 的不一致项目被拒绝;正常来源恢复/投递路径仍通过,没有声称靠手工改源数据实现恢复。typecheck、3路径 Ruff、唯一 commit 的 DCO 通过。

标准 premerge 初次有1项失败,直接诊断为该独立 worktree 未安装 TypeScript dev dependency,不是本次词汇/权限行为回归;按仓库说明 npm ci --ignore-scripts 后,以完全未改动的产品源码重跑整个 standard gate:6 direct +2 catalog +8 risk 全通过,无 manual hold。初次失败保留,不放宽测试或预算。没有查询、轮询或等待 CI;也没有仅拿初次其它绿色检查覆盖这项环境缺口。

本轮验证的是实际本地存储、原 effect runtime、来源 grant 与投递代码;外部来源/模型用隔离夹具,未向真实服务写消息。未要求无关前端扩展、全量语言迁移或新权限模式;合法源的配置、持久 Session/receipt 格式和默认调度均保持。部署后若 Host 真有不一致来源,应由原 Host/source owner 恢复完整身份,不能以猜测频道或放宽 grant 继续。

我的整体评价

APPROVE / goal_achieved,限于这一个项目身份错误扩大范围的修复。来源分类继续由既有 TypeScript owner 决定;两个 Python 观察适配器只保留字段真实存在性。 当前 PR 只修复项目身份不一致时的错误扩大范围,保留合法管家、Goal、项目与已绑定来源的既有路径。 long_horizon=preserved:恢复来源不会在后续交接时扩大身份,原合法会话仍可继续;user_experience=improved:正常用户无需重述已知项目或多一次确认,异常来源也不会悄悄投递到更广域。

保留历史字段缺失/null 区分有真实存储消费者和阳性/阴性对照,成本仅两个薄观察适配器,没有新的 request decoder或双重 policy。这个范围已经能通过现有真实产品入口使用,不是只有 helper 或 mock 的准备工作。本头没有当前必需验证缺口;合并仍需另外的当前 readiness 与维护者授权,本轮没有 merge、dismiss 或本机升级。

English verdict: APPROVE — 6e34ea6db9a821cf7b8e56dddb41a2afbc22e70f fixes inconsistent recovered project identity without widening or overblocking valid existing sources. The same11-case oracle fails on immutable base (10 incorrect delivery admissions and1 explicit-null portfolio classification) and passes at head;281 baseline production modules are verified.197 Python and44 TypeScript checks, typecheck,3-path Ruff, DCO and the complete recovered standard premerge pass. The first gate failure was missing local TypeScript dependencies, diagnosed and recovered without product changes. No live provider/model, production installation, merge action or CI wait is claimed.

@huangruiteng
huangruiteng merged commit 5254898 into main Oct 19, 2026
33 of 40 checks passed
@huangruiteng
huangruiteng deleted the codex/project-recipient-source-20261020 branch October 19, 2026 18:49
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