feat: streamline conversational birth-time rectification
This commit is contained in:
@@ -313,3 +313,99 @@
|
||||
- 相关记录:BUG-008、BUG-009、BUG-016、ERR-085、ERR-091
|
||||
- 复发自:无
|
||||
- 修复版本:待提交(生产 smoke 待当前精确 SHA 发布后补齐)
|
||||
|
||||
## BUG-018 | 生时校正把语言问答包装成高阻力卡片表单
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-07-22
|
||||
- 最近更新:2026-07-22
|
||||
- 影响面:首页生时校正会话、经历录入、候选核对与更正
|
||||
- 用户现象:每轮同时出现候选卡、领域按钮、年份与月份下拉、经历回顾卡和确认卡;用户需要理解多层控件才能回答一个问题,移动端尤为费力。
|
||||
- 触发条件:进入生时校正并提交或更正一条真实经历。
|
||||
- 根因:后端已有自由文本证据契约,但前端仍用结构化表单和多卡片包装;校正叙事 Agent 也未加载 Jyotish Skill 来生成自然、逐问式的取证措辞。
|
||||
- 修复:改为一段助理提问加一个自然语言输入框;候选状态和证据历史收进可展开进度区;保留明确确认、更正、持久化、计费、计算和分钟验证门禁;叙事 Agent 加载 Jyotish Skill,但服务端技术包仍是候选事实和确认权限的唯一来源。
|
||||
- 验证:语言优先组件静态与真实 Chromium 390px 回归 8/8 通过;校正路由与叙事契约 23/23 通过;目标文件 ESLint 和 Next.js production build 通过。
|
||||
- 防复发:语言问答不得重新拆成领域按钮或日期下拉;Skill 只能改进问题策略与措辞,不得生成、重算或确认候选时间。
|
||||
- 相关记录:BUG-008、BUG-009、BUG-015、BUG-016、BUG-017
|
||||
- 复发自:无
|
||||
- 修复版本:待提交(本地可测)
|
||||
|
||||
## BUG-019 | 自然语言真实事件在分钟评分入口被静默丢弃
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-07-22
|
||||
- 最近更新:2026-07-22
|
||||
- 影响面:生时校正自然语言抽取、历史事件持久化、分钟评分、首轮与兜底叙事
|
||||
- 用户现象:用户已经提供带日期的真实经历,系统仍反复索取证据;首轮回答展示完整 D 层技术清单,却没有用一个具体问题推进取证。19 世纪事件、疾病、手术、事故和丧亲尤其容易无法参与评分。
|
||||
- 触发条件:日期早于 1900 年;事件属于健康或重大压力;累计有效事件超过 6 条;或叙事模型未满足首轮全量技术层合同而进入确定性兜底。
|
||||
- 根因:前端日期正则写死 1900–2099;健康类关键词落入 `other`,并在路由中被过滤,尽管后端已有 `health_pressure` 与 D30 评分支持;路由另有独立的 6 条截断;叙事校验强制首轮正文列出全部稳定层、敏感层和值。
|
||||
- 修复:日期抽取支持 1000–2099 的四位历史年份;健康、事故、丧亲映射到既有 `health_pressure`/D30 合同并贯通持久化、旧数据导入和公开 turn schema;评分截断统一复用 8 条收敛上限;技术包和 validation receipt 继续完整保存,但非最终用户正文只呈现候选范围、未确认边界和一个高信息量问题,确定性兜底也遵守相同语言交互。
|
||||
- 验证:抽取、叙事、路由聚焦测试 59/59 通过;真实案例回放、编排和端到端契约 65/65 通过;目标文件 ESLint、Python replay/compilation、`git diff --check` 和 Next.js production build 通过。公开 smoke 中 Steve Jobs、Einstein、Marie Curie 分别保留 4、3、4 条可评分事件,产品过滤结果与结构化 oracle 一致。
|
||||
- 防复发:新增 18xx 中文与 ISO 日期、健康/事故/丧亲、8 条事件上限和单问题兜底断言;技术层可进入服务端证据包,不得重新进入普通会话正文;family/other 仍是持久化背景,不得伪装成已评分领域。
|
||||
- 相关记录:BUG-008、BUG-009、BUG-015、BUG-016、BUG-018
|
||||
- 复发自:BUG-018
|
||||
- 修复版本:待提交(本地可测)
|
||||
|
||||
## BUG-020 | 生时校正入口等待首轮请求完成后才切换会话
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-07-22
|
||||
- 最近更新:2026-07-22
|
||||
- 影响面:首页生时校正入口、普通咨询中的“先完成生时校正”、侧栏恢复校正会话
|
||||
- 用户现象:点击生时校正后长时间停留在首页或原咨询 session,直到恢复、建案、计算和会话持久化全部完成才突然跳转,用户容易误以为点击无效并重复操作。
|
||||
- 触发条件:`start`、`resume`、durable handoff 或 session persistence 任一请求响应较慢。
|
||||
- 根因:`openBirthTimeRectification` 虽然先设置了 loading,但专属 session 的插入、激活和校正 surface 的开放都位于首个异步请求之后;surface 还要求首个 turn 已存在,因此 loading 状态无法在目标会话中显示。
|
||||
- 修复:创建或复用专属 session 后,在任何 `await` 之前立即插入并激活该 session;校正 surface 允许以空 turn 渲染既有“正在建立校正记录…”状态;增加同步 in-flight 门禁防止快速重复点击发出多个启动请求;失败时新建 session 回滚到来源会话,复用 session 则保留可见错误与重试入口。
|
||||
- 验证:`frontend/tests/consultation-entrypoint.test.ts` 21/21 通过,锁定 session 插入、激活和 loading surface 必须早于首个异步请求,并锁定单请求门禁;目标文件 ESLint、`git diff --check` 和 Next.js production build 通过;真实应用内 Chromium 从首页点击时,在后台恢复完成前已经显示“正在建立校正记录…”,从普通会话切回校正 session 也立即显示目标会话。
|
||||
- 防复发:首页卡片、普通 session 建议和侧栏恢复必须继续共用同一启动函数;不得重新用首个 turn 是否返回作为 session 可见性的条件。
|
||||
- 相关记录:BUG-016、BUG-018、BUG-019
|
||||
- 复发自:无
|
||||
- 修复版本:待提交(本地可测)
|
||||
|
||||
## BUG-021 | 初始化地址保存后的加载提示仍指向生时评估
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-07-22
|
||||
- 最近更新:2026-07-22
|
||||
- 影响面:新用户初始化流程、出生地点保存后的全屏加载提示
|
||||
- 用户现象:用户填完出生地址后,页面实际准备进入首页,但加载提示仍显示正在生成生时评估,造成流程去向与界面文案不一致。
|
||||
- 触发条件:初始化流程完成出生时间填写,并提交最后一步出生地点。
|
||||
- 根因:出生时间保存和出生地点保存共用 `saving_profile` 展示阶段;该阶段文案仍按旧流程描述为即将生成生时评估。
|
||||
- 修复:新增独立的 `entering_home` 展示阶段,仅在 `saveOnboardingPlace` 提交地址时使用,显示“正在进入首页 / 出生资料已保存,正在为你准备首页。”;出生时间保存继续使用原 `saving_profile` 阶段。
|
||||
- 验证:聚焦测试锁定地址提交与 `entering_home` 的绑定及目标文案;目标文件 ESLint 与 `git diff --check` 通过。
|
||||
- 防复发:初始化步骤的加载文案必须绑定实际导航结果;不得通过修改共享 `saving_profile` 文案改变出生时间提交阶段的语义。
|
||||
- 相关记录:BUG-020
|
||||
- 复发自:无
|
||||
- 修复版本:待提交(本地可测)
|
||||
|
||||
## BUG-022 | 侧栏会话标题与更多操作被拆成两块
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-07-22
|
||||
- 最近更新:2026-07-22
|
||||
- 影响面:聊天记录侧栏、当前会话选中态与更多操作入口
|
||||
- 用户现象:会话标题显示在一块选中背景中,右侧更多操作却以独立圆形按钮悬在外侧,看起来像两个不一致的控件。
|
||||
- 触发条件:侧栏展开并选中任意会话。
|
||||
- 根因:选中背景只应用在左侧 `.session-main`,右侧 `.session-menu-trigger` 又单独使用 `50%` 圆角和悬停背景。
|
||||
- 修复:把选中、悬停和聚焦背景统一应用到整行 `.session-row`;子按钮保持透明,并移除更多操作按钮的独立圆形底色。
|
||||
- 验证:侧栏契约测试锁定整行选中背景、透明标题按钮和非圆形更多操作按钮;目标文件 ESLint 与 `git diff --check` 通过。
|
||||
- 防复发:会话标题和行内操作必须共享同一个行级状态面,不得分别绘制互相竞争的选中背景。
|
||||
- 相关记录:无
|
||||
- 复发自:无
|
||||
- 修复版本:待提交(本地可测)
|
||||
|
||||
## BUG-023 | 健康压力追问被数据库误判为校正操作冲突
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-07-22
|
||||
- 最近更新:2026-07-22
|
||||
- 影响面:生时校正首条自然语言回答、`POST /api/birth-time-conversation`、Supabase 对话持久化契约
|
||||
- 用户现象:用户提交一条带年月的真实经历后等待约一分钟,接口返回 `409 action_conflict`,页面提示加载最新进度后重试;重复提交仍无法进入下一问。
|
||||
- 触发条件:技术包为下一轮选择 `health_pressure`(健康与重大压力)作为待补证据领域。
|
||||
- 根因:应用层已把 `health_pressure` 作为正式领域,并允许语言问答每轮只追问一个重点领域;durable SQL 既缺少该领域,又要求 evidence request 至少包含两个领域。完整计算和叙事生成完成后,`save_conversational_rectification_turn` 才以 `conversational_action_conflict` 拒绝公开 turn。
|
||||
- 修复:新增向前迁移,将 `health_pressure` 同步加入四个 durable validator 和事件证据表约束,并把 evidence request 基数从 2–4 对齐为应用契约的 1–4;保留现有幂等、版本和候选确认门禁。
|
||||
- 验证:真实浏览器复现确认只有 `conversational_rectification_valid_evidence_request` 失败,其余公开 turn 子结构、事件、回执和私有候选均通过;迁移应用到测试 Supabase 后,用同一条“2023 年 3 月离家来北京工作”重放,`POST /api/birth-time-conversation` 返回 `200`,日志为 `actionKind: answer`、`resultCategory: success`,事件规范化保存为 `2023-03 · 离家来北京工作`,页面继续自然追问学业经历且输入框恢复可用;聚焦迁移测试锁定四个 validator 与表约束必须共同支持该领域。
|
||||
- 防复发:应用 evidence domain 枚举新增值时,必须同时更新 TypeScript schema、公开 recap/request、私有候选、事件表约束和迁移契约测试;不得把正常领域扩展映射为通用 409。
|
||||
- 相关记录:BUG-007、BUG-018、BUG-019
|
||||
- 复发自:BUG-007
|
||||
- 修复版本:待提交(测试 Supabase smoke 通过)
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
# 对话式生时纠正修改方案与真实回放门槛
|
||||
|
||||
日期:2026-07-22
|
||||
|
||||
## 结论先行
|
||||
|
||||
当前系统可以改成普通 session 式的一问一答,但不能把“交互更顺”描述成“已经能准确到分钟”。现有公开开发案例的分钟评分仍不稳定;产品入口还会丢弃健康、事故、家庭类证据,并且实际只把最近 6 条事件送入评分。
|
||||
|
||||
本方案把修改拆成两个互不混淆的目标:
|
||||
|
||||
1. 让用户通过自然语言持续补充经历,系统每轮只问一个最有区分力的问题。
|
||||
2. 用开发集和独立冻结盲测证明分钟排序是否真的收敛;没有通过门槛时只返回候选范围和证据缺口。
|
||||
|
||||
## 已确认的问题
|
||||
|
||||
### 1. 首轮正文被技术回执合同绑架
|
||||
|
||||
`narrative-agent.ts` 当前要求首轮正文复述所有稳定层、敏感层、具体值和领域映射。模型未满足时,fallback 又会输出同一份 D 层清单。技术包本身可以保留,但不应该成为用户正文。
|
||||
|
||||
### 2. 自然语言证据域不完整
|
||||
|
||||
`evidence-extractor.ts` 只显式识别事业、学业、迁移、关系、家庭、财富。疾病、手术、事故和丧亲会落到 `other`;`route.ts` 又会排除 `family` 和 `other`,所以 D30、家庭与部分重大人生事件无法参与评分。
|
||||
|
||||
日期正则还被限制为 1900–2099 年。公开历史人物案例中的 18xx 年事件会被保存成“日期未知”,无法评分;这也意味着现有历史 AA 开发案例并没有真正通过当前产品的自然语言入口。
|
||||
|
||||
### 3. 事件数量合同互相矛盾
|
||||
|
||||
- 会话收敛层:3 条开始排序,8 条停止继续取证。
|
||||
- 路由评分层:只保留最近 6 条。
|
||||
- Jyotish Skill:至少 5 条 dated events 才适合定框;高置信度通常需要 10–15 条多领域事件。
|
||||
|
||||
3 条可以产生早期候选反馈,但不得升级成准确分钟。停止条件也不能仅由事件数量触发。
|
||||
|
||||
### 4. 当前问题选择仍偏“让用户交材料”
|
||||
|
||||
系统应从候选差异中选择一个信息增益最高、用户容易回忆的问题,例如“第一次正式工作是哪年哪月”,而不是一次要求用户提交多个领域的事件。
|
||||
|
||||
## 最小实施方案
|
||||
|
||||
### 阶段 A:修正文合同,不改评分器
|
||||
|
||||
建议改动:
|
||||
|
||||
- `frontend/src/lib/conversational-rectification/narrative-agent.ts`
|
||||
- 首轮正文只要求:当前范围、尚未确认边界、证据进度、一条具体问题。
|
||||
- 取消首轮必须公开全部 stable/sensitive layer values 的校验。
|
||||
- fallback 同样只输出一条问题。
|
||||
- 技术层继续完整保存在 technical packet / receipt 中,在 UI 中放入可折叠“计算依据”。
|
||||
- 用户消息区、输入框、滚动和留白完全复用普通 session 布局,不保留卡片式问卷。
|
||||
|
||||
验收:首轮正文不出现 D1/D9/D10 技术 dump;每轮只有一个问号和一个待回答主题。
|
||||
|
||||
### 阶段 B:补齐事件入口
|
||||
|
||||
建议改动:
|
||||
|
||||
- 在持久化和技术包域中新增 `health_pressure`,不要把它降级成 `other`。
|
||||
- 抽取器识别:确诊、住院、手术、事故、受伤、创伤、重大疾病、康复。
|
||||
- 日期解析支持出生之后的合法公历年份,而不是写死 19xx/20xx;继续用 `asOfDate` 排除未来事件。
|
||||
- 家庭事件不要整体丢弃;按父母、子女、生育、丧亲等映射到后端支持的主题证据,若评分器尚无对应合同则明确存储为 context-only,而不是静默消失。
|
||||
- 移除 `.slice(-6)` 的隐式截断。建立一个共享常量;建议开发回放先测 5、8、10、12 条,再决定产品上限。
|
||||
- UI 显示“已记录 / 可评分 / 需补日期 / 仅作背景”的数量,避免用户以为回答已评分。
|
||||
|
||||
验收:真实测试集中所有标记为可评分的自然语言回答都能保留正确日期、精度和领域;任何被排除的事件都有可见原因。
|
||||
|
||||
### 阶段 C:一次问一个高信息量问题
|
||||
|
||||
复用现有 `candidateDifferences`、`suggestedDomains` 和 fact difference opportunities:
|
||||
|
||||
1. 过滤已经问过、用户表示不记得、或缺少后端支持的主题。
|
||||
2. 优先选择能把当前候选分成最均衡分区的事件领域。
|
||||
3. 将领域转成生活化问题,并要求“年份/月份 + 发生了什么”。
|
||||
4. 用户回答后重新排序,再选择下一题。
|
||||
|
||||
问题模板必须具体,例如:
|
||||
|
||||
> 你第一次明显的工作转折发生在什么时候?可以是入职、离职、换行业、升职或创业。直接告诉我大约哪一年哪一月和发生了什么;记不清月份也可以先说年份。
|
||||
|
||||
### 阶段 D:安全收敛
|
||||
|
||||
每轮都可以展示“当前领先范围”,但只有同时满足以下条件才允许提示确认:
|
||||
|
||||
- 至少 5 条可评分事件,且至少 3 个领域;高置信度目标使用 10–15 条。
|
||||
- 真实候选形成唯一分钟或预先规定的窄范围。
|
||||
- ±1/2/5 分钟邻近稳定性通过。
|
||||
- leave-one-event-out 通过,不能由单一事件决定结果。
|
||||
- 没有缺失的强制计算层。
|
||||
- 独立冻结盲测达到发布指标。
|
||||
|
||||
未满足时输出:候选范围、支持事件、冲突事件、未评分事件和下一条问题,不允许写“准确时间为”。
|
||||
|
||||
## 测试集分层
|
||||
|
||||
### 对话开发回放集
|
||||
|
||||
文件:`references/real_case_calibration/conversational_rectification_development_v1.json`
|
||||
|
||||
当前 v1 是入口 smoke fixture,不是分钟收敛 benchmark:TypeScript 测试验证 fixture 中自然语言在现有抽取器下的日期、精度和领域;Python 回放使用同一 fixture 的人工 `expected_route_scoreable` 标签模拟现有路由过滤,再测试逐轮排名。它不是自然语言到评分的端到端回放,且每例不足 5 条可评分事件,不能用于判断 Skill 级收敛。
|
||||
|
||||
下一版 development benchmark 必须把每例扩充至至少 5 条、目标 10–15 条多领域事件,并直接调用抽取器和路由投影,覆盖记不清、拒答、否定、纠正、重复和一条消息多事件。它引用仓库已有公开 AA 开发案例,永久排除在 holdout 之外,可以用于修 bug 和调问题排序。
|
||||
|
||||
### 独立冻结 holdout v4
|
||||
|
||||
开发集不能证明发布准确率。正式验证需要另一位 reviewer 收集至少 20 个未参与调参的公开 AA 案例,在评分前完成:出生来源复核、事件来源复核、假分钟承诺、manifest hash、实现 hash 和真值密封。只允许盲回放一次;失败后整批降为 development,下一版重新收集 fresh holdout。
|
||||
|
||||
## 指标
|
||||
|
||||
对话入口:
|
||||
|
||||
- 日期和精度提取准确率。
|
||||
- 领域提取准确率。
|
||||
- 应评分事件保留率。
|
||||
- 每轮问题数必须等于 1。
|
||||
- 不能回答、记不清、纠正旧答案时仍能继续。
|
||||
|
||||
分钟能力:
|
||||
|
||||
- 3、5、8、10 条事件时的 Top-1 / Top-3。
|
||||
- 逐轮真实分钟排名和误差轨迹。
|
||||
- 唯一分钟率、邻近稳定性、leave-one-out。并列范围未破时 `predicted_time` 必须为空;如保留确定性 tie-break,只能单列为诊断 MAE,不能当成分钟能力。
|
||||
- false confirmation rate 和 confirmation coverage 必须同时报告。
|
||||
|
||||
建议继续沿用当前发布门槛:Top-1 ≥ 60%,Top-3 ≥ 85%,MAE ≤ 2 分钟,false confirmation ≤ 5%,insufficient-evidence rejection ≥ 90%。confirmation coverage 不能为 0,否则只是“永不确认”而非可用收敛。
|
||||
|
||||
## 实施顺序
|
||||
|
||||
1. 先合并阶段 A 与入口可观测性,不改变“准确分钟”声明。
|
||||
2. 用本开发回放集修阶段 B,确保事件没有在入口丢失。
|
||||
3. 接入阶段 C 的单问题排序并做多轮 replay。
|
||||
4. 当开发集达到稳定目标后,冻结实现并收集 fresh holdout v4。
|
||||
5. 只有 holdout 通过后才开放分钟确认;否则产品始终停在候选范围。
|
||||
Reference in New Issue
Block a user