---
name: step-05a-handoff
description: Build development handoff data, map business rules to code, write handoff to feature.json
model: sonnet
next_step: steps/step-05b-deploy.md
---

> **Context files:** `_shared.md` | `_architecture.md`

# Step 5a: Handoff - Build & Write

## MANDATORY EXECUTION RULES

- **ALWAYS** verify status = "consolidated" before proceeding
- **ALWAYS** ask user for implementation strategy preference (multi-module only)
- **ALWAYS** derive prd.json from feature.json (NEVER independently)
- **NEVER** invent entities/FRs/BRs not in feature.json
- **ALL** API routes from specification.apiEndpoints (exact copy)
- **Permission** paths from specification.permissionMatrix (full format)
- **ALWAYS** generate 5 CORE SeedData task entries per module

## YOUR TASK

Build the development handoff data: verify consolidation, choose implementation strategy, calculate complexity, map specification to files (7 categories), map business rules to code, generate API endpoint summary, and write handoff to EACH module feature.json.

---

## EXECUTION SEQUENCE

### 1. Verify Consolidation Passed

Use ba-reader to locate the feature and verify consolidation status:

```
ba-reader.findFeature({feature_id})
→ Check status = "consolidated"
```

**IF** status ≠ "consolidated" → **STOP**. Return to step-04a-collect.md.

Display validation summary:

```
✓ Consolidation: APPROVED
✓ Modules: {count} specified and validated
✓ Cross-module: interactions mapped
✓ Permissions: coherent
→ Proceeding to handoff...
```

Include:
- Number of modules
- Number of entities across all modules
- Number of use cases across all modules
- Number of business rules across all modules
- Cross-module interaction count

---

### 1b. Cache Warming for Handoff & Deploy

> **Performance Optimization:** Pre-load handoff templates and references to reduce redundant reads during handoff generation.
> This step runs ONCE at start of step-05a, files retained through step-05b.

```
// Pre-load handoff & deploy references (Bucket 5)
const handoffRefs = [
  "~/.claude/skills/business-analyse/references/handoff-file-templates.md",
  "~/.claude/skills/business-analyse/references/handoff-mappings.md",
  "~/.claude/skills/business-analyse/references/deploy-data-build.md",
  "~/.claude/skills/business-analyse/references/deploy-modes.md",
  "~/.claude/skills/business-analyse/references/html-data-mapping.md"
];

for (const file of handoffRefs) {
  read(file);  // Pre-load into cache
}

// Pre-load HTML template (large file, loaded once)
read("~/.claude/skills/business-analyse/html/ba-interactive.html");

Display: "✓ Cache warmed: handoff templates (139KB, 6 files)"
Display: "  Expected token savings: ~3,000 tokens (handoff refs read 2× → 1×)"
Display: "  Retention: through step-05b (deploy)"
```

**Rationale:**

- Handoff templates are read 2× during step-05a + step-05b (without caching)
- HTML template (85KB) is read once but benefits from explicit pre-load (faster deploy)
- Token savings: ~3,000 tokens for handoff process
- Cache retained until session end (needed for both handoff and deploy steps)

**Why NOT loaded at step-00:**
- Large files (139KB total), especially ba-interactive.html (85KB)
- Only used at END of workflow (steps 05a, 05b)
- Low re-use (1-2× each)
- Loading at step-05a is more efficient (just-in-time caching)

See [references/cache-warming-strategy.md](../references/cache-warming-strategy.md) § Bucket 5 for details.

---

### 2. Implementation Strategy Choice (Multi-Module)

**IF** more than 1 module defined in feature.json:

Ask via AskUserQuestion:

```
question: "Quelle stratégie d'implémentation préférez-vous ?"
header: "Stratégie d'implémentation"
options:
  - label: "Module par module (Recommandé)"
    description: "Implémenter chaque module complètement avant de passer au suivant. Suit l'ordre topologique des dépendances."
  - label: "Couche par couche"
    description: "Implémenter toutes les entités, puis tous les services, puis tous les contrôleurs, etc. Plus de parallélisation possible mais plus complexe."
  - label: "Hybride"
    description: "Modules fondation en premier (couche par couche), puis modules dépendants (module par module)"
```

