Repository navigation
fix(mobile): prevent listperf sweeps from fighting tail following - #7086
Conversation
Signed-off-by: elfcv <270533111+elfcv@users.noreply.github.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
[Low impact] The changes are limited to the DEV list performance page. 合并前需要同步更新默认值对应的测试断言。 Findings
Fix with agent prompt### Issue 1
apps/mobile/app/listperf.tsx:39
将 `recycle` 默认值改为关闭后,`messageNativeLifecycleContracts.test.ts:64` 仍要求源码包含旧表达式 `const recycle = params.recycle !== '0';`。运行完整 Mobile 测试套件时,该断言必然失败。请同步更新断言,保留对显式开启回收的检查。
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
|
Signed-off-by: elfcv <270533111+elfcv@users.noreply.github.com>
|
命中 UI 路径(apps/mobile/app/listperf.tsx / apps/mobile/src/debug/scrollProfiler.ts)但 description 未附界面效果证据——建议补充改动后效果:截图/录屏,或改动后界面的 HTML 页面(```html 代码块、.html 附件或在线预览链接),便于确认界面符合 DESIGN.md 设计规范。 (非阻断提醒:本页为 DEV-only 性能 harness,不影响正式产品界面,不因此打回。) |
MagicLizi
left a comment
There was a problem hiding this comment.
Review report — PR #7086(head 93fca8f)
fix(mobile): prevent listperf sweeps from fighting tail following
作者 elfcv · base 08d1788(main) · 标准档审查
Findings
没有 P0/P1。本次改动全部落在 DEV-only 性能测试链路(__DEV__ 门禁 + dev deeplink 页面、
debug 测量工具)与测试,未触碰正式消息列表、自动跟随控制器、原生配置或依赖;共享符号
runScrollSweep 唯一调用方就是本 harness,返回值从 void 改为取消函数不破坏任何其他
调用点;focusedItemKey / devExposeList / devRecycleItems 均为 MessageRenderer 既有
API,用法与既有语义(显式消息定位拥有初始位置、关闭贴底跟随)一致。
维护者确认门(product 触发)语义定性:不 hold。逐文件判据——
apps/mobile/app/listperf.tsx:DEV-only 临时 harness(__DEV__门禁,生产构建只显示
"DEV-only" 提示),bugfix(扫描与贴底跟随争抢滚动所有权、run 生命周期泄漏),对最终
用户零可见差异;apps/mobile/src/debug/scrollProfiler.ts:DEV-only 测量工具,纯技术改动(返回取消函数);apps/mobile/src/__tests__/listPerfHarness.test.tsx:新增回归测试(测试路径确定性排除);apps/mobile/src/__tests__/messageNativeLifecycleContracts.test.ts:断言机械同步 1 行,
不改变 guard 规则含义。
按 product 门判据「用户看不看得见」:生产用户不可见、无外观/布局/文案/交互流向变化 →
执行 fallback=review,不创建讨论 issue、不挂确认标签。
Rule coverage — 读取的规则文件及逐项结论
AGENTS.md:仓库边界、安全底线 —— 无凭证/敏感数据改动,无跨仓改动。通过。docs/dev-rules/development-workflow.md(P0/P1/P2 口径、验证真实性):PR 模板三段齐全、
title 类型 fix 与 diff 一致;验证声明逐条核对(见 Verification)。通过。docs/dev-rules/environment-setup.md:审查 worktree 按文档安装依赖后验证。通过。docs/dev-rules/mobile-development.md/docs/dev-rules/remote-and-mobile-adaptation.md
(apps/mobile 命中):未触碰app.json/app.config.js/eas.json/package.json/
plugins//modules/等 runtime fingerprint 输入,无冷更边界问题;未触碰 device-link、
workdir 或 IPC。通过。docs/design-rules/DESIGN.md(UI 命中,强制):改动仅 DEV harness 页面内的既有
<Text>展示串(phase 文案)与行为,未新增/修改样式、组件或主题 token,无硬编码绕过
token 的新增(styles 为既有未改动历史代码)。无设计硬伤。- rule-map「审查时的固定问题」逐项:①单一目的(测试驱动滚动所有权修复),描述与 diff/
测试一致;②共享符号runScrollSweep读方(仅 listperf)已核;错误/回滚路径:effect
清理取消 timer+rAF、cancelled双保险挡 onDone,无悬挂句柄;③无权限/凭证/跨平台面;
④无新增依赖、无危险写法、无新数据流向(security 扫描 hard/soft 均 0 命中);
⑤新增真实回归测试 4 项且先红后绿;⑥未把流程塞进 Core;⑦UI 证据缺失属非阻断提醒
(DEV-only 页面,PR 已注明「不涉及」理由);⑧不涉原生配置,无冷更;⑨无 P0/P1。
Verification — 实际运行的命令、结果、未执行项及原因
(均在审查 worktree(head 93fca8f)内运行,日志保留完整输出与退出码)
| 命令 | 结果 |
|---|---|
pnpm install --frozen-lockfile --prefer-offline --prod=false |
EXIT=0 |
pnpm --filter mobile run typecheck |
EXIT=0(与 PR 声明一致) |
vitest run listPerfHarness / messageNativeLifecycleContracts / messageScroll / messageTailFollower |
EXIT=0,95 项全过(与 PR 声明的 95 项一致) |
pnpm --filter mobile test(整包) |
EXIT=0,768 文件 / 10801 项全过 |
pnpm --filter mobile run test:scope |
EXIT=0,mobile-scope-guard passed |
git diff --check 08d1788...HEAD |
EXIT=0 |
pnpm check:dco |
EXIT=0,2 个提交均签名(e500a7f0..93fca8f) |
pnpm check:test-hygiene |
EXIT=1:报 runtimePrompt.test.ts sourceReads: 0 -> 4、MacModifierShortcutListenerStartRace.test.ts resetModules: 0 -> 1。经核:两个文件与 scripts/test-hygiene-baseline.json 均未被本 PR 触碰(git diff --name-only e500a7f..HEAD 仅 4 个 mobile 文件);失败源于分支落后 main 223 个提交,main 侧已清理这两个 desktop 测试并收紧 ratchet 基线(363→361 条),本分支旧基线与 trusted base(origin/main)对比被判"上调"。合并结果按三方合并取 main 侧文件与基线,合入后即通过;属分支落后 artifact,不计入本 PR 缺陷 |
未执行:模拟器/真机运行验证(PR 已提供 2026-10-25 iOS 模拟器轨迹与 fps 对照证据,本次
审查未复跑);security-scan.mjs 重档扫描(standard 档不适用,security 门 0 命中)。
其它观察(不阻断):bot 静默期按 20 分钟超时放行(copilot / chatgpt-codex-connector 未对
当前 head 表态,迟到意见由 post-merge-sweep 兜底);Codex 汇总标记自称 b49fb85 上有未解决
findings,但其 review 状态为 failed 且 GitHub 上无对应未解决 thread(greptile P1 thread 已由
93fca8f 修复并 Resolve);UI 证据缺失提醒已按非阻断规则处理。
Intent alignment
- 描述来源:PR 当前 body(2026-10-25,含两轮修复后的验证说明);关联 #7053 合并后的模拟器
性能报告排查(无独立需求 issue,signoff 无讨论 issue)。 - 初始实现:
b49fb85f2ecb75f476648791185f2cc9aea40050(fix(mobile): keep list performance
sweep in history mode,基线e500a7f0d9721b26766ddd5e9e73e71ee3934254):listperf.tsx
8+/3- —— focusedItemKey 走真实消息定位进入历史模式、key={runKey}独立列表生命周期、
recycle 默认对齐正式列表。已实际读取该 revision 的 diff 核对。 - 现在要合什么:head
93fca8f7= 初始实现 +93fca8f757(cancel stale list performance
sweeps):effect 清理取消等待 timer 与扫描 rAF、runScrollSweep返回取消函数且取消后不
发布未完成测量、扫描闭包绑定本轮列表 API、新增真实组件回归测试 4 项、同步 guard 断言。
| 原目标/初始行为 | 最终行为与影响 | 代码/提交证据 | 变化依据或待确认问题 |
|---|---|---|---|
| 自动扫描不再被贴底跟随纠正回尾部(原始目标) | focusedItemKey 显式进入历史浏览意图,nearBottom=false,扫描全程不受 tail-follow 纠正 | b49fb85 apps/mobile/app/listperf.tsx(MessageRenderer 既有 focusedItemKey 路径,MessageRenderer.tsx:2746-2783) |
一致:围绕同一目标的实现 |
| 每个 run 独立、旧扫描不得写入新列表 | key={runKey} 重挂 + 清理取消 timer/rAF + scrollTo 闭包绑定本轮 api |
93fca8f listperf.tsx、scrollProfiler.ts |
一致:PR body 明示的缺陷修复 |
| recycle 默认与正式列表一致 | params.recycle === '1'(默认关),显式 recycle=1 仍可 A/B |
b49fb85;guard 断言在 93fca8f 同步 | 一致:修复 greptile P1(断言与默认值不同步),thread 已 Resolve |
结论:一致。两轮 Codex/Greptile 意见及修复(greptile P1:recycle 默认值改动使
messageNativeLifecycleContracts.test.ts:64 断言失效 → 93fca8f 同步断言并补回归)均围绕
原始目标,未删除/削弱/反转原承诺,无无关扩范围,未用禁用功能或绕开验证消除报错。核心
目标(测试驱动不与贴底跟随争抢滚动、run 间生命周期隔离)在最终 diff 中可核实落实。
Overall
pass —— 没有 P0/P1。原意一致性复核完成,无未裁定的核心方向问题。
|
合了。listperf 的自动扫描终于不用跟「跟随最新消息」抢滚动所有权,模拟器上的性能数据以后能直接采信;顺手补上的生命周期回归测试把这类挂载期竞态也钉住了,谢谢。 |
这次改了什么
摘要
修复 DEV-only
listperf自动滚动测试与“跟随最新消息”争夺位置的问题。旧测试从顶部扫描,却保持贴底意图;实际轨迹在请求 135 px 时被纠正回约 20,304 px,反复挂载列表两端,把测试自身的干扰算成业务卡顿。自动测试现在通过已有
focusedItemKey历史定位入口进入首条消息,再开始扫描;每个 runKey 使用独立列表生命周期。默认recycle=0与当前正式列表一致,显式recycle=1仍可做 A/B。离开页面或切换参数时,现在会取消等待计时器与滚动帧循环;扫描绑定本轮列表 API,旧扫描不能写入新列表。变更类型
fix缺陷修复范围
listperf、其scrollProfiler、对应原生生命周期 guard,并新增真实测试页面的生命周期回归。不修改正式消息列表、自动跟随控制器、缓存优化、原生配置或依赖。UI 变化
怎么验证的
自动验证
pnpm --filter mobile typecheck通过。listPerfHarness、messageNativeLifecycleContracts、messageScroll、messageTailFollower,95 项通过,2.22 秒。listPerfHarness.test.tsx:先红后绿(修复前 3 失败 / 1 通过,修复后 4 通过);独立运行 1.67 秒。真实组件 + 真实runScrollSweep,仅替换原生/路由端口,使用虚拟时钟。覆盖 settle 期间切换、运行中切换、卸载,以及连续运行与回收 opt-in;旧控制器测试未挂载测试页,因此漏掉这类生命周期问题。tier 为 unit。pnpm --filter mobile test:scope通过。git diff --check、pnpm check:test-hygiene(363 个文件)及pnpm check:dco(本 PR 2 个提交)通过。运行验证
2026-10-25,Apple M1 / 16 GiB / macOS 27.0.1,iPhone 18 Pro / iOS 27.0 Simulator,原生 Debug / Hermes。
工作树
cindy-performance-audit,分支fix/mobile-listperf-scroll-ownership;官方 whoami 验证 Metro :8081 归属和源码指纹e500a7f0d+05368c5fd7,已观察新 bundle 和模拟任务首页。该 dirty 指纹对应本提交的同一文件内容;原生指纹599a8b60981045ea119d52ab4a1842fbc10effbc匹配。最小复现:
listperf?turns=40&media=0&auto=1&vel=45&recycle=0。修复前 80 条场景重复解析 621–733 次,修复后 42–69 次。这里减少的是测试引入的往返渲染,不是正式 App 获得同等倍数提速。
2026-10-25 追加验证(93fca8f75)
mobileRuntimeIdentity()返回提交 93fca8f;诊断注入已清除。这些数据是测试驱动的重复性验证,不是产品性能提速比例。旧 head Windows CI 的两个失败位于未改动的 Desktop guestHost resume 测试;尚未证明根因或 Windows 通过。新 head 完整 CI、正式审批与正常合并门禁仍以实时结果为准。
最新 CI 结果(93fca8f75)
2026-10-25 主任务直接复核:client-ci 40153329646 已全部成功,包含 Linux/Windows 各四组、Windows runner/database、Desktop Git integration、verify-checks、verify 与 Windows 汇总;该 head 的 DCO、PR design-basis 也成功。旧 head 的 Windows resume 失败没有在此次运行重现,不据此宣称其根因已定位。
现有审阅线程全部解决;仍缺正式 Approve,当前账号上游 READ,等待维护者按正常规则批准/合并。模拟器与本地测试证据仍对应同一 head,边界保持上述说明。
未执行的验证
listperf本来就有 DEV-only 门禁。本轮先通过原生轨迹定位并消除测试干扰,没有为测试开放生产调试入口。media=1不代表每个富内容块均被完整验收。风险
风险分类
影响与回滚
提交前检查