Skip to content

fix(mobile): 修复生产构建环境并减少列表手势和聊天重复更新 - #7083

Merged
MagicLizi merged 2 commits into
mainfrom
dash/mobile-render-fanout
Oct 24, 2026
Merged

MagicLizi merged 2 commits into
mainfrom
dash/mobile-render-fanout

Conversation

@dashhuang

@dashhuang dashhuang commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

这次改了什么

摘要

修复手机版首页、任务和聊天卡顿的三条已确认路径:Release 构建夹带动画调试代码、列表更新/旋转时反复重建手势,以及无关任务更新引发正文和列表重复计算。

留存的较早 Release bundle 没有 Worklets 调试 Error,新测试包在 __DEV__=false 下却有 711 处 new global.Error()、682 处动画内嵌 source map。真实 Expo/Metro transform 回归重现了 NODE_ENV/BABEL_ENV=development 污染 Release 输出。现在按 Metro 请求的 dev 标志隔离同步 transform,并在正式打包入口明确 production;反向的开发构建仍保留调试信息。

同时移除详情页无用的全任务订阅,让 Markdown 只观察引用任务的标题,稳定待发送操作回调;标题和时间更新只重算当前任务,避免触发全任务保留扫描和消息时间重锚定。真实 store 的 1,000 任务、30 次更新时间回放中,比较次数 30,060→90,重锚定 30,000→30。此为 Mac 合成回放,不代表 iPhone 提速倍数,也不能据此宣称全部卡顿已消除。

继续排查返回首页和连续旋转后,定位到项目拖动 worklet 捕获整个项目(含任务树),以及项目/任务行回调和 hitSlop 引用反复变化,导致 RNGH 重建和序列化手势图。项目拖动改为只捕获 key、sessionCount;行手势回调保持稳定,通过 layout effect 更新当前任务及宽度,保留最新归档、已读和新建行为。真实设备的有界堆栈采样中,32 个 setter 样本有 24 个来自 RNGH updateHandlers。用户安装最后一轮修复后确认连续旋转明显顺畅。

变更类型

  • fix 缺陷修复
  • refactor / perf 性能优化
  • docs / test 文档与回归验证

范围

  • 关联需求:排查手机首页、打开任务和聊天卡顿,区分新构建问题与既有更新放大。
  • 包含:Mobile 订阅、元数据 patch、队列操作引用、列表手势捕获及回调、Metro 编译环境、正式构建环境和相关测试。
  • 不包含:原生依赖升级、协议或权限变化、诊断探针。
  • 用户可见变化:减少任务更新和旋转时的卡顿;无关任务更新不再刷新当前正文;生产包不再创建动画调试堆栈。
  • breaking change:无。

UI 变化

  • 引用的设计规范:不涉及:改动命中 UI 代码,但只减少重复计算并稳定订阅和回调,无视觉、交互或文案变化。

怎么验证的

自动验证

env -u NODE_ENV -u NODE_DEBUG -u CLAUDE_CODE_IDE_SKIP_AUTO_INSTALL -u CINDY_INPUT_HANDOFF_ROUTE node scripts/test-workspaces.mjs --tier unit --workspace apps/mobile
结果:最新修改后的 Mobile 完整 unit 通过(63.7s)。

pnpm --dir apps/mobile exec vitest run src/__tests__/{PendingSendBubble.touch,swipeableProjectHeader,swipeableSessionRowIos}.test.tsx
结果:3 文件 51 项通过(1.69s);手势回调身份回归在修复前失败。

pnpm --dir apps/mobile exec vitest run src/__tests__/{optimisticSessionComposer,sessionSwipe,swipeableSessionRowLifecycle}.test.ts
结果:3 文件 74 项通过(1.94s)。

pnpm --filter mobile typecheck
pnpm --filter mobile test:scope
node --test scripts/__tests__/client-endpoint-build-env.test.mjs
node --test scripts/__tests__/dev-docs-contract.test.mjs
pnpm check:test-hygiene
pnpm check:dco
git diff --check
结果:通过;构建环境 7 项、文档合同 10 项。

node apps/mobile/scripts/ci-fingerprint.mjs compute --output <report>
结果:base 325a1a8520 与 HEAD 在同一本机环境分别计算;iOS、Android hash 均相同。

