fix(chat): honor new-chat intent from secondary pages
Independent Staging Quality Gate / validate (push) Successful in 13m41s
Independent Staging Quality Gate / publish (push) Successful in 3m30s

Create a fresh local consultation for explicit new-chat navigation and keep reserved recovery from taking over its landing. Add regression tests and record validation gaps for remote review.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
jesse-ux
2026-09-24 00:25:28 +08:00
co-authored by Claude Code
parent 1c95eb3979
commit 8902e48468
17 changed files with 368 additions and 6 deletions
+16
View File
@@ -13474,6 +13474,22 @@
- 复发自:聊天面板既有 focus 防滚动合同的新增组件遗漏。
- 修复版本:`36a737616c67a251610662ccab76845b193993fb`(staging;未部署)。
## BUG-1015 | 次级页「新建对话」没有新建意图,回首页打开旧对话
- 状态:blocked(本地修复及针对性回归通过;完整构建、部署与受控真人走查未完成,不提前标 resolved)
- 首次发现:2026-09-23
- 最近更新:2026-09-23
- 影响面:星盘、星历、报告列表及详情页的只读侧栏新建入口与首页启动落点。
- 用户现象:在次级页点击「新建对话」后进入旧会话,而不是空咨询。
- 触发条件:只读侧栏缺少首页 controls,其新建入口原为无意图的 `/`;若还有旧 reserved 咨询,启动恢复还会主动激活旧会话。
- 根因:回首页与新建共用无参数地址,首页按既有 URL/登录存根/默认选择规则落点;原任务书只补 URL 意图,独立验收又确认后台恢复在新建激活后覆盖活动会话。前者不是缓存或导航性能复发,后者是同一入口的组合路径遗漏。
- 修复:唯一 URL helper 生成 `/?new=1`、按参数存在性识别,优先于 c 与登录存根;sessionHref 一律消费 new。首页复用已有本地 createSession 分支,激活前 replace 清除 new/c 并清存根;产品追加授权后,在旧咨询恢复完成的同步区块内恢复新建落点并清本次恢复提示,保留 pending/recovering,不取消后台任务。首问保存与列表过滤沿用 BUG-989。
- 验证:URL/落点/侧栏及既有深链、列表、增长合同通过;新增动态执行真实恢复函数及首页装配区块的测试,new-chat 保持新落点、无 new 保持旧恢复行为。最终全量数字、独立验收及环境证据见 `docs/tasks/PROGRESS-secondary-new-chat-intent-20260923.md`。未以源码测试冒充登录浏览器或部署验收。
- 防复发:保持 BUG-744 单侧栏、BUG-745/927 共享外壳、BUG-989 首问前不落库/不写 c/列表无 draft;新增优先级、参数消费、激活顺序、本地创建与 reserved 恢复冲突测试。原合同只锁导航方式及无参数默认落点,没有连接“新建”意图,故未拦住本次问题;既有断言未删除或弱化。
- 相关记录:BUG-744、BUG-745、BUG-927、BUG-989、BUG-705、BUG-995;`TASK-secondary-new-chat-intent-20260923.md`(D7 为本轮追加授权)。
- 复发自:无;与 BUG-745 同入口但不同根因。
- 修复版本:本次提交(执行分支 `codex/secondary-new-chat-intent-20260923`,基线 `1c95eb397`);2026-09-24 产品授权推 staging 供远程 review,精确 SHA 以实际推送及远端核对为准,部署尚待核验。
## BUG-1014 | 输入框源码合同未跟上已删除人物的发送限制
- 状态:resolved(run 2857 的 H3 门禁通过;staging 总门禁仍因 BUG-1011 失败,尚未部署)
+6
View File
@@ -2,6 +2,12 @@
Purpose: read this file before substantial project work. It exists to stop repeat mistakes caused by multiple Codex windows, WorkBuddy mirrors, local drafts, backup folders, and partial cloud-git visibility.
## 2026-09-24 · 次级页新建意图交付预检
- 产品授权推送供远程 review;fetch 与 pre_work_check 远端可见性均成功,推送仍须另核 SHA,不将远端可读等同写入成功。
- Windows python3 launcher 退出49;已有 Python 3.11.7 可运行预检。适配器与碎片扫描步骤成功,focused 22通过/2失败:`.workbuddy` 镜像路径缺失断言复现;fragment audit candidate_count=4 与 workspace_residue_count=29 的数量约束不成立。未伪造镜像、未清理他人目录、未改测试,整体预检仍为 fail。
- 本单前端最终定向95/95、全量新增9项通过且89项既有失败原因不变;Windows Skill symlink EPERM 导致完整构建/Static/gzip未闭环。详见 `docs/tasks/PROGRESS-secondary-new-chat-intent-20260923.md`,不以允许远程 review 冒充验收或部署通过。
## 2026-09-23 · staging 门禁修复交付的写认证复发
- 默认 Git 认证推送 `36a73761` 返回 `Failed to authenticate user`;本地提交成功不等于远端交付,首次失败后明确保留未推送状态。
@@ -0,0 +1,103 @@
# PROGRESS · 次级页「新建对话」意图(2026-09-23)
## 结论与交付边界
实现与定向独立复核完成;**完整验收尚未完成**。2026-09-24 产品明确要求先 push 供远程 review,本次提交交付 staging;推送成功与远端 SHA 以实际核对回报为准,不以提交本身冒充部署成功。不提升 main、不改 workflow/DNS。BUG-1015 暂记 blocked(已本地修复,构建/受控真人证据未闭环),不按任务书预先指定的 resolved 提前结案。
| 项目 | 值 |
| --- | --- |
| 任务书 | `docs/tasks/TASK-secondary-new-chat-intent-20260923.md` |
| 实测基线 | `origin/staging = 1c95eb397`(已 fetch;任务书原基线之后仅任务文档) |
| 执行分支 | `codex/secondary-new-chat-intent-20260923` |
| 工作树 | `.worktrees/secondary-new-chat-intent-20260923` |
| BUG 编号 | 开工最大 BUG-1014,本单 BUG-1015 |
| 固定构建基线 | 本工作树下 `.worktrees/secondary-new-chat-baseline-20260923`,detached `1c95eb397` |
| 原始日志 | 本地 `artifacts/secondary-new-chat/`,不纳入提交 |
| 真人清单 | `docs/testing/secondary-new-chat-20260923.md` |
## 已实现
- T1:`chat-session-url.ts` 唯一生成/解析新建意图;参数按存在性识别(`?new=1`、`?new=`、`?new` 均有效),优先于合法/非法/未加载的 c 及登录存根,`missing=false`。所有 sessionHref 都消费 new,保留无关参数。
- T2:首页复用原 starter 创建分支,不重复拼装会话,不新增状态/ref;激活前清 URL,按既有 clearStoredReturn 清存根。
- T3:只改只读侧栏既有新建链接,仍经 SidebarMenuLink → AppLink,仍关闭抽屉;首页按钮、账户页脚、品牌标记不变。
- T4:更新 BUG_HISTORY、CHANGELOG、DESIGN、任务状态板、BLOCKED、本进度与真机清单。没有新增产品文案,VOICE 无需修改;Skill 不 bump。
- 补修 D7:旧 reserved 咨询仍执行真实恢复逻辑并保留 pending/recovering,之后新建意图重新取得活动落点并清启动恢复提示。无 new 时不改变恢复行为。
## 决策、勘误与偏离
1. **追加授权而非擅自破红线**:独立验收首次发现 `restoreConsultationRecovery()` 无条件激活旧会话,导致新建路径被覆盖。主会话向产品说明超出“一行”范围,产品明确选择“一并修复”。已在 TASK D7 记录:仅首页额外四行保护,首页总计 +5 行,无新增 state/ref,不改恢复 hook 或后台任务,不取消请求。
2. T2“激活前清理”与“放在 replace-clear 邻行”原描述冲突;以明确时序为准,清理放在 setActiveSessionId 前。
3. 当前品牌行无任务书所说的 AppLink,只是 div/span/strong,不补造入口。默认会话也可能受收藏及返回存根影响,不扩大修改无参数首页规则。
4. 空历史启动已有兜底会创建一个本地空咨询,再执行新建分支会产生另一个本地空对象;两者均不落库、不显示于历史。本单按“new 恒新建”要求保留,不另改会话状态流。
5. 任务书预写 resolved 与事实证据冲突:完整构建/真人/部署未完成,按 AGENTS 诚实边界暂记 blocked。
6. 测试数量按 BUG-995 / frontend AGENTS 比较**名称多重集合**,不仅看汇总尾行。没有把既有失败当通过。
## 历史检索与保护
开工只读代理按现象、入口、模块及 `/api/sessions` 检索并完整读取相关记录:BUG-744、745、927、928、987、989、705、967、995 等。
- BUG-744 单一侧栏与只读同构仍由 sidebar-contract 守护。
- BUG-745 的旧 sidebar-data-cache 已被 BUG-927 共享 `(app)` / SessionListProvider 替代,不恢复旧缓存;客户端导航、provider 生命周期合同仍在。
- BUG-989 本地新建、首问 persistSession(create)、创建成功才写 c、列表无 draft 与咨询专用过滤均仍在。
- BUG-705 未列出合法深链仍 lookup,不受 new 分支之外的行为影响。
- 本次原测试没拦住:只锁住了“导航方式”和“无参数默认落点”,没有验证跨页新建意图;补上组合与真实恢复冲突验证。
## 验证数字
| 检查 | 改动前基线 | 最终补修后 | 结论 |
| --- | ---: | ---: | --- |
| tsc --noEmit | 0 错 | 0 错 | 通过 |
| npm run lint | 0 error / 119 warning | 0 error / 119 warning | 通过;不顺手修 warning |
| 全量测试总数 | 3708 | 3717 | +9 |
| 全量 pass | 3619 | 3628 | +9 |
| 全量 fail | 89 | 89 | 失败名单无增减,不是全绿 |
| cancelled / skipped | 0 / 0 | 0 / 0 | 不变 |
| 顶层 TAP 名称 | 3690 | 3699 | 删除0、新增9 |
| 全部含子测试名称 | 3708 | 3717 | 多重集合删除0、新增9,新增全通过 |
| 本轮定向(8文件) | — | 95 pass / 0 fail | 通过 |
| 独立新增恢复测试 | — | 2 pass / 0 fail | 通过 |
| 独立内存变异(3种) | — | 每种1 pass / 1预期fail | 删除保护/只删落点/只删提示清理均被捕获 |
| 首页增长 | 基线 | +5行 / state+0 / ref+0 | D7已授权,增长合同通过 |
| next build Static | 未完成 | 未完成 | 环境缺口 |
| 首屏 gzip ±2% | 未测得 | 未测得 | 环境缺口,不报推测数字 |
命令及日志:
- `./node_modules/.bin/tsc --noEmit` → `baseline-tsc.log` / `final2-tsc.log`。
- `npm run lint` → `baseline-lint.log` / `final2-lint.log`。
- `npm test` → `baseline-test.log` / `final2-test.log`;`compare-tests.cjs final2` → `test-comparison.json`(名称、失败名、基础诊断字段)。
- 定向:chat-session-url、home-bootstrap-reveal、sidebar-contract、new-chat-recovery、session-lookup-unlisted、session-list-filter、chat-session-authority、home-shell-growth-contract → `final2-focused.log`。
- 最初先加测试验证红灯:未实现新导出导致URL测试无法载入,落点/只读链接断言失败;随后实现转绿。未将该次红灯当作“全部9条都单独复现”。
- 第一次备用基线构建与新增测试编辑重叠,在类型阶段读到尚未实现的新导出,**该次日志无效,不充当基线**;已另建固定提交隔离工作树重新构建作为有效对照。
最终 `baseline-test.log` 与 `final2-test.log` 已独立逐项复核:89/89 完整 TAP 失败诊断(多行 error、expected/actual/operator、code、failureType、完整栈)在只归一化耗时、PID/时间戳、随机临时目录及经 SHA-256 验证的路径派生哈希后相同,未抹栈或行号。既有测试状态变化0。code分布两侧均 ERR_TEST_FAILURE49 / ERR_ASSERTION32 / ENOENT4 / EPERM4。41/41 Docker 项目均对应各自 daemon 地址池耗尽输出;4个文件加载前置stderr归一化后也一致。原始完整诊断有51项随机值变化;Compose附带进度/包装有6/41项差异,但失败原因不变,不宣称原文逐字一致。
| 最终既有失败类别 | 数量 |
| --- | ---: |
| Docker默认网络地址池耗尽 | 41 |
| symlink EPERM(含子进程/文件加载) | 13 |
| Windows重复盘符路径ENOENT | 4 |
| methodology解析断言 | 9 |
| 迁移读取到链接目标字符串而非SQL | 5 |
| 其他既有脚本/环境断言 | 17 |
| 合计 | 89 |
其余17项涉及备份边界6、数据库环境校验3、部署环境校验3、缺rsync2、install权限1、YAML子进程9009共1、docs-only-range子进程49共1;日志不足以进一步确定所有退出码底因,不擅自修复或笼统归因。
## 既有断言变更表
| 原值 | 新值 | 原因 |
| --- | --- | --- |
| 只读侧栏测试仅守同构、无菜单、页脚 `/`、无写请求 | 保留全部原断言,追加 `.new-chat` 必须调用 newChatHref 且关闭抽屉、不得字面量 `/` | 锁定新建语义,不弱化旧合同 |
| 其余既有断言 | 不变 | 新增9个测试,无删改或重命名既有用例;sibling 参数原断言也未改 |
新增测试:URL 5、落点2、reserved恢复2;恢复测试执行真实函数与首页区块,不仅做正则存在性断言。
## 环境缺口与后续验收
1. 复用本机 node_modules junction;根工作树 lock 与基线 lock 文件不同,但逐项核对顶层已安装非可选包版本与本单 lock 相符,没有安装/升级依赖。默认 Turbopack 报依赖链接超出 filesystem root;没有为此改 next.config。
2. 固定基线与最终均补跑官方 `npm run build -- --webpack`。编译及构建内类型检查成功,页面数据收集创建 Skill SKILL.md 符号链接报 EPERM。有效基线日志 `baseline-isolated-build.log`、最终 `final2-build.log`。不修改 Skill 权限或禁用检查,Static/gzip 缺口保留。
3. Docker daemon 有响应但默认网络地址池耗尽;数据库 fixture 无法创建网络,未真正运行SQL。本单无数据库变更,不运行单独 test:db、不清理共享网络。
4. 没有本轮受控登录浏览器证据,移动抽屉/首问网络/真实恢复按真人清单补验。存在本机浏览器与否不等于已有受控登录态,不冒称“无Chrome”或“浏览器通过”。
5. 2026-09-23 实现完成时未 commit/push;2026-09-24 产品明确授权推送供远程 review,已重新 fetch,远端仍为 `1c95eb397`,BUG-1015 未被其他单占用,符合快进交付前置条件。此次只提交本单代码/测试/记录,不包含 artifacts 或依赖链接;Gitea 门禁及部署仍须独立核验。
6. 推送前按 §9 运行 pre_work_check:本机 python3 launcher 退出49;改用已有 Python 3.11.7 执行,远端 verified、适配器与碎片扫描步骤成功,但 focused 22通过/2失败:既有 `.workbuddy` 镜像路径断言,以及 candidate_count=4 不满足 workspace_residue_count=29 的数量断言。未伪造镜像或改治理测试以消红;不把整体预检写成通过。日志在本地 `push-pre-work-python.log`,同步追加错误台账。
+1 -1
View File
@@ -117,7 +117,7 @@
| 任务书 | 进度 | 主题 | 状态 | 落点 |
| --- | --- | --- | --- | --- |
| `TASK-secondary-new-chat-intent-20260923.md` | — | **次级页「新建对话」落到最近一次对话**:`/chart` `/ephemeris` `/reports` 的侧栏没有 `controls`,「新建对话」只是 `href="/"` 的回首页链接;首页无参启动的落点是 `nextSessions[0]`(最近更新那条),只有最近一条是校正会话才改落空咨询。BUG-745 修过同一入口的「慢」,没修「回到哪」。产品 09-23 拍板:链接改 `/?new=1`,首页看到 `new` 就本地建空咨询并 `replaceState` 抹掉参数;`new` 胜过 `c` 与登录返回存根;沿用 BUG-989 不落库不写 `?c=`;页脚与品牌行的 `/` 不改;刷新无参 `/` 仍落最近对话属既有设计。红线:`/` 保持 Static、不得用 `useSearchParams`;解析与生成只在 `chat-session-url.ts` 一处。BUG-1015 | 待领取 | — |
| `TASK-secondary-new-chat-intent-20260923.md` | `PROGRESS-secondary-new-chat-intent-20260923.md` | **次级页「新建对话」落到最近一次对话**:`/chart` `/ephemeris` `/reports` 的侧栏没有 `controls`,「新建对话」只是 `href="/"` 的回首页链接;首页无参启动的落点是 `nextSessions[0]`(最近更新那条),只有最近一条是校正会话才改落空咨询。BUG-745 修过同一入口的「慢」,没修「回到哪」。产品 09-23 拍板:链接改 `/?new=1`,首页看到 `new` 就本地建空咨询并 `replaceState` 抹掉参数;`new` 胜过 `c` 与登录返回存根;沿用 BUG-989 不落库不写 `?c=`;页脚与品牌行的 `/` 不改;刷新无参 `/` 仍落最近对话属既有设计。红线:`/` 保持 Static、不得用 `useSearchParams`;解析与生成只在 `chat-session-url.ts` 一处。BUG-1015;执行中追加 D7:保留旧任务恢复但不抢新建落点。 | 待验收(本地定向通过;构建/真人缺口) | 本次提交(`codex/secondary-new-chat-intent-20260923`);09-24 授权推 staging 供 review,远端 SHA 以交付回报为准,部署待核验 |
| `TASK-chat-message-authority-20260901.md` | — | 消息服务端权威化 | 已验收 | `b6989c3e`(BUG-464) |
| `TASK-session-url-20260901.md` | — | 会话 URL 化 | 已验收 | `924f4202` |
| `TASK-cloud-truth-convergence-20260901.md` | — | 本地/云端双份真相收敛 | 已验收 | `ce6a8a7e`(BUG-466) |
@@ -33,6 +33,8 @@
- **D4** 优先级:`new` 胜过 `c` 与登录返回存根(`storedReturnId`)。带 `new` 时忽略两者,并清掉存根(它只服务于登录后回到原会话,用户既然点了新建,存根已过时)。
- **D5** 不改的:侧栏页脚 `.profile-trigger` 与品牌行两个 `href="/"` 仍是"回首页",落点规则不变;首页自身按钮不变;`BUG-989` 的三条防复发不变。
- **D6** 不在本单:刷新 `/`(无参数)仍落最近对话——这是既有设计,不是本单事故。
- **D7(执行中追加授权,2026-09-23)** 独立验收发现:存在旧 `reserved` 咨询时,`restoreConsultationRecovery()` 会把新建落点改回旧咨询。产品明确选择「一并修复」,授权首页在恢复后增加 `new-chat` 落点保护并清除此次恢复提示,保留旧任务的 pending/recovering 能力,不取消任务、不改恢复 hook。本授权有限扩展红线 5 / T2「首页只加一行」:允许额外一个四行保护块(首页合计 +5 行、state/ref 不增),必须补动态执行真实恢复函数与首页装配段的回归测试;无 `new` 的恢复行为不变。
- **执行勘误**:当前品牌行是 `div` + `span/strong`,没有 D5 所述链接;保持现状,不补造入口。首页无参数还受收藏顺序及登录存根影响,本单不更改这些规则。URL 清理优先满足 T2「激活之前」时序,不拘泥于位于激活之后的 `replace-clear` 邻行。
## 硬红线
@@ -0,0 +1,30 @@
# 次级页「新建对话」真人验收(2026-09-23)
关联:`TASK-secondary-new-chat-intent-20260923.md`、BUG-1015。
## 前置与记录边界
- 本清单尚未执行,不以源码合同或纯函数测试代替真实登录走查。
- 在本轮修复已部署的 staging 使用受控测试账号;先核对 `/api/health` 的部署提交。不借用任何他人的登录态。
- 使用明确虚构的资料与对话。测试账号至少有一条已保存的普通咨询;记录列表项数量,不记录账号、会话 ID、出生信息或完整请求体。
- 用浏览器网络面板核对请求方法和路径即可,不保存 Cookie、JWT 或请求正文。每个场景记录通过/未通过、浏览器、日期和脱敏现象。
## 必验
| 步骤 | 操作 | 预期 |
| --- | --- | --- |
| 1 | 从已有普通咨询进入 `/chart`,点侧栏「新建对话」 | 首页为空会话,不显示旧消息;地址为 `/`,无 `new`、无 `c`;历史列表不增加;没有创建会话的 `POST /api/sessions`,无“该对话不存在或已被删除”提示 |
| 2 | 在步骤 1 的空会话发送第一问 | 走既有创建流程;成功后地址为 `/?c=<新会话>`,历史顶部出现新会话;输入与回复正常 |
| 3 | 重做步骤 1,不发消息,直接刷新 | 按无参数首页的既有规则恢复会话,不再次执行新建意图;不是继续保留上一步未保存空会话。无收藏/存根干扰时回最近普通咨询(D6) |
| 4 | 在 `/ephemeris`、`/reports`、`/reports/<受控测试报告>` 分别重复步骤 1 | 与步骤 1 一致 |
| 5 | 移动端打开次级页抽屉,点「新建对话」 | 与步骤 1 一致,抽屉关闭;没有新入口、额外等待动画 |
| 6 | 已有登录返回存根时,访问 `/?new=1&c=<已有会话>`;另测 c 为格式错误值 | 新建意图胜出,打开空咨询;清除两种参数及存根;不恢复旧会话,不提示会话缺失 |
| 7 | 次级页点击账户页脚返回 `/`;首页点击自己的「新建对话」 | 页脚仍走原回首页规则;首页按钮仍走原本地新建流程 |
| 8 | 单独访问有效 `/?c=<已有会话>`(不带 new),并浏览器后退/前进 | 深链仍打开指定会话;没有被本次新建规则抢走;URL 历史仍按原设计工作 |
| 9 | 在旧咨询仍后台生成时进入次级页,再点「新建对话」 | 仍停留新空咨询;旧任务继续恢复但不抢回活动会话,启动恢复提示不留在空会话上;无 `new` 正常回首页时仍恢复旧咨询 |
## 边界复核
- 刚注册、没有历史的受控账号进入新建入口仍只有一个可见空会话,首问前不写数据库、不显示空列表行。启动内部已有的空列表兜底与本单新建分支可能分别产生本地空对象;两者都必须隐藏且不持久化。
- 普通刷新 `/` 不承诺“始终空白”,本单不更改默认落点规则。
- 需要模型凭据才能完成步骤 2 的真实回复;若不可用,只记录创建链的实际证据,将回复部分标环境缺口,不伪写通过。