diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dec4af4..eedbc9cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - 问事业、财运、父母这类首轮,以前会按固定小标题往下写,最后再交一份「这周可以做的一件事」。现在首轮是几段人话:先给结论,再写最关键的依据,相关时带上时间。问到几个人就分段说,段首点名,不写小标题(BUG-1244)。 - 行动不再每轮都要。盘上确实指向一件相关的具体事情时,顺口说一句;用户问该怎么办时,那一轮可以多说几条。提示词里的示范删掉了会被逐字照抄的生活建议(BUG-1245)。 - 同一件事仍只说一遍。追问仍是直接回答,讲清楚为准。思考栏不再出现「这周可以做什么」;没有小标题的回答,写作行是「组织回答」。 +- 示范和指令写明段落之间空一行;以前单个换行在界面上只是折行,几段话会挤成一整块。 +- 助手回答旁边的圆形头像去掉了(对话、生时校正、首次引导三处都去),回答从栏边开始,追问按钮和校正时间轴跟着对齐正文。 - Skill 版本不变;不改数据库;不改模型、答题时钟和计费。 ## 2026-10-05 — 普通对话不再白等校正闸的外部快照,用量页能看分段时间(未上线) diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index dc610bb7..aa5b4869 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -16683,8 +16683,8 @@ - 现象:首轮按「开场 → 按对象的小标题 → 依据节 → 时间节 → 行动节」往下写。行动清单放在固定的最后一节。问到几个人时,段首是二级标题。申报时段还会要求先写「先回答你的问题」这个标题。 - 根因:2026-10-01 的形状(BUG-1132)把「按对象分段」做成了二级标题,并保留三个固定节。2026-09-27 的「行动只在最后一节出现一次」(BUG-1073 的标题部分)仍要求交那一节。模型按标题填空,读起来是汇报。 - 修复:形状只在 `consultation-thinking-plan.ts` 定义一处。首轮不写二级标题;问到几个人就分段落,段首点名。行动不强制,盘上有具体指向才顺口一句,用户问怎么办时那一轮可以给几条。首轮通常三到六段,不设硬截断。追问仍讲清楚为准;换领域或要求完整看时回到同样的段落形状。思考计划去掉行动节。正文没有二级标题时,思考节在流式中不保持进行中,结算后一起完成。写作行走「组织回答」。历史消息里已经写出的标题仍能拆开。`REPORT_HEADING` 只留在拆旧消息和思考节的 heading 字段里,不再拼进提示词。 -- 验证:合同测试见进度记录。本机没有模型凭据,四道离线题没有真跑。真机八步见 `docs/testing/consult-conversational-answer-20261006.md`。staging 尚未部署这次改动。 -- 防复发:`consultation-thinking-plan.test.ts`、`consultation-voice-contract.test.ts`、`consultation-run-timeline.test.ts` 锁住「不写 ## 节名」「段首点名」「行动不强制」「三到六段」,以及无标题首轮的思考节与写作行。改断言写了原值 / 新值 / 原因。 +- 验证:合同测试见进度记录。本机没有模型凭据,四道离线题没有真跑。真机八步见 `docs/testing/consult-conversational-answer-20261006.md`。staging 尚未部署这次改动。 验收复核(Claude,Linux + Node 22.14,2026-10-06):首版 28113fa0 全量失败名单比基线 86cafe68 多一条 `chat-answer-detail` 合同测试(锁「Every H2 must start its own line」),执行方在 Windows 上没跑到;修复后全量 4941 项 fail 24,名单与基线逐条一致(基线另一条 70 s 计时测试是并发抖动,单独跑 3/3 通过);`next build` 后 `/` 仍 Static,首屏 gzip 567,642 → 567,007 B(-0.1%)。 +- 防复发:`consultation-thinking-plan.test.ts`、`consultation-voice-contract.test.ts`、`consultation-run-timeline.test.ts` 锁住「不写 ## 节名」「段首点名」「行动不强制」「三到六段」,以及无标题首轮的思考节与写作行。改断言写了原值 / 新值 / 原因。 验收补修:`chat-answer-detail.test.ts` 改为不再要求 H2 那句;`consultation-voice-contract.test.ts` 新增「示范段落空一行、指令写明段落之间空一行」——聊天正文 `.message p` 是 pre-wrap,单个换行只折行、没有段间距,去掉标题后几段话会挤成一块。 - 相关记录:BUG-1073(同一件事只说一遍,保留)、BUG-1132(10-01 的按对象标题与三个固定节,本记录推翻其标题部分)。 - 复发自:无。这是产品改口径,不是 1073 / 1132 的同一缺陷复发。 - 修复版本:待发布 diff --git a/docs/tasks/PROGRESS-consult-conversational-answer-20261006.md b/docs/tasks/PROGRESS-consult-conversational-answer-20261006.md index 348d7c11..590d70de 100644 --- a/docs/tasks/PROGRESS-consult-conversational-answer-20261006.md +++ b/docs/tasks/PROGRESS-consult-conversational-answer-20261006.md @@ -72,3 +72,28 @@ ## 构建 `npx next build --webpack`(Next.js 16.3.1):webpack 编译成功,接着的 TypeScript 检查也通过。收集页面数据时失败,原因与测试里的技能链接相同:`SkillPackageRegistryError`,无法为 `skills/jyotish-vedic-astrology/SKILL.md` 创建符号链接(EPERM)。路由表没有打出来。`/` 是否仍为 Static、首屏 gzip 相对基线的变化,本机没有数。没有改用 Turbopack:工作树的 `node_modules` 是联接,Turbopack 会直接拒绝。 + +## 验收修复(Claude 直接执行,2026-10-06) + +产品要求直接修复,并顺带去掉助手回答旁的头像。修复单 `TASK-consult-conversational-answer-fix-20261006.md`。 + +漏掉的原因:执行方在 Windows 上全量测试有 145 条因技能符号链接 EPERM 整文件加载失败,`chat-answer-detail.test.ts` 混在里面,进度记录也没有和基线逐条比对。 + +| 项 | 做了什么 | +| --- | --- | +| F1 | `chat-answer-detail.test.ts`:原值要求 `Every H2 must start its own line` / 新值不再要求 / 原因 首轮不写 ## | +| F2 | 父母题、事业题 Good 示范段落之间空一行;`NATAL_ANSWER_SHAPE_SUMMARY`、`natalAnswerShapeBody()`、`ANSWER SHAPE` 写明段落之间空一行(单换行在界面上不分段)。英文摘要里「One person or one matter stays one stretch of prose」改成「is not split by person」,避免单对象题被读成只写一段。新增合同测试一条 | +| 头像 | 删 `AgentAvatar`(对话、生时校正、首次引导三处)与 `.agent-avatar` 样式;`--assistant-content-inset` 两处回到 `0px`,`.message-assistant` 的 gap 删掉。推翻 09-16 `071317f7`「加回头像」。两条既有断言改三栏:`rectification-timeline-20260909.test.ts`、`rectification-agentic-entry.test.ts`(原值 `calc(32px + var(--space-3))` / 新值 `0px` / 原因 产品 10-06 要求去头像)。新增「助手消息没有头像」测试一条 | + +验证(Linux + Node 22.14,干净 `npm ci`): + +| 项 | 基线 86cafe68 | 修复后 | +| --- | --- | --- | +| `tsc --noEmit` | — | 0 错 | +| `npm run lint` | — | 0 error / 126 warning | +| `npm test` | 4936 项 / fail 25 | 4941 项 / fail 24,名单与基线逐条一致(基线多出的 70 s 计时测试是并发抖动,单跑 3/3 通过) | +| `next build` | `/` ○ Static | `/` ○ Static | +| 首屏 gzip | 567,642 B | 567,007 B(-0.1%) | + +环境缺口:无模型凭据,没有真跑新提示词;无浏览器,去头像后的版面没有截图核对,列入真机清单第 9、10 步。 + diff --git a/docs/testing/consult-conversational-answer-20261006.md b/docs/testing/consult-conversational-answer-20261006.md index 6657eeaf..7eb44a3c 100644 --- a/docs/testing/consult-conversational-answer-20261006.md +++ b/docs/testing/consult-conversational-answer-20261006.md @@ -12,3 +12,6 @@ | 6 | 新开对话,打「你好」 | 仍是一句寒暄 | | 7 | 用没填出生分钟的人物档案问事业 | 不点个人大运,不写月份,也没有标题 | | 8 | 盯第 1 步回答上方的进度栏,直到写完 | 首轮不出现「这周可以做什么」。结束后没有卡住的转圈项 | +| 9 | 看第 1、2 步的回答 | 段落之间有空隙,不是一整块挤在一起的文字 | +| 10 | 看普通对话、生时校正、首次引导三处的助手回答 | 回答左边没有圆形头像;回答文字、下面的追问按钮、校正页顶部时间轴左边对齐 | + diff --git a/frontend/DESIGN.md b/frontend/DESIGN.md index 6dbaab7e..2788d7fa 100644 --- a/frontend/DESIGN.md +++ b/frontend/DESIGN.md @@ -370,7 +370,7 @@ The birth-time rectification session is the consultation transcript plus a house |---|---|---| | `opening` | live row “正在读取你的出生资料,准备第一个问题…”, then tool labels | enabled (typing queues), stop visible | | `empty` | “这段校正还没有开始。” and one primary action “开始提问” | enabled | -| `question-live` | the asking message carries the embedded card or the spoken stem. An active spoken or choice focus without `asked_turn_id` hangs on the last assistant message, same avatar column. A deterministic reply streams “ack + stem” so the stem is readable before the card arrives; once the snapshot attaches the card, the bubble drops that sentence on the live transcript as well as on refresh (BUG-1045) | enabled, placeholder points at the card | +| `question-live` | the asking message carries the embedded card or the spoken stem. An active spoken or choice focus without `asked_turn_id` hangs on the last assistant message, same text column. A deterministic reply streams “ack + stem” so the stem is readable before the card arrives; once the snapshot attaches the card, the bubble drops that sentence on the live transcript as well as on refresh (BUG-1045) | enabled, placeholder points at the card | | `question-gap`, persisted question | the snapshot's current question hangs on the latest settled assistant message (the client does this too, not only GET), and any other copy of the same `focus_id` comes off: one focus, one card (BUG-1046). The host question row (`data-testid="persisted-question"`) appears only when no assistant message can carry the prompt: there is none, or the latest one already carries a different question | enabled, placeholder “请回答上面的问题…” | | `question-live`, after a failed tap | the tapped option is taken back (question active again, nothing selected), the card remounts tappable, the Case is re-read, and the error line is “这次没提交上,请再点一次。” — never a second copy of the card below (BUG-1046) | enabled | | `question-gap`, retries left | one timeline live row “正在准备下一个问题…”, refetching on a 2s timer up to two retries | enabled | @@ -479,7 +479,7 @@ The birth-time rectification session is the consultation transcript plus a house ### Message - **Variants:** assistant editorial text on canvas; user text on warm card surface; streaming; error. Streaming uses a timeline of completed steps plus the current step; the thinking body expands while streaming, collapses when answer text appears, and is stored with the assistant message. -- **Identity:** neither role carries an avatar. The assistant reply is plain editorial text starting at the column edge; the user's turn is a right-aligned tinted bubble. The 32px Jyotisha logo used to sit beside every assistant message — at one avatar per turn it became the most repeated element in a long transcript, and it pushed the reply 44px in from the column the user reads down. `--assistant-content-inset` is `0px` now, so the follow-up chips and the run timeline line up with the reply text itself rather than with a mark that is gone. +- **Identity:** neither role carries an avatar. The assistant reply is plain editorial text starting at the column edge; the user's turn is a right-aligned tinted bubble. The 32px Jyotisha logo used to sit beside every assistant message — at one avatar per turn it became the most repeated element in a long transcript, and it pushed the reply 44px in from the column the user reads down. `--assistant-content-inset` is `0px` now, so the follow-up chips and the run timeline line up with the reply text itself rather than with a mark that is gone. History: removed 2026-09-16 (R3), restored the same day after a real-device review because rectification narration had no visual owner (071317f7), removed again on 2026-10-06 at the product owner's request — on every surface, rectification and onboarding included. The rectification timeline bar and candidate cards use the same `0px` inset. - **Typography:** assistant body `--type-body-md` (16px) with serif subheadings; user body 14px. - **Tables:** three-column technique audit tables keep 状态 on one line. Below 768px they stack each row as title + status, then the note, instead of squeezing 已执行 into a vertical glyph column. - **Follow-up:** the latest settled consultation answer may offer two or three grounded next questions under that answer. Clicking one sends it in the current session. The composer never hosts suggestion chips. If the answer does not support a grounded continuation, nothing is shown. diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css index 656d320a..f25d8379 100644 --- a/frontend/src/app/globals.css +++ b/frontend/src/app/globals.css @@ -483,7 +483,7 @@ section[popover]:has(> [data-sonner-toaster]), section[popover][aria-label^="页 .birth-time-assessment-progress strong { margin-top: var(--space-2); color: var(--color-ink); font-family: var(--font-display); font-size: var(--type-title-md); font-weight: 500; } .birth-time-assessment-progress > span { font-size: var(--type-body-sm); line-height: 1.55; text-wrap: pretty; word-break: auto-phrase; } -.message-assistant { align-items: flex-start; justify-content: flex-start; gap: var(--space-3); } +.message-assistant { align-items: flex-start; justify-content: flex-start; } .message-user { justify-content: flex-end; } .message-user .message-content { display: flex; flex-direction: column; align-items: flex-end; } .message-assistant .message-content { width: auto; max-width: none; flex: 1; } @@ -1243,9 +1243,10 @@ section[popover]:has(> [data-sonner-toaster]), section[popover][aria-label^="页 .message-list { - /* Follow-up chips and the run timeline line up with the assistant's text, - which starts past the avatar and its gap. */ - --assistant-content-inset: calc(32px + var(--space-3)); + /* The assistant reply starts at the column edge (no avatar since + 2026-10-06), so follow-up chips and the run timeline line up with the + text itself. */ + --assistant-content-inset: 0px; margin: 0 auto; width: min(900px, 100%); padding: var(--space-8) var(--space-8) var(--space-16); @@ -1258,8 +1259,6 @@ section[popover]:has(> [data-sonner-toaster]), section[popover][aria-label^="页 color: var(--color-ink-secondary); } .message { display: flex; padding: var(--space-2) 0; } -/* Restored after real-device review; see chat-message-row.tsx for why. */ -.agent-avatar { width: 32px; height: 32px; display: block; flex: 0 0 32px; margin-top: var(--space-2); border-radius: 50%; background: var(--color-canvas) url("/jyotish-logo.png") center / contain no-repeat; box-shadow: 0 0 0 1px var(--ring-hairline); } .message-content { min-width: 0; max-width: min(80%, 680px); } .message-bubble { overflow: hidden; border: 0; padding: var(--space-3) var(--space-4); border-radius: var(--radius-lg); background: var(--color-canvas-muted); } .message-assistant .message-bubble { border-radius: 0; background: transparent; padding: var(--space-3) 0; } @@ -2581,18 +2580,6 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class margin-top: var(--space-8); } -.conversation:not(.is-empty):not(.is-rectification) .message-assistant { - gap: var(--space-4); -} - -.conversation:not(.is-empty):not(.is-rectification) .message-assistant .agent-avatar { - width: 30px; - height: 30px; - flex-basis: 30px; - margin-top: 2px; - box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-border) 82%, transparent); -} - .conversation:not(.is-empty):not(.is-rectification) .message-assistant .message-bubble { padding: 0 0 var(--space-2); @@ -2676,10 +2663,6 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class margin-top: var(--space-6); } - .conversation:not(.is-empty):not(.is-rectification) .message-assistant { - gap: var(--space-3); - } - .conversation:not(.is-empty):not(.is-rectification) .message-user .message-content { max-width: 88%; @@ -2888,9 +2871,9 @@ input:not([type="radio"]):not([type="checkbox"]):not([class^="ant-"]):not([class The pending state keeps the same box for the same reason. */ .rectification-workspace__chat { --rectification-timeline-height: 64px; - /* Same token as `.message-list`: avatar 32px + gap. The bar sits outside the - transcript, so it cannot inherit that custom property from there. */ - --assistant-content-inset: calc(32px + var(--space-3)); + /* Same token as `.message-list`. The bar sits outside the transcript, so it + cannot inherit that custom property from there. */ + --assistant-content-inset: 0px; } .rectification-timeline { height: var(--rectification-timeline-height); diff --git a/frontend/src/components/chat-message-row.tsx b/frontend/src/components/chat-message-row.tsx index 13286f32..afbb85fc 100644 --- a/frontend/src/components/chat-message-row.tsx +++ b/frontend/src/components/chat-message-row.tsx @@ -31,14 +31,6 @@ function motionPreferred() { if (motionPreferred()) prefetchOnIdle(loadGsap); -/* Restored after real-device review: R3 removed it on the grounds that it was - the most repeated element in a long transcript, but without it the assistant - turn has no visual owner — in the rectification surface especially, where - narration, a question and its options all stack as plain text. */ -export function AgentAvatar() { - return