run-unit-gate.sh <worktree>  # 内部运行 pnpm test:unit
首轮:28 个 workspace unit 通过,包括 Mobile 完整单测(58.3s);
Desktop Vitest 进程 SIGSEGV,无断言失败;门禁自动复跑一次仍以相同故障结束。

env -u NODE_ENV -u NODE_DEBUG -u CLAUDE_CODE_IDE_SKIP_AUTO_INSTALL -u CINDY_INPUT_HANDOFF_ROUTE node scripts/test-workspaces.mjs --tier unit --workspace apps/desktop
干净 base 325a1a8520 对照:同样在 Desktop Vitest 出现 SIGSEGV,无断言失败。
已归类为本机/基线测试进程问题,未把整仓门禁写成全绿;由 CI 继续验证。

测试价值(均为 unit tier,经过真实入口,边界设备组件按需替代):

测试文件 缺口、最小失败输入与观察结果 单文件耗时
mobileBabelTransform.test.ts 配置中的真实 Expo transformer 编译并执行一个 worklet;Release 继承 development、开发构建继承 production,断言调试元数据及环境恢复;修复前两项失败 0.519s
PendingSendBubble.touch.test.tsx 直接导入页面使用的生产 hooks 并挂载真实气泡;30 次更新、同 client ID 切换任务后的 retry/edit、busy 更新;恢复每次新建 retry 回调时测试失败。删除原源码拼装 Probe 测试 2.47s
swipeableProjectHeader.test.tsx 真实项目行跨宽度和项目更新保持手势回调及 hitSlop 稳定,动作使用最新项目与阈值;修复前失败 1.52s
swipeableSessionRowIos.test.tsx 同 ID 新对象、旋转、行复用后回调稳定且动作使用当前任务与阈值;修复前失败 1.21s
homeAutomationWindow.test.tsx 用真实 Worklets Babel 插件编译生产拖动回调,断言只捕获标量、不读取项目任务树;修复前失败 1.74s
markdownBlockContent.test.tsx 真实 store 推送 30 次无关任务变更,正文不重渲染;关联标题更名、移除、恢复和链接目标变化仍生效;纯文本不订阅 2.26s
homeListPatchWhileCovered.test.tsx 覆盖中的链接标题冻结;恢复页面后无额外列表请求即看到更名,移除预览取消后重新出现 1.64s
remoteSessionStore.test.ts 同 ID 两个来源,旧来源 patch 不覆盖权威来源;隐藏预览、标题/时间/用量混合 patch 不破坏首页投影与其他行引用 1.81s
client-endpoint-build-env.test.mjs 正式打包入口收到 development 环境,输出固定 production 且不修改父对象;区域端点选择保持原语义 0.126s

手工验证

  • 实现分支 dash/mobile-render-fanout;worktree cindy-src-mobile-render-fanout。
  • iPhone 并装测试应用使用原 Duo 的精确 JS 基线 2e8a8a052d4d,在独立 cindy-mobile-perf-validation 中叠加本 PR 修改,保留登录和数据。
  • 内嵌生产 bundle,未启动 Metro;bundle 中 __DEV__=false。故意让完整 export 继承 development 环境,修复产物仍为 0 处调试 Error、0 处内嵌动画 source map。
  • 用户手动验证旋转、进入任务、返回首页:先修项目捕获后整页冻结未再反馈,但快速连续旋转仍卡;稳定行手势后确认连续旋转明显顺畅。
  • 最后一轮带计时诊断的 85 秒记录包含 78 次 geometry 通知、5 次导航;空闲时重复手势更新明显减少。不过快速旋转中仍记录到 1.922s、1.118s 两次 JS stall。不同操作强度及探针开销无法严格分离,不把该轮写成零停顿,也不据此宣称整体分配率下降。
  • 随后安装同版无临时探针的生产构建。11:35:04–11:37:38 的 215 条记录无 JS stall、warn/error;该窗口主要为首页运行,没有覆盖同强度连续旋转。系统崩溃列表没有 10:35:36 之后的新 Cindy crash。
  • 诊断过程中,仓库外早期临时探针曾造成启动约 20 秒后 fatal JS 异常;已撤除。这是诊断失误,不归因于用户原有问题。所有临时探针均未进入本 PR,当前安装包也不包含它们。

