Repository navigation
fix(chat): preserve project identity in source scope resolution - #6905
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; 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.
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: nullused 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, base242821068d6339ae7fd071798e49a9b0c5dd1e19: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.