Claude-skill-registry-data mapper-runtime-checks

Runtime mapper validation using debug logs to detect missing fields

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry-data
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/mapper-runtime-checks" ~/.claude/skills/majiayu000-claude-skill-registry-data-mapper-runtime-checks && rm -rf "$T"
manifest: data/mapper-runtime-checks/SKILL.md
source content

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 for
    phoneNumber
    )
  • 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:

  1. Check if field is in API spec (api.yml)

    • YES → Update mapper immediately
    • NO → Escalate to schema-specialist to update spec first
  2. 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!)
};
  1. Re-run validation to verify fix

  2. 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:

  1. DO NOT add to mapper (will cause TypeScript error)
  2. Escalate to schema-specialist to update api.yml
  3. Document in issue tracker
  4. 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