docs(tasks): 年月阶段焦点被模型追问覆盖任务书(BUG-908~911)
追问句下挂录入卡 = set-focus 同号覆盖 event_date_entry 焦点题干;事件入账后年月焦点没关;答短句撞步骤上限;persisted 问题块无缩进。 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
37f77fe8b3
commit
453b6c017d
@@ -101,6 +101,7 @@
|
||||
| `TASK-rectification-superseded-focus-duplicate-20260910.md` | `PROGRESS-rectification-superseded-focus-duplicate-20260910.md` | P0:一轮两次 batch 让感情采集题被顶替成 superseded 行;题号唯一约束含已结束行、汇总只聚合 declined/skipped,计划层看不见→撞号 `duplicate_focus` 被当「已问过」→出口误走交付旁白无卡(BUG-644);交付口吻与 `can_adopt=false` 矛盾(BUG-645) | 待验收(环境缺口:`next build` / 真人走查) | `a3a51c32`(BUG-644/645) |
|
||||
| `TASK-rectification-exhausted-gate-exit-20260910.md` | `PROGRESS-rectification-exhausted-gate-exit-20260910.md` | 五领域全拒答 + 三件带月经历:门槛句后无载体、客户端误报「没有拿到下一个问题」并循环「接着问」(BUG-646);第三件被留作 holdout 导致永远没有选择题(BUG-647)。含产品建议:一次性开放追问 + 终态标记 + 穷尽后释放 holdout | 已被取代(并入采集重设计单) | — |
|
||||
| `TASK-rectification-collection-redesign-20260910.md` | `PROGRESS-rectification-collection-redesign-20260910.md` | 产品口径:用户先说、系统从已说的事锚定追问、不得用生日推年份、不得说「领域」、永远交付结果。无固定题数:收集问题池按信息价值排序问到训练门开;选择题问到收敛门开或增益见底;门关不出结果只出精确缺口句并保持开放;≥4 件才留 holdout;撤回 BUG-642 年份线索、BUG-646 单终态与「暂定采用」;Skill 10.0.23(BUG-646~648) | 待验收 | `dd8f35f7` |
|
||||
| `TASK-rectification-year-focus-overlay-20260916.md` | `PROGRESS-rectification-year-focus-overlay-20260916.md` | 真机:定向健康题选 A 后打字给年月,助手追问「是你本人做的吗」,追问句下面挂着录入卡(`set-focus` 同号覆盖年月焦点题干、`event_date_entry` 仍在,BUG-908);事件入账后年月焦点没关(BUG-909,回放定 resolve 还是计划层);答短句撞「本轮达到步骤上限」(BUG-910,host 前置接无年月短句,先 investigating);persisted 问题块无 `--assistant-content-inset`(BUG-911)。主体默认本人不追问,Skill 10.0.29 | 待领取 | — |
|
||||
|
||||
### 聊天主链路与首页
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
# 任务书 · 年月阶段焦点被模型追问覆盖:追问句下面挂着录入卡、问题块不对齐、答完撞步骤上限(2026-09-16)
|
||||
|
||||
## 0. 基线
|
||||
|
||||
- 基线 commit:`05cf20fb`(`origin/staging` head,staging 已部署同一 SHA,含 BUG-747~752 的引导式补经历)。
|
||||
- 分支:`codex/rectification-year-focus-overlay-20260916`,`git worktree add -b codex/rectification-year-focus-overlay-20260916 .worktrees/rectification-year-focus-overlay-20260916 origin/staging`。
|
||||
- 串行:与 `TASK-console-noise-20260916.md` 无文件交集,可并行。
|
||||
- BUG 段:**BUG-908 起**(BUG-906/907 已被控制台噪音单占用;开工时核对 `docs/BUG_HISTORY.md` 最大号)。
|
||||
- Skill:本单要改 `SKILL.md` 的一句话(§5 T1c),按既有规则 bump 到 10.0.29,历史会话可打开的合同测试照跑(BUG-621 教训)。
|
||||
|
||||
## 1. 事故实证(产品负责人 2026-09-16 staging 真机)
|
||||
|
||||
对话顺序(用户原话已脱敏,只保留结构):
|
||||
|
||||
1. 服务器定向补事存在题:「身体上有没有过住院、手术、受伤或特别难熬的一段时间,哪一年都算?」A/B/C/D。用户选 A「有,我来填时间」。
|
||||
2. 用户在输入框打字给了「YYYY年M月做过手术」。
|
||||
3. 助手正文:「记下了。」+ **「YYYY年M月这次手术,是你本人做的吗?」**。时间轴「已完成 4 步 / 记下了:YYYY年M月做过手术。」→ 事件确实入账。
|
||||
4. 消息底部只读范围行:「目前范围 04:48–05:07,再说一件带年月的事就能继续」。
|
||||
5. 消息之后又出现一个**独立问题块**:同一句「是你本人做的吗?」,下面挂着「哪一类事(学业/事业/搬家/感情/家人/财务/健康)+ 发生年月」录入卡。产品原话:「为什么下面问问题了又出现个选择时间的卡,这个卡没用啊」「rectification-message-question UI 没跟消息对齐」。
|
||||
6. 用户回答了这个追问(是/不是一类的短句)→ 整轮报错 **「本轮达到步骤上限,状态已记录。」**
|
||||
|
||||
### 代码定位
|
||||
|
||||
| 现象 | 位置 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 问题块 + 录入卡 | `frontend/src/components/rectification-agentic-chat.tsx:1741-1780`(`questionGap === "persisted_question"` 分支) | 渲染 `currentQuestion.prompt`,且只要 `yearEntry` 非空就挂 `EventDateEntryCard`;`yearEntry = parseYearEntryQuestionId(currentQuestion.question_id)`(`:1427`),**只看题号**是不是 `collect:targeted:<domain>:year` / `collect:guided:window:…:year`,不看题干写的是什么 |
|
||||
| 题干被模型覆盖 | `frontend/src/mastra/rectification-v9-tools.ts:1218-1270`(`rectification-set-focus`,活动焦点与 `input.questionId` 同号的分支) | `withSpokenPrompt({...activeFocus.expectedAnswerSchema}, spoken.prompt)`(`spoken-prompt.ts:99-113`):schema 不是 `targeted_collect` 就直接把 `schema.prompt` 换成模型的话,`event_date_entry: true` 原样保留。于是「大概哪年几月?」变成「是你本人做的吗?」,卡还在 |
|
||||
| 校验拦不住 | `spoken-prompt.ts:24-97` `validateSpokenPrompt` | 无 `choice_frame` 的采集题只查长度、单问号、领域关键词;「手术」命中健康关键词即通过 |
|
||||
| 年月焦点为什么还活着 | `rectification-v9-tools.ts:1628-1646`(batch 写入后 resolve 活动采集焦点,条件 `isCollectFocusSchema`);`collection-question-pool.ts:881-905` `pendingTargetedYearDomain`(存在题 resolved、领域未覆盖、年月题未关闭 → 继续出 `:year`) | 事件已入账(时间轴有回执)但最终画面仍是 `:year` 焦点。两条可能:(a) 选 A 后由 `answer-choice.ts:934 persistNextInterviewAfterChoice` 落的年月焦点 schema 不满足 `isCollectFocusSchema`,batch 没 resolve;(b) 模型先 set-focus 后 batch,或 batch 后计划层因事件 domain/kind 没映射到 `health` 又出了一次 `:year`。**执行方必须用回放测试定出是哪一条**(§5 T2) |
|
||||
| 追问本身不该有 | `scripts/rectification/contracts.py:192-200` `subject_for_event_domain` 默认 `self`;存在题题干就是「身体上」;`rectification-v9-tools.ts:1515` batch 的 `subject` 默认 `self` | 服务器从没出过「主体」题。模型是按 `SKILL.md:100`「`needs_clarification` 不得猜补主体」自己加的追问;年月阶段的 hint(`method-followup.ts:2493`「若用户已说带年份的经历走 batch;否则继续问一件带大概年份的事」)没有禁止追问 |
|
||||
| 不对齐 | `frontend/src/app/globals.css:2969-2981` `.rectification-message-question` 无 `margin-inline-start`;同块里的 `.rectification-event-entry`(`:3089`)自带 `margin-inline-start: var(--assistant-content-inset)`;`.rectification-question-gap`(`:2985`)也带 | 消息内的同名块(`rectification-message-entry.tsx:169`,经 `chat-message-row.tsx:148` 的 `afterAnswer`)在消息正文里,天然有缩进;独立的 persisted 块在消息外,题干顶到左边、卡片却缩进了,三者三个左边线 |
|
||||
| 步骤上限 | `agent-run.ts:733` evidence 动作预算 8 步;`run-diagnostic.ts:88-90` 无正文即 `max_steps`;`agent-run.ts:898-910` host fallback 只在 batch `completed` 时兜底 | 用户回答「是/不是」时活动焦点仍是 `:year` 录入 schema,模型拿到的是「有年份走 batch,否则再问」的 hint,短句没有年月 → batch 写不进(`needs_clarification`/rejected)→ set-focus 同号幂等 → 循环到 8 步没正文;batch 没 completed 所以 fallback 也不接。**这是推断,不是实证**,本单按 `investigating` 记,T3 的回放测试要么复现要么写明复现不了 |
|
||||
|
||||
## 2. 根因(按层)
|
||||
|
||||
1. **数据层**:年月阶段焦点是服务器题(题干固定「大概哪年几月?」,答案走录入卡或带年月的自由文本),但 `set-focus` 允许模型用同号覆盖它的题干。定向存在题在 BUG-673 已经堵了这条(`targeted_collect` 只存 `spoken_prompt` 侧字段,不动 `prompt`),年月阶段没堵。
|
||||
2. **计划层**:事件入账后年月焦点没有随之关闭(§1 表 (a)/(b) 二选一,待回放定)。
|
||||
3. **提示层**:年月阶段的 hint 没说「用户给了年月就到此为止,不追问主体/原因/细节」;`SKILL.md:100` 的「不得猜补主体」被模型读成「要去问主体」。
|
||||
4. **表现层**:persisted 问题块没有和消息同一条左边线。
|
||||
|
||||
## 3. 决策记录
|
||||
|
||||
- 产品负责人 2026-09-16 授权:追问句下面不得出现录入卡;问题块与消息对齐;答完不得撞步骤上限。
|
||||
- **年月阶段的题干归服务器**:模型的 spokenPrompt 只能作旁白侧字段,不能替换 `prompt`。这不推翻 BUG-673(同一原则扩到年月阶段)。
|
||||
- **定向健康题主体默认本人,不追问**。`truth-consent-boundaries.md:30`「亲属主体必须显式标记」指的是用户自己说了「我妈住院」这类话时要标 `family`,不是让模型去问。用户原话没有亲属就是 `self`。
|
||||
- 用户在年月阶段用自由文本给了年月,等同于录入卡提交;不得再要求用卡。
|
||||
- 不改出卡时机、不改 `precision_gate`、不改 BUG-751 的「线没问完不出卡」。
|
||||
|
||||
## 4. 硬红线
|
||||
|
||||
1. `page.tsx` 不增长;`rectification-agentic-chat.tsx` 不新增 hook。
|
||||
2. BUG-673 的防复发(定向存在题焦点只允许点选形态;`persisted_question` 块不得画成卡片绕数据层)原样保留;本单是补年月阶段,不是重写焦点层。
|
||||
3. BUG-750 的录入卡提交文本格式不变;BUG-749 的 `GUIDED_ANY_DOMAIN` 解析不变。
|
||||
4. 既有断言只允许因 schema 形状变化而更新,写「原值 / 新值 / 原因」三栏;不得静默弱化。
|
||||
5. Skill bump 后 `frontend/tests/` 里的历史会话可打开合同测试必须绿(BUG-621)。
|
||||
6. 不得用生日推年份;不得因为本单把 `subject` 追问改成服务器题。
|
||||
|
||||
## 5. 任务分解
|
||||
|
||||
### T1 年月阶段焦点不可被模型覆盖(BUG-908)
|
||||
|
||||
- **T1a** `spoken-prompt.ts` `withSpokenPrompt`:`schema.event_date_entry === true` 与 `targeted_collect === true` 同等对待——只写 `spoken_prompt`,不动 `prompt`。
|
||||
- **T1b** `turn-decision.ts` `projectCurrentQuestion`(`:85` 起):`event_date_entry` 题投影 `prompt` 时只用服务器 `prompt`,忽略 `spoken_prompt`。前端 `persisted_question` 分支的题干因此恒为「大概哪年几月?」类服务器题干。
|
||||
- **T1c** 提示层:`method-followup.ts:2493` 那条 `active_focus` hint 与 `TARGETED_YEAR_PROMPT` 所在的年月 followup `user_prompt_hint`,补一句「用户给了年月就走 batch 写入并结束本题;不追问主体、原因、细节;定向健康题主体默认本人」。`SKILL.md:100` 改为「`needs_clarification` 不得猜补日期、主体……;用户原话没有亲属时主体就是本人,不要追问『是不是你本人』」。Skill bump 10.0.29。
|
||||
- 验收:
|
||||
- 新契约测试:活动焦点为 `collect:targeted:health:year`(`event_date_entry: true`)时调用 `set-focus`,同号、spokenPrompt 为一句不含年月的追问 → 焦点 `expected_answer_schema.prompt` 不变,`spoken_prompt` 为模型句;`projectCurrentQuestion` 得到的 `prompt` 是服务器题干。
|
||||
- `rectification-guided-collect-20260916.test.ts` 与 `rectification-targeted-*.test.ts` 原断言绿。
|
||||
|
||||
### T2 事件入账后年月焦点必须关闭(BUG-909)
|
||||
|
||||
- 先写回放测试定根因:存在题答 A → `persistNextInterviewAfterChoice` 落年月焦点 → 用 batch 写一件同领域带年月事件 → 断言活动焦点 `status=resolved`,且 `buildMethodFollowupPlan` 的 `next_followup` 不再是该领域 `:year`。
|
||||
- 若红在 resolve:修 `answer-choice.ts` 落年月焦点的 schema,使其满足 `isCollectFocusSchema`(带 `COLLECT_FOCUS_SCHEMA_KEY` 与 `prompt`),或修 batch 的 resolve 条件按题号前缀识别 `:year`(与 BUG-673「识别以题号前缀为准」同口径)。
|
||||
- 若红在计划层:修 `coveredCollectKinds` / 事件 `kind→CollectKind` 映射,让「手术/住院」类事件覆盖 `health`;并在 `pendingTargetedYearDomain` 里把「该领域已有本轮之后写入的带年月事件」也算 `yearClosed`。
|
||||
- 顺带:`rectification-propose-evidence`(单条写入,`rectification-v9-tools.ts:1708` 起)现在**不** resolve 采集焦点,只有 batch 会。让两条写入路径走同一段 resolve 逻辑(抽函数),否则模型走单条工具时 T2 复发。
|
||||
- 验收:回放测试绿;两条写入路径都有 resolve 断言;进度记录写明定出的是 (a) 还是 (b)。
|
||||
|
||||
### T3 年月阶段收到无年月短句不得烧完步骤(BUG-910,先 `investigating`)
|
||||
|
||||
- 在 `agent-run.ts:309-335` 日期可靠性分类器旁边加同形状的 host 前置:活动焦点 `event_date_entry === true` 且用户消息里没有年份(`19xx/20xx` 或「x 年」)→ 不进模型,host 直接以服务器题干再问一次(复用 `emitVisibleSpoken` 路径),不扣点、不占步骤;有年份则照常进模型。
|
||||
- 用回放测试复现 §1 的循环:活动 `:year` 焦点 + 消息「是」→ 修前应到 `max_steps`(或写明复现不了,改记 `investigating` 并保留 host 前置作为防御);修后 host 前置接住。
|
||||
- 验收:`run-diagnostic` 的 `max_steps` 映射不变;`applyHostFallback` 不改条件;新测试绿。
|
||||
|
||||
### T4 persisted 问题块与消息同一条左边线(BUG-911)
|
||||
|
||||
- `globals.css`:给 `rectification-agentic-chat.tsx:1741` 的独立块加修饰类(如 `.rectification-message-question.is-standalone`),`margin-inline-start: var(--assistant-content-inset)`;块内的 `.rectification-event-entry` 与 `.rectification-choice-card.is-embedded` 把自己的 `margin-inline-start` 归零,避免双重缩进。消息内的同名块不动。
|
||||
- 验收:`chart-page-view.test.tsx` 同款的 CSS 声明断言:独立块有 inset、块内卡片 inset 为 0;`frontend/DESIGN.md` 记一句「校正独立问题块与助手正文共用 `--assistant-content-inset`」。
|
||||
|
||||
### T5 记录
|
||||
|
||||
- `docs/BUG_HISTORY.md`:BUG-908~911(T3 按实证状态写 `resolved` 或 `investigating`)。
|
||||
- `CHANGELOG.md`:年月阶段不再被追问覆盖;问题块对齐;Skill 10.0.29。
|
||||
- `docs/tasks/PROGRESS-rectification-year-focus-overlay-20260916.md`:tsc / lint / test 数字与基线失败清单逐条比对、gzip、`/` Static。
|
||||
- `docs/testing/rectification-year-focus-overlay-20260916.md` 真机清单(§8)。
|
||||
|
||||
## 6. 让步顺序
|
||||
|
||||
1. T3 的 host 前置若与 `date_reliability` 分类器抢同一段(两者都看活动焦点 schema),按「先日期可靠性、后年月录入」排序,写进注释。
|
||||
2. T2 若两条根因都红,先修 resolve(数据层),计划层的 `yearClosed` 扩展作第二提交。
|
||||
3. T1c 的 Skill 改动若因 hash 合同测试卡住,可只改 hint 不改 SKILL.md,进度记录写明,产品下一轮再 bump。
|
||||
4. T4、T5 不可让步。
|
||||
|
||||
## 7. 开工前置命令
|
||||
|
||||
```bash
|
||||
git fetch origin --prune
|
||||
git worktree add -b codex/rectification-year-focus-overlay-20260916 .worktrees/rectification-year-focus-overlay-20260916 origin/staging
|
||||
cd .worktrees/rectification-year-focus-overlay-20260916/frontend
|
||||
./node_modules/.bin/tsc --noEmit && npm run lint && npm test 2>&1 | tail -20 # 记基线总数与失败清单
|
||||
grep -o "BUG-[0-9]\+" ../docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1 # 核对起始号
|
||||
grep -rn "10.0.28" ../skills/jyotish-birth-time-rectification/SKILL.md ../frontend/src/lib/rectification-agentic/*.ts | head # Skill 版本落点
|
||||
```
|
||||
|
||||
验收口径:`tsc` 0 错;lint 0 error;`npm test` 失败清单与基线逐条一致且总数不减;`next build` 后 `/` 仍 Static;首屏 gzip ±2%;Python 不动则不跑快速门。
|
||||
|
||||
## 8. 环境缺口(留给产品负责人真机)
|
||||
|
||||
- 定向健康题选 A 后在输入框打字给一件带年月的事:助手只说「记下了」,不追问「是不是你本人」;下面**没有**录入卡;如有下一题则是下一题。
|
||||
- 若助手仍口头追问了别的,回一句短句不应再出现「本轮达到步骤上限」。
|
||||
- 任何独立问题块(题干 + 卡)左边线与助手正文对齐。
|
||||
Reference in New Issue
Block a user