---
name: 02-self-check-validation
description: Post-build self-check validation to detect data loss when building FEATURE_DATA
---

# Self-Check Validation

After building `FEATURE_DATA.moduleSpecs` and enriching `anticipatedSections` with section-level use cases and business rules, run this mandatory self-check to detect data loss between the source files and the built object.

## Purpose

Ensures that no useCases, businessRules, entities, or screens were lost during the normalization and mapping process. Data loss indicates a bug in the build logic (e.g., missing array handling, failed normalization, wrong field names).

## Execution Timing

**AFTER:**
1. All `moduleSpecs[moduleCode]` entries are populated
2. `anticipatedSections` are enriched with section-level UC/BR

**BEFORE:**
- Proceeding to step-03 (HTML rendering)

## Self-Check Code

```javascript
// SELF-CHECK: compare source file counts vs FEATURE_DATA counts
const errors = [];
FEATURE_DATA.modules.forEach(m => {
  const spec = FEATURE_DATA.moduleSpecs[m.code];
  const source = collected_data.modules[m.code];
  if (!spec) { errors.push(`MISSING moduleSpecs[${m.code}]`); return; }

  // Check useCases (handle both key conventions)
  const srcUC = (source?.usecases?.useCases || source?.usecases?.usecases || []).length;
  const bltUC = (spec.useCases || []).length;
  if (srcUC > 0 && bltUC === 0)
    errors.push(`${m.code}: useCases EMPTY but source has ${srcUC}`);

  // Check businessRules (handle both key conventions)
  const srcBR = (source?.rules?.rules || source?.rules?.businessRules || []).length;
  const bltBR = (spec.businessRules || []).length;
  if (srcBR > 0 && bltBR === 0)
    errors.push(`${m.code}: businessRules EMPTY but source has ${srcBR}`);

  // Check entities
  const srcEnt = (source?.entities?.entities || []).length;
  const bltEnt = (spec.entities || []).length;
  if (srcEnt > 0 && bltEnt === 0)
    errors.push(`${m.code}: entities EMPTY but source has ${srcEnt}`);

  // Check screens (handle both formats: screens[] and sections[])
  const srcScreens = (source?.screens?.screens || source?.screens?.sections || []).length;
  const bltScreenResources = (spec.screens || []).reduce(
    (acc, s) => acc + (s.resources || []).length, 0);
  if (srcScreens > 0 && bltScreenResources === 0)
    errors.push(`${m.code}: screens EMPTY (0 resources) but source has ${srcScreens} screens/sections`);

  // Check serialization: [object Object] in useCases steps = BUG
  (spec.useCases || []).forEach(uc => {
    if (uc.steps && uc.steps.includes("[object Object]"))
      errors.push(`${m.code}: UC "${uc.name}" has [object Object] in steps — steps[] contains objects not strings`);
  });
});

if (errors.length > 0) {
  Display("⛔ SELF-CHECK FAILED — data loss detected:");
  errors.forEach(e => Display("  - " + e));
  // FIX: re-map the failing modules from collected_data before continuing
}
```

## Validation Points

### 1. moduleSpecs Structure

**Check:** Every module in `FEATURE_DATA.modules` has a corresponding entry in `FEATURE_DATA.moduleSpecs[moduleCode]`.

**Failure Symptom:** `MISSING moduleSpecs[${m.code}]`

**Fix:** Ensure the build loop populates `moduleSpecs[moduleCode]` for ALL modules.

### 2. useCases Count

**Check:** If source file has useCases (`usecases.useCases` or `usecases.usecases`), the built `spec.useCases` array must not be empty.

**Failure Symptom:** `${m.code}: useCases EMPTY but source has ${srcUC}`

**Common Causes:**
- Field is `usecases` but code looks for `useCases` (camelCase mismatch)
- Nested field is `usecases` instead of `useCases` (lowercase variant)
- Mapping function didn't handle array correctly

**Fix:** Check field names in `mod.usecases?.useCases || mod.usecases?.usecases`.

### 3. businessRules Count

**Check:** If source file has businessRules (`rules.rules` or `rules.businessRules`), the built `spec.businessRules` array must not be empty.

**Failure Symptom:** `${m.code}: businessRules EMPTY but source has ${srcBR}`

**Common Causes:**
- Field is `businessRules` but code looks for `rules` (nested field name mismatch)
- Rules array is not being mapped correctly

**Fix:** Check field names in `mod.rules?.rules || mod.rules?.businessRules`.

### 4. Entities Count

**Check:** If source file has entities (`entities.entities`), the built `spec.entities` array must not be empty.

**Failure Symptom:** `${m.code}: entities EMPTY but source has ${srcEnt}`

**Common Causes:**
- Mapping didn't iterate over entities array
- Fallback to `fields[]` when `attributes[]` is missing not working

**Fix:** Check the entities mapping includes both `attributes[]` and `fields[]` fallback.

### 5. Screens Count

**Check:** If source file has screens (either `screens.screens[]` or `screens.sections[]`), the normalized `spec.screens[].resources[]` must have at least the same number of total resources.

**Failure Symptom:** `${m.code}: screens EMPTY (0 resources) but source has ${srcScreens} screens/sections`

**Common Causes:**
- Format detection logic failed (neither Format A nor B found)
- Screen format detection chose the wrong branch
- `normalizeColumn`, `normalizeField`, `normalizeFilter` functions not applied

**Fix:**
1. Verify `mod.screens.screens` or `mod.screens.sections` exists
2. Run format detection logic step-by-step
3. Ensure screen resources are being pushed into the array

### 6. Serialization Bug: [object Object]

**Check:** useCases steps field must be a string (or converted to string via `.join()`). If it contains `[object Object]`, the steps array contains unconverted objects.

**Failure Symptom:** `${m.code}: UC "${uc.name}" has [object Object] in steps — steps[] contains objects not strings`

**Fix:** Ensure the mapping converts step objects to strings:
```javascript
steps: (uc.mainScenario || uc.steps || []).map(s =>
  typeof s === 'string' ? s : (s.action || s.description || "")
).join("\n")  // .join() is CRITICAL to convert array to string
```

## Resolution Workflow

When self-check fails:

1. **Identify failing module** from error message
2. **Locate the source file** in `collected_data.modules[m.code]`
3. **Compare field structure** between source and mapping code
4. **Fix the mapping** (update field names, add fallbacks, fix type conversions)
5. **Re-build moduleSpecs** for the failing module
6. **Re-run self-check** to verify fix

## Post-Check Actions

If self-check **PASSES**:
- Continue to step-03 (HTML rendering)
- No further data validation needed

If self-check **FAILS** with errors:
- DO NOT proceed to rendering
- Fix each error in the module build logic
- Re-build affected moduleSpecs entries
- Re-run self-check

## Expected Output

### Success Case

No errors array or empty:
```
✅ Self-check PASSED — all modules have complete data
```

### Failure Case

Display all errors:
```
⛔ SELF-CHECK FAILED — data loss detected:
  - Employees: useCases EMPTY but source has 5
  - Employees: UC "Create Employee" has [object Object] in steps — steps[] contains objects not strings
  - Payroll: screens EMPTY (0 resources) but source has 3 screens/sections
```

---

## Design Rationale

The self-check is **mandatory and blocking** because:

1. **Silent data loss is worse than errors** — empty arrays are valid JavaScript but indicate a bug
2. **Hard to debug later** — if screens/UC/BR are missing, the HTML viewer will appear empty but rendering code will work
3. **Source of truth is always the collected files** — self-check compares against collected_data, not against user expectations
4. **Early detection** — catch bugs in step-02 before they cascade into step-03 rendering