未执行的验证

  • 尚未验证 Android 真机、长期连续使用及干净构建同强度快速旋转;没有声称所有自然操作下的内存分配率或卡顿均已改善。首次返回首页右侧空白的单张截图未独立复现,用户后续反馈恢复正常。
  • 没有新增视觉变化,因此不提交截图;原始设备日志和诊断包仅留本机。

风险

风险分类

  • 其他:订阅粒度、元数据更新捷径、手势回调生命周期及 Babel 环境隔离。
  • 原生层 / fingerprint / OTA:两个平台实测指纹均不变,无本 PR 导致的冷更。

影响与回滚

  • 影响范围:Mobile;构建环境入口覆盖 iOS/Android。同步 transformer 使用 try/finally 恢复父环境,开发模式有反向回归覆盖;状态/来源等结构字段保留原全量重算。
  • 回滚方式:回退本 PR 提交并重新导出 JS bundle;无需迁移或清理用户数据。
  • 存量插件影响:无。

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名
  • UI 变化已说明不涉及的理由
  • 未提交凭证、令牌或授权文件
  • 构建环境开发文档已同步
  • 已确认测试结果或说明未执行原因

Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
@dashhuang
dashhuang requested a review from a team as a code owner October 24, 2026 21:52
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-24T22:43:19.334541Z 0d4867e Draft marked ready
🔒 Security Review ✅ Completed 2026-10-24T22:43:21.628383Z 0d4867e Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@greptile-apps

greptile-apps Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] 本轮未发现阻止合并的新问题。

Summary

本 PR 修正 Mobile 正式构建的编译环境,并减少列表手势和聊天正文的重复更新。本轮重点检查上次审查后的回调抽取、手势引用稳定化和回归测试调整,未发现需要新增评论的问题。

  • Home drag and swipe gestures stay stable as task rows change.
  • Task metadata patches update one task without rebuilding the full list.
  • Markdown task links follow only the titles they show.
  • Pending-send actions stay stable and use the current task.
  • Release bundles use production settings even from a development shell.

Reviews (2) · Last reviewed commit: "fix(mobile): 稳定列表手势并通过真实入口验证待发送操作" · Reviewed by Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 963b3f1e73

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/mobile/src/__tests__/pendingSendActionsRender.test.tsx Outdated
@dashhuang
dashhuang marked this pull request as draft October 24, 2026 22:03
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
@dashhuang dashhuang changed the title fix(mobile): 隔离生产构建环境并减少任务更新重复渲染 fix(mobile): 修复生产构建环境并减少列表手势和聊天重复更新 Oct 24, 2026
@dashhuang
dashhuang marked this pull request as ready for review October 24, 2026 22:39
@MagicLizi MagicLizi added touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:rules 改动碰到规则 / 规范文档(review-pr 自动维护,仅展示) touches:security 改动碰到安全边界(review-pr 自动维护,仅展示) labels Oct 24, 2026
@MagicLizi

Copy link
Copy Markdown
Contributor

PR #7083 独立代码审查报告(heavy 档)

Findings

  • 无可证实的 P0/P1。P2 级观察不报告、不阻断。

