fix(web): 无用户行钉顶、闲置不上留白,并修会话列表 tsc 两错
Independent Staging Quality Gate / validate (push) Failing after 6m27s
Independent Staging Quality Gate / publish (push) Skipped

This commit is contained in:
jesse-ux
2026-09-17 22:25:53 +08:00
parent b5e16b96f4
commit cc1a89802e
8 changed files with 135 additions and 16 deletions
+34 -2
View File
@@ -12143,8 +12143,40 @@
- 触发条件:主会话或生时校正发出一轮,模型输出超过一屏。
- 根因:跟随语义是「贴底」。`anchored` 初值为真,`ResizeObserver` 在内容变高时把 `scrollTop` 设到 `scrollHeight``send()` 还会 `anchorToLatest()`。对短回答两者等价,对长回答则把开头推出视口。
- 修复:同一 hook 改为新一轮把本轮开头(用户行,或没有用户行时的新助手行)钉在滚动容器顶部,流式期间不再跟随。回答长出视口时用已有的「跳到最新」贴底并恢复跟随。末尾动态留白让短回答也能把开头留在顶部。切换会话仍先落底。取代 BUG-041 / BUG-048 的贴底语义。
- 验证:`chat-notice-and-scroll-contract.test.ts` 源码合同与行为测试;校正面 `pinLatestTurn` 三处源码断言。
- 验证:`chat-notice-and-scroll-contract.test.ts` 源码合同与行为测试;校正面 `pinLatestTurn` 三处源码断言。验收方用 Chrome 真实布局骨架页跑过 S1–S4(长历史发问钉顶、短历史留白、先上滑再发问、切会话落底)。S5/S6 见 BUG-931 / BUG-932。
- 防复发:跟随只经 `useConversationScrollAnchor`,跳到最新只经 `JumpToLatestButton``send()` 必须调 `pinLatestTurn`;校正面新轮只在提交文字、点选项、开场/无用户行助手到达时各 pin 一次。
- 相关记录:BUG-478、BUG-041、BUG-048
- 相关记录:BUG-478、BUG-041、BUG-048、BUG-931、BUG-932
- 复发自:无
- 修复版本:待发布
## BUG-931 | 无用户行的一轮钉不住,随后退回贴底跟随
- 状态:resolved
- 首次发现:2026-09-17
- 最近更新:2026-09-17
- 影响面:`useConversationScrollAnchor` `applyTurnSpacer` / `pinLatestTurn`;生时校正点选项、开场、自动续轮
- 用户现象:点选项或开场后新助手行不在顶部;流式一开始视口又钉到最后一个字。
- 触发条件:本轮没有 `.message-user``pinLatestTurn()` 钉的是最后一条 `.message-assistant`
- 根因:最后一条助手行同时是 turn head 和留白承载。`applyTurnSpacer``head.offsetHeight``--latest-turn-head-height`,量到的是「内容 + 上一帧留白」,公式自指后 `min-height` 坍成 0`scrollTo` 被夹住。随后 `distance ≤ 96` 解除 `holdUnpin``anchored` 翻回真。
- 修复:head 与 `lastTurnTail` 是同一元素时 `--latest-turn-head-height``0px`,该行 `min-height` 等于整个视口。选这一路而不是先 `clearTurnSpacer` 再量,是因为清变量后仍要等一次布局,`offsetHeight` 在同一帧里不可靠。
- 验证:`chat-notice-and-scroll-contract.test.ts`「a turn with no user row…」。
- 防复发:无用户行时 spacer 头高必须是 0;pin 后增高不得把 `anchored` 翻回真。
- 相关记录:BUG-930
- 复发自:无
- 修复版本:待发布
## BUG-932 | 闲置会话上滑后子元素尺寸变化被写留白
- 状态:resolved
- 首次发现:2026-09-17
- 最近更新:2026-09-17
- 影响面:`useConversationScrollAnchor` `follow()` 非贴底分支
- 用户现象:在旧会话里上滑阅读时,窗口变宽、图片加载或思考块折叠会把最后一条助手行撑出一段空白,「跳到最新」也可能被顶出来。
- 触发条件:`anchored = false` 且本轮没有 `pinLatestTurn`,滚动容器子元素高度变化。
- 根因:`follow()` 在未贴底时无条件 `applyTurnSpacer`,把闲置上滑和「本轮已钉住」当成同一件事。
- 修复:只在 `pinnedHeadRef.current` 非空时写留白。`anchorToLatest()``resetKey` 变化时清 ref 和 CSS 变量。
- 验证:`chat-notice-and-scroll-contract.test.ts`「idle history does not write a spacer…」。
- 防复发:未 pin 的上滑不得写 `--conversation-viewport``latestBelowFold` 仍按尾部超出 96px 判定。
- 相关记录:BUG-930
- 复发自:无
- 修复版本:待发布
@@ -0,0 +1,26 @@
# PROGRESS · 回答定位到开头修复单(2026-09-17)
工作树:`worktree-green-harbor-5be3`
分支:`worktree/green-harbor-5be3`
基线:`origin/staging` @ `b5e16b96`
本机 Windows。
Skill **未 bump**。未改 Python、迁移、Skill、组件、CSS、`page.tsx`
## 任务状态
| 任务 | 状态 | 说明 |
| --- | --- | --- |
| 前置 tsc 两行 | 完成 | `sessionSidebarTitle(session, library)` 与测试第二参去掉。标题函数本来只吃 session,这两处是 `e4e73f56` 挡住门禁的 TS 错。 |
| F1 BUG-931 | 完成 | head 与 `lastTurnTail` 同一元素时 `--latest-turn-head-height``0px`。不采用先 clear 再量:同一帧 `offsetHeight` 仍含上一帧 min-height。 |
| F2 BUG-932 | 完成 | `follow()` 只在 `pinnedHeadRef` 非空时写留白;`anchorToLatest` / `resetKey` 清 ref 与变量。 |
| F3 记录 | 完成 | BUG-931/932BUG-930 验证补 Chrome 骨架页;真机清单第 5 条拆成点选项 / 开场;状态板。 |
## 测试
| 项 | 结果 |
| --- | --- |
| `tsc --noEmit` | 0 错(清掉过期 `.next/types` 之后;原先两处 `Expected 1 arguments, but got 2` 已修) |
| `npm run lint` | 0 error / 117 warning |
| 定向 | chat-notice-and-scroll + chart-library-session **23 passed / 0 failed**(含 F1/F2 两条新测试) |
| `next build --webpack` | Compile + TypeScript 通过。本机 Windows 在 collect page data 时 Skill `symlink EPERM`,未核 `/` Static 与 gzip。Linux 门禁应能过类型检查。 |
+1 -1
View File
@@ -133,7 +133,7 @@
| `TASK-consult-followup-tool-contract-20260917.md` | `PROGRESS-consult-followup-tool-contract-20260917.md` | 真机:申报时段会话连发「?」「你在说什么鬼」都 `run.failed runtime_contract_incomplete`,回执无任何 `tool` 步骤。根因是 Agent 系统指令写明「简单追问可复用已有 packet / context、不调工具」,而 `contractReady()` 要求每次请求恰好一次成功排盘调用;「已有 packet」跨请求并不存在(缓存只在单次请求内)。本命与窗口两个 Agent 同构。**产品拍板方案 1**:每轮必调工具(BUG-922 删例外句 + BUG-923 第 0 步 `toolChoice: required`);否决「没调工具就走不扣点纯对话」。第一轮正经问题为何失败留 T4 取证(回执只在 web 容器日志) | 待验收 | `codex/consult-followup-tool-contract-20260917` |
| `TASK-session-list-single-source-20260917.md` | `PROGRESS-session-list-single-source-20260917.md` | 会话列表一处数据源:本地 PG 兼容层 `order()` 只保留最后一键,`/api/sessions` 实际按 `id` 排、与游标不一致;`/` 与次级页两份数据源、`/` 每次回来重启动(产品拍板:首页与三个次级页进同一路由组,侧栏外壳与列表 provider 常驻 layout,不做 store);空「新对话」落库堆积(首页 50 条里 28 条);标题类别在后、同名靠墙钟 HH:MM。串行在 composer-guard 单之后。BUG 段 926 起 | 待验收(T1–T4;延迟落库让步) | `codex/session-list-single-source-20260917` |
| `TASK-consultation-answer-start-anchor-20260917.md` | `PROGRESS-consultation-answer-start-anchor-20260917.md` | 主会话回答落在结尾:`useConversationScrollAnchor` 是贴底跟随,流式期间视口钉在最后一个字,回答开头滚出视口;改为发送后问题钉顶、回答向下长、长出视口显示「跳到最新」、末尾动态留白;产品追加拍板:校正面同一语义(推翻 BUG-041/048 贴底),本轮开头 = 用户行或新助手行。BUG 段 930 起 | 验收未通过:主会话钉顶/跳到最新/切会话(Chrome 真实布局 S1–S4)通过;P1 无用户行的一轮(校正点选项/开场)留白自指坍缩、钉不住并回退贴底(BUG-931);P2 闲置会话上滑后子元素尺寸变化被写留白(BUG-932)。tsc/build 红继承自 e4e73f56。修复单 `TASK-consultation-answer-start-anchor-fix-20260917.md` | `worktree/green-harbor-5be3` |
| `TASK-consultation-answer-start-anchor-fix-20260917.md` | | 验收修复单:F1 头就是留白行时留白按整视口算(BUG-931);F2 留白只在钉住期间存在(BUG-932);前置:先修 e4e73f56 的两处 TS 错否则门禁不过 | 待领取 | |
| `TASK-consultation-answer-start-anchor-fix-20260917.md` | `PROGRESS-consultation-answer-start-anchor-fix-20260917.md` | 验收修复单:F1 头就是留白行时留白按整视口算(BUG-931);F2 留白只在钉住期间存在(BUG-932);前置:先修 e4e73f56 的两处 TS 错否则门禁不过 | 待验收 | `worktree/green-harbor-5be3` |
### 个人报告
@@ -6,5 +6,7 @@
2. 回答超过一屏后出现「跳到最新」;按下贴底,并跟随到这一轮结束。
3. 短回答(一两句)问题仍在顶部,下方有留白,不抖动。
4. 切换到别的已有会话:落在底部(最新内容)。
5. 生时校正:打字提交、点选项、开场三种情况下本轮开头都在顶部;长旁白时出现「跳到最新」,按下能看到选择卡
6. iPhone 键盘弹起再收起后位置不跳(配合 BUG-920 一起看)
5. 生时校正点选项后:新助手行在顶部,回答从它下面往下长,不贴底
6. 生时校正开场轮:第一条助手行在顶部
7. 生时校正打字提交:用户行在顶部;长旁白时出现「跳到最新」,按下能看到选择卡。
8. iPhone 键盘弹起再收起后位置不跳(配合 BUG-920 一起看)。