Skip to content

fix(status): restore the open_todo_items and todo_item_task_class compat re-exports - #8160

Merged
huangruiteng merged 2 commits into
loopx-project:mainfrom
Weimr2627:weimr/status-compat-reexports
Nov 6, 2026
Merged

huangruiteng merged 2 commits into
loopx-project:mainfrom
Weimr2627:weimr/status-compat-reexports

Conversation

@Weimr2627

Copy link
Copy Markdown
Contributor

Goal And Delivered Outcome

  • Outcome basis / optional anchor: a reproduced defect — four shipped public smokes fail on main with the same root cause, first red in the nightly Full Public Smokes sweep of 2026-11-05 (no issue filed for it yet).
  • Goal/source and gap: loopx.status is the compatibility facade that read-model owners re-export through. PR refactor(status): compose the status task graph in TypeScript #7904 (refactor(status): compose the status task graph in TypeScript, merged 2026-11-05T03:21:17Z) is the only commit in that window touching loopx/status.py, and it dropped two names from the facade: open_todo_items and todo_item_task_class.
    • examples/control_plane/todo-readmodel-boundary-smoke.py:101 exists specifically to pin that pairing: assert status_module.open_todo_items is todo_read_model.open_todo_items (alias bound to loopx.control_plane.todos.todo_summary at :39).
    • examples/control_plane/todo-first-open-summary-smoke.py imports todo_item_task_class from the facade.
    • Consequence: four shipped smokes die at import/attribute level, and the compat boundary the guard protects is silently unenforced.
  • Observable before → after, with the validation row that proves it: before, all four fail (ImportError: cannot import name 'open_todo_items' from 'loopx.status'; the boundary guard then AttributeError: module 'loopx.status' has no attribute 'open_todo_items'); after, all four pass on the tested revision.
  • Issue/task and intended base: no pre-existing issue; self-contained repair of a regression. Intended base is loopx-project/loopx:main at 54e26effd9cc958179b9fe555d50ba22d13538a6.

Onset evidence

Reading Result
nightly 41937099939 (2026-11-04T23:52:34Z) none of the four smokes appear in the failed set → green
nightly 42132115859 (2026-11-05T23:47:56Z) all four appear in the failed set → red
commits touching loopx/status.py between the two exactly one: #7904

Author Declaration

  • Written by: model_agent — Qoder AI assistant, at the contributor's direction; no human review has occurred.

Implemented against

  • Specification and revision: the compat-boundary guard examples/control_plane/todo-readmodel-boundary-smoke.py at 54e26effd9cc, and the facade form that existed immediately before the regression — read directly from 00926abcd^1:loopx/status.py (lines 232 and 240), where both names were plain imports from .control_plane.todos.todo_summary with no owner-mapping entries.
  • Criteria:
Criterion (spec clause) Disposition Symbol / path Test or command
status_module.open_todo_items is todo_summary.open_todo_items implemented loopx/status.py:232 examples/control_plane/todo-readmodel-boundary-smoke.py
status_module.todo_item_task_class importable from the facade implemented loopx/status.py:240 examples/control_plane/todo-first-open-summary-smoke.py
Binding owner and spelling match the pre-#7904 facade (bare names from todo_summary, no new owner-map rows) implemented same two lines diff review against 00926abcd^1:loopx/status.py
Behaviour of the read models themselves out_of_scope loopx/control_plane/todos/todo_summary.py unchanged by this diff
  • Self-check before submission: read the guard's required symbol set (23 names) and found only open_todo_items missing from it; found todo_item_task_class separately through the second smoke's import list, so this diff restores two names rather than the one the guard alone reports. Both were confirmed to bind to the same objects the guard expects. The four smokes were also run with the two lines stripped, and the guard breaks — so neither restored line is decorative. Deliberately left loopx/registry.py, the read models, and every other facade name unchanged.

