Módulo 2: Code Review Automático en PRs

Personalizar Convenciones del Equipo

Personalizar Convenciones del Equipo

Descripción

Hasta ahora tu bot funciona con un prompt genérico: "haz code review de este diff". El resultado son comentarios genéricos: "considera type hints", "este nombre podría ser más claro", "agrega docstring". Útiles, pero no específicos a tu proyecto.

Cada equipo tiene matices: convenciones de naming particulares, patrones aceptados que difieren del estándar, módulos legacy con reglas distintas, decisiones arquitecturales documentadas. Un bot que aplica reglas genéricas pierde valor rápido — el equipo empieza a percibirlo como ruido.

Esta cápsula te enseña a alimentar al bot con las convenciones específicas de tu equipo vía CLAUDE.md y prompts personalizados. Al terminar, vas a tener un bot que aplica las reglas que tu equipo definió, no las que el modelo asume genéricamente.


El Problema con Convenciones Genéricas

BOT GENÉRICO:
> "El nombre createOrder debería ser create_order para
   seguir snake_case en Python."

EL EQUIPO:
> "Sí, lo sabemos. Pero ese archivo es legacy de cuando
   usábamos camelCase. No queremos refactorizarlo todo
   ahora. Ignora el comment."

RESULTADO:
- Comment técnicamente correcto
- Comment pragmáticamente inútil
- Equipo desactiva el bot porque "comenta cosas que no
  importan"

El bot necesita saber que ese módulo es excepción. Esa información vive en la cabeza del equipo — pero ahora la puedes pasar al bot.


CLAUDE.md como Source of Truth

CLAUDE.md es el archivo donde documentas las convenciones del proyecto para que Claude Code (y otros agentes AI) las apliquen. Nació para sesiones interactivas pero también funciona en CI.

Estructura recomendada

# Project Conventions

## Stack
- Python 3.11+, Flask, SQLAlchemy
- TypeScript en frontend (React)

## Naming
- Python: snake_case para funciones/variables, PascalCase para clases
- TypeScript: camelCase para variables, PascalCase para tipos/componentes
- Excepciones documentadas:
  - `src/legacy/` mantiene camelCase original — no refactorizar
  - APIs externas usan camelCase para compatibilidad

## Patrones aceptados
- Service layer obligatorio para lógica de negocio (no en routes)
- Repositories vía SQLAlchemy ORM (no queries raw)
- Type hints en funciones públicas (no en privadas para reducir ruido)

## Patrones prohibidos
- `bare except` (siempre especificar excepción)
- `print()` en código de producción (usar el logger)
- SQL string concatenation (siempre parameterized)

## Estructura
- `src/api/routes/` — solo I/O, sin lógica
- `src/services/` — lógica de negocio
- `src/models/` — SQLAlchemy models
- `src/utils/` — helpers genéricos

## Tests
- Pytest, fixtures en `tests/conftest.py`
- Coverage mínimo: 70% en módulos nuevos
- Tests de integración en `tests/integration/`

## Tech debt conocido (no comentar)
- `src/legacy/payments_v1.py` — se va a deprecar Q3
- Falta de type hints en `src/utils/*` — backlog explícito

Cargar CLAUDE.md en el prompt del bot

from pathlib import Path

# Cargar las convenciones
claude_md_path = Path("CLAUDE.md")
if claude_md_path.exists():
    conventions = claude_md_path.read_text()
else:
    conventions = "Sin convenciones documentadas."

# Construir el prompt con conventions inline
prompt = f"""Eres un code reviewer profesional para este proyecto.

CONVENCIONES DEL PROYECTO (de CLAUDE.md):
{conventions}

INSTRUCCIONES:
- Aplica ESTAS convenciones, no convenciones genéricas
- Si una excepción está documentada, NO la marques como issue
- Si el tech debt está en la lista de "no comentar", ignóralo
- Tu output debe respetar el JSON estructurado del review

DIFF A REVISAR:

{diff_text}


[resto del prompt con formato JSON esperado]
"""

