---
name: step-04-check
description: Check completion criteria with status-based logic
next_step: steps/step-05-report.md OR steps/step-01-task.md
---

# Step 4: Check Completion

## YOUR TASK:

Check if all tasks are complete and decide whether to output completion promise or continue to next task.

---

## EXECUTION SEQUENCE:

### 1. Read Current State

**Load prd.json:**

```javascript
const prd = readJSON('.ralph/prd.json');

const tasksCompleted = prd.tasks.filter(t => t.status === 'completed').length;
const tasksSkipped   = prd.tasks.filter(t => t.status === 'skipped').length;
const tasksFailed    = prd.tasks.filter(t => t.status === 'failed').length;
const tasksBlocked   = prd.tasks.filter(t => t.status === 'blocked').length;
const tasksPending   = prd.tasks.filter(t => t.status === 'pending').length;
const tasksTotal     = prd.tasks.length;

const allDone      = (tasksCompleted + tasksSkipped) === tasksTotal;
const hasFailures  = tasksFailed > 0;
const hasBlocked   = tasksBlocked > 0;
const hasPending   = tasksPending > 0;
```

### 2. Check Iteration Limit

**If `prd.config.current_iteration` > `prd.config.max_iterations`:**

```
╔══════════════════════════════════════════════════════════════════╗
║  ⚠️ MAX ITERATIONS REACHED                                     ║
╠══════════════════════════════════════════════════════════════════╣
║  Iterations: {current_iteration} / {max_iterations}             ║
║  Tasks: {tasksCompleted} / {tasksTotal} complete                ║
║  Failed: {tasksFailed}  |  Blocked: {tasksBlocked}             ║
╠══════════════════════════════════════════════════════════════════╣
║  Ralph loop stopped due to iteration limit.                     ║
║  Remaining tasks:                                                ║
║  {list of tasks with status != completed and != skipped}        ║
╚══════════════════════════════════════════════════════════════════╝

-> Generating partial report...
```

**Update prd.json:**
```javascript
prd.status = 'partial';
prd.updated_at = new Date().toISOString();
writeJSON('.ralph/prd.json', prd);
```

**Proceed to step-05-report.md**

### 3. Check All Tasks Complete

**If allDone = true:**

```
╔══════════════════════════════════════════════════════════════════╗
║  ✅ ALL TASKS COMPLETE                                          ║
╠══════════════════════════════════════════════════════════════════╣
║  Iterations: {current_iteration - 1}                            ║
║  Tasks: {tasksCompleted} completed, {tasksSkipped} skipped      ║
╠══════════════════════════════════════════════════════════════════╣
║  Output completion promise:                                      ║
║  <promise>{completion_promise}</promise>                         ║
╚══════════════════════════════════════════════════════════════════╝

<promise>{completion_promise}</promise>
```

**Update prd.json:**
```javascript
prd.status = 'completed';
prd.updated_at = new Date().toISOString();
writeJSON('.ralph/prd.json', prd);
```

**CRITICAL: Output the promise tag exactly as shown:**
```
<promise>{completion_promise}</promise>
```

**Proceed to step-05-report.md**

### 4. Check for Dead-End (all remaining are blocked/failed)

**If !hasPending AND !allDone:**

All remaining tasks are blocked or failed. No progress is possible.

```
╔══════════════════════════════════════════════════════════════════╗
║  ⚠️ DEAD-END DETECTED                                          ║
╠══════════════════════════════════════════════════════════════════╣
║  Tasks: {tasksCompleted} completed, {tasksFailed} failed,       ║
║         {tasksBlocked} blocked                                   ║
╠══════════════════════════════════════════════════════════════════╣
║  No more tasks can be executed.                                  ║
║  Failed tasks:                                                   ║
║  {list of failed tasks with error messages}                     ║
║                                                                  ║
║  Blocked tasks (downstream):                                     ║
║  {list of blocked tasks with dependency info}                   ║
╚══════════════════════════════════════════════════════════════════╝

-> Generating partial report...
```

**Update prd.json:**
```javascript
prd.status = 'failed';
prd.updated_at = new Date().toISOString();
writeJSON('.ralph/prd.json', prd);
```

**Proceed to step-05-report.md**

### 5. More Tasks Remaining

**If hasPending AND iteration < max_iterations:**

```
Progress: {tasksCompleted} / {tasksTotal} tasks
Failed: {tasksFailed}  |  Blocked: {tasksBlocked}  |  Pending: {tasksPending}

Next eligible task will be determined by dependency resolution.

Continuing to next iteration...
```

**Loop back to step-01-task.md**

---

## DECISION TREE:

```
                    ┌─────────────────────┐
                    │  Check Completion   │
                    └──────────┬──────────┘
                               │
          ┌────────────────────┼────────────────────┐
          │                    │                    │
          ▼                    ▼                    ▼
   ┌──────────────┐   ┌──────────────┐   ┌──────────────┐
   │ Max Iters    │   │ All Tasks    │   │ Tasks        │
   │ Reached      │   │ Done         │   │ Remaining    │
   └──────┬───────┘   └──────┬───────┘   └──────┬───────┘
          │                  │                   │
          │                  │          ┌────────┴────────┐
          │                  │          │                 │
          ▼                  ▼          ▼                 ▼
   ┌──────────────┐   ┌──────────────┐ ┌─────────────┐ ┌─────────────┐
   │ Partial      │   │ Output       │ │ Dead-End    │ │ Loop to     │
   │ Report       │   │ Promise      │ │ (all blocked│ │ step-01     │
   │ step-05      │   │ step-05      │ │ or failed)  │ │             │
   │ status:      │   │ status:      │ │ step-05     │ │             │
   │ "partial"    │   │ "completed"  │ │ status:     │ │             │
   └──────────────┘   └──────────────┘ │ "failed"    │ └─────────────┘
                                       └─────────────┘
```

---

## OUTPUT FORMAT:

**If continuing:**
```
Completion Check:

| Field | Value |
|-------|-------|
| Iteration | {current_iteration} / {max_iterations} |
| Completed | {tasksCompleted} / {tasksTotal} |
| Failed | {tasksFailed} |
| Blocked | {tasksBlocked} |
| Pending | {tasksPending} |
| Status | Continuing |

-> Loading next task...
```

**If complete:**
```
Completion Check:

| Field | Value |
|-------|-------|
| Iterations Used | {current_iteration - 1} |
| Completed | {tasksCompleted} / {tasksTotal} |
| Skipped | {tasksSkipped} |
| Status | COMPLETE |

<promise>{completion_promise}</promise>

-> Generating report...
```

**If partial/failed:**
```
Completion Check:

| Field | Value |
|-------|-------|
| Iterations Used | {current_iteration - 1} |
| Completed | {tasksCompleted} / {tasksTotal} |
| Failed | {tasksFailed} |
| Blocked | {tasksBlocked} |
| Status | {PARTIAL or FAILED} |
| Reason | {max iterations / dead-end} |

-> Generating report...
```

---

## CRITICAL RULES:

**NEVER output the completion promise unless:**
1. ALL tasks have `status: "completed"` or `status: "skipped"`
2. Zero tasks with `status: "blocked"` or `status: "failed"`
3. The statement is genuinely true

**False promises to escape the loop are FORBIDDEN.**

**Always update `prd.status` and `prd.updated_at` before proceeding.**

---

## NEXT STEP:

- If complete or max iterations or dead-end: `./step-05-report.md`
- If tasks remaining: `./step-01-task.md`
