# Compact Loop — Inline Execution

> **Loaded by:** step-04 section 5 (after first full iteration)
> **Purpose:** Execute all subsequent iterations inline without re-reading step files.
> **Rule:** NEVER stop the loop. NEVER wait for user input. NEVER re-read step files.

---

## Loop Entry

Display compact progress:
```
[{iteration}/{max}] {completed}/{total} done | Finding eligible tasks...
```

---

## A. Find Eligible Tasks

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

// Block tasks whose dependencies failed
for (const task of prd.tasks) {
  if (task.status !== 'pending') continue;
  const depsBlocked = task.dependencies.some(depId => {
    const dep = prd.tasks.find(t => t.id === depId);
    return dep && (dep.status === 'failed' || dep.status === 'blocked');
  });
  if (depsBlocked) { task.status = 'blocked'; task.error = 'Blocked by failed dependency'; }
}

// Find ALL eligible tasks (dependencies met)
const eligible = prd.tasks.filter(task => {
  if (task.status !== 'pending') return false;
  return task.dependencies.every(depId => {
    const dep = prd.tasks.find(t => t.id === depId);
    return dep && dep.status === 'completed';
  });
});

if (eligible.length === 0) {
  // Dead-end or all done — return to step-04 sections 2-4
  goto CHECK_COMPLETION;
}

// BATCH: group by category, take first group (max 5)
const firstCategory = eligible[0].category;
const batch = eligible.filter(t => t.category === firstCategory).slice(0, 5);
```

Display:
```
Batch: {batch.length} [{firstCategory}] → {batch.map(t => `[${t.id}] ${t.description.substring(0, 60)}`).join(' | ')}
```

---

## B. Execute Batch

**For EACH task in batch:**

1. Mark `task.status = 'in_progress'`, `task.started_at = now`
2. **Read `references/category-rules.md`** for category-specific rules
3. Implement the task following SmartStack conventions
4. Track `files_created` and `files_modified`

**Execution cycle per task:**
1. Generate code following category-rules.md
2. **BUILD verification (BLOCKING per task):**
   - Backend (domain/infra/app/api): `dotnet build --no-restore` → MUST exit 0
   - Frontend: `npm run typecheck` → MUST exit 0
3. If build fails → **CLASSIFY ERROR FIRST** (read `references/error-classification.md`):
   - **Category A/B (assembly/package):** Run `dotnet add package {Name}` → `dotnet restore` → rebuild. Do NOT edit source code.
   - **Category C (DI):** Edit DI registration file only → rebuild.
   - **Category D (migration):** Run migration commands → rebuild.
   - **Category E (config):** Edit config file → rebuild.
   - **Category F (code):** Fix source code → rebuild → loop until pass.
   - **If 2+ rebuild attempts fail on same error and Category F was chosen:** Re-classify — likely wrong category.
4. **ARTIFACT verification (BLOCKING per task):**
   - `files_created` MUST NOT be empty for code-generating tasks
   - Category-specific checks (see below)
   - IF no artifacts produced → task.status = 'failed', task.error = 'No artifacts created'
5. Verify acceptance criteria from task description
6. If failed after 3 attempts: `task.status = 'failed'`, `task.error = reason`, continue to next in batch

**Category-specific artifact checks (step 4 above):**

| Category | Artifact Check | FAIL if |
|----------|---------------|---------|
| `domain` | Entity .cs files exist in Domain/ | 0 files created |
| `infrastructure` with migration | `Migrations/` folder has .cs files | No migration files |
| `infrastructure` with seed data | Seed data .cs files exist | 0 files created |
| `application` | Service + DTO + Validator files exist | 0 files created |
| `api` | Controller .cs files exist | 0 files created |
| `frontend` | .tsx page files exist | 0 files created |
| `test` | Test project dir exists AND contains test .cs files | No test project or 0 test files |
| `validation` | `dotnet test` exit 0 AND `dotnet build` exit 0 | Either command fails |

**Category-specific triggers:**

| Category | Action |
|----------|--------|
| `infrastructure` with `_migrationMeta` | Migration sequence: `suggest_migration` MCP → `dotnet ef migrations add` → `dotnet ef database update` → `dotnet build` |
| `infrastructure` with seed data keywords | **MANDATORY:** Read `references/core-seed-data.md` → implement templates → `dotnet build` |
| `frontend` | MCP-first: `scaffold_api_client` → `scaffold_routes` (outputFormat: clientRoutes) → **wire to App.tsx (standard + tenant blocks)** → create pages → `npm run typecheck && npm run lint` |
| `test` | **Create tests:** `scaffold_tests` MCP → **Run:** `dotnet test --verbosity normal` → **Fix loop:** if fail → fix SOURCE CODE → rebuild → retest → repeat until 100% pass |
| `validation` | `dotnet clean && dotnet restore && dotnet build` → `dotnet test` (full) → `validate_conventions` MCP |

**Post-batch verification (BLOCKING — ALL must pass before commit):**

1. **Backend build:**
   ```bash
   dotnet build --no-restore
   ```
   If FAIL → fix → rebuild → DO NOT commit until exit 0

2. **Tests (if test tasks in batch OR after infrastructure batch):**
   ```bash
   TEST_PROJECT="tests/$(basename $(pwd)).Tests.Unit"
   dotnet test "$TEST_PROJECT" --no-build --verbosity normal
   ```
   If FAIL → fix source code (NOT tests) → rebuild → retest → loop until 100% pass

2bis. **Runtime assembly check (if api/validation tasks in batch):**
   ```bash
   API_PROJECT=$(ls src/*Api*/*.csproj 2>/dev/null | head -1)
   if [ -n "$API_PROJECT" ]; then
     dotnet run --project "$API_PROJECT" --urls "http://localhost:5098" > /tmp/ralph-startup-check.log 2>&1 &
     CHECK_PID=$!
     sleep 5
     if ! kill -0 $CHECK_PID 2>/dev/null; then
       CRASH_OUTPUT=$(cat /tmp/ralph-startup-check.log 2>/dev/null)
       echo "RUNTIME ASSEMBLY ERROR DETECTED"
       # Classify per references/error-classification.md
       # If Category A: dotnet add package → rebuild → DO NOT count as iteration failure
     fi
     kill $CHECK_PID 2>/dev/null
     wait $CHECK_PID 2>/dev/null
     rm -f /tmp/ralph-startup-check.log
   fi
   ```
   If FAIL → classify error per `references/error-classification.md` → apply fix → rebuild → verify again

2ter. **DI completeness (if application tasks in batch):**
   Verify `Application/DependencyInjection.cs` registers all validators and services:
   - Count validators in `Validators/` folder
   - Verify `AddValidatorsFromAssemblyContaining` is present
   - If empty/TODO → FAIL → fix DI registration → rebuild

3. **Frontend (if frontend/i18n tasks in batch):**
   ```bash
   npm run typecheck && npm run lint
   ```
   If FAIL → fix → re-check → loop until pass

3bis. **Dependency audit (if frontend tasks in batch):**
   ```bash
   cd {frontend_dir}
   npm ls --depth=0 2>&1 | grep "MISSING" && echo "FAIL: missing deps" && exit 1
   ```
   If FAIL → `npm install {missing_packages}` → re-check → loop until pass

4. **MCP validation:**
   `mcp__smartstack__validate_conventions` ONCE for the whole batch

5. **DB validation (if infrastructure/migration tasks in batch):**
   ```bash
   # Quick check: pending model changes after batch?
   INFRA_PROJECT=$(ls src/*Infrastructure*/*.csproj 2>/dev/null | head -1)
   API_PROJECT=$(ls src/*Api*/*.csproj 2>/dev/null | head -1)
   if [ -n "$INFRA_PROJECT" ] && [ -n "$API_PROJECT" ]; then
     dotnet ef migrations has-pending-model-changes \
       --project "$INFRA_PROJECT" \
       --startup-project "$API_PROJECT"
     if [ $? -ne 0 ]; then
       echo "MIGRATION MISSING: Model has uncommitted changes"
       # Create fix task for missing migration
     fi

     # If batch included migration tasks: verify migration applies on real SQL Server
     DB_NAME="SmartStack_Ralph_Check_${iteration}"
     CONN_STRING="Server=(localdb)\\MSSQLLocalDB;Database=$DB_NAME;Integrated Security=true;TrustServerCertificate=true;Connect Timeout=120;"
     dotnet ef database update \
       --connection "$CONN_STRING" \
       --project "$INFRA_PROJECT" \
       --startup-project "$API_PROJECT"
     if [ $? -ne 0 ]; then
       echo "MIGRATION BROKEN: Cannot apply migrations on SQL Server"
       # Fix migration → rebuild → DO NOT commit until this passes
     fi

     # Cleanup temp database
     sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "IF DB_ID('$DB_NAME') IS NOT NULL BEGIN ALTER DATABASE [$DB_NAME] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; DROP DATABASE [$DB_NAME]; END" 2>/dev/null
   fi
   ```
   If FAIL → migration is broken → fix → rebuild → DO NOT commit

**Error resolution cycle:**
1. Read the FULL error output (not just first line)
2. Identify root cause: file path + line number
3. Fix the issue in source code
4. Rebuild/retest
5. If still failing → repeat from step 1
6. **NEVER** commit with failing build or tests

---

## C. Commit Batch

```bash
# Stage all changed files from batch
git add {all_files_from_batch}
git add .ralph/prd.json

