Files
Jyotisha/docs/tasks/TASK-session-list-single-source-fix-20260917.md
T

9.4 KiB
Raw Blame History

验收修复单 · 会话列表单一数据源:四条源码合同没跟着外壳搬家,门禁卡住(2026-09-17)

0. 基线

  • 验收对象:e4e73f56(会话列表单)与 6d81062b(校正输入框守卫单),当前都在 origin/staginghead cc1a8980
  • 分支:codex/session-list-single-source-fix-20260917,从 origin/staging 起。
  • 范围:frontend/tests/ 四个合同测试;tests/test_daily_and_rectification_entrypoints.pyfrontend/src/app/(app)/page.tsxF3,只允许减行或持平);docs/。不动 provider、不动排序、不动路由组。
  • BUG 段:BUG-933 起(基线最大号 BUG-932)。
  • 本单是 staging 能否部署的唯一拦路石/api/health 仍是 dc2f2a16,今天四个代码提交一个都没上线。

1. 验收结论

校正输入框守卫单 6d81062b通过

任务 结果
T1 send() 会话类型守卫 通过。consultSendBlockedByRectificationSession 在扣点与撤回窗口之前拦下,保留草稿,转 openRectificationSession;刷新恢复重放同样受守卫,pending 存储里指向校正会话的记录直接丢弃
T2 普通输入框只有禁用态 通过。inputDisabled / submitBlocked 都加了 activeRectificationSession,占位文案「正在打开生时校正…」,打开失败出「重新打开生时校正」按钮并先清 rectificationError
T3 三条回退路径 通过,且多修了归档一条。fallbackSessionId 优先非校正会话,落到校正会话时走 selectSession 的延迟切换
T4 服务端错误码 通过。类型不对回 409 session_not_consultation(在扣点预留之前,不扣点),真查不到仍 404;客户端 payloadCode 把 code 带到 ConsultationResponseError,命中后回滚乐观消息、不显示报错、直接开校正面
T5 记录 通过。BUG-924 / 925、CHANGELOG、DESIGN、VOICE、真机清单齐
page.tsx 行数 1830 → 1830

残留一条 P3,见 F3。

会话列表单 e4e73f56未通过(P1

实现本身按任务书落地:多键排序(ordering 改数组 + formatOrderClause)、(app) 路由组 + (app)/layout.tsx 常驻外壳 + SessionListProviderapp/SidebarProvider 恰好一次、use-sidebar-data.tssidebar-data-cache.ts 已删、服务端排除 messages = [] 并单独回一条 draft 供启动复用、标题改「类别 · M月D日」并删 uniquifytoSidebarSessionRow 两处侧栏共用。两条让步(元数据操作未上移、延迟落库未做)任务书都允许。

npm test 多出 4 条红,且这 4 条会让 staging 门禁必红。

.gitea/workflows/backend-quality-gate.ymlValidate backend, package, frontend, and database contracts 步骤在 set -euo pipefail 下依次跑 npm test --prefix frontendnpm run lint --prefix frontend。这 4 条是纯源码正则合同,不依赖 Docker、不依赖环境,在门禁机上照样红:

测试文件 断言找不到的东西 它现在在哪
chat-navigation-a11y-contract.test.ts <main className="chat-app"> 紧跟 replyAnnouncement 的 sr-only 播报 <main>(app)/layout.tsx,播报仍在 page.tsx,只是不再相邻
rectification-history-open-20260909.test.ts page.tsxopenErrorSessionId={rectificationErrorSessionId} (app)/layout.tsxregistration.openErrorSessionId 传给 AppSidebar
rectification-surface-contract.test.ts page.tsxopeningSessionId={rectificationOpeningSessionId} 同上,经 registration.openingSessionId
chat-session-url.test.ts page.tsxconst [nextAccount, modelCatalogResult, sessionsPayload] 启动改成 await sessionListReady + sessionListBoot(),这个解构没了

四条被保护的性质都还成立/○ Static,侧栏行仍拿得到 opening / openError,播报仍在),所以是合同陈旧、不是行为回归。但它们被留在红里,等于把门禁堵死。

根因是流程:执行方只跑了定向测试(进度记录写「定向 26 + 先前 114/115」),没跑全量 npm test,也因此没发现同批次带进的两处 TS 错(session-sidebar-row.ts(30,41)chart-library-session.test.ts(89,42),进度记录写着「tsc 0 错」,实测 2 错,后来由滚动单的 cc1a8980 顺手修掉)。

2. 任务分解

F1 四条源码合同跟着外壳搬家(BUG-933)

