fix(collaboration): prepare return routes before publishing requests - #5234
Conversation
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
|
Validation for head
Author review checked unchanged authorization and immutable ingress identity, request-lock/route-lock ordering, inert route-only recovery, readback before receiver visibility, and once-only original-conversation return. The bounded future-facing pass reuses the peer publication ordering without adding a queue or decision owner. This qualifies a return-path defect, not native owner selection or complete multi-Agent acceptance. No deployment or merge performed; maintainer review remains required. #5106 should carry this invariant into its exact-GoalRef path during integration. |
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
English verdict: APPROVE - exact head 9e0925a44697907aebef4f1bdf04e35cfe1392b6, immutable base 440a19aab2b69dc23748bb734fa58f2a53e2872f. No blocking finding. The publication/return-preparation defect is reproduced on the base and fixed on this head; full native worker execution and A24 are not certified. This author-owned record is a COMMENTED review, not a formal GitHub self-approval or merge authorization.
动机
这个问题不是“测试少了一项”,而是接收方可能在请求刚发布、发送方还没拿到 receipt 时执行并返回结果,却找不到原会话的回程路由。回程存储失败也可能留下已经可见的工作。独立进程在发布瞬间读取并 report 的对照验证复现了旧问题,所以这是 R3/A8/A9 的实际可靠性增量;不是完整 A24 已完成。
改动思路
复用现有 register、Inbox 原子写入和锁,把路由准备及回读放在 entry 发布之前。请求身份、来源授权和冲突判断都保留;route-only 记录不代表已交办,entry 才是工作可见的边界。原始 session/client turn/channel 来自可信 Chat/provider 状态,不能从接收 Goal 或 source digest 猜一个返回目的地。这里没有新增手填声明、协议版本或 Python 决策源,TypeScript 仍拥有请求规范化与回程状态规则。
具体改动
关键代码讲解
deliver:入口先验证 source/recipient,再在现有 entry lock 内做 identity conflict 检查、register和 entry 写入。之前先发布 entry、后登记路由;现在路由写入或回读失败时,没有工作被发布。成功 receipt 的字段及“不改优先级、不创建 Todo、不打断执行”保持不变。register:路由锁内继续校验旧 identity,新增保存后对七个原有稳定字段的精确回读。不是只检查文件存在,也不会把空/错误路由当作成功。entry 写失败留下的准备记录可由同 identity 的 retry 完成,不产生第二份工作。report:未改动的真实结果消费者先读 exact entry/route,再经共享 Inbox 保存结果。发布瞬间的独立接收进程现在能走通这个入口;初始 receipt 完成后,原 App/Goal Chat transcript 经两次 fresh-store drain 只出现一次结论,不需要第二次模型 Turn。external 仍明确为 queued,测试没有发送真实群消息。
整份 diff 是生产代码 +9/-2、164 行聚焦测试及 12 行规范说明。活跃生产调用是 ChatRunner._run_turn 的 context_handoff;没有新 frontend 配置或 receipt 字段,所以无需配套 UI 改动。现有 Chat/Lark 消费测试已验证,实际打包部署和 live transport 不在本次验收内。
对主干的风险
重点检查了相反两个方向:路由不完整不能放行,但一个坏 route 也不能永久阻断同 Goal 的其他合法请求。route/entry IO 失败、lost ACK、错误目的地、缺失回读、exact retry、新请求、历史 route annotation、completed replay 均有覆盖。23 个无关记录超过 pending 页面上限、顺逆创建顺序及 later-page 读取,也没有改变 exact 请求的交付与回程。entry→route 的嵌套锁没有发现反向锁依赖,真实接收进程在发送方尚未返回时可以完成 report。
独立验证结果:
- 9 个现有/新增集成文件:129 passed,覆盖 Manager、Goal Chat、peer、Chat 和 Lark return 消费边界。
- 相同 30-case 发布/恢复 fixture:base 为 21 个预期 invariant failure、9 个合法 control passed;head 全部 30 passed。另有 6 个分页/顺序 control 在两边均通过。
- 14 个完整可观察结果对照:授权/关闭授权、正常输入、重复请求、历史 annotation、错误全文、拒绝优先级及全部持久 JSON 均一致;只归一化时间戳和合成 runtime 根路径。fixture fingerprint 为
2657adfccfd198d95c2983e258c4a082d4874a6f533683873661a1358cc5e736,base/head observation 均为9ed1b957d02107e5b0400443eb4cbb5fc7c83acbb3ed0508abe0864d77ec41c7。 - Ruff、2 个 typed return 测试、最终 premerge 的 5 个 direct + 9 个 catalog + 8 个 risk-profile + 1 个 public-boundary check 全通过,零失败/手动 hold。exact-scope 凭证
cqr_36738622d465f1f86d81已回读有效。初次 semantic scan 因独立 worktree 未安装 TypeScript 依赖失败,按仓库要求执行npm ci --ignore-scripts后,base/head 均通过。
语义与 CI 对齐
没有读取、轮询或等待远端 CI。以上结论来自 exact-head 本地验证;没有改预算或把环境失败归咎于 PR。此次是已有交付路径的默认 IO 顺序修复,不新增 opt-in;external policy 关闭时仍保持原拒绝、提示和无 entry/route 的状态。没有新增子串状态分类、领域特定义务或更宽的 actor/lease authority。RFC 将“发布前回读”写成强制不变量,也明确它不证明 native selection/execution/full A24。
我的整体评价
APPROVE,无阻塞发现。长期运行与用户体验在这个边界得到实际改善:可见工作能保留原会话的结果返回能力,失败后的同 identity 重试不新增请求;正常成功、关闭授权和历史读回契约保持完整对照一致。成本是 entry 写失败可能留一份 inert route,retry 可复用;没有后台执行或重复投递,全局清理仍由原生命周期边界承担。
future-facing pass 的结论是复用现有 publisher/route owner 即可,不加 manager/peer 参数化框架。历史格式仍需读回,不应为了删代码丢掉旧请求;也无需保留一个新的平行版本。#5106 的 GoalRef 集成必须把同样顺序和回读带入 exact 与 legacy 两条 persist_entry 分支,这不是本 PR 的阻塞项。完整 R3/A24、真实部署和 GoalRef migration 仍保留原验收边界;控制面代码留给维护者合并,本次不会自合并。
Frame-aligned conclusion —
|
Problem and result
A receiver could see a Chat handoff before its original-conversation return route existed. A route write failure or an immediate receiver response then left accepted work unable to return, even though the sender had already published it.
Prepare and verify the existing trusted route inside the request lock before publishing the inbox entry. Failed preparation exposes no work; an interrupted entry write can be retried with the same identity. App steward, Goal Chat and external-audience ingress share this path. Permissions, request identity, receiver planning and return-state transitions remain unchanged.
Validation and scope
Placement/future-facing review: this is filesystem IO ordering in the existing Python adapter; it follows the peer request's route-before-entry sequence and creates no second TypeScript state owner or new queue. Existing App/Lark renderers consume unchanged receipts and results, so no frontend bundle change is needed. The RFC records this R3 return-path invariant; native owner selection/execution and the complete A24 journey remain unqualified.
Integration note: #5106 changes these same persistence functions for GoalRef. Preserve route preparation before entry publication in both its legacy and exact-identity paths when integrating these changes.