Skip to content

fix(home-session-switch): 修复 Home 左栏 Sessions 单击无法切换的死链 - #544

Merged
ThreeFish-AI merged 3 commits into
feature/1.x.xfrom
ThreeFish-AI/fix-session-switch-click
May 16, 2026
Merged

fix(home-session-switch): 修复 Home 左栏 Sessions 单击无法切换的死链#544
ThreeFish-AI merged 3 commits into
feature/1.x.xfrom
ThreeFish-AI/fix-session-switch-click

Conversation

@ThreeFish-AI

Copy link
Copy Markdown
Owner

背景

  • 本次变更要解决的问题:Home 页 (/) 左栏 Sessions 列表单击会话条目后 URL 不更新、对话区被清空、顶部仍显示旧会话——出现「清空但未切换」错位状态,单击成为死链;该问题在 Next.js 16.2.3 dev 模式下用 mcp__chrome_devtools__clickelement.click()、手动 dispatchEvent(mousedown→mouseup→click) 三种触发方式均稳定复现。
  • 关联上下文/Issue/文档:docs/issue.md ISSUE-088;同源历史 ISSUE-061 v2-D(URL 单源派生)、ISSUE-062(stable deps)、ISSUE-066(router.replace 异步延迟下的 pending auto-send);memory feedback_router_replace_race.md

核心变更

  • 根因定位:通过 patch history.replaceState 抓包验证,Next.js 16.2.3 useRouter().replace(target, { scroll: false }) 在「同 pathname、仅 query 变更」场景下会输出 history.replaceState({__NA: true}, "", 旧URL) 的 no-op 路径——__NA 即 Navigation Aborted,浏览器 URL 不更新 → useSearchParams 不重派生 → sessionId/agent/activeSession 维持旧值,但 handleSessionChange 已同步执行 clearSessionState() 清空 projection,造成「清空但未切换」错位。
  • 最小干预修复app/page.tsxsetSessionIdfeatures/session/hooks/useSessionListService.tssetSessionListView 改走 window.history.replaceState(null, "", target) 直写浏览器 URL,绕开 Next.js 的 RSC 导航判定;由 Next.js 14+ App Router 中 useSearchParams 监听 history API 变更触发派生重渲染。移除两文件不再使用的 useRouter import 与 useCallback deps 中的 router
  • 作用面隔离:其他 router.replace 调用(admin/layout.tsxinterface/layout.tsxinterface/task-models/page.tsxinterface/models/page.tsx)都是 pathname 跳转,不在 bug 影响面,保持原样。
  • 单测同步迁移tests/unit/features/session/useSessionListService.test.ts 取消 routerReplace mock,改 spy on window.history.replaceState + 从真实 window.location.search 派生 useSearchParams;新增 ISSUE-088 双路径用例(archived / active)。
  • 文档沉淀docs/issue.md 追加 ISSUE-088 摘要(含 __NA: true 抓包证据、后续防范守则、与 061/062/066 的同源关联)。

风险与回滚

  • 主要风险:window.history.replaceState 不会触发 Next.js RSC fetch / route cache 刷新——本场景下 sessionId / view 都不绑定服务器渲染段(数据全靠客户端 fetch),因此无影响;如未来某入口同型迁移时其依赖 RSC 重渲,需要保留 router.replace 走 pathname 级跳转。
  • 回滚方式:git revert <commit> 即可,仅触及 4 文件、零迁移;回滚后回到「router.replace + __NA no-op」状态(即修复前 bug)。

验证证据

  • 单元测试:pnpm --filter negentropy-ui test 全量 87 test files / 644 tests 全绿;其中 useSessionListService.test.ts 新增「ISSUE-088 archived / active 双路径」断言验证 window.history.replaceState 调用形状与 window.location.search 落盘。
  • 集成测试:pnpm --filter negentropy-ui test -- home-flow 全绿(未 mock router,使用注入 setCurrentSession 装具,与本次 wiring 改动正交)。
  • E2E/Workflow:未涉及 Playwright e2e。Lint / typecheck / typecheck:test 三线全绿。
  • 覆盖率/关键截图:实机用户主 Chrome 真实登录态走 7 个正交场景全部通过:①初始单击切换 → URL/active 高亮/对话区/State Snapshot/Event Timeline 同步刷新;②连续切换 B→C→D(3 次直写 + 0 次 NA 残留旧 URL);③回到原会话内容完整还原;④Archived 视图切换(?view=archived 入出);⑤双击重命名(onClick + onDoubleClick 双 handler 共存正常);⑥刷新保持 sessionId;⑦+ New 创建新会话并展示空态。每个场景 window.__historyCalls 抓包显示我们的直写均为 naFlag: null + 正确新 URL,无 __NA: true 残留。

影响范围

  • 前端:apps/negentropy-ui/app/page.tsxapps/negentropy-ui/features/session/hooks/useSessionListService.tsapps/negentropy-ui/tests/unit/features/session/useSessionListService.test.ts
  • 后端:无。
  • GitHub Actions / 文档:docs/issue.md 追加 ISSUE-088 摘要;无 CI 配置变更。

Next Best Action

  • 合入后,可以把同样的「同 pathname + 仅 query 变更」模式抽成一个共享 hook(例如 useUrlQueryUpdater())放到 apps/negentropy-ui/hooks/,让后续 Knowledge / Memory / Interface 页加入 ?tab=... / ?filter=... 入口时直接复用,避免每个新入口都踩同一个 Next.js 16 router.replace 坑。

- 表因:Home 页左栏单击会话条目后 URL 不更新、对话区被清空、顶部仍显示旧会话——出现"清空但未切换"错位。
- 根因:Next.js 16.2.3 useRouter().replace(target, { scroll: false }) 在「同 pathname、仅 query 变更」场景下会输出 history.replaceState({__NA: true}, "", 旧URL) 的 no-op 路径,浏览器 URL 不更新→useSearchParams 不重派生→sessionId/agent/activeSession 全部维持旧值。
- 处理:app/page.tsx 的 setSessionId 与 useSessionListService 的 setSessionListView 改走 window.history.replaceState 直写浏览器 URL,由 Next.js 14+ App Router 中 useSearchParams 监听 history API 触发派生重渲染;移除两文件不再使用的 useRouter import;单测同步迁移到 spy on window.history.replaceState + 从 window.location.search 派生 useSearchParams,新增 ISSUE-088 / ISSUE-061 v2-D 两条断言。
- 验证:pnpm lint / typecheck / typecheck:test / 644 项单元 + 集成测试全绿;实机用户主 Chrome 真实登录态走 7 个正交场景(初始单击 / 连续切换 / 回到原会话 / Archived 视图切换 / 双击重命名 / 刷新保持 / + New),URL、active 高亮、对话区、State Snapshot、Event Timeline 全链路同步刷新,全部 __NA: true 痕迹消失。
- 文档:docs/issue.md 追加 ISSUE-088 摘要(含 __NA 抓包证据 + 后续防范 + 与 ISSUE-061/062/066 同源关联)。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
…后的相对链接;

合并 origin/feature/1.x.x 后 issue.md 被搬迁到 docs/agents/,
将本期新增 ISSUE-088 中 `../apps/...` 与 `./agents/browser-validation.md`
分别修正为 `../../apps/...` 与 `./browser-validation.md`,恢复跳转有效性。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
@ThreeFish-AI
ThreeFish-AI merged commit 933af0f into feature/1.x.x May 16, 2026
6 checks passed
@ThreeFish-AI
ThreeFish-AI deleted the ThreeFish-AI/fix-session-switch-click branch May 17, 2026 06:02
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.

1 participant