# Steward Application Reimbursement State Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Build a persistent ontology-bound steward state for travel application and travel reimbursement flows.

**Architecture:** Keep the existing steward planning UI and assistant delegation flow. Add a backend state layer that stores `steward_state` in `AgentConversation.state_json`, merges LLM/rule output as patches, and rejects fields outside the ontology registry before downstream services consume them.

**Tech Stack:** FastAPI, SQLAlchemy JSON state, Pydantic schemas, pytest in Docker `x-financial-main:/app`, Vue/Vite frontend.

---

### Task 1: Backend State Contract

**Files:**
- Modify: `server/src/app/schemas/steward.py`
- Create: `server/src/app/services/steward_flow_state.py`
- Test: `server/tests/test_steward_flow_state.py`

- [ ] **Step 1: Write failing tests**

```python
def test_state_merge_keeps_application_and_reimbursement_flows():
    service = StewardFlowStateService()
    state = service.merge_state(
        {},
        StewardFlowStatePatch(
            active_flow="travel_application",
            flow_id="travel_application",
            intent="travel_application_create",
            fields={"expense_type": "travel", "location": "上海"},
        ),
    )
    state = service.merge_state(
        state,
        StewardFlowStatePatch(
            active_flow="travel_reimbursement",
            flow_id="travel_reimbursement",
            intent="travel_reimbursement_draft",
            fields={"amount": "708", "invoice_no": "NO-1"},
        ),
    )

    assert state["flows"]["travel_application"]["fields"]["location"] == "上海"
    assert state["flows"]["travel_reimbursement"]["fields"]["amount"] == "708"
```

```python
def test_state_merge_filters_non_ontology_fields():
    service = StewardFlowStateService()
    state = service.merge_state(
        {},
        StewardFlowStatePatch(
            active_flow="travel_application",
            flow_id="travel_application",
            intent="travel_application_create",
            fields={"location": "上海", "invented_field": "x"},
        ),
    )

    assert state["flows"]["travel_application"]["fields"] == {"location": "上海"}
```

- [ ] **Step 2: Run red tests**

Run:

```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_flow_state.py
```

Expected: fail because `steward_flow_state.py` does not exist.

- [ ] **Step 3: Implement minimal state service**

Create `StewardFlowStatePatch`, `StewardFlowStateService.merge_state`, ontology field filtering, and event append logic.

- [ ] **Step 4: Run green tests**

Run the same pytest command and expect pass.

### Task 2: Steward Plan Persistence

**Files:**
- Modify: `server/src/app/schemas/steward.py`
- Modify: `server/src/app/api/v1/endpoints/steward.py`
- Modify: `server/src/app/services/agent_conversations.py`
- Test: `server/tests/test_steward_planner.py`

- [ ] **Step 1: Write failing API/service test**

Add a test proving `/steward/plans` response contains `conversation_id` and `steward_state` when `context_json.session_type = steward`, and the state contains two flows when the input contains one application and one reimbursement task.

- [ ] **Step 2: Run red test**

Run:

```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
```

- [ ] **Step 3: Implement conversation state persistence**

Add `conversation_id` and `steward_state` fields to response schemas, persist state through `AgentConversationService`, and merge planner tasks into `steward_state`.

- [ ] **Step 4: Run green test**

Run the same pytest command and expect pass.

### Task 3: Runtime Decision Reads Persistent State

**Files:**
- Modify: `server/src/app/services/steward_runtime_decision_agent.py`
- Test: `server/tests/test_steward_runtime_decision_agent.py`

- [ ] **Step 1: Write failing test**

Add a test proving runtime decision uses `context_json.conversation_state.steward_state` when `runtime_state` is empty.

- [ ] **Step 2: Implement minimal fallback hydration**

Normalize runtime state by merging request runtime state with persisted steward state.

- [ ] **Step 3: Run green test**

Run:

```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_runtime_decision_agent.py
```

### Task 4: Frontend State Carry

**Files:**
- Modify: `web/src/views/scripts/stewardPlanModel.js`
- Modify: `web/src/views/scripts/TravelReimbursementCreateView.js`
- Modify: `web/src/views/scripts/useTravelReimbursementSessionState.js`

- [ ] **Step 1: Preserve steward state from backend responses**

Normalize `conversation_id` and `steward_state` from plan/runtime responses into the local session model.

- [ ] **Step 2: Send steward state in later requests**

Include the current `steward_state` under `context_json` for plan and runtime decision calls.

- [ ] **Step 3: Build frontend**

Run:

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

Expected: build succeeds.

### Task 5: Final Verification

- [ ] **Step 1: Run backend steward tests**

```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_flow_state.py server/tests/test_steward_planner.py server/tests/test_steward_runtime_decision_agent.py server/tests/test_steward_slot_decision_agent.py
```

- [ ] **Step 2: Run frontend build**

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

- [ ] **Step 3: Report workspace status**

Run:

```bash
git status --short
```
