# 多 task 串行推进时 task2(业务招待费报销)无法启动

## 修复记录

- 12:14：记录 bug 修复：多 task 串行推进时，task1（出差申请）做完后点击"继续处理费用报销"，task2（业务招待费报销）根本无法启动，报销草稿交互不起来，task2 语义（招待费/2000元/昨天）全部丢失。
  - Git 提交检查：`git fetch --all --prune` 因远端 SSL 连接失败未拉到新内容；`HEAD..@{u}` 为空（无 upstream 新提交）；`@{u}..HEAD` 本地领先 8 个提交，其中与本 bug 相关的前置提交为 `3a5664c4 feat(web): 多 task 串行推进`、`3e4b1e15 fix(web): 保存草稿/提交成功后也推进到下一个 task`、`43c3ff86 fix(web): steward plan 确认按钮直接拉起申请预览,不丢失 remaining tasks`。
  - 修改：
    - `web/src/composables/workbenchAiMode/useWorkbenchAiActionRouter.js`：`travel_reimbursement` 分支不再硬编码 `requiresApplicationBeforeReimbursement=true`，改为从 `steward_current_task.ontology_fields` 解析费用类型并调 `requiresApplicationBeforeReimbursement(expenseType)` 判断；用 `buildAiExpenseDraftPrefillValues` 把 task 语义（金额/时间/事由/地点）预填进报销草稿；透传 `steward_remaining_tasks`。`ai_application_start_inline` 分支也透传 `prefill_values` 和 `steward_remaining_tasks`，让"查不到申请单→发起申请单"后能回到 task2。`buildNextTaskSuggestedAction` payload 补 `steward_remaining_tasks: remainingTasks.slice(1)`，防 3+ task 断链。
    - `web/src/composables/workbenchAiMode/useWorkbenchAiExpenseFlow.js`：`startAiExpenseDraft` 扩展第 4 参 `options`（`prefillValues`/`stewardRemainingTasks`）；`resolveAiExpenseApplicationLink` 接收 options，查不到申请单时按费用类型动态生成"确认发起业务招待申请"按钮（不再写死"出差申请"），并透传 `prefill_values`/`steward_remaining_tasks`；新增 `attachStewardRemainingTasks`/`resolveStewardRemainingTasks`/`resolveRequiredApplicationLabel`/`buildExpenseDraftNextTaskAction` helper，把 remaining tasks 上下文挂在 draft 上贯穿报销→关联申请单→pollLinkedDraftJob 全流程；`advanceAiExpenseDraft`、`linkAiExpenseApplication`、`replaceInlineAssistantMessage`、`resumePendingLinkedReimbursementDraftJobs` 均补 remaining tasks 透传。
    - `web/src/composables/workbenchAiMode/useWorkbenchAiApplicationPreviewFlow.js`：`buildApplicationPreviewNextTaskAction` payload 补 `steward_remaining_tasks: remainingTasks.slice(1)`。
    - `web/src/utils/aiExpenseDraftModel.js`：`createAiExpenseDraft` 新增第三参 `prefillValues`，按已填值推进 `stepKey` 到第一个未填字段；新增 `buildAiExpenseDraftPrefillValues` 把 task ontology 映射到草稿字段。
    - `web/src/composables/workbenchAiMode/workbenchAiMessageModel.js`：`createInlineMessage`/`normalizeRuntimeMessage`/`serializeRuntimeMessage` 三处补 `stewardRemainingTasks` 字段读写，避免消息重建/刷新丢失推进上下文。
    - `web/src/utils/aiWorkbenchConversationStore.js`：`normalizeMessage` 持久化时保留 `stewardRemainingTasks`。
  - 操作：未提交（工作区有大量预先存在的未提交改动，未自动提交）。容器 `local-x-financial-linux` 此前未运行，已 `docker start` 恢复。
  - 验证：在容器内（node v22.22.3）跑 `node --test tests/ai-expense-draft-model.test.mjs tests/ai-workbench-conversation-store.test.mjs tests/workbench-ai-action-router.test.mjs`，16 个测试全部通过（含新增的 `buildAiExpenseDraftPrefillValues`、`createAiExpenseDraft` 预填、`stewardRemainingTasks` 持久化、`travel_reimbursement` 分支预填+透传 4 个用例）。其余前端测试失败为基线已存在（git stash 对比确认，与本次改动无关，多为正则匹配源码文本的断言因工作区其他未提交改动而失败）。
  - 影响：用户一次提问含"出差申请 + 招待费报销"等多 task 时，task1 完成后 task2 现在能正常启动：招待费类型、2000元金额、时间、事由会预填到报销草稿；招待费需要前置招待申请单（业务规则保留），查不到时按钮文案按类型动态展示并承接语义，发起申请单后能回到 task2；3+ task 不再断链；刷新会话后推进上下文不丢失。

