Skip to content

test(control-plane): pin the resume_at transport case to an injected clock - #4421

Merged
huangruiteng merged 1 commit into
loopx-project:mainfrom
Yue021130:codex/4413-resume-at-clock
Sep 15, 2026
Merged

huangruiteng merged 1 commit into
loopx-project:mainfrom
Yue021130:codex/4413-resume-at-clock

Conversation

@Yue021130

Copy link
Copy Markdown
Contributor

Summary / 概要

Fixes #4413. The parametrized resume_at case built its canonical Todo summary without an evaluated_at, so summary construction re-derived resume readiness from the wall clock. Once real time passed the hard-coded 2026-09-15T00:00:00Z instant, the case failed deterministically.

  • loopx/control_plane/testing/quota_fixtures.py: quota_todo_summary now accepts evaluated_at and passes it to compact_todo_group, which already supported the parameter.
  • tests/control_plane/test_delivery_response.py: one shared EVALUATED_AT constant drives both evaluate_todo_resume_conditions and summary construction.
  • New boundary regression test_resume_at_boundary_projects_from_the_injected_clock_not_the_wall_clock covers before / at / after the scheduled instant (5 parametrized instants) and keeps the tampered-clock_provider half of the original contract.

Note on #4411 / 与 #4411 的关系

#4411 (merged today) changed the literal to 2099-01-01T00:00:00Z as a stopgap, with a comment saying a near-future literal makes the case start failing the day it passes. That constraint no longer exists once the clock is injected, so this PR restores the 2026-09-15T00:00:00Z literal — one day ahead of the injected 2026-09-14T00:00:00Z clock — so the case actually exercises a near boundary and stays deterministic forever. Happy to keep the 2099 literal instead if you prefer.

Validation / 验证

  • Regression sensitivity / 回归敏感度: with the evaluated_at injection reverted, 3 cases fail — the original [resume_at:2026-09-15T00:00:00Z-patch3] plus the two boundary instants that precede the scheduled time. All pass with the fix.
  • uv run python -m pytest tests/control_plane/test_delivery_response.py -q → 17 passed.
  • uv run python -m pytest tests/control_plane -q -p no:randomly → 27 failed, 2050 passed, 5 skipped, 1918 errors; the clean origin/main baseline gives the identical 27 failed / 1918 errors with 2045 passed. The delta is exactly the 5 new boundary cases. The pre-existing failures and errors are unrelated (for example test_empty_canonical_ownership_never_revives_display_claim_or_local_lease[sqlite], which also fails on the clean tree).
  • uv run ruff check on both changed files: clean. git diff --check: clean.
  • loopx canary premerge --from-git-diff: 3 direct checks, 4 catalog canaries, 8 risk-profile smokes — 15/15 passed, no manual holds.

Scope / 范围

Test fixture and test only. No runtime behavior change, no Todo authority change, no live goal-state migration, and no default-provider or public-contract change.

…clock

The parametrized resume_at case built its canonical Todo summary without an
evaluated_at, so summary construction re-derived resume readiness from the wall
clock. Once real time passed the hard-coded 2026-09-15T00:00:00Z instant the
case failed deterministically.

- thread evaluated_at through quota_todo_summary into compact_todo_group
- evaluate and summarize the case against one shared EVALUATED_AT constant
- restore the scheduled-instant literal now that it is pinned to that clock
- add a boundary regression covering before, at, and after the instant

The boundary regression fails on the pre-fix fixture for both instants that
precede the scheduled time and passes once the clock is injected.

Fixes loopx-project#4413

Signed-off-by: Yue <108062406+Yue021130@users.noreply.github.com>
@Yue021130
Yue021130 force-pushed the codex/4413-resume-at-clock branch from 469c8c9 to edb92e0 Compare September 15, 2026 05:36

@huangruiteng huangruiteng 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.

动机

resume_at 的传输契约用例原本用一个"足够远的未来"字面量(resume_at:2099-01-01T00:00:00Z)保证条件不满足,但 canonical summary 的构造路径没有注入求值时刻,apply_resume_conditions → evaluate_todo_resume_conditions 在 evaluated_at 缺省时会退回 now_utc_iso()。也就是说这条用例其实依赖挂钟:真实时间一旦越过所写字面量(作者在描述里说这个日期已经过去,会确定性变红),用例就会失败。修复方向是对的:把时钟注入补齐,而不是把字面量再往后推。

