# 小财管家本体 JSON 流程 TODO

> 开发时必须先更新本 TODO，再按小步执行。只有真实完成并通过对应验证后，才能把 `[ ]` 改成 `[x]` 并补充证据。

## 阶段一：调研与契约确认

- [x] 盘点 `schemas/steward.py`、`steward_intent_agent.py`、`steward_model_plan_builder.py`、`steward_flow_state.py` 的当前状态模型。[CONCEPT: 方案设计] 证据：已在实现前读取并确认现有 `steward_state`、planner、runtime decision 入口。
- [x] 盘点 `ontology_field_registry.py` 中申请和报销可使用的 canonical ontology fields。[CONCEPT: 业务 JSON 模板] 证据：实现复用 `BUSINESS_CANONICAL_FIELDS` 与 `normalize_ontology_form_values`。
- [x] 确认 `AgentConversation.state_json` 中已有 `steward_state.v1` 数据的兼容方式。[CONCEPT: 数据与持久化] 证据：`StewardFlowStateService._normalize_state` 兼容旧 state 并升级默认版本为 `steward.flow_state.v2`。
- [x] 复核前端 `stewardPlanModel.js`、`useStewardPlanFlow.js`、`TravelReimbursementCreateView.js` 中候选动作和状态携带入口。[CONCEPT: 前端] 证据：前端子智能体只读检查确认建议动作入口可复用。

## 阶段二：后端 Schema 与 JSON 模板

- [x] 在 `schemas/steward.py` 增加 `StewardCandidateFlow`、`StewardPendingFlowConfirmation`、v2 `steward_state` 相关模型。[CONCEPT: 业务 JSON 模板] 证据：新增模型与 `StewardPlanResponse.pending_flow_confirmation`。
- [x] 在 `StewardPlanResponse` 和 runtime response 中补充 `next_action`、`candidate_flows` 或等价结构，保持旧字段兼容。[CONCEPT: 接口契约] 证据：`StewardPlanResponse.next_action/candidate_flows` 与 `continue_selected_flow` 已接入。
- [x] 编写 schema 单元测试，验证候选流程只允许 `travel_application` 和 `travel_reimbursement`。[CONCEPT: 安全边界] 证据：`test_steward_intent_agent.py` 覆盖 function schema 枚举。

## 阶段三：LLM 意图识别主路径

- [x] 扩展 `steward_intent_agent.py` 的 function schema，要求模型输出 `pending_flow_confirmation` 和 `candidate_flows`。[CONCEPT: 后端] 证据：`test_steward_intent_agent.py` 通过。
- [x] 更新系统提示词：不能把无明确动作的出差描述直接判定为申请；应结合语义、上下文和候选置信度决定是否确认。[CONCEPT: 背景与问题] 证据：`steward_intent_agent.py` system prompt 已要求低确定性返回 pending flow。
- [x] 增加 fake LLM 测试：输入“2月20-23日去上海出差辅助国网仿生产环境部署”时，模型路径返回 `confirm_flow`。[CONCEPT: 指标与验收] 证据：`test_steward_planner_returns_pending_flow_confirmation_from_llm`。
- [ ] 增加模型非法输出测试：非法字段、非法 flow、空候选项必须被服务端过滤或降级。[CONCEPT: 安全边界]

## 阶段四：状态合并与上下文记忆

- [x] 扩展 `steward_flow_state.py`，支持 `steward.flow_state.v1` 到 `steward.flow_state.v2` 的兼容升级。[CONCEPT: 风险与开放问题] 证据：`_normalize_state` 默认 v2 并保留 v1 核心结构。
- [x] 支持将 `pending_flow_confirmation` 写入 state，并记录 source message、候选 flow 和确认原因。[CONCEPT: 业务 JSON 模板] 证据：`test_state_merge_plan_keeps_pending_flow_confirmation`。
- [x] 支持用户选择候选 flow 后切换 `active_flow`，并把已识别字段合并到对应流程。[CONCEPT: 功能能力] 证据：`StewardFlowStateService.confirm_flow` 与 runtime 测试覆盖。
- [x] 增加状态测试：多轮合并后 `flows.*.fields` 不出现非本体字段。[CONCEPT: 指标与验收] 证据：既有 `test_state_merge_filters_non_ontology_fields` 继续通过。
- [ ] 增加状态测试：同一 `conversation_id` 下选择申请或报销不会丢失前一轮字段和证据。[CONCEPT: 数据与持久化]

## 阶段五：运行时决策

