docs(tasks): 侧栏统一进度记录、BUG-744~746、真机清单与 CHANGELOG

`PROGRESS-sidebar-unify-20260916.md` 记基线与改后的 tsc / lint / 测试总数 /
失败清单 diff / 五个路由标记 / gzip,逐条列改过的既有断言、触发的让步顺序
(T5 第 1 条)、次级页体积增加的原因,以及无 Chrome 无登录态的环境缺口。
`docs/testing/sidebar-unify-20260916.md` 是七组可照做的真机条目。
状态板本单一行改「待验收」,执行分支 `codex/sidebar-unify-20260916`。

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
This commit is contained in:
Jesse_Chen
2026-09-16 11:23:43 +00:00
co-authored by Claude Fable 5.1
parent fb77c86585
commit 22edabbcd3
5 changed files with 255 additions and 1 deletions
+49
View File
@@ -11615,3 +11615,52 @@
- 复发自:无
- 修复版本:无
## BUG-744 | 侧栏写成两套标记,次级页会话行与页脚跟首页长得不一样
- 状态:resolved
- 首次发现:2026-09-16
- 最近更新:2026-09-16
- 影响面:`frontend/src/components/app-sidebar.tsx`、已删除的 `app-nav-rail.tsx``frontend/src/components/sidebar-session-row.tsx``frontend/src/app/globals.css`
- 用户现象:staging 真机上,`/` 的侧栏和 `/chart``/ephemeris``/reports` 的侧栏不是同一个东西——会话行的高度、内边距、当前项标记都对不上,页脚一个 56px 一个 44px。
- 触发条件:从 `/` 走到任一次级页,对比左侧同一列。
- 根因:次级页侧栏当初为了不把 `Home()` 的会话管理层上提,另写了第二个组件。它的会话行是 `<Link className="session-row nav-rail-row">` 直接套 `.session-title`**没有 `.session-main` 这一层**,因此丢掉了 `padding: var(--space-2)``min-height: 44px``.session-main[data-active="true"]::before` 的 2px 当前项标记;而 `.session-row``grid-template-columns: minmax(0, 1fr) 44px` 仍给一个从不渲染的菜单按钮留着 44px 空列。页脚另起 `.nav-rail-identity`(44px flex,带「N 点」),与 `/``.profile-trigger`56px grid、带 chevron)并列存在。产品要的是「不带写操作」,从来不是「长得不一样」;分叉是实现手段的副作用。
- 修复:`AppSidebar` 收编第二个组件——会话操作与账户菜单收进可选的 `controls`,不传就渲染只读模式:会话行仍是同一个 `SidebarSessionRow`、同一套 `.session-row > .session-main` 标记,只是 `.session-main``<Link>`、不渲染菜单按钮、并用 `data-readonly="true"` 去掉那一列 44px 空位;页脚是同一个 `.profile-trigger`,渲染成去 `/` 的链接,不带 chevron、不带菜单。`app-nav-rail.tsx``.nav-rail-*` 两段 CSS 删除。只读模式**只**少菜单按钮、chevron、账户菜单三样。
- 验证:`frontend/tests/sidebar-contract.test.ts` 新增「the same component renders read-only when `/` is not the one mounting it」,锁 `controls?` 可选、只读行带 `.session-main`、只读行不含 `session-menu-trigger``.session-row[data-readonly="true"]` 不留 44px 列、页脚是 `.profile-trigger` 链接;`grep -rn "AppNavRail\|nav-rail" frontend/src` = 0。改过的既有断言逐条写在 `docs/tasks/PROGRESS-sidebar-unify-20260916.md`
- 防复发:产品里只有一个侧栏组件。再要一个「只读侧栏」必须走 `controls` 缺省,不得新建第二个组件或第二套类名;合同测试锁住「只读模式只少三样」。
- 相关记录:BUG-711、BUG-438
- 复发自:无
- 修复版本:待发布
## BUG-745 | 首页进次级页整页刷新,次级页外壳逐页重挂,每跳一次重拉会话列表
- 状态:resolved
- 首次发现:2026-09-16
- 最近更新:2026-09-16
- 影响面:`frontend/src/components/app-sidebar.tsx``frontend/src/app/(secondary)/layout.tsx``frontend/src/hooks/use-sidebar-data.ts``frontend/src/lib/sidebar-data-cache.ts``frontend/src/hooks/use-session-management.ts``frontend/src/app/page.tsx`
- 用户现象:每进一次次级页,侧栏的会话列表都要重新读一遍;从次级页点「新建对话」回首页要等很久。
- 触发条件:`/``/chart``/chart``/ephemeris``/reports`
- 根因:三件事叠加。① 侧栏的 `leaveChat()``window.location.assign(path)`,首页出去是整页刷新,React 树与内存全部清零。② `app/` 下没有把四个次级路由包起来的 layout,三个页面各自在组件内部渲染 `SecondaryShell`,每份都挂一套 `SidebarProvider + 侧栏`,因此**即便是客户端跳转**外壳也整个重挂,数据 hook 的 effect 重新 `GET /api/sessions?limit=40` + `GET /api/account`。③ 这两个读没有任何缓存。
- 修复:① 三个页面项改 `<SidebarMenuLink href=…>` 客户端跳转,`persistLoginSessionReturn()` 保留在 `onClick` 里,`/login` 仍是硬跳转;顺带删掉从来没被调用过的死 prop `onOpenReports`(侧栏里解构成 `_onOpenReports`),它删掉后 `page.tsx``router` 再无消费者,`useConsultationRun` 那个同样解构成 `_router` 的死参数一并删。② 四个路由移进 `app/(secondary)/` 路由组,`layout.tsx` 承载 `SidebarProvider + AppSidebar(只读) + SidebarInset`,URL 与四个渲染标记均未变。③ 模块级按账户 id 键的 60 s 缓存,同步读、后台刷新;`/` 上新建 / 重命名 / 删除 / 归档 / 收藏成功后调 `invalidateSidebarCache()`401 清空。不落 localStorage。
- 验证:`frontend/tests/sidebar-data-cache.test.ts` 4 条(命中不重拉、过期重拉一次、写操作后拿到新标题、双账户不串、只存内存、401 清空);`frontend/tests/chart-page-view.test.tsx` 新增「the (secondary) layout mounts one read-only sidebar for all four routes」;`next build` 四个路由标记与基线逐个一致(`/chart` `○``/ephemeris` `○``/reports` `ƒ``/reports/[reportId]` `ƒ`),`/``○`。浏览器级证据(Network 面板没有 document 请求、跨页没有 `/api/sessions`)无 Chrome 无登录态做不了,写成 `docs/testing/sidebar-unify-20260916.md` 的真机清单。
- 防复发:次级页不得再在组件内部挂第二份 `SidebarProvider`;合同测试锁 layout 里 `<SidebarProvider>` 恰好一次、且不传 `controls`。侧栏源码里不得再出现 `window.location``/login` 的硬跳转在 `page.tsx``use-billing-panel.ts`,由 `chat-navigation-a11y-contract` 守)。
- 相关记录:BUG-744、BUG-746
- 复发自:无
- 修复版本:待发布
## BUG-746 | 侧栏折叠状态不跨页保留,每换一页又展开
- 状态:resolved
- 首次发现:2026-09-16
- 最近更新:2026-09-16
- 影响面:`frontend/src/components/ui/sidebar.tsx``frontend/src/lib/sidebar-state.ts`
- 用户现象:在 `/` 把侧栏收起来,进 `/chart` 又是展开的;反过来也一样。
- 触发条件:桌面或平板宽度下收起侧栏,然后换一页。
- 根因:`SidebarProvider``defaultOpen` 只活在内存里,`ready` 之后一律回到 `defaultSidebarOpen(viewport)` 的断点默认值,没有任何持久化。以前四个次级页各挂一份 provider,跳一次就重置一次。
- 修复:`readStoredSidebarOpen` / `writeStoredSidebarOpen` 落在 `localStorage``sidebar_state` 键;`commitOpen` 每次显式切换时写入,`ready` 的那个 effect 用 `readStoredSidebarOpen(viewport) ?? defaultSidebarOpen(viewport)` 取值。移动端抽屉不读不写。
- 验证:`frontend/tests/sidebar-state.test.ts` 新增两条——收起后重挂仍收起(含无存储 / 存了脏值 / 存储不可用三种降级)、移动端不读不写且 `null` 存储不抛。
- 防复发:不得改用需要服务端读取的 cookie:`/``/chart``/ephemeris` 都是 `○ Static`,服务端读 cookie 会让三条路由一起掉出静态渲染。
- 已知缺口(不得写成已解决):读取发生在挂载后的同一个 effect 里,也就是断点默认值原本就生效的那一帧。对一个把侧栏收起来的桌面用户,**整页加载**时首帧仍是展开、随后收起,这是让步顺序第 1 条,任务书允许。客户端跳转(`/` ↔ 次级页)不受影响,因为 provider 不重挂或重挂时 `localStorage` 已可读。
- 相关记录:BUG-745
- 复发自:无
- 修复版本:待发布