重点核验(均通读实现与调用方后排除问题):

  1. remoteSessionStore.applySessionPatch 新增的元数据快路径(title/updatedAt/userSendAt+usage):
    • 非 status、非 pinnedAt 的 patch 不可能触发 historyTurnEnded(只看 lastTurnEndedAt)
      或 unpinned reseed(只看 pinnedAt),跳过 recomputeSessions 不吞事件;
    • bindPendingHostAnchorSendAt + reanchorPendingLiveAssistantRows(..., { consumePending: false })
      与全量路径逐字一致;非 canonical shard 的 patch 只写物理分片、不进 merged 投影,与
      usage 快路径同口径;retentionForSession 只依赖 source+详情态,元数据字段不可能造成
      留存档位迁移被跳过。
  2. useRemoteSessionTitles / useMarkdownSessionLinkTitles:以 JSON 字符串做原语快照,无关
    推送不重渲染;复用 RemoteSessionStoreSubscriptionGate 冻结语义(covered 页面不追更);
    纯文本不订阅(NOOP_SUBSCRIBE)。旧实现读 useRemoteSessions()(visible)语义等价。
  3. 手势稳定化(SwipeableProjectHeader / SwipeableSessionRow.ios / HomeSurface ProjectRow):
    latest-ref + useLayoutEffect 模式,回调只在 close(稳定 useCallback)变化时重建;
    读 gestureInputs.current 保证动作用最新任务/宽度/阈值;拖动 worklet 只捕获
    key/sessionCount/displayTitle 标量,不再递归序列化项目任务树(回归测试用抛异常的
    sessions 哨兵验证)。
  4. usePendingSendActions / usePendingOutboxActions 抽取:与原内联实现逐行等价(retry/remove
    确认弹窗、creation-recovery 门槛、unsent 取消口径均保留),依赖数组覆盖全部闭包变量
    (beginQueueEdit 仅使用 pendingUploads.length,deps 即 .length,与既有代码同口径)。
  5. babel-transformer.js + metro.config.js:metro-babel-transformer 的 transform 是同步
    函数,且其自身 BABEL_ENV 处理正是泄漏源(dev=false 时保留父进程 BABEL_ENV);包裹层
    按请求 dev 标志同步置 NODE_ENV/BABEL_ENV 并 try/finally 恢复,方向正确且无跨请求泄漏窗口。
  6. client-endpoint-build-env.mjs 固定 NODE_ENV/BABEL_ENV=production:调用方仅
    build-ios.mjs / build-android.mjs(可安装 Release 包),不影响 dev 端点选择语义,
    与新增文档表述一致。
  7. 冷更边界:未触碰 app.json / app.config.js / eas.json / apps/mobile/package.json / plugins /
    modules / 原生目录;作者以 ci-fingerprint.mjs compute 对 base 与 HEAD 分别实测 iOS/Android
    指纹相同,无本 PR 导致的冷更。

Rule coverage

  • AGENTS.md(仓库边界、DCO、安全底线):仅 apps/mobile + scripts/docs;两个 commit 均带
    Signed-off-by 且与 author 一致;无凭证/密钥落盘。
  • docs/dev-rules/development-workflow.md(PR 契约、验证真实性、P0/P1/P2):Description 三大段
    齐全、验证命令可复核,本机 Desktop Vitest SIGSEGV 如实标注为基线问题未写成全绿。
  • docs/dev-rules/mobile-development.md(含「冷更边界」):见上述第 7 条;本 PR 对该文档的
    新增段落(Release 必须 NODE_ENV/BABEL_ENV=production)与代码实现互证成立。
  • docs/dev-rules/remote-and-mobile-adaptation.md Review 清单:①无 workdir/agent/会话数据
    远程通道改动(纯客户端渲染/订阅);②无新 IPC/推送;③本 PR 即手机版且有回归测试;
    ④Description 范围段逐项给出「不包含」及理由;⑤未触及 device-link 重试/超时/断链恢复,
    无故障半径三问要求。
  • DESIGN.md / docs/design-rules/cindy-design-system.md:命中 UI 路径但 diff 无视觉、
    交互、布局或文案改动(仅回调身份与订阅粒度),无可对照的视觉违规;UI 证据缺失属非阻断
    提醒范围。
  • 固定问题 1–9:单一目的(手机卡顿三条路径)、共享符号(store/hook/回调)读方与错误路径已
    追踪、无权限/凭证/协议变化、无新增依赖与危险写法进生产、Mobile 路径有真实测试证据、
    无流程塞进 Core、UI 证据缺失不阻断、无 fingerprint 变化、0 P0/P1。

Verification

