# State Schema

CCW Loop 的状态结构定义（统一版本）。

## 状态文件

**位置**: `.loop/{loopId}.json` (统一位置，API + Skill 共享)

**旧版本位置** (仅向后兼容): `.workflow/.loop/{session-id}/state.json`

## 结构定义

### 统一状态接口 (Unified Loop State)

```typescript
/**
 * Unified Loop State - API 和 Skill 共享的状态结构
 * API (loop-v2-routes.ts) 拥有状态的主控权
 * Skill (ccw-loop) 读取和更新此状态
 */
interface LoopState {
  // =====================================================
  // API FIELDS (from loop-v2-routes.ts)
  // 这些字段由 API 管理，Skill 只读
  // =====================================================

  loop_id: string                // Loop ID, e.g., "loop-v2-20260122-abc123"
  title: string                  // Loop 标题
  description: string            // Loop 描述
  max_iterations: number         // 最大迭代次数
  status: 'created' | 'running' | 'paused' | 'completed' | 'failed'
  current_iteration: number      // 当前迭代次数
  created_at: string             // 创建时间 (ISO8601)
  updated_at: string             // 最后更新时间 (ISO8601)
  completed_at?: string          // 完成时间 (ISO8601)
  failure_reason?: string        // 失败原因

  // =====================================================
  // SKILL EXTENSION FIELDS
  // 这些字段由 Skill 管理，API 只读
  // =====================================================

  skill_state?: {
    // 当前执行动作
    current_action: 'init' | 'develop' | 'debug' | 'validate' | 'complete' | null
    last_action: string | null
    completed_actions: string[]
    mode: 'interactive' | 'auto'

    // === 开发阶段 ===
    develop: {
      total: number
      completed: number
      current_task?: string
      tasks: DevelopTask[]
      last_progress_at: string | null
    }

    // === 调试阶段 ===
    debug: {
      active_bug?: string
      hypotheses_count: number
      hypotheses: Hypothesis[]
      confirmed_hypothesis: string | null
      iteration: number
      last_analysis_at: string | null
    }

    // === 验证阶段 ===
    validate: {
      pass_rate: number           // 测试通过率 (0-100)
      coverage: number            // 覆盖率 (0-100)
      test_results: TestResult[]
      passed: boolean
      failed_tests: string[]
      last_run_at: string | null
    }

    // === 错误追踪 ===
    errors: Array<{
      action: string
      message: string
      timestamp: string
    }>
  }
}

interface DevelopTask {
  id: string
  description: string
  tool: 'gemini' | 'qwen' | 'codex' | 'bash'
  mode: 'analysis' | 'write'
  status: 'pending' | 'in_progress' | 'completed' | 'failed'
  files_changed: string[]
  created_at: string
  completed_at: string | null
}

interface Hypothesis {
  id: string                    // H1, H2, ...
  description: string
  testable_condition: string
  logging_point: string
  evidence_criteria: {
    confirm: string
    reject: string
  }
  likelihood: number            // 1 = 最可能
  status: 'pending' | 'confirmed' | 'rejected' | 'inconclusive'
  evidence: Record<string, any> | null
  verdict_reason: string | null
}

interface TestResult {
  test_name: string
  suite: string
  status: 'passed' | 'failed' | 'skipped'
  duration_ms: number
  error_message: string | null
  stack_trace: string | null
}
```

## 初始状态

### 由 API 创建时 (Dashboard 触发)

```json
{
  "loop_id": "loop-v2-20260122-abc123",
  "title": "Implement user authentication",
  "description": "Add login/logout functionality",
  "max_iterations": 10,
  "status": "created",
  "current_iteration": 0,
  "created_at": "2026-01-22T10:00:00+08:00",
  "updated_at": "2026-01-22T10:00:00+08:00"
}
```

### 由 Skill 初始化后 (action-init)

