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

7.5 KiB
Raw Blame History

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_windowtheme=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()

时间线:处理器 d04fc30b08-18)引入 → 窗口 Agent 9958e00a(08-21)新建时就带绑定、不带方法块 → 申报时段路线自 2026-08-21 起每轮必败,已持续约四周

为什么四周没人发现:abort() 被翻成与「模型没调工具」同一个公开码 runtime_contract_incomplete。BUG-922/923/937 处理的正是同名现象,本命线被救活后现象消失一半,窗口线这条根因从未被触及。

2. BUG-954P0)窗口 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-955P1)处理器 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-consultationinputSchema 只有 questionconsultation-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. 开工前置

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.md954 按证据转 resolved955~958 新增)+ CHANGELOG.md(申报时段咨询四周不可用属用户可感知),与代码同一批推 staging