name: mapper-runtime-checks description: Runtime mapper validation using debug logs to detect missing fields
Mapper Runtime Validation Process
PURPOSE: Detect missing fields by comparing raw API responses with mapped outputs.
This process catches field mapping bugs that static analysis misses:
- Field name mismatches (e.g., API uses
mobilePhone, mapper looks forphoneNumber) - Fields present in API but not in spec
- Fields in spec but not mapped
- Type conversion errors
When to Run Runtime Validation
MANDATORY for:
- New module creation (after all operations implemented)
- Adding new operations to existing module
- API spec updates
- After mapper refactoring
RECOMMENDED for:
- Periodic validation (quarterly)
- Before major releases
- After API version upgrades
4-Step Runtime Validation Process
Step 1: Add Temporary Debug Logs
Add [TEMP-RAW-API] debug logs in each Producer API implementation BEFORE mapping:
// In UserProducerApiImpl.ts
import { LoggerEngine } from '@zerobias-org/logger';
export class UserProducerApiImpl implements UserProducerApi {
private readonly logger = LoggerEngine.root();
async list(results: PagedResults<User>, organizationId: string): Promise<void> {
const response = await this.httpClient.get(`/orgs/${organizationId}/users`);
// 🎯 CRITICAL: Log BEFORE any mapping
this.logger.debug('[TEMP-RAW-API] listUsers:', JSON.stringify(response.data, null, 2));
// Then map
results.items = response.data.data.map(toUser);
results.count = response.data.totalCount || 0;
}
}
Key Points:
- Use
[TEMP-RAW-API]prefix for easy identification - Log
response.data(the raw API payload) - Log BEFORE any mapper calls
- Add to ALL operations in ALL producers
Step 2: Run Tests with Debug Logging
# Run all integration tests with debug output
cd package/<vendor>/<service>/<product>
env LOG_LEVEL=debug npm run test:integration > /tmp/debug-full.log 2>&1
# Or run per producer for easier analysis
env LOG_LEVEL=debug npm run test:integration -- --grep "User Producer" > /tmp/user-debug.log 2>&1
This captures:
- Raw API responses (from [TEMP-RAW-API] logs)
- Mapped results (from test debug logs)
- All field values before and after transformation
Step 3: Compare Raw vs Mapped
Manual Analysis:
# 1. Extract raw API response
grep -A 100 "\[TEMP-RAW-API\] listUsers" /tmp/user-debug.log > /tmp/raw-api.txt
# 2. Extract mapped result
grep -A 50 "userApi.list" /tmp/user-debug.log > /tmp/mapped-result.txt
# 3. Compare field-by-field
diff /tmp/raw-api.txt /tmp/mapped-result.txt
Automated Analysis (RECOMMENDED):
Use parallel mapping-engineer agents to analyze each producer:
// Launch one agent per producer
Task(mapping-engineer, {
prompt: `Analyze User producer for missing fields:
1. Read /tmp/user-debug.log
2. Extract [TEMP-RAW-API] responses
3. Compare with mapper in src/Mappers.ts
4. List ALL missing fields
5. Update mapper if needed`
})
Run all 11 in parallel for fastest results.
Step 4: Fix Missing Fields
For each missing field found:
-
Check if field is in API spec (api.yml)
- YES → Update mapper immediately
- NO → Escalate to schema-specialist to update spec first
-
Update mapper to include field:
// Before (missing field)
const output: User = {
id: String(raw.id),
name: raw.name,
email: map(Email, raw.email)
// Missing: phoneNumber
};
// After (field added)
const output: User = {
id: String(raw.id),
name: raw.name,
email: map(Email, raw.email),
phoneNumber: optional(raw.mobilePhone) // ← Added (note field name difference!)
};
-
Re-run validation to verify fix
-
Remove temp debug logs when complete:
# Find all temp logs
grep -r "\[TEMP-RAW-API\]" src/
# Remove them after validation passes
Common Issues Found by Runtime Validation
Issue 1: Field Name Mismatches
Example: API uses mobilePhone, spec defines phoneNumber
// ❌ WRONG - Looking for wrong field name
phoneNumber: optional(raw.phoneNumber) // API doesn't have this field!
// ✅ CORRECT - Use actual API field name
phoneNumber: optional(raw.mobilePhone) // Maps API field to interface field
Detection: Raw API log shows mobilePhone, mapped output has phoneNumber: undefined
Issue 2: Missing Nested Object Fields
Example: API returns identity.namespace with 3 fields, mapper only maps 1
// ❌ WRONG - Incomplete nested mapping
function toIdentityNamespace(raw: any): IdentityNamespace {
return {
id: raw.id
// Missing: nickname, namespaceType
};
}
// ✅ CORRECT - All fields mapped
function toIdentityNamespace(raw: any): IdentityNamespace {
ensureProperties(raw, ['id']);
return {
id: raw.id,
nickname: optional(raw.nickname),
namespaceType: mapWith(toNamespaceType, raw.namespaceType)
};
}
Detection: Raw API log shows 3 fields in namespace, mapped output only has id
Issue 3: API Returns Fields Not in Spec
Example: API returns boundary, contactName, contactPhone but spec doesn't define them
# Raw API response
{
"id": 1239,
"name": "Site 1",
"boundary": null, ← NOT in spec
"contactName": null, ← NOT in spec
"contactPhone": null ← NOT in spec
}
Action:
- DO NOT add to mapper (will cause TypeScript error)
- Escalate to schema-specialist to update api.yml
- Document in issue tracker
- After spec updated → regenerate types → update mapper
Issue 4: Array Element Mapping Incomplete
Example: API returns array with 5 fields per item, mapper only maps 3
// ❌ WRONG - Array elements incompletely mapped
entries: raw.entries?.map((e: any) => ({
id: e.id,
name: e.name
// Missing: 3 more fields per element
}))
// ✅ CORRECT - Use helper mapper
function toEntry(raw: any): Entry {
ensureProperties(raw, ['id', 'name']);
return {
id: String(raw.id),
name: raw.name,
zone: mapWith(toZone, raw.zone),
acu: mapWith(toAcu, raw.acu),
status: optional(raw.status)
// All 5 fields mapped
};
}
entries: Array.isArray(raw.entries) ? raw.entries.map(toEntry) : undefined
Detection: Raw API shows 5 fields per array element, mapped shows only 2
Runtime Validation Checklist
Before marking mapper validation complete:
- Added [TEMP-RAW-API] debug logs to all operations
- Ran integration tests with LOG_LEVEL=debug
- Captured debug output to file(s)
- Extracted raw API responses
- Extracted mapped results
- Compared field-by-field for each operation
- Verified ZERO missing fields
- Checked for field name mismatches
- Validated nested object completeness
- Validated array element mapping
- Fixed any missing fields
- Re-ran validation to confirm fix
- Removed [TEMP-RAW-API] debug logs
- Documented any API-spec gaps
Parallel Agent Pattern
For modules with multiple producers, use parallel agents for efficiency:
// Launch one mapping-engineer agent per producer
const producers = [
'Auth', 'User', 'Group', 'Entry', 'Site', 'Zone',
'Audit', 'Schedule', 'Role', 'Credential', 'IdentityProvider'
];
// Single message with multiple Task invocations
producers.map(producer =>
Task(mapping-engineer, {
description: `Analyze ${producer} mapper`,
prompt: `
1. Read /tmp/${producer.toLowerCase()}-debug.log
2. Extract [TEMP-RAW-API] responses
3. Compare with mapper in src/Mappers.ts
4. List ALL missing fields
5. Update mapper if needed
6. Return detailed report
`
})
);
Benefits:
- All producers analyzed simultaneously
- 10-20x faster than sequential
- Each agent focuses on one producer
- Clear separation of concerns
Example Session Output
When runtime validation finds issues:
✅ Auth Producer - 0 missing fields (10/10 mapped)
❌ User Producer - 14 missing fields found:
- fullName, initials, opal
- mobilePhone (field name mismatch: API uses mobilePhone, mapper looks for phoneNumber)
- isEmailVerified, idpUniqueIdentifier, language
- nicknames, needsPasswordChange
- createdAt, updatedAt
- IdentityNamespace.nickname, IdentityNamespace.namespaceType
✅ Group Producer - 0 missing fields (12/12 mapped)
... etc
Integration with Validation Gates
This runtime validation should be added to Gate 3: Implementation Validation:
# After all operations implemented
npm run test:integration # All tests pass
npm run build # Build succeeds
# THEN run runtime mapper validation
env LOG_LEVEL=debug npm run test:integration > /tmp/validation.log 2>&1
# Analyze for missing fields (manual or agent-assisted)
Gate 3 should not pass until:
- All integration tests pass
- Runtime validation shows ZERO missing fields
- No API-spec gaps documented
Tools and Scripts
Save per-producer logs for easier analysis:
#!/bin/bash
# run-producer-validation.sh
PRODUCERS=(
"Auth Producer:auth"
"User Producer:user"
"Group Producer:group"
# ... etc
)
for producer in "${PRODUCERS[@]}"; do
IFS=':' read -r pattern name <<< "$producer"
env LOG_LEVEL=debug npm run test:integration -- --grep "$pattern" > /tmp/debug-$name.log 2>&1
done
Then analyze each file separately.
References
- Static validation: mapper-field-validation skill
- Mapper patterns: mapper-patterns skill
- Mapping engineer: @.claude/agents/mapping-engineer.md
- Operation engineer: @.claude/agents/operation-engineer.md
- Gate 3 validation: @.claude/workflows/implementation-validation.md