fix(collaboration): recover return verification without prose classifiers - #5253
Conversation
…iers Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
详细中文评审:PR #5253,完整 reviewed head 93bf4cb04e551c1e0fbcafd9a6043427c485db26,基线 da5aac12e1602bef9d572cef6e6cfe9a60205f9f,当前八文件 diff 为 +136/-54。
动机
这次修复的是已经被 provider 接受的回复无法继续核验:旧 Python 分支仅凭异常里出现 route、authorization 或 initial reply,就写成永久 explicit_unverified。我在两个真实 File 路径都复现了这个错误;重启也不会再核验该回复。当前改动符合 R3 路线 和 异步收件箱 RFC:恢复原受众的既有结果,避免用户再次提问或重复发送。它是完整、可回滚的持久化恢复增量,未关闭 GQ09 的完整线上旅程。
改动思路
继续使用既有 ReturnService -> drain,收件箱、原 Chat 回执、实时授权和 provider accepted attempt 各自保留原 owner。Python 只把可信的 typed resolution failure 交给既有 TS classifier;删除 Python 原因集合、关键词兼容和任意 .reason 属性判断。既有 File writer、定位信息、退避、幂等消息以及 source-session admission/GoalRef 生命周期继续负责 IO 与恢复,没有增加队列、协议版本、配置入口或第二份状态真相。
正向路径中,先保存 accepted attempt,之后遇到普通回读异常保留它;立即再次 pump 不重复回读,退避后读取同一条 provider 消息,更新同一条原会话回复。Goal A 重建成 B 后,旧回复仍使用原 A 的 GoalRef;新 B 请求也能独立送达。预 admission 的授权或路由拒绝先挡住 provider 效果,恢复现有 owner 的真实授权后可以继续;这与 verifier 报告 typed 永久失败后终止是不同阶段,不能把送达状态当成 Goal 或委托工作完成。
具体改动
生产代码增加 26、删除 36 行,主要删掉重复规则。TS 增加三个已有 exact reason 的处理,严格布尔校验、完成回读才能证明送达、真实 mismatch 的处理均保留。Python 的 missing/ambiguous route、原会话丢失、授权不匹配和初始回执未完成改成明确 typed cause。既有 Lark adapter 已使用同一个异常接口,未知异常文字继续只是诊断信息。
测试同时覆盖 transient 的关键词误判、三个 typed terminal 原因、locator 缺失,以及保存 attempt 后崩溃并重建 Goal 的恢复、退避和原 GoalRef。RFC/README 披露默认语义变化和当前边界。两处生成 census 的修改仅更新 roundtrip/CLI 的真实源码行号,没有改扫描根、规则或分类。
关键代码讲解
ReturnResolutionBlocked通过当前 TS classifier 验证 reason,不再维护 Python reason set;现有 ValueError/RuntimeError 接口保持。_verification_exception_error只读取这个异常类型的 reason,四个 exact/legacy 错误入口共享同一判定,普通异常或恰好叫 reason 的属性不能制造永久失败。classifyManagerReturnVerification仅在未完成核验时接受三个 exact resolution code;null、对象、前缀及相似文字仍保持不确定,成功和实际 mismatch 规则保持原样。_route保留原会话/GoalRef 的可信路由核对,给出 typed cause,不能按 Goal alias 猜一个新受众。drain继续分派既有 legacy/exact 路径。保存过的 provider 写入只做核验,原 admission、grant、初始回执、幂等和退避边界仍先于外部效果。
对主干的风险
独立执行的当前 Python 组合为 109 passed;TS classifier 3 passed,control-plane typecheck、Ruff、配置的 mypy 19 文件、diff hygiene 和三份 commit 的 DCO 均通过。真实隔离 Chat HTTP server smoke 通过,实际 late-return consumer 在 base/head 都通过。还运行了相同输入的 20 组 legacy + 13 组 source-session File 回放:两个基线矩阵各有四个独立 oracle 反例,head 均通过;不变的 25 组完整 consumer 事实一致。另验证了发送后初始回执失效会停止核验。每条原结果只发送一次、只出现一条 transcript,原 Turn/GoalRef 保持,provider 私有字段和异常文字不进入公开回读。缺失 locator、typed terminal、scope escape、授权恢复、新 B 请求和 2001 条无关路由均有实际负向证据。
仍有一个独立的质量 HOLD:personal-workspace-contract.test.mjs:359 在 base/head 同样失败,正则要求 workspace_ref: "current" 直接出现在 workspace-action-form.tsx,而未改动的表单已委托给同样未改动的 goalCreateRequest helper,字段在那里。断言、表单、helper 和受影响 return consumer/badge 在两边字节一致;当前 PR 不改变 Goal 创建。该必需失败保持原样,严格质量回执不通过,不能用代码评审 APPROVE 代替合并门禁。census 的基线失败已由本次 source-position 更新修复,当前 head 的九个 architecture case 全部通过。
语义与 CI 对齐
本次复用已有 return status、failure code、attempt v0 和 GoalRef 语义,明确改变旧 prose 默认行为,没有新增 actor 生命周期或外部授权。无 default-off/opt-in 声明;既有 private path 的 provider 调用为零。没有查看、轮询或等待远端 CI。五次 warm File 首次失败 drain 的中位数为 base 47.93 ms、head 53.37 ms;普通 send-error/read-error 序列增加两个 classifier crossing,每次 compact 参数 82 字节。这些是有界本地观测,未证明持续运行或真实 provider 延迟,也没有放宽预算。
我的整体评价
代码评审 APPROVE,maintainer merge 继续 HOLD。 这次同时改善持续推进和用户体验:短暂回读故障可以恢复原结果,重建 Goal 不改变原承诺,新请求不被旧不确定状态拦住,用户不用重新提问。未来维护也更直接:共享 reason 规则已收束到 TS owner,原持久化格式和真实 IO/lifecycle seam 保留。完整 GQ09、真实 provider 可用性和长期性能仍交给既有 R3/App owner 验收;未把局部恢复、测试数或 receipt 当成全局完成。重新取得合并资格前,需要现有 workspace contract owner 修复其陈旧位置断言,并对修复后的最新 exact head 重新评审,取得通过的严格质量回执及 native readiness。没有 self-merge。
English verdict: APPROVE - 93bf4cb; independently verified accepted-write recovery without resend on both File profiles and original GoalRef after recreation, with 109 Python tests, 3 TS tests and real isolated Chat/consumer evidence. Strict quality/merge remains HOLD for an independently reproduced unchanged workspace source-location assertion; remote CI was not consulted. Live provider and full GQ09 remain outside this slice.
|
Frame-aligned conclusion for PR #5253 at I judged the change against the overall roadmap R3, async-inbox RFC persisted-recovery acceptance, and the GQ09 journey.
当前交付边界是恢复原会话的持久化回复;未把局部送达或回执视为全局 Goal 完成。完整双语评审给出了 109 个 Python 测试、3 个 TS 测试、33 组独立回放和 baseline failure attribution。 |
Problem and result
A temporary return-verification failure mentioning a route, authorization or the initial reply could permanently strand an already-sent result. Use the existing TypeScript classifier for exact typed resolution reasons; remove the Python substring classifier and duplicate reason list. Unknown failures retain the provider locator and backoff, then verify the same reply without another send or model turn. Explicit revoked authority, lost routes and missing initial receipts still stop recovery.
This now integrates the merged GoalRef continuity work (#5106). With
source_session_v1, a crash-persisted reply from a retired Goal instance recovers through its original conversation even when the first verification fails temporarily. The replacement Goal cannot take over that reply. The profile remains opt-in; existing permissions and default activation are unchanged.This is an R3/GQ09 recovery slice. Python retains File I/O and transport orchestration; the existing TS boundary owns classification. App and Lark reuse that owner. No new provider, queue, configuration or frontend controls are added. The existing App receipt component already renders the resulting states; complete live owner selection, adopted steering and native execution remain separate acceptance work.
Validation
Final head:
93bf4cb04e551c1e0fbcafd9a6043427c485db26; integrated main:da5aac12e1602bef9d572cef6e6cfe9a60205f9f.The related refactor removes duplicate classification, without introducing another state owner. The complete final-head premerge rerun passed all 14 catalog/risk canaries, the public-boundary scan, diff and compile checks. The initial run failed during host disk exhaustion and lost its JSON; both affected smokes and then the full set were rerun unchanged after regenerable cache cleanup. No timeout, skip or gate relaxation was used.
Hold: final-head remote builds and
chat-bundlestill failpersonal-workspace-contract.test.mjsat the Create Goal workspace assertion. This same failure was independently reproduced from an archive of baseda5aac12e. The assertion expectsworkspace_refin the form after extraction intogoalCreateRequest, which still sets it tocurrent. Downstream skipped lanes are not passes. Exact-scope quality receiptcqr_2db3bee0ce10816684d2retains this required CI failure; correct the assertion with behavioral request coverage and rerun packaged qualification before merge. Maintainer review and installed-App verification remain open.