Skip to content

fix(periodic-report): honor canonical Goal stops - #6549

Open
Duang777 wants to merge 1 commit into
loopx-project:mainfrom
Duang777:codex/core-bug-20261015
Open

Duang777 wants to merge 1 commit into
loopx-project:mainfrom
Duang777:codex/core-bug-20261015

Conversation

@Duang777

Copy link
Copy Markdown
Collaborator

Summary

  • prevent periodic-report cadence work from starting or continuing after the canonical Goal activation is stopped
  • suppress pending-report delivery authority for canonically stopped Goals
  • add coverage for initial registration, post-registration recheck, and pending intent readback

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.

Signed-off-by: duang777 <duangjl007@gmail.com>
@Duang777
Duang777 force-pushed the codex/core-bug-20261015 branch from cc9637f to d9fa9a6 Compare October 15, 2026 19:01

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

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; 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 处理。

关键代码讲解

  1. periodic_report_cadence_hooks,第22行:注册前检查 canonical activation 和 legacy 生命周期,再检查订阅、日历和 reporter,停止时根本不安装新钩子。
  2. resolve_current_subscription,第55行:日历锁取得后重读注册、生命周期和订阅,防止旧 closure 使用过时授权;不是只在第一次读取时过滤。
  3. _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)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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 回归。

This branch has not been deployed

No deployments
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.

[Bug]: Periodic reports are admitted for canonically stopped Goals

2 participants