Resultado: el bot entiende que src/legacy/ usa camelCase a propósito, que print() es prohibido, que falta de type hints en src/utils/* no debe comentarse.


Convenciones por Tipo de Archivo

A veces las reglas dependen del tipo de archivo. CLAUDE.md puede estructurarse así:

## Reglas por Tipo

### Python (`*.py`)
- snake_case
- type hints en funciones públicas
- docstrings en funciones de >5 líneas

### TypeScript (`*.ts`, `*.tsx`)
- camelCase para variables, PascalCase para tipos
- Strict mode habilitado, no `any`
- Props con interfaces explícitas

### YAML (`.github/workflows/*.yml`)
- Pinear versiones de actions (`@v4`, no `@latest`)
- Permisos explícitos por job
- Comentarios en steps no-obvios

### SQL migrations (`migrations/*.sql`)
- Idempotente (IF NOT EXISTS, IF EXISTS)
- Down migration documentada
- Cambios destructivos requieren approval explícito

El bot recibe esta información en el prompt y aplica reglas según extensión del archivo.


Ejemplos de Buenas y Malas Implementaciones

Más efectivo que reglas abstractas: mostrar ejemplos de código aceptable y código rechazable. CLAUDE.md puede incluir:

## Ejemplos: Manejo de Errores

### ✅ ACEPTABLE
\```python
try:
    result = process_payment(amount)
except PaymentValidationError as e:
    logger.warning(f"Validation failed: {e}")
    raise PaymentError("Invalid input") from e
except ExternalAPIError as e:
    logger.error(f"Stripe API failed: {e}")
    raise PaymentError("Payment provider unavailable") from e
\```

### ❌ RECHAZABLE
\```python
try:
    result = process_payment(amount)
except Exception as e:  # bare-ish, captura todo
    logger.error(e)     # sin contexto
    return None         # silencia el error
\```

**Por qué importa:** el segundo ejemplo silencia errores y dificulta debugging. El primero tiene specific exceptions, contexto en logs, y propaga con `from e`.

Ejemplos hablan más que reglas. El modelo los usa como pattern matching para detectar violaciones.


Permitir Override por Archivo o Directorio

Algunas excepciones son por archivo. Puedes documentarlas inline en el código con comentarios marcados:

# claude-code: skip-review
def legacy_function(camelCaseParam):
    # ... código que no queremos comentar
    pass

El bot puede ignorar archivos o funciones marcadas. Implementación en el script:

def filter_skipped_sections(diff_text: str) -> str:
    """Remover secciones marcadas como skip-review del diff."""
    lines = diff_text.split("\n")
    result = []
    skip = False
    for line in lines:
        if "claude-code: skip-review" in line:
            skip = True
        elif skip and line.strip().startswith("def ") and not line.startswith("+"):
            skip = False
        if not skip or line.startswith("---") or line.startswith("+++"):
            result.append(line)
    return "\n".join(result)

Trade-off: flexibilidad vs accountability. Si abusas del marker, el bot se vuelve inútil. Documentar criterio de uso en CLAUDE.md.


Configuración por Equipo en Monorepo

En monorepos, distintos sub-proyectos pueden tener distintas convenciones. CLAUDE.md jerárquico:

proyecto-monorepo/
├── CLAUDE.md           ← convenciones globales
├── apps/
│   ├── web/
│   │   └── CLAUDE.md   ← override para frontend
│   └── api/
│       └── CLAUDE.md   ← override para backend
└── packages/
    └── shared/
        └── CLAUDE.md   ← convenciones para shared lib

Script para cargar el CLAUDE.md más cercano a cada archivo modificado:

def load_conventions_for_file(file_path: str) -> str:
    """Buscar CLAUDE.md en el árbol ascendente."""
    path = Path(file_path).parent
    convention_files = []
    
    while path != path.parent:
        candidate = path / "CLAUDE.md"
        if candidate.exists():
            convention_files.insert(0, candidate.read_text())
        path = path.parent
    
    # Agregar el root
    if Path("CLAUDE.md").exists():
        convention_files.insert(0, Path("CLAUDE.md").read_text())
    
    # Combinar (las más específicas sobrescriben)
    return "\n\n---\n\n".join(convention_files)

Para PRs que tocan múltiples áreas del monorepo, puedes correr el bot por área con el CLAUDE.md relevante.


Iterar el CLAUDE.md Basándose en Comments del Bot

Una práctica que mejora el bot continuamente: cuando el bot comenta algo que el equipo desestima como falso positivo, agregar la excepción a CLAUDE.md.

PR semana 1:
Bot: "createOrder no sigue snake_case"
Developer: "ese archivo es legacy intencional"
Acción: agregar a CLAUDE.md → "src/legacy/orders.py mantiene camelCase"

PR semana 2:
Bot: ya no comenta el caso
Developer: "el bot mejoró"

PR semana 3:
Bot: "raise generic Exception es prohibido"
Developer: "ese try/except es para capturar errores externos del SDK"
Acción: agregar a CLAUDE.md → ejemplo de patrón aceptado para errores
externos del SDK

Cada falso positivo es información sobre cómo refinar las convenciones. Después de 4-6 semanas de iteración, CLAUDE.md describe con precisión las reglas reales del equipo.


Trampas Comunes

Error 1: CLAUDE.md genérico copiado de internet

Síntoma: Las "convenciones" no reflejan lo que el equipo realmente hace.

Por qué pasa: Copiar un template sin observación real del código.

Cómo corregir: Empezar leyendo 5-10 archivos del proyecto. Documentar qué patrones realmente se usan. Las convenciones documentadas deben ser observables en el código.

Error 2: CLAUDE.md sin ejemplos

Síntoma: El bot interpreta las reglas distinto a como el equipo las aplica.

Por qué pasa: Reglas abstractas tienen ambigüedad. "Type hints obligatorios" — ¿en todas las funciones o solo públicas? ¿en parámetros o solo en return?

Cómo corregir: Incluir ejemplos de código aceptable y rechazable. Eliminan ambigüedad.

Error 3: CLAUDE.md no se actualiza

Síntoma: El bot sigue comentando cosas que el equipo desestimó hace meses.

Por qué pasa: "Después actualizo CLAUDE.md" — no pasa.

Cómo corregir: Establecer ritmo: cada vez que el bot comenta un falso positivo, agregar a CLAUDE.md en el mismo PR de ajuste. Hace el archivo vivo.

Error 4: Demasiadas excepciones

Síntoma: CLAUDE.md tiene 30 archivos marcados como excepción. El bot básicamente no comenta nada.

Por qué pasa: El equipo prefiere desactivar reglas en lugar de aplicarlas.

Cómo corregir: Si el 50% del proyecto es excepción a una regla, la regla está mal. Reformular. Tal vez snake_case no es la convención real — es algo más matizado.

Error 5: CLAUDE.md sin prioridades

Síntoma: Todas las reglas tienen el mismo peso. El bot comenta cosas críticas y triviales con la misma severity.

Por qué pasa: Estructura plana de reglas.

Cómo corregir: Categorizar por severidad. "Reglas críticas (siempre comentar)" vs "Sugerencias (solo si impactante)". El prompt usa esa categorización para decidir severity.


Diagnóstico

Pregunta 1: ¿Tu CLAUDE.md está basado en observación real o en un template?

Si es template, las convenciones probablemente no reflejan el código real. Auditar leyendo 5-10 archivos.

Pregunta 2: ¿Tu CLAUDE.md incluye ejemplos de código aceptable y rechazable?

Sin ejemplos, las reglas son ambiguas. Ejemplos eliminan interpretación.

Pregunta 3: ¿Cuándo fue la última vez que actualizaste CLAUDE.md?

Si es "hace meses", está desactualizado. CLAUDE.md vivo es el más útil.

Pregunta 4: ¿Documentas tech debt conocido para que el bot no lo comente?

Si no, el bot va a comentar deuda que el equipo ya conoce y decidió postergar. Crea ruido.

Pregunta 5: ¿Las reglas de CLAUDE.md tienen prioridades/severidad?

Si todas tienen el mismo peso, todos los comments del bot suenan igual de importantes. Categorizar permite el bot priorizar bien.


Ejercicios

Ejercicio 1: Crear un CLAUDE.md mínimo basado en observación (Medio)

Para tu proyecto:

  1. Lee 5 archivos representativos
  2. Documenta las 3-5 convenciones más visibles
  3. Agrega 2 ejemplos (aceptable + rechazable) por convención
  4. Identifica 2-3 áreas de tech debt conocida que no quieres que el bot comente
Ver template inicial
# Project Conventions

## Stack
- [Lenguaje + versión]
- [Framework principal]

## Naming
- [Convención general]
- Excepciones:
  - [Archivo/dir y por qué]

## Patrones aceptados (con ejemplo)
### [Categoría 1]
✅ ACEPTABLE: [código]
❌ RECHAZABLE: [código]
**Por qué:** [explicación]

## Tech debt conocido (no comentar)
- [Archivo]: [razón]

Ejercicio 2: Cargar CLAUDE.md en el prompt (Fácil)

Modifica el script de review para que cargue CLAUDE.md y lo incluya en el prompt antes de pedir el review.

Ejercicio 3: Iterar sobre falsos positivos (Difícil)

Durante 2 semanas, anota cada falso positivo del bot. Al final:

  1. Categoriza los falsos positivos
  2. Para cada categoría, agrega una excepción específica a CLAUDE.md
  3. Verifica que en la siguiente semana el bot ya no comenta esas categorías

Resumen

  • CLAUDE.md es el source of truth de las convenciones del equipo
  • Basar en observación, no en templates genéricos
  • Ejemplos > reglas abstractas — eliminan ambigüedad
  • Documentar tech debt conocido evita comments sobre deuda asumida
  • Iterar el CLAUDE.md basándose en falsos positivos lo vuelve más útil con el tiempo
  • CLAUDE.md jerárquico en monorepos permite reglas por área
  • Categorizar por severidad ayuda al bot a priorizar comments

Próxima cápsula: 06 — Manejar PRs grandes con chunking. Tu bot funciona perfecto en PRs chicos y medianos. ¿Qué pasa cuando llega un PR de 80 archivos? La última cápsula del módulo cubre el caso extremo: chunking, priorización, y cuándo decir "este PR es demasiado grande para review automático".


Recursos Adicionales

  1. Anthropic: CLAUDE.md best practices — Documentación oficial
  2. Google Style Guides — Ejemplos de convenciones documentadas
  3. Airbnb JavaScript Style Guide — Convenciones populares como referencia
  4. PEP 8 — Convenciones default de Python
  5. Effective Python — Brett Slatkin — Patrones idiomáticos para CLAUDE.md
  6. Ruff configuration — Cómo otros linters codifican convenciones (referencia conceptual)