```json
{
  "loop_id": "loop-v2-20260122-abc123",
  "title": "Implement user authentication",
  "description": "Add login/logout functionality",
  "max_iterations": 10,
  "status": "running",
  "current_iteration": 0,
  "created_at": "2026-01-22T10:00:00+08:00",
  "updated_at": "2026-01-22T10:00:05+08:00",

  "skill_state": {
    "current_action": "init",
    "last_action": null,
    "completed_actions": [],
    "mode": "auto",

    "develop": {
      "total": 3,
      "completed": 0,
      "current_task": null,
      "tasks": [
        { "id": "task-001", "description": "Create auth component", "status": "pending" }
      ],
      "last_progress_at": null
    },

    "debug": {
      "active_bug": null,
      "hypotheses_count": 0,
      "hypotheses": [],
      "confirmed_hypothesis": null,
      "iteration": 0,
      "last_analysis_at": null
    },

    "validate": {
      "pass_rate": 0,
      "coverage": 0,
      "test_results": [],
      "passed": false,
      "failed_tests": [],
      "last_run_at": null
    },

    "errors": []
  }
}
```

## 控制信号检查 (Control Signals)

Skill 在每个 Action 开始前必须检查控制信号：

```javascript
/**
 * 检查 API 控制信号
 * @returns { continue: boolean, action: 'pause_exit' | 'stop_exit' | 'continue' }
 */
function checkControlSignals(loopId) {
  const state = JSON.parse(Read(`.loop/${loopId}.json`))

  switch (state.status) {
    case 'paused':
      // API 暂停了循环，Skill 应退出等待 resume
      return { continue: false, action: 'pause_exit' }

    case 'failed':
      // API 停止了循环 (用户手动停止)
      return { continue: false, action: 'stop_exit' }

    case 'running':
      // 正常继续
      return { continue: true, action: 'continue' }

    default:
      // 异常状态
      return { continue: false, action: 'stop_exit' }
  }
}
```

### 在 Action 中使用

```markdown
## Execution

### Step 1: Check Control Signals

\`\`\`javascript
const control = checkControlSignals(loopId)
if (!control.continue) {
  // 输出退出原因
  console.log(`Loop ${control.action}: status = ${state.status}`)

  // 如果是 pause_exit，保存当前进度
  if (control.action === 'pause_exit') {
    updateSkillState(loopId, { current_action: 'paused' })
  }

  return  // 退出 Action
}
\`\`\`

### Step 2: Execute Action Logic
...
```

## 状态转换规则

### 1. 初始化 (action-init)

```javascript
// Skill 初始化后
{
  // API 字段更新
  status: 'created' → 'running',  // 或保持 'running' 如果 API 已设置
  updated_at: timestamp,

  // Skill 字段初始化
  skill_state: {
    current_action: 'init',
    mode: 'auto',
    develop: {
      tasks: [...parsed_tasks],
      total: N,
      completed: 0
    }
  }
}
```

### 2. 开发进行中 (action-develop-with-file)

```javascript
// 开发任务执行后
{
  updated_at: timestamp,
  current_iteration: state.current_iteration + 1,

  skill_state: {
    current_action: 'develop',
    last_action: 'action-develop-with-file',
    completed_actions: [...state.skill_state.completed_actions, 'action-develop-with-file'],
    develop: {
      current_task: 'task-xxx',
      completed: N+1,
      last_progress_at: timestamp
    }
  }
}
```

### 3. 调试进行中 (action-debug-with-file)

```javascript
// 调试执行后
{
  updated_at: timestamp,
  current_iteration: state.current_iteration + 1,

  skill_state: {
    current_action: 'debug',
    last_action: 'action-debug-with-file',
    debug: {
      active_bug: '...',
      hypotheses_count: N,
      hypotheses: [...new_hypotheses],
      iteration: N+1,
      last_analysis_at: timestamp
    }
  }
}
```

### 4. 验证完成 (action-validate-with-file)

```javascript
// 验证执行后
{
  updated_at: timestamp,
  current_iteration: state.current_iteration + 1,

  skill_state: {
    current_action: 'validate',
    last_action: 'action-validate-with-file',
    validate: {
      test_results: [...results],
      pass_rate: 95.5,
      coverage: 85.0,
      passed: true | false,
      failed_tests: ['test1', 'test2'],
      last_run_at: timestamp
    }
  }
}
```

### 5. 完成 (action-complete)