实际运行(均在审查 worktree,退出码如实记录):

  1. node --test scripts/__tests__/client-endpoint-build-env.test.mjs → exit 0,7/7 通过
    (覆盖 NODE_ENV/BABEL_ENV 固定与父环境不被修改)。
  2. pnpm --dir apps/mobile exec vitest run <本次改动的 9 个测试文件> → exit 0,
    9 files / 432 tests 全部通过(含 mobileBabelTransform、PendingSendBubble.touch、
    homeAutomationWindow、homeListPatchWhileCovered、markdownBlockContent、
    optimisticSessionComposer、remoteSessionStore、swipeableProjectHeader、swipeableSessionRowIos)。
  3. pnpm --filter mobile run typecheck → exit 0,无类型错误。
  4. node scripts/test-workspaces.mjs --tier unit --workspace apps/mobile(作者同款命令)→
    PASS apps/mobile unit(57.0s),退出码 0。
  5. heavy 安全扫描 node scripts/security-scan.mjs --base 325a1a8520eab7157b67441c6a4725e2f54960f5
    → 依赖漏洞扫描:本 PR 未新增依赖,无需扫描;静态扫描(semgrep,仅新增):0 条。
    注意:semgrep 对 apps/mobile/src/__tests__/swipeableProjectHeader.test.tsx:76 有一条
    TSX 泛型语法解析错误,该文件未被部分规则覆盖,已人工通读确认无问题。
  6. 依赖安装为 pnpm install --frozen-lockfile --ignore-scripts(本地 store 命中,8.1s)。

heavy 恶意代码/数据外发专项:signoff.triggers[kind=security] 的 3 处 dynamic-eval 全部位于
本次新增/修改的测试文件(测试内 new Function 执行 Babel 编译产物、加载配置指定的
babel transformer),不进入生产 bundle;newDependencies 为空、lockfile 未动、无 install
钩子、无新增网络或数据流向。结论:非恶意、无外发。

未执行项(如实声明):全仓 pnpm test:unit(改动面全在 apps/mobile 与 scripts,已由本地
mobile 全量单测 + CI client-ci 全绿覆盖);Android 真机与视觉证据(本 PR 无视觉变化,
作者实机验证记录在 Description;UI 证据缺失走非阻断提醒)。

Intent alignment

  • 描述来源:PR 标题与当前 body(2026-10-24T23:26Z 读取);无关联需求 issue,
    signoff.discussionIssue 为空(维护门由 zqchris 的 GitHub Approve 放行,无待落实讨论要求)。
  • 初始实现:963b3f1e73ffc8baa3271674b0ea16b209a95dd1(base 325a1a8,
    构建环境隔离 + 减少任务更新重复渲染);第二批次 0d4867e
    (列表手势稳定 + 真实入口回归)。已实际读取两个提交的完整 diff 与待合并 head。
原目标/初始行为 最终行为与影响 代码/提交证据 变化依据
Release 包不再混入 Worklets 调试堆栈(环境隔离) 保持;补 mobileBabelTransform/client-endpoint-build-env 回归 963b3f1 apps/mobile/babel-transformer.js、metro.config.js、scripts/shared/client-endpoint-build-env.mjs 同一目标的缺陷修复与回归补强
无关任务更新不再重算正文/列表 保持;元数据快路径 + 链接标题收窄订阅 963b3f1 apps/mobile/src/session/remoteSessionStore.ts、useMarkdownSessionLinkTitles.ts 同一目标
列表更新/旋转不重建手势 0d4867e 引入(第一批次未含),行/项目手势回调稳定 + worklet 标量捕获 0d4867e SwipeableProjectHeader.tsx、SwipeableSessionRow.ios.tsx、HomeSurface.tsx PR body 明确的第三条修复路径,同一目标的第二批次
测试须经真实生产入口(Codex P2) 删除源码拼装 Probe 测试,抽取 usePendingSendActions/usePendingOutboxActions 生产 hooks 并由真实气泡挂载回归 0d4867e usePendingSendActions.ts、PendingSendBubble.touch.test.tsx;thread https://github.com/makecindy/cindy/pull/7083#discussion_r4368656178(已 Resolve) 测试可靠性整改,逻辑逐行等价搬运,无产品方向变化

结论:一致。核心目标(三条卡顿路径 + 生产构建环境)在最终 diff 中全部保留且有回归覆盖;
Codex P2 与 Greptile(无新增问题、confidence 5/5)意见均未改变原目标。无确认偏离、无需裁定项。

Overall

pass —— 没有 P0/P1。原意一致性复核通过,建议合并。

@MagicLizi
MagicLizi merged commit 5e04b5a into main Oct 24, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:rules 改动碰到规则 / 规范文档(review-pr 自动维护,仅展示) touches:security 改动碰到安全边界(review-pr 自动维护,仅展示)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants