From 6bb892b82624dc08412f3881c75f5554cd987a15 Mon Sep 17 00:00:00 2001 From: jesse-ux Date: Tue, 15 Sep 2026 17:40:17 +0800 Subject: [PATCH] fix(chat): keep page.tsx at the 1951-line freeze after lookup wiring Move BUG-705 bootstrap selection + session lookup into resolveLookupBootstrap so Home only awaits once. The 1951 cap in chart-view-route.test.ts is unchanged. --- ...fication-open-retitles-session-20260915.md | 17 ++++++++ .../PROGRESS-rectification-p0-fix-20260915.md | 42 +++++++++++++++++++ docs/tasks/README.md | 2 +- frontend/src/app/page.tsx | 17 +------- frontend/src/lib/home-cloud-sync.ts | 28 ++++++++++--- 5 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 docs/tasks/PROGRESS-rectification-p0-fix-20260915.md diff --git a/docs/tasks/PROGRESS-rectification-open-retitles-session-20260915.md b/docs/tasks/PROGRESS-rectification-open-retitles-session-20260915.md index 320036e6..a2256688 100644 --- a/docs/tasks/PROGRESS-rectification-open-retitles-session-20260915.md +++ b/docs/tasks/PROGRESS-rectification-open-retitles-session-20260915.md @@ -39,3 +39,20 @@ - 任务 3 / 5.3 staging 核对因本机没有库连接而未跑。产品在 staging 跑:`node frontend/scripts/repair-rectification-session-titles.mjs` 看行数,确认后加 `--apply`。 - 浏览器项见 `docs/testing/rectification-open-identity-20260915.md`,不得写成通过。 + +## 验收补正(2026-09-15,`f51e494c`) + +Claude 在 Linux 上验收 `f51e494c`:六条缺陷全部实现且实现方式正确。 + +| 项 | Linux 实测 | +| --- | --- | +| `tsc --noEmit` | 0 错 | +| `npm run lint` | 0 error / 119 warning(全部既有) | +| 本轮 8 个合同套件 | 130 项全绿 | +| `npm run build` | exit 0;`/` 仍是 `○ Static` | +| 首屏 JS gzip-9 | 584,413 B(对上一次 583,660 B,**+0.13%**) | +| 全量测试 | 父提交 `d3a2c48b` fail **32** → `f51e494c` fail **33** | + +多出来的一条是 `frontend/tests/chart-view-route.test.ts` 的 `page.tsx does not grow to host the chart page`:`page.tsx` 从 1951 涨到 1964 行。增长来自 BUG-705 接线,逻辑已在 lib 里,超的只是 `page.tsx` 里那十来行。 + +执行方本机把全量 TAP 记成 Windows 缺口,没有对照 Linux 的 32→33,所以当时没看见这条红。修复见 `TASK-rectification-p0-fix-20260915.md` / `PROGRESS-rectification-p0-fix-20260915.md`:接线搬进 `resolveLookupBootstrap`,`page.tsx` 回到 1951,上限未放宽。 diff --git a/docs/tasks/PROGRESS-rectification-p0-fix-20260915.md b/docs/tasks/PROGRESS-rectification-p0-fix-20260915.md new file mode 100644 index 00000000..6cdeae29 --- /dev/null +++ b/docs/tasks/PROGRESS-rectification-p0-fix-20260915.md @@ -0,0 +1,42 @@ +# PROGRESS · page.tsx 增长冻结修复(2026-09-15) + +- 执行分支:`codex/rectification-p0-fix-20260915` +- 工作树:`.worktrees/rectification-p0-fix-20260915` +- 基线:`origin/staging` @ `4161222b`(代码基线 `f51e494c`) + +## 做了什么 + +把 BUG-705 的 bootstrap 接线从 `page.tsx` 搬进已有的 `resolveLookupBootstrap`(`frontend/src/lib/home-cloud-sync.ts`)。该函数现在自己做 `resolveBootstrapSessionSelection` + lookup 三分支,`page.tsx` 只留一次 `await` 和两个赋值。 + +三分支语义未改:`found` 并进列表并选中;`missing`(404)才 `SESSION_MISSING_NOTICE` 并清 `?c=`;`unavailable` 保留 URL,提示「这条对话暂时读不到,请稍后重试。」 + +没有改 `chart-view-route.test.ts` 的 `1951` 上限,没有改 `session-lookup-unlisted.test.ts` / `chat-session-url.test.ts` 的任何断言。 + +## page.tsx 行数 + +| | 换行数 | +| --- | ---: | +| 父提交 `d3a2c48b` | 1951 | +| `f51e494c` | 1964 | +| 本单 | **1951** | + +`node -e` 实测 1951。`npx tsx --test tests/chart-view-route.test.ts` fail=0。 + +## 测试 + +| 项 | 结果 | +| --- | --- | +| `tsc --noEmit` | 0 错 | +| `npm run lint` | **0 error** / 118 warning(既有) | +| `tests/chart-view-route.test.ts` | 7/7,含 `page.tsx does not grow` | +| `tests/session-lookup-unlisted.test.ts` | 3/3,断言未改 | +| `tests/chat-session-url.test.ts` | 12/12,断言未改 | +| 全量 `npm test`(本机 Windows) | 3087 条,pass 2998,fail **75**,skipped 14 | + +全量 TAP 里 `ok 624 - page.tsx does not grow to host the chart page`。本机 fail 75 是 Windows / 无 Docker / SKILL symlink 缺口,不是这条红。Linux 门禁上的目标是 fail 33→32(就少这一条);本机对不上 32/33,不把 75 写成通过。未修另一会话的星历 / 星盘页失败。 + +未新增 BUG 号。未改 `CHANGELOG.md`。 + +## 合入 + +`git push origin HEAD:staging`,核对远端 SHA。 diff --git a/docs/tasks/README.md b/docs/tasks/README.md index ec249fa1..b35f0767 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -122,7 +122,7 @@ | `TASK-chat-reading-load-fix-20260915.md` | `PROGRESS-chat-reading-load-fix-20260915.md` | **验收修复单**:`chat-bundle-splitting-contract`(`message-markdown` 包裹数 1→2、`plainParagraphs(spoken)` 字面量已不存在)与 `chat-navigation-a11y-contract`(`window.location.assign("/login")` 4→3,建议问题入口删除带走一处)两条既有断言被本轮打红且未更新;Linux 全量 27→29。只改测试不改产品代码 | 待验收 | `codex/chat-reading-load-fix-20260915` | | `TASK-rectification-open-retitles-session-20260915.md` | `PROGRESS-rectification-open-retitles-session-20260915.md` | **P0**:打开历史校正改名(BUG-699,`2d7698ea` 已合入)+ 校正答题不 bump `updated_at`(BUG-704)+ `?c=` 不在当前页就报已删除(BUG-705)+ 标题/`updated_at` 回填脚本 | 待验收 | `codex/rectification-p0-20260915` | | `TASK-rectification-tiebreak-card-loss-20260915.md` | `PROGRESS-rectification-tiebreak-card-loss-20260915.md` | **P0**:点卡上「再答两道参考题」交付卡消失(BUG-706);按钮亮但选项建不出变成裸题(BUG-708);旁白写「相对支持度」并与卡上入口打架(BUG-709)。卡上入口删除,出卡前收集,有活题时卡留下、采用置灰 | 待验收 | `codex/rectification-p0-20260915` | -| `TASK-rectification-p0-fix-20260915.md` | — | **验收修复单**:`f51e494c` 六条缺陷全部实现且方式正确,但 `page.tsx` 从 1951 涨到 1964 行,撞了 `chart-view-route.test.ts` 的 `<= 1951` 上限(AGENTS.md §6 增长冻结)。全量 fail 32→33,就这一条。门禁红很可能是 staging 停在 `2d7698ea`、6 个提交未部署的原因。修法是把 BUG-705 的十来行接线搬出 page.tsx,不放宽上限 | 待领取 | `codex/rectification-p0-fix-20260915` | +| `TASK-rectification-p0-fix-20260915.md` | `PROGRESS-rectification-p0-fix-20260915.md` | **验收修复单**:`f51e494c` 六条缺陷全部实现且方式正确,但 `page.tsx` 从 1951 涨到 1964 行,撞了 `chart-view-route.test.ts` 的 `<= 1951` 上限(AGENTS.md §6 增长冻结)。全量 fail 32→33,就这一条。门禁红很可能是 staging 停在 `2d7698ea`、6 个提交未部署的原因。修法是把 BUG-705 的十来行接线搬出 page.tsx,不放宽上限 | 待验收 | `codex/rectification-p0-fix-20260915` | | `TASK-settings-dialog-size-and-nav-20260915.md` | — | **复发单**:设置弹窗四个分区尺寸仍随内容跳变(BUG-698,复发自 BUG-554——旧防复发只查「有没有写 height」,查不到「写了没生效」);首要嫌疑是 `.settings-modal` 的 `dvh` 没有 `vh` 回退,不支持时整条 `height` 作废退化成内容高度,需先复现确认。另按产品要求去掉分区菜单左侧强调条,并拆开与悬停共用的选中态 | 待领取 | `codex/settings-dialog-size-and-nav-20260915` | ### 个人报告 diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 7d6832a5..d864a1b8 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -125,9 +125,6 @@ import { writeChatSession } from "@/lib/chat-session-write-contract"; import { SESSION_MISSING_NOTICE, clearLoginSessionReturn, - parseSessionUrlQuery, - readLoginSessionReturn, - resolveBootstrapSessionSelection, writeSessionUrl, } from "@/lib/chat-session-url"; import { consultationReportMarkdown } from "@/lib/consultation-report-export"; @@ -994,20 +991,10 @@ export default function Home() { } if (controller.signal.aborted) return; - const listedSelection = resolveBootstrapSessionSelection({ - listedIds: nextSessions.map((session) => session.id), - defaultSessionId: nextSessions[0].id, - search: window.location.search, - storedReturnId: readLoginSessionReturn(), - }); const lookedUp = await resolveLookupBootstrap({ - selection: listedSelection, - sessions: nextSessions, - defaultSessionId: nextSessions[0].id, - catalog: nextModelCatalog, - signal: controller.signal, + sessions: nextSessions, catalog: nextModelCatalog, + defaultSessionId: nextSessions[0].id, signal: controller.signal, }); - if (controller.signal.aborted) return; nextSessions = lookedUp.sessions; const bootstrapSelection = lookedUp.selection; let landingSessionId = resolveStarterHomeLandingSessionId( diff --git a/frontend/src/lib/home-cloud-sync.ts b/frontend/src/lib/home-cloud-sync.ts index 99b5a86e..f9e9f062 100644 --- a/frontend/src/lib/home-cloud-sync.ts +++ b/frontend/src/lib/home-cloud-sync.ts @@ -2,6 +2,8 @@ import { writeChatSession } from "@/lib/chat-session-write-contract"; import { bootstrapSelectionFromLookup, persistLoginSessionReturn, + readLoginSessionReturn, + resolveBootstrapSessionSelection, SESSION_LOOKUP_FAILED_NOTICE, type BootstrapSessionSelection, } from "@/lib/chat-session-url"; @@ -496,8 +498,14 @@ export async function lookupSessionById( return { status: "found", session }; } +function throwIfAborted(signal?: AbortSignal) { + if (!signal?.aborted) return; + const error = new Error("Aborted"); + error.name = "AbortError"; + throw error; +} + export async function resolveLookupBootstrap(input: { - selection: BootstrapSessionSelection; sessions: ChatSession[]; defaultSessionId: string; catalog: PublicLanguageModelCatalog | null; @@ -507,10 +515,18 @@ export async function resolveLookupBootstrap(input: { sessions: ChatSession[]; notice: string | null; }> { - if (input.selection.urlAction !== "lookup") { - return { selection: input.selection, sessions: input.sessions, notice: null }; + throwIfAborted(input.signal); + const selection = resolveBootstrapSessionSelection({ + listedIds: input.sessions.map((session) => session.id), + defaultSessionId: input.defaultSessionId, + search: window.location.search, + storedReturnId: readLoginSessionReturn(), + }); + if (selection.urlAction !== "lookup") { + return { selection, sessions: input.sessions, notice: null }; } - const looked = await lookupSessionById(input.selection.sessionId, input.catalog, input.signal); + const looked = await lookupSessionById(selection.sessionId, input.catalog, input.signal); + throwIfAborted(input.signal); if (looked.status === "found") { return { selection: bootstrapSelectionFromLookup("found", looked.session.id, input.defaultSessionId), @@ -520,13 +536,13 @@ export async function resolveLookupBootstrap(input: { } if (looked.status === "missing") { return { - selection: bootstrapSelectionFromLookup("missing", input.selection.sessionId, input.defaultSessionId), + selection: bootstrapSelectionFromLookup("missing", selection.sessionId, input.defaultSessionId), sessions: input.sessions, notice: null, }; } return { - selection: bootstrapSelectionFromLookup("unavailable", input.selection.sessionId, input.defaultSessionId), + selection: bootstrapSelectionFromLookup("unavailable", selection.sessionId, input.defaultSessionId), sessions: input.sessions, notice: SESSION_LOOKUP_FAILED_NOTICE, };