Files
Jyotisha/PROGRESS-contract-repairs-20260901.md
T
Jesse_Chen 551d6317ae
Independent Staging Quality Gate / validate (push) Has been cancelled
Independent Staging Quality Gate / publish (push) Has been cancelled
refactor(chat): extract consultation and session hooks after contract repairs
Keep archive as a PATCH of archived_at rather than DELETE, pass entry_mode through onboarding, and let popstate to the default chat reuse selectSession. Then move send/stop/recovery and session management out of page.tsx so the home surface stays within the batch-two line budget.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 04:34:14 +08:00

5.5 KiB
Raw Blame History

PROGRESS · 小刀轮:孤儿契约红修复 + popstate 副作用对齐(2026-09-01

工作树:.worktrees/contract-repairs-20260901
分支:codex/contract-repairs-20260901(跟踪 origin/staging
基线:origin/staging @ a6148af8(任务书提交;产品代码与第一批 54269fcf 相同,另加两份任务书)

不要写成 PROGRESS.md。小刀轮与第二批在同一工作树落地(第二批任务书写「小刀轮落地后的 origin/staging」;小刀当时尚未推送,故未另开 home-split-batch2 工作树)。交付为快进推 origin/staging

开工后 origin/staging 又快进了 4 个无关文档提交(ff97de5e8b7eda9f),未并入本树。

任务 1 · 归档契约

文件:tests/test_session_management_entrypoints.py::test_archiving_never_calls_the_delete_endpoint

原值 新值
读取面 PAGE.read_text()(仅 page.tsx _home_surface()page.tsx + 第一批抽出文件 + 若存在则拼接 hooks/use-session-management.tshooks/use-consultation-run.ts
切片 function toggleArchivedSessionasync function shareSession 同左(两函数第二批一起搬进 session hook,切片标记仍相邻)
正断言 "setArchivedSessionIds" in archive_action 'writeChatSession(sessionId, { archived_at: nextArchivedAt }, "update")' in archive_action"archived_at: nextArchivedAt" in archive_action
负断言 "/api/sessions/" not in archive_action 'method: "DELETE"' not in archive_action"DELETE" not in archive_action
PATCH (无) chat-session-write-contract.tsmethod: mode === "create" ? "POST" : "PATCH"

同文件 test_chat_history_management_actions_are_exposed 的读取面从 PAGE + STYLES + SESSION_ROW 改为 _home_surface() + STYLES + SESSION_ROW,断言 token 未改。test_chat_session_delete_is_server_controlled_and_granted 仍读路由/迁移。

CORE_PYTEST_TARGETS:加入 tests/test_session_management_entrypoints.py,注释「Locks archive as PATCH archived_at, never HTTP DELETE (data-safety).」

任务 2 · 引导旅程契约

文件:tests/test_birth_time_journey_contract.py::test_web_onboarding_uses_the_deterministic_free_journey

原值 新值
page 读取面 page.tsx + home-profile.ts _home_surface()(同上,含可选 hook 文件)
mastra 读取面 frontend/src/mastra/index.ts _mastra_consultation_surface() = index.ts + consultation-workflow.tsindex.ts 只再导出;token 在 workflow
正断言 'entry_mode: entryMode' in mastra 不变(现码 consultation-workflow.ts
负断言 'entry_mode: "direct_chart"' not in mastra 不变(schema 默认值是 entryMode: z.enum(...).default("direct_chart"),不是 entry_mode: "direct_chart"consultation-tools.ts 未拼进此读取面)

白名单决定:加入 CORE_PYTEST_TARGETS。整文件只读 SQL 迁移与 TS 源码,无 subprocess、无网络、无 Docker。注释「Pure source/SQL regex for the birth-time journey; no runtime services.」

任务 3 · popstate 副作用对齐

applySessionPopStateRef(现位于 use-session-management.ts,小刀改完后原样搬):

原值 新值
requestedId query.present ? query.sessionId : fallbackId(无 ?c= 时直接等于列表首项,空 id 分支实际上只有「列表为空」才会进) query.sessionId(无 ?c= 时进空 id 分支)
空 id 分支 setActiveSessionId(""); return; fallbackIdsessionSelectionSource.current = "history"; selectSession(fallbackId);;否则维持 setActiveSessionId("")

有会话时 back 到 / 仍走 selectSession(清草稿/提示、切绑定星盘),来源保持 history,不二次 pushState。无会话时行为不变。

frontend/tests/chat-session-url.test.ts

  • 原 P1 合同「popstate reuses selectSession without a second push」未改断言;切片里 writeSessionUrl(..., "push") 仍只有 selectSession 内那一处。
  • 新增「popstate to a missing session query reuses selectSession side effects for the default chat」,锁空 id 分支源码形态,且 popstate 切片内 writeSessionUrl(..., "push") 次数为 0。

frontend/tests/home-surface.ts 同步加入可选 hook 文件(existsSync),避免第二批把 selectSession / popstate 搬走后本文件立刻再红。

前瞻(第二批)

两份 Python 合同与 chat-session-url.test.ts 都走拼接读取。第二批把 toggleArchivedSession / applySessionPopStateRef 搬进 use-session-management.ts 后,hook 文件进可选清单即可。切片标记保持相邻。

验证

  • ./node_modules/.bin/tsc --noEmit:通过(小刀后与第二批抽取后各跑一次)。
  • python3.12 -m pytest tests/test_session_management_entrypoints.py tests/test_birth_time_journey_contract.py -q12 passed3 + 9)。
  • 连同 tests/test_supabase_user_data_contract.py tests/test_daily_and_rectification_entrypoints.py24 passed。
  • tsx --test tests/chat-session-url.test.ts12 pass / 0 fail / 0 skipped。
  • 前端全量 npm test2428 pass / 0 fail / 0 skipped(小刀新增 1 条 popstate 源码合同;相对第一批 2427)。
  • ./node_modules/.bin/next build --webpack┌ ○ / Static。首屏 JS gzip-9 = 501104 B(第一批后 501315 B,−0.04%)。

未改 .gitea/workflows/**。未动数据库。未提升 main