Repository navigation
fix(chat): reject ambiguous calendar task completion readback - #7559
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; OpenAI gpt-6.1-sol; runtime_reported; reasoning_effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
动机 / Motivation
使用原 managed Session 重复已有任务的用户及其日历确认调用者。
原任务已执行并有正文,但消息日志损坏或 native 结果冲突时,旧读取仍报告已确认;修复后保留未确认窗口,原记录恢复后才继续。
损坏或冲突不再被误认作完整结果,正常结果仍能在重启后确认并进入下一独立周期。
本次仅修结果读回,不完成自然语言配置、完整任务前端、外部消息发送或真实模型与自然到期验收。
通用周期任务的完整前端与真实模型验收,以及原有日报启动前拒绝后的恢复问题仍未完成。
改动思路 / Approach
原生提交指既有 Turn 的持久结算事实,完成回执则还要确认原 Chat 回复完整可读。这里只在已有 _completion 适配器收敛两项证据:结果事件必须唯一且完整匹配原 response;原消息使用已存在的严格 reader。原 TS 准入、Task 验证和日历存储均保持原 owner。
继续使用原确认适配器及已有严格消息读取,确认由原记录推导;无需新增状态或另设执行策略。
只改变 SessionCalendarTasks 的完成读回和对应回归、文档,保持原日历、Task、Turn 与设置事务。
| 原记录 | 旧行为 | 当前精确头 |
|---|---|---|
| 坏 JSON / 非对象消息 | 跳过后误报已确认 | 保留未知,原 clear preview 拒绝 |
| 重复 / 冲突结果 | 任意 committed 即可 | 要求一条完整匹配结果 |
| 完整原记录 | 可以确认 | 冷重启同结果确认,后续独立周期正常 |
这个比较表来自同一合成数据的真实存储/HTTP 路径,不是生产自然到期或真实模型的证据。严格读取可能因其他坏行而保持等待;完整原回复无法证实时,这比制造成功事实更符合现有合同。没有增加确认轮次或日志自动修复。
具体改动 / Changes
规格依据:docs/product/periodic-reports.md,改动前 revision f205c02a37d5a668c956733a721af911dcac7fab。其未编号的合同按以下名称映射:original-result-readback、unknown-no-replay、independent-next-period 已在本切片实现;full-product-journey 继续由既有周期任务产品工作负责,不能从本次测试推断完成。
关键代码讲解
- SessionCalendarTasks._completion:保留原 Task、actor、window、subscription 与 commit 校验;把结果事件收集后与唯一原 response 完整比较,再严格读取同一 message_id 的原回复。任何缺失、不匹配或读取失败都不给确认回执。
- SessionCalendarTasks.frontier:调用者未改,继续在原 cadence journal 写同一完成回执;新回归证明恢复时没有新增模型调用,下一独立周期仍能产出新结果。
- session_report_configuration_guard:原设置事务通过
_published_window共享这个读回。未知结果的 clear preview 返回400,原配置和原窗口保持;不是把未知取消成成功或重新运行。
三文件共生产 +6/-3、回归 +75、文档 +9。新增测试在 File/SQLite 上实际写坏消息或追加冲突事件,核原日志/Task/Turn/config 不变,再恢复仅测试夹具的原字节,冷重启确认同一回复并执行下一天的新周期。
对主干的风险 / Risks
本次没有改变 schema、actor、受众、来源准入、配额或业务重放资格。默认未配置、暂停、普通/attached 会话不进入此确认路径;原 calendar 的错误 scope、归档引用、忙会话和下一周期用例继续通过。代价是坏日志可能明确阻塞这个窗口,解除条件仍是原证据可读,不是单改一个状态标志。
验证:精确 head 的10项定向回归 PASS;旧基线 4659bc38f0bde2e1aba405779ede6706bed2d43c 的同一测试为8项误确认 FAIL、2项健康对照 PASS。rebase 到 f205c02a37d5a668c956733a721af911dcac7fab 没有更改 LoopX 生产源或这些测试字节。最终 standard premerge 的6项直接、11项选中检查及 Ruff/公开边界 PASS;Goal 的 CQR disabled,如实保留。
扩大回归为 177 PASS / 4 FAIL,不报告全绿。四个 test_original_pump_resumes_exact_prelaunch_rejection_once_without_replaying_unknown_work 在完整 immutable base f205c02a37d5a668c956733a721af911dcac7fab 与 head 上均为同一四个 File/SQLite case、line1096 的 IndexError,根拒绝均为 report launch recovery is not proven safe by the original native rejection。两个被动诊断运行均记录本次 _completion 调用0次,四个相关原 owner 文件逐字相同,按当前矩阵归为 pre_existing_unrelated。该已有 report 启动恢复问题仍需原 owner 修复,不由本 PR 宣称解决。
语义与 CI 对齐
沿用已有 Task/Turn/Chat/cadence 术语与 owner,没有新增权威词汇。改变的是原不充分证据的误确认;这是既有合同要求的修复。wait_for_ci=false,没有读取、轮询或等待 CI;这不把本地失败变成通过,也不授予 merge 或安装权限。
我的整体评价 / Verdict
未发现本次精确头的阻塞性问题。problem_context=justified_increment;long_horizon 与 user_experience 均 improved:未知结果可见地保留,原证据恢复后继续同结果和后续周期,零新增用户准备/确认步骤。repository_reuse=reused、observable_semantics=intentional_change_validated、code_volume=necessary、change_proportionality=proportionate、default_off_isolation=isolated、authority_semantics=aligned、semantic_alignment=aligned。
继续使用原确认适配器及已有严格消息读取,确认由原记录推导;无需新增状态或另设执行策略。
只改变 SessionCalendarTasks 的完成读回和对应回归、文档,保持原日历、Task、Turn 与设置事务。
检查三文件 diff,未修改任何渲染或交互代码;本次只改变原设置 API 和完成读回,不适用视觉审查。
完整周期任务前端、安装 App 及真实模型理解不在本次合成证据范围。
原事件 reader 仍沿用已有存储实现,本审查没有资格化通用日志修复、所有损坏组合或无限期活性。四项既有启动恢复失败和父级产品缺口继续开放;APPROVE 仅针对这项有用、可独立回退的读取修复,合并/安装还需原授权及 fresh readiness。
English verdict: APPROVE d6a2a42; exact completion-readback regressions pass on File/SQLite. Four unchanged prelaunch-recovery failures remain explicitly open and were reproduced on the immutable base; full product and live-model acceptance are not claimed.
Calendar tasks could report a verified completion after skipping a damaged message-journal record, or after finding one committed result among duplicate or conflicting native results. That could acknowledge an unconfirmed period and allow its settings to be cleared.
Require one complete native result matching the stored Turn response, and use the existing strict Chat message reader before acknowledging the original reply. An uncertain return retains its window and configuration. After the original records become readable and unambiguous, restart reconciliation acknowledges the same result without rerunning that task; a later independent period can still execute.
Validation:
test_original_pump_resumes_exact_prelaunch_rejection_once_without_replaying_unknown_workcases fail identically on immutable basef205c02a37d5a668c956733a721af911dcac7faband this head: the unchanged report-launch admission refuses recovery, followed by an empty pump result at line 1096. Instrumented base/head runs record zero calls to the changed completion method. This pre-existing report recovery gap remains open; the suite is not reported as fully passing.The change stays in the existing Python Chat IO adapter and adds no schema or scheduling policy. The tests use real native File/SQLite, HTTP settings and cold restart with a synthetic host; live-model understanding, production deadlines and the full recurring-task frontend remain outside this evidence.