Scope And Continuation

  • Completed scope and remaining work: complete within this scope. The remaining nightly failures on this head are unrelated (the context_capture_navigation_v1 envelope migration and two module-size ratchet violations in files that already have open PRs).
  • Slice boundary / successor: N/A — one facade regression, independently reversible.

Validation

  • Tested revision: 22d31a229084c3702e4207f3f9c4e7275c9ba30a
  • Run state: finished
  • Input classes: public_fixture, synthetic
Check kind Result Public-safe evidence / limitation
integration passed todo-readmodel-boundary-smoke.py, todo-first-open-summary-smoke.py, maintenance-latest-run-routing-smoke.py, monitor-display-projection-smoke.py → all four pass on the tested revision.
regression_parity passed On base 54e26effd9cc958179b9fe555d50ba22d13538a6 the same four fail at import/attribute level with the messages quoted above; with the two lines removed again the boundary guard fails, which is the negative control for this guard.
static passed python -m py_compile loopx/status.py; git diff --check; identity assertion loopx.status.open_todo_items is todo_summary.open_todo_items and same for todo_item_task_class.
unit not_run Full pytest suite not run locally: the diff adds two import bindings to an existing module and touches no logic; the hosted required checks cover it once a maintainer enables them for this fork PR.
  • Coverage and gaps: covered — the facade bindings and the four shipped smokes that consume them. Not covered — hosted CI on this head: fork workflows are queued behind the maintainer approve workflows gate, so no required-check result is attached yet. No behaviour beyond re-export visibility changed.

Frontend / Visual Evidence

  • UI impact: none
  • Before: N/A
  • After: N/A
  • First viewport and preview: N/A
  • States and viewports shown: N/A
  • Source data: none
  • Attention review: N/A
  • Craft review: N/A

Type of Change

  • Bug fix

LoopX Area

  • Control plane (goals, todos, quota, scheduler, registry, runtime)

Technical Direction

Shared-authority RFC fixture impact

  • Production-scale fixture schema: N/A
  • Semantic dimensions changed, or reviewed no-impact rationale: N/A — two re-export names restored on an existing facade; no schema, fixture, provider arm or vocabulary added.
  • Provider conformance arms run: N/A
  • Read-only legacy/file/PostgreSQL three-arm rehearsal (required for promotion, runtime-routing, or compatibility-projection changes): N/A — this restores a re-export that an accepted guard already requires; it introduces no new compatibility projection.

Boundary Checklist

  • Neither the diff nor this PR body/comments/attachments disclose private state, credentials, raw traces or verifier output, internal links, or local machine paths (including .loopx/, .codex/goals/, and live ACTIVE_GOAL_STATE.md).
  • I did not duplicate maintainer-owned benchmark work unless a maintainer split out a public issue for it.
  • I kept the change scoped to the linked issue/task.
  • Existing English/Chinese RFC pairs both have a diff, and the local premerge check passes, or no paired RFC changed (no RFC changed here).
  • I completed the visual evidence section for UI changes, or marked UI impact none.
  • Every commit includes a DCO Signed-off-by trailer (git commit -s).

…pat re-exports

Signed-off-by: Weimr2627 <134630546+Weimr2627@users.noreply.github.com>

@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] 恢复的两个导出需要显式标记 re-export。 同命令 python -m ruff check --select E4,E7,E9,F loopx/status.py 在不可变基线通过,当前 head 在新增232、240行各报 F401。请分别写为 open_todo_items as open_todo_items、todo_item_task_class as todo_item_task_class,保留同一 owner 与对象身份,再运行这条检查及四个既有 smoke。这是已复现的新增本地验证失败,尚未发现导出功能本身错误。

精确 head:22d31a229084c3702e4207f3f9c4e7275c9ba30a;完整差异基点:54e26effd9cc958179b9fe555d50ba22d13538a6。PR 元数据当时的 main tip 为927d0b389096a9ca8702c4da14a43836063ed29b,实际 merge-base 是上述54e,未把后来主干提交算进这两行。

动机 / Motivation

