Files
Jyotisha/docs/BUG_HISTORY.md
T
2026-07-27 12:01:31 +08:00

165 KiB
Raw Blame History

Bug History

本文件是本仓库产品与代码 Bug 的长期知识库。处理任何 Bug 前先读并搜索本文件;完成修复或确认阻塞后,在同一变更中更新本文件。

基础设施、外部引擎、碎片目录和开工预检类风险仍记录在 docs/research/pre_work_error_ledger.md。同一问题若同时影响两类台账,应互相引用,不复制大段内容。

使用流程

  1. 用报错原文、接口路径、状态码、模块名和用户操作搜索本文件。
  2. 找到相似记录时,先验证既有防复发措施是否仍存在,再定位新的回归入口。
  3. 修复必须包含与风险相称的自动化测试;生产问题还要记录部署版本和脱敏后的生产验证。
  4. 完成后更新已有记录,或按下方模板添加新记录。复发问题必须填写 复发自,不能伪装成无关的新问题。
  5. 不记录姓名、出生资料、邮箱、用户/案例 ID、Cookie、JWT、密码、密钥、完整请求体或模型原文。

状态定义

  • investigating:现象已确认,根因未确认。
  • blocked:缺少权限、环境或外部条件,当前无法继续验证。
  • mitigated:用户影响已被安全降级,但根因或全链路尚未闭环。
  • resolved:根因已修复,并有自动化或真实环境证据。
  • regressed:历史问题再次出现;必须关联原记录并说明旧防线为何失效。

新记录模板

## BUG-NNN | 简短标题

- 状态:investigating | blocked | mitigated | resolved | regressed
- 首次发现:YYYY-MM-DD
- 最近更新:YYYY-MM-DD
- 影响面:页面、接口或模块
- 用户现象:脱敏后的可观察现象
- 触发条件:最小复现路径
- 根因:已验证的技术原因;未知时明确写未知
- 修复:实际采取的最小修复
- 验证:测试、生产 smoke、迁移账本或监控证据
- 防复发:测试、约束、监控或发布门禁
- 相关记录:BUG-NNN / ERR-NNN;没有则写无
- 复发自:BUG-NNN;首次出现则写无
- 修复版本:Git SHA、迁移版本或待发布

已记录问题

BUG-001 | 对话删除不可用或只改变前端状态

  • 状态:resolved
  • 首次发现:2026-07-21
  • 最近更新:2026-07-21
  • 影响面:会话列表、DELETE /api/sessions/[id]、Supabase chat_sessions
  • 用户现象:用户点击删除后对话无法真正删除,或删除交互与账户弹窗不一致。
  • 触发条件:登录后删除自己的一条历史会话。
  • 根因:删除曾缺少所有者约束的服务端入口和对应数据库授权,前端也没有统一的站内确认面。
  • 修复:增加所有者约束的服务端删除接口与数据库 grant,并统一站内确认弹窗。
  • 验证:tests/test_session_management_entrypoints.pyfrontend/tests/chat-session-delete-contract.test.ts
  • 防复发:删除必须经服务端所有权校验;测试同时锁定 API、迁移和前端入口。
  • 相关记录:无
  • 复发自:无
  • 修复版本:e3d619c65b8c425650ed1fcf5794

BUG-002 | Onboarding 首次请求 409、重复请求或读到旧问题

  • 状态:resolved
  • 首次发现:2026-07-21
  • 最近更新:2026-07-21
  • 影响面:POST /api/onboarding、首页入门问题缓存与恢复
  • 用户现象:出生资料已经填写,第一次请求仍返回资料未完成或 pending,随后又请求一次并返回缓存结果。
  • 触发条件:入门资料完成、缓存生成尚未结束或资料在并发生成期间发生变化。
  • 根因:缓存就绪/处理中状态没有完整绑定当前资料指纹,旧请求完成时可能覆盖新资料的生成结果。
  • 修复:用全部决策字段生成无明文 SHA-256 身份;领取和完成都使用版本、时间戳和 pending 身份 CAS,并校验账户所有权。
  • 验证:onboarding route/cache/candidate completion 测试矩阵,历史完整前端套件 455/455。
  • 防复发:缓存命中、pending、超时回收和完成写入必须绑定同一资料身份;任何旧请求只能返回安全 pending
  • 相关记录:无
  • 复发自:无
  • 修复版本:28d58d45ee925c308e5d5e13d595346ec02a9ffbd9

BUG-003 | 浏览器原始报错 “The string did not match the expected pattern” 泄露给用户

  • 状态:resolved
  • 首次发现:2026-07-21
  • 最近更新:2026-07-21
  • 影响面:生时校正自动流程、候选时间确认、“都不符合”分支
  • 用户现象:选择候选时间或“都不符合”后直接看到浏览器英文 DOMException。
  • 触发条件:自动或手动生时流程中的底层浏览器/传输异常进入未归一化错误分支。
  • 根因:部分 journey effect 直接展示实现层异常信息,没有统一转换为安全、可操作的中文错误。
  • 修复:所有相关 mutation/effect 统一经 birthTimeUserError 归一化,屏蔽 DOMException、网络和语法实现细节。
  • 验证:frontend/tests/birth-time-user-errors.test.ts 包含该英文原文回归用例。
  • 防复发:禁止 setError(caught.message);新增异步入口必须走统一错误映射。
  • 相关记录:无
  • 复发自:无
  • 修复版本:a38a096

BUG-004 | 点击生时校正后先进入中间卡片,失败时无法自然回到首页

  • 状态:resolved
  • 首次发现:2026-07-21
  • 最近更新:2026-07-22
  • 影响面:首页生时校正入口、首轮加载与恢复 UI
  • 用户现象:点击入口后先看到“开始生时校正”或“正在恢复账户里的校正进度”卡片;依赖失败时停留在重试卡片。
  • 触发条件:首轮校时 RPC 尚未返回或返回失败。
  • 根因:页面在首轮有效 turn 生成前就切换到专用校正会话。
  • 修复:首轮生成期间保持首页;只有有效首轮 turn 返回后才进入校正会话,失败以首页输入区提示呈现。
  • 验证:frontend/tests/consultation-entrypoint.test.ts 及生产入口 smoke。
  • 防复发:会话切换以“首轮可展示结果”而非“请求已发出”为边界。
  • 相关记录:ERR-087
  • 复发自:无
  • 修复版本:dc0077e

BUG-005 | 保存出生时间返回 PATCH /api/account 500

  • 状态:resolved
  • 首次发现:2026-07-21
  • 最近更新:2026-07-22
  • 影响面:账户出生资料、Supabase profiles
  • 用户现象:选择记录时间和误差后显示“暂时无法保存账户资料”,接口返回 500。
  • 触发条件:账户已被候选时间写入 reported 字段,之后再次编辑原始出生时间声明。
  • 根因:旧触发器把候选/活动时间复制为用户报告时间,同时数据库又把报告时间视为不可变字段。
  • 修复:报告时间保持可编辑,禁止候选时间反写原始声明,修复不一致历史行并增加来源/时间一致性约束。
  • 验证:迁移 20260721140000 已进入生产账本;生产合成账户修改与恢复均返回 200。
  • 防复发:候选、活动、用户报告时间保持独立语义;profile persistence 测试锁定迁移行为。
  • 相关记录:ERR-088
  • 复发自:无
  • 修复版本:dc0077e20260721140000_repair_reported_birth_time_revision.sql

BUG-006 | 生时校正首轮在没有历史事件时进入确认态并返回 409

  • 状态:resolved
  • 首次发现:2026-07-21
  • 最近更新:2026-07-22
  • 影响面:POST /api/birth-time-conversation 首轮、计费释放
  • 用户现象:等待约一至两分钟后首轮返回 action_conflict,费用预留被释放。
  • 触发条件:技术扫描在零条历史事件时直接返回 ready_for_confirmation
  • 根因:应用构建了 confirming 首轮,而数据库契约只允许首轮为 active;技术就绪错误绕过了三条有效历史事件的业务门槛。
  • 修复:所有技术包统一经过 MINIMUM_SCOREABLE_EVENTS 门禁;未满三条时清除 result ID,并保持 pending_validation/active
  • 验证:核心 orchestrator/e2e 回归测试;生产首轮随后成功创建并收费一次。
  • 防复发:确认态只能由三条以上有效、已发生、可评分事件触发。
  • 相关记录:ERR-089
  • 复发自:无
  • 修复版本:b8ed740

BUG-007 | finance 证据通过应用校验但被数据库拒绝为 409

  • 状态:resolved
  • 首次发现:2026-07-21
  • 最近更新:2026-07-22
  • 影响面:生时校正技术包、事件证据、Supabase durable validators
  • 用户现象:真实首轮计算完成后仍返回统一的 action_conflict
  • 触发条件:D2/D11 产生 finance 建议主题,或摘要包含应用已支持的 domain 字段。
  • 根因:TypeScript 已支持 finance 和摘要 domain,初始 SQL 枚举及表约束仍是旧版本。
  • 修复:向前迁移同步 evidence request、life event、private candidate、public recap 和事件表约束。
  • 验证:迁移 20260721150000 已进入生产账本;迁移契约测试和生产首轮 smoke 通过。
  • 防复发:应用证据枚举变更必须同时更新 durable SQL,并由迁移契约测试检查。
  • 相关记录:BUG-006、ERR-090
  • 复发自:无
  • 修复版本:b981c4e20260721150000_align_conversational_finance_domain.sql

BUG-008 | 后续证据把范围压得过窄后返回 503

  • 状态:resolved
  • 首次发现:2026-07-21
  • 最近更新:2026-07-22
  • 影响面:生时校正后续回答、技术包构建
  • 用户现象:首轮、“都不符合”、暂停恢复均正常,但提交后续明确事件时返回 service_unavailable
  • 触发条件:事件评分产生的窄区间不足两个时间样本或不足两个可区分分盘主题。
  • 根因:这是“证据仍不足”的正常业务状态,代码却把它作为 TypeError 依赖故障终止。
  • 修复:显式分类区间区分度不足;撤回本次过度收窄,保留上一候选范围、评分证据和未确认状态,然后继续提问或安全保存范围。
  • 验证:核心回归 85/85;生产从失败点续跑通过;全新生产 smoke 覆盖资料、首轮、“都不符合”、暂停恢复、多事件、范围终态、计费和问题交接。
  • 防复发:任何新候选范围必须先满足技术证据契约;不满足时回退,不返回 503,也不伪造确定分钟。
  • 相关记录:ERR-091
  • 复发自:无
  • 修复版本:b981c4e

