# TASK · 申报时段咨询修复(2026-09-18 第四轮) > 基线:`origin/staging` @ `9cdcf96b`(已部署,健康检查一致)。 > 事故记录:`docs/BUG_HISTORY.md` BUG-954(根因已由服务端日志确认)。 > BUG 编号起点:开工时最大号为 **BUG-954**,本单占 **BUG-954 ~ BUG-958**。 > > **修订说明(2026-09-18 晚)**:本单初版按「模型没调工具」立论,服务端日志已证伪。根因是窗口 Agent 的系统提示里没有 skill 方法块,模型**从未被调用**。原 §3「服务端预跑」降级为 P2 结构性改进(BUG-957),不再是本单的 P0。 ## 0. 事故实证(服务端日志) staging 真实一轮(`consultationMode=declared_birth_window`、`theme=general`、问题「未来半年我事业如何?」、`history=[]`),`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) [agent-observability] toolCalls: [] modelStepCount: 0 inputTokens: 0 outputTokens: 0 run.total durationMs: 69 retryCount: 1 errorCode: runtime_contract_incomplete ``` **整轮 69 毫秒,模型一次都没被调用,0 token。** 公开事件里的 `skill.started/completed` 是绑定步骤自己报的,不代表方法块真的进了提示。 ## 1. 根因 | 位置 | 事实 | | --- | --- | | `skill-binding.ts:143-153` | `jyotishSkillBoundProcessor` 在输入处理阶段断言系统提示含 `BOUND_METHOD_MARKER` = ``,缺失即 `abort()` | | `index.ts:21` | `${jyotishSkillMethodBlock}` **只**插值进 `jyotishInstructions`(本命) | | `index.ts:176-190` | `windowJyotishInstructions` 从来没有这个块 | | `index.ts:198` | `getWindowJyotishAgent` 照样 `...jyotishSkillBinding()` | 时间线:处理器 `d04fc30b`(08-18)引入 → 窗口 Agent `9958e00a`(08-21)新建时就带绑定、不带方法块 → **申报时段路线自 2026-08-21 起每轮必败,已持续约四周**。 为什么四周没人发现:`abort()` 被翻成与「模型没调工具」同一个公开码 `runtime_contract_incomplete`。BUG-922/923/937 处理的正是同名现象,本命线被救活后现象消失一半,窗口线这条根因从未被触及。 ## 2. BUG-954(P0)窗口 Agent 必须绑定方法块 1. `windowJyotishInstructions` 注入带 marker 的方法块。**不能直接照抄 `jyotishSkillMethodBlock`**:它带本命 Level 2 报告骨架与「六步宫位 / Yoga 表 / 技法审计表」的输出要求,与窗口口径(无精确应期、只报稳定层、变动层列可能性)冲突。做法二选一,在进度记录里写明选了哪条: - (a) 抽出 `jyotishSkillMethodBlock` 的「方法主体 + marker」部分,报告骨架段落作为可选后缀,本命加、窗口不加; - (b) 窗口保留完整方法块,紧随其后用窗口口径逐条覆盖(明确写「以下窗口约束优先于上面方法块里的报告骨架与应期表述」)。 2. 验收标准: - 新增源码合同测试——**凡 attach `jyotishSkillBinding()` 的 Agent,其 `instructions` 必须包含 `BOUND_METHOD_MARKER`**(遍历 `index.ts` 里的 Agent 工厂,不是逐个手写断言); - 新增运行测试——构造窗口 Agent 的输入处理,`jyotishSkillBoundProcessor` 不 abort; - 部署后在 staging 真发一轮申报时段提问,`/api/health` SHA 对得上,回执里有 `run-jyotish-window-consultation` 的 completed 步。 ## 3. BUG-955(P1)处理器 abort 不得与「合同未完成」同码 `abort()` 目前落到与「模型没调工具」相同的公开码,是这条 bug 藏四周的直接原因。 1. 输入处理器 abort 走独立内部码(例如 `skill_binding_failed`),回执追加 `validation skill-binding-abort failed`,服务端打 `[consult-binding-error]` 日志(requestId + 内部码,不含提示词原文)。 2. 公开层可以继续用现有枚举,但**回执必须能一眼区分**「装配失败」与「模型没调工具」。 3. 参照 BUG-938 对供应商 error 块的同类处置。 4. 验收:假流两条——装配失败 / 模型没调工具,回执步骤名不同;`agent-observability` 两个码都能落日志。 ## 4. BUG-956(P1)合同未绿时不得静默丢弃模型正文 `stream-agent-response.ts` 现在在合同未绿时丢弃全部正文,用户只看到「未完成」。即便 BUG-954 落地,这条兜底仍要有: 1. 两次 attempt 后合同仍未绿、但模型产出过非空正文时,不再整轮失败;改为交付该正文并在回执追加 `validation contract-degraded failed`,同时在正文末尾附一句服务端确定性说明(文案对照 `frontend/docs/VOICE.md`,不得由模型生成)。 2. 模型既没调工具也没写字时,维持现有 `runtime_contract_incomplete`(不扣点)。 3. 验收标准:假流「无工具 + 有正文」→ 用户拿到正文 + 降级说明;假流「无工具 + 无正文」→ 仍是 `runtime_contract_incomplete`。 ## 5. BUG-957(P2)结构性改进:计算不该由模型触发 本单初版的主修法,现在降级为独立改进项,与 BUG-954 无因果关系,但值得单独做:`run-jyotish-window-consultation` 的 `inputSchema` 只有 `question`(`consultation-tools.ts:765-767`),出生数据完全服务端绑定——由模型决定调不调,对计算结果没有信息增益,只多一条失败路径(BUG-205/214/922/923/937 都在这条链上)。建议服务端在模型循环前预跑计算并记账,工具仍留在 Agent 上命中同请求缓存。**不要与 BUG-954 同轮做**:先让窗口路线活过来并在真实环境验证,再动运行时结构。 ## 6. BUG-958(P3)窗口指令里「必须调工具」与「不得给应期」的冲突要写清 `src/mastra/index.ts:178-190` 补一句显式口径:应期类问题**仍然要先调工具**,再用稳定层给方向性回答,并说明哪部分需要出生分钟;不得因为「精确应期不可用」而跳过计算或拒答整题。验收:`consultation-workflow-contract.test.ts` 加一条源码断言。 ## 7. 硬红线 1. `tsc --noEmit` 0 错、`npm run lint` 0 error、`npm test` 失败数不超过基线 `9cdcf96b` 实测的 31 条且清单逐条一致;测试总数不低于 3495。 2. 不得放宽 `contractReady()` 的「每请求一次真实计算」语义。BUG-954 是把方法块补进提示,不是绕过绑定校验;不得用「删掉 `jyotishSkillBinding()`」的方式让窗口路线通过。 3. 不得再写 `toolChoice: "required"` / named toolChoice。 4. 改既有断言写「原值 / 新值 / 原因」三栏。 ## 8. 开工前置 ```bash git fetch origin --prune git worktree add -b codex/window-consult-contract-20260918 \ .worktrees/window-consult-contract-20260918 origin/staging cd .worktrees/window-consult-contract-20260918/frontend npm test 2>&1 | grep -E "^# (tests|pass|fail)" # 开工基线:tests 3495 / pass 3449 / fail 31 ``` 让步顺序:**BUG-954 单独一轮先上**(四周不可用,越快越好,改动面是一段提示词 + 两条测试),955 同轮或紧随;956 次之;957 必须等 954 在真实环境验证通过后另开一轮;958 顺手。 收工:`docs/tasks/PROGRESS-window-consult-contract-20260918.md` + `docs/BUG_HISTORY.md`(954 按证据转 `resolved`,955~958 新增)+ `CHANGELOG.md`(申报时段咨询四周不可用属用户可感知),与代码同一批推 `staging`。