维护兼容入口及运行仓库已发布 Todo smoke 的贡献者。 TypeScript 迁移后,消费者从 loopx.status 导入这两个既有名字会失败;本 head 恢复直接绑定,四个原有消费者 smoke 从基线失败转为通过。 两个入口确实绑定到 todo_summary 的同一函数对象,已有待办摘要、截断与监视展示对照通过;新增裸导入仍产生两条 F401。 本 PR 不改变待办分类、排序、持久化或 TypeScript 决策 owner,也不认证真实安装、其他平台或宿主采用。

这是有实际消费者的兼容回归:既有 guard 和导入方在进入读模型之前失败,继续保留缺失绑定会让这些仓库验收路径一直不可用。无需为这项修复新建 issue、任务图或包装层;两行绑定已经能恢复行为,剩余修复同样只需在这两行完成。

改动思路 / Approach

两个直接绑定即可修复现有兼容边界,重用 todo_summary 而不再实现读模型;不需要另一层包装或新增 owner-map 项。 当前切片仅恢复 status 兼容入口的两个名字与原函数身份;完整任务图迁移和其余主干质量债保留原 owner。

loopx.status 保持兼容 facade,真实读模型仍是 todo_summary,任务分类再委托既有 typed projection。名字恢复不会引入另一套排序、状态或授权规则。已从迁移前 00926abcd^1:loopx/status.py 核实两名原来也是直接 import,没有 owner-map 项;因此不要求为历史接口另造配置。显式同名别名是同一引用的导出声明,能消除当前静态失败,无需改回算法或删除 guard。

具体改动 / Changes

完整 PR 为一个生产文件 +2/−0,没有测试、生成物或持久格式改动。实现依据是既有可执行兼容合同 examples/control_plane/todo-readmodel-boundary-smoke.py,不可变修订 54e26effd9cc958179b9fe555d50ba22d13538a6,并连同 todo-first-open-summary 的导入消费者读取。原合同没有条款编号,本次映射 CB-1:open_todo_items 必须与 todo_summary 同一对象,implemented;CB-2:既有消费者能从 facade 导入 todo_item_task_class,implemented。读模型算法和 task graph 迁移之外的质量债属于 out_of_scope。

关键代码讲解

  • open_todo_items:恢复对 canonical 函数的直接绑定。guard 的身份断言及完整调用通过,独立断言也确认不是包装函数;malformed 输入和已完成项保留原有空列表行为。
  • todo_item_task_class:恢复 first-open 消费者所用的另一个名字,函数本体仍在 todo_summary,未在 facade 重建分类逻辑。这里和232行一样,裸导入触发 F401,应采用相邻多个兼容导出已使用的显式同名写法。

已查 guard 的身份/移除集合、todo_summary 的状态与排序函数、四个消费入口和迁移前源码;当前新增两名不在 guard 要移除的旧 aliases 集合里。函数、TypeScript决策、配置、依赖和 owner-map 都未改变,没有新 schema、枚举或调用权限。

对主干的风险 / Risks

四条现有 smoke:todo-readmodel-boundary、todo-first-open-summary、maintenance-latest-run-routing、monitor-display-projection,全部在不可变 base 因缺少导入/属性失败,全部在本 head 通过;三个相关 Python 模块48项在两端均通过。这里证明的是现有仓库消费者与身份合同,未声称已观察真实外部安装用户。

PASS:上述行为验证、CI 声明 lint roots、配置指定17根 mypy、完整 semantic vocabulary、diff advisory、编译/diff和变更文件公开边界扫描。FAIL:changed-file Ruff 恰好报告两条新 F401,而相同基线命令 PASS。功能 smoke 通过不能覆盖这个检查,最小修复是首段同名别名;删除导入会重新破坏实际消费者。

初次把 maintenance smoke 错放到 control_plane 子目录,命令未执行;已更正现有路径并完成 base/head 对照。首次 inventory --check 参数不完整及隐式运行根冲突也保留失败,随后运行真正 semantic smoke 与隔离公开扫描通过,没有动产品或断言。

