Files
Jyotisha/docs/tasks/TASK-window-consult-contract-20260918.md
T
Jesse_ChenandClaude Opus 5 e5b2ad14dd docs: BUG-954 根因由服务端日志定死——窗口 Agent 没绑方法块
日志:input-processor jyotish-skill-bound abort ×2,modelStepCount 0、
0 token、整轮 69ms,模型从未被调用。windowJyotishInstructions 从不含
BOUND_METHOD_MARKER,而 getWindowJyotishAgent 照样 attach 绑定,自
9958e00a(08-21)起申报时段每轮必败。abort 与「模型没调工具」同码,
是它藏四周的原因。初版任务书的「模型没调工具」立论已证伪并改写。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-18 07:50:31 +00:00

90 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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` = `<jyotish-skill name="jyotish-vedic-astrology">`,缺失即 `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`。