85ae00f391
Deploy staging to test server / deploy (push) Successful in 2m27s
Make staging migration, deployment, and maintenance workflows use the staging branch exclusively so test delivery no longer depends on or modifies production main.
181 KiB
181 KiB
Bug History
本文件是本仓库产品与代码 Bug 的长期知识库。处理任何 Bug 前先读并搜索本文件;完成修复或确认阻塞后,在同一变更中更新本文件。
基础设施、外部引擎、碎片目录和开工预检类风险仍记录在 docs/research/pre_work_error_ledger.md。同一问题若同时影响两类台账,应互相引用,不复制大段内容。
使用流程
- 用报错原文、接口路径、状态码、模块名和用户操作搜索本文件。
- 找到相似记录时,先验证既有防复发措施是否仍存在,再定位新的回归入口。
- 修复必须包含与风险相称的自动化测试;生产问题还要记录部署版本和脱敏后的生产验证。
- 完成后更新已有记录,或按下方模板添加新记录。复发问题必须填写
复发自,不能伪装成无关的新问题。 - 不记录姓名、出生资料、邮箱、用户/案例 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]、Supabasechat_sessions - 用户现象:用户点击删除后对话无法真正删除,或删除交互与账户弹窗不一致。
- 触发条件:登录后删除自己的一条历史会话。
- 根因:删除曾缺少所有者约束的服务端入口和对应数据库授权,前端也没有统一的站内确认面。
- 修复:增加所有者约束的服务端删除接口与数据库 grant,并统一站内确认弹窗。
- 验证:
tests/test_session_management_entrypoints.py、frontend/tests/chat-session-delete-contract.test.ts。 - 防复发:删除必须经服务端所有权校验;测试同时锁定 API、迁移和前端入口。
- 相关记录:无
- 复发自:无
- 修复版本:
e3d619c、65b8c42、5650ed1、fcf5794
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。 - 相关记录:无
- 复发自:无
- 修复版本:
28d58d4、5ee925c、308e5d5、e13d595、346ec02、a9ffbd9
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
- 复发自:无
- 修复版本:
dc0077e、20260721140000_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
- 复发自:无
- 修复版本:
b981c4e、20260721150000_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.ts、frontend/tests/consultation-entrypoint.test.ts、frontend/tests/consultation-birth-time-mode.test.ts、frontend/tests/birth-time-intake.test.ts。 - 防复发:咨询路由测试锁定“有效填报分钟无需授权即可使用”;页面契约禁止重新引入生时校正 toast 或阻断式选择。
- 相关记录:BUG-003、BUG-004
- 复发自:无
- 修复版本:待提交(本地可测)
BUG-010 | 浏览器直连 Supabase 导致自托管 PostgreSQL staging 误报未配置
- 状态:resolved
- 首次发现:2026-07-22
- 最近更新:2026-07-27
- 影响面:聊天首页启动、会话模型选择、退出登录;自托管 PostgreSQL staging。
- 用户现象:数据库和身份服务正常,首页却显示“Supabase 尚未配置”。
- 触发条件:
AUTH_PROVIDER=self-hosted且不提供浏览器 Supabase 公钥。 - 根因:页面启动、会话模型更新和退出登录仍直接创建浏览器 Supabase client;仅服务端 API 已切换到同源 PostgreSQL 路径。
- 修复:
/api/account返回当前用户完整 profile;首页通过/api/account、/api/sessions和/api/sessions/:id读写,退出使用 self-hosted identity client。 - 验证:
frontend/tests/chat-session-write.test.ts、frontend/tests/session-model-persistence.test.ts、frontend/tests/account-api.test.ts、ESLint、next build。 - 防复发:首页不得引用
createBrowserSupabaseClient;会话与 profile 只能经同源 API 访问。 - 相关记录:BUG-001、BUG-003
- 复发自:BUG-010
- 修复版本:待发布 staging
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.ts、frontend/tests/evidence-audit-panel.test.ts、frontend/tests/consultation-report-export.test.ts锁定聊天消息不再挂载这些内部组件。 - 防复发:聊天消息渲染契约禁止直接展示
techniqueTruth和workflowReceipt;需要运营或调试时使用独立的受控界面。 - 相关记录: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_validator从thin队列移入excellent断言,保持测试与同一审计规则一致。 - 验证:
tests/test_api_server_security.py::test_capability_audit_scans_registry_and_local_sources;Python 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的日志分别记录了RectificationTechnicalPacketRangeError和candidate_differences TimeoutError。 - 修复:稀疏扫描差异改用明确的范围级文案,禁止伪称相邻分钟切换;超过六小时的宽范围首轮跳过分钟级候选分区,较窄范围在候选分区发生已知超时、取消、配置或服务故障时保留服务端扫描证据并继续收集,不再返回 503;未知编程或契约错误仍失败关闭。
- 验证:
frontend/tests/conversational-technical-packet.test.ts、frontend/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_chart与unverified_birth_time两种星盘模式,继续拒绝general_no_birth_time、旧校正入口和不一致 request ID;分钟确认门禁保持不变。 - 验证:生产合成账号复现
409 mode_changed;frontend/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 处于
claimed或executing,两分钟租约已经过期,客户端重新加载交接。 - 根因:数据库 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,直到恢复、建案、计算和会话持久化全部完成才突然跳转,用户容易误以为点击无效并重复操作。
- 触发条件:
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.ts21/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: answer、resultCategory: 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:30–06: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_apply、confirmation_allowed和can_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 ESMregisterPlugin加载错误阻断,尚未进入业务断言。 - 防复发:主聊天区不得从 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_ready、confirmation_allowed: false、can_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_date、event_detail、new_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,自动使用最新caseId和turnVersion执行resume,不重复扣点;如果刷新后仍没有声明匹配的 case,则保留原错误,避免未经用户确认自动放弃旧校正记录。 - 验证:
frontend/tests/consultation-entrypoint.test.ts23/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 的逐段生成体验不一致。
- 触发条件:任意生时校正
start、resume或answer命令成功返回自然语言 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.ts32/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 消息在
thinking、streaming、settled三种视图状态之间切换。 - 根因:共享
ChatMessageRow使用条件分支把thinking渲染为仅有AgentActivityStatus,又只在streaming时显示 composing 状态;settled分支只保留正文,因此活动状态和正文被实现成了互斥内容,而不是同一消息的连续生命周期。 - 修复:assistant 消息始终在同一气泡内先渲染活动状态,再渲染当前已有正文;thinking/streaming 继续使用 working/composing orb,settled 只把状态文案切换为“回答已完成”,并把 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_date与event_detail仍等待对应数据库迁移后持久化。 - 验证:直接 RPC 探针确认旧格式为
true、带followUp为false;新增 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_date、event_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 继续正常读取。迁移应用后自动使用完整查询。
- 验证:服务角色直接查询确认修复前错误为
42703;frontend/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 / UPDATE,PostgREST 返回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/account、POST /api/consult、POST /api/birth-time-journey、今日星语、合盘与遗留生时评估接口 - 用户现象:全球出生地点已保存且可进入首页,但已有生时校正记录无法恢复并反复触发
action_conflict 409;正式咨询可能在扣点前返回资料不可用;部分旧功能仍要求中国行政区代码,合法全球资料会静默退回模板或 503。 - 根因:全球地点迁移只修复了 onboarding 与 conversational rectification 主入口,多个兄弟读取路径仍各自维护旧合同:强制
timezone_offset为数字、直接比较 Geoapify 七位小数坐标,或把中国省市区中心当作唯一地点真值。账户接口因此看不到数据库中实际存在的未完成 case,前端误判为需要重新创建。 - 修复:抽取共享历史时区解析器,兼容数据库 snake_case 与浏览器 camelCase 资料,并按实际申报/确认时间调用本地 IANA 历史时区服务;账户恢复使用已存 case 的不可变 offset 作为仅用于匹配的 fallback,并把坐标统一到六位耐久精度;咨询在扣点前使用最终 active time 补算 offset;journey 入口和 case loader 在严格解析前补算;今日星语、合盘和遗留评估优先使用真实全球经纬度与时区,中国行政区仅作兼容 fallback。
- 验证:账户 nullable offset + 七位坐标可恢复旧金山已有 case,时区 ID 或地点 ID 不一致仍拒绝恢复;verified consultation 使用最终 active time 解析
-8且解析失败不调用扣点;journey、今日星语、合盘和遗留评估的全球地点回归通过。两组聚焦套件共 84/84 通过,目标文件 ESLint、TypeScript--noEmit与git 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 持久化声明已经支持
placeId、placeType、provider、timezoneId和timezoneSource,但数据库函数conversational_rectification_valid_declared_birth_input仍只允许旧中国地点字段。合法全球地点声明在create_conversational_rectification_case内被判无效,并被 RPC 统一映射为conversational_action_conflict。 - 修复:新增向前迁移同步数据库地点声明白名单,接受全球地点身份、IANA 时区来源及坐标字段;地点身份允许
city、cityCode或placeId任一存在,同时保留旧中国地点兼容和数值边界校验。 - 验证:数据库迁移单独执行成功;使用新的 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_conflict;case 的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 递增到 1,narrative 和目标event_detailfollow-up 正常返回;用同一 actionId 重放返回相同 turn,账户积分保持 99。服务端日志两次均为actionKind=answer、resultCategory=success、billingState=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_id与raw_text恢复,但旧恢复链路没有读取这些数据。 - 修复:新会话从首条 Agent narrative 开始持久化完整消息序列,每次回答后保存真实的
Agent → 用户 → Agenttranscript;resume 接口按 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_date和event_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 在消息列表末尾设置了滚动锚点和
scrollIntoVieweffect;生时校正使用独立的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
- 影响面:生时校正首轮引导、中间事件追问、方向切换、未来事件、暂停、放弃与确认消息
- 用户现象:模型已经结合上下文生成回答后,网页仍显示“已记录”“当前累计”“下一步”“还差时间定位”等重复话术;部分操作还会新增程序模板气泡,使对话像问卷而不是连续的一问一答。
- 根因:编排层把事件提取结果、
followUpmetadata 和收敛状态当成可见文案的唯一真源,在模型生成之后又根据分支拼接或替换 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=true、schemaValidated=false、issues=["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 秒成功结果还曾因旧引用正则误判被丢弃。
- 修复:生产模型只生成
narrative与evidenceRequest,候选状态、时间、范围、分盘层、引用和领域依据由服务端从 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-conversation的regenerate与其他非最终叙事轮、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。生成结果携带实际模型 ID,validation 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_evaluated、blocked技法和确认权限,却没有继续提出下一个问题;回答像调试报告而不是连续的一问一答。 - 根因:叙事上下文直接暴露事件的私有
domain、建议领域和完整 expert workflow 状态,模型因此围绕工程元数据组织回答;同时问题修复器只处理首轮或明显截断的句子,语法完整但没有问号的中间回答会原样通过。技法保持not_evaluated的直接原因则是当前有效、受支持且可评分的事件不足三条,路由尚未进入scoreEvents(),并非 Mastra 无法调用技法。 - 修复:新增叙事专用上下文,移除事件
domain、建议领域和内部评分;证据采集阶段只允许暴露已实际used或partial的技法,不再展示未调用清单、阻塞项或确认权限。私有语义领域仍保留在服务端用于事件去重、跨领域路由和候选评分,但不得进入用户可见文案。所有非最终回答必须包含且只引导一个下一问题;模型正文漏问时追加同一次模型生成的evidenceRequest.prompt,不使用固定业务模板。 - 验证:新增回归覆盖事件正文可见但内部领域不可见、建议领域不进入叙事 packet、未调用技法不在采集轮展示,以及完整陈述漏问时补入模型自写问题;叙事、路由和编排聚焦测试通过,目标 ESLint、TypeScript
--noEmit与git 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
--noEmit与git 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 文本的
start、answer、regenerate命令加入可选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:07–05: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 原生
career、wealth、marriage领域各选择一条最强事件;直接映射优先于代理映射,日级优先于月级和年级,同精度选择较新事件。月级和年级事件只取范围中点作为代表日,两个候选最多发起六次外部事件扫描;响应明确记录符合条件事件数、实际选中数和选择策略,不再暗示全部事件均已外部验证。通用 range scan 保持不变。 - 验证:长对话回归断言十二条符合映射的事件只产生六次扫描,两个候选各覆盖事业、财富、关系三领域,所有扫描均为单日;相关 Python 测试 42/42 通过。使用真实 VedAstro key 重跑同一十二事件 fixture,首次完整命令约 9.7 秒、缓存后约 3.6 秒,官方响应状态为
official_verified。真实SearchEvents对05: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=false和vedastro_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,不能只跑单元测试或tsc;App Routerroute.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 校验中持久化
prompt、answerMode与proposedDate。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 <= 5且margin >= 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 持久化、日期候选确认与数据库约束
- 用户现象:代码已写入
prompt、answerMode和proposedDate,但生产迁移工作流不会上传或执行对应 migration;生产数据库仍可能按旧 JSON 合同拒绝新 turn。 - 触发条件:从 GitHub Actions 手动执行生产生时校正 migration 的
check或apply操作。 - 根因:新增
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_no和followUp.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-v3case,首轮候选已经包含rangeStart/rangeEnd,但可见 narrative 没有显示它们;旧生产版本还会调用模型生成同类泛化开场。 - 根因:BUG-072 的快速首轮正确保留了候选范围,却只把范围写入结构化
candidate;首页不单独渲染该字段,固定 narrative 仍沿用了不含范围的旧提问。 - 修复:复用首轮已经计算出的声明范围,在确定性 narrative 中明确显示当前待核对边界,并说明它不是已确认分钟;继续只问一件带年月的重要经历,不恢复零证据模型调用或分钟扫描。
- 验证:Orchestrator 回归断言首轮正文包含真实
rangeStart–rangeEnd、未确认边界和单事件提问;聚焦测试、目标 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:26–05:30,无空问题死状态,原active_birth_time不变且未主动保存前acceptedRange为空。静态浏览器验收确认日期修订输入框、范围保存按钮、非确认分钟文案和 390px 无横向溢出;真实登录态 UI 因隔离服务未连接认证配置,本轮未声称已验收。 - 防复发:生时校正业务真源必须是 V4 Case 和 append-only 事件台账,不得从聊天正文反向恢复;任何公开结果只能显示通过稳定性门的范围,单分钟峰值不得成为可保存结果;证据不足必须生成下一题或明确暂停,不能进入
awaiting_answer + currentQuestion=null;V4 路径不得写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 所在的 Composedefault网络。 - 根因:
rectification-v4-worker只加入app网络;api只在default网络。Worker 虽正确配置JYOTISH_API_BASE=http://api:5200,但 Docker DNS 无法跨网络解析和连接api。 - 修复:让 staging Worker 同时加入
default与app网络,不改变 production compose,也不暴露 API 端口。 - 验证:部署合同测试固定 Worker 的内部 API 地址和双网络配置;聚焦测试、Compose 渲染、目标 ESLint、
git diff --check及 staging 登录态 smoke 另行记录。 - 防复发:需要同时访问内部 API 与 staging PostgreSQL 的服务必须在 Compose 合同中显式加入两个现有私有网络。
- 相关记录:BUG-082
- 修复版本:本次修复提交
BUG-085 | 生时校正回退为独立面板和固定领域问卷
- 状态:investigating
- 首次发现:2026-07-27
- 最近更新:2026-07-28
- 影响面:生时校正聊天 Surface、事件语义、后台 Job、候选计算、诊断、Reasoner、Renderer 与持久化主链
- 用户现象:进入生时校正后看到独立的校正面板、证据区域和固定问题;交互不像普通 session,领域也不再根据用户刚讲的经历动态选择。
- 触发条件:旧 V4 既在界面层使用独立校正结构,又让
question-planner.ts和question-author.ts直接决定领域顺序与问题文案;模型只负责写下一问,后台没有形成完整 Agent 决策闭环。 - 根因:产品状态被压缩成“下一问字符串”,事件语义、候选特征、诊断结果、问题机会、模型决策和公开消息之间没有受约束的 durable contract;因此即使替换提示词,系统仍会沿用问卷式控制流,且无法审计模型为何选题或安全重放已完成 Job。
- 修复:删除旧
question-planner.ts与question-author.ts,将回答处理重构为完整 V5 主链:保存回答并创建后台 Job → Evidence Reconciliation → Candidate Engine / Feature Snapshot → Diagnostics → Opportunity Builder → Bounded Reasoner → Decision Validator → Renderer → Atomic Job Completion。可见层继续复用普通 session 聊天 Surface;Reasoner 只能选择服务端生成的 opportunity 或受约束动作,不能注入分钟、分数、事件或任意问题;Renderer 只表达已验证决定,候选范围不得表述为已确认出生分钟。Agent Run、Public Message、Diagnostics、Feature Snapshot、Pending Evidence 和事件修订均作为一等产物持久化。 - 验证:67 个 TypeScript 聚焦合同全部通过,覆盖普通 session UI、完整 V5 artifact chain、Reasoner 单次诊断预算、Opportunity 选择、shadow/legacy 隔离和 range-only 输出;7 个 Python 服务合同通过。真实 PostgreSQL 14 已按 V4 → V5 顺序完成 migration dry-run,并跑通
processing → reasoning → rendering → complete、五类 artifact 各一条落库和 completed Job 幂等重放。tsc --noEmit未出现 V5 新错误,只剩birth-time-journey-engine、identity-auth-integration、onboarding-route三处无关基线错误。当前完成边界为本地可测,尚未提交、推送、迁移 staging 或执行登录态 smoke。 - 防复发:生时校正不得再次把模型降级为“问题文案生成器”;所有可见动作必须来自 server-owned opportunity,经 bounded reasoner、decision validator 和 renderer 后原子持久化。测试必须同时锁定 legacy/shadow 隔离、artifact 完整性、候选范围边界和 completed-job replay 指纹。
- 相关记录:BUG-020、BUG-075、BUG-080、BUG-081、BUG-082、BUG-083、BUG-084、BUG-086
- 修复版本:本地 V5 重构,待提交与 staging 验收
BUG-086 | 模型下一问可绕过当前事件而跳成领域问卷
- 状态:investigating
- 首次发现:2026-07-27
- 最近更新:2026-07-28
- 影响面:生时校正 V5 的当前事件延续、问题机会构建、诊断工具预算、模型决策验证和 Job replay
- 用户现象:用户回答“2016 年离家去外地上大学”后,下一问直接变成“请说一次影响较大的搬家或长期迁居”,看起来仍按“升学 → 搬家”模板轮询,而没有承接刚才的具体经历。
- 触发条件:当前事件仍缺必要精度,但旧 Worker 只校验模型返回结构;只要模型输出一个格式合法的新领域问题,就可以绕过当前事件和服务端已知证据缺口。
- 根因:旧方案把“required continuation”作为给模型的提示,而不是服务器拥有的候选动作和最终决策约束;诊断结果也没有独立工具预算、持久化产物和可回放选择依据,无法阻止合法 JSON 携带错误业务路由。
- 修复:Opportunity Builder 将未解决的当前目标设为独占路由,并只发布带稳定 ID、目标事件、效用分解和隐私成本的问题机会;Bounded Reasoner 最多执行一次只读诊断,最终只能选择活动 opportunity 或受限状态动作;Decision Validator 拒绝不存在、跨 Case、非活动或越权的机会,也禁止模型直接写问题、分钟、分数和事件。Reasoner 不可用、返回非最终诊断或耗尽预算时走同一确定性 fallback policy;Renderer 根据 validated decision 生成自然语言承接,Worker 再通过单一 completion RPC 原子保存全部产物。
- 验证:对抗合同覆盖“当前目标独占下一问”“只能选择服务端活动 opportunity”“诊断预算耗尽 fail closed”“模型不得注入问题/分钟/事件/分数”和“Reasoner/Renderer 不可用时确定性降级”。真实 PostgreSQL completed-job replay 已验证:相同完整 payload 指纹返回既有 Case;任一 artifact 改变且指纹不同会抛出
rectification_v5_replay_payload_mismatch,不会二次写入或接受漂移结果。当前仅完成本地验证,staging 行为仍待发布后验收。 - 防复发:当前事件延续必须是服务端 opportunity 所有权规则,而不是 prompt 建议;模型输出即使结构合法,也必须经过 bounded tool budget、active-opportunity lookup、decision validation 和 completion payload hash 四层门控。
- 相关记录:BUG-075、BUG-085
- 修复版本:本地 V5 重构,待提交与 staging 验收
BUG-087 | self-hosted staging 管理员看不到独立后台入口
- 状态:superseded by BUG-092
- 首次发现:2026-07-29
- 最近更新:2026-07-29
- 影响面:self-hosted staging 账户菜单、
GET /api/account、独立后台入口;不影响后台独立登录与requireAdminSession - 用户现象:身份库已持久化
admin或viewer角色的用户登录主站后,账户菜单不显示后台入口;即使显示旧入口,主站/admin路径也会返回 404。 - 触发条件:
AUTH_PROVIDER=self-hosted,后台部署在与主站不同的AUTH_ADMIN_ORIGIN,用户角色以逗号分隔形式持久化在identity.users.role。 - 根因:主站
isAdminUser对 self-hosted 模式直接返回false,没有读取持久化角色;侧栏又把入口写死为主站相对路径/admin/codes。既有后台鉴权已按持久化角色执行,但主站入口发现逻辑没有复用同一授权事实,独立域名部署合同也没有进入账户响应。 - 修复:self-hosted 分支通过现有
ADMIN_DATABASE_URL管理只读连接查询当前用户的identity.users.role,仅admin或viewer可见入口,且不使用ADMIN_EMAILS替代角色授权;GET /api/account在服务端解析身份配置并返回AUTH_ADMIN_ORIGIN + /admin/codes,Supabase 模式继续返回/admin/codes;账户与侧栏类型透传该 URL,并将文案改为“后台管理”。后台独立登录和requireAdminSession保持不变。 - 验证:
frontend/tests/admin-contracts.test.ts、frontend/tests/admin-users-contract.test.ts、frontend/tests/account-api.test.ts、frontend/tests/sidebar-contract.test.ts锁定持久化角色、独立后台 URL、服务端环境边界和后台写权限门禁;目标 TypeScript、构建与 staging 登录态 smoke 结果另行记录。 - 防复发:self-hosted 主站入口发现必须以
identity.users.role为授权事实,不能退回邮箱 allowlist;客户端不得读取后台 origin 环境变量或硬编码主站/admin路径;后台 API 必须继续独立执行requireAdminSession,入口可见性不得被当作授权。 - 相关记录:BUG-010、BUG-083、BUG-084、BUG-092
- 复发自:BUG-010
- 修复版本:已由 BUG-092 的同域单会话架构取代
BUG-092 | self-hosted staging 双域后台与主站会话模型冲突
- 状态:resolved
- 首次发现:2026-07-29
- 最近更新:2026-07-29
- 影响面:staging Better Auth 配置、后台页面与 API、登录、账户入口、Caddy、部署校验和 smoke;生产配置不变。
- 用户现象:管理员需要第二套后台域名和浏览器会话才能进入后台,主站登录态不能直接使用;
viewer还被当作后台只读角色,与仅数据库admin可进入的产品合同冲突。 - 触发条件:self-hosted staging 同时配置用户与后台 origin/secret、Caddy 拆分两个站点,并按 Host 选择 Better Auth 实例。
- 根因:早期隔离设计把后台浏览器 surface 当成第二套身份系统,导致入口发现、登录、Cookie、部署变量和授权策略重复;同时把入口可见性与 API 权限错误扩展到
viewer。 - 架构决策:后台复用主站 Better Auth user session;
identity.users.role的持久化admin是唯一后台授权事实。Better Auth 插件的/api/auth/adminendpoint 继续在主站 fail-closed404,未知 Host 继续421。 - 修复:删除活动运行时后台 origin/secret 与
services.admin,服务端数据 client 和requireAdminSession统一读取 user session;后台 layout 增加服务端 gate,匿名转/login、非 admin 不渲染;所有后台 API 保留独立 guard,payments/packages 改用requireAdminSession;isAdminUser、账户入口和 Refine policy 收敛为 admin-only;登录取消 Host 分流;staging Caddy、Compose、环境校验、部署脚本、工作流和 smoke 收敛为同域。 - 验证:身份 config/host/auth、admin policy/contracts、account/sidebar/login、部署/工作流与 admin layout/API guard 合同更新;针对性测试、TypeScript、Next build 与
git diff --check结果记录在本次交付报告。生产部署未执行。 - 防复发:活动运行配置和测试不得重新引入独立后台域名、
AUTH_ADMIN_ORIGIN、BETTER_AUTH_ADMIN_SECRET或浏览器 admin auth service;viewer对后台入口、页面、读 API 和写 API 均必须为403;入口可见性不能替代 route guard。 - 相关记录:BUG-010、BUG-083、BUG-084、BUG-087
- 复发自:BUG-087
- 修复版本:
435e628806390e7ae138363491e7bae63ee801d4,staging 已验收
BUG-093 | 后台支付入口分散且界面风格不一致
- 状态:investigating
- 首次发现:2026-07-29
- 最近更新:2026-07-30
- 影响面:后台 Refine 侧栏、
/admin/payments、/admin/packages、易支付配置与对话页充值入口。 - 用户现象:支付记录与支付配置占用两个导航项,页面仍使用主站
standalone-page/admin-header/admin-section样式;套餐新增表单常驻页面,后台默认退出入口还会触发登出,管理员难以直接返回对话;对话页支付入口缺少安全默认关闭和服务端创建订单硬门禁。2026-07-29 复发时,Z-Pay 配置不能折叠且占据长页面,后台受全局html/body overflow:hidden限制无法纵向滚动,套餐 API 与易支付配置 API 仍调用 self-hosted adapter 不支持的 Supabase builder/RPC。2026-07-30 部署dd8e2ad9c7e76d0152b4563c43a45b1e26137035后,GET /api/admin/payments与套餐管理仍返回 500。 - 触发条件:进入同域
/admin后管理支付记录或套餐,或点击 Refine 侧栏底部默认 Logout;复发条件为进入支付管理、展开长配置或调用套餐 CRUD / 易支付配置读写。2026-07-30 的数据库权限复发在admin_runtime通过ADMIN_DATABASE_URL查询支付表时稳定触发。 - 根因:首轮支付后台实现依赖 Supabase 专用关联 select、分页、计数和 Admin Auth 查询;self-hosted staging 的本地 PostgreSQL adapter 不支持这些 builder 能力,支付记录因此统一降级为“支付记录服务暂时不可用”。同页套餐设计也不符合最新后台信息架构,易支付配置响应漏投影
chat_enabled,chat 创建订单又依赖服务端提交网关后猜测跳转地址,不兼容标准易支付收银台表单页。复发遗漏源于上轮只把支付记录切换到 PostgreSQL,套餐与配置契约测试没有锁定 self-hosted 数据链,且未覆盖聊天全局滚动边界下的后台专用滚动容器。2026-07-30 的直接根因是20260727020000_epay_packages_orders.sql只向 Supabase 的service_role/authenticated授权,未向 self-hosted 后台实际使用的admin_runtime授予payment_packages、payment_orders权限,也未添加对应 RLS 策略;因此数据库健康且新 SHA 已部署,后台 SQL 仍被 PostgreSQL权限门禁拒绝。同日还确认 staging 迁移与部署工作流错误地要求目标 SHA 属于main历史,使完全独立的测试分支被生产分支阻塞;该控制面耦合导致为恢复 staging 而误合并生产 main。 - 修复:支付记录改为通过
queryAdminRows执行参数化 SQL,联表public.payment_orders、public.payment_packages和identity.users,以窗口计数保留分页合同并用独立聚合 SQL输出统计;不再使用 Supabase builder 或 Admin Auth。后台在支付管理之后新增独立“套餐管理”资源和页面,套餐新增、编辑、停用、错误重试及原字段保持完整,支付页只保留概览、Z-Pay(易支付)渠道配置和支付记录。配置读取补回chat_enabled与chatEnabled。创建订单完成登录、开关、配置、SSRF、套餐和订单校验后,直接返回带sign/sign_type的标准submit.php收银台 URL,不服务端请求网关、不返回商户密钥;对话页用浏览器打开该 URL,套餐加载异常显示安全错误,正常enabled=false仍静默隐藏。复发修复将 Z-Pay 配置改为默认收起的 Ant DesignCollapse,展开后才显示表单和操作;为 AdminApp 增加admin-app-shell的100dvh独立纵向滚动边界而不改聊天全局规则;套餐 CRUD 全部改用queryAdminRows参数化 SQL、UUID 校验、returning与 404;易支付读取仅在 PostgreSQL42P01时回退环境变量,保存直接参数化调用public.admin_save_epay_settings并使用函数返回行,保留原子审计和脱敏响应。2026-07-30 新增前向迁移20260730010000_admin_payment_permissions.sql,向admin_runtime最小授予套餐读写、订单只读、易支付配置读取及保存函数执行权限,并为启用 RLS 的支付表补齐角色策略;不授予订单写入或删除权限。Gitea 与 GitHub 的 staging 迁移、部署和测试环境运维工作流统一 checkoutstaging,删除 staging SHA 属于main历史的要求;生产工作流保持不变。误合入 main 的 PR #1 已由 PR #2 的 revert 恢复,恢复后 main 内容树与合并前提交43581ac0f75e7f157032503475e878bd53ad161d完全一致。 - 验证:
frontend/tests/admin-contracts.test.ts锁定支付、套餐资源顺序;frontend/tests/admin-payments-contract.test.ts锁定本地参数化 SQL、identity.users联表、套餐 SQL CRUD/UUID/404、独立套餐页面、默认折叠和后台专用滚动容器;frontend/tests/epay-settings.test.ts锁定chatEnabled回显、queryAdminRows读取、参数化admin_save_epay_settings、不依赖 Supabase builder/RPC、默认折叠和不泄露 key。2026-07-29 运行三份契约测试共 27 项全部通过;ESLint、TypeScript 与git diff --check结果记录在本次交付报告。2026-07-30 线上健康响应证明部署 SHA 为dd8e2ad9c7e76d0152b4563c43a45b1e26137035且本地业务库、身份库均健康;静态权限审计确认支付迁移缺少admin_runtimegrant/RLS。新增权限迁移契约后,支付、套餐、配置三组 21 项回归全部通过;生产态最终验证仍等待迁移应用和已登录 smoke,因此状态保持investigating。 - 防复发:self-hosted staging 后台查询不得依赖 LocalPostgresDataClient 未实现的 Supabase builder、RPC 或 Admin Auth 能力;支付与套餐必须保持独立资源顺序。套餐与易支付配置契约必须显式拒绝 Supabase builder/RPC 并锁定参数化 SQL、404、原子函数写入和安全错误响应;支付配置必须默认折叠,后台必须拥有独立滚动容器且不得放宽聊天的全局
overflow:hidden。易支付配置读写测试必须同时覆盖数据库列和公开字段;创建订单只生成经公网 SSRF 校验的签名收银台 URL,商户密钥只能参与服务端签名,不得进入 URL、响应、日志或审计。对话支付默认关闭,UI 与创建订单 API 必须共享服务端开关;可用性测试不得提交伪订单或返回 URL、PID、密钥、headers/body。 - 相关记录:BUG-087、BUG-092
- 复发自:BUG-093
- 修复版本:待提交(本地可测)