Repository navigation
Conversation
The conversation-activity scenario sampled the page's mocked clock with page.evaluate(() => Date.now()) and passed that instant to page.clock.pauseAt. Between the evaluate round trip and the pause command the running clock keeps advancing, so on a loaded runner the clock can already be past the sampled instant, and pausing into the past throws 'Cannot fast-forward to the past' — the failure that has been flipping the required dashboard-browser shard 1 red for open PRs (loopx-project#8256, loopx-project#8290) and main's browser lanes. goal-showcase and navigation-sorting already freeze at a fixed future instant for exactly this reason ('a sampled now can already be in the past when the next browser command arrives'); conversation-activity was the one remaining site that still sampled. Pause at the sampled instant plus a five-second headroom, which keeps the scenario's property — one frozen instant compared across views — while guaranteeing the target stays in the clock's future regardless of command latency. Signed-off-by: Lihua <1017343802@qq.com>
|
CI attribution for the |
|
This pull request has merge conflicts with Choose the remote for the base repository, not an out-of-date fork. git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEADFor a same-repository clone whose Keep the DCO |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max
动机 / Motivation
维护工作区浏览器验收的人,在核对安静中的对话和切换视图后的计时一致性时会遇到这个问题。旧测试从仍在运行的浏览器时钟读取当前时间,随后才发暂停命令,命令到达时该时间可能已经过去;新写法增加五秒余量,意图让测试继续到达原来的交互断言。普通延迟下暂停成功,但命令延迟超过五秒时同一异常仍可复现,因此这里只缩小了竞态窗口。范围仅是既有 smoke 的时钟控制,不修改对话产品、SSE 服务、权限或线上计时规则。
改动思路 / Approach
这个场景已经使用 fake clock(可控的浏览器时钟)快进 25 秒,再暂停时钟来比较导航前后的同一时刻。改动保留了两次独立命令:先采样,再把采样值加五秒传给暂停。余量可以容忍较短延迟,却仍让命令调度速度决定成功。无需另建时钟抽象;主干已有安装时明确起点、直接推进到未来固定时刻的实现。
具体改动 / Changes
关键内容讲解
准确审阅 head 2f9788aeae21bf1c86bbdb890e98b57186155ae0,一处 smoke 文件 +5/-1。第 56 行 sampledNow 读取的仍是运行中的时间,第 57 行 pauseAt(sampledNow + 5_000) 仍需晚于命令实际到达时的时钟。原有 quiet 状态、视图切换、elapsed 一致性和 resume 断言均保留。
规范依据:docs/development/good-smokes.md,固定修订 21013c0c113445b71a30f6ce06ab61455b56f1f2。其未编号表格行 Is the result deterministic? 在此 head 为 not_met:仍由墙钟与命令到达速度决定是否越过暂停边界。最小修复是复用现有可控起点,避免增加任意余量。
在真实 Ego 空白页中注入当前依赖 Playwright 1.62.1 的原始 clock 实现,对相同命令序列施加受控延迟,得到:
| 时钟序列 | 采样后延迟 | 结果 |
|---|---|---|
| 原基线,暂停到采样值 | 250 ms | FAIL:Cannot fast-forward to the past |
| 此 head,采样值加五秒 | 250 ms | PASS:成功冻结 |
| 此 head,采样值加五秒 | 5,250 ms | FAIL:同一异常 |
| 主干固定起点的对照 | 5,250 ms | PASS:冻结在起点后 25 秒 |
这证明的是实际 clock 的语义和命令延迟边界,未运行完整 Playwright driver、打包页面、HTTP/SSE 或导航场景。node --check 和原生 quick premerge 的 4 项直接检查、3 项选择检查均 PASS;它们不覆盖这个延迟反例。没有查询或等待远端 CI。
对主干的风险 / Risks
[P2] 用受控时钟起点替代五秒竞态窗口(第 57 行)。 当主机或浏览器命令队列延迟超过五秒,pauseAt 会把已过去的目标送进 _innerFastForwardTo,在任何导航一致性断言之前失败。受控 5.25 秒延迟已复现;普通延迟的一次通过不能证明该竞态消失。复用主干 f5c6385 的已控制起点:先取 beforeIdle,install({time:beforeIdle}),直接 pauseAt(beforeIdle+25000);对齐主干或关闭已覆盖提案,保留原交互断言。
主干已包含上述修复,当前 PR 还显示合并冲突;没有修改作者分支或替作者解决冲突。沿用现有单个 smoke 即可,不建议再创建同形测试。扫描了同作者的 #8338、#8340 及相邻时钟调用,没有足够证据认定批量提交滥用,不提出贡献限制。原评论中的其他 CI 故障仍仅是诊断,未认证其归因。
我的整体评价 / Verdict
REQUEST_CHANGES。 这个小改动有明确维护目标,但当前 head 仍未交付稳定的时钟边界。long_horizon 为 not_applicable:未改变 Goal 持久化、调度或续跑;user_experience 为 not_applicable:未改变产品交互,风险限定在回归测试可信度。视觉检查为 not_applicable,因为检查的 examples/personal-workspace-browser/conversation-activity.mjs 只改时钟控制;未验证范围是完整打包浏览器旅程。没有新增共享语义词汇、格式兼容分支或运行时默认值;最有价值的简化是直接复用主干修复。没有合并授权。
English verdict: REQUEST_CHANGES — the five-second margin retains the running-clock race; reuse the controlled clock origin already on main.
| // the time the pause command arrives the running clock can already be | ||
| // past a sampled "now", and pausing into the past throws. | ||
| const sampledNow = await page.evaluate(() => Date.now()); | ||
| await page.clock.pauseAt(sampledNow + 5_000); |
There was a problem hiding this comment.
[P2] 暂停目标仍取决于运行时钟的五秒余量。受控 5,250 ms 命令延迟下,准确 head 的 Playwright 1.62.1 clock 仍抛 Cannot fast-forward to the past;250 ms 对照通过。请复用主干 f5c6385 的受控起点安装和直接 pauseAt(beforeIdle+25000),保留原导航/elapsed 断言。此验证是实际 injected clock 的语义探针,未冒充完整打包浏览器场景。
Review follow-up: five seconds of headroom only narrowed the race — a controlled 5.25 s command delay still reproduces 'Cannot fast-forward to the past', because the sampled instant stays subject to command scheduling. Install the fake clock at a fixed origin and pause at a deterministic future instant from that origin, the pattern goal-showcase and navigation-sorting already use; only the equality of the frozen instant across views is asserted, which the fixed origin preserves. Verified in a real browser: the scenario passes (6,784 ms). Signed-off-by: Lihua <1017343802@qq.com>
LIHUA919
left a comment
There was a problem hiding this comment.
Addressed on new head c0f701f88: the pause now uses the controlled-origin pattern you prescribed (install at Date.UTC(2030, 0, 1), fastForward 25 s, pauseAt(clockStart + 60_000)), identical in shape to goal-showcase and navigation-sorting — no sampled instant and no arbitrary headroom remains, so command latency can no longer decide the outcome. Only the equality of the frozen instant across views is asserted. Verified in a real browser on this head: the scenario passes (6,784 ms). English verdict: the deterministic fixed-origin pause replaces the racy sampled+headroom form; the delay counterexample cannot reproduce.
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent | gpt-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max
动机 / Motivation
维护对话浏览器验收的人,在检查安静中的对话和导航前后的计时一致性时会遇到这个问题。旧测试对运行中的时钟采样后再暂停,命令到达时目标可能已经过去;此 head 改用固定起点和一分钟后的目标,意图消除这个异常。上轮五秒余量的反例已通过,但暂停前仍有运行中的时钟,35.25 秒延迟可复现同一错误。范围仅为既有 smoke 的时钟控制,不修改对话产品、SSE、权限或线上计时策略。
改动思路 / Approach
固定起点只固定安装时的时间值,install 后时钟仍在走。随后 fastForward(25000) 先消耗 25 秒,再预约起点后 60 秒的暂停,实际仍依赖约 35 秒余量。当前改动没有移除两条独立命令之间的调度窗口,因此新注释所说的“regardless of command latency”不成立。
最小边界仍是这个 smoke:让比较使用的 Date 真正固定,同时推进定时器,并在导航比较后显式恢复系统时间和运行。无需新的时钟框架、生产状态或重试策略。我用同一实际 clock 实现验证了 setFixedTime → fastForward → pauseAt → setSystemTime/resume 控制序列;这只证明替代时钟控制可行,尚未认证完整场景。
具体改动 / Changes
关键内容讲解
准确 head c0f701f88a0759546c3f2e47a408f0b0f801528a,完整 PR 相对真实 merge base 87a153d4d206fdc9e466ae2ed4bf1381006d235a 仅一处 smoke +9/-4。相对上轮 head 2f9788aeae21bf1c86bbdb890e98b57186155ae0,新增固定 2030 起点及 60 秒暂停目标,保留 fastForward(25000)。第 55–58 行负责本次行为;quiet、elapsed、导航一致性、恢复和后续 steering 断言未删除。
规范依据:docs/development/good-smokes.md,固定修订 21013c0c113445b71a30f6ce06ab61455b56f1f2。未编号审阅表行 Is the result deterministic? 在本 head 为 not_met:是否进入原交互断言仍由墙钟延迟决定。该表行 Is the assertion durable? 为 implemented:原来的状态与导航断言保留。
在真实 Ego 空白页注入本分支依赖 Playwright 1.62.1 的原始 clock 实现,分别控制命令间延迟:
| 序列 | 延迟 | 结果 |
|---|---|---|
| 原基线,暂停到采样值 | 250 ms | FAIL:Cannot fast-forward to the past |
| 上轮五秒余量 | 5,250 ms | FAIL:同一异常 |
| 当前固定起点 + 快进 25 秒 + 暂停到 60 秒 | 5,250 ms | PASS |
| 当前同一序列 | 35,250 ms | FAIL:暂停前已到起点后 60,252 ms |
| 固定 Date、推进定时器、暂停并恢复的控制序列 | 35,250 ms | PASS:比较前后 Date 相等,恢复后推进 26 ms |
控制序列中定时器实际触发 36 次;没有用返回成功的 mock 代替时钟。上轮主干控制只验证过 5.25 秒边界,不能把那次成功推断成任意延迟都安全。本轮没有把主干的另一个有限未来目标当作无竞态证明。
node --check、源码标准 premerge 的 4 项直接检查和 2 项选择检查均 PASS。初次长 page.evaluate 命中 Ego 的 15 秒观察限制,随后重载自有空白页,改成异步启动、按完成状态读回;上述失败来自完成的 clock 探针,不是观察超时。未运行完整 Playwright driver、打包页面、HTTP/SSE 或导航验收,没有查询远端 CI。
对主干的风险 / Risks
[P2] 固定起点后仍保留约 35 秒的运行时钟窗口(第 58 行)。 当快进完成到暂停命令之间累计延迟超过剩余余量,pauseAt 仍进入 _innerFastForwardTo 的过去时间错误,在 quiet 与导航断言前终止。受控 35.25 秒延迟已复现;5.25 秒通过只扩大了容忍范围,不能证明竞态消失。请使比较使用的时钟真正固定并保留定时器推进及恢复,例如上述固定 Date 的序列,再运行原 5.25 秒和本次 35.25 秒反例及完整场景;不要继续扩大常量或只改注释。
当前主干 efd49352cc087cb299d5f7194cefd95a64b83e95 在同一位置已有另一修复;实际三方合并仍冲突。这是独立的整合门,本结论不以冲突代替时钟发现,也没有修改作者分支。保留现有一个场景即可。同作者 #8338、#8340 与此主题不同,未建立批量重复违规证据,不建议贡献限制。
我的整体评价 / Verdict
REQUEST_CHANGES。 原问题的修复尚未证明,现有小边界合理,所需简化是改正时钟控制,保留原断言。long_horizon 与 user_experience 均为 not_applicable:检查的场景只改测试设置,不改变 Goal 续跑、产品交互或用户配置。视觉检查为 not_applicable,因为 examples/personal-workspace-browser/conversation-activity.mjs 没有更改渲染呈现;未验证范围为完整打包浏览器旅程。无新增共享词汇、生产默认值或持久兼容格式,未合并。
English verdict: REQUEST_CHANGES — head c0f701f still fails at a controlled 35.25-second delay; freeze the comparison clock and retain timer advancement and recovery.
| // Compare the same instant across views; clock.install alone keeps | ||
| // advancing and can cross a second boundary while navigation completes. | ||
| await page.clock.pauseAt(await page.evaluate(() => Date.now())); | ||
| await page.clock.pauseAt(clockStart + 60_000); |
There was a problem hiding this comment.
[P2] 固定起点仍保留约35秒运行时钟窗口。准确head先fastForward(25000),再pauseAt(clockStart+60000);实际Playwright1.62.1 clock在35,250ms受控延迟后已到+60,252ms,仍抛Cannot fast-forward to the past。5,250ms通过只扩大容忍范围。请真正固定比较所用Date,并保留定时器推进和比较后的时间恢复;同一clock的setFixedTime→fastForward→pauseAt→setSystemTime/resume控制已通过35.25秒对照,完整driver/页面场景仍需复验。不要继续只扩大常量。
Second review round: a finite future pause target still leaves a
scheduling race — install({time}) only sets the starting value and the
clock keeps running between commands, so a sufficiently delayed pause
(35.25 s in the review's probe) again aims into the past.
Follow the review's validated control sequence: setFixedTime pins Date
to the controlled instant, fastForward advances the timers without a
running wall clock, and the pause lands on the already-pinned instant —
no command latency can move the target. After the navigation comparison
the scenario restores the system time and resumes, so later steering
assertions run on a live clock again. Verified in a real browser: the
scenario passes (7,701 ms).
Signed-off-by: Lihua <1017343802@qq.com>
LIHUA919
left a comment
There was a problem hiding this comment.
Addressed on new head 985e6c454: implemented your validated control sequence — install({time: clockStart}) → setFixedTime(clockStart) → fastForward(25000) → pauseAt(clockStart), and after the navigation comparison setSystemTime(Date.now()) → resume() so the later steering assertions run on a live clock. With Date pinned there is no running wall clock between commands, so no command latency can move the pause target — the finite-target race is gone by construction, not by headroom. Verified in a real browser on this head: scenario passes (7,701 ms). English verdict: the deterministic pinned-instant sequence replaces every finite-future-target form.
Problem
The required
dashboard-browser (1)shard has been flipping red withclock.pauseAt: Error: Cannot fast-forward to the past— seen on open PRs (#8256, #8290) and main's browser lanes. The crash site is theconversation-activityscenario, which sampled the page's mocked clock and passed that instant topage.clock.pauseAt:Between the
evaluateround trip and the pause command, the installed clock keeps advancing, so on a loaded runner the clock is already past the sampled instant and pausing there throws.goal-showcaseandnavigation-sortingalready freeze at a fixed future instant for exactly this reason (their comment: "a sampled 'now' can already be in the past when the next browser command arrives");conversation-activitywas the one remaining site that still sampled.Change
One file,
examples/personal-workspace-browser/conversation-activity.mjs: pause at the sampled instant plus five seconds of headroom. The scenario's property — one frozen instant compared across views, so the elapsed text cannot drift while navigation completes — is unchanged; the target is simply guaranteed to stay in the clock's future regardless of command latency.Validation
conversation-activitypasses twice (6,997 ms and 7,126 ms) where it previously crashed the runner; the run continues through later scenarios.nowpause sites remain (goal-showcase,navigation-sortingand the dashboard acceptance smokes all use fixed instants or barefastForward).typed-actionswaitFor timeout and aconfiguration-backupModuleNotFoundError: No module named 'loopx'appeared in my local all-scenarios runs; both are local-environment artifacts (no installed package for the spawned Python backend; CI installs-e .), unrelated to this one-file timing fix and not observed in the CI shard logs.node --checkclean; no product code touched.