- 12:23：继续修复同一 bug：模型计划已经返回“出差申请 + 业务招待费报销”两个 task 时，AI 工作台入口只消费第一个申请 task，第二个 task 没有自动开始。
  - Git 提交检查：`git fetch --all --prune` 仍因 `LibreSSL SSL_connect: SSL_ERROR_SYSCALL` 失败；`HEAD..@{u}` 为空，未发现可见 upstream 新提交；`@{u}..HEAD` 本地领先 8 个提交：`43c3ff86 fix(web): steward plan 确认按钮直接拉起申请预览,不丢失 remaining tasks`、`3e4b1e15 fix(web): 保存草稿/提交成功后也推进到下一个 task`、`3a5664c4 feat(web): 多 task 串行推进 - task1 完成后自动展示 task2 确认按钮`、`d139a63e refactor(server): 意图识别改 LLM 驱动,规则只做闲聊拦截+resume 兜底`、`8a2ae6eb fix(server): gate_classify 复用 _classify_irrelevant_input 修复 off_topic 误杀`、`992cf71f refactor(server): Phase 1 图拓扑重构 - LangGraph 成为唯一编排者`、`54356ba8 refactor(server): scene 注册表骨架 + 统一门控管道设计文档`、`e9d7c56d feat(server): 会话上下文保留（LLM 历史 + 确定性兜底双保险）`。
  - 修改：`workbenchAiIntentPlannerModel.js` 在归一化模型计划时保留 application task 后面的 `stewardRemainingTasks`，并只在存在剩余 task 时放进可执行申请请求；`usePersonalWorkbenchAiMode.js` 把 remaining tasks 传入申请预览，并在预览生成后通过现有 `steward_continue_next_task` 路由自动启动下一个 task；低置信确认按钮 payload 也继续携带队列；`useWorkbenchAiApplicationPreviewFlow.js` 在普通申请预览完成后调用 `onPreviewReadyForNextTask`；`useWorkbenchAiActionRouter.js` 的 `ai_application_confirm_intent` 分支同样透传 remaining tasks 并注册自动续跑回调。
  - 操作：新增回归测试覆盖“模型返回申请 task + 业务招待报销 task 时，前端可执行请求保留第二个 task”，以及“低置信确认按钮不丢队列并提供自动续跑回调”；保留既有未提交工作区改动，没有回滚或提交其他文件。
  - 验证：先看到新增测试红灯（`plan.stewardRemainingTasks` 为 `undefined`，确认按钮 options 也没有 remaining tasks），修复后 `node --test web/tests/workbench-ai-intent-planner-model.test.mjs web/tests/workbench-ai-action-router.test.mjs` 通过 24/24；`git diff --check` 通过；`docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-local-linux timeout 60s /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_planner.py -k 'future_travel_without_apply_word_as_application or uses_llm_for_multi_financial_demands'` 通过 2/2；同命令在 `local-x-financial-linux` 收集阶段因该容器缺 `langgraph` 失败，已改用当前映射 5173 的 `x-financial-local-linux` 验证；`npm --prefix web run build` 通过；真实 `http://localhost:5173/api/v1/steward/plans` 采样确认该用户句子返回 `expense_application` 与 `reimbursement` 两个 task。
  - 影响：用户输入“2月20-23日去上海出差3天，服务国网服务器部署，并且报销昨天的业务招待费2000元”时，前端不再在第一个申请预览处截断队列；申请预览生成后会自动把第二个业务招待费报销 task 交给现有报销流程继续处理，同时刷新/低置信确认路径也不丢 task 队列。

