---
name: step-01-transform
description: Build handoff data per module - 8 categories from flat BA files
next_step: steps/step-02-export.md
---

# Step 01: Transform (Handoff Data Generation)

## MANDATORY EXECUTION RULES

- **ALWAYS** process modules in topological order (dependencies first)
- **ALWAYS** delegate each module to an **isolated Agent** (context isolation — CRITICAL for large projects)
- **ALWAYS** load data from **flat files** (entities.json, usecases.json, rules.json, screens.json, permissions.json)
- **ALWAYS** map to 8 categories (including "documentation")
- **ALWAYS** propagate personRoleConfig verbatim from entities
- **ALWAYS** separate seedData into core/business categories
- **ALWAYS** map entity to domain file path (1:1)
- **ALWAYS** include dependencies[] per file entry
- **NEVER** invent entities/BRs not in module JSON files
- **NEVER** load all module data in the main conversation (causes context overflow on 5+ modules)
- **ALWAYS** generate API endpoints from use cases + entities (BA does not produce apiEndpoints)
- **ALWAYS** canonicalize entity names before generating file paths — see `references/entity-canonicalization.md`

## YOUR TASK

Orchestrate the transform: determine module order, then delegate each module's transform to an Agent with isolated context. This prevents context accumulation across modules.

---

## CONTEXT ISOLATION ARCHITECTURE

```
Main conversation (orchestrator):
  ├─ Determine topological order
  ├─ FOR each module:
  │   └─ Agent(ba-writer) ──► reads 5 files, builds handoff, writes result
  │                           (isolated context: ~500-1000 lines per module)
  └─ Collect results, display summary
```

**WHY:** A 10-module project has ~10K lines of JSON data. Loading all at once exceeds Sonnet's effective context. Processing one module per Agent keeps each invocation under ~2K lines.

---

## EXECUTION SEQUENCE

### 1. Determine Module Processing Order

From step-00 data, extract the topological order of modules. Display:

```
Module processing order:
  1. {module1} (0 dependencies)
  2. {module2} (depends on: module1)
  ...
```

### 2. Process Each Module via Agent

For **EACH module** in topological order, use the **Agent tool** (subagent_type: `ba-writer`) with the following prompt structure:

```
Transform module "{moduleCode}" for handoff.

## Input
- Module BA directory: {moduleDir}  // ba-006: {docs_dir}/{appKebab}/{moduleKebab}/
- Application code: {appCode}
- Application name: {appName}
- Feature description: {featureDescription}
- Module index: {moduleDir}/index.json

## Instructions
Read the following 5 files from {moduleDir} (ba-006: docs/{projectSlug}/v{X.Y}/{appKebab}/{moduleKebab}/):
  1. entities.json → entities[]
  2. usecases.json → useCases[] (canonical key: "useCases", fallback: "usecases")
  3. rules.json → rules[] (canonical key: "rules", fallback: "businessRules")
  4. permissions.json → roles[], matrix[], permissionPaths[]
  5. screens.json → sections[] (canonical key: "sections", fallback: "screens")

### Normalization Safety Net (BACKWARD COMPAT)
When reading flat files, prefer canonical keys but fall back to alternatives:
  - useCases: `data.useCases || data.usecases || []`
  - primaryActor: `uc.primaryActor || uc.actor`
  - mainScenario: `uc.mainScenario || uc.steps` (if steps[] contains objects, extract `.action`)
  - rules: `data.rules || data.businessRules || []`
  - screens: `data.sections || data.screens` (if screens[] exists, treat each screen as a section with 1 resource)
This safety net handles pre-4.52 BA outputs. It should become unnecessary once step-03-specify enforces canonical keys.

Then build the handoff data following these rules:

### Complexity
| Criteria | Simple | Medium | Complex |
|----------|--------|--------|---------|
| Entities | <=3 | <=6 | >6 |
| Use Cases | <=5 | <=12 | >12 |
| Business Rules | <=10 | <=20 | >20 |

### API Endpoints (generate from use cases)
- UC "Create X" → POST /api/{app}/{module}
- UC "List X"   → GET  /api/{app}/{module}
- UC "Update X" → PUT  /api/{app}/{module}/{id}
- UC "Delete X" → DELETE /api/{app}/{module}/{id}
- UC "Get X"    → GET  /api/{app}/{module}/{id}
- Use permission paths from permissions.json

### Section UC/BR Enrichment
Using sectionCode from usecases.json and rules.json, link each UC and BR to its section.

### Entity Name Canonicalization (MANDATORY)
Before generating any file paths, canonicalize ALL entity names from `entities.json`:
1. Read `references/entity-canonicalization.md` for complete rules
2. For each entity in `entities.json > entities[]`:
   - If entity has `codeIdentifier` or `englishName` → use it directly
   - Otherwise → apply canonicalization: strip diacritics, remove apostrophes/spaces, remove French articles (d, de, du, l, la, le, les, un, une, des, a, au, aux, en), PascalCase
3. Use the CANONICALIZED name in ALL file path templates (`{EntityName}`, `{ServiceName}`, `{DtoName}`, etc.)
4. Store the mapping `{ originalName: "Type d'absence", canonicalName: "TypeAbsence" }` in handoff metadata for traceability

**Example:** Entity `"Type d'absence"` → canonicalized to `"TypeAbsence"` → path `src/Domain/Entities/App/Module/TypeAbsence.cs`

**BLOCKING:** If ANY entity name after canonicalization is not a valid C# identifier (`/^[A-Za-z_][A-Za-z0-9_]*$/`), STOP and report the error.

### File Mapping (8 Categories)
Read `references/handoff-file-templates.md` for complete JSON templates.
All backend paths MUST include {ApplicationName}/ hierarchy.

| Category | Source | Key rules |
|----------|--------|-----------|
| **Domain** | entities[] | Entities, ValueObjects, Enums |
| **Application** | useCases[] | Services, DTOs, Validators |
| **Infrastructure** | entities[] | EF Configurations, DbSet |
| **API** | Generated from useCases + entities | Controllers |
| **Frontend** | screens[] | Pages, Components, Hooks; split by file (NOT monolithic) |
| **SeedData** | entities + permissions | CORE + business (include category field) |
| **Tests** | All layers | Unit, Integration, Security |
| **Documentation** | All layers | Technical docs (can be empty []) |

Frontend: each page as separate entry, FK fields, ALL pages use /ui-components.
Routes: PascalCase module codes → kebab-case (NEVER include /business/ prefix).

### BR-to-Code Mapping
Read `references/handoff-mappings.md` for mapping rules.
For each rule: ruleId, title, module, severity, implementationPoints[].

### personRoleConfig
If entity has personRoleConfig, copy verbatim into handoff.

### SeedData
Read `references/handoff-seeddata-generation.md` for core seed generation.
- category: "core" → Navigation, Permissions, Roles
- category: "business" → Domain-specific data

### Entity Domain Mapping
Read `references/entity-domain-mapping.md` for mapping rules.
- Entity → src/Domain/Entities/{App}/{Module}/{EntityName}.cs
- ValueObject → src/Domain/{Module}/ValueObjects/{VOName}.cs
- Enum → src/Domain/{Module}/Enums/{EnumName}.cs

### Dependencies per File Entry
| Layer | Dependencies |
|-------|-------------|
| domain | [] |
| infrastructure | ["domain"] |
| application | ["domain"] |
| api | ["application"] |
| seedData | ["domain", "infrastructure"] |
| frontend | ["api"] |
| tests | ["domain", "application", "infrastructure", "api"] |
| documentation | [] |

### Write Result
Write via ba-writer.enrichModuleHandoff with the complete handoff payload:
- complexity, filesToCreate (8 categories), brToCodeMapping, apiEndpointSummary
- prdFile: ".ralph/prd-{moduleCode}.json"
- totalFiles, totalTasks, handedOffAt (ISO timestamp)
- featureDescription: {featureDescription}

### Specification Files (MANDATORY)
After writing the handoff data, ALSO write 5 companion files:
1. `.ralph/prd-{moduleCode}.entities.json` = VERBATIM copy of `{moduleDir}/entities.json`
2. `.ralph/prd-{moduleCode}.rules.json` = VERBATIM copy of `{moduleDir}/rules.json`
3. `.ralph/prd-{moduleCode}.usecases.json` = VERBATIM copy of `{moduleDir}/usecases.json`
4. `.ralph/prd-{moduleCode}.screens.json` = VERBATIM copy of `{moduleDir}/screens.json`
5. `.ralph/prd-{moduleCode}.permissions.json` = VERBATIM copy of `{moduleDir}/permissions.json`

Add `specificationFiles` to the PRD referencing these files (relative names, all in `.ralph/`):
```json
"specificationFiles": {
  "entities": "prd-{moduleCode}.entities.json",
  "rules": "prd-{moduleCode}.rules.json",
  "usecases": "prd-{moduleCode}.usecases.json",
  "screens": "prd-{moduleCode}.screens.json",
  "permissions": "prd-{moduleCode}.permissions.json"
}
```

### POST-CHECK (BLOCKING)
After writing, verify:
1. Handoff not empty
2. All 8 categories present
3. brToCodeMapping non-empty
4. Section resources have entity field
5. SeedData contains CORE entries (NavigationModuleSeedData, NavigationSectionSeedData if sections exist, PermissionsSeedData, RolesSeedData)
6. For FIRST module only: SeedData contains APP-LEVEL CORE entries (NavigationApplicationSeedData, ApplicationRolesSeedData)
7. All 5 companion files exist in `.ralph/` and are non-empty
8. `specificationFiles` present in the PRD with all 5 paths
9. Entity count in companion matches source: `prd-{moduleCode}.entities.json` entities[] count = `{moduleDir}/entities.json` entities[] count
10. BR count in companion matches source: `prd-{moduleCode}.rules.json` rules[] count = `{moduleDir}/rules.json` rules[] count
11. Each `brToCodeMapping[].statement` is non-empty (not just a title paraphrase)
Display: "POST-CHECK PASS: {moduleCode} -- 8 categories, {brCount} BRs mapped, {coreCount} core seeds, 5 companion files"
```

### 3. Display Progress

After each Agent completes, display:

```
handoff {i+1}/{N}: {moduleCode} ({fileCount} files) ✓
```

### 4. Display Summary

```
================================================================
  TRANSFORM COMPLETE
================================================================
Modules processed: {N}/{N}
Total files mapped: {totalFiles}
Global complexity: {highest_complexity}
================================================================
```

---

## NEXT STEP

Load: `steps/step-02-export.md`
