# TODO系统迁移方案：pm-agent → oc-collab

**方案编号**: PROPOSAL-MIGRATE-TODO-001  
**发起人**: agent3 (pm-agent产品经理)  
**日期**: 2026-02-23  
**状态**: 待评审

---

## 一、背景

根据提案 `PROPOSAL_pm_agent_unified_todo.md`，pm-agent 需要废弃自建 TODO 系统，统一使用 oc-collab 的 TODO。

**当前状态**：
- pm-agent 使用 JSON 文件存储 TODO：`state/TODO-*.json`
- oc-collab 已支持 agent3-9 (commit ce6b37f)
- 跨子系统发送 TODO 功能已可用

---

## 二、迁移目标

1. **统一存储**：所有 TODO 存储到 oc-collab 的 `state/todos.db`
2. **统一接口**：使用 `oc-collab todowrite` 创建 TODO
3. **平滑过渡**：保留历史 TODO 可查

---

## 三、当前 pm-agent TODOjson
{
  格式

``` "id": "TODO-DEV-2026-02-022",
  "title": "PM-Agent v2.0 开发任务",
  "from_agent": "agent3",
  "to_agent": "agent4",
  "type": "development",
  "priority": "high",
  "status": "pending",
  "created_at": "2026-02-22T14:00:00Z",
  "content": { ... },
  "action_required": "请根据设计文档开发v2.0功能",
  "deadline": "M2: 联调测试通过"
}
```

---

## 四、oc-collab todowrite 命令格式

```bash
oc-collab todowrite --content "<内容>" --to <agent_id> --priority <high|medium|low> --source <REQUIREMENT|BUG|FEEDBACK|MANUAL>
```

**参数说明**：
- `--content`: TODO 内容（必填）
- `--to`: 接收者 Agent ID（如 3, 4）
- `--priority`: 优先级（默认 medium）
- `--source`: 来源标签（默认 MANUAL）

---

## 五、迁移方案

### 5.1 创建 OcCollabClient 封装

在 `pm-agent/backend/services/oc_collab_client.py` 中添加：

```python
class OcCollabClient:
    """oc-collab 客户端封装"""
    
    def __init__(self):
        self.cli_path = "oc-collab"
    
    def create_todo(
        self,
        content: str,
        to_agent: str,
        priority: str = "medium",
        source: str = "PM-Agent",
        deadline: str = None
    ) -> dict:
        """
        创建 TODO
        
        Args:
            content: TODO 内容
            to_agent: 接收者 Agent ID (如 "4")
            priority: 优先级
            source: 来源
            deadline: 截止日期
        
        Returns:
            {"id": "TODO-xxx", "status": "created"}
        """
        import subprocess
        
        # 构建命令
        cmd = [
            self.cli_path, "todowrite",
            "--content", content,
            "--to", to_agent,
            "--priority", priority,
            "--source", source
        ]
        
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True
        )
        
        if result.returncode != 0:
            raise Exception(f"oc-collab todowrite failed: {result.stderr}")
        
        # 解析输出获取 TODO ID
        # 输出格式: "TODO created: TODO-2026-02-xxx"
        output = result.stdout
        # TODO: 解析 TODO ID
        
        return {"status": "created", "output": output}
```

### 5.2 修改 TODO 创建流程

**当前流程**（直接写 JSON）：
```python
# pm-agent/agent3 创建 TODO
todo_data = {...}
with open(f"state/TODO-{id}.json", "w") as f:
    json.dump(todo_data, f)
git add ... && git commit -m "agent3: 创建TODO"
```

**新流程**（调用 oc-collab）：
```python
# pm-agent/agent3 创建 TODO
oc_client = OcCollabClient()
result = oc_client.create_todo(
    content=todo_content,
    to_agent="4",  # agent4
    priority="high",
    source="PM-Agent"
)
print(f"TODO created: {result['id']}")
```

### 5.3 数据迁移脚本

```python
#!/usr/bin/env python3
"""迁移历史 TODO 到 oc-collab"""

import json
import glob
from backend.services.oc_collab_client import OcCollabClient

def migrate_todos():
    """迁移所有历史 TODO"""
    oc = OcCollabClient()
    
    # 读取所有 TODO JSON 文件
    for filepath in glob.glob("state/TODO-*.json"):
        with open(filepath) as f:
            todo = json.load(f)
        
        # 转换格式
        content = f"{todo.get('title', '')}\n{todo.get('action_required', '')}"
        to_agent = todo.get('to_agent', '').replace('agent', '')
        priority = todo.get('priority', 'medium')
        
        # 创建 TODO
        try:
            result = oc.create_todo(
                content=content,
                to_agent=to_agent,
                priority=priority,
                source="PM-Agent-Migration"
            )
            print(f"Migrated: {filepath} -> {result}")
        except Exception as e:
            print(f"Failed: {filepath} -> {e}")

if __name__ == "__main__":
    migrate_todos()
```

---

## 六、实施步骤

| 步骤 | 任务 | 负责人 | 工作量 |
|------|------|--------|--------|
| 1 | 创建 OcCollabClient 封装类 | agent4 | 0.5h |
| 2 | 替换 agent3 的 TODO 创建逻辑 | agent4 | 1h |
| 3 | 迁移历史 TODO 数据（可选） | agent3 | 0.5h |
| 4 | 更新文档（AGENTS.md） | agent3 | 0.5h |
| 5 | 测试验证 | agent3 | 0.5h |

**总计**: 3h

---

## 七、验证方法

```bash
# 1. 测试创建 TODO
cd pm-agent
oc-collab todowrite --content "测试迁移" --to 4 --priority high --source PM-Agent

# 2. 验证 TODO 已创建
oc-collab todo list --unread --agent 4

# 3. 验证 pm-agent 可以正常调用
python -c "
from backend.services.oc_collab_client import OcCollabClient
oc = OcCollabClient()
result = oc.create_todo('测试', '4', 'high', 'PM-Agent')
print(result)
"
```

---

## 八、测试控制（根据agent6评审补充）

### 8.1 测试用例清单

| 测试文件 | 测试内容 | 用例数 | 优先级 |
|----------|---------|--------|--------|
| `tests/test_oc_collab_client.py` | 客户端单元测试 | 10 | P0 |
| `tests/test_todo_migration.py` | 迁移脚本测试 | 5 | P1 |
| `tests/test_todo_integration.py` | 全流程集成测试 | 8 | P0 |

### 8.2 单元测试用例

```python
# tests/test_oc_collab_client.py

def test_create_todo_success():
    """测试正常创建TODO"""
    oc = OcCollabClient()
    result = oc.create_todo("测试内容", "4", "high", "PM-Agent")
    assert result["status"] == "created"
    assert "id" in result

def test_create_todo_invalid_agent():
    """测试无效Agent ID"""
    oc = OcCollabClient()
    with pytest.raises(Exception):
        oc.create_todo("测试", "invalid", "high", "PM-Agent")

def test_create_todo_priority_validation():
    """测试优先级校验"""
    oc = OcCollabClient()
    result = oc.create_todo("测试", "4", "high", "PM-Agent")
    assert result["status"] == "created"

def test_create_todo_missing_content():
    """测试缺失内容"""
    oc = OcCollabClient()
    with pytest.raises(Exception):
        oc.create_todo("", "4", "high", "PM-Agent")

def test_create_todo_cli_error():
    """测试CLI异常处理"""
    oc = OcCollabClient()
    oc.cli_path = "nonexistent-cli"
    with pytest.raises(Exception):
        oc.create_todo("测试", "4", "high", "PM-Agent")
```

### 8.3 集成测试用例

```python
# tests/test_todo_integration.py

def test_pm_agent_to_oc_collab_full_flow():
    """测试完整流程：agent3创建 -> oc-collab存储 -> agent4查询"""
    # 1. agent3创建TODO
    oc = OcCollabClient()
    result = oc.create_todo("测试任务", "4", "high", "PM-Agent")
    todo_id = result["id"]
    
    # 2. 验证oc-collab存储
    import subprocess
    output = subprocess.run(
        ["oc-collab", "todo", "list", "--unread", "--agent", "4", "--json"],
        capture_output=True, text=True
    )
    assert todo_id in output
    
def test_migration_idempotency():
    """测试迁移幂等性"""
    # 多次运行迁移脚本，结果应一致
    pass

def test_data_integrity_after_migration():
    """测试迁移后数据完整性"""
    pass
```

### 8.4 灰度发布方案

| 阶段 | 范围 | 验证内容 | 决策条件 |
|------|------|---------|---------|
| Stage 1 | 10%流量 | 监控错误率 | 错误率 < 1% |
| Stage 2 | 50%流量 | 性能指标 | 响应时间 < 500ms |
| Stage 3 | 100%流量 | 全面验证 | 全部通过 |

### 8.5 回滚操作

```bash
# 回滚步骤
1. 恢复 JSON 文件备份
   cp state/TODO-*.json.bak state/

2. 停止使用 OcCollabClient
   # 修改代码，恢复直接写JSON逻辑

3. 恢复旧代码
   git checkout HEAD~1 -- backend/services/oc_collab_client.py

4. 验证现有 TODO 可用
   python -c "from backend.services.oc_collab_client import OcCollabClient"
```

### 8.6 数据校验方案

```python
def verify_migration():
    """验证迁移数据一致性"""
    import sqlite3
    
    # 1. 统计oc-collab中的TODO数量
    conn = sqlite3.connect("../oc-collab/state/todos.db")
    cursor = conn.cursor()
    cursor.execute("SELECT COUNT(*) FROM todos WHERE source='PM-Agent'")
    oc_count = cursor.fetchone()[0]
    
    # 2. 统计JSON文件数量
    import glob
    json_count = len(glob.glob("state/TODO-*.json"))
    
    # 3. 校验
    assert oc_count == json_count, f"数据不一致: oc={oc_count}, json={json_count}"
    print(f"✅ 数据校验通过: {oc_count} 条")
```

---

## 九、风险与缓解

| 风险 | 缓解措施 |
|------|---------|
| oc-collab CLI 不可用 | 保留本地 JSON 作为 fallback |
| 网络问题 | 使用本地 SQLite |
| 迁移丢失数据 | 迁移前备份 JSON 文件 |
| 测试覆盖不足 | 补充单元测试、集成测试 |
| 回滚失败 | 完善回滚操作文档 |
| 数据不一致 | 增加数据校验脚本 |

---

## 十、受益

- ✅ 统一 TODO 管理，无需维护两套系统
- ✅ 跨系统 TODO 互通（pm-agent ↔ test-agent）
- ✅ 减少维护成本
- ✅ 符合统一架构
- ✅ 测试覆盖完整

---

## 十一、实施步骤（更新）

| 步骤 | 任务 | 负责人 | 工作量 |
|------|------|--------|--------|
| 1 | 创建 OcCollabClient 封装类 | agent4 | 0.5h |
| 2 | 编写单元测试用例 | agent4 | 1h |
| 3 | 替换 agent3 的 TODO 创建逻辑 | agent4 | 1h |
| 4 | 编写集成测试用例 | agent6 | 1h |
| 5 | 迁移历史 TODO 数据 | agent3 | 0.5h |
| 6 | 数据校验 | agent3 | 0.5h |
| 7 | 灰度发布验证 | agent4 | 0.5h |
| 8 | 更新文档（AGENTS.md） | agent3 | 0.5h |

**总计**: 5.5h

---

## 十二、决策

请评审确认：
- [ ] 是否同意此迁移方案
- [ ] 实施时间安排
- [ ] 是否有其他需要调整的地方
