---
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:**

**First, check for multi-module queue:**

```javascript
const queuePath = '.ralph/modules-queue.json';
const hasQueue = fileExists(queuePath);

if (hasQueue) {
  const queue = readJSON(queuePath);
  const currentModule = queue.modules[queue.currentIndex];

  // Mark current module as completed
  currentModule.status = 'completed';
  queue.completedModules++;

  // Check if more modules remain
  const nextIndex = queue.currentIndex + 1;

  if (nextIndex < queue.totalModules) {
    // ADVANCE TO NEXT MODULE
    queue.currentIndex = nextIndex;
    queue.modules[nextIndex].status = 'in-progress';
    writeJSON(queuePath, queue);

    // Mark current prd.json as completed
    prd.status = 'completed';
    prd.updated_at = new Date().toISOString();
    writeJSON('.ralph/prd.json', prd);

    // Reset iteration counter for next module
    // (preserve max_iterations from config)

    console.log(`
╔══════════════════════════════════════════════════════════════════╗
║  ✅ MODULE COMPLETE: ${currentModule.code}                      ║
╠══════════════════════════════════════════════════════════════════╣
║  Tasks: ${tasksCompleted} completed, ${tasksSkipped} skipped    ║
║  Modules: ${queue.completedModules} / ${queue.totalModules}     ║
╠══════════════════════════════════════════════════════════════════╣
║  ADVANCING TO NEXT MODULE: ${queue.modules[nextIndex].code}     ║
╚══════════════════════════════════════════════════════════════════╝
    `);

    // Loop back to step-01 which will load next module's prd
    // -> Proceed to step-01-task.md
    return;
  }

  // ALL MODULES COMPLETE - fall through to completion below
  writeJSON(queuePath, queue);

  console.log(`
╔══════════════════════════════════════════════════════════════════╗
║  ✅ ALL MODULES COMPLETE                                        ║
╠══════════════════════════════════════════════════════════════════╣
║  Modules: ${queue.completedModules} / ${queue.totalModules}     ║
║  ${queue.modules.map(m => m.code + ": " + m.status).join("\n║  ")} ║
╚══════════════════════════════════════════════════════════════════╝
  `);
}
```

**Then output completion (single module or all modules done):**

```
╔══════════════════════════════════════════════════════════════════╗
║  ✅ 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    │ │ More modules│ │ No more     │ │ Dead-End /  │
   │ Report     │ │ in queue?   │ │ modules     │ │ Loop to     │
   │ step-05    │ │ → step-01   │ │ → Promise   │ │ step-01     │
   │ status:    │ │ (next mod)  │ │ → step-05   │ │             │
   │ "partial"  │ └─────────────┘ └─────────────┘ └─────────────┘
   └────────────┘
```

---

## 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 all tasks complete AND more modules in queue: `./step-01-task.md` (next module)
- If all tasks complete AND no more modules (or no queue): `./step-05-report.md`
- If max iterations or dead-end: `./step-05-report.md`
- If tasks remaining in current module: `./step-01-task.md`