Store the chosen strategy in `handoff.implementationStrategy`.

**IF** only 1 module → default to "Module par module" (no choice needed).

---

### 3. Calculate Complexity

For each module in feature.json.modules[], calculate:

```json
{
  "complexity": "simple|medium|complex",
  "complexityDetails": {
    "entities": {count},
    "useCases": {count},
    "businessRules": {count},
    "calculated": "{level} (≤X entities, ≤Y UCs, ≤Z BRs)"
  }
}
```

| Criteria | Simple | Medium | Complex |
|----------|--------|--------|---------|
| Entities | ≤3 | ≤6 | >6 |
| Use Cases | ≤5 | ≤12 | >12 |
| Business Rules | ≤10 | ≤20 | >20 |

**Global complexity** = highest complexity across all modules.

Example:
- Module A: 4 entities, 6 use cases, 8 BRs → **simple**
- Module B: 8 entities, 15 use cases, 25 BRs → **complex**
- Overall: **complex**

---

### 4. Map Specification to Files

> **IMPORTANT:** Generate `handoff.filesToCreate` as structured object with 7 categories.
> Each file entry is `{path, type, linkedFRs, linkedUCs, module}`. NO free text.
> Read `.smartstack/config.json` to extract baseNamespace for project namespace.

**Order by topological dependency** (modules with no deps first, then dependents).

For **EACH module** in topological order:

> **PATH HIERARCHY CONVENTION:** All backend file paths MUST include the context and application hierarchy.
> Derive from module feature.json metadata:
> - `{ContextPascal}` = PascalCase of `metadata.context` (e.g., `"business"` → `"Business"`)
> - `{ApplicationName}` = `metadata.application` (e.g., `"HumanResources"`)
> - `{ModuleName}` = `metadata.module` (e.g., `"Projects"`)
>
> **Controller context-to-folder mapping (`{ContextShort}`):**
> | metadata.context | Controller Folder |
> |-----------------|-------------------|
> | `business` | `Business` |
> | `platform` | `Admin` |
> | `personal` | `User` |
>
> **Example** for context=business, application=HumanResources, module=Projects:
> - Domain: `src/Domain/Entities/Business/HumanResources/Projects/Project.cs`
> - Application: `src/Application/Services/Business/HumanResources/Projects/ProjectService.cs`
> - Infrastructure: `src/Infrastructure/Persistence/Configurations/Business/HumanResources/Projects/ProjectConfiguration.cs`
> - API: `src/API/Controllers/Business/HumanResources/ProjectsController.cs`
> - Tests: `src/Tests/Unit/Domain/Business/HumanResources/Projects/ProjectTests.cs`

#### 4.1-4.7 File Category Templates

See [references/handoff-file-templates.md](../references/handoff-file-templates.md) for the complete JSON templates for all 7 categories:

| Category | Source | Key rules |
|----------|--------|-----------|
| **4.1 Domain** | `analysis.entities[]` | Entities, ValueObjects, Enums, Exceptions |
| **4.2 Application** | `analysis.useCases[]` | Services, DTOs, Validators |
| **4.3 Infrastructure** | `analysis.entities[]` | EF Configurations, DbSet, DI |
| **4.4 API** | `specification.apiEndpoints[]` | Controllers with `{ContextShort}` mapping |
| **4.5 Frontend** | `specification.uiWireframes[]` | Pages, Components, Hooks + wireframe traceability |
| **4.6 SeedData** | `specification.seedDataCore` | 5 CORE + business + IClientSeedDataProvider |
| **4.7 Tests** | All layers | Unit, Integration, Security tests |

**Critical rules:**
- All backend paths include `{ContextPascal}/{ApplicationName}/` hierarchy
- Frontend pages MUST have `linkedWireframes[]` + `wireframeAcceptanceCriteria`
- SeedData: 5 CORE entries ALWAYS + IClientSeedDataProvider for client projects
- Path convention: `Persistence/Seeding/Data/` (NEVER `Data/SeedData/`)

