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

6.6 KiB
Raw Blame History

任务书 · 开始聊天选择人物与会话对象锁定(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. 开工前置命令

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 时写环境缺口,不得写通过。