改动思路

生产侧的 owner 早就支持注入时钟:compact_todo_group(evaluated_at=...)(loopx/control_plane/todos/todo_summary.py:1077)和 evaluate_todo_resume_conditions(..., evaluated_at=...)(同文件 784 行,缺省才用挂钟)。真正缺的是测试夹具包装层:loopx/control_plane/testing/quota_fixtures.py 的 quota_todo_summary 没有把这个参数转发下去。因此本 PR 只在夹具上加一个可选参数并转发,再把测试模块里的时钟统一成 EVALUATED_AT/RESUME_AT 常量,并补一条覆盖边界两侧的用例。没有引入 fake clock 框架、没有 monkeypatch datetime、也没有在生产语义上做任何改动。

具体改动

  1. loopx/control_plane/testing/quota_fixtures.py:70,79:quota_todo_summary(..., evaluated_at=None) 透传给 compact_todo_group;默认 None,保持所有既有调用方行为不变。
  2. tests/control_plane/test_delivery_response.py:19-20:新增 EVALUATED_AT = 2026-09-14T00:00:00Z 与 RESUME_AT = 2026-09-15T00:00:00Z(后者比前者晚一天,因此不受 CI 运行日期影响)。
  3. 同文件 :107,110:原参数化传输用例改用这两个常量,evaluate_todo_resume_conditions 与 quota_todo_summary 都收到注入时刻。
  4. 同文件 :120,148:新增 _resume_at_projection 与边界用例,覆盖 2026-09-14T00:00:00Z / 23:59:59Z(未满足 → canonical_todo_wait)与 2026-09-15T00:00:00Z / +1s / +1y(已满足 → history_supervision),并断言被篡改 clock_provider 的未满足等待仍让位给 history_supervision。

对主干的风险

  • 生产行为零变化:唯一非测试改动是一个带默认值的可选关键字参数,且该夹具模块只被测试引用。
  • 我做了两组对照实验,确认这条修复不是"看起来更整洁"而是承重的:在 head 上不注入时钟时,resume_at:2026-09-15T00:00:00Z(当前已是过去时刻)会被总结成 resume_ready=True、satisfied=True,注入 2026-09-14T00:00:00Z 才是 False;把 head 的测试文件放到 base(c979cf11c)上跑则是 9 failed / 8 passed(该参数在 base 不存在)。
  • 残留脆弱点:夹具参数仍是可选的,将来在本模块给某条 resume_when 加时钟敏感条件却忘记注入时,挂钟依赖会悄悄回来。

验证(exact head edb92e042):

  • pytest tests/control_plane/test_delivery_response.py -q → 17 passed(base 同文件 12 passed;head 文件在 base 上 9 failed/8 passed)。
  • 自建挂钟对照探针(同上,两个方向都跑了真实 summary 与 project_delivery_response)。
  • 远端检查:该分支(codex/4413-resume-at-clock)当前没有任何 CI 记录,head 的验证来自上列本地运行,合并前建议先触发一次 CI。

我的整体评价

根因定位准确、修法最小、证据可复现:它在正确的层次(测试夹具)补上了既有生产参数的透传,并把"日期一到就变红"的隐藏依赖换成显式注入时钟的边界用例。给出 APPROVE。

非阻塞建议:如果希望把这条不变式变成机械约束,可以让夹具在遇到时钟敏感的 resume_when 而未显式传入 evaluated_at 时直接报错,这样第三个调用点不会再默默退回挂钟。

English verdict: APPROVE at exact head edb92e0. The case only passed because summary construction fell back to the wall clock; quota_todo_summary now forwards the already-supported evaluated_at, and the new boundary test pins both sides of the instant (17 passed at head, 9 failed/8 passed when the head test file runs against origin/main, and a direct probe shows the un-injected clock reports the already-past instant as satisfied). One non-blocking note: the branch reports no remote CI checks yet, and the fixture parameter stays optional so a future clock-sensitive case could silently regress to wall-clock evaluation.

@huangruiteng
huangruiteng merged commit 65fadb6 into loopx-project:main Sep 15, 2026
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.

test(control-plane): resume_at transport test becomes time-dependent after 2026-09-15

2 participants