BUG-009 | 未校正的已填报时间被降级为零星盘咨询

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:生日初始化、普通咨询路由、生时校正提示
  • 用户现象:已填写具体出生时间但没有完成生时校正时,普通问题仍提示只能回答一般知识或必须先完成校正。
  • 触发条件:出生时间来源包含有效具体分钟,但状态不是 confirmed,且当前聊天没有旧的临时授权状态。
  • 根因:前端把“使用未校正填报时间”设计成逐会话授权;没有授权时默认退回 general_no_birth_time,因此完全绕过现有的未校正星盘安全模式。
  • 修复:具体填报时间现在自动进入 unverified_birth_time,保留禁止精确应期的安全边界但不禁用个人分析;无具体分钟时直接进入无分钟模式;移除校正 toast、弹窗和每条回答前重复的校正警告,并把生日入口收敛为“知道准确时间 / 不确定准确时间”两个选择。
  • 验证:frontend/tests/birth-time-consultation-consent.test.tsfrontend/tests/consultation-entrypoint.test.tsfrontend/tests/consultation-birth-time-mode.test.tsfrontend/tests/birth-time-intake.test.ts
  • 防复发:咨询路由测试锁定“有效填报分钟无需授权即可使用”;页面契约禁止重新引入生时校正 toast 或阻断式选择。
  • 相关记录:BUG-003、BUG-004
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-010 | 浏览器直连 Supabase 写会话泄露 TypeError: Load failed

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:回答完成后的聊天记录持久化、移动 Safari 错误提示
  • 用户现象:回答已经生成,但页面反复显示“云端同步失败:TypeError: Load failed”,并要求复制保存后重试。
  • 触发条件:浏览器直接向 Supabase chat_sessions 发起跨域写入时发生传输失败。
  • 根因:会话读取和多数业务写入已经使用同源 Next.js API,但会话创建与更新仍由浏览器客户端直写 Supabase;异常原文又被拼进回答错误区域。
  • 修复:新增同源 POST /api/sessionsPATCH /api/sessions/[id],服务端校验登录、所有权和写入负载;客户端对可重试失败短重试一次,并把最终失败降级为输入区状态提示,不再把浏览器异常原文渲染成回答错误。
  • 验证:frontend/tests/chat-session-write.test.ts 覆盖同源路由、所有者约束、短重试和 Load failed 脱敏;相关咨询与资料回归测试通过。
  • 防复发:会话写入契约禁止页面直接调用 supabase.from("chat_sessions");网络异常必须映射为稳定用户文案。
  • 相关记录:BUG-001、BUG-003
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-011 | 对话消息暴露内部证据审计状态

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:普通问答消息、Agent 回答顶部区域
  • 用户现象:回答正文上方显示“证据状态:not-applicable”和“证据链摘要 · not-applicable”等工程审计信息,正文下方还显示单条回答的报告下载控件。
  • 触发条件:任意已完成的 Agent 回答,尤其是后端返回 not-applicable 时。
  • 根因:消息行对每条非思考态 Agent 消息无条件渲染 claim boundary 与 Technique Audit Table;未识别状态又直接回退显示原始状态值。
  • 修复:从普通聊天消息行移除内部证据徽章、审计面板和单条回答报告下载控件;证据状态和 workflow receipt 仍随消息保存并供内部约束使用。
  • 验证:frontend/tests/claim-boundary-badge.test.tsfrontend/tests/evidence-audit-panel.test.tsfrontend/tests/consultation-report-export.test.ts 锁定聊天消息不再挂载这些内部组件。
  • 防复发:聊天消息渲染契约禁止直接展示 techniqueTruthworkflowReceipt;需要运营或调试时使用独立的受控界面。
  • 相关记录:BUG-009
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-012 | 自动生时流程重构后再次直出实现层错误

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:生时校正自动出题与评分轮询、use-birth-time-automatic-journey-effects
  • 用户现象:自动流程失败时可能再次显示底层异常原文,而不是稳定、可操作的中文提示。
  • 触发条件:自动出题或评分轮询 Promise 进入异常分支。
  • 根因:出生时间流程重构保留了 automatic effect 中直接读取 caught.message 的旧分支;原回归测试后来只检查 guided hook,因此没有锁定 automatic hook 的两个入口。
  • 修复:automatic effect 的出题与轮询异常统一经过 birthTimeUserError;回归测试同时检查 guided 与 automatic 两个 hook,并禁止两种直接展示 caught.message 的写法。
  • 验证:frontend/tests/birth-time-user-errors.test.ts
  • 防复发:错误归一化测试按入口文件验证安全不变量,不再依赖单文件精确调用次数。
  • 相关记录:BUG-003
  • 复发自:BUG-003
  • 修复版本:待提交(PR #25

BUG-013 | 精简生时校正文案后真实 Chromium 测试等待已删除标题

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:frontend/tests/conversational-rectification-component.test.ts、前端完整质量门禁
  • 用户现象:页面已经正确渲染候选时间、经历和输入控件,但测试持续等待并最终报 Timed out waiting for async initial turn
  • 触发条件:运行真实 Chromium 390px 组件回归测试,并把 active turn 注入精简后的生时校正界面。
  • 根因:产品把重复的“当前判断”叙事改成“已记录”行动文案后,浏览器测试仍以旧标题作为异步渲染完成信号。
  • 修复:测试改为等待候选代表时间与已记录经历两个稳定结构信号,不再绑定可变标题文案。
  • 验证:frontend/tests/conversational-rectification-component.test.ts
  • 防复发:真实浏览器等待条件优先绑定语义结构和状态数据,不用已批准可调整的展示标题充当加载边界。
  • 相关记录:BUG-004
  • 复发自:无
  • 修复版本:待提交(PR #25

BUG-014 | 能力审计新增案例验证主题后质量门禁仍断言旧主题集合

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:tests/test_api_server_security.py、Python quick quality gate
  • 用户现象:能力审计正确返回 Case Validation 并将案例验证评为可产品化,但质量门禁仍按旧主题集合和 thin 等级失败。
  • 触发条件:运行能力审计测试,且应用可见主题已包含案例验证入口。
  • 根因:案例验证能力进入 _app_visible_topics 后,对应主题集合和 UX 等级断言都没有同步更新。
  • 修复:把 Case Validation 纳入预期可见主题,并把 case_validatorthin 队列移入 excellent 断言,保持测试与同一审计规则一致。
  • 验证:tests/test_api_server_security.py::test_capability_audit_scans_registry_and_local_sourcesPython quick quality gate。
  • 防复发:扩展应用可见主题时必须同时更新能力审计契约测试;精确集合断言继续用于发现意外增删。
  • 相关记录:无
  • 复发自:无
  • 修复版本:待提交(PR #25

BUG-015 | 分钟校正 safeguards PR 与主线证据契约分叉

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:分钟候选输入身份、公共 holdout 校验、三引擎证据包、PR quality gate
  • 用户现象:PR 与 main 在五个文件发生冲突,聚焦测试通过但完整 quick quality gate 在 API 安全测试收集阶段失败。
  • 触发条件:基于旧基线开发 v1 holdout safeguards,同时主线独立升级到 v2/v3 证据契约并移除旧 API store 导入。
  • 根因:PR 复用了旧 holdout 字段和 true node 默认,未执行与 CI 相同的 quick quality gate;主线已经采用 mean node 和更严格的 sealed holdout schema。
  • 修复:以主线为准新增兼容的输入指纹、邻近分钟探针和语义哈希;新增 v4 独立审核、日级事件、假分钟承诺门禁及非生产 intake;不恢复旧自动评估循环。
  • 验证:分钟校正聚焦回归、脚本直接执行检查、Ruff、Python compilation 和 quick quality gate。
  • 防复发:新 safeguards 必须以当前 schema 向前升级;候选身份必须继承产品计算默认;PR 验收必须包含 workflow 实际执行的 quick quality gate。
  • 相关记录:BUG-009、BUG-014、ERR-045、ERR-053、ERR-086
  • 复发自:无
  • 修复版本:d7d9703

BUG-016 | 生时校正首轮被扫描稀疏度或候选分区超时打成 503

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:首页“先完成生时校正”、POST /api/birth-time-conversation 首轮技术包
  • 用户现象:点击生时校正后仍停留在普通咨询页,并显示“生时校正暂时无法继续”;接口返回 503。
  • 触发条件:候选扫描包含真实但不连续的时点差异,或动态候选分区依赖在 45 秒内没有返回。
  • 根因:技术包只承认相邻分钟切换,错误拒绝了稀疏扫描中的真实范围差异;同时首轮把用于改善问题排序的候选分区依赖当成不可降级的硬依赖。生产版本 b981c4e 的日志分别记录了 RectificationTechnicalPacketRangeErrorcandidate_differences TimeoutError
  • 修复:稀疏扫描差异改用明确的范围级文案,禁止伪称相邻分钟切换;超过六小时的宽范围首轮跳过分钟级候选分区,较窄范围在候选分区发生已知超时、取消、配置或服务故障时保留服务端扫描证据并继续收集,不再返回 503;未知编程或契约错误仍失败关闭。
  • 验证:frontend/tests/conversational-technical-packet.test.tsfrontend/tests/conversational-rectification-route.test.ts、真实 Chromium 390px 组件回归和 npm run build 通过;完整前端套件 844 项中 837 项通过,余下 7 项均为沙箱 Chromium / PostgreSQL 端口环境失败,针对性 Chromium 在沙箱外 8/8 通过。
  • 防复发:首轮必须区分核心扫描失败与可降级的候选排序依赖;稀疏差异文案必须显式否认相邻分钟切换;生产验收必须核对接口状态与实际进入校正会话。
  • 相关记录:BUG-004、BUG-008、ERR-091
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-017 | 候选范围终态继续原问题必定返回 409

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:生时校正范围终态、POST /api/consult、durable 原问题交接
  • 用户现象:生时校正安全结束并保存候选范围后,点击“继续原问题”仍提示原问题状态变化,接口返回 409。
  • 触发条件:分钟确认发布门禁未通过,校正以 candidate.status=pending_validation 完成;页面按未确认分钟选择 unverified_birth_time 并携带 durable handoff。
  • 根因:页面正确区分确认分钟与保存范围,但咨询接口把所有 handoff 硬限制为 verified_chart;范围终态因此在计费和模型调用前被拒绝。
  • 修复:handoff 允许 verified_chartunverified_birth_time 两种星盘模式,继续拒绝 general_no_birth_time、旧校正入口和不一致 request ID;分钟确认门禁保持不变。
  • 验证:生产合成账号复现 409 mode_changedfrontend/tests/consultation-birth-time-mode.test.ts 锁定范围终态模式与一般咨询隔离;发布后需复跑 durable claim、正常咨询和聊天删除 smoke。
  • 防复发:范围终态和精确确认必须分别覆盖 continuation 模式;不得把“拥有 handoff”错误等同于“已经确认出生分钟”。
  • 相关记录:BUG-008、BUG-009、BUG-016、ERR-085、ERR-091
  • 复发自:无
  • 修复版本:待提交(生产 smoke 待当前精确 SHA 发布后补齐)

BUG-018 | 首次保存未确认出生时间没有写入档案状态

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:账户出生资料保存、未确认星盘咨询、生时校正后继续原问题
  • 用户现象:已经保存“大概时间”等出生资料,但继续咨询时仍提示出生时间状态发生变化,接口返回 409。
  • 触发条件:档案没有旧的 active minute、legacy minute、candidate 或 case pointer,第一次经账户接口保存未确认出生时间声明。
  • 根因:账户写入只在清除旧候选结果时补写 birth_time_status=reported;干净档案和首次 upsert 被提前跳过,留下完整声明但空状态,随后被服务端星盘真值校验拒绝。
  • 修复:所有未确认声明变更都原子写入 reported 并清空不可沿用的应用结果;首次创建档案时也写入同一状态;确认分钟仍禁止被普通资料编辑覆盖。
  • 验证:frontend/tests/account-api.test.ts 覆盖空状态档案与首次档案写入;生产使用认证账户重新保存合法声明后复跑范围终态 handoff、模型咨询、计费和会话删除。
  • 防复发:出生声明与 birth_time_status 必须由同一次服务端写入建立,不允许依赖后续校正流程补齐状态。
  • 相关记录:BUG-009、BUG-017
  • 复发自:无
  • 修复版本:本次自动滚动修复提交

BUG-019 | 原问题交接租约过期后永久显示处理中

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:生时校正范围终态、跨设备/失败重试、durable 原问题 handoff
  • 用户现象:一次继续咨询在输出前失败后,刷新仍无法重试,接口返回“原问题状态已经变化”。
  • 触发条件:handoff 处于 claimedexecuting,两分钟租约已经过期,客户端重新加载交接。
  • 根因:数据库 projection 只看持久化 state,把过期租约仍投影为 in_progress;客户端因此不会发起 claim,而执行 RPC 又正确拒绝过期租约,形成永久卡死。
  • 修复:projection 将已过期的 claimed/executing 租约投影为 pending,复用既有加锁 claim RPC 原子接管;未过期租约仍保持 in_progress,双设备隔离不变。
  • 验证:迁移契约测试锁定过期租约恢复语义;生产制造过期 claim 后重新加载、claim、执行模型咨询和 settle。
  • 防复发:所有租约型状态的读取投影必须同时解释 lease deadline,不允许只依赖枚举 state。
  • 相关记录:BUG-017、BUG-018
  • 复发自:无
  • 修复版本:待提交

BUG-020 | 生时校正把语言问答包装成高阻力卡片表单

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-021 | 自然语言真实事件在分钟评分入口被静默丢弃

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-020
  • 复发自:BUG-020
  • 修复版本:待提交(本地可测)

BUG-022 | 生时校正入口等待首轮请求完成后才切换会话

  • 相关记录:BUG-008、BUG-009、BUG-015、BUG-016、BUG-018
  • 复发自:BUG-018
  • 修复版本:待提交(本地可测)

BUG-020 | 生时校正入口等待首轮请求完成后才切换会话

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:首页生时校正入口、普通咨询中的“先完成生时校正”、侧栏恢复校正会话
  • 用户现象:点击生时校正后长时间停留在首页或原咨询 session,直到恢复、建案、计算和会话持久化全部完成才突然跳转,用户容易误以为点击无效并重复操作。
  • 触发条件:startresume、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-020、BUG-021
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-023 | 初始化地址保存后的加载提示仍指向生时评估

  • 相关记录: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-022
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-024 | 侧栏会话标题与更多操作被拆成两块

  • 相关记录:BUG-020
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-022 | 侧栏会话标题与更多操作被拆成两块

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:聊天记录侧栏、当前会话选中态与更多操作入口
  • 用户现象:会话标题显示在一块选中背景中,右侧更多操作却以独立圆形按钮悬在外侧,看起来像两个不一致的控件。
  • 触发条件:侧栏展开并选中任意会话。
  • 根因:选中背景只应用在左侧 .session-main,右侧 .session-menu-trigger 又单独使用 50% 圆角和悬停背景。
  • 修复:把选中、悬停和聚焦背景统一应用到整行 .session-row;子按钮保持透明,并移除更多操作按钮的独立圆形底色。
  • 验证:侧栏契约测试锁定整行选中背景、透明标题按钮和非圆形更多操作按钮;目标文件 ESLint 与 git diff --check 通过。
  • 防复发:会话标题和行内操作必须共享同一个行级状态面,不得分别绘制互相竞争的选中背景。
  • 相关记录:无
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-025 | 健康压力追问被数据库误判为校正操作冲突

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: answerresultCategory: success,事件规范化保存为 2023-03 · 离家来北京工作,页面继续自然追问学业经历且输入框恢复可用;聚焦迁移测试锁定四个 validator 与表约束必须共同支持该领域。
  • 防复发:应用 evidence domain 枚举新增值时,必须同时更新 TypeScript schema、公开 recap/request、私有候选、事件表约束和迁移契约测试;不得把正常领域扩展映射为通用 409。
  • 相关记录:BUG-007、BUG-020、BUG-021
  • 复发自:BUG-007
  • 修复版本:待提交(测试 Supabase smoke 通过)

BUG-026 | 首页与会话改版后旧测试阻断生产发布门禁

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:production 发布门禁、首页主题入口、会话输入区、生时校正组件服务端渲染测试
  • 用户现象:production 应用构建成功,但完整前端测试有 7 项失败,导致最新 main 无法通过发布前验证。
  • 触发条件:运行完整前端测试;旧断言仍查找已移除的首页证据预览、固定 180px 模型菜单、无条件输入区类名和旧 profile 文案来源;旧手动 workflow 还固定在 Node 20,而当前 @mastra/core 明确要求 Node 22.13 以上。
  • 根因:首页与普通 session 的布局和文案已经更新,测试契约没有随产品行为同步;Jyotish Skill Tests 的 Node 版本也落后于其他 production 门禁和应用依赖声明,使 Node 20 把 GSAP ESM 错误解析成 CommonJS namespace。
  • 修复:测试改为锁定当前首页主题选择、内容自适应模型菜单、带首页修饰类的停靠输入区和 profileDraft 文案来源;GSAP 使用正式命名导出;手动 production 测试 workflow 与其余门禁统一到 Node 22。
  • 验证:6 个相关测试文件、Node 22 完整前端测试、ESLint、production build 与 patch check 全部通过后方可发布。
  • 防复发:产品 UI 结构调整时必须在同一提交同步源码契约测试;workflow 的 Node 主版本不得低于已锁定运行时依赖声明的最低版本。
  • 相关记录:BUG-022、BUG-024、BUG-025
  • 复发自:无
  • 修复版本:待提交(production gate

BUG-027 | 已完成的生时校正会话打开后误建新案例

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:生时校正历史会话恢复、范围终态展示、首页继续入口与计费
  • 用户现象:范围校正完成后刷新,点击侧边栏原会话会卡在“正在建立校正记录”,或跳到另一个会话并提示加载最新进度;首页同时重新显示开始入口。
  • 触发条件:已绑定 case 的生时校正会话对应 completed/abandoned 终态,而账户接口只投影当前未完成 case;或者账户另有一个更新的未完成 case。
  • 根因:会话打开逻辑只按账户当前 case 决定 resume/start,没有优先恢复所点击会话自己的 rectificationCaseId;历史终态加载后又会覆盖账户当前可恢复 case,异步账户刷新还拒绝接受 null 或另一个最新 case。
  • 修复:已绑定的生时校正会话始终以自身 case id 执行只读 resume;只有首页或未绑定会话才按账户当前 case 复用或创建;历史终态不再覆盖另一个未完成 case,终态后账户刷新接受服务端最新投影。
  • 验证:入口契约测试锁定历史会话按自身 case 恢复、首页重新校正仍创建独立会话,以及历史终态不覆盖当前未完成 case;发布后用 production 合成账号复查范围终态、刷新恢复、首页入口与余额不变量。
  • 防复发:聊天会话的 rectificationCaseId 是历史查看的第一绑定键;账户 rectificationCase 只代表当前未完成案例,二者不得相互替代。
  • 相关记录:BUG-017、BUG-019、BUG-020
  • 复发自:无
  • 修复版本:待提交(production gate

BUG-028 | 生时校正收到具体经历后仍重复泛问

  • 相关记录:BUG-007、BUG-018、BUG-019
  • 复发自:BUG-007
  • 修复版本:待提交(测试 Supabase smoke 通过)

BUG-024 | 生时校正收到具体经历后仍重复泛问

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:生时校正自然语言追问、事件补充信息合并、会话可见回复
  • 用户现象:用户已经描述自己的具体经历,助理没有针对该内容继续追问或反馈,而是重复上一轮的泛化问题。
  • 触发条件:用户提供的事件缺少年月并在下一轮单独补时间;或已经回答技术包当前首选领域后,下一轮仍沿用同一领域提示。
  • 根因:存在三处断链:会话组件忽略服务端已经生成的针对性 turn.narrative,转而根据公开 evidence request 重组固定问题;用户先说事件、下一轮只补年月时,两轮分别保存为“无日期事件”和“无内容日期”,未形成可评分事实;服务端下一问直接采用技术包首选领域,没有排除本轮已经回答的领域。
  • 修复:会话组件改用独立的可见叙事函数,优先承接用户最近一条具体但不完整的经历并只追问缺失项;编排器把下一轮仅含日期或仅含内容的补充合并回最近一条待澄清事件,同时用 correctsEvidenceIds 保留 append-only 修订链;下一问从技术包允许领域中优先选择尚未回答的领域,并同步覆盖公开 evidence request。
  • 验证:相关自然语言抽取、叙事、编排、路由、公开案例回放与端到端测试共 111 条全部通过;回归覆盖“先说离家工作、再补 2023 年 3 月”后合并为 2023-03 · 离开家去北京开始工作、具体事件缺日期时回复必须复述该事件并询问年月、关系领域回答后下一问切换到事业领域。目标文件 ESLint 与补丁检查通过。
  • 防复发:保持“服务端叙事是用户可见回复真相源”的纯函数测试;每条待澄清证据必须测试跨轮补全与修订链;下一领域必须测试排除有效 recap 已覆盖领域;端到端断言不得只绑定泛化提示词。
  • 相关记录:BUG-018、BUG-019
  • 复发自:BUG-019
  • 修复版本:待提交(本地可测)

BUG-029 | 生时校正仍有未回答区分领域时提前结束

BUG-025 | 生时校正仍有未回答区分领域时提前结束

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:生时校正多领域追问、候选范围停滞终止策略
  • 用户现象:用户只回答两轮后,系统仍有财务或关系等可区分领域未询问,却直接保存宽候选范围并结束。
  • 触发条件:自然语言单轮抽取出多条可评分经历,使累计数量达到最低门槛;候选范围连续两轮未变化,同时技术包仍建议尚未回答的领域。
  • 根因:停滞终止只检查可评分经历数量和候选范围是否连续不变,没有检查当前技术包是否仍存在未回答的区分领域。
  • 修复:停滞结束前增加未回答建议领域门禁;仍有可区分领域时继续自然追问,全部建议领域已覆盖后才允许按范围停滞安全结束。证据数量上限和无可区分问题终止保持不变。
  • 验证:编排器回归锁定学业、搬迁、事业三轮后必须继续询问尚未覆盖的关系领域,补充关系事件后才保存未确认范围;本地真实流程修复前复现为两轮即结束且范围仍为 04:3006:30
  • 防复发:停滞终止测试必须同时断言候选范围未变化和技术包建议领域已全部回答,不能只按事件条数结束。
  • 相关记录:BUG-019、BUG-028
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-030 | 职位和管理职责变化未识别为事业证据

  • 相关记录:BUG-019、BUG-024
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-026 | 职位和管理职责变化未识别为事业证据

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:生时校正自然语言证据分类、事业领域覆盖判断、下一轮追问
  • 用户现象:用户已经说明“开始承担管理职责”或“职位发生明显变化”,系统记录事件后仍继续要求事业经历。
  • 触发条件:事业变化使用“职位”“任职”或“管理职责”描述,但没有出现“工作”“升职”“职业”等原有关键词。
  • 根因:事业领域分类词表缺少常见的岗位和职责变化表达,导致可评分事件被归入 other,无法计入事业领域覆盖。
  • 修复:将“职位”“任职”“管理职责”加入事业领域分类规则,保留既有日期、评分和持久化契约。
  • 验证:抽取器回归覆盖三种带年月的岗位与职责变化表达,均分类为 career、保留月份并可参与评分;本地真实流程已复现修复前的漏判行为。
  • 防复发:事业领域分类测试必须覆盖入离职、晋升以及不含“工作/职业”字样的职责变化表达。
  • 相关记录:BUG-028、BUG-029
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-031 | 生时纠正未收敛仍永久扣费且事件事实未进入评分契约

  • 相关记录:BUG-024、BUG-025
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-027 | 生时纠正未收敛仍永久扣费且事件事实未进入评分契约

  • 状态:resolved
  • 首次发现:2026-07-22
  • 最近更新:2026-07-22
  • 影响面:生时纠正计费终态、事件评分输入、候选计算指纹、用户结果说明
  • 用户现象:用户完成多领域问答后只得到宽候选范围,当前排盘时间没有更新,但已永久扣除点数;同时用户描述的具体经历虽然出现在对话记录中,传给分钟候选评分器时只剩领域和日期。
  • 触发条件:公开分钟盲测门禁尚未通过,流程按范围结束或用户主动放弃;以及可评分经历带有具体事件摘要时进入生产评分路径。
  • 根因:启动结算在候选计算完成后立即把预留点数标记为 charged,范围终态和放弃终态没有对应退款;前端评分载荷与 Python 输入规范只序列化 id/domain/date/precision,丢弃 eventSummary,导致不同事实可能共享同一规范输入。
  • 修复:新增向前迁移,在范围完成或主动放弃的同一数据库事务中将已收费状态幂等转换为 released、退回点数并更新动作回执;只有通过分钟门禁且用户明确确认的分钟保留收费。评分载荷新增可选 summary,Python API 规范化并限制长度,候选输入契约升级为 rectification-candidate-input-v2,把具体事件摘要纳入 canonical hash。用户终态文案明确说明未纠正成功、本次不计费、候选代表时间不会替换当前排盘时间。
  • 验证:前端生时纠正路由、编排器、存储和旅程引擎聚焦测试 77 条通过;Python 对话数据库契约、事件 API 与候选评分测试 67 条通过。回归明确断言事件摘要变化会改变 canonical input hash,但 can_applyconfirmation_allowedcan_narrow_to_minute 仍保持关闭;SQL 契约断言范围结束与放弃均在终态事务内退款,且迁移不写入 active_birth_time
  • 防复发:任何新增事件评分字段都必须进入前端载荷、Python 规范化输入和 canonical hash;任何非 confirmed 终态都必须有幂等计费回收断言;不得用候选范围中点或代表时间替换用户的当前排盘分钟。真正分钟确认仍依赖独立来源审计、sealed blind replay、准确率/误确认率及 ±1/2/5 分钟稳定性门禁。
  • 相关记录:BUG-019、BUG-028、BUG-029
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-032 | 生时校正覆盖历史回答且完成后无法返回原问题

  • 相关记录:BUG-019、BUG-024、BUG-025
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-028 | 生时校正覆盖历史回答且完成后无法返回原问题

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生时校正逐轮问答、Agent 可见叙事、完成态原问题交接
  • 用户现象:多轮回答后,用户经历全部连续显示在右侧,页面只保留最新一条 Agent 回复;Agent 收到具体事项后仍重复模板式说明;完成后点击“返回原问题”没有可见跳转。
  • 触发条件:在同一个生时校正 case 中连续提交两轮以上经历;或从普通咨询问题进入校正并走到完成态。
  • 根因:聊天区直接遍历 evidenceRecap 生成全部用户气泡,却只渲染当前 turn.narrative,因此旧 Agent 回复天然被覆盖;可见叙事层和编排器在 Agent 生成回答后又用固定进度文案覆盖,且 Agent prompt 没有收到最新具体事件;完成态页面会提前自动领取 continuation,handoff 缺失时又错误地把当前校正 session 当作来源 session。
  • 修复:controller 为当前 case 维护交错的 assistant/user 消息序列,成功提交后原子追加用户原话与新 Agent 回复,聊天区只按该序列渲染;可见层优先采用 Agent 原始 narrative,中间轮 prompt 带入最新事件并要求先具体回应再追问,编排器保留通过校验的 Agent 文本;删除完成态自动 continuation,只在用户点击时领取,并按本地 handoff、持久化 return session、最近普通咨询 session 的顺序寻找真实返回目标。
  • 验证:聚焦 controller、Agent narrative、visible narrative、orchestrator 和首页 handoff 测试 89 条通过,覆盖 assistant → user → assistant 历史、具体事件进入 prompt、旧模板不覆盖 Agent 回答、仅点击后返回来源 consultation session。组件 SSR 测试在当前 Node 环境仍被仓库既有 GSAP ESM registerPlugin 加载错误阻断,尚未进入业务断言。
  • 防复发:主聊天区不得从 evidence recap 反推当前会话消息;任何 Agent narrative 后处理不得抹掉已校验的具体回应;完成态 continuation 不得自动领取,也不得以当前 rectification session 作为来源会话兜底。若需要刷新后永久恢复每轮 Agent 原文,必须扩展服务端 turn/RPC 持久化契约,不能用当前 narrative 冒充完整历史。
  • 相关记录:BUG-018、BUG-019、BUG-028
  • 复发自:BUG-018、BUG-028
  • 修复版本:待提交(本地可测)

BUG-033 | 生时校正缺少连续事件语义导致模板式跳问

  • 相关记录:BUG-018、BUG-019、BUG-024
  • 复发自:BUG-018、BUG-024
  • 修复版本:待提交(本地可测)

BUG-029 | 生时校正缺少连续事件语义导致模板式跳问

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生时校正中间轮 Agent prompt、事件纠错与追问顺序、聊天区可见回答
  • 用户现象:用户已经补充某件经历的原因、主动或被动、结果或后续转折,Agent 没有继续处理当前事件,反而重复要求泛化领域事件;通过校验的自然回答后还会追加“累计条数”“下一领域”“本轮区分重点”等模板。
  • 触发条件:同一事件需要两轮以上补齐,历史事件与最新表述存在日期矛盾,或某领域已有证据但当前事件仍缺关键细节。
  • 根因:narrative context 只携带本轮抽取结果,没有完整事件账本、原始表述、纠错状态和未决事实;编排器又无条件把确定性进度模板拼到 Agent narrative 后面,因此模型既无法发现跨轮矛盾,也无法决定应先补完当前事件还是切换领域。
  • 修复:中间轮 narrative context 新增最新用户原话、最近事件账本、有效/失效纠错状态和未决证据;prompt 明确要求先完成当前事件、核对日期冲突、合并同一事件的原因与结果且不得重复计分,每轮只问一个信息量最高的问题;通过 grounding 校验的 Agent narrative 直接作为可见回答,仅在模型 fallback 时保留确定性进度文案。
  • 验证:聚焦测试覆盖完整事件账本进入 prompt、历史日期与最新原话同时可见、连续事件规则进入 output contract、有效 Agent 回答不再追加进度模板,以及 fallback 仍保持安全的一问式文案。测试数据全部为虚构案例,不写入真实用户经历。
  • 防复发:不得把“领域是否出现过”当作切换话题的唯一条件;任何新增对话规划信息必须先进入受限 narrative context,并保持 minute_holdout_not_readyconfirmation_allowed: falsecan_narrow_to_minute: false 等分钟安全门禁不变。
  • 相关记录:BUG-028、BUG-029、BUG-032
  • 复发自:BUG-028、BUG-032
  • 修复版本:待提交(本地可测)

BUG-034 | 生时校正 Agent 降级只记录 200 导致模板回退不可诊断

  • 相关记录:BUG-024、BUG-025、BUG-028
  • 复发自:BUG-024、BUG-028
  • 修复版本:待提交(本地可测)

BUG-030 | 生时校正 Agent 降级只记录 200 导致模板回退不可诊断

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生时校正中间轮自然语言回答、服务端可观测性、网页端响应时延
  • 用户现象:用户提交明确事件后等待约 53 秒,网页仍显示“当前累计”“下一步”“本轮区分重点”等固定进度模板;接口日志只有成功的 200,无法看出 Agent 已经连续两次生成或校验失败。
  • 触发条件:叙事模型调用抛错、输出不是契约 JSON,或输出未通过 packet grounding 校验并在第二次重试后降级。
  • 根因:generateRectificationNarrative 会把所有失败收敛为安全 fallback,但此前仅把失败类型写入持久化 validation receipt,没有输出脱敏运行日志;补充日志后真实网页请求确认了两类误杀:其一,校验器机械要求中文必须逐字包含“已经发生/过去、年、月”,导致语义正确的“后来在什么时候”“年份和月份”等自然问法被丢弃;其二,只要一段自然叙事同时提到多个既有年份并出现“还是”,就会被误判为禁止的宽年份选项问卷,即使“还是”实际在询问毕业方式或职业转折类型。
  • 修复:fallback 边界保留结构化脱敏日志;日期请求改为识别“发生、后来、开始、毕业、入职、离职”等历史语义和“什么时候、年份、月份”等日期语义,缺少硬边界时只修补内部请求,不再用固定模板覆盖 Agent 正文;宽年份问卷仅拦截明确的年份二选一、A/B 年份选项或年份区间选择,不再因正文包含多个已知事件年份而误杀;当 Agent 的确认段只有说明、没有面向用户的具体问题时,将内部 evidenceRequest.prompt 投影到聊天气泡,且避免重复追加制度化提示。
  • 验证:聚焦 narrative、orchestrator、route 测试 76/76 通过;新增“多个已知年份 + 非年份还是问句”与“说明需要更多信息但没有直接问题”的回归覆盖;真实网页账号完整保留历史气泡,2017 年入职和 2020 年主动离职均得到针对事件内容的自然确认,后者明确追问“离职后下一份工作或职业转向在何年何月开始”,没有再次落入“当前累计/下一步/本轮区分重点”模板。测试前先释放未确认校正费用并清理校正数据,点数从 207 恢复到 208;新测试正常收取 1 点后为 207。
  • 防复发:叙事 fallback 必须同时保留安全用户文案、持久化回执和不含个人数据的运行时诊断;HTTP 200 不得作为自然语言 Agent 正常工作的唯一证据;禁止年份选项问卷的规则必须判断年份之间的选择结构,不能使用全文“出现多个年份 + 任意还是”作为替代。
  • 相关记录:BUG-032、BUG-033
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-035 | 生时校正发送错误内容后无法撤回修改

  • 相关记录:BUG-028、BUG-029
  • 修复版本:待提交(本地可测)

BUG-031 | 生时校正发送错误内容后无法撤回修改

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生时校正文字输入、事件证据提交与对话历史
  • 用户现象:用户发现刚发送的经历写错后只能等待 Agent 完成本轮,再通过下一轮更正;输入框在生成期间被锁定,错误内容可能直接进入事件账本。
  • 触发条件:在生时校正中提交自由文本回答后立即发现日期或事实写错。
  • 根因:校正回答会立即调用持久化命令,界面只有发送和等待状态,没有普通 session 已有的发送撤回窗口;仅中止浏览器请求也不能保证服务端停止保存。
  • 修复:复用普通 session 的安全语义,在真正发起校正命令前提供 2.5 秒撤回窗口;发送后立即显示用户气泡和停止按钮,撤回时取消定时任务、移除临时气泡、把原文恢复到输入框并重新聚焦。只有窗口结束后才调用校正接口,因此成功撤回的本轮不会生成、不会写入证据历史,也不计入校正任务。
  • 验证:新增真实 Chromium 回归断言,覆盖发送、停止、草稿恢复和延时后未调用 answer;本地登录账号手测中,唯一测试文本撤回后仍保留在输入框,等待超过窗口后未进入“正在核对”、未出现在用户历史消息中。目标文件 ESLint 与 git diff --check 通过;独立 Node 组件套件当前仍被既有 GSAP Node 导入错误阻断。
  • 防复发:撤回必须发生在业务命令发出前;不得把客户端 fetch.abort() 误认为服务端事务已取消。
  • 相关记录:BUG-018、BUG-032
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-036 | Agent 化生时校正上线前被旧模板组件断言阻断

  • 相关记录:BUG-018、BUG-028
  • 修复版本:待提交(本地可测)

BUG-032 | 连续事件补充回答丢失状态并重新进入日期模板

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生产发布门禁、生时校正前端组件测试
  • 用户现象:最新 main 已保留 Agent 自然语言回复与历史气泡,但生产测试门禁失败,无法进入部署。
  • 触发条件:运行生产 Jyotish Skill Tests 的完整前端测试套件。
  • 根因:组件测试仍断言旧版确定性模板会覆盖 Agent 叙事、经历摘要带固定“已记录”前缀,并直接调用无撤回窗口的提交表达式;真实 Chromium 等待条件也仍匹配旧文案。
  • 修复:更新 5 条过期断言,使其验证 Agent 原始叙事、折叠进度中的经历摘要、2.5 秒撤回后提交路径和当前移动端文案;不回退现有业务实现。
  • 验证:生时校正组件测试、完整前端测试、生产质量门禁与生产部署工作流;以对应提交 SHA 的线上健康检查为最终验收。
  • 防复发:对话呈现测试应验证用户可见契约,不再把旧模板句式或内部调用参数写成不必要的固定实现约束。
  • 相关记录:BUG-034、BUG-035
  • 复发自:无
  • 修复版本:待提交

BUG-037 | 生时校正刷新后把真实对话重建成“已记录”模板

  • 影响面:生时校正多轮问答、事件证据账本、Agent 自然追问
  • 用户现象:用户先提供“2017年5月参加工作”,Agent 继续确认“正式工作还是实习/兼职”;用户回答“正式工作”后,系统却把这句话当成新事件,重新追问“具体是什么年月/只记得年份也可以”,既重复问题又丢失上一轮的年月。
  • 触发条件:Agent 的追问属于已有事件的日期补充或细节补充,但公开 turn 只保存问题文本,没有保存追问目标事件和问题类型。
  • 根因:编排器仅根据当前消息是否含日期决定分支;上一轮没有持久化 event_dateevent_detailnew_event 状态和目标 evidenceId,导致无日期的补充回答落入固定非评分模板;后续虽让 narrative Agent 输出了目标状态,进度装饰层仍无条件重建 evidence request 并覆盖为 new_event;细节合并还会被事件分隔符错误拆成多个证据。
  • 修复:为 evidence request 增加向后兼容的 follow-up 状态机,记录问题类型和目标事件 ID;narrative Agent 被要求在追问已有事实时输出对应状态;进度装饰只维护确定性的下一领域,不再覆盖 Agent 可见问题对应的 follow-up 目标;服务端按状态将日期或细节 append-only 合并到目标事件并保留 correctsEvidenceIds,只有 new_event 才创建独立事件;细节合并改为单事件解析后覆盖组合摘要,避免标点导致错误拆分。
  • 验证:叙事、编排与存储聚焦测试 81/81 通过;真实两轮编排回归覆盖 Agent 先追问已有事件细节并持久化目标,然后“2017-05 参加工作”后回答“正式工作”仍保留 2017-05、形成“参加工作;正式工作”并不再出现日期模板;旧 turn 缺少 follow-up 时仍按兼容路径处理。目标文件 ESLint、相关 TypeScript 检查和 git diff --check 通过。
  • 防复发:每个中间轮必须断言追问类型、目标 evidence ID 和下一轮的事件合并结果;模型回退时默认显式 new_event,不得把已有事件细节当成新事实;跨轮测试必须断言用户可见回复不重复已回答的日期问题。
  • 相关记录:BUG-024、BUG-029、BUG-030
  • 复发自:BUG-029
  • 修复版本:待提交(本地可测)

BUG-033 | 首次进入生时校正长期停留在建立记录

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生时校正历史持久化、刷新/重新进入恢复、Agent 一问一答呈现
  • 用户现象:同一轮实时回答时 Agent 会针对经历自然追问,但刷新页面或重新进入生时校正后,旧回复全部变成“已记录这段经历:……”;用户原话也被日期和事件摘要替代,看起来像 Agent 又退回固定模板。
  • 触发条件:已有两轮以上生时校正回答后刷新网页、从首页重新进入,或在当前页面同步一个更新的持久化案例。
  • 根因:数据库已保存每轮 Agent narrative,但恢复 RPC 只返回 latest_turn;前端为了补齐历史,使用 evidenceRecap 机械合成用户气泡和“已记录”助手气泡。实时链路使用内存中的原话与真实 narrative,恢复链路却使用另一套有损数据源,导致刷新前后表现不一致。
  • 修复:为校正 turn 向前新增受约束的 nullable user_message,answer 保存事务同时持久化用户原话;新增仅限 service_role 的 history load/save/completion wrapper RPC,按轮次返回最近 200 轮 userMessage + narrative;客户端响应契约支持恢复历史,首次加载和同案例重新同步均直接渲染原始一问一答。旧记录只在有明确原始 evidence 时回填用户文本;无法恢复的旧轮次只显示真实最新 Agent narrative,不再伪造模板。
  • 验证:控制器回归覆盖首次恢复、旧数据 fallback、同案例重新同步和“不得出现已记录这段经历”;聚焦校正测试 90/90 通过;本地 PostgreSQL 从头应用全部迁移成功,并验证新列与 history RPC 的 service_role/authenticated 权限边界。测试内容均为虚构经历,不写入真实用户资料。
  • 防复发:任何对话历史必须从持久化的原始 user/assistant turn 恢复;事件摘要只能用于进度和评分,不得反向伪造聊天内容。网页验收必须同时检查实时回答和刷新后的同一历史。
  • 相关记录:BUG-032、BUG-034、BUG-036
  • 复发自:BUG-032
  • 修复版本:待提交

BUG-038 | 老案例摘要被误标成原始对话且第七条事件后无法继续

  • 影响面:首次创建生时校正 case、首条 Agent 引导消息、进入校正页面的等待时间
  • 用户现象:点击生时校正后已经进入统一加载动画,但长时间停留在“正在建立校正记录…”。
  • 根因:建档事务在写入首轮和完成扣点前同步等待 Mastra Agent 的结构化输出;模型 SDK 自带重试,叙事校验层也允许重试一次,慢请求和双重重试会把整段时间全部暴露给用户。实测本地星盘扫描约 0.08 秒,不是主要瓶颈。
  • 修复:首轮叙事的两次校验尝试共享 10 秒中止信号,并关闭 Mastra SDK 内部重试;10 秒内生成成功仍使用 Agent 自然回答,超时或两次校验失败则使用现有的安全、可评分 fallback 完成建档。中间轮和最终总结不受该首轮时限影响。
  • 验证:新增回归断言,确保首轮两次叙事尝试共享同一个 AbortSignal;目标 narrative 测试、ESLint、TypeScript 与生产构建通过后记录最终结果。
  • 防复发:首轮建档不得无限等待模型,也不得同时开启 SDK 重试和业务校验重试;耗时预算必须覆盖整个首轮生成,而不是每次尝试单独重新计时。
  • 相关记录:BUG-030
  • 修复版本:待提交(本地可测)

BUG-034 | 生时校正入口旧快照重复 start 导致 409

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生产生时校正老案例恢复、累计 7–8 条可评分事件后的继续问答
  • 用户现象:部署历史恢复修复后,老案例刷新仍显示“已记录这段经历”;继续回答一条明确事件后,页面提示暂时无法继续并把文本退回草稿。
  • 触发条件:案例来自原始消息持久化上线之前,且旧事件 evidence 能提供规范化 raw_text;或累计可评分事件超过 6 条。
  • 根因:首版迁移把旧 evidence 的规范化摘要回填到 user_message,却没有标记它不是逐字捕获的聊天原文,恢复 RPC 因而把合成摘要当成真实历史;产品收敛上限允许 8 条事件,但 Python 事件评分 API 仍只接受最多 6 条,前端第 7 条后稳定收到 400。
  • 修复:为 turn 增加 user_message_captured 来源标记,只有 answer 事务当场保存的逐字用户文本才进入可见历史;旧案例没有可靠原文时只显示真实最新 Agent narrative,不再展示伪造气泡。事件评分 API 上限与产品常量统一为 8,并增加八事件回归。
  • 验证:迁移从零应用并检查来源标记与 RPC 权限;八事件 API 测试、聚焦对话测试、生产构建与真实生产浏览器继续问答/刷新/重新进入 smoke。
  • 防复发:消息历史必须携带来源可信度,事件 evidence 不得默认等价于聊天原文;跨服务的事件数量上限必须由同一契约测试锁定。
  • 相关记录:BUG-034、BUG-037
  • 复发自:BUG-037
  • 修复版本:0850619eaf5002736542463394720b0ab1949ce9

BUG-039 | 生时校正 Agent 回答等待结束后一次性出现

  • 影响面:生时校正首页入口、未完成 case 恢复、重复 start 防护
  • 用户现象:用户点击进入生时校正时,接口发送新的 start,返回 409 action_conflict,页面无法进入校正会话。
  • 触发条件:前端账户快照没有包含已有未完成 case,或账户快照在出生声明变更后隐藏了旧 case,但数据库中仍存在该用户的未完成 V3 case。
  • 根因:前端只根据内存账户状态选择 start/resume;数据库会阻止同一用户创建第二个未完成 V3 case,旧快照因此被拒绝。
  • 修复:首次 start 收到 409 后刷新账户状态;如果刷新得到可恢复 case,自动使用最新 caseIdturnVersion 执行 resume,不重复扣点;如果刷新后仍没有声明匹配的 case,则保留原错误,避免未经用户确认自动放弃旧校正记录。
  • 验证:frontend/tests/consultation-entrypoint.test.ts 23/23 通过,覆盖 409、刷新账户、使用最新 case 版本恢复;目标文件 ESLint 与 git diff --check 通过。完整套件仍有既有 CSS 断言和数据库权限测试失败,与本修复无关。
  • 防复发:生时校正入口必须把 start 视为可恢复的幂等操作;收到 case 冲突时先刷新 durable 状态,再决定恢复或提示用户;不得直接再次扣费、创建第二个 case,或在声明不一致时静默删除旧 case。
  • 相关记录:BUG-030、BUG-033
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-035 | 服务层重复 start 未在扣费前复用同一声明的未完成 case

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生时校正首次进入、回答传输、Agent 生成状态、移动端对话可读性
  • 用户现象:首次进入时只显示“正在建立校正记录”,看不到后台生成的第一条 Agent 引导;用户发送经历后也只能看到“正在核对星盘信息”,待模型、校验和保存全部完成后,Agent 整段回答一次性出现,与普通 session 的逐段生成体验不一致。
  • 触发条件:任意生时校正 startresumeanswer 命令成功返回自然语言 narrative。
  • 根因:/api/birth-time-conversation 固定使用 Response.json(turn),客户端也完整读取并校验 JSON 后才更新控制器;即使 narrative 已生成,传输层和聊天渲染层都没有增量事件契约。首次入口另由首页直接执行 start/resume,没有把生成中的首条 narrative 投影给尚未初始化的校正组件。
  • 修复:成功响应在客户端声明支持时改用 application/x-ndjson;服务端只对已经完成技法校验并持久化的 narrative 分块发送 delta,最后发送完整 durable turn。客户端逐行解析并即时投影到同一个 assistant 气泡,首次 start/resume 也把增量引导传入空白校正界面;最终 turn 到达后无缝转为 settled 历史。错误响应继续使用既有安全 JSON,已输出 delta 的中断不自动重放,避免重复文字。代理技法校验、事件事务和分钟安全门禁均保持在流输出之前。
  • 验证:新增 route 分块顺序与禁用代理缓冲回归、client NDJSON 增量解析回归、controller 在 durable turn 未到达前发布流式文本回归、组件 streaming 气泡回归;聚焦校正测试、真实 Chromium 390px 组件测试、ESLint、TypeScript 与 production build 通过。
  • 防复发:生时校正成功响应不得退回一次性 JSON 作为唯一前端路径;可见增量内容必须来自已校验 narrative,不得直接透传未完成或未通过约束的模型 token。
  • 相关记录:BUG-034、BUG-037、BUG-038
  • 复发自:无
  • 修复版本:本次流式修复提交

BUG-040 | Agent 活动状态与回答被错误渲染为互斥状态

  • 影响面:生时校正 start 编排、重复点击/多标签进入、首轮等待时间与扣费预留
  • 用户现象:前端收到新的 start 后仍等待模型计算,最终返回 409 action_conflict;账户刷新未必能返回可恢复 case,导致用户无法进入会话。
  • 触发条件:同一用户使用不同 actionId 重复进入生时校正,或两个入口并发发起 start。
  • 根因:编排器只按当前 actionId 查询 case;数据库在 reserve/create 阶段才执行“同一用户只能有一个未完成 V3 case”的约束,应用因此先做了不必要的计算和扣费预留。
  • 修复:在 reserve 前增加账户级未完成 case 查询;同一 declaredBirthInput 直接返回已有公开 turn,不重复计算或扣费;声明不一致继续稳定返回冲突。并发竞态在释放本次预留后重新读取账户,复用同声明的胜出 case。
  • 验证:frontend/tests/conversational-rectification-orchestrator.test.ts 32/32 通过,覆盖同声明重复 start 复用、声明不一致冲突和既有预留重试;后续需补充线上部署后的真实 smoke。
  • 防复发:start 幂等性必须同时在入口、编排器和 durable RPC 三层成立;任何新增 actionId 的 start 都必须先检查账户级未完成 case,不能把数据库冲突当成正常流程。
  • 相关记录:BUG-030、BUG-033、BUG-034
  • 复发自:BUG-034
  • 修复版本:待提交(本地可测)

BUG-036 | 旧数据库校验器把首条新事件回答误报为 409

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:普通 session 与生时校正共用的 Agent 消息行、流式回答反馈、完成态识别
  • 用户现象:Agent 尚未产出正文时只显示 orb 活动状态;开始出现正文后状态与答案的关系不连续,完成后活动状态直接消失,用户无法从同一消息位置判断回答仍在生成还是已经结束。
  • 触发条件:任意 assistant 消息在 thinkingstreamingsettled 三种视图状态之间切换。
  • 根因:共享 ChatMessageRow 使用条件分支把 thinking 渲染为仅有 AgentActivityStatus,又只在 streaming 时显示 composing 状态;settled 分支只保留正文,因此活动状态和正文被实现成了互斥内容,而不是同一消息的连续生命周期。
  • 修复:assistant 消息始终在同一气泡内先渲染活动状态,再渲染当前已有正文;thinking/streaming 继续使用 working/composing orbsettled 只把状态文案切换为“回答已完成”,并把 orb 替换为 Lucide 完成图标。普通 session 与生时校正共享该行为,React 消息 identity 与正文内容保持不变。
  • 验证:消息视图回归覆盖 working、composing、completed 三态、正文与状态同时存在、完成态 Lucide 图标;相关普通 session 与生时校正契约测试通过,并执行真实浏览器检查。
  • 防复发:Agent 活动状态只能描述消息生命周期,不得控制正文是否渲染;完成态必须保留稳定的视觉反馈,不能以卸载整个状态区域代替状态转换。
  • 相关记录:BUG-039
  • 复发自:无
  • 修复版本:4a9b1dc

BUG-041 | 生时校正生成回答时消息列表不自动跟随到底部

  • 影响面:生时校正首条及后续普通新事件回答
  • 用户现象:case 与请求版本同为 0,提交首条经历仍返回 409 action_conflict
  • 根因:应用已为证据请求加入可选 followUp 状态,但当前数据库校验器仍只接受旧字段;显式的 new_event 与旧默认语义相同,却在保存边界被拒绝。
  • 修复:保存任何 turn 时都移除语义冗余的 followUp: new_event,兼容旧校验器;event_dateevent_detail 仍等待对应数据库迁移后持久化。
  • 验证:直接 RPC 探针确认旧格式为 true、带 followUpfalse;新增 store 回归测试覆盖首轮与后续 turn 的兼容投影。
  • 防复发:新增可选持久化字段时,默认语义必须能向旧数据库降级;数据库迁移未应用前不得把兼容字段直接写入 durable RPC。
  • 相关记录:BUG-032、BUG-034、BUG-035
  • 修复版本:待提交(本地可测)

BUG-037 | 非评分回答绕过 Agent 并显示固定澄清模板

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生时校正消息历史、用户发送后的撤回窗口、Agent thinking / streaming / settled 回答阶段
  • 用户现象:用户发送经历或 Agent 开始生成回答后,新内容出现在消息列表下方,但列表停留在旧位置;用户必须手动向下滚动才能看到生成状态和最新回答。
  • 触发条件:生时校正已有足够内容使独立消息容器产生纵向滚动,然后发送新经历或接收流式 Agent 回答。
  • 根因:普通 session 有独立的底部跟随 effect,生时校正虽然使用可滚动的 .rectification-message-list,但组件没有保存该容器的 ref,也没有在消息、提交状态、流式文本或最终 turn 更新时调整容器滚动位置。
  • 修复:为生时校正消息容器增加专用 ref,并在用户消息、生成状态、流式增量、错误及最终 turn 生命周期变化后滚动该容器到底部;生成过程中直接跟随,完成后平滑定位,且尊重 reduced-motion,不调用会牵动外层页面的 scrollIntoView
  • 验证:真实 Chromium 390px 回归制造独立消息容器 overflow,并分别断言初始历史、乐观用户消息、流式 Agent 增量和完成回答都保持在底部;相关聚焦测试、ESLint、TypeScript 与生产 smoke。
  • 防复发:生时校正的消息生命周期新增阶段必须进入底部跟随依赖;真实浏览器测试必须验证容器自身的 scrollTop,不能只检查正文是否出现在 DOM。
  • 相关记录:BUG-039、BUG-040
  • 复发自:无
  • 修复版本:本次自动滚动修复提交

BUG-042 | 生时校正沿用系统滚动条导致视觉割裂

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生时校正独立消息列表的桌面端滚动反馈
  • 用户现象:生时校正右侧直接显示浏览器或操作系统默认滚动条,与站内温和、低对比的编辑式界面不一致。
  • 触发条件:生时校正历史内容超过消息区高度,在桌面浏览器出现纵向滚动条。
  • 根因:.rectification-message-list 只声明了 overflow-y: auto,没有提供跨浏览器的产品内滚动条颜色、宽度和交互状态。
  • 修复:为生时校正消息区增加细宽、透明轨道、低对比圆角拇指;默认隐藏拇指,仅在指针移动、列表滚动或键盘焦点进入消息区时短暂显示,停止操作后自动隐藏。Firefox 使用标准 scrollbar 属性,Chromium / Safari 使用 WebKit 伪元素,颜色继续取现有设计 token。
  • 验证:CSS 契约锁定默认透明、交互显现及标准与 WebKit 两套样式,聚焦组件测试、目标 ESLint、production build 与生产浏览器 smoke。
  • 防复发:独立滚动容器必须复用产品 token,并同时覆盖标准 scrollbar 属性和 WebKit 伪元素;默认态不得持续抢占视觉注意力,也不得引入渐变、重阴影或高饱和装饰。
  • 相关记录:BUG-041
  • 复发自:无
  • 修复版本:本次简约滚动条修复提交

BUG-043 | 生时校正把后台证据状态重复渲染成可展开管理面板

  • 状态:resolved
  • 首次发现:2026-07-23
  • 最近更新:2026-07-23
  • 影响面:生时校正消息流、候选进度、历史经历与更正入口
  • 用户现象:Agent 已经在自然对话中确认和追问经历,消息区底部仍额外显示“当前候选 · 待验证”、候选范围、历史经历列表和“更正”按钮;用户需要理解并操作第二套记录界面,破坏一问一答的连续性。
  • 触发条件:任何已有候选或至少一条 evidence recap 的生时校正案例。
  • 根因:语言交互改版后仍保留旧产品流程的 <details> 进度与证据管理面板,把本应仅供后台评分和恢复使用的结构化状态再次暴露给用户。
  • 修复:从生时校正消息流移除整块候选进度与历史经历管理面板,不再显示候选状态、范围、经历列表或逐条更正按钮;后台 evidence、评分与持久化保持不变,最终可确认状态仍通过明确确认动作呈现。
  • 验证:组件与真实 Chromium 回归锁定页面不包含候选进度、历史经历面板或更正按钮,同时保留自然对话、流式回答、撤回窗口、自动贴底和最终确认能力。
  • 防复发:结构化 evidence 是 Agent 的后台推理与持久化输入,不得在语言优先界面重复渲染成需要用户管理的卡片或表单;需要纠正时继续通过自然语言表达。
  • 相关记录:BUG-020、BUG-034、BUG-042
  • 复发自:BUG-020
  • 修复版本:待提交
  • 影响面:生时校正缺少年月、未来事件、换方向和非评分更正后的自然问答
  • 用户现象:用户用自然语言补充“化学专业”“后来换了工作”等内容后,页面直接显示“你提到……具体内容我已经记下了。它大致是什么年月?”,与前后 Agent 语气断裂,也可能忽略刚才已经建立的事件上下文。
  • 根因:编排器发现本轮暂时没有可评分事件后,直接进入同步 nonScoringTurn();该函数完全没有调用 narrative Agent,而是用固定字符串生成可见回复。Mastra 和模型没有获得生成这轮回答的机会。
  • 修复:非评分分支先用当前候选技术包、完整事件账本、最新用户原话和未决证据调用现有 narrative Agent;状态机只在后台固定本轮追问属于 event_dateevent_detail 还是 new_event,不再替代 Agent 的可见措辞。模型或技术包调用失败时仍保留确定性安全文案,避免正常澄清变成 5xx。
  • 验证:编排回归 32/32 通过;相关叙事、编排和存储测试 81/81 通过。新增断言确认无年月事件会得到 Agent 针对该事件生成的单一自然问题,并持久化 event_date + evidenceId,不再出现旧固定模板;未来事件、换方向和已有评分事件的行为保持兼容。
  • 防复发:任何能继续对话的业务分支都必须优先经过 narrative Agent;状态机可以决定证据目标和可评分性,但不得直接占用正常用户回复。确定性模板只能作为模型或技术计算失败时的技术兜底。
  • 相关记录:BUG-029、BUG-030、BUG-032
  • 复发自:BUG-029
  • 修复版本:待提交(本地可测)

BUG-038 | 全球地点字段未迁移导致账户余额接口整体 500

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:GET /api/account、首页账户初始化、余额和生时校正入口
  • 用户现象:已登录用户访问本地首页时,账户接口返回 500 {"error":"暂时无法读取账户余额"},余额与账户状态均无法加载。
  • 根因:账户 GET 为全球出生地点新增了 birth_place_*timezone_* 字段查询,但当前 Supabase 尚未应用对应迁移,PostgREST 返回 42703 column profiles.birth_place_label does not exist。PATCH 已有旧表回退,GET 缺少同等兼容路径,并把资料字段错误误报成余额错误。
  • 修复:GET 检测缺列或 schema cache 错误后,回退到迁移前的 profile 字段集合;全球地点字段在响应中返回空值,余额、出生时间状态和未完成校正 case 继续正常读取。迁移应用后自动使用完整查询。
  • 验证:服务角色直接查询确认修复前错误为 42703frontend/tests/account-api.test.ts 增加旧表回退回归,另运行 TypeScript、目标 ESLint 与本地登录接口 smoke。
  • 防复发:向账户初始化查询增加非关键资料字段时,应用发布必须兼容迁移前后的数据库形状;不能让可选地点元数据阻断余额与核心账户状态。
  • 相关记录:BUG-034、BUG-035
  • 修复版本:待提交(本地可测)

BUG-039 | 全球地点迁移漏掉服务角色列权限导致账户保存 500

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:PATCH /api/account、初始化出生地点保存、全球地点资料更新
  • 用户现象:读取账户已经恢复,但提交出生资料返回 500 {"error":"暂时无法核对现有出生资料"}
  • 根因:账户 PATCH 的并发保护和缺失 profile 恢复路径通过服务角色读取、插入及更新 profiles;全球地点迁移只授予了 authenticated 更新权限,遗漏服务角色对六个新字段的列级 SELECT / INSERT / UPDATEPostgREST 返回 42501 permission denied for table profiles
  • 修复:在全球地点迁移中为服务角色补齐六个新字段的最小列级读取、插入和更新权限,不恢复表级宽权限。
  • 验证:迁移权限静态回归、生产事务 dry-run、正式授权、字段权限查询和真实登录 PATCH smoke。
  • 防复发:扩展服务端账户 upsert 字段时,必须同时审计 authenticated 自助保存和 service_role 并发读取/upsert 两条权限链。
  • 相关记录:BUG-034、BUG-038
  • 修复版本:待提交(本地可测)

BUG-040 | 选择全球地点后重复搜索且候选列表被卡片裁切

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:初始化出生地点搜索、全球地点选择与资料保存
  • 用户现象:选择“中国 · 河北省 · 邯郸市 · 峰峰矿区”后,完整标签又触发一次搜索并返回泛化的 Geoapify 结果;候选列表还会被出生地点卡片截断,后续选项看不全。
  • 根因:位置服务在没有完整出生时刻时合法返回 timezoneOffset: null,但页面只把数字 offset 视为已选择地点,因此父组件继续向 combobox 传入空值,选中标签被当成新查询;同时 onboarding 卡片使用 overflow: hidden 裁切了绝对定位的候选列表。
  • 修复:地点完整性改为接受“合法坐标 + IANA timezoneId”,数字 offset 可暂时为空;选中地点时使在途搜索序列失效并清空候选;出生时间过渡卡片允许候选列表溢出显示。
  • 验证:地点选择、出生资料完整性和全球地点目标测试覆盖 nullable offset、缺失 timezoneId、选择竞态保护与候选列表可见性。
  • 防复发:前端地点完整性必须与位置 API 的 nullable offset 合同一致;选择类异步组件必须在 commit selection 时废弃旧请求,浮层祖先不得无意裁切。
  • 相关记录:BUG-038、BUG-039
  • 修复版本:待提交(本地可测)

BUG-041 | 全球地点资料已保存但初始化接口仍判定未完成

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:POST /api/onboarding、全球出生地点用户进入首页
  • 用户现象:用户已填写称呼、出生日期、时间线索和旧金山地点,保存成功后进入首页仍返回 出生资料尚未完成
  • 根因:onboarding 服务端完整性判断仍把中国 province_code + city_code 写死为必填,没有识别已经持久化的全球地点标签、经纬度和 IANA 时区。
  • 修复:服务端资料投影补齐全球地点字段;完整性判断接受“有效全球地点”或“旧中国行政区地点”,并复用出生资料共享校验。
  • 验证:新增旧金山 period_only + timezoneOffset null + America/Los_Angeles 回归用例,确认可生成首页初始问题。
  • 防复发:读取全球地点的服务端流程不得继续以中国行政区代码作为唯一地点完成条件。
  • 相关记录:BUG-038、BUG-040
  • 修复版本:待提交(本地可测)

BUG-042 | 全球地点缺少数字时区偏移导致生时校正入口 409

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:POST /api/birth-time-conversation、仅填写时间段的全球出生地点用户
  • 用户现象:旧金山资料已完成并能进入首页,但点击生时校正返回 profile_incomplete
  • 根因:地点搜索在没有具体出生分钟时只保存 IANA 时区,数字历史 offset 合法为空;生时校正入口起初没有在计算前补算。补算 offset 后,Geoapify 的七位小数坐标又超过校正持久化合同的六位小数边界,仍被统一映射成 profile_incomplete
  • 修复:生时校正读取资料后复用现有本地时区服务,按出生日期和已申报时间或时间段参考时刻解析历史 offset;进入持久化合同前把经纬度规范为六位小数;旧 case 导入走同一路径。
  • 验证:旧金山 1955-02-24 + evening + America/Los_Angeles 回归确认请求历史时区服务、得到 -8、规范化 Geoapify 坐标后进入校正。
  • 防复发:资料保存可以暂缺 offset,但任何进入分钟计算的路径必须先通过 IANA 历史时区解析;外部地理编码坐标必须在进入耐久 JSON 合同前规范化,不能把 offset null 或坐标精度问题误报为资料缺失。
  • 相关记录:BUG-040、BUG-041
  • 修复版本:待提交(本地可测)

BUG-043 | 全球出生地点在兄弟接口中被误判、冲突或静默退化

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:GET /api/accountPOST /api/consultPOST /api/birth-time-journey、今日星语、合盘与遗留生时评估接口
  • 用户现象:全球出生地点已保存且可进入首页,但已有生时校正记录无法恢复并反复触发 action_conflict 409;正式咨询可能在扣点前返回资料不可用;部分旧功能仍要求中国行政区代码,合法全球资料会静默退回模板或 503。
  • 根因:全球地点迁移只修复了 onboarding 与 conversational rectification 主入口,多个兄弟读取路径仍各自维护旧合同:强制 timezone_offset 为数字、直接比较 Geoapify 七位小数坐标,或把中国省市区中心当作唯一地点真值。账户接口因此看不到数据库中实际存在的未完成 case,前端误判为需要重新创建。
  • 修复:抽取共享历史时区解析器,兼容数据库 snake_case 与浏览器 camelCase 资料,并按实际申报/确认时间调用本地 IANA 历史时区服务;账户恢复使用已存 case 的不可变 offset 作为仅用于匹配的 fallback,并把坐标统一到六位耐久精度;咨询在扣点前使用最终 active time 补算 offsetjourney 入口和 case loader 在严格解析前补算;今日星语、合盘和遗留评估优先使用真实全球经纬度与时区,中国行政区仅作兼容 fallback。
  • 验证:账户 nullable offset + 七位坐标可恢复旧金山已有 case,时区 ID 或地点 ID 不一致仍拒绝恢复;verified consultation 使用最终 active time 解析 -8 且解析失败不调用扣点;journey、今日星语、合盘和遗留评估的全球地点回归通过。两组聚焦套件共 84/84 通过,目标文件 ESLint、TypeScript --noEmitgit diff --check 通过。
  • 防复发:出生地点完成性与计算就绪性必须分层;资料层可保存 IANA timezoneId 且 offset 暂空,但所有星盘计算入口必须统一补算历史 offset。不得在新接口复制中国专用地点解析,也不得用未经规范化的外部坐标直接比较持久化声明。
  • 相关记录:BUG-040、BUG-041、BUG-042
  • 修复版本:待提交(本地可测)

BUG-044 | 数据库出生地点声明校验落后导致创建校正记录误报 409

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:POST /api/birth-time-conversation、Geoapify 等全球地点用户首次创建生时校正记录
  • 用户现象:账户资料完整且不存在未完成 case,点击生时纠正仍返回 409 action_conflict;重试同一个已释放的 action 后可能转为计费失败。
  • 根因:TypeScript 持久化声明已经支持 placeIdplaceTypeprovidertimezoneIdtimezoneSource,但数据库函数 conversational_rectification_valid_declared_birth_input 仍只允许旧中国地点字段。合法全球地点声明在 create_conversational_rectification_case 内被判无效,并被 RPC 统一映射为 conversational_action_conflict
  • 修复:新增向前迁移同步数据库地点声明白名单,接受全球地点身份、IANA 时区来源及坐标字段;地点身份允许 citycityCodeplaceId 任一存在,同时保留旧中国地点兼容和数值边界校验。
  • 验证:数据库迁移单独执行成功;使用新的 actionId 对本地接口真实 smoke 返回 200 active,创建可恢复 case,首轮 narrative 非空;相同 actionId 重放仍返回同一 case,账户积分只从 100 扣至 99;无待交接内容时 handoff 按合同返回 204。相关持久化与全球地点测试 28/28 通过。
  • 防复发:任何扩展 declaredBirthInput.birthplace 的应用字段都必须同步更新数据库 JSON 校验函数并增加迁移文本回归断言;不得把声明校验失败笼统诊断为旧 case 冲突。
  • 相关记录:BUG-034、BUG-035、BUG-042、BUG-043
  • 修复版本:待提交(本地可测)

BUG-045 | 数据库追问合同落后导致第一条回答误报 409

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:POST /api/birth-time-conversation、已创建校正 case 的第一条及后续自然语言回答
  • 用户现象:校正记录能够创建和恢复,但提交第一条人生事件后返回 409 action_conflictcase 的 turnVersion 保持不变,积分没有再次扣除。
  • 根因:应用的 evidence request 已支持带目标事件的 followUp: { kind, evidenceId },但共享 Supabase 尚未执行仓库已有迁移 20260723010000_align_conversational_follow_up_request.sql。旧版 conversational_rectification_valid_evidence_request 拒绝该合法字段,保存 RPC 将校验失败统一映射成 conversational_action_conflict
  • 修复:在 Supabase 项目 vtvnfqmonbfuxmqkqdlc 单独执行已有向前迁移,使数据库 evidence request 校验与当前 TypeScript 持久化合同一致;未执行其他迁移,也未重新部署应用。
  • 验证:对原 case 使用新 actionId 重试第一条回答返回 HTTP 200,turnVersion 从 0 递增到 1narrative 和目标 event_detail follow-up 正常返回;用同一 actionId 重放返回相同 turn,账户积分保持 99。服务端日志两次均为 actionKind=answerresultCategory=successbillingState=unchanged;持久化与迁移聚焦测试 27/27 通过。
  • 防复发:应用扩展 durable JSON 合同时,数据库迁移必须进入环境迁移账本并在发布验收中执行第一条真实写入 smoke;不能只用迁移文件存在或静态测试通过代替远端数据库合同验证。
  • 相关记录:BUG-034、BUG-035、BUG-044
  • 修复版本:数据库向前迁移已应用;应用代码待提交(本地可测)

BUG-046 | 生时校正刷新丢失首条引导并堆叠历史用户气泡

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正会话首次进入、连续问答及刷新后的历史恢复
  • 用户现象:首次进入时 Agent 的引导消息刷新后消失;已录入的人生事件被集中恢复成多条连续的右侧用户气泡,最后只剩一条 Agent 回复,破坏真实的一问一答顺序。
  • 根因:新会话没有把完整问答 transcript 持久化到 session;恢复接口只返回最新 turn,前端只能把最新 turn 中累计的 evidenceRecap 误当成逐轮聊天历史。数据库实际保存了每轮 birth_time_rectification_turns.narrative,用户原文也可通过 birth_time_rectification_event_evidence.source_turn_idraw_text 恢复,但旧恢复链路没有读取这些数据。
  • 修复:新会话从首条 Agent narrative 开始持久化完整消息序列,每次回答后保存真实的 Agent → 用户 → Agent transcriptresume 接口按 turn version 读取 narrative,并用 evidence 的 source turn 关联用户原文,返回耐久的交替历史;页面优先用数据库历史修复旧 session。无法可靠恢复用户原文的残缺旧 turn 不再伪造模板回复,相邻 Agent 状态只保留最新一条;最末级 legacy fallback 也只恢复最近一组可靠消息,不再展开全部累计 evidence。
  • 验证:client、controller、route 聚焦测试 52/52 通过;component 非 Chromium 测试 8/8 通过;TypeScript --noEmit、目标文件 ESLint 与 git diff --check 通过。按用户要求未运行 Chrome/Playwright。
  • 防复发:聊天历史必须以逐轮 durable transcript 或可验证的 turn/evidence 关联为真源;累计业务证据只能用于评分与摘要,不能被前端推断成消息列表,也不能为缺失历史生成看似真实的 Agent 文案。
  • 相关记录:BUG-024、BUG-029、BUG-032、BUG-045
  • 修复版本:待提交(本地可测)

BUG-047 | 相对日期缺少上下文解析并触发模板式重复追问

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正连续追问、自然语言事件提取与澄清合并
  • 用户现象:Agent 已知用户在 1972年12月正式退学,继续追问彻底离校时间后,用户回答“来年1月份我彻底离开的学校”,系统仍重复询问具体年份和月份。
  • 根因:事件提取器把“来年、次年”等相对日期视为无日期文本,但不读取正在讨论的事件年份;澄清合并又只接受不含描述的纯日期回答;非评分分支随后用固定澄清模板覆盖模型已经生成的上下文回答。
  • 修复:对 event_dateevent_detail 追问使用目标事件或最近明确事件作为年份锚点,将“来年、次年、第二年、翌年”和“同年、当年、那年”的月份上下文化后再提取,同时保留用户原始文本;允许带自然描述的日期补充完成原事件,但仅在纯日期、同领域或低信息细节时合并,避免把“搬家”等明确新事件吞入上一条澄清;普通澄清优先显示 narrative Agent 的自然回答,确定性模板仅保留为模型失败兜底。
  • 验证:事件提取与编排聚焦测试 59/59 通过,覆盖“2022年12月正式退学 → 来年1月彻底离校”解析为 2023-01、带描述日期补充、相对日期无上下文时不臆造年份,以及不同领域新事件不误合并。目标 TypeScript、ESLint 与补丁检查通过;按用户要求未运行 Chrome/Playwright。
  • 防复发:事件状态机只负责持久化目标、证据质量与评分边界,不得替代 Agent 的可见对话;相对日期必须在明确的当前事件上下文内解析,缺少可靠锚点时保持待澄清;澄清合并必须同时判断日期、摘要和领域连续性。
  • 相关记录:BUG-029、BUG-032、BUG-037
  • 修复版本:待提交(本地可测)

BUG-048 | 生时校正消息更新后没有自动滚动到最新内容

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正聊天区、用户发送、Agent 思考态及回答更新
  • 用户现象:用户发送经历后,Agent 开始思考并生成回答,但消息列表停留在原位置,需要手动向下滚动才能看到最新内容。
  • 根因:普通 session 在消息列表末尾设置了滚动锚点和 scrollIntoView effect;生时校正使用独立的 rectification-message-list 滚动容器,却没有对应的末尾锚点和消息更新监听。
  • 修复:在生时校正消息列表末尾增加滚动锚点,并在消息数量、最新回答文本、思考状态、提交状态、turn version 和错误状态变化时滚动到末尾;生成中即时跟随,完成后平滑滚动,同时尊重 prefers-reduced-motion
  • 验证:组件目标回归测试通过;TypeScript --noEmit、目标 ESLint 与 git diff --check 通过。按用户要求未运行 Chrome/Playwright。
  • 防复发:新增独立聊天滚动容器时必须同时提供末尾锚点,并覆盖乐观用户消息、生成状态和回答文本更新三类触发源。
  • 相关记录:BUG-046
  • 修复版本:待提交(本地可测)

BUG-049 | 生时校正 Agent 提问悬空截断且回答缺少消息操作

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正自然语言回答、Agent 消息操作、当前轮次重跑
  • 用户现象:Agent 已经理解并复述了用户的教育经历,但回答最后停在“我需要确认一个关键信息——”,没有显示真正的问题;每条 Agent 回答下方也缺少赞、踩、复制和重跑操作。
  • 根因:Mastra 返回的结构化 JSON 可以通过校验,但其中 narrative 自身可能以破折号、冒号或“关键信息”等悬空引导语结束;旧逻辑只要在正文中看见“确认”等疑问词,就误判为已经包含可见问题,因此没有把同一结构化输出中的完整 evidenceRequest.prompt 补到正文末尾。
  • 修复:增加悬空提问结尾识别;中间轮次若正文没有完整问题或停在悬空引导语,自动追加模型结构化输出中的具体问题。Agent 回答下方增加赞、踩、复制和重跑图标;赞踩互斥并保留在当前页面,复制写入剪贴板,只有最新回答可以重跑。
  • 重跑边界:新增独立、幂等的 regenerate 命令,使用上一轮已经持久化的用户原文和事件台账重新生成当前 Agent narrative;不重新提取事件、不追加用户消息、不重复评分、不改变候选范围、不扣点,并在当前消息列表和刷新后的耐久历史中替换原 Agent 回答。
  • 验证:TypeScript --noEmit 通过;叙事、Controller、client、route、orchestrator 聚焦测试 119/119 通过,覆盖悬空提问补全、无 payload 重跑、消息原位替换、证据与候选保持不变;组件静态/SSR 检查 9 项通过;目标 ESLint 与 git diff --check 通过。测试过滤器未按预期排除文件内的真实 Chromium 用例,该用例误启动后以 SIGTRAP 退出,未作为本次 UI 验收依据,且不再重试。
  • 防复发:结构化回答校验必须区分“出现疑问相关词”与“存在完整可回答的问题”;任何重新生成操作都必须与 evidence mutation、评分和计费分离,并通过相同 action receipt 保持幂等。
  • 相关记录:BUG-029、BUG-046、BUG-047、BUG-048
  • 修复版本:待提交(本地可测)

BUG-050 | 生时校正重跑期间重复显示旧回答和新思考气泡

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正 Agent 回答重跑交互
  • 用户现象:点击重跑后旧回答仍保留,列表底部额外出现一个思考消息,生成完成后旧回答才被替换。
  • 根因:重跑只复用了通用 pending 状态;消息列表继续渲染旧回答,同时通用 pending 分支又在列表末尾追加思考气泡。
  • 修复:组件记录当前重跑消息,立即在原消息位置显示思考态并隐藏操作栏;重跑期间不渲染通用末尾思考气泡,成功后原位显示新回答,失败后恢复旧回答。
  • 验证:组件静态回归、目标 ESLint、TypeScript 与补丁检查通过;按既定限制未运行 Chrome/Playwright。
  • 防复发:原位更新类操作必须把进行中状态绑定到目标消息,不得同时复用追加新消息的通用 pending UI。
  • 相关记录:BUG-048、BUG-049
  • 修复版本:待提交(本地可测)

BUG-051 | 既有事件的原因补充被误判为无日期新事件

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正自然语言事件补充、事件台账合并、Agent 可见回答
  • 用户现象:Agent 已围绕一条带年月的事件追问原因,用户回答原因后,系统仍固定回复“还差时间定位”,再次索要年份和月份。
  • 触发条件:模型可见问题是在追问既有事件的原因或具体表现,但结构化 followUp 偶尔错标为 new_event;用户随后用不带日期的自然语言回答。
  • 根因:澄清合并逻辑完全信任结构化 followUp,遇到 new_event 立即退出;原因回答因此被提取成新的无日期事件,并触发确定性的日期澄清模板覆盖正常对话。
  • 修复:当上一轮可见问题明确包含原因、表现或“哪些方面”等细节追问语义时,即使 metadata 错标为 new_event,也把回答合并回最近一条带日期的有效事件;同时移除“这件事很有用,但还差时间定位”的固定话术,保留不假定上下文的简短兜底。
  • 验证:orchestrator 回归覆盖“1972年12月退学 → 追问压力原因但 metadata 错标 → 经济负担导致无法继续”,断言沿用原日期、合并为同一有效事件且不再出现固定索时模板;目标 ESLint、TypeScript 与补丁检查。
  • 防复发:事件追问的可见语义必须能够兜底结构化 metadata 的偶发错标;已有日期事件的原因、性质和具体表现回答不得强制再次提供日期。
  • 相关记录:BUG-029、BUG-047
  • 复发自:BUG-047
  • 修复版本:待提交(本地可测)

BUG-052 | 确定性流程模板覆盖生时校正 Agent 的自然回答

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正首轮引导、中间事件追问、方向切换、未来事件、暂停、放弃与确认消息
  • 用户现象:模型已经结合上下文生成回答后,网页仍显示“已记录”“当前累计”“下一步”“还差时间定位”等重复话术;部分操作还会新增程序模板气泡,使对话像问卷而不是连续的一问一答。
  • 根因:编排层把事件提取结果、followUp metadata 和收敛状态当成可见文案的唯一真源,在模型生成之后又根据分支拼接或替换 narrative。原本用于事实安全和失败兜底的确定性逻辑因此越界成了对话作者,并且 metadata 的偶发误判会直接中断正常语义交流。
  • 修复:可见文案统一以 Agent narrative 为准;删除首轮候选前后缀、事件保存与计数进度、领域推荐、方向切换、无日期、未来事件、暂停、放弃和确认成功等确定性模板。事件提取、未来事件不计分、去重、更正、候选计算和确认时间原子落库继续作为不可见业务状态运行,提取失败或 metadata 标错不得覆盖模型回答。增加脱敏诊断日志,仅记录阶段、校验问题代码、重试和 fallback 类别,不记录用户原文或完整模型输出。
  • 表格边界:稳定层/敏感层、技法审计和事件证据三类表可在中间轮按上下文需要出现;最终确认前必须提供完整汇总。表中候选、范围、分盘、技法和引用只能来自 technical packet,不得编造、泄露私有分数或声称运行了未执行的技法。
  • 验证:叙事与编排单元测试覆盖 Agent 原文保留、结构化 metadata 不覆盖自然回答、未来事件后台排除、原因补充合并、暂停/放弃/确认无新增模板气泡,以及最终确认仍更新正式出生时间;合成 E2E 覆盖首轮、换方向、无日期和未来事件均保留模型可见回答。目标 ESLint、TypeScript、测试与补丁检查结果见本轮验证记录。
  • 防复发:状态机只能决定允许的动作和持久化状态,不能编写用户可见话术;新增任何确定性文本前必须证明它属于安全错误而非正常对话,并增加“模型输出未被覆盖”的回归断言。
  • 相关记录:BUG-046、BUG-047、BUG-049、BUG-051
  • 修复版本:待提交(本地可测)

BUG-053 | 首轮结构化结果为空时错误展示确定性引导模板

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正首轮 Agent 引导、Mastra 结构化输出兼容、首轮等待时限
  • 用户现象:新建生时校正后固定显示“当前仍在核对……先说一件已经发生的学业事件”,看起来像 Agent 回答,实际没有使用模型生成的自然文案。
  • 触发条件:DeepSeek 已完成一次 Mastra 调用,但 result.object 未形成结构化对象;提供商返回的文本结果未被继续解析,两次尝试均被记录为 schema 失败。
  • 根因:生产叙事适配器只解析 result.object,没有兼容 Mastra/模型组合返回 JSON 文本的情况;首轮失败后又调用 fallbackNarrative(),把程序模板伪装成了 Agent 消息。脱敏 receipt 为 fallbackUsed=trueschemaValidated=falseissues=["root:invalid_type"],不是超时错误。
  • 修复:优先使用通过 schema 的 result.object,为空时把非空 result.text 交回既有 JSON 提取和 packet 校验流程;首轮连续两次仍失败时返回可重试服务错误并释放预留计费,不再持久化或展示确定性首轮模板;中间轮既有安全 fallback 暂不改变。首轮等待策略的后续修复见 BUG-054。
  • 验证:叙事测试覆盖“两次不合格时拒绝而非展示模板”;路由测试覆盖 result.object 为空但 result.text 有 JSON 的兼容路径;目标叙事、编排和路由测试通过。
  • 防复发:模型适配层必须兼容结构化对象与 JSON 文本两种合法承载方式;正常首轮不得用程序模板冒充 Agent 成功回答,timeout、schema 和 grounding 失败必须在脱敏日志中分别可辨认。
  • 相关记录:BUG-046、BUG-052
  • 修复版本:待提交(本地可测)

BUG-054 | 首轮两次生成共用超时信号导致重试立即失败

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:POST /api/birth-time-conversation 首轮生成与重新生成
  • 用户现象:移除首轮固定模板后,重新生成等待约 30 秒返回可重试的 service_unavailable 503
  • 触发条件:首轮模型生成超过共享的 30 秒 deadline;第二次尝试继承已经取消的 AbortSignal,无法获得独立生成时间。
  • 根因:两次尝试在循环外创建并共用一个超时信号;诊断日志又只保留最后一次异常,把首次超时误记为 schema_invalid
  • 修复:每次首轮尝试创建独立的 45 秒超时信号,累计两次尝试的脱敏问题代码,并将 TimeoutError / AbortError 明确归类为 timeout
  • 验证:本地开发日志复现请求在 30331ms 失败;回归测试锁定两次尝试使用不同信号并将超时记录为 timeout,目标测试、ESLint、TypeScript 与补丁检查通过。
  • 防复发:重试不得复用已取消的信号;超时、schema 和事实校验必须在脱敏日志中保持不同类别。
  • 相关记录:BUG-016、BUG-053
  • 复发自:BUG-053
  • 修复版本:待提交(本地可测)

BUG-055 | 首轮完整技术输出与重复重试放大模型延迟并触发 503

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:POST /api/birth-time-conversation 首轮 Agent 引导、Mastra 结构化输出、60 秒路由预算
  • 用户现象:本地首轮请求等待约 49–90 秒后返回可重试的 service_unavailable 503;同一模型的轻量探针正常。
  • 触发条件:正式首轮把候选状态、时间范围、稳定层、敏感层、引用与完整 expert workflow 全部交给模型重复输出;一次超时后又立即进行第二次完整生成。
  • 根因:模型承担了程序已经确定的 packet 字段复制工作,正式 prompt 曾达到约 8.4k 字符;提供商延迟波动时,两次 45 秒调用可超过路由声明的 60 秒预算。一次 26 秒成功结果还曾因旧引用正则误判被丢弃。
  • 修复:生产模型只生成 narrativeevidenceRequest,候选状态、时间、范围、分盘层、引用和领域依据由服务端从 packet 确定性补全;首轮 prompt 精简到必要边界和建议领域;第一次纯超时不再触发第二次完整调用;单次等待上限调整为 47 秒,校验失败的短重试最多 7 秒;首轮若只写了介绍但漏掉问题,追加模型自己生成的 evidenceRequest.prompt,不使用程序话术模板。
  • 验证:正式本地认证请求的 prompt 从 4785 字符进一步降到 1399 字符,provider 在 29066ms 返回,接口 HTTP 200 并生成自然首轮回答;定向测试 66/66、ESLint、TypeScript 与补丁检查通过。
  • 防复发:模型结构化输出不得重复由服务器掌握的确定性 packet;生成总预算必须小于路由平台预算;首轮 timeout、schema、grounding 继续使用脱敏分类日志,不记录提示词、用户资料或模型正文。
  • 相关记录:BUG-053、BUG-054
  • 复发自:BUG-054
  • 修复版本:待提交(本地可测)

BUG-056 | 关键词领域分类阻断自然语义并在生成失败后回退到错误领域模板

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正自然语言事件分类、中间轮 Agent 回答与候选评分输入
  • 用户现象:带明确年月的研究院实习、研究员经历被保存为 other;同轮模型生成失败后,页面又固定追问学业事件,看起来像 Agent 没有理解刚才的事业经历。
  • 根因:确定性关键词分类被当作最终语义判断,事业词表没有覆盖所有自然表达;中间轮叙事连续失败后仍允许 fallbackNarrative() 生成固定业务话术,并按技术 packet 的首个建议领域继续提问。
  • 修复:单条事件落入 other 时,优先调用 narrative Agent 结合最近事件上下文返回允许的语义领域;模型不可用、超时或仍返回 other 时才保留确定性结果。首轮和中间轮叙事连续失败统一返回可重试服务错误且不保存本轮,只有最终确认阶段保留包含安全边界与三类表的确定性 fallback。
  • 验证:新增“2020年4月去石油化工研究院实习做研究员”语义分类回归,确认保存为 career 并可评分;新增中间轮不合格输出回归,确认返回 service_unavailable、不保存事件、不推进版本且不产生模板消息。事件提取、叙事、编排和路由定向测试 134/134 通过。
  • 防复发:正则只负责低成本初筛和模型不可用时的降级,不得覆盖 Agent 对自然语言事件的语义判断;非最终轮生成失败不得用业务模板伪装成成功回答;候选时间、分盘事实、未来事件和重复计分仍由程序校验。
  • 相关记录:BUG-029、BUG-032、BUG-047、BUG-053
  • 复发自:BUG-053
  • 修复版本:待提交(本地可测)

BUG-057 | 中间轮重跑在 Pro 模型延迟波动时直接返回 503

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:POST /api/birth-time-conversationregenerate 与其他非最终叙事轮、Mastra 模型降级、validation receipt
  • 用户现象:本地生时校正点击重跑后返回可重试的 service_unavailable 503,原回答仍保留但无法得到新的 Agent 回答。
  • 触发条件:中间轮技术 packet、事件账本和上下文组成约 5.7k 字符的提示词,首选 Pro 模型在提供商延迟波动时超过 47 秒单次等待上限。
  • 根因:BUG-055 为避免两次慢模型调用超过 60 秒路由预算,曾规定第一次纯超时直接结束;这避免了重复 Pro 调用,却也让瞬时延迟直接变成 503。受控本地复现中,同一重跑请求成功时总耗时约 45 秒,其中模型约 32 秒,证明服务和 Mastra 结构化输出可用,但原策略没有快速恢复路径。
  • 修复:将叙事预算调整为首选模型 38 秒和独立恢复模型 7 秒;第一次调用使用 deepseek-v4-pro,超时、schema 或事实校验失败后以新的 AbortSignal 调用 deepseek-v4-flash。生成结果携带实际模型 IDvalidation receipt 记录真正成功的模型;两次均失败时继续返回 503,不恢复固定业务模板。
  • 验证:新增 Pro 超时后 Flash 成功的回归,断言两次调用使用独立 signal、第二次 attempt 标记正确、receipt 写入 Flash 模型且不使用模板;新增 regenerate 双模型均失败的事务回归,断言不推进 turnVersion、不覆盖上一条 Agent 消息、不新增事件、不改变候选和计费。叙事、路由与编排定向测试 110/110 通过。
  • 防复发:慢模型与快速恢复模型必须共享明确的总预算而不是各自获得完整路由时限;receipt 必须记录实际成功 provider/model;生成失败只能作为可重试技术错误,不能提交半轮状态或用业务模板伪装成功。
  • 相关记录:BUG-053、BUG-054、BUG-055、BUG-056
  • 复发自:BUG-055
  • 修复版本:待提交(本地可测)

BUG-058 | 私有事件路由与未执行技法清单泄露到 Agent 回答并中断追问

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正中间轮自然语言回答、事件评分路由、Technique Audit 上下文与下一问题生成
  • 用户现象:用户提供带年月的真实经历后,Agent 主动解释内部“事件归类”,展示大量 not_evaluatedblocked 技法和确认权限,却没有继续提出下一个问题;回答像调试报告而不是连续的一问一答。
  • 根因:叙事上下文直接暴露事件的私有 domain、建议领域和完整 expert workflow 状态,模型因此围绕工程元数据组织回答;同时问题修复器只处理首轮或明显截断的句子,语法完整但没有问号的中间回答会原样通过。技法保持 not_evaluated 的直接原因则是当前有效、受支持且可评分的事件不足三条,路由尚未进入 scoreEvents(),并非 Mastra 无法调用技法。
  • 修复:新增叙事专用上下文,移除事件 domain、建议领域和内部评分;证据采集阶段只允许暴露已实际 usedpartial 的技法,不再展示未调用清单、阻塞项或确认权限。私有语义领域仍保留在服务端用于事件去重、跨领域路由和候选评分,但不得进入用户可见文案。所有非最终回答必须包含且只引导一个下一问题;模型正文漏问时追加同一次模型生成的 evidenceRequest.prompt,不使用固定业务模板。
  • 验证:新增回归覆盖事件正文可见但内部领域不可见、建议领域不进入叙事 packet、未调用技法不在采集轮展示,以及完整陈述漏问时补入模型自写问题;叙事、路由和编排聚焦测试通过,目标 ESLint、TypeScript --noEmitgit diff --check 通过。
  • 防复发:私有语义路由与用户叙事必须使用不同数据视图;未执行的技术状态不得被包装成已完成分析;每个非最终 Agent 回答都必须断言存在一个明确的下一问题,同时最终轮仍须使用真实技术 packet 生成可审计的三类表。
  • 相关记录:BUG-052、BUG-053、BUG-055、BUG-056、BUG-057
  • 修复版本:待提交(本地可测)

BUG-059 | Flash 恢复窗口过短导致模型波动时偶发 503

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:POST /api/birth-time-conversation 非最终叙事轮、Pro 超时后的 Flash 恢复请求
  • 用户现象:同一条合法回答偶发返回可重试 service_unavailable 503,随后原 action 幂等重试又能正常生成回答。
  • 根因:首选 Pro 模型等待上限为 38 秒,但恢复模型只有 7 秒;提供商延迟稍高时,两次尝试都会在接口 60 秒总预算之前被主动中止。原请求幂等重试约 43 秒成功并正常推进一轮,排除了数据库、case 版本和技术 packet 故障。
  • 修复:保留 38 秒 Pro 窗口,将独立 Flash 恢复窗口从 7 秒放宽到 14 秒;最坏模型等待仍为 52 秒,为鉴权、技术计算和持久化保留约 8 秒,不引入第三次请求或固定模板回退。
  • 验证:使用原 action 幂等重试返回成功并生成自然下一问;叙事、路由和编排聚焦测试、目标 ESLint、TypeScript --noEmitgit diff --check 通过。
  • 防复发:两次模型尝试的总预算必须显式小于路由 maxDuration;恢复模型窗口不能短于其实际常见尾延迟;非最终轮仍不得用确定性业务模板伪装生成成功。
  • 相关记录:BUG-055、BUG-057、BUG-058
  • 复发自:BUG-057
  • 修复版本:待提交(本地可测)

BUG-060 | 生时校正模型选择器显示 GPT-5.5 但请求实际使用默认 DeepSeek

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正首次引导、用户回答和重跑的叙事模型选择,以及失败操作的幂等身份
  • 用户现象:生时校正输入框下方明确选择 GPT-5.5,但接口请求没有携带模型标识;Agent 回答的延迟和实际调用模型与界面选择不一致。
  • 根因:普通会话会把当前会话的 modelId 发送给 /api/consult,生时校正控制器和首页首次 start 请求却没有把同一字段写入命令;服务端叙事生成器因此只能使用 RECTIFICATION_NARRATIVE_MODEL_ID,未配置时默认选择 DeepSeek。模型选择器此前只改变了会话 UI 状态,没有贯通生时校正 API。
  • 修复:为会生成 Agent 文本的 startanswerregenerate 命令加入可选 modelId;首页首次启动使用新建或恢复的生时校正会话模型,控制器每次发送时读取当前选择。路由从既有服务端模型目录解析所选模型,合法的 GPT-5.5 优先于配置默认模型,原恢复模型仍作为第二次尝试;过期或不可用模型以安全的 model_unavailable 409 返回,且不扣点。操作身份同时纳入模型 ID,避免失败后切换模型仍复用旧 action fingerprint。
  • 验证:增加请求序列化、首次启动、回答、切换模型后重跑、路由模型解析、不可用模型拒绝和服务分发回归;receipt 继续记录实际成功的 provider/model,而不是只记录界面选择。
  • 防复发:任何带模型选择器的会话入口都必须证明 UI 会话模型、发出的命令和服务端解析结果一致;新增生成命令时必须同时更新 schema、幂等身份、客户端和路由测试。
  • 相关记录:BUG-055、BUG-057、BUG-059
  • 修复版本:待提交(本地可测)

BUG-061 | 同版本恢复响应被丢弃导致本轮双方消息同时消失

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正回答成功后的消息同步、冲突恢复与持久化对话历史
  • 用户现象:接口已经成功返回新的自然语言回答和完整 conversationMessages,但页面没有显示本轮 Agent 回答,本轮用户气泡也在请求结束后消失。
  • 触发条件:请求在途时,父级状态先同步到与成功响应相同的 turnVersion;临时用户气泡随旧版本结束而移除,随后控制器的同版本保护又直接丢弃成功响应。
  • 根因:控制器把“同版本业务 turn 不应被晚响应覆盖”扩大成了“同版本响应的全部内容均不可采用”,没有区分业务状态与更完整的持久化消息 transcript。
  • 修复:更高版本响应仍优先、较旧响应仍丢弃;同版本响应只有在携带更完整的持久化历史,且其最后一条 Agent 文案与当前轮一致时,才只补齐消息列表并保留当前 turn。新版本响应也优先采用服务端持久化历史,避免本地推断覆盖耐久真源。
  • 验证:新增在途回答期间父级先同步到版本 8、随后恢复响应携带完整 Agent → 用户 → Agent 历史的回归;确认本轮用户与 Agent 气泡均恢复,同时原有“外部同版本 turn 不被晚响应覆盖”测试继续通过。controller、client、route 聚焦测试 61/61 通过。
  • 防复发:同版本保护必须分别比较业务 turn 与消息 transcript;完整且与当前 narrative 一致的耐久历史可以修复 UI,但不得用晚响应覆盖同版本外部业务状态。
  • 相关记录:BUG-046、BUG-048
  • 复发自:BUG-046
  • 修复版本:待提交(本地可测)

BUG-062 | 两位年份与模型领域标签导致合法经历被降级为未完成分析

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正自然语言事件提取、非最终轮叙事校验与恢复模型调用
  • 用户现象:用户用“21年”“23年”描述一段连续经历后,系统没有正常理解时间线,而是显示“这次分析暂时没有完成”的固定失败提示。
  • 根因:事件提取器只识别四位年份,两位年份会被视为缺少日期;同时,首选模型虽然成功生成了完整回答,但旧版结构化输出中的下一问题领域标签不在技术 packet 当前建议集合内,整段回答因此被判为 ungrounded_evidence_domain。恢复模型随后超时,编排层最终保存了确定性失败提示。
  • 修复:两位中文年份根据当前日期展开为最近且不晚于当前年的四位年份;旧版完整模型输出继续校验候选时间、范围、分盘和引用等事实字段,但下一问题的内部领域只保留与 packet 建议集合的交集,交集为空时才使用 packet 建议,不再因无害的领域措辞差异丢弃自然回答。
  • 验证:新增“21年元旦回家备考、21年底封控、在家到23年”的提取回归,以及旧版模型选择非建议领域的叙事回归;事件提取、叙事和编排聚焦测试共 109 项通过。
  • 防复发:自然语言年份解析必须覆盖常见缩写表达;服务端安全校验只约束可核验事实,不应让模型的对话选题标签覆盖或中断已通过事实校验的回答。
  • 相关记录:BUG-052、BUG-057、BUG-059
  • 修复版本:待提交(本地可测)

BUG-063 | 精确日期追问收到月日后重复确认同一节点

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正事件日期追问、上下文日期补全与 append-only 事件修订
  • 用户现象:Agent 已询问 2026 年 7 月上旬决定开公司的具体日期,用户回答“7 月 10 号”后,Agent 又询问是否指 2026 年 7 月 10 日及其对应节点。
  • 根因:日期提取器只直接识别带年份的中文日期;编排器只会补全“来年/同年”等相对年月,并且补全逻辑仅支持空日期,不支持把已有 2026-07 提升为 2026-07-10。简短回答因此被保存成新的未定日期事件,而不是目标事件的精度修订。
  • 修复:仅在明确指向既有事件的 event_date 追问中,从目标事件继承年份或年月;允许兼容的年到月、月到日精度提升,并继续以 correctsEvidenceIds 保存修订链。普通新事件不猜测缺失年份。
  • 验证:新增 2026-07 · 决定开公司 → 7 月 10 号 回归,断言生成 2026-07-10 修订、保留原事件、沿用原摘要且不再次询问日期归属。
  • 防复发:无年份月日只能在定向日期追问且存在可靠目标日期时补全;日期精度提升必须与目标已有年份或月份前缀一致。
  • 相关记录:BUG-024、BUG-047、BUG-062
  • 修复版本:待提交(本地可测)

BUG-064 | 窄候选被本地稳定性前置门控阻断导致长对话无法进入 VedAstro 验证

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正事件评分、三引擎校验、VedAstro 外部验证与最终确认阶段
  • 用户现象:用户跨教育、事业、搬迁、关系和财务等领域补充大量带时间事件后,候选范围已经缩窄,但系统仍持续追问,始终不给出可确认的纠正时间。
  • 触发条件:本地评分已经产生唯一领先且不超过 15 分钟的候选范围,但领先幅度、正负 1/2/5 分钟邻域稳定或 leave-one-event-out 诊断未全部通过。
  • 根因:外部验证入口错误依赖本地 can_apply=true;而本地 can_apply 又把邻域稳定和 leave-one-event-out 当作硬门槛。最终确认合同同时要求 VedAstro 通过,形成“本地未完全稳定则不调用 VedAstro、未调用 VedAstro则永远不能确认”的循环门控。
  • 修复:新增独立的外部验证就绪判定;当至少 3 条事件、2 个领域、必需分层完整、候选唯一领先且范围不超过 15 分钟时,即进入三引擎和 VedAstro 事件区分验证。邻域稳定与 leave-one-event-out 继续保留在审计 gate 和置信度诊断中,但不再进入 hard_blockers;最终确认仍要求本地窄候选、必需分层、三引擎一致、VedAstro 官方响应与事件区分全部通过,并继续等待用户明确确认后才写入出生时间。
  • 验证:将一组 12 条、覆盖 5 个领域的长对话事件固化为回归;修复前本地得到 05:0705:08 且 VedAstro 调用次数为 0,测试失败;修复后同一 fixture 进入外部验证,模拟官方事件扫描严格区分首选与次选后返回 confirm_minute。活动事件评分、API 与技法合同相关测试 42/42 通过;前端相关 95 项中 94 项通过,唯一失败为既有“最多十条事件”兼容测试,与当前已取消最大事件条数的产品规则冲突,不属于本次改动。
  • 防复发:测试必须同时覆盖“本地低置信但已形成窄候选”和“VedAstro 未执行或未区分时仍禁止确认”;研究稳定性诊断不得再次被用作外部验证的前置开关。
  • 相关记录:BUG-051、BUG-055、BUG-058
  • 修复版本:待提交(本地可测)

BUG-065 | 真实 VedAstro 事件扫描请求乘法导致生时校正数分钟无响应

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正进入外部候选区分后的同步响应时间、VedAstro SearchEvents 调用量
  • 用户现象:本地候选已经缩窄并开始真实 VedAstro 验证后,请求运行超过五分钟仍未完成,网页表现为长时间等待或最终服务不可用。
  • 触发条件:高严谨生时校正包含多条月级或年级事件,并且至少有两个候选分钟需要外部比较。
  • 根因:每个候选都会扫描全部可映射事件,而 VedAstro adapter 又把月级事件拆成约十二个采样日;十二条事件、两个候选时最坏接近 288 次同步 HTTP 请求。mock 每次立即返回,因此原回归只证明进入了 VedAstro,没有暴露真实网络延迟。
  • 修复:生时校正专用调用层按 VedAstro 原生 careerwealthmarriage 领域各选择一条最强事件;直接映射优先于代理映射,日级优先于月级和年级,同精度选择较新事件。月级和年级事件只取范围中点作为代表日,两个候选最多发起六次外部事件扫描;响应明确记录符合条件事件数、实际选中数和选择策略,不再暗示全部事件均已外部验证。通用 range scan 保持不变。
  • 验证:长对话回归断言十二条符合映射的事件只产生六次扫描,两个候选各覆盖事业、财富、关系三领域,所有扫描均为单日;相关 Python 测试 42/42 通过。使用真实 VedAstro key 重跑同一十二事件 fixture,首次完整命令约 9.7 秒、缓存后约 3.6 秒,官方响应状态为 official_verified。真实 SearchEvents05:07 与第二候选 05:21 返回相同的三领域命中与 36 分信号,因此正确保持 vedastro_candidate_not_discriminated,没有把无法区分的外部结果伪装成分钟确认。
  • 防复发:任何真实外部服务回归都必须同时锁定请求数量与代表事件选择,不得只用零延迟 mock 证明“已调用”;新增事件或采样策略时必须评估候选数 × 事件数 × 日期采样数的乘法上限。
  • 相关记录:BUG-055、BUG-064
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-066 | SearchEvents 被误作最终分钟裁判且未比较官方分钟敏感层

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:高严谨生时校正候选比较、VedAstro 官方验证与最终分钟确认
  • 用户现象:本地事件评分已经得到首选与次选分钟后,系统仍依赖 VedAstro SearchEvents 的事件命中差异决定能否确认;两个候选即使 Ascendant、宫位、D9、D10 或 Dasha 技术状态不同,只要事件搜索指标相同就无法继续收敛。
  • 触发条件:进入 VedAstro 外部验证的两个窄候选在 SearchEvents 中返回相同事件数量和 signal lift,或反过来事件搜索指标不同但官方分钟敏感快照相同。
  • 根因:旧外部验证合同把事件搜索指标当成候选分钟的最终判别器,却没有从 VedAstro 官方完整快照提取并比较 Ascendant/宫位边界、D9、D10 和 Dasha 边界身份。SearchEvents 适合补充事件背景,不足以独立证明某个出生分钟正确。
  • 修复:为两个排名最高的候选生成不含原始响应的 VedAstro 官方分钟快照,分别对 Ascendant 与宫位、D9、D10、Dasha 边界生成安全 fingerprint;至少一个官方分钟敏感层存在差异时才通过候选身份区分 gate。候选排序继续以本地已发生事件评分为准;SearchEvents 改为 event_background_validation,明确 used_for_decision=false。KP cusp/sub-lord 因当前已验证官方接口没有可审计结果而保持 unsupported,不以 IsPlanetInHouseKP 冒充。
  • 验证:官方快照适配器测试锁定四个分钟敏感层均生成非空 fingerprint、KP 明确 unsupported,且响应不泄露 API key 或 raw response;活动事件集成测试锁定 SearchEvents 指标完全相同时仍可由分钟敏感层差异完成区分,并锁定 SearchEvents 即使明显偏向首选、分钟快照完全相同时也必须保持 can_apply=falsevedastro_minute_sensitive_layers_not_discriminated。相关聚焦测试通过。
  • 防复发:任何最终分钟确认都必须区分“本地事件排序”“VedAstro 官方分钟技术身份验证”和“SearchEvents 背景验证”三种职责;两个官方快照有差异只证明候选技术状态不同,不得描述为 VedAstro 已独立证明本地首选分钟正确。
  • 相关记录:BUG-055、BUG-064、BUG-065
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-067 | 主分支同步后生时校正首轮流式、历史与重跑持久化回归

  • 状态:resolved
  • 首次发现:2026-07-24
  • 最近更新:2026-07-24
  • 影响面:生时校正首轮引导、NDJSON 流式回答、刷新后的交替历史、重跑持久化、Next.js 生产构建与迁移顺序
  • 用户现象:进入生时校正后首条 Agent 引导不显示或不流式;成功回答在页面上消失,刷新后 Agent 与用户消息错位;重跑后同一条用户消息被重复保存;同步主分支后开发测试可过但生产构建因 App Router 非法导出或缺失状态 setter 失败。
  • 根因:合并时删除了首轮 opening stream 与控制器 streamingAssistantText 的部分状态链,并把 NDJSON 客户端退回整包解析;持久化读取只恢复最终 turn,没有按 authored narrative 还原完整交替历史。重跑仍把上一条用户文本作为新 turn 保存,导致刷新后重复。两个迁移使用相同版本号;多个 route.ts 还导出了测试 helper,违反 Next.js App Router 生产构建的导出合同。最后,页面保留了 setRectificationOpeningAssistantText 调用但状态声明被删,只有完整生产 type-check 才暴露。
  • 修复:恢复服务端 NDJSON 增量事件和客户端逐块解析;恢复首轮 opening stream、控制器流式状态及持久化交替历史。重跑改为 assistant-only turn,数据库向前迁移允许 user_message = null,历史折叠时用新 Agent 回答替换上一轮回答而不复制用户气泡。迁移版本改为唯一顺序;将出生资料和全局地点 helper 移出 App Router route 文件,复杂生时校正实现移入 handler.ts,路由仅导出 HTTP handler 与受支持配置;补回首轮流式状态声明。
  • 验证:Next.js webpack 生产构建通过;除已知会使本机 Chrome 崩溃的真实 Chromium 组件测试外,前端测试 968/968 通过;VedAstro 适配器测试 24/24 通过;ESLint 0 error(保留 3 条既有 warning);git diff --check 通过。新增回归覆盖首轮流式增量、刷新后交替历史、assistant-only regenerate、迁移合同、全局出生地点 helper 与路由导出边界。
  • 防复发:发布门禁必须包含真实 next build --webpack,不能只跑单元测试或 tscApp Router route.ts 不得导出测试 helper;重跑必须以“替换上一轮 Agent 回答”为持久化语义;首轮消息、后续消息和刷新恢复必须共享同一对话历史合同。
  • 相关记录:BUG-052、BUG-053、BUG-055、BUG-058、BUG-060
  • 复发自:无
  • 修复版本:待提交(待生产验收)

BUG-068 | 生时校正确认词被当成新事件且重复追问同一日期

  • 状态:resolved
  • 首次发现:2026-07-25
  • 最近更新:2026-07-25
  • 影响面:生时校正连续问答、事件日期确认、刷新后继续会话
  • 用户现象:Agent 问某个事件是否发生在明确年月,用户回答“是的”后,下一轮仍重复询问相同年月;确认词还可能被保存成一条日期待补充的新事件。
  • 触发条件:用户使用确认词、否定词、代词或承接上一问的简短自然语言回答,而当前轮没有再次写出完整事件和绝对日期。
  • 根因:叙事模型原先每轮只收到最新用户文字和事件账本,缺少同一 case 的连续 Assistant/User 历史;即使补回历史,候选日期仍只存在于上一轮可见文案中,没有作为业务状态持久化,确定性提取器仍可能把确认词当成新事件。依赖从 Agent 文案正则反推日期也会随文案改写、语言变化或恢复路径失效。
  • 修复:复用现有 turn 与 event evidence 存储,每轮向 Agent 注入同一 case 最近 40 条连续问答;同时在共享 follow-up 合同和数据库 JSON 校验中持久化 promptanswerModeproposedDate。Orchestrator 在事件提取前确定性处理 yes/no:肯定时把候选日期作为 append-only correction 合并到目标 evidence,否定时不生成事件并把同一目标切换为开放式日期追问。模型成功返回时,其 follow-up 不再被提取器的自动澄清覆盖;Narrative Agent 拒绝缺少结构化候选、重复已解决问题或继续指向已完成 evidence 的输出。
  • 验证:回归覆盖“2020年10月吗?→是的”、单独“不是”、“不是,是2021年10月”、刷新/resume 后候选日期仍存在,以及同一 actionId 重放不重复写入;断言确认词不成为独立事件、修正 lineage 正确、否定后切换为 free_text,并断言叙事 prompt 末尾连续包含上一条 Assistant 问题和当前 User 回答。
  • 防复发:任何承接式回答必须以持久化会话历史为第一语境;确认或否认是否改变业务事实必须由持久化 follow-up 状态和确定性状态机执行,不得再从自然语言文案反推候选日期。
  • 相关记录:BUG-032、BUG-063、BUG-067
  • 复发自:无
  • 修复版本:待提交(本地可测)

BUG-069 | 生时校正最终候选被收集阶段约束退回并无限追问

  • 状态:resolved
  • 首次发现:2026-07-25
  • 最近更新:2026-07-25
  • 影响面:生时校正连续评分、候选收敛、VedAstro 外部验证与有限结果终止
  • 用户现象:用户连续提供多条真实经历后,本地候选已经缩小到单分钟或极窄范围,系统仍可能退回原始范围并继续追问;提问还可能停留在“为什么辞职、主动还是被动、造成什么影响”等不会改变当前评分的细节。
  • 触发条件:Technical Packet 收到单分钟候选或不足两个新建议领域;本地候选宽度已经适合外部验证但最终 margin 尚未达到确认阈值;事件达到旧的 3 条/2 领域门槛却未达到前端 4 条/3 领域门槛;候选连续多轮不再变化;或 family/other 背景事件被编排层计入评分覆盖。
  • 根因:收集阶段和最终确认阶段共用了错误门槛。Technical Packet 把“没有足够的新问题可问”当成候选无效,Orchestrator 又把窄候选失败静默替换为 baseRange;评分、技法合同和 Candidate Schema 分别使用 3/2 与 4/3 门槛,前两条事件不进入评分;plateau 只记录不终止,系统验证阻塞继续被转换成用户问题。外部验证入口还被误收紧为最终确认所需的 width <= 5margin >= 20%。同时 family/other 虽不进入 Python 评分器,却仍帮助编排层满足事件数和领域数;Agent 也继续追问不参与当前评分的原因、主动性和影响。原确定性校验只识别正确标注为 event_detail 的请求,模型可把同一详情问题错标成 new_event 绕过;最终轮也只靠提示词要求 evidenceRequest=null
  • 修复:建立前后端共享的收敛策略:第一条有效事件即评分,最终确认统一要求至少 4 条事件、3 个可评分领域、候选宽度不超过 5 分钟且 margin 不低于 20%。Technical Packet 接受单分钟和零建议领域;删除窄候选失败后退回 baseRange 的路径。候选在证据覆盖后连续两轮不变时结束为 completed + pending_validation,仅剩系统验证阻塞时直接结束有限结果,不再追问用户。外部验证单独使用最多 15 分钟的入口宽度,只要求唯一领先和必需层完整,不再提前要求最终 margin。编排层统一排除 family/other 的评分与确认计数,但继续持久化并展示为背景。Narrative Agent 的共享校验器禁止对已评分事件继续追问无计算价值详情,包括错标为 new_event 的详情语义;最终轮任何非空 evidenceRequest 都会触发重试,连续失败后才使用既有无追问 fallback。
  • 验证:前端聚焦测试覆盖结构化日期确认、单事件起评、单分钟候选、plateau/系统阻塞终止、家庭背景不进入评分计数、已评分事件详情错标重试,以及最终轮非空 evidenceRequest 重试。Python 聚焦测试覆盖长对话窄化后恢复 VedAstro 调用、4 条/3 领域统一门槛、官方分钟快照判别与 Technique Contract。
  • 防复发:必须区分“开始本地评分”“进入外部验证”“允许最终确认”三个阶段;没有新问题可问不得解释为候选无效。只有评分器实际支持的领域可以推进收敛计数,模型提问必须能改变日期、事件身份或评分领域,否则由确定性校验拒绝。
  • 相关记录:BUG-064、BUG-066、BUG-068
  • 修复版本:待提交(本地可测)

BUG-070 | 结构化日期确认迁移未接入生产迁移工作流

  • 状态:resolved
  • 首次发现:2026-07-25
  • 最近更新:2026-07-25
  • 影响面:生产环境生时校正 follow-up 持久化、日期候选确认与数据库约束
  • 用户现象:代码已写入 promptanswerModeproposedDate,但生产迁移工作流不会上传或执行对应 migration;生产数据库仍可能按旧 JSON 合同拒绝新 turn。
  • 触发条件:从 GitHub Actions 手动执行生产生时校正 migration 的 checkapply 操作。
  • 根因:新增 20260725010000_structured_conversational_date_confirmation.sql 后,没有同步加入工作流的 scp 上传列表和远端顺序执行列表。
  • 修复:将该 migration 同时加入上传与执行列表,继续复用现有 checksum、迁移账本和单事务执行保护。
  • 验证:静态回归断言 migration 文件名在生产工作流中恰好出现两次,分别覆盖上传和执行路径。
  • 防复发:新增需要生产执行的 migration 时,必须同时更新受审生产迁移清单并由测试覆盖上传和执行两处引用。
  • 相关记录:BUG-068、BUG-069
  • 修复版本:待提交(本地可测)

BUG-071 | 结构化日期校验器的冗余正则在 PostgreSQL 执行时报错

  • 状态:resolved
  • 首次发现:2026-07-25
  • 最近更新:2026-07-25
  • 影响面:生产环境生时校正首次建案、proposedDate 持久化与预留点数释放
  • 用户现象:开始生时校正时接口返回 409 action_conflict 和“请加载最新进度后再试”,预留点数随后自动释放且没有创建 case。
  • 触发条件:首轮 Agent 生成带 followUp.answerMode=yes_nofollowUp.proposedDate 的 evidence request,数据库开始执行结构化日期校验。
  • 根因:20260725010000_structured_conversational_date_confirmation.sql 同时保留了一个冗余的聚合日期正则;该正则括号不平衡,PostgreSQL 在函数运行时抛出 2201B invalid regular expression。下方按 year/month/day 精度分别校验的正则已经完整覆盖格式约束。
  • 修复:新增向前迁移 20260725020000_repair_structured_conversational_date_validator.sql,删除冗余聚合正则,只保留现有精度分支;同步加入生产迁移工作流。
  • 验证:生产事务回滚 dry-run 通过;以 2020-10 + month + yes_no 调用校验器返回 true;迁移账本、函数定义和生产健康状态均复核。
  • 防复发:数据库 JSON 合同的日期格式只维护一组精度分支;新增生产迁移时必须执行真实 PostgreSQL 函数调用,而不是只做 SQL 文本断言。
  • 相关记录:BUG-067、BUG-070
  • 修复版本:本次修复提交(生产已向前迁移)

BUG-072 | 生时校正首轮在零事件时执行全范围扫描并阻塞输入

  • 状态:resolved
  • 首次发现:2026-07-25
  • 最近更新:2026-07-25
  • 影响面:首页生时校正入口、start 编排、首次会话持久化与咨询问题 handoff
  • 用户现象:从首页进入生时校正后长时间停留在加载状态;未知时间或宽时段资料最明显,首问出现后输入框也可能继续等待会话同步。
  • 触发条件:新建生时校正 case,尤其声明时间为全天未知或宽时段;首页没有待转交咨询问题时也会读取 durable handoff。
  • 根因:start 在尚无人生事件时仍构建 Technical Packet,按声明范围逐分钟重排,随后再调用叙事模型生成固定性质的首问;前端收到首轮后又串行等待 persistSession(),并且直接首页入口无条件读取 durable handoff。
  • 修复:start 只按已声明时间范围创建确定性首轮和待验证候选,不做分钟扫描或模型生成;第一条有效事件回答后才进入原技术计算与叙事链。首页先展示首轮并开放输入,再后台同步会话;只有存在本地或显式待转交问题时才读取 durable handoff。
  • 验证:Orchestrator、入口、客户端、路由、持久化与同会话写入队列聚焦测试 144/144 通过;目标 ESLint 与 git diff --check 通过。覆盖首轮不扫描/不生成叙事、先展示后按序后台持久化,以及无 handoff 时跳过 durable 读取。
  • 防复发:零证据首轮不得执行分钟级技术计算或模型调用;非关键会话同步不得阻塞已持久化 case 的首轮交互;可选 handoff 读取必须由实际 handoff 状态触发。
  • 相关记录:BUG-055、BUG-065、BUG-067
  • 修复版本:待提交(本地可测)

BUG-073 | 咨询入口与持久化出生时间能力不一致

  • 状态:resolved
  • 首次发现:2026-07-25
  • 最近更新:2026-07-25
  • 影响面:首页状态文案、每日观察入口、推荐初始问题、/api/consult 出生时间模式判定
  • 用户现象:一类用户没有具体出生分钟,首页却仍诱导个人星盘问题;另一类用户已经保存准确到分钟的填报时间,旧标签页或旧客户端仍可能把咨询请求标为 general_no_birth_time,随后错误提示当前一般咨询模式不能生成个人星盘结论。
  • 触发条件:无分钟资料仍出现个人入口,或数据库已保存合法 family_exact / hospital_record / approximate 填报分钟,但客户端咨询模式停留在旧的 general_no_birth_time
  • 根因:首页没有复用出生时间路由结果来约束入口能力;同时 /api/consult 只在客户端请求星盘模式时加载 profile,收到 general_no_birth_time 时完全信任客户端状态,没有用持久化资料纠正陈旧模式。
  • 修复:首页复用 resolveBirthTimeConsultationRoute():无具体分钟时只显示一般知识文案和问题,有合法填报分钟时保留个人星盘入口。服务端对一般咨询请求也 best-effort 读取 profile;若持久化资料含合法未校正填报分钟则提升为 unverified_birth_time,若为 confirmed 且有合法 active time 则提升为 verified_chart,并继续由服务端 profile 构建星盘输入。period_only / unknown 仍保持一般咨询,不虚构分钟,也不把用户填报时间伪装成已校正时间。
  • 验证:聚焦测试覆盖无分钟首页入口、陈旧 general 请求被准确分钟 profile 提升为 unverified_birth_time,以及无具体分钟仍保持 general_no_birth_time;目标 ESLint、Webpack 构建与 git diff --check 通过。
  • 防复发:首页可点击入口必须与 resolveBirthTimeConsultationRoute() 的能力结果一致;服务端不得把客户端咨询模式当作出生资料真源,具体填报分钟必须进入 unverified_birth_time,只有 confirmed + active_birth_time 才能进入 verified_chart
  • 相关记录:BUG-009
  • 修复版本:待提交(本地可测)

BUG-074 | 生时校正首轮隐藏已知候选范围并让用户误以为系统没有读取资料

  • 状态:resolved
  • 首次发现:2026-07-25
  • 最近更新:2026-07-25
  • 影响面:生时校正新建 case 的确定性首轮引导
  • 用户现象:用户已经填写具体出生时间和误差范围,进入生时校正后却只看到泛化的重大事件提问,不知道系统实际正在核对哪个时间窗口。
  • 触发条件:新建 conversational-evidence-v3 case,首轮候选已经包含 rangeStart / rangeEnd,但可见 narrative 没有显示它们;旧生产版本还会调用模型生成同类泛化开场。
  • 根因:BUG-072 的快速首轮正确保留了候选范围,却只把范围写入结构化 candidate;首页不单独渲染该字段,固定 narrative 仍沿用了不含范围的旧提问。
  • 修复:复用首轮已经计算出的声明范围,在确定性 narrative 中明确显示当前待核对边界,并说明它不是已确认分钟;继续只问一件带年月的重要经历,不恢复零证据模型调用或分钟扫描。
  • 验证:Orchestrator 回归断言首轮正文包含真实 rangeStartrangeEnd、未确认边界和单事件提问;聚焦测试、目标 ESLint 与 git diff --check 通过。
  • 防复发:只要首轮已向用户展示生时校正状态,可见文案必须同时呈现结构化候选边界;不得只在隐藏状态中保存范围,也不得为了润色首问重新引入模型调用。
  • 相关记录:BUG-055、BUG-067、BUG-072
  • 修复版本:待提交(本地可测)

BUG-075 | 生时校正强制每轮提问并阻碍开放叙事

  • 状态:resolved
  • 首次发现:2026-07-26
  • 最近更新:2026-07-26
  • 影响面:生时校正 Narrative Agent、非评分轮续接、确定性首轮、聊天消息完成态
  • 用户现象:用户叙述一段或多段人生经历后,Agent 会机械追加问题、反复继承上一轮追问,并在普通资料交流结束后显示“回答已完成”,整体表现像问卷收集器而不是能理解人生轨迹的校时助手。
  • 触发条件:非最终轮模型只做自然回应但同时返回结构化追问,或本轮没有生成新追问却沿用上一轮 evidenceRequest;所有 settled Assistant 消息都会渲染统一完成标签。
  • 根因:Narrative Prompt 强制每个非最终回复恰好以一个问题结束;服务端 repair 会把隐藏的 evidenceRequest.prompt 自动追加到正文;非评分轮会自动生成缺失信息追问并继承旧 evidenceRequest;通用消息组件把 settled 状态映射成“回答已完成”。
  • 修复:允许用户一次叙述一件或多件经历并自由连续表达,问题改为 Agent 可选行为;删除自动补问和已评分事件的聊天限制,普通自然回复使用 evidenceRequest: null;首轮只开放邀请叙述,非评分轮不再自动规划或继承问题,仅在明确的结构化纠正承接中保留必要状态;settled 消息不再渲染活动状态。事件抽取、保存、技术评分、候选收敛和分钟确认安全门保持不变。
  • 验证:Narrative Agent、Orchestrator 与聊天布局聚焦测试 101/101 通过;目标 ESLint 无错误或警告;Next.js 16 Webpack 生产构建与 git diff --check 通过。
  • 防复发:代码不得要求每轮必须提问,也不得把隐藏 prompt 自动拼接到 Agent 正文;没有可见短答问题时 evidenceRequest 应为 null,用户叙述节奏由 Agent 与用户共同决定,代码只维护记录、抽取、评分、收敛与确认边界。
  • 相关记录:BUG-070、BUG-072、BUG-074
  • 修复版本:待提交(本地可测)

BUG-076 | 完整出生资料已保存但权威档案状态为空

  • 状态:resolved
  • 首次发现:2026-07-26
  • 最近更新:2026-07-26
  • 影响面:账户出生资料保存、星盘库同步、POST /api/consult 服务端资料校验
  • 用户现象:出生日期、家人确认的具体时间、地点、坐标和时区都已填写,星盘库副本也显示 birthTimeStatus: reported,但咨询仍返回“暂时无法核对完整出生资料”。
  • 触发条件:首次创建 profiles 行,或既有合法出生声明的 birth_time_status 为空且用户原样重新保存。
  • 根因:分钟校正主链合并时把 BUG-018 的首次档案派生状态分支退回为 {};共享 helper 又只在声明字段发生变化时写 reported,导致空状态行原样重存也无法自愈。chart_profiles.profile 只是星盘库 JSON 副本,不是咨询接口采用的权威出生资料。
  • 修复:账户路由统一调用共享状态派生 helper;新档案和合法声明空状态均原子写入 reported,确认分钟继续禁止被普通资料编辑覆盖;增加前向迁移,仅回填没有 active/candidate/case 应用结果且声明满足来源规则的空状态行。
  • 验证:账户 helper 回归覆盖新档案、空状态原样重存、候选失效和 confirmed 保护;迁移契约锁定安全过滤条件,并要求生产迁移工作流上传和应用各一次。
  • 防复发:服务端权威 profiles 的声明和状态必须同写;星盘库 JSON 不得作为咨询真值,历史空状态只能通过受约束前向迁移修复。
  • 相关记录:BUG-018、BUG-073
  • 复发自:BUG-018
  • 修复版本:待提交(本地可测)

BUG-077 | Python 诊断门状态导致历史事件评分误报 503

  • 状态:resolved
  • 首次发现:2026-07-26
  • 最近更新:2026-07-26
  • 影响面:生时校正历史事件评分、Python 技术合同到 Web 候选结果的适配边界
  • 用户现象:用户提交第一条可评分历史事件后,请求返回 503,日志显示 stage=score_events error=ZodError,开放叙事无法继续收敛。
  • 触发条件:Python technique_contract.gates 返回诊断专用状态 diagnostic_fail
  • 根因:Python 引擎合法使用 diagnostic_fail 表示诊断未通过但不构成技术异常;Web wire schema 只接受 pass | fail | blocked | not_evaluated,因此在业务判断前拒绝整份候选结果。
  • 修复:Web wire schema 接受 diagnostic_fail,并在共享适配边界将其规范化为内部既有的 fail;不扩大持久化合同,不修改 Python 引擎。
  • 验证:适配器回归覆盖含 diagnostic_fail 的技术合同并断言内部状态为 fail;聚焦测试、目标 ESLint 与 git diff --check 通过。
  • 防复发:跨语言 wire schema 必须覆盖 Python 真源可返回的枚举;诊断状态在适配边界归一化,内部领域模型继续保持最小稳定集合。
  • 相关记录:BUG-067、BUG-075
  • 修复版本:本次修复提交

BUG-078 | 叙事模型超时导致已完成的事件评分整轮返回 503

  • 状态:resolved
  • 首次发现:2026-07-26
  • 最近更新:2026-07-26
  • 影响面:生时校正开放叙事、历史事件保存、候选收敛、Narrative Agent 降级路径
  • 用户现象:历史事件已被成功抽取和技术评分,但主叙事模型与备用模型超时后,整轮返回 503,用户必须重试且无法看到已记录结果。
  • 触发条件:非最终轮的两次叙事生成均超时、报错或未通过安全校验。
  • 根因:安全的 packet 驱动兜底已经存在,却只允许最终轮使用;首轮和中间轮在两次生成失败后直接抛出 RectificationNarrativeUnavailable,把非关键的文案依赖变成了事件记录与收敛的硬依赖。
  • 修复:所有阶段在两次生成失败后统一使用既有的确定性安全兜底;保留已完成的事件记录、技术评分与候选推进,evidenceRequest 为 null,不机械追问,也不展示模型未验证内容。
  • 验证:回归覆盖首轮超时、首轮非法问卷、首轮非法技术层和中间轮虚构引用,均返回安全兜底且不泄漏被拒内容;Narrative Agent 聚焦测试、目标 ESLint、生产构建与 git diff --check 通过。
  • 防复发:叙事模型只能影响自然语言表达,不能成为事件持久化和确定性收敛的单点故障;降级输出必须来自已验证 packet。
  • 相关记录:BUG-067、BUG-075、BUG-077
  • 修复版本:本次修复提交

BUG-079 | 无可用路由领域时 Agent 追问导致 paused 会话返回 503

  • 状态:resolved
  • 首次发现:2026-07-26
  • 最近更新:2026-07-26
  • 影响面:生时校正开放叙事、暂停后恢复、历史事件保存、Narrative Agent 到公开 turn 的适配边界
  • 用户现象:完整 synthetic smoke 在暂停并恢复后提交下一条历史事件,技术评分和模型叙事都成功,但接口返回 service_unavailable,事件无法保存。
  • 触发条件:技术 packet 的 suggestedDomains 为空,而模型自然提出了一个可继续回答的问题。
  • 根因:Narrative Agent 会把模型领域替换成服务端允许的领域;允许集合为空时产生 evidenceRequest.domains=[]。叙事校验未拒绝空数组,但公开 turn 合同要求至少一个领域,导致 turnFromNarrative() 在持久化前把整轮转换为 503。
  • 修复:在 Narrative Agent 的共享适配边界统一处理 authored 与 legacy 输出;没有任何服务端可验证路由领域时保留自然语言正文,只把可选 evidenceRequest 归一化为 null。不放宽公开持久化 schema,也不信任模型自报领域。
  • 验证:回归覆盖无路由领域的 authored 输出,并覆盖 pause → resume → answer 完整编排路径;确认正文保留、evidenceRequest=null、事件正常保存且不返回 503。
  • 防复发:模型自然语言不得成为事件保存的硬依赖;私有路由元数据为空时应省略可选状态,而不是生成违反持久化合同的半合法对象。
  • 相关记录:BUG-075、BUG-078
  • 修复版本:本次修复提交

BUG-080 | 开放叙事仍被技术上下文塑造成流程播报

  • 状态:resolved
  • 首次发现:2026-07-26
  • 最近更新:2026-07-26
  • 影响面:生时校正普通叙事轮、自然对话、追问状态持久化
  • 用户现象:用户叙述“2016 年离家去外地上大学”后,Agent 仍回答“先记为、对校时有价值、参与候选核对、不会确认某个分钟”,像记录员而不是自然交谈。
  • 触发条件:普通 intermediate 轮生成叙事时仍向模型提供 Technical Packet、候选分钟、分盘、事件台账和未决证据。
  • 根因:此前开放叙事只取消了“每轮必须提问”,没有隔离普通聊天与技术收敛上下文;模型继续模仿内部流程措辞。叙事没有可见问题时,模型返回的隐藏 evidenceRequest 还会进入下一轮状态。普通提示不再暴露事件 ID 后,旧 authored schema 又仍强制模型提交已有 evidenceId,形成合同矛盾。
  • 修复:普通叙事轮只向模型提供最近真实对话和本轮用户原话,禁止主动播报记录、校时价值、候选范围、分盘、评分与收敛;只有用户主动询问技术结果时才提供受约束技术包。没有可见问题的隐藏 evidenceRequest 统一清空;自然追问只由模型表达问题意图,目标事件 ID 由服务器依据活动事件和未决证据绑定。首轮、最终轮及主动技术询问仍保留技术边界。
  • 验证:Narrative Agent 与 Orchestrator 联合回归 99/99 通过,覆盖普通 prompt 不含 packet/eventLedger、隐藏追问清空、服务器绑定 follow-up、相对日期承接、fallback、暂停恢复和并发幂等。
  • 防复发:普通聊天的可见措辞不得由技术 packet 或事件台账驱动;内部收敛状态只能记录和计算,不能成为 Agent 每轮必须复述的脚本。
  • 相关记录:BUG-074、BUG-075、BUG-078、BUG-079
  • 修复版本:本次修复提交

BUG-081 | 开放叙事只共情不继续引导

  • 状态:resolved
  • 首次发现:2026-07-26
  • 最近更新:2026-07-26
  • 影响面:生时校正开放叙事的中间轮回复
  • 用户现象:用户讲完一段包含明确行动与转折的经历后,Agent 只分析感受和性格,没有自然询问后续经历,对话停在原地。
  • 根因:为消除问卷式强制追问,中间轮 prompt 将提问设为完全可选,且校验器只检查已有问题是否可见,没有要求事件轮承担继续引导叙事的职责。
  • 修复:普通中间轮 prompt 要求在本轮新事件后以一个贴着上下文的开放问题收尾;优先询问事件之后的下一步,继续禁止机械补年月、结果或转折。若模型仍只共情不引导,服务端直接补一句开放问题,不增加第二次模型调用;无模型可用时的安全兜底也保留自然后续问题。
  • 验证:回归覆盖“研究院实习后因价值观冲突辞职”场景,确认只共情不引导的回复会保留原文并补上后续问题,且不触发模型重试。
  • 防复发:开放叙事不等于被动倾听;事件轮默认负责自然推进,但不得恢复固定问卷模板。
  • 相关记录:BUG-075、BUG-080
  • 修复版本:本次修复提交

BUG-082 | 生时校正缺少独立证据状态机并把分钟峰值误导为产品答案

  • 状态:resolved
  • 首次发现:2026-07-26
  • 最近更新:2026-07-26
  • 影响面:生时校正建案、事件采集、日期修订、候选评分、暂停恢复、范围保存、原咨询问题 handoff 与扣费幂等
  • 用户现象:专业 Agent 可以持续收集跨领域事件、逐步补充日期并做稳定性复核,但 Web 流程把对话、抽取、评分和叙事绑在单次请求中;容易重复追问同一事件、出现等待状态无下一题、在低置信度下突出单个峰值分钟,并且刷新或多设备继续时缺少独立业务真源。
  • 根因:旧 conversational-evidence-v3 同时承担聊天体验和校时状态机;人生事件没有稳定的 eventId + revision 修订链,问题没有持久化目标事件,分钟扫描结果也没有强制经过范围聚类、日期敏感性、逐项排除和邻近分钟门控。聊天会话、计算任务和咨询 handoff 的生命周期耦合,无法独立恢复和仲裁并发。
  • 修复:新增 rectification-evidence-v4 独立领域模型、Case/Turn/Event Revision/Snapshot/Job/Handoff 持久化状态机和后台 Worker。先完成教育、迁移、关系、事业、财务、健康压力、家庭七领域覆盖,再对非日精度事件按 targetEventId 追加同一事件 revision;已追问或跳过的事件不循环。候选分钟先聚类,再通过事件数、领域数、范围宽度、邻近分钟、leave-one-out、日期敏感性和计算口径 hash 门;公开合同固定 canConfirmExactMinute=false,只允许用户主动保存候选范围,不更新 profiles.active_birth_time。Handoff 和扣费由 PostgreSQL lease、幂等 action 与 settlement receipt 保护。
  • 验证:前端 V4/domain/service/migration/replay/handoff/consultation continuation 33 个测试通过;Python 2 个测试通过;目标 ESLint 与 Webpack 生产构建通过。隔离 PostgreSQL 12 项不变量通过;真实 PostgreSQL + Python E2E 完成七领域与定向日期修订后进入 range_ready,主要范围为 05:2605:30,无空问题死状态,原 active_birth_time 不变且未主动保存前 acceptedRange 为空。静态浏览器验收确认日期修订输入框、范围保存按钮、非确认分钟文案和 390px 无横向溢出;真实登录态 UI 因隔离服务未连接认证配置,本轮未声称已验收。
  • 防复发:生时校正业务真源必须是 V4 Case 和 append-only 事件台账,不得从聊天正文反向恢复;任何公开结果只能显示通过稳定性门的范围,单分钟峰值不得成为可保存结果;证据不足必须生成下一题或明确暂停,不能进入 awaiting_answer + currentQuestion=nullV4 路径不得写 profiles.active_birth_time
  • 相关记录:BUG-067、BUG-069、BUG-072、BUG-074、BUG-075、BUG-080、BUG-081
  • 修复版本:待提交(本地可测)

BUG-083 | staging 质量门使用无可用 Linux sandbox 的浏览器运行时导致验收失败

  • 状态:resolved
  • 首次发现:2026-07-27
  • 最近更新:2026-07-27
  • 影响面:生时校正 V4 的 390px 真实浏览器验收、staging 镜像发布与后续部署
  • 用户现象:PR 质量门已通过且相同提交的其余 1031 个测试成功,但推送到 staging 后唯一的真实 Chromium 测试未能取得 DevTools 端口,导致不可变镜像未发布、部署未继续。
  • 触发条件:backend-quality-gate.yml 未显式供应带系统 sandbox 的浏览器,或安装 Playwright 默认的 chromium-headless-shell 后直接用原始二进制启动。
  • 根因:真实浏览器测试刻意保留 Chromium sandbox,但 Playwright 默认下载的 chromium-headless-shell 是原始构建;当前 GitHub Linux Runner 无法为该原始二进制建立所需 sandbox,进程以 SIGTRAP 退出。仅依赖 Runner 偶然预装的 Chrome 也不具备可重复性。
  • 修复:通过 Playwright 官方 chrome 安装通道供应系统级 stable Chrome 及其依赖,再执行真实浏览器合同;避免选择无系统 sandbox 包装的 headless shell,不跳过验收,也不增加 --no-sandbox
  • 验证:workflow 合同回归断言 Playwright stable Chrome 必须被安装;聚焦部署合同测试、完整前端测试、目标 ESLint、生产构建与 git diff --check 通过;staging 质量门和部署结果另行记录。
  • 防复发:保留浏览器 sandbox 的 CI 必须使用具备系统 sandbox 包装的浏览器安装通道,不能直接启动无相应宿主配置的原始 headless shell,也不能依赖 hosted runner 的偶然预装状态。
  • 相关记录:BUG-082
  • 修复版本:本次修复提交

BUG-084 | staging V4 Worker 与候选引擎位于不同 Docker 网络

  • 状态:resolved
  • 首次发现:2026-07-27
  • 最近更新:2026-07-27
  • 影响面:生时校正 V4 后台评分、第三条及后续可评分事件、staging 登录态验收
  • 用户现象:Case 创建和前两条事件成功,第三条事件触发候选引擎后 Worker Job 失败并返回 fetch failed
  • 触发条件:staging Worker 同时需要访问 PostgreSQL app 网络和 API 所在的 Compose default 网络。
  • 根因:rectification-v4-worker 只加入 app 网络;api 只在 default 网络。Worker 虽正确配置 JYOTISH_API_BASE=http://api:5200,但 Docker DNS 无法跨网络解析和连接 api
  • 修复:让 staging Worker 同时加入 defaultapp 网络,不改变 production compose,也不暴露 API 端口。
  • 验证:部署合同测试固定 Worker 的内部 API 地址和双网络配置;聚焦测试、Compose 渲染、目标 ESLint、git diff --check 及 staging 登录态 smoke 另行记录。
  • 防复发:需要同时访问内部 API 与 staging PostgreSQL 的服务必须在 Compose 合同中显式加入两个现有私有网络。
  • 相关记录:BUG-082
  • 修复版本:本次修复提交