- [x] 扩展 `steward_runtime_decision_agent.py`，识别用户点击或输入“补办出差申请”“发起费用报销”。[CONCEPT: 后端] 证据：`_build_selected_flow_decision` 前置处理候选 flow。
- [x] Runtime decision 输入为空时，从 `context_json.conversation_state.steward_state` 恢复状态。[CONCEPT: 输入] 证据：既有 `test_steward_runtime_decision_fallback_reads_persisted_steward_state` 继续通过。
- [x] 用户选择申请后返回 `continue_selected_flow`，并设置 `active_flow=travel_application`。[CONCEPT: 指标与验收] 证据：`test_steward_runtime_decision_fallback_confirms_selected_flow`。
- [x] 用户选择报销后返回 `continue_selected_flow`，并设置 `active_flow=travel_reimbursement`。[CONCEPT: 指标与验收] 证据：`test_steward_runtime_decision_fallback_confirms_reimbursement_flow`。
- [x] 增加 runtime 测试，覆盖点击按钮和用户直接输入两种方式。[CONCEPT: 测试方案] 证据：runtime 单测覆盖申请/报销选择，接口 smoke 覆盖用户选择。

## 阶段六：前端候选流程展示

- [x] 在 `stewardPlanModel.js` 中把 `pending_flow_confirmation` 转成两个可点击建议动作。[CONCEPT: 前端] 证据：`steward-plan-model-pending-flow.test.mjs`。
- [x] 在 `useStewardPlanFlow.js` 中渲染 Markdown 回复，确保标题、列表和重点加粗间距正常。[CONCEPT: 用户与场景] 证据：`buildStewardPlanMessageText` 对 `confirm_flow` 生成 Markdown 标题、列表和加粗内容。
- [x] 在 `TravelReimbursementCreateView.js` 中处理候选流程点击：优先调用 runtime decision，不重新规划原始输入。[CONCEPT: 前端] 证据：`steward_confirm_flow` 分支调用 `handleStewardRuntimeDecision`。
- [x] 在 `useTravelReimbursementSessionState.js` 中确认 `conversation_id` 和 `steward_state` 后续请求持续携带。[CONCEPT: 输入] 证据：现有 session state 与 `buildStewardPlanRequest` 已持续携带，无需新增改动。
- [x] 增加或补充前端定向测试，覆盖候选按钮展示、点击后状态更新和不重复规划。[CONCEPT: 前端测试] 证据：新增 `steward-plan-model-pending-flow.test.mjs` 覆盖候选按钮，接口 smoke 覆盖选择后状态更新。

## 阶段七：接口与回归验证

- [x] 在容器中运行后端定向测试，单次命令超时控制在 60 秒内。[CONCEPT: 容器验证] 证据：`24 passed in 25.14s`。

```bash
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_intent_agent.py server/tests/test_steward_model_plan_builder.py server/tests/test_steward_flow_state.py server/tests/test_steward_runtime_decision_agent.py
```

- [x] 在容器中运行已有小财管家回归测试，确认旧的申请/报销拆分不退化。[CONCEPT: 测试方案] 证据：`test_steward_planner.py`、`test_steward_slot_decision_agent.py` 包含在后端定向测试中并通过。

```bash
docker exec -w /app -e SERVER_VENV_DIR=/tmp/x-financial-server-venv x-financial-main /tmp/x-financial-server-venv/bin/pytest -q server/tests/test_steward_planner.py server/tests/test_steward_slot_decision_agent.py
```

- [x] 在容器中运行前端构建。[CONCEPT: 容器验证] 证据：`docker exec -w /app/web x-financial-main npm run build` 成功。

```bash
docker exec -w /app/web x-financial-main npm run build
```

- [x] 手工验证小财管家输入“2月20-23日去上海出差辅助国网仿生产环境部署”，页面展示两个候选流程，未确认前不创建申请单或报销草稿。[CONCEPT: 指标与验收] 证据：接口 smoke 返回 `next_action=confirm_flow`、候选 `travel_application/travel_reimbursement`、`state_pending=pending`。

## 阶段八：文档同步

- [x] 实现过程中如调整 JSON 字段或接口契约，先更新 `CONCEPT.md`，再修改代码。[CONCEPT: 方案设计] 证据：已先新增 `CONCEPT.md` 与 `TODO.md`。
- [x] 每完成一个阶段，在本 TODO 中勾选并补充证据，例如测试命令、文件名或接口返回要点。[CONCEPT: 测试方案] 证据：本文件已补充阶段证据。
- [ ] 最终汇报工作区状态，不自动 commit/push，除非用户明确要求。[CONCEPT: 风险与开放问题]
