Files
Jyotisha/docs/tasks/TASK-chat-subject-picker-20260922.md
T
2026-09-22 11:19:35 +08:00

92 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 任务书 · 开始聊天选择人物与会话对象锁定(2026-09-22)
## 0. 基线与串行依赖
- 基线 commit:`1bc6a954c597e2817fe72bfedad93119ab19a527`;执行方开工前必须 fetch 并以最新 `origin/staging` 重核。
- 执行分支:`codex/chat-subject-picker-20260922`;工作树:`.worktrees/chat-subject-picker-20260922`。
- 强依赖:必须在 `TASK-consultation-subject-binding-20260922.md` 的服务端 resolver、`/api/consult` 接入和服务端测试合入 staging 后再开工;不得两个分支并行改会话 binding 或聊天顶栏。
- 与首页可靠性、starter-entry 和图标动效任务遵守文件级串行:若这些任务尚未合入,不能同时修改 `page.tsx`、`starter-home.tsx`、聊天顶栏或相关共享 CSS;功能绑定先于 UI 选择器,入口视觉和图标审计随后进行。
- 本轮 other 只覆盖普通聊天。报告、每日星语、生时校正不接入人物选择器。
## 1. 会议事实与现状
会议明确:切换其他人物后聊天不能继续使用本人资料;“我的星盘”不适合查看他人,建议改为“当前星盘”;业务认可点击聊天顶部人名展开人物列表;开发侧提出开始聊天时选对象,会话进行中不再更换,业务认可方向但未展开所有边界。
代码事实:
- `frontend/src/hooks/use-session-management.ts` 的新会话目前隐式继承账户级 `activeChartId`,没有开始聊天前的显式确认流程。
- `frontend/src/app/(app)/page.tsx` 的 `.chat-header-chart` 当前是静态 `span`,没有 button/popover/键盘语义。
- `frontend/src/components/chart-library-panel.tsx` 是账户设置资料管理,不应整块复制成聊天选择器。
- `frontend/src/lib/home-profile.ts` 已有 `chartSnapshotForSession` 与 `sessionChartLabel`;`ChatSession` 已有 chart profile 三字段,但 UI 选择必须最终写会话 binding,而不是只改 localStorage。
- `frontend/DESIGN.md` Chat header 目前是一行 quiet chart chip;本轮改动必须同步 DESIGN,并保持 44px 透明命中区、暖色 palette、popover 120ms 与 reduced-motion。
## 2. 决策记录(产品已拍板)
- 第一条消息发送前可以选择人物;本人可作为明确的默认选中项,但必须让用户看得到当前对象。
- 第一条消息发送后人物锁定;需要换人时新建会话,不改绑旧会话。
- 历史会话人物绑定固定;打开历史会话不得修改其 binding。
- 人物资料编辑后,后续普通聊天读取该人物最新资料。
- 人物删除后旧会话可阅读,但发送阻断,不自动退回本人。
- 顶部人物名是人物入口;空会话可选择,有消息会话点击其他人物时走“新建会话并使用此人物”路径,不能静默改绑。
## 3. 硬红线
1. 不得只改 `activeChartId` 或 localStorage;选择必须改变新会话的服务端 binding,或创建新会话。
2. 有消息的会话不得改人物;不得通过重写 `chart_profile_name` 伪造切换。
3. 人物列表和错误态不得泄露其他账户资料;删除人物不得回退 self。
4. 使用现有 `ChatComposer`、`useConversationScrollAnchor`、既有 popover/加载机制;不新增输入框、滚动跟随或 spinner。
5. `Home()` 的 useState/useRef 和行数增长冻结不得被绕过;新状态放 hook/lib/组件。
6. 所有可见文案对照 `frontend/docs/VOICE.md`;交互合同同步 `frontend/DESIGN.md`;源码符号/旧文案删除前先 `git grep -n` 覆盖 `tests/ frontend/`。
## 4. 任务分解与验收标准
### T1 · 会话启动选择器
- 从 chart library 读取本人和当前用户拥有的 other 资料,建立独立的 `ChatProfilePicker`/等价组件,不复制账户设置编辑表单。
- 空会话首次发送前显示当前人物与切换入口;选择状态清晰;资料加载中/失败/不完整有明确非阻塞状态。
- 新会话创建时写入服务端确认过的 `chart_profile_id`,服务端名称/关系不能被客户端任意覆盖。
验收:新建聊天能看到 self + owned other;选择 other 后创建/发送的会话绑定正确;未选择时默认行为可理解且不依赖隐式 localStorage;加载失败不创建错误 binding。
### T2 · 顶部当前星盘入口
- 将 `page.tsx` 中 `.chat-header-chart` 静态 span 改为可访问 button/等价控件,名称改为“当前星盘”语义,实际显示当前人物名。
- click、Enter、Space 均能打开/关闭 popover;实现 `aria-expanded`、`aria-controls`、焦点回收、Escape、点击外部关闭。
- 列表显示本人、owned other、当前选中、资料删除/不可用状态;至少 44px 触控目标,遵循现有 popover motion。
验收:键盘和触摸均可用;顶栏仍保持单行/移动端尺寸;不引入第二个顶部入口或第二套列表。
### T3 · 已有消息的锁定行为
- 空会话选择人物直接更新该会话的待发送 binding。
- 有消息的会话选择其他人物不改旧会话;给出“新建会话并使用此人物”的单一路径,创建后才发送。
- 发送中/流式请求期间不允许创建冲突 binding;等待当前请求结束后再执行新会话动作。
验收:旧会话历史和服务端 subject 不变;新会话绑定新人物;刷新、深链、跨设备仍一致;删除人物显示阻断而不是改成本人。
### T4 · UI/行为回归
至少覆盖:picker self/other、默认状态、空会话选择、已有消息锁定、新建会话路径、键盘/焦点/44px、资料加载失败、删除资料、刷新/深链。扩展现有 `chart-library-session`、`session-open-preserves-identity`、chat session write/authority 合同;不删除旧测试名。
## 5. 让步顺序
T1 服务端绑定接线 > T2 可访问入口 > T3 锁定/新建路径 > T4 细节视觉。若无法安全实现顶部入口,宁可保留静态显示并记录 blocked,不得交付假切换。
## 6. 开工前置命令
```bash
git status -sb
git fetch origin --prune
# 确认 consultation-subject-binding 已合入 origin/staging 后再创建本分支
git worktree add -b codex/chat-subject-picker-20260922 .worktrees/chat-subject-picker-20260922 origin/staging
cd .worktrees/chat-subject-picker-20260922/frontend
./node_modules/.bin/tsc --noEmit
npm run lint
npm test
npm run build
```
## 7. 记录与验收
同轮更新 `frontend/DESIGN.md`、必要的 `frontend/docs/VOICE.md`、`docs/tasks/PROGRESS-chat-subject-picker-20260922.md` 和 `docs/tasks/README.md` 状态板;若确认原始人物错配 Bug 尚未有记录,按开工时 `BUG_HISTORY.md` 最大编号 +1 连续登记并关联相关历史。浏览器级登录验收写入 `docs/testing/`;未具备登录态/Chrome 时写环境缺口,不得写通过。