merge: sync latest staging into rectification v9

# Conflicts:
#	docs/BUG_HISTORY.md
This commit is contained in:
Jesse
2026-08-11 18:08:42 +08:00
29 changed files with 1893 additions and 310 deletions
+20 -3
View File
@@ -2745,7 +2745,24 @@
- 复发自:无
- 修复版本:本地 staging 候选(未 push / deploy
## BUG-162 | 生时校正入口没有服务端 Case 状态,复用第一条校正 Session 且并发会重复创建
## BUG-162 | 咨询工作流由路由预执行,Agent 无法真实编排 Skill 与服务器排盘工具
- 状态:resolvedstaging candidate
- 首次发现:2026-08-11
- 最近更新:2026-08-11
- 影响面:`POST /api/consult` 的个人/一般咨询、Mastra Agent、浏览器流式活动状态、咨询消息执行回执与计费结算;production 默认路径不变。
- 用户现象:回答可以生成,但服务端在 Agent stream 前已经完成咨询工作流,Agent 只是复述结果;Web 只能按“有无正文”猜测状态,无法证明 Agent 实际加载 Jyotish Skill 或调用排盘工具。
- 触发条件:咨询进入旧 runtime;route 直接执行 `runConsultationWorkflow()`,再把大段结果塞入 prompt,且仅返回 `text/plain`
- 根因:编排权在 Next.js route,不在 Agent;个人 Agent 未绑定服务器排盘工具,Skill/tool 执行合同和公开事件协议均不存在。若直接透传 `fullStream`,还会泄露 reasoning、工具参数/结果、出生资料或 Skill 内容。
- 修复:增加 `legacy|canary|enabled` runtime 开关;新路径由带 Jyotish Skill 的 Mastra Agent 调用请求级 `run-jyotish-consultation`,工具参数只允许 question/theme,出生资料始终由服务器上下文绑定,并以请求内 Promise 保证重复调用只计算一次。服务端把 `fullStream` 清洗为 NDJSON,仅公开安全的 run/Skill/tool/activity/answer 事件;Skill 和主工具合同未完成时最多重试一次,仍失败则释放预留点数且不保存成功消息。Web 按 content-type 保留 legacy `text/plain` 回滚路径,新路径只累积 `answer.delta`,收到 `run.completed` 后保存 workflow/execution receipt,并用服务器 activity 驱动状态 UI。浏览器断线后服务端继续完成互斥结算。
- 验证:聚焦回归覆盖动态 Skill 工具、General Agent 无个人排盘工具、服务器绑定参数、并发幂等、unverified precise timing blocked、私有 chunk 过滤、任意 NDJSON 边界、合同完成前正文阻塞、失败不保存、真实 activity UI、execution receipt 持久化、legacy 流与断线结算合同;最终命令和结果记录在本次 staging 发布回报。
- 防复发:个人咨询不得在 Agent stream 前直接执行主 workflow;不得把出生资料放入模型工具参数;公开流不得包含 reasoning、provider metadata、工具输入/结果或 Skill 正文;只有 `run.completed` 可进入成功消息持久化,步骤最多 32 个,计算与结算都必须请求内幂等。
- 回滚:仅将 staging 的 `CONSULTATION_AGENTIC_RUNTIME` 设为 `legacy`;无需回滚数据库或修改 production。
- 相关记录:BUG-161
- 复发自:历史咨询 runtime
- 修复版本:本次 staging 候选提交
## BUG-163 | 生时校正入口没有服务端 Case 状态,复用第一条校正 Session 且并发会重复创建
- 状态:resolvedlocal candidate;真实 PostgreSQL fixture 待远端 runner 执行)
- 首次发现:2026-08-12
@@ -2789,7 +2806,7 @@
- `sessions.find(sessionType === "birth_time_rectification")` 取客户端数组第一条,既不保证精确 sessionId,也不校验 Case 绑定;排序、缓存或刷新差异都会改变打开哪条记录。
- 旧测试只覆盖“能找到一条校正 Session”的客户端行为,没有服务端 Case 状态机、没有“点击指定 Session 必须精确恢复”的契约、没有并发/双击/多标签幂等断言,也没有 legacy→V9 一次性回填的数据库级验证,因此这些缺陷在回归中被遗漏。
## BUG-163 | V9 红队审查:引擎适配器契约不匹配 + accept 重放幂等顺序错误
## BUG-164 | V9 红队审查:引擎适配器契约不匹配 + accept 重放幂等顺序错误
- 状态:resolved(已修复;真实 PostgreSQL 17 与真实 Python 引擎双重实证)
- 首次发现:2026-08-11(红队审查 `60e2ce4f..724fb64c`
@@ -2813,5 +2830,5 @@
- 真实 Python 引擎:`scripts/jyotish_api_server.py` 启动后,修复后 `engine-client` 直连 `/api/rectification/v5/score` + `/v5/diagnostics` 成功产出候选(rank/relative_support/tied)、family_event 被排除、`confirmation_allowed=false`、diagnostics 键完整映射。
- 新增 `rectification-v9-engine-contract.test.ts`(9 项,含真实引擎响应形状 fixture)与 migration 顺序静态回归 1 项;v9 聚焦 33+108 全部通过;全量 `npm test` 12561232 pass / 18 Docker ENOENT 环境失败,与基线 6d7a9a97 同因,worktree 实证);`tsc --noEmit` 仅剩 6 个既有未触碰测试文件错误;ESLint 0 error`next build` 通过;`git diff --check` 通过。
- 防复发:引擎适配器必须有真实响应形状的契约测试;新增任何映射层必须对照 `scripts/rectification/contracts.py:SCOREABLE_EVENT_KINDS`;RPC 重放/幂等语义以“先重放后校验、重放校验已落库状态”为唯一实现顺序;迁移修改必须在真实 PostgreSQL 上从空库全量应用并重跑。
- 相关记录:BUG-162、BUG-112
- 相关记录:BUG-163、BUG-112
- 修复版本:本地 staging 候选(未 push / deploy