```javascript
// 循环完成后
{
  status: 'running' → 'completed',
  completed_at: timestamp,
  updated_at: timestamp,

  skill_state: {
    current_action: 'complete',
    last_action: 'action-complete'
  }
}
```

## 状态派生字段

以下字段可从状态计算得出，不需要存储：

```javascript
// 开发完成度
const developProgress = state.develop.total_count > 0
  ? (state.develop.completed_count / state.develop.total_count) * 100
  : 0

// 是否有待开发任务
const hasPendingDevelop = state.develop.tasks.some(t => t.status === 'pending')

// 调试是否完成
const debugCompleted = state.debug.confirmed_hypothesis !== null

// 验证是否通过
const validationPassed = state.validate.passed && state.validate.test_results.length > 0

// 整体进度
const overallProgress = (
  (developProgress * 0.5) +
  (debugCompleted ? 25 : 0) +
  (validationPassed ? 25 : 0)
)
```

## 文件同步

### 统一位置 (Unified Location)

状态与文件的对应关系：

| 状态字段 | 同步文件 | 同步时机 |
|----------|----------|----------|
| 整个 LoopState | `.loop/{loopId}.json` | 每次状态变更 (主文件) |
| `skill_state.develop` | `.loop/{loopId}.progress/develop.md` | 每次开发操作后 |
| `skill_state.debug` | `.loop/{loopId}.progress/debug.md` | 每次调试操作后 |
| `skill_state.validate` | `.loop/{loopId}.progress/validate.md` | 每次验证操作后 |
| 代码变更日志 | `.loop/{loopId}.progress/changes.log` | 每次文件修改 (NDJSON) |
| 调试日志 | `.loop/{loopId}.progress/debug.log` | 每次调试日志 (NDJSON) |

### 文件结构示例

```
.loop/
├── loop-v2-20260122-abc123.json         # 主状态文件 (API + Skill)
├── loop-v2-20260122-abc123.tasks.jsonl  # 任务列表 (API 管理)
└── loop-v2-20260122-abc123.progress/    # Skill 进度文件
    ├── develop.md                       # 开发进度
    ├── debug.md                         # 调试理解
    ├── validate.md                      # 验证报告
    ├── changes.log                      # 代码变更 (NDJSON)
    └── debug.log                        # 调试日志 (NDJSON)
```

## 状态恢复

如果主状态文件 `.loop/{loopId}.json` 损坏，可以从进度文件重建 skill_state:

```javascript
function rebuildSkillStateFromProgress(loopId) {
  const progressDir = `.loop/${loopId}.progress`

  // 尝试从进度文件解析状态
  const skill_state = {
    develop: parseProgressFile(`${progressDir}/develop.md`),
    debug: parseProgressFile(`${progressDir}/debug.md`),
    validate: parseProgressFile(`${progressDir}/validate.md`)
  }

  return skill_state
}

// 解析进度 Markdown 文件
function parseProgressFile(filePath) {
  const content = Read(filePath)
  if (!content) return null

  // 从 Markdown 表格和结构中提取数据
  // ... implementation
}
```

### 恢复策略

1. **API 字段**: 无法恢复 - 需要从 API 重新获取或用户手动输入
2. **skill_state 字段**: 可以从 `.progress/` 目录的 Markdown 文件解析
3. **任务列表**: 从 `.loop/{loopId}.tasks.jsonl` 恢复

## 状态验证

```javascript
function validateState(state) {
  const errors = []

  // 必需字段
  if (!state.session_id) errors.push('Missing session_id')
  if (!state.task_description) errors.push('Missing task_description')

  // 状态一致性
  if (state.initialized && state.status === 'pending') {
    errors.push('Inconsistent: initialized but status is pending')
  }

  if (state.status === 'completed' && !state.validate.passed) {
    errors.push('Inconsistent: completed but validation not passed')
  }

  // 开发任务一致性
  const completedTasks = state.develop.tasks.filter(t => t.status === 'completed').length
  if (completedTasks !== state.develop.completed_count) {
    errors.push('Inconsistent: completed_count mismatch')
  }

  return { valid: errors.length === 0, errors }
}
```