git commit -m "$(cat <<'EOF'
feat({scope}): [{category}] {batch.length} tasks — {short summary}

Tasks: {task_ids} / {total}
Iteration: {iteration}
{module ? "Module: " + module : ""}

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
EOF
)"

COMMIT_HASH=$(git rev-parse --short HEAD)
```

**Finalize tasks in prd.json:**
```javascript
const now = new Date().toISOString();
for (const task of batch) {
  if (task.status !== 'failed') task.status = 'completed';
  task.completed_at = now;
  task.iteration = prd.config.current_iteration;
  task.commit_hash = COMMIT_HASH;
}
prd.history.push({
  iteration: prd.config.current_iteration,
  task_ids: batch.map(t => t.id),
  action: 'batch-completed',
  timestamp: now,
  commit_hash: COMMIT_HASH,
  notes: "{summary}"
});
prd.config.current_iteration++;
prd.updated_at = now;
writeJSON('.ralph/prd.json', prd);
```

**Commit progress:**
```bash
git add .ralph/prd.json .ralph/progress.txt
[ -f .ralph/modules-queue.json ] && git add .ralph/modules-queue.json
git commit -m "chore(ralph): progress — iteration {iteration}"
```

---

## D. Loop Back

**IMMEDIATELY return to step-04 section 1 (Read Current State).**
DO NOT stop. DO NOT wait for user. DO NOT re-read step files.

The only exit conditions:
- ALL tasks complete (all modules if multi-module)
- Max iterations reached
- Dead-end (all remaining blocked/failed)
- User Ctrl+C