四条都按「原值 / 新值 / 原因」三栏改写,不得删除测试、不得弱化成只判存在

  • chat-navigation-a11y-contract.test.ts:改为分别断言 (app)/layout.tsx 里有且只有一处 <main className="chat-app">,且 page.tsxreplyAnnouncement 的 sr-only 播报仍带 role="status" aria-live="polite" aria-atomic="true",并且它是 SidebarInset 内容的第一个子节点。
  • rectification-history-open-20260909.test.tsrectification-surface-contract.test.ts:改为断言 (app)/layout.tsxopenErrorSessionId / openingSessionId / openErrorMessage 传给 AppSidebar,且 page.tsxregisterShellControls 载荷里带这三个字段(两端都断,缺一端就等于断链)。
  • chat-session-url.test.ts:把「首页自己并发拉账户/目录/列表」的断言改成「首页 await sessionListReady 后读 sessionListBoot(),并且 page.tsx 里不再出现 fetchSessions(」,保留它原本要守的「/ 是静态路由上的客户端读」这一性质。
  • 验收:npm test --prefix frontend 的失败清单与 cc1a8980少这 4 条、不多任何一条npm run lint 0 error。

F2 两条陈旧的 Python 入口合同(BUG-934

tests/test_daily_and_rectification_entrypoints.py 断言首页出现 daily-starlanguage-card / birth-rectification-card,这两个类名在 62903b7a(空状态改成「问候 + 输入框 + 两枚入口 pill」)就已删除,全仓已无。这是既有欠账,不是本批引入,也不在 CORE_PYTEST_TARGETS 里,所以不挡门禁,但任何一次 Python 定向跑都会红。

  • 改为断言当前真实的入口形态(StarterEntries 的两枚 pill 与 startDailyStarlanguageConsultation / 校正入口),或在确认无对应实现后连同该断言一并删除并在测试里写明原因。选哪种由执行方判断后写进进度记录。
  • 验收:.venv/bin/python -m pytest tests/test_daily_and_rectification_entrypoints.py 全绿。

F3 校正守卫的残留死角:一个会话都不活跃时输入框静默吞发送(BUG-935)

page.tsxactiveSession 现在是 sessions.find(id === activeSessionId) ?? sessions.find(非校正)。当列表里只剩校正会话时它是 undefined(旧代码 ?? sessions[0] 不会)。此时:activeRectificationSession 为假 → 普通输入框可用;按发送 send()!currentSession 直接 return false,没有任何提示;因为 activeRectificationSession 为假,「重新打开生时校正」按钮也不出现。

触发路径:账号里只有校正会话,或删除当前普通会话后剩下全是校正会话,且此时校正面正在打开或打开失败。窄,但正是本单要消灭的那类死角。

  • 修法:activeSession 为空且列表里存在校正会话时,按「校正会话占位」处理——输入框禁用、占位文案「正在打开生时校正…」、打开失败出重开按钮;派生值放进现有 hook 或 rectification-session-composer-guard.tspage.tsx 不增行。
  • 验收:rectification-session-composer-guard.test.ts 加一条纯函数断言(输入「列表全是校正会话、activeSession 为空」→ 锁定态为真);send() 在无活跃会话时不得静默返回而不给任何反馈。

F4 记录

  • docs/BUG_HISTORY.md 新增 BUG-933 / 934 / 935933 关联 BUG-927 与 BUG-745935 关联 BUG-924)。
  • BUG-927 的「防复发」补一条:外壳搬家必须同步搬走针对 page.tsx 的源码合同,且交付前必须跑全量 npm testtsc --noEmit,不得只跑定向。
  • docs/tasks/PROGRESS-session-list-single-source-fix-20260917.md;状态板三行改状态。
  • T2 的「元数据操作未上移到 provider」目前只写在进度记录里,补进 BLOCKED.md,与延迟落库那条并列。

3. 硬红线

  1. 不得靠删测试或放宽断言过门;四条合同必须仍然守住原来的性质。
  2. 不动排序、provider、路由组的既有行为。
  3. page.tsx 不增行。
  4. 交付前必须跑全量 npm test --prefix frontendtsc --noEmitnext build --webpack,并把失败清单与 cc1a8980 逐条比对后写进进度记录。

4. 开工前置命令

git fetch origin --prune
git worktree add -b codex/session-list-single-source-fix-20260917 .worktrees/session-list-single-source-fix-20260917 origin/staging
cd .worktrees/session-list-single-source-fix-20260917/frontend
./node_modules/.bin/tsc --noEmit && npm run lint && npm test 2>&1 | tail -20

5. 验收口径

tsc --noEmit 0 错;npm run lint 0 errornpm test 相对 cc1a8980 少 4 条红、不新增;next build --webpack 通过且 /○ Static、首屏 gzip ±2%pytest tests/test_daily_and_rectification_entrypoints.py 全绿。合入后必须核对 /api/healthdeployment.gitCommit 等于最近一次含门禁路径的 staging 提交——今天四个代码提交至今一个都没上线。