---

### 5. Map Business Rules to Code

See [references/handoff-mappings.md](../references/handoff-mappings.md) — Section "Business Rules to Code Mapping".

For each BR in `analysis.businessRules[]` of EACH module, generate:
- **ruleId**, **title**, **module**, **severity** (critical/high/medium/low)
- **implementationPoints**: Array of `{layer, component, method, implementation}` across Domain, Application, Infrastructure, API, Frontend

---

### 6. API Endpoint Summary

> **ABSOLUTE RULE:** Copy **EXACTLY** from `specification.apiEndpoints[]`. **NEVER** reinvent routes.

See [references/handoff-mappings.md](../references/handoff-mappings.md) — Section "API Endpoint Summary".

For each endpoint: operation, method, route, linkedUC, linkedFR, permissions, requestSchema, responseSchema, errorCodes, module.

Total endpoints = count of specification.apiEndpoints[] across all modules.

---

### 7. Write Handoff to Feature.json

> **BLOCKING RULE: The handoff MUST be written in EACH module feature.json.**
> A handoff at master level alone is INSUFFICIENT. Ralph-loop consumes module-level handoffs.
> An empty module handoff (`"handoff": {}`) is a CRITICAL BUG that blocks all downstream generation.

#### 7a. Module Handoff Loop (MANDATORY)

> **STRUCTURE CARD: handoff** — Field names are EXACT. Include ALL fields below.
> **PATH RULE:** All backend paths MUST include `{ContextPascal}/{ApplicationName}/` hierarchy (see section 4).
> ```json
> {
>   "complexity": "simple|medium|complex",
>   "filesToCreate": {
>     "domain": [{"path": "src/Domain/Entities/{Ctx}/{App}/{Mod}/{Entity}.cs", "type": "Entity|ValueObject|Enum", "linkedFRs": [], "linkedUCs": [], "module": "..."}],
>     "application": [{"path": "src/Application/Services/{Ctx}/{App}/{Mod}/{Svc}Service.cs", "type": "Service|Dto|Validator", "linkedFRs": [], "linkedUCs": [], "module": "..."}],
>     "infrastructure": [{"path": "src/Infrastructure/Persistence/Configurations/{Ctx}/{App}/{Mod}/{Entity}Configuration.cs", "type": "EFConfiguration", "linkedFRs": [], "module": "..."}],
>     "api": [{"path": "src/API/Controllers/{CtxShort}/{App}/{Entity}Controller.cs", "type": "ApiController", "linkedUCs": [], "linkedFRs": [], "module": "..."}],
>     "frontend": [{"path": "src/pages/{Mod}/{Page}Page.tsx", "type": "Page|Component|Hook|DashboardPage", "linkedUCs": [], "linkedWireframes": [], "module": "..."}],
>     "seedData": [{"path": "src/Infrastructure/Persistence/Seeding/Data/{Mod}/...SeedData.cs", "type": "SeedData", "category": "core|business", "source": "...", "module": "..."}],
>     "tests": [{"path": "src/Tests/Unit/Domain/{Ctx}/{App}/{Mod}/{Entity}Tests.cs", "type": "UnitTests|IntegrationTests|SecurityTests", "linkedFRs": [], "linkedUCs": [], "module": "..."}]
>   },
>   "brToCodeMapping": [{"ruleId": "BR-...", "files": ["path1", "path2"], "implementation": "description"}],
>   "apiEndpointSummary": [{"method": "GET|POST|PUT|DELETE", "path": "/api/...", "permission": "business.{app}.{module}.{action}", "linkedUC": "UC-..."}],
>   "prdFile": ".ralph/prd-{module}.json",
>   "totalFiles": 0,
>   "totalTasks": 0,
>   "handedOffAt": "{ISO timestamp}"
> }
> ```
> **MANDATORY fields:** ALL of the above. `filesToCreate` MUST have all 7 categories (even if empty arrays).
> **FORBIDDEN:** `handoff: {}` (empty object is a CRITICAL BUG). Missing `brToCodeMapping` or `apiEndpointSummary`.

