fix(consult): BUG-954~956/958 窗口方法块、abort 分码、合同降级

窗口 Agent 注入不含本命骨架的方法块;tripwire abort 走 skill_binding_failed;
无工具但有正文降级交付;应期问题仍先调工具。BUG-957 等窗口线验证后再做。
This commit is contained in:
jesse-ux
2026-09-18 16:37:43 +08:00
parent e5b2ad14dd
commit 5b6abc238b
13 changed files with 594 additions and 27 deletions
+74 -9
View File
@@ -12512,7 +12512,7 @@
## BUG-954 | 申报时段咨询自 08-21 起每轮秒败:窗口 Agent 绑了 skill 却没把方法块写进系统提示
- 状态:investigating(根因已由服务端日志确认,修复未做)
- 状态:resolved
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`src/mastra/index.ts` `windowJyotishInstructions` / `getWindowJyotishAgent`、`src/mastra/skill-binding.ts` `jyotishSkillBoundProcessor`;`declared_birth_window` 模式的每一轮
@@ -12521,13 +12521,78 @@
- 根因(服务端日志实证,requestId 脱敏为前八位 `95de38fd`):
1. `docker logs jyotisha-staging-web-1` 命中两条 `[WORKFLOW] Error executing step ... input-processor.step.processor:jyotish-skill-bound: Error: Jyotish skill method is not bound into the system prompt for jyotish-vedic-astrology`(两次 attempt 各一条)。
2. 同一 runId 的 `[agent-observability]`:`toolCalls: []`、`modelStepCount: 0`、`inputTokens: 0`、`outputTokens: 0`、`run.total durationMs: 69`、`retryCount: 1`、`errorCode: runtime_contract_incomplete`。**模型从未被调用**,整轮 69 毫秒结束。
3. 代码对应:`jyotishSkillBoundProcessor`(`skill-binding.ts:143-153`)在输入处理阶段断言系统提示里含 `BOUND_METHOD_MARKER`(`<jyotish-skill name="...">`),缺失即 `abort()`。`jyotishSkillMethodBlock` 只在 `jyotishInstructions`(本命,`index.ts:21`)里插值;`windowJyotishInstructions`(`index.ts:176-190`)从未包含它,而 `getWindowJyotishAgent`(`index.ts:198`)照样 `...jyotishSkillBinding()`。
4. 时间线:处理器由 `d04fc30b`(2026-08-18)引入;窗口 Agent 由 `9958e00a`(2026-08-21)新建,**诞生时就带绑定、不带方法块**。因此申报时段路线自 2026-08-21 起每轮必败,已持续约四周。
- 为什么没被发现:`abort()` 被翻译成与「模型没调工具」相同的公开码 `runtime_contract_incomplete`,与 BUG-922/923/937 的现象完全同名。BUG-937 的记录写的是「本命与申报时段两条路线每一轮都失败」,本命线被 `required` 的修复救活,窗口线的这条根因从未被触及,却因为现象消失一半而被当作同一件事结案。测试侧也没有「凡 attach `jyotishSkillBinding()` 的 Agent,其 instructions 必须含 marker」这条源码合同。
- 修复:见 `docs/tasks/TASK-window-consult-contract-20260918.md`。要点:窗口指令注入带 marker 的方法块(不能直接照抄本命块,它带 Level 2 报告骨架与本命口径);补源码合同测试;处理器 abort 给出独立可见错误码,不再与合同未完成同码。
- 验证:待实现。
- 防复发:待实现。
- 关联记录:BUG-205、BUG-214、BUG-922、BUG-923、BUG-937、BUG-938
3. 代码对应:`jyotishSkillBoundProcessor` 在输入处理阶段断言系统提示里含 `BOUND_METHOD_MARKER`,缺失即 `abort()`。`jyotishSkillMethodBlock` 只在本命 `jyotishInstructions` 里插值;`windowJyotishInstructions` 从未包含它,而 `getWindowJyotishAgent` 照样 `...jyotishSkillBinding()`。
4. 时间线:处理器由 `d04fc30b`(2026-08-18)引入;窗口 Agent 由 `9958e00a`(2026-08-21)新建,诞生时就带绑定、不带方法块。申报时段路线自 2026-08-21 起每轮必败,约四周。
- 为什么没被发现:`abort()` 被翻译成与「模型没调工具」相同的公开码 `runtime_contract_incomplete`。见 BUG-955。
- 修复:选任务书方案 (a)。抽出 `jyotishSkillMethodCoreBlock`(方法主体 + marker,不含本命 Level 2 报告骨架),窗口指令注入该块;本命仍用带骨架的 `jyotishSkillMethodBlock`。窗口口径写明不采用 Level 2 骨架,并优先于方法块里的报告模板 / 应期表述。
- 验证:遍历式源码合同——凡 `index.ts` 里 attach `jyotishSkillBinding()` 的 Agent,instructions 必须含 marker;窗口 Agent `getInstructions()` 后 `jyotishSkillBoundProcessor` 不 abort。部署后仍需在 staging 真发一轮申报时段提问,回执出现 `run-jyotish-window-consultation` completed。
- 防复发:源码遍历合同;不得用删掉 `jyotishSkillBinding()` 让窗口路线通过。
- 关联记录:BUG-205、BUG-214、BUG-922、BUG-923、BUG-937、BUG-938、BUG-955
- 复发自:无(与 922/923/937 同现象、不同根因;那三条均未覆盖窗口 Agent 的提示词装配)
- 修复版本:待发布
- 修复版本:`8e3e5c73`
## BUG-955 | 输入处理器 abort 与「合同未完成」同码,窗口装配失败藏了四周
- 状态:resolved
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`stream-agent-response.ts`、`agent-observability.ts`、`jyotishSkillBoundProcessor`
- 用户现象:窗口路线 abort 后公开码仍是 `runtime_contract_incomplete`,与「模型没调工具」无法区分,观测上像 BUG-922。
- 触发条件:系统提示缺 `BOUND_METHOD_MARKER`,Mastra 发 `tripwire` 块且不调模型。
- 根因:`consumeAttempt` 把 tripwire 当未知块丢掉,流正常结束;`contractReady()` 为假后走合同重试,最终抛同一公开码。
- 修复:识别 `tripwire` / 「not bound into the system prompt」为内部码 `skill_binding_failed`;回执追加 `validation skill-binding-abort failed`;打 `[consult-binding-error]`(requestId + 内部码,不含提示词);不走合同重试。公开层仍用 `runtime_contract_incomplete`,靠回执步骤名区分。无工具导致的合同未完成另记 `runtime-contract-incomplete`。
- 验证:假流 tripwire vs 空流,回执步骤名分别为 `skill-binding-abort` / `runtime-contract-incomplete`;`toAgentObservabilityErrorCode` 两个码都能落。
- 防复发:装配失败不得再并进合同未完成;参照 BUG-938 对供应商 error 块的同类处置。
- 关联记录:BUG-954、BUG-938、BUG-922
- 复发自:无
- 修复版本:`8e3e5c73`
## BUG-956 | 合同未绿时静默丢弃模型正文,用户只看到「未完成」
- 状态:resolved
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`stream-agent-response.ts`
- 用户现象:合同没绿时模型写过的正文被丢掉,用户只看到「Agent 未完成必要的方法与计算步骤」。
- 触发条件:`requireTool` 路径上工具成功次数为 0,但有非空 `text-delta`。
- 根因:`outputText` 在 `contractReady()` 为假时直接 return,重试后仍未绿就抛 `runtime_contract_incomplete`,正文从未发出。
- 修复:未绿期间仍缓冲正文。两次 attempt 后仍未绿、且零次成功计算、缓冲非空:交付该正文,文末附服务端说明「这次没跑完星盘计算,上面是模型直接写的,先看着。」,回执 `validation contract-degraded failed`,`run.completed`。无工具也无正文:维持 `runtime_contract_incomplete`。不放宽 `contractReady()` 的「每请求一次真实计算」。二次成功计算仍失败,不走降级。
- 验证:假流无工具+有正文 → 正文 + 降级说明 + `contract-degraded`;假流无工具+无正文 → `runtime_contract_incomplete`。
- 防复发:合同未绿不得再整段丢正文;既有「合同完成前的旁白不进可见回答」仍保留,成功计算后清空缓冲。
- 关联记录:BUG-954
- 复发自:无
- 修复版本:`8e3e5c73`
## BUG-957 | 窗口计算由模型决定调不调,对结果无信息增益
- 状态:investigating
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`consultation-tools.ts` `run-jyotish-window-consultation`、咨询运行时
- 用户现象:无(窗口线被 BUG-954 挡住,本项尚未在真实环境验证)。
- 触发条件:窗口工具 `inputSchema` 只有 `question`,出生数据完全服务端绑定。
- 根因:由模型决定调不调对计算结果没有信息增益,只多一条失败路径(BUG-205/214/922/923/937)。
- 修复:本单不做。任务书要求等 BUG-954 在真实环境验证通过后再单独做服务端预跑 + 同请求缓存。
- 验证:未做。
- 防复发:不得与救急同轮改运行时结构。
- 关联记录:BUG-954、BUG-205、BUG-214、BUG-922、BUG-923、BUG-937
- 复发自:无
- 修复版本:—
## BUG-958 | 窗口指令「必须调工具」与「不得给应期」未写清,模型可能跳过计算或拒答
- 状态:resolved
- 首次发现:2026-09-18
- 最近更新:2026-09-18
- 影响面:`src/mastra/index.ts` `windowJyotishInstructions`
- 用户现象:应期类问题在窗口模式下可能因为「精确应期不可用」而跳过计算或整题拒答。
- 触发条件:申报时段咨询问到时间 / 应期。
- 根因:窗口指令写了必须调工具,也写了不得给精确应期,两句之间没有显式仲裁。
- 修复:补一句:应期类问题仍然要先调工具,再用稳定层给方向性回答,并说明哪部分需要出生分钟;不得因为精确应期不可用而跳过计算或拒答整题。
- 验证:`consultation-workflow-contract.test.ts` 源码断言。
- 防复发:窗口指令源码合同锁住该句。
- 关联记录:BUG-954
- 复发自:无
- 修复版本:`8e3e5c73`
@@ -0,0 +1,47 @@
# PROGRESS · 申报时段咨询修复(2026-09-18 第四轮)
工作树:`.worktrees/window-consult-contract-20260918`
分支:`codex/window-consult-contract-20260918`
基线:`origin/staging` @ `e5b2ad14`(任务书写 `9cdcf96b`,其后纯文档已快进到改写后的任务书)
合入提交:`8e3e5c73`
任务书:`docs/tasks/TASK-window-consult-contract-20260918.md`
## 任务状态
| 任务 | 状态 | 说明 |
| --- | --- | --- |
| BUG-954 窗口指令注入带 marker 的方法块 | 完成 | 选方案 (a) |
| BUG-955 abort 与合同未完成分码 | 完成 | 内部码 `skill_binding_failed`,公开码不变 |
| BUG-956 合同未绿不得丢正文 | 完成 | 零次计算 + 有正文 → 降级交付 |
| BUG-957 服务端预跑 | 未做 | 按任务书等 954 真实环境验证后再单开 |
| BUG-958 应期仍先调工具 | 完成 | 窗口指令补一句 + 源码断言 |
## 954 选型
选 **(a)**。抽出 `jyotishSkillMethodCoreBlock`(方法主体 + marker),本命 Level 2 报告骨架留在 `jyotishSkillMethodBlock` 作为可选后缀。窗口不加骨架。另加一句窗口口径优先于方法块里的报告模板 / 应期表述,避免 SKILL.md 摘录把 Level 2 又带回来。不选 (b):完整方法块再逐条覆盖,会把本命应期口径先写进去再否定,窗口线刚活过来时更脆。
## 断言三栏(既有测试)
| 测试 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| 无工具 + 有正文 | `run.failed`,不发 `answer.delta` | 交付正文 + 降级说明,`run.completed`,回执 `contract-degraded` | BUG-956 |
| 被拒 tool 的回执 status | `["completed", "failed"]` | 多一拍 `runtime-contract-incomplete` | BUG-955 |
| schema 拒收后 `state.steps` | `skill + tool:failed` | 再加 `validation:failed` | BUG-955 |
| 已记录的 tool 失败数 | 全部 failed 步 === 1 | tool failed 仍为 1;另有合同未完成步 | BUG-955 不得把 tool 失败再记一次 |
| 失败回执 durationMs | `[undefined, 20936]` | 多一拍无 duration | BUG-955 |
| 上述 used | 2 | 3 | 同上 |
## 测试
| 项 | 结果 |
| --- | --- |
| `tsc --noEmit` | 0 错 |
| `npm run lint` | 0 error(120 warning,与基线同量级,未顺手修) |
| 定向(workflow-contract / agentic-runtime / observability / voice / birth-time-mode) | 116 pass / 2 fail。2 条是本机 Windows `EPERM` 无法为 live skill 建 symlink(`personal Agent exposes…` / `general agent runtime has no Jyotish skill package…`),与基线缺口同类,不是本单引入 |
| 本单新增 | 遍历 attach `jyotishSkillBinding()` 的 Agent 必须含 marker;窗口 `getInstructions` 后处理器不 abort;tripwire vs 空流回执步骤名不同;无工具+有正文降级;无工具+无正文仍 incomplete;窗口应期仍先调工具 |
Linux 门禁才是验收数字:目标 fail 回到 31,总数 ≥ 3495。窗口 Agent 运行测试在 `skill-binding.test.ts`,依赖 live skill symlink,CI Linux 上应绿。
## 部署后欠
任务书验收:staging 真发一轮申报时段提问,`/api/health` SHA 对得上,回执里有 `run-jyotish-window-consultation` 的 completed 步。本机无登录态、无 Chrome,写在这里不写成通过。
+1 -1
View File
@@ -138,7 +138,7 @@
| `TASK-consult-three-channels-20260918.md` | `PROGRESS-consult-three-channels-20260918.md` | 咨询运行时三通道:进度 / 思考 / 正文生成时分离。设计分支误用 BUG-939/940/941,落地改号 942–944 | 验收未通过(见修复单) | `94c1e81f` |
| `TASK-consult-three-channels-fix-20260918.md` | `PROGRESS-consult-three-channels-fix-20260918.md` | 验收修复单:领域上限解耦(945)、31s 预算断言(946)、校正思考分片门(947)、Pass 4 按模式分流(948)、容量算术(949) | 已验收通过(Claude:tsc 0 / lint 0 error / npm test 3491 条 31 红且与基线 `742ffbc6` 同一组、原 12 条红全绿 / `/` 仍 Static / 首屏 js gzip 468,388 B 较基线 +0.02%);review 另出 BUG-950~953 见下一行 | `e32ce624` |
| `TASK-consult-pass4-streaming-20260918.md` | `PROGRESS-consult-pass4-streaming-20260918.md` | 验收 review 三轮:Pass 4 一 hold 正文就整段蹦出、逐字流式消失(BUG-950 产品拍板按句放行);无出生分钟模式整段被一句拒绝顶掉、一般知识句一起丢(951 改按句丢弃);该模式下日期不留痕(952);校正流 token 级 thinking 是死链,按 P2 删除并把测试翻转成否定合同(953)。基线 `1e553976` | 待验收 | `cd4775ae` |
| `TASK-window-consult-contract-20260918.md` | — | **P0 线上**:申报时段模式**自 2026-08-21 起每轮秒败**(69ms、0 token、模型从未被调用)。服务端日志实证根因:窗口 Agent attach 了 `jyotishSkillBinding()`,但 `windowJyotishInstructions` 从来不含方法块 marker,输入处理器直接 abort(BUG-954)。abort 与「模型没调工具」同码,是它藏四周的原因(955);另含合同未绿不得丢正文(956)、计算不该由模型触发(957,须等 954 上线后另轮)、窗口指令应期冲突(958)。基线 `9cdcf96b` | 待领取 | — |
| `TASK-window-consult-contract-20260918.md` | `PROGRESS-window-consult-contract-20260918.md` | **P0 线上**:申报时段模式**自 2026-08-21 起每轮秒败**(69ms、0 token、模型从未被调用)。服务端日志实证根因:窗口 Agent attach 了 `jyotishSkillBinding()`,但 `windowJyotishInstructions` 从来不含方法块 marker,输入处理器直接 abort(BUG-954)。abort 与「模型没调工具」同码,是它藏四周的原因(955);另含合同未绿不得丢正文(956)、计算不该由模型触发(957,须等 954 上线后另轮)、窗口指令应期冲突(958)。基线 `9cdcf96b` | 待验收 | `8e3e5c73` |
| `TASK-first-paint-dead-screen-fallback-20260917.md` | — | 真机:首页永远停在「正在载入账户」,兜底全在没跑起来的 bundle 里(BUG-936 investigating)。根 layout 加与 bundle 无关的内联兜底 + 去掉本仓正则后行断言 | 待领取 | — |
| `TASK-consultation-answer-start-anchor-20260917.md` | `PROGRESS-consultation-answer-start-anchor-20260917.md` | 主会话回答落在结尾:`useConversationScrollAnchor` 是贴底跟随,流式期间视口钉在最后一个字,回答开头滚出视口;改为发送后问题钉顶、回答向下长、长出视口显示「跳到最新」、末尾动态留白;产品追加拍板:校正面同一语义(推翻 BUG-041/048 贴底),本轮开头 = 用户行或新助手行。BUG 段 930 起 | 已验收(经修复单) | `worktree/green-harbor-5be3` |
| `TASK-consultation-answer-start-anchor-fix-20260917.md` | `PROGRESS-consultation-answer-start-anchor-fix-20260917.md` | 验收修复单:F1 头就是留白行时留白按整视口算(BUG-931);F2 留白只在钉住期间存在(BUG-932);前置:先修 e4e73f56 的两处 TS 错否则门禁不过 | 已验收 | `cc1a8980`(Claude 验收:tsc 0 / lint 0 error / npm test 3457 条 39 红与 11c0028d 逐条一致、新增 2 条绿 / `next build --webpack` 通过、`/` Static、首屏 gzip 591,242(较 09-16 基线 582,800 +1.45%,含会话列表单)/ Chrome 真实布局 S1–S6 全部通过,S6 新助手行距顶 16px 且增高不动,S5 不再写留白);真机六条欠 |