- 22:30：继续修复同一 bug：用户点击“保存草稿”后，task1 已经完成，但界面仍只展示“继续处理费用报销”按钮，没有自动开始 task2。
  - Git 提交检查：`git fetch --all --prune` 仍因 `LibreSSL SSL_connect: SSL_ERROR_SYSCALL` 失败；`HEAD..@{u}` 为空，未发现可见 upstream 新提交；`@{u}..HEAD` 本地仍领先 8 个提交：`43c3ff86`、`3e4b1e15`、`3a5664c4`、`d139a63e`、`8a2ae6eb`、`992cf71f`、`54356ba8`、`e9d7c56d`。
  - 修改：`useWorkbenchAiApplicationPreviewFlow.js` 在保存草稿/提交申请成功后，如果当前申请消息还有 `stewardRemainingTasks`，就调用 `onApplicationActionCompleted` 自动续跑下一项；自动续跑时结果消息只保留查看详情动作，不再额外保留“继续处理”按钮，避免重复触发同一个 task。`usePersonalWorkbenchAiMode.js` 将该回调接到 `startModelPlannedNextTask`；`useWorkbenchAiActionRouter.js` 的低置信确认路径也同步传入保存/提交成功回调。
  - 操作：先补红灯断言，要求工作台入口向申请预览流传 `onApplicationActionCompleted`，且申请预览流在保存/提交成功分支调用该回调；然后按同一条 `steward_continue_next_task` 路由复用原有报销启动逻辑。
  - 验证：红灯阶段 `node --test web/tests/workbench-ai-intent-planner-model.test.mjs` 失败在缺少 `onApplicationActionCompleted`；修复后 `node --test web/tests/workbench-ai-intent-planner-model.test.mjs` 17/17 通过，`node --test web/tests/workbench-ai-action-router.test.mjs` 7/7 通过；`git diff --check` 通过；`npm --prefix web run build` 通过。
  - 影响：复合任务里用户保存第一张出差申请草稿后，系统会立即进入第二个业务招待费报销任务，不再要求用户手动点击“继续处理费用报销”；低置信确认后再保存草稿也保持同样行为。

- 22:45：继续修复同一 bug：真实页面已经显示“申请草稿已保存”，但保存动作结束后没有继续拉起第二个业务招待费报销 task。
  - Git 提交检查：`git fetch --all --prune` 仍因 `LibreSSL SSL_connect: SSL_ERROR_SYSCALL` 失败；`HEAD..@{u}` 为空，未发现可见 upstream 新提交；`@{u}..HEAD` 本地领先 13 个提交：`6bdaeed6 chore: 忽略 .zcode 本地目录并更新规则表与开发日志`、`d5a8f847 refactor(web): 应用外壳/差旅详情/报销创建视图适配主题与多 task`、`c4b5fcc0 feat(web): AI 工作台多 task 串行推进与会话适配`、`5753899e feat(web): 主题皮肤系统与 LLM 设置面板重构`、`9c3fa80d feat(server): 设置持久化新增 LLM 模型表与主题字段`，以及前面记录过的 8 个本地 ahead 提交。
  - 修改：`useWorkbenchAiApplicationPreviewFlow.js` 在保存草稿/提交申请成功分支新增 `actionCompletedHandler`，优先使用本次 `executeInlineApplicationPreviewAction` / `startAiApplicationPreview` options 传入的 `onApplicationActionCompleted`，没有时再回落到 composable 初始化回调；自动保存草稿时同步把 `options.onApplicationActionCompleted` 透传给保存动作。`workbench-ai-application-context-submit.test.mjs` 新增“自动保存申请草稿后继续剩余 steward task”的行为测试；`workbench-ai-intent-planner-model.test.mjs` 更新结构断言，锁住 options 回调优先和自动保存透传契约。
  - 操作：先用新增测试复现红灯：自动保存时确实只触发初始化回调，`options` 里的续跑回调没有被使用；再做最小修复，让保存动作按本次调用上下文续跑下一任务。
  - 验证：红灯阶段 `node --test web/tests/workbench-ai-application-context-submit.test.mjs` 失败在 `fromOptions` 为 `undefined`；修复后该测试 2/2 通过；`node --test web/tests/workbench-ai-intent-planner-model.test.mjs` 17/17 通过；`node --test web/tests/workbench-ai-action-router.test.mjs` 7/7 通过；真实 `http://127.0.0.1:5173/api/v1/steward/plans` 采样确认该用户句子仍返回 `expense_application` + `reimbursement` 两个 task；`npm --prefix web run build` 通过；`git diff --check` 通过。
  - 影响：保存草稿结果消息到达后，前端会使用当前任务链路传下来的续跑回调立即处理剩余 task；用户截图里的“申请草稿已保存”不再是终点，后续业务招待费报销会自动进入现有报销流程。