**For i = 0; i < modules.length; i++:**

```
1. moduleCode = modules[i].code
2. moduleFeatureId = modules[i].featureJsonPath or find via ba-reader.findFeature()
3. Read the module feature.json via ba-reader.findFeature(moduleFeatureId)
4. Build the handoff payload for THIS module:
   - complexity (from section 3 calculation)
   - filesToCreate (full 7-category structure from section 4, filtered for this module)
   - brToCodeMapping (from section 5, filtered for this module)
   - apiEndpointSummary (from section 6, filtered for this module)
   - prdFile path
   - totalFiles count
   - totalTasks count
   - handedOffAt timestamp

5. Write via ba-writer:
   ba-writer.enrichModuleHandoff({
     moduleFeatureId: {moduleFeatureId},
     handoffData: {
       complexity: "{simple|medium|complex}",
       filesToCreate: {...},
       brToCodeMapping: [...],
       apiEndpointSummary: [...],
       prdFile: ".ralph/prd-{moduleCode}.json",
       totalFiles: {count},
       totalTasks: {count},
       handedOffAt: "{ISO timestamp}"
     }
   })

6. VERIFICATION (MANDATORY - done automatically by enrichModuleHandoff):
   - handoff !== {}
   - handoff.filesToCreate has 7 categories
   - handoff.brToCodeMapping.length > 0
   IF verification fails → STOP, report error, do NOT continue

7. Display progress:
   "✓ Handoff module {i+1}/{N} : {moduleCode} ({fileCount} fichiers, {brCount} BRs mappées)"
```

#### 7b. Master Handoff (after ALL modules written successfully)

```
ba-writer.enrichSection({
  featureId: {feature_id},
  section: "handoff",
  data: {
    status: "handed-off",
    complexity: "{simple|medium|complex}",
    implementationStrategy: "{strategy}",
    moduleCount: {count},
    moduleOrder: [...],
    totalFilesToCreate: {sum across all modules},
    totalTasks: {sum across all modules},
    prdStructure: "per-module | consolidated",
    prdFiles: [
      { module: "{module1}", path: ".ralph/prd-{module1}.json" },
      { module: "{module2}", path: ".ralph/prd-{module2}.json" }
    ],
    progressTrackerPath: ".ralph/progress.txt",
    handedOffAt: "{ISO timestamp}"
  }
})
```

#### 7c. Final Verification (BLOCKING)

```
count = 0
FOR each module in modules[]:
  Read module feature.json
  IF module.handoff !== {} AND module.status === "handed-off":
    count++

IF count < modules.length:
  → BLOCKING ERROR: {modules.length - count} modules missing handoff
  → List the missing modules by name
  → DO NOT proceed to step-05b
  → Return to 7a for missing modules only

IF count === modules.length:
  ba-writer.updateStatus({feature_id}, "handed-off")
  Display: "✓ Handoff complet: {count}/{modules.length} modules avec handoff valide"
```

Status journey: analyze → consolidate → handed-off

---

## SELF-VERIFICATION

Before proceeding to step-05b-deploy.md, VERIFY:

1. **filesToCreate** has all 7 categories populated (domain, application, infrastructure, api, frontend, seedData, tests) for each module
2. **Complexity** calculated for all modules
3. **Implementation strategy** chosen (for multi-module features)
4. **ALL module feature.json** have `handoff.brToCodeMapping.length > 0`
5. **ALL module feature.json** have `handoff.apiEndpointSummary.length > 0`
6. **ALL module feature.json** status = "handed-off"
7. **Master feature.json** has `handoff` section with implementationStrategy, moduleOrder, totalFilesToCreate
8. **Master status** = "handed-off"

**IF any check fails → FIX before proceeding.**

---

## NEXT STEP

Load: `steps/step-05b-deploy.md`