语义与 CI 对齐

TS2345(conversation_binding.ts:1144)和 raw maintainability 的旧超大 interaction 函数也 FAIL;完整输出在不可变 base/head 分别逐字一致,致因源码、配置、依赖整 blob 未改,独立的导出/消费者证据通过,保留 pre_existing_unrelated 归因。这两项不是本 PR 需顺便修的内容,但仍作为必检失败记录。严格 CQR cqr_7c531a4f4acbd5f0858f 为 FAIL、verify为invalid_receipt;quick premerge 的6项直接检查和3项选中 smoke 通过,整体仍为 quality_invalid_receipt。未获取、轮询或等待远端 CI,也没有把新 F401 伪装成基线失败。

我的整体评价 / Verdict

REQUEST_CHANGES,请求限于首段两处导出声明及重跑,不否认四个消费者已被修复。problem_context=goal_achieved 只描述这个兼容行为;long_horizon=preserved、user_experience=improved 基于原 owner 不变和消费者恢复。整个切片比例合适、复用正确,同域重构已评估为无需新增;没有要求另开后继任务或扩大迁移。

这是 compatibility_only 的既有符号复用,没有新增词汇、Goal gate、执行义务或 default-off 功能。已检查 status 入口、Todo 读模型与四个消费者;差异只有两个 Python 导入,不改变渲染页面或布局,视觉审查不适用。 真实安装、原生 Windows、已安装 App/宿主采用和长期完整成本未验证。 修复 F401 后仍须对新 head 重查,原 TS/ratchet 与严格质量门也继续保留独立状态。本轮未修改作者源码或合并。

English verdict: REQUEST_CHANGES — 22d31a2. The four existing consumers and 48 tests pass, but both restored bare imports introduce F401 against a passing base. Use explicit same-name re-exports and rerun Ruff plus those consumers; unchanged TS/ratchet failures remain separately disclosed.

Comment thread loopx/status.py Outdated
compact_todo_group as compact_todo_group,
compact_todo_item as compact_todo_item,
first_open_todo_text,
open_todo_items,

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] 请把这里和240行标为显式 re-export:open_todo_items as open_todo_items,以及 todo_item_task_class as todo_item_task_class。相同的 python -m ruff check --select E4,E7,E9,F loopx/status.py 在不可变54e26eff基线通过,本head恰好在两条新增裸导入报F401。四个消费者smoke和48项测试已通过,说明功能修复有效;最小修复仅为这两个同名别名,保留 canonical 函数身份,不要删导入或新增owner-map。改后重跑上述Ruff与四个既有smoke。

Signed-off-by: Weimr2627 <134630546+Weimr2627@users.noreply.github.com>
@Weimr2627

Copy link
Copy Markdown
Contributor Author

Fixed as requested on a new head: 246f85c21946a67758fd88427a06be60adf30ffa (one extra commit, 1 file, +2/-2 — only the two restored lines changed).

What was wrong

Both lines were bare imports inside the todo_summary block. Nothing in loopx/status.py consumes them, so each is an unused import by Ruff:

$ python -m ruff check --select E4,E7,E9,F loopx/status.py     # head 22d31a2290
F401 ... imported but unused  -> loopx/status.py:232 (open_todo_items)
F401 ... imported but unused  -> loopx/status.py:240 (todo_item_task_class)
Found 2 errors.

The same command on the immutable base file (git show 54e26effd9cc:loopx/status.py) reports 0 errors, so these two were introduced by my diff, exactly as the review said.

My earlier justification was wrong, and it is worth stating why: I checked 00926abcd^1:loopx/status.py, saw both names imported bare, and treated bare as the historical form. But at that revision the module used them further down (the open_todo_items=open_todo_items / todo_item_task_class=todo_item_task_class call sites), which is why no F401 existed there. Restoring only the binding without a consumer is not the same shape, and the neighbours in this block already spell compat bindings as explicit same-name aliases (todo_item_next_due_at as todo_item_next_due_at, todo_projection_sort_key as todo_projection_sort_key).

