Repository navigation
Conversation
Signed-off-by: duang777 <duangjl007@gmail.com>
cc9637f to
d9fa9a6
Compare
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; model=gpt-6.1-sol; provider=OpenAI; runtime_reported; reasoning_effort=max
阻塞发现:[P2] 已排队报告的发送路径仍绕过 Goal 停止状态。 在当前 head 的真实报告发送 owner 中,我分别设置“发送前已停止”和“第一条发送后停止”,两种情况都继续调用了两次发送命令并返回 satisfied。替代传输仅记录命令,没有发出真实消息。关闭订阅的对照组则在任何发送前拒绝。这个缺口基线也存在,属于本次停止授权链尚未闭合,不能描述成新引入的回归。
动机
已启用定期报告的 Goal 所有者,在暂停自动推进时需要同时停止报告工作。旧版即使已通过正式停止命令暂停 Goal,只要旧状态仍为 active,日历钩子仍会创建报告窗口;本提案能阻止这种新建工作,但已经生成并排队的报告仍能越过停止状态进入发送。应当让停止覆盖报告从排期到发送的整个授权链,恢复后继续原窗口,而不丢弃原有报告或让用户额外修改订阅。本次不新增日历、通知渠道或自动执行器,也不把停止等同于删除 Goal。
改动思路
入口是 quota/managed turn 共用的 extend_cadence_turn_start_dispatch。注册前先读取 Goal;构造后的钩子在日历日志锁内重新读取注册者、订阅和生命周期;待发投影再检查当前 standing delivery authority。这三处新增判断都调用既有 goal_is_stopped,没有创建另一份停止状态。复用 GoalActivationState 的停止事实及原有日历锁,比新增暂停状态或要求用户另关订阅更小;发送前的生效授权仍须由同一报告能力闭合。本 PR 应在现有 periodic-report 能力内闭合注册、锁内重查、待发投影和每次实际发送前的停止授权检查,保留停止前生成物和恢复后的原窗口。
独立基线/当前对照已经证明前半条链有效:正式 stop 后,基线仍注册并写一个窗口,当前 head 注册数为零;注册后再 stop 的钩子返回 empty 且不写日志;已经冻结的窗口在 stop 时不投影,resume 后恢复同一个窗口并进入 editorial_required。两个独立 Goal(含停止后新增的 Goal)仍正常排期,停止不会扩大为整个 registry 的全局封锁。但既有 Lark 发送 owner 只重新解析订阅配置,不读取 Goal 的停止事实,因此生成前的拦截不能撤销已经排队的发送授权。
具体改动
规范依据为 docs/reference/protocols/periodic-report-v0.md,固定版本 9fc858c;同版本 docs/book/en/chapters/core-state-machines.md 的 “Goal activation does not mean automation is enabled” 规定 stopped 暂停自动 Turns。前者明确 stopped/paused/archived 无 active standing delivery subscription,已经准入的日历也不能重新激活工作。
- REPORT-ADMISSION:implemented。
cadence_runtime.py在注册与锁内重查两处增加 canonical stop 判断。新旧 active、无 activation 的旧 registry、订阅禁用、无日历及 legacy 三种停用状态均做了对照。 - REPORT-DELIVERY:not_met。
pending_intent.py的生效订阅解析会返回 None,但loopx/extensions/lark/periodic_report_delivery.py::_resolved_goal_channel_binding仍直接解析 enabled 配置。既有请求保留同一订阅 revision,在 canonical stop 前置和两次发送之间发生时都继续调用第二次发送。 - REPORT-RECOVERY:implemented。 stop 不改写冻结窗口,resume 后原 window_id 可继续进入编辑;日历顺序、reporter 更换、订阅重配、重放和 publication cursor 仍由原 owner 处理。
关键代码讲解
periodic_report_cadence_hooks,第22行:注册前检查 canonical activation 和 legacy 生命周期,再检查订阅、日历和 reporter,停止时根本不安装新钩子。resolve_current_subscription,第55行:日历锁取得后重读注册、生命周期和订阅,防止旧 closure 使用过时授权;不是只在第一次读取时过滤。_active_delivery_subscription,第228行:影响 pending 列表、交互投影及 consume 的准入。当前调用者没有涵盖发送端,正是剩余缺口。
测试文件把 canonical stop 加入构造后撤销与已准入窗口的参数矩阵,保留 reporter、日历变更和 legacy 生命周期断言。完整差异为三文件 +52/-9,没有 UI 或新状态词汇。
对主干的风险
已执行:三份 periodic-report 聚焦文件、Goal activation 及 report authority 共 137 passed;CLI capability chain 与 Goal Channel delivery 24 passed;原生 canary 的五项直接检查和五项选择检查通过,包含完整语义检查,advisory 先执行。没有查询或等待远程 CI。这些现有测试全绿仍未覆盖上述发送前和发送之间的 canonical stop;独立 base/head 反例在两边都观察到两次发送调用,所以这是相关验收缺口,不能归入无关历史红灯。
最小修复是在报告能力现有 owner 中统一生效订阅/生命周期检查,并让发送端每次发送前复用它。保留 generation/receipt 与 dedupe 历史;不要靠清空待发状态、仅修改显示状态或要求用户额外禁用订阅来绕过。回归应覆盖:已生成报告随后 stop 时零次发送;第一条后 stop 时不再发送第二条;resume 后按既有消息回执去重继续。可扩展 tests/extensions/test_periodic_report_goal_channel_delivery.py 的 live-authority 测试,并重跑上述五份核心文件及该 delivery 文件。传输是替代 runner,证明的是发送命令是否可达,未将替代回执宣称为真实消息送达。
语义与 CI 对齐
复用已注册的 GoalActivationState,没有新 Enum、协议或 Python 决策源;当前 REPORT-DELIVERY 的生效授权语义仍不一致。默认关闭的订阅没有新钩子、窗口或发送;已启用但另一 Goal 的工作没有被连带阻断。停止检查是强制授权条件,不是可忽略建议。前瞻性重构应止于同一报告能力的实时授权解析,发送渠道本身不应复制 Goal 状态规则;无须扩大到全局调度重构。
我的整体评价
REQUEST_CHANGES。 新窗口准入及恢复路径确有独立验证的收益,但在用户停止 Goal 后仍可能继续发送旧报告,所以本次“停止报告工作”的结果尚未闭合。长期运行中的冻结窗口和恢复得到保留,用户体验上的停止承诺仍未满足;需要补齐同一授权链的最后一个消费者。无需增加状态、配置开关或更大框架。以上结论绑定当前 exact head,当前没有修复、合并或撤销其他评审的权限声明。
English verdict: REQUEST_CHANGES - HEAD d9fa9a6; canonical stop now blocks cadence admission and pending projection, but queued delivery still bypasses stop before and between sends. Complete the live authority check at the existing delivery owner.
| if not isinstance(goal, Mapping) or goal.get("status") in {"stopped", "paused", "archived"}: | ||
| if ( | ||
| not isinstance(goal, Mapping) | ||
| or goal_is_stopped(goal) |
There was a problem hiding this comment.
[P2] 让发送端也复用 canonical stop 授权检查。这里阻止了 pending/consume,但已生成报告仍直接进入 _resolved_goal_channel_binding,后者只解析 enabled 订阅,未检查 Goal 生命周期。同一请求在发送前 canonical stop、或第一条后 stop 时,当前 head 都调用两次发送命令并返回 satisfied(替代传输,无真实消息);disabled 订阅对照则在发送前拒绝。基线也有此缺口,属于本次 REPORT-DELIVERY 停止承诺未闭合。请在现有报告能力中统一生效授权,并于每次发送前重查,保留已生成物与去重历史,补 stop-before/between-send 和 resume-dedupe 回归。
Summary
Closes #6076.
Validation
fnm exec --using=22.22.3 uv run --extra test pytest -q tests/capabilities/test_periodic_report_pending_intent.py tests/capabilities/test_periodic_report_cadence_journal.py tests/capabilities/test_periodic_report_cadence.py(75 passed)fnm exec --using=22.22.3 uv run --extra test loopx canary premerge --from-git-diff(passed)fnm exec --using=22.22.3 uv run --extra test python examples/semantic-vocabulary-drift-smoke.py(passed)Future-facing refactor pass: not needed; the change reuses the existing typed Goal activation owner without adding another lifecycle abstraction.