Skip to content

fix(lark): return timed-out private conversation results - #5607

Merged
huangruiteng merged 1 commit into
mainfrom
codex/native-private-timeout-recovery-20261005
Oct 5, 2026
Merged

huangruiteng merged 1 commit into
mainfrom
codex/native-private-timeout-recovery-20261005

Conversation

@loopx-agent

@loopx-agent loopx-agent commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

When a native private Turn times out, Core records timed_out but the Lark adapter leaves its result pending indefinitely. Ordinary replies and commission first-round results now use the existing Chat terminal-state owner and return an actionable timeout message in the original conversation. Provider readback continues to gate delivery; restart/redelivery reconcile the saved attempt without another model execution or send.

Placement: this is a bundled Lark transport correction within native-chat. The bounded refactor removes two copied terminal classifications; it adds no state owner, scheduler, permission, or runner. Readiness remains tied to the existing real-time conversation/RFC acceptance, with live-provider recovery required at the switch gate.

Validation:

  • 35 related tests passed. Three added cases fail against the unchanged main provider and pass with this fix. Ordinary idle/hard deadlines run through native Core; the commission case injects a typed host timeout after activation and does not qualify a live Goal deadline.
  • Ruff and focused Mypy passed; semantic advisory reports no new vocabulary. Exact-scope native premerge passed 5 direct and 11 selected checks, with one inherited maintainability advisory in goal_topic_runtime.py (outside this diff).
  • Public-boundary scan and diff checks passed. A separate local source canary composed with the existing image/reaction implementation recovered an actual old idle-timeout result through the original Feishu route; web visibility and native provider-readback delivery were verified, original Sessions/threads/grants preserved. Combined regressions and frozen-source media/timeout tests passed. This is not a release or proof of live commission deadlines, full-repository Mypy, or sustained end-to-end latency. No live bindings, credentials, or private evidence are included.

Runtime change: proposed for maintainer review/merge; no self-merge or admin bypass.

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 | reasoning_effort=xhigh | declaration_source=runtime_reported | observation=98b47db0742b44f7bbc50fdc19057b889f0d2fb100d3787fbbd3e617a78de3d4

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

Exact reviewed head: 5607@c1ff443feb6c89982c9007dab6dcbf0383c2a0e0. Immutable base: 37b77d4aff1e1e9faa14487888c055c99482c43e.

动机

使用已配置 Bot 私聊的普通项目用户,以及明确确认新委托的管家用户。

用户在已授权的 Bot 私聊发起耗时工作。Core 已将原 Turn 记为 timed_out,旧适配器仍等待终态,原消息得不到结果;本修复在原私聊告知超时并保留状态和恢复命令,发送凭据未验证时只继续核验。

普通 idle/hard 超时与注入的委托首轮超时均返回原消息;重启和事件重投没有新模型请求或重复发送,超时事实不伪改为成功。

不新增授权、Goal 调度或生命周期;真实外部账户、安装版切换和真实委托 deadline 的资格仍留在既有 switch gate。

这是一项 justified_increment:解决当前适配器漏掉原生超时终态的具体问题;剩余缺口是安装版真实 provider 恢复和真实委托 deadline,由既有文档的切换验收继续承担,不能用本评审替代它。

改动思路

现有 Chat/Core 已经持久保存 Session、Turn 和终态,Lark 适配器应呈现它们。PR 删除两个独立终态集合,直接使用既有 TERMINAL_TURN_STATES,分别处理普通回复和已确认委托的首轮结果;原消息发送、凭据保存、回读、ACK 和恢复继续使用 _deliver 及既有 Inbox。Python 代码留在 bundled Lark provider 合理,这里只翻译 provider 的输入输出,没有新增通用决策源、权限或调度器。

不修会继续在超时后长期 pending;只修普通回复会遗留委托路径;增加自动重试模型会破坏既有不重放契约。当前同一 owner 的小修复比新增恢复机制更合适。

具体改动

整个 diff 是三文件 +113/-4:provider +7/-4、readiness 文档 +9,以及一个 97 行原生回归文件。没有新配置、CLI、receipt schema 或存储状态。文档明确合成 host/provider 的证据范围,并保留实际安装切换门。

关键代码讲解

  • loopx/extensions/lark/private_conversations.py:264:普通分支读取原 Session/Turn;缺失或非终态继续等待,timed_out 现在进入原消息结果发送并给出 /status,不会改成 completed。
  • loopx/extensions/lark/private_conversations.py:278:委托首轮也用同一终态 owner;超时文本保留原 Goal、resource ids 和 /resume-commission,没有另造执行或 Goal。
  • loopx/extensions/lark/private_conversations.py:195:复用未改的 _deliver。首次尝试先保存 started/locator;重启后 verify 同一个 attempt,未经验证不能 ACK,原消息与现有 binding 仍须重新校验。