The fix

-    open_todo_items,
+    open_todo_items as open_todo_items,
-    todo_item_task_class,
+    todo_item_task_class as todo_item_task_class,

Still the same owner module and the same objects — no wrapper, no owner-map entry, no second implementation of either rule.

Re-run on the new head

Check Result
python -m ruff check --select E4,E7,E9,F loopx/status.py passes (was 2 F401)
ruff check loopx/status.py with the repository's default configuration passes
loopx.status.open_todo_items is todo_summary.open_todo_items and same for todo_item_task_class holds (asserted, so this is a re-export declaration, not a new function)
todo-readmodel-boundary-smoke, todo-first-open-summary-smoke, maintenance-latest-run-routing-smoke, monitor-display-projection-smoke all four pass
py_compile, git diff --check clean

The pre-existing failures the review recorded (the conversation_binding.ts TS2345 and the raw maintainability ratchet item) are unchanged by this commit and I am not claiming them.

One note on my own process: my first push attempt for this commit reported success locally but had not reached the remote; I re-checked the remote branch sha before re-pushing rather than assuming, and the branch is now at 246f85c2194. This verdict is still CHANGES_REQUESTED until re-reviewed on the new head.

@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 | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max

动机 / Motivation

维护兼容入口、运行既有待办摘要和监视展示检查的贡献者会遇到这个问题。 迁移后从旧入口导入这两个名字会立即失败,检查无法进入实际逻辑;本次恢复原有绑定,并用显式导出消除上一版新增的静态检查错误。 独立对照确认四个既有消费者从基线失败变为当前版本通过,两个名字均指向现有实现的同一函数对象,当前变更文件的严格 Ruff 检查通过。 本 PR 不改变待办分类、排序、持久化、TypeScript 决策或执行权限,也不认证安装态、其他平台及宿主长期采用。

改动思路 / Approach

两个显式同名导出复用已有函数对象,既恢复仍被调用的入口,也不引入包装层、第二套规则或同步状态。 本次交付边界是恢复两个仍有消费者的 Python 兼容符号及其静态检查有效性。 导入入口只暴露名字,过滤、排序和任务分类仍由已有 Todo 读模型负责;原生 task graph 和持久化 authority 也没有被兼容入口替代。消费者不需要重新配置或额外确认,所需交互轮次为零。保留名字的成本是两个绑定,删除既有检查或再加包装器都不能更好地满足对象身份合同。这里没有 optional observer、provider IO、默认启用策略或新增失败恢复机制。

具体改动 / Changes

审查完整差异:54e26effd9cc958179b9fe555d50ba22d13538a6 → 246f85c21946a67758fd88427a06be60adf30ffa,一个生产文件 +2/−0;上一轮 22d31a229084c3702e4207f3f9c4e7275c9ba30a → 当前 head 只把两个裸导入改成显式同名导出。实际 merge-base 是54e,而 PR 元数据的 main tip 927d 不是本次完整差异的起点,未把后来主干历史算入 PR。

依据上一轮已固定版本的审查框架,修订 22d31a229084c3702e4207f3f9c4e7275c9ba30a,并对照其中引用的54e既有可执行兼容合同:CB-1(open_todo_items 与 canonical owner 同一对象)、CB-2(first-open 消费者可导入 todo_item_task_class)、F401(显式导出且严格 Ruff 与四个消费者通过)均为 implemented。CB 标签是上一轮对无编号可执行合同的映射;不是新增 RFC 条款。作者已在修复说明确认前版裸导入的错误,本轮仍以独立复验为依据。

关键代码讲解

  • open_todo_items:显式同名导出直接绑定已有函数。独立断言和既有边界检查确认对象身份相等,None 输入仍为空列表;没有在 facade 复制过滤、去重和排序规则。实际四个消费者在基线均因名字缺失失败,当前版本完整执行通过。
  • todo_item_task_class:恢复 first-open 资产构建实际传入的分类函数;本体仍在 todo_summary 的532行并委托原分类器。独立对象身份断言通过。显式别名与相邻兼容导出一致,避免本轮又引入静态检查错误。

