feat(home): 首页开场语改成一行问候,占位符改「想聊什么都可以」
Independent Staging Quality Gate / validate (push) Failing after 6m23s
Independent Staging Quality Gate / publish (push) Skipped

开场语从「称呼行 + 追问句」收成 claude.ai 式的单行问候:时段池、
星期池、回访池按顺序拼成一个数组,按 variantSelection 确定性取一条;
名字为空时跳过带称呼的条目。副标题行与 .starter-salutation 下线,
h1 降到 clamp(24px, 2.8vw, 30px) / line-height 1.25。追问改由输入框
占位符承担。

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
This commit is contained in:
Jesse_Chen
2026-09-17 15:54:20 +00:00
co-authored by Claude Fable 5.1
parent dd281dd9c9
commit ff0427cf08
13 changed files with 318 additions and 97 deletions
@@ -0,0 +1,78 @@
# PROGRESS · 首页开场语改成一行问候(2026-09-17)
- 基线 commit`b51e7aff``origin/staging`2026-09-17 取)
- 分支:`codex/starter-greeting-20260917`worktree `.worktrees/starter-greeting-20260917`
- 模式:直接执行(产品拍板,非 Bug,不占 BUG 号,未写 `docs/BUG_HISTORY.md`
- 未推送。
## 1. 做了什么
| # | 改动 | 文件 |
| --- | --- | --- |
| 1 | 开场语从「称呼行 + 追问句」五时段十五条,换成三个池子的单行问候 | `frontend/src/lib/starter-greeting.ts` |
| 2 | `createOnboardingFallbackGreeting` 改成 `欢迎,{名字}` | 同上 |
| 3 | `createStartGreetingParts` 返回 `{ text }`,两个导出都多一个 `hasSessions` 形参 | 同上 |
| 4 | `StarterGreeting` 删掉 `<p className="starter-salutation">`,只留 `<h1 id="starter-heading">{starterGreeting.text}</h1>` | `frontend/src/components/starter-home.tsx` |
| 5 | `hasSessions` 由既有 `sessions` 列表派生(`sessions.some((session) => session.id !== activeSession?.id)`),未新增 `useState` / `useRef` | `frontend/src/app/(app)/page.tsx` |
| 6 | 删 `.starter-salutation` 规则;`.starter-greeting-block h1` 字号 `clamp(26px, 3.2vw, 34px)``clamp(24px, 2.8vw, 30px)``line-height` 1.3 → 1.25`--font-display` / 500 / `-.02em` / `text-wrap: balance` 保持;`.starter-greeting-block` 未动 | `frontend/src/app/globals.css` |
| 7 | 普通输入框占位符末行 `例如:未来半年是否适合换工作?``想聊什么都可以`(其它分支未动) | `frontend/src/lib/rectification-session-composer-guard.ts` |
| 8 | DESIGN / VOICE / CHANGELOG / 任务索引 | `frontend/DESIGN.md``frontend/docs/VOICE.md``CHANGELOG.md``docs/tasks/README.md` |
### 选择规则(实现口径)
给定 `(name, now, variantSelection ∈ [0,1), hasSessions)` 确定性地得到一行:
1. 时段池按 `now.getHours()`(早晨 5–11 / 中午 1114 / 下午 1418 / 傍晚 18–23 / 深夜其余),沿用改动前的划分;
2. 星期池按 `now.getDay()`,只有周一 / 周五 / 周六 / 周日各一条,其余星期不贡献条目;
3. 回访池只在 `hasSessions` 为真时拼进去;
4. 三池按「时段 → 星期 → 回访」顺序拼成一个数组;`name.trim()` 为空时先滤掉所有带 `{名字}` 的条目(时段池每段都留有不带称呼的条目,所以结果永不为空);
5. 下标 `clamp(floor(variantSelection * pool.length), 0, pool.length - 1)`,再把 `{名字}` 换成称呼。
句尾无句号;`今天过得怎么样?``最近还好吗,{名字}` 保留问号。
## 2. 测试数字
| 项 | 基线 `b51e7aff` | 本轮 | 结论 |
| --- | --- | --- | --- |
| `./node_modules/.bin/tsc --noEmit` | 0 错 | 0 错 | 通过 |
| `npm run lint` | 0 error / 118 warning | 0 error / 118 warning | 通过(warning 数量未变,未顺手修) |
| `npm test` 总数 | 3458 | 3465 | +7 |
| `npm test` pass | 3407 | 3414 | +7 |
| `npm test` fail | 36 | 36 | 失败清单逐条相同(见下) |
| `npm test` skipped | 15 | 15 | — |
| `next build``/` | `○ Static` | `○ Static` | 通过 |
| 首屏 gzip`.next/static` 全部 `*.js` 逐个 gzip 后字节合计,68 个文件,同机同命令各测一次) | 1,450,864 B | 1,450,774 B | 90 B,−0.006%,在 ±2% 内 |
失败清单逐条比对:基线 36 条与本轮 36 条排序后 `diff` 为空(`admin code functions…``rectification agent maps setup failures…``generating does not disable the textarea…`、若干 `database` / `ephemeris` / `live staging sync` 套件等)。全部是无 Docker / 无数据库 / 无外部引擎的既有环境缺口,与本轮无关。
`next build` 环境备忘:worktree 里把 `node_modules` 软链到 `.worktrees/accept-20260916/frontend/node_modules` 时,Turbopack 直接 panic`Symlink [project]/frontend/node_modules is invalid, it points out of the filesystem root`)。按开工说明改成 `rm node_modules && npm ci` 后构建正常。基线数字的取法:`git diff > /tmp/work.patch``git checkout -- frontend/` → 构建取数 → `git apply /tmp/work.patch`(未用 `git stash`AGENTS §3.5)。
## 3. 被改的既有断言(原值 / 新值 / 原因)
| 文件 · 测试 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `tests/onboarding-presentation.test.ts` · `terminal and fallback greetings follow the current profile name` | `createStartGreeting("周宁", SUNDAY(8), 0)``fallbackGreeting === "周宁,从你此刻最关心的问题开始吧。"` | `createStartGreeting("周宁", SUNDAY(8), 0.25)`= `早上好,周宁`);`fallbackGreeting === "欢迎,周宁"` | 时段池第一条改成不带称呼的「早上好」,要取带称呼的条目得换下标;兜底问候按产品口径改成单行。两条「必须带当前称呼、不得带旧称呼」的断言原样保留,另加了逐字相等断言,强度不降 |
| 同上 · `the starter hero splits one time-aware greeting…``the starter greeting is one line drawn from daypart, weekday and returning pools` | 断言 `parts.salutation === "中午好,周宁。"``parts.question === "现在最想理清哪件事?"`、两半拼起来等于整行、每时段至少 12 条不同问句 | 断言 `parts.text` 按下标取到「中午好」/「中午好,周宁」,`createStartGreeting``parts.text` 相等,`variantSelection` 为 1 / 0.999999 不越界 | 「招呼语 + 问句」两半的形状被产品取消,问句池不再存在,原断言的被测对象没了。边界不越界这一条原样保留 |
| 同上 · `the starter hero stays at a salutation and a question``the starter hero is one heading and nothing else` | 断言 `<p className="starter-salutation">{starterGreeting.salutation}</p>``<h1 …>{starterGreeting.question}</h1>` 同时存在 | 断言只剩 `<h1 id="starter-heading">{starterGreeting.text}</h1>`,且 `starter-salutation``starterGreeting.salutation|question` 在源码与 `globals.css` 里都不得出现 | 副标题行连同它的样式一起下线;断言从「必须有两行」改成「只有一行且不得有第二行」,是收紧不是放松 |
| `tests/consultation-entrypoint.test.ts` · `the starter heading is drawn per visit…` | `<h1 id="starter-heading">{starterGreeting.question}</h1>` | `<h1 id="starter-heading">{starterGreeting.text}</h1>` | 同上;「每次进首页重抽一次」(`useState(() => Math.random())` + 离开首页重抽)两条断言原样保留 |
| `tests/consultation-entrypoint.test.ts` · `the starter greeting keeps the display stack and display weight` | `font-size: clamp(26px,` | `font-size: clamp(24px, 2.8vw, 30px);`,并新增 `line-height: 1.25;` | 单行之后不需要 34px 上限那一档。原断言只匹配前缀,新断言匹配完整 clamp 并多钉一条 `line-height`,强度提高;`--font-display` / `font-weight: 500` / 不得是 `--font-body` 三条原样保留 |
| `tests/chat-composer-queue.test.ts` · `a queued card renders above the live textarea` | fixture `placeholder: "例如:未来半年是否适合换工作?"` | `placeholder: "想聊什么都可以"` | 只是渲染 `ChatComposer` 时传的样例 prop,不是被断言的对象;跟着产品文案更新以免留下过期字面量。断言本身未动 |
## 4. 新增测试(`tests/onboarding-presentation.test.ts`3 条 → 10 条)
| 测试 | 覆盖 |
| --- | --- |
| `late night has its own three lines and none of them asks a follow-up` | 深夜三条逐字;23 点与 4 点同属深夜 |
| `a blank name leaves only the lines that carry no name` | 名字为空(含全空白)只出不带称呼的条目;周一条目与回访池整条不可达;结果非空、不残留 `{名字}`、不以逗号收尾 |
| `the weekday pool only opens on its own day` | 周五能选到 `周五快乐`,周三选不到且池子恰好 3 条;周一 / 周日各自的条目可达 |
| `the returning pool needs at least one session behind the account` | `hasSessions=false` 时四条回访句一条都选不到(池子 3 条);`hasSessions=true` 时四条全部可达(池子 7 条) |
| `the same inputs always produce the same line` | 同一 `(name, now, variantSelection, hasSessions)` 连调两次结果相同 |
| `no greeting line uses a metaphor or trails off into a sentence` | 7 天 × 24 小时 × 2 种称呼 × 2 种 `hasSessions` × 100 个 selection:任何条目不含 `星` `月` `陪`、不以 `。` 结尾、长度 ≤ 12 |
| `the greeting knows whether the account already has sessions` | `hasSessions` 必须由既有 `sessions` 列表派生,`page.tsx` 不得另开状态 |
`frontend/tests/home-shell-growth-contract.test.ts` 未改动且仍绿:`page.tsx` 只多了一行 `const starterHasPriorSessions = …``useState` / `useRef` 计数不变。
## 5. 环境缺口
- 无登录态、无浏览器走查:真实首页上「一行问候居中、不再一大一小、占位符文案」的观感未在浏览器里确认,仅有 `next build` + 源码/样式合同。
- 本轮未跑 `npm run test:db`(未动数据库结构)、未跑 Python 测试(无 Python 改动)。
+1
View File
@@ -137,6 +137,7 @@
| `TASK-first-paint-dead-screen-fallback-20260917.md` | — | 真机:首页永远停在「正在载入账户」,兜底全在没跑起来的 bundle 里(BUG-936 investigating)。根 layout 加与 bundle 无关的内联兜底 + 去掉本仓正则后行断言 | 待领取 | — |
| `TASK-consultation-answer-start-anchor-20260917.md` | `PROGRESS-consultation-answer-start-anchor-20260917.md` | 主会话回答落在结尾:`useConversationScrollAnchor` 是贴底跟随,流式期间视口钉在最后一个字,回答开头滚出视口;改为发送后问题钉顶、回答向下长、长出视口显示「跳到最新」、末尾动态留白;产品追加拍板:校正面同一语义(推翻 BUG-041/048 贴底),本轮开头 = 用户行或新助手行。BUG 段 930 起 | 已验收(经修复单) | `worktree/green-harbor-5be3` |
| `TASK-consultation-answer-start-anchor-fix-20260917.md` | `PROGRESS-consultation-answer-start-anchor-fix-20260917.md` | 验收修复单:F1 头就是留白行时留白按整视口算(BUG-931);F2 留白只在钉住期间存在(BUG-932);前置:先修 e4e73f56 的两处 TS 错否则门禁不过 | 已验收 | `cc1a8980`Claude 验收:tsc 0 / lint 0 error / npm test 3457 条 39 红与 11c0028d 逐条一致、新增 2 条绿 / `next build --webpack` 通过、`/` Static、首屏 gzip 591,242(较 09-16 基线 582,800 +1.45%,含会话列表单)/ Chrome 真实布局 S1–S6 全部通过,S6 新助手行距顶 16px 且增高不动,S5 不再写留白);真机六条欠 |
| — | `PROGRESS-starter-greeting-20260917.md` | 首页开场语改成 claude.ai 式单行问候:`starter-greeting.ts` 的「称呼 + 追问句」五时段十五条收成三个池子(时段 / 星期 / 回访,按 `variantSelection` 确定性取一条),副标题行与 `.starter-salutation` 下线,h1 降到 `clamp(24px, 2.8vw, 30px)`;追问移到输入框占位符「想聊什么都可以」。产品直接拍板,非 Bug,不占 BUG 号 | 待验收 | `codex/starter-greeting-20260917` |
### 个人报告