规范依据:loopx/extensions/lark/docs/realtime-conversation-readiness.md,spec_revision=37b77d4aff1e1e9faa14487888c055c99482c43e,使用 PR 前的不可变文本判断,而不是新增文案自证。terminal-canonical-result 已实现(原 timed_out 保留);delivery-only-recovery 已实现(不可见回执仅恢复验证);original-source-and-session 已实现(原消息/受众/会话验证);installed-provider-switch 明确 deferred,由既有切换 owner 运行安装版真实账户/宿主旅程。

语义与 CI 对齐

这次 reuse_existing:原生终态 owner 是 completed/interrupted/timed_out/failed;旧适配器中的 expired 没有合法 producer,原生队列过期本来就保存为 timed_out/session_queue_expired。开发期 advisory 没发现支持的新词汇 carrier,全树 semantic smoke 通过;空 advisory 不代表完整语义证明。按本次策略未查询或等待 CI。

对主干的风险

最危险的反例是执行已超时后原消息受众或授权发生变化,以及回复已经发送但 provider 暂时无法读回。独立实际 Core/Inbox 测试验证:改原消息 chat id 或撤销 binding 后零发送;重新创建 binding 不接管旧请求;恢复同一个合法原消息后只验证已存 attempt。重启和 event_id 改变的重投没有第二次发送、第二个模型请求或新的 Session。原失败状态始终保留。

当前 head 22 项相关测试和 16 项状态/Agent companion 测试通过;隔离矩阵六项通过(含三项 deadline/commission 和三项独立 source/authority/ordinary control)。同一隔离 deadline 矩阵在 immutable base 的三项都因缺少超时结果失败;ordinary completed control 在 base/head 的完整归一化结果 SHA256 都是 dc6d9f3b57dba0bcabe779165edb920040d0b2f3080a980463d570d75740ae65。委托 case 在启动后注入 typed host timeout,不能证明真实 Goal deadline。

早期放在外部证据目录的探针没有加载 tests/conftest 的默认 runtime 隔离,因此委托停在准备阶段;另两处把内部 reconcile 计数和重建 binding id 当不变条件也是错误测试预期。已保留失败记录并补上原隔离 fixture,改验真正的发送次数、原资源、授权和模型请求,不把早期 setup 错误称为产品缺陷。

Canonical mypy19、Ruff、全树 semantic、diff/public-boundary 和 native exact-diff premerge 通过。五个 direct 检查通过;11 个 selected 执行,十个通过、一个 inherited maintainability advisory 仍失败:同 base/head 都是 module_metric_budget:loopx/extensions/lark/goal_topic_runtime.py,因果文件 blob 相同且 magnitude regression=0;保留该债务,不能宣称每个检查全绿。原生 change-quality 的严格 receipt 同样保留 fail / validator:inherited_ratchet;该独立合并资格失败不被本 APPROVE 覆盖。

先前 main 525bfa26f3e8c8981c7f6c65f06d1f6426d38297 的纯 merge tree 六项通过;收到相邻 #5634 实际合并的消息后,重新拉取 main 59eb5d5976663c1ea52d31d1a7299c1dda39595e,对其纯 merge tree c322b923bfdc0a3d3e4da8165e07c0612ba6ea52 再执行同一六项隔离探针,仍全部通过。两组组合不是已发布 commit 或安装版本。没有验证真实外部账户、产品切换、长期时延,也没有修改活跃配置/凭据。

我的整体评价

APPROVE。long_horizon 和 user_experience 都是 improved:原先终态仍无结果,现在可收到明确失败并用原会话继续恢复,发送验证不会引入重复工作。bounded future-facing pass 已应用:删除两个复制的终态规则;把普通/委托展示强行再抽成泛用层没有必要。完整生产增量仅七行新增,规范/验证与其直接相关,比例合适。

该结论只接受这项源代码修复;安装版 switch gate、真实 provider 恢复和真实委托 deadline 尚未验收,仍由现有维护者/发布流程处理。运行时 PR 交维护者整合;COMMENTED 是 GitHub 同账号限制下的完整批准结论,不是平台 formal APPROVED,也不赋予合并权限。

English verdict: APPROVE - 5607@c1ff443feb6c89982c9007dab6dcbf0383c2a0e0. Reuse the canonical terminal owner to return ordinary and commission timeout failures through the original source, with saved-attempt recovery and no resend/model replay. Source-level native/negative/base-head checks pass; live installed provider/deadline qualification and the inherited unrelated module advisory remain explicit.

@huangruiteng
huangruiteng merged commit 5ca7118 into main Oct 5, 2026
24 of 34 checks passed
@huangruiteng
huangruiteng deleted the codex/native-private-timeout-recovery-20261005 branch October 5, 2026 16:59
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