PASS:四个既有完整 smoke;两端各45个 graph/status 案例,包括真实 CLI 对临时 File/SQLite canonical authority 的读取、显示文件缺失/损坏/过期、provider unavailable 拒绝陈旧 fallback 和显示状态字节不变;变更文件默认/严格 Ruff、CI 声明 lint roots、配置指定17根 mypy 均两端通过。将精确旧版22d文件送入当前 Ruff,仍恰好得到232/240两条 F401;当前实际文件通过,因此验证能够区分前版缺陷。

对主干的风险 / Risks

未发现当前 head 的阻塞问题。最强风险是用包装器表面恢复导入、实际却偏离原算法或 authority;直接对象身份、四个完整消费者和45项 canonical 对照覆盖了这一风险,单独函数测试通过不能替代缺失入口的负对照。完整差异没有测试断言、配置、扫描范围或预算阈值修改,没有新增词汇、执行授权、状态写入、default-off 声明或 Agent 指令。

以下原始失败保留,未宣称整体质量门通过:

当前检查 原始结果与独立归因
npm run -s typecheck:control-plane FAIL,conversation_binding.ts:1144 的 TS2345;两端完整158字节输出相同,致因源码、配置和依赖整 blob 未改。
raw maintainability ratchet FAIL,interaction_contract.py 的既有超大 _admitted_interaction_next_cli_actions;两端完整399字节输出相同,checker/owner 未改。
runtime-handoff-status-read-path smoke FAIL,256行读取 payload["decision"] 触发 KeyError;两端单独执行同命令,完整733字节 traceback 仅替换 checkout 根路径后相同,smoke 和 quota 相关 owner 整 blob 未改。未臆断该历史问题的更深原因。

当前标准 premerge 的6项直接检查通过,18项选中检查含上述 handoff 失败与旧 maintainability advisory,整体仍为 FAIL。对精确选中失败命令的独立基线/当前对照支持 pre_existing_unrelated;这不表示完整基线 premerge 已重跑。两行导出不改变其致因路径,变化本身有独立通过证据,因此不要求本 PR 顺便修改这些无关 owner,也不放宽后续合并检查。未获取、轮询或等待远端 CI。真实 CLI 使用隔离临时 authority;未改运行中的 Goal 或宿主安装。

我的整体评价 / Verdict

APPROVE 当前 246f85c21946a67758fd88427a06be60adf30ffa,本次兼容恢复目标 goal_achieved,上一轮新增 F401 已修复。long_horizon 判为 preserved:原有 canonical 状态读取、失败拒绝与继续路径未改;user_experience 判为 improved:既有调用者恢复工作且不新增设置、导航或确认。该比例适当的完整切片复用单一 owner,当前无必要的相邻重构;保留兼容绑定,待真实消费者迁移及合同主动退役时再删除。

已检查 loopx/status.py、Todo 读模型和四个调用者;差异只增加两个 Python 导出,不修改任何渲染页面或布局,视觉审查不适用。 真实安装、原生 Windows、已安装 App/宿主采用和长期完整成本未验证。 这些未测范围没有被当作已验收的长期收益。语义归类为 compatibility_only,复用既有名称,无新状态词汇或义务。审查结论与仍失败的仓库质量门、有效旧 review 的处理、maintainer 合并权限分别判断;本轮没有执行合并、安装或部署。

English verdict: APPROVE — 246f85c. Both explicit re-exports restore the existing consumers and fix the prior F401 regression; unchanged TypeScript, ratchet and handoff failures remain disclosed as separate repository gate failures.

@huangruiteng
huangruiteng merged commit c6c328d into loopx-project:main Nov 6, 2026
21 of 27 checks passed
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.

3 participants