@saulwade/swl-ses 2.3.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +241 -199
- package/README.md +597 -597
- package/agentes/_intent-spec.md +73 -73
- package/agentes/_propose-step.md +90 -90
- package/agentes/accesibilidad-wcag-swl.md +2 -2
- package/agentes/arquitecto-swl.md +2 -2
- package/agentes/auto-evolucion-swl.md +2 -2
- package/agentes/backend-api-swl.md +2 -2
- package/agentes/backend-csharp-swl.md +2 -2
- package/agentes/backend-go-swl.md +2 -2
- package/agentes/backend-java-swl.md +2 -2
- package/agentes/backend-node-swl.md +2 -2
- package/agentes/backend-python-swl.md +2 -2
- package/agentes/backend-rust-swl.md +2 -2
- package/agentes/backend-workers-swl.md +2 -2
- package/agentes/cloud-infra-swl.md +2 -2
- package/agentes/consolidador-swl.md +2 -2
- package/agentes/datos-swl.md +2 -2
- package/agentes/depurador-swl.md +2 -2
- package/agentes/devops-ci-swl.md +2 -2
- package/agentes/disenador-ui-swl.md +2 -2
- package/agentes/documentador-swl.md +2 -2
- package/agentes/frontend-angular-swl.md +2 -2
- package/agentes/frontend-css-swl.md +2 -2
- package/agentes/frontend-react-swl.md +2 -2
- package/agentes/frontend-swl.md +2 -2
- package/agentes/frontend-tailwind-swl.md +2 -2
- package/agentes/gh-fix-ci-swl.md +275 -275
- package/agentes/implementador-swl.md +2 -2
- package/agentes/investigador-swl.md +2 -2
- package/agentes/investigador-ux-swl.md +2 -2
- package/agentes/llm-apps-swl.md +2 -2
- package/agentes/migrador-swl.md +2 -2
- package/agentes/mobile-android-swl.md +2 -2
- package/agentes/mobile-cross-swl.md +2 -2
- package/agentes/mobile-ios-swl.md +2 -2
- package/agentes/mobile-testing-swl.md +2 -2
- package/agentes/nemesis-auditor-swl.md +1 -1
- package/agentes/notificador-swl.md +2 -2
- package/agentes/observabilidad-swl.md +2 -2
- package/agentes/orquestador-swl.md +41 -14
- package/agentes/pagos-swl.md +2 -2
- package/agentes/perfilador-usuario-swl.md +2 -2
- package/agentes/planificador-swl.md +2 -2
- package/agentes/producto-prd-swl.md +2 -2
- package/agentes/red-team-swl.md +218 -218
- package/agentes/release-manager-swl.md +2 -2
- package/agentes/rendimiento-swl.md +2 -2
- package/agentes/resolutor-build-swl.md +2 -2
- package/agentes/revisor-angular-swl.md +2 -2
- package/agentes/revisor-codigo-swl.md +36 -3
- package/agentes/revisor-csharp-swl.md +2 -2
- package/agentes/revisor-go-swl.md +2 -2
- package/agentes/revisor-java-swl.md +2 -2
- package/agentes/revisor-kotlin-swl.md +2 -2
- package/agentes/revisor-nextjs-swl.md +2 -2
- package/agentes/revisor-php-swl.md +2 -2
- package/agentes/revisor-react-swl.md +2 -2
- package/agentes/revisor-rust-swl.md +2 -2
- package/agentes/revisor-seguridad-swl.md +2 -2
- package/agentes/revisor-swift-swl.md +2 -2
- package/agentes/revisor-typescript-swl.md +2 -2
- package/agentes/sre-swl.md +2 -2
- package/agentes/tdd-qa-swl.md +2 -2
- package/comandos/swl/briefing.md +119 -119
- package/comandos/swl/contexto.md +0 -2
- package/comandos/swl/contribuir.md +233 -233
- package/comandos/swl/deuda-codigo.md +97 -0
- package/comandos/swl/predecir.md +139 -139
- package/comandos/swl/sesiones.md +1 -1
- package/gateway/agent-executor.js +1 -1
- package/gateway/lib/event-channel.js +191 -191
- package/habilidades/agent-deep-links/SKILL.md +148 -148
- package/habilidades/agentes-como-servicio/SKILL.md +2 -2
- package/habilidades/angular-moderno/SKILL.md +24 -1
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -276
- package/habilidades/backend-async-postgres-testing/SKILL.md +215 -215
- package/habilidades/backend-error-design/SKILL.md +221 -221
- package/habilidades/backend-production-resilience/SKILL.md +288 -288
- package/habilidades/benchmark-memoria/SKILL.md +186 -186
- package/habilidades/calidad-anti-patrones-universales/SKILL.md +368 -368
- package/habilidades/calidad-contract-testing/SKILL.md +165 -165
- package/habilidades/calidad-mutation-testing/SKILL.md +170 -170
- package/habilidades/changelog-generator/scripts/parse-commits.js +367 -367
- package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -60
- package/habilidades/contenedores-docker/SKILL.md +3 -1
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/drift-detection/SKILL.md +179 -179
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +1 -1
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -57
- package/habilidades/eval-framework/SKILL.md +212 -212
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
- package/habilidades/harness-claude-code/SKILL.md +4 -4
- package/habilidades/harness-claude-code/recursos/disciplina-harness-regla.md +253 -252
- package/habilidades/legacy-code-rescue/SKILL.md +268 -267
- package/habilidades/meta-skills-estandar/SKILL.md +1 -1
- package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +2 -2
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
- package/habilidades/perfil-usuario/SKILL.md +200 -200
- package/habilidades/postgresql-experto/SKILL.md +3 -1
- package/habilidades/prevencion-sobreingenieria/SKILL.md +70 -92
- package/habilidades/prevencion-sobreingenieria/recursos/EXAMPLES.md +580 -580
- package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -0
- package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -0
- package/habilidades/proceso-ddia-fundamentos/SKILL.md +255 -255
- package/habilidades/proceso-ddia-streaming/SKILL.md +231 -231
- package/habilidades/proceso-debate-adversarial/recursos/personas.md +105 -105
- package/habilidades/proceso-discovery-machote/SKILL.md +157 -157
- package/habilidades/proceso-dynamic-workflows/SKILL.md +138 -138
- package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -65
- package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -65
- package/habilidades/proceso-intent-engineering/SKILL.md +269 -269
- package/habilidades/proceso-modular-split/SKILL.md +256 -256
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +2 -2
- package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
- package/habilidades/structured-outputs/SKILL.md +2 -2
- package/habilidades/swl-claudemd/recursos/contrato-aprender.md +83 -83
- package/habilidades/swl-claudemd/recursos/duplicacion-reglas-globales.md +85 -85
- package/habilidades/swl-claudemd/recursos/plantillas-init.md +94 -94
- package/habilidades/swl-dashboard/SKILL.md +2 -2
- package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -111
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +1 -1
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +1 -1
- package/hooks/audit-trail.js +4 -4
- package/hooks/calidad-pre-commit.js +15 -11
- package/hooks/captura-acciones-post.js +3 -2
- package/hooks/captura-acciones-session.js +3 -2
- package/hooks/ciclo-evolucion-subagente.js +26 -26
- package/hooks/ciclo-evolucion.js +26 -26
- package/hooks/claudemd-bloat-detector.js +161 -161
- package/hooks/claudemd-duplicacion-detector.js +170 -170
- package/hooks/contexto-iteracion.js +145 -144
- package/hooks/contexto-subagente.js +68 -0
- package/hooks/guardrail-modelo.js +14 -4
- package/hooks/inyeccion-contexto.js +12 -12
- package/hooks/lib/agent-routing.js +107 -107
- package/hooks/lib/auto-consolidator.js +335 -335
- package/hooks/lib/autonomia.js +208 -208
- package/hooks/lib/ciclo-evolucion.js +47 -47
- package/hooks/lib/deep-links.js +185 -185
- package/hooks/lib/error-classifier.js +308 -308
- package/hooks/lib/etapa-auto-evolucion.js +701 -701
- package/hooks/lib/etapa-metricas.js +388 -388
- package/hooks/lib/etapa-perfil-usuario.js +376 -376
- package/hooks/lib/loop-telemetry.js +321 -321
- package/hooks/lib/merkle-audit.js +96 -96
- package/hooks/lib/model-router.js +2 -2
- package/hooks/lib/propose-step.js +358 -358
- package/hooks/lib/provenance-tracker.js +191 -191
- package/hooks/lib/rate-limit-tracker.js +253 -253
- package/hooks/lib/resource-quota.js +122 -122
- package/hooks/lib/retry-jitter.js +165 -165
- package/hooks/lib/security-net.js +201 -201
- package/hooks/lib/skill-auditor.js +588 -588
- package/hooks/lib/sync-status.js +228 -228
- package/hooks/lib/taint-tracker.js +107 -107
- package/hooks/lib/text-similarity.js +241 -241
- package/hooks/lib/token-estimator.js +1 -0
- package/hooks/lib/toon-compressor.js +245 -245
- package/hooks/lib/usage-model.js +1 -1
- package/hooks/registro-turnos.js +210 -209
- package/hooks/session-briefing.js +98 -98
- package/hooks/spec-gate.js +212 -211
- package/hooks/sugerir-contribuir.js +2 -1
- package/hooks/sugerir-regenerar-inventario.js +171 -170
- package/hooks/tdd-gate.js +242 -241
- package/hooks/telemetria-skill-routing.js +100 -100
- package/hooks/validar-formato-post-subagente.js +140 -140
- package/hooks/validar-intent-spec.js +242 -242
- package/hooks/validar-memoria-hook.js +218 -218
- package/hooks/validar-planning-paths.js +134 -134
- package/instintos/autonomia.yaml +27 -27
- package/instintos/prompt-appendices.yaml +57 -57
- package/llms.txt +29 -29
- package/manifiestos/agent-output-schemas.json +57 -57
- package/manifiestos/canonical-hashes.json +2948 -1964
- package/manifiestos/hook-profiles.json +0 -2
- package/manifiestos/hooks-config.json +469 -477
- package/manifiestos/invariantes-criticos.json +30 -0
- package/manifiestos/modulos.json +1390 -1390
- package/manifiestos/planning-paths.json +44 -44
- package/manifiestos/skills-lock.json +1282 -1282
- package/package.json +93 -93
- package/plantillas/auditor-veto-template.md +105 -105
- package/plantillas/github-workflows/README.md +47 -47
- package/plantillas/github-workflows/release-please.yml +44 -44
- package/plantillas/github-workflows/swl-ci.yml +107 -107
- package/plantillas/github-workflows/swl-security.yml +51 -51
- package/plugin.json +369 -371
- package/reglas/accesibilidad.md +10 -10
- package/reglas/analisis-previo-tareas-grandes.md +172 -172
- package/reglas/api-diseno.md +9 -9
- package/reglas/arreglar-al-detectar.md +240 -240
- package/reglas/auditorias-documentales-estructurales.md +7 -7
- package/reglas/cloud-infra.md +8 -8
- package/reglas/consultar-vault-primero.md +195 -195
- package/reglas/debatir-antes-de-aceptar.md +158 -158
- package/reglas/fragmentos-compartidos.md +183 -183
- package/reglas/hooks.md +6 -6
- package/reglas/intent-engineering.md +218 -218
- package/reglas/markitdown.md +8 -8
- package/reglas/monitor-ci.md +309 -309
- package/reglas/patrones.md +6 -6
- package/reglas/sesiones-paralelas.md +180 -180
- package/reglas/sin-duplicacion-reglas-globales.md +182 -182
- package/reglas/skills-estandar.md +6 -6
- package/reglas/testing.md +7 -7
- package/reglas/tests-cleanup.md +224 -224
- package/reglas/usar-code-review-graph.md +155 -155
- package/reglas/usar-context7.md +226 -226
- package/reglas/verificar-citas-normativas.md +548 -548
- package/schemas/agent-frontmatter.schema.json +5 -3
- package/schemas/agent-message.schema.json +73 -73
- package/schemas/agent-output-implementacion.schema.json +114 -114
- package/schemas/agent-output-planificacion.schema.json +150 -150
- package/schemas/agent-output-review.schema.json +98 -98
- package/schemas/diary-entry.schema.json +112 -112
- package/schemas/hook-profiles.schema.json +54 -54
- package/schemas/hooks-config.schema.json +89 -89
- package/schemas/modulos.schema.json +38 -38
- package/schemas/perfiles.schema.json +36 -36
- package/schemas/plugin.schema.json +77 -77
- package/schemas/skill-evals.schema.json +119 -119
- package/schemas/skill-frontmatter.schema.json +245 -245
- package/scripts/audit-tools/audit-history.js +330 -330
- package/scripts/audit-tools/bundle-tracker.js +290 -290
- package/scripts/audit-tools/canary-monitor.js +352 -352
- package/scripts/audit-tools/code-profiler.js +605 -605
- package/scripts/audit-tools/dep-doctor.js +320 -320
- package/scripts/audit-tools/env-validator.js +206 -206
- package/scripts/audit-tools/lib/fs-walk.js +48 -48
- package/scripts/audit-tools/lib/output.js +23 -23
- package/scripts/audit-tools/migration-checker.js +392 -392
- package/scripts/audit-tools/pentest-scanner.js +1436 -1436
- package/scripts/benchmark-memoria.js +167 -167
- package/scripts/cli/aprobar-plan.js +73 -73
- package/scripts/cli/briefing.js +23 -23
- package/scripts/cli/ciclo-evolucion.js +26 -26
- package/scripts/cli/configurar-ci.js +40 -40
- package/scripts/cli/derivar-feature-list.js +25 -25
- package/scripts/cli/detectar-host.js +27 -27
- package/scripts/cli/diary-entry.js +69 -69
- package/scripts/cli/execution-state.js +18 -18
- package/scripts/cli/gateway-notify.js +41 -41
- package/scripts/cli/liberar-fase.js +42 -42
- package/scripts/cli/loop-telemetry.js +125 -125
- package/scripts/cli/mark-evolved.js +56 -56
- package/scripts/cli/metricas-dora.js +26 -26
- package/scripts/cli/near-duplicate.js +55 -55
- package/scripts/cli/notificaciones.js +123 -123
- package/scripts/cli/propose-step.js +29 -29
- package/scripts/cli/schedule-parse.js +19 -19
- package/scripts/cli/sugerir-modelo.js +20 -20
- package/scripts/cli/verificar-plan.js +36 -36
- package/scripts/cli/verificar-trazabilidad.js +35 -35
- package/scripts/configurar-branch-protection.js +418 -418
- package/scripts/detectar-aprendizajes-duplicados.js +151 -151
- package/scripts/field-report.js +199 -199
- package/scripts/generar-checklists-consolidados.js +273 -273
- package/scripts/generar-matriz-lenguajes.js +271 -271
- package/scripts/instalador.js +4 -1
- package/scripts/lib/artefactos-python.js +43 -43
- package/scripts/lib/auditar-invocaciones-comandos.js +104 -104
- package/scripts/lib/benchmark-metrics.js +160 -160
- package/scripts/lib/budget-enforcer.js +252 -252
- package/scripts/lib/ci-reader.js +193 -193
- package/scripts/lib/claude-sessions.js +1 -0
- package/scripts/lib/configurar-ci.js +380 -380
- package/scripts/lib/contadores-inventario.js +217 -217
- package/scripts/lib/detectar-host-swl.js +175 -175
- package/scripts/lib/detectar-stack-detallado.js +307 -307
- package/scripts/lib/detector-autoduplicacion-intra-archivo.js +234 -234
- package/scripts/lib/detector-reglas-duplicadas.js +220 -220
- package/scripts/lib/diary-entry.js +234 -234
- package/scripts/lib/eval-metrics-store.js +218 -218
- package/scripts/lib/eval-quality.js +171 -171
- package/scripts/lib/eval-schemas.js +144 -144
- package/scripts/lib/eval-self-correct.js +106 -106
- package/scripts/lib/eval-validator.js +185 -185
- package/scripts/lib/evidencia-release.js +322 -322
- package/scripts/lib/gate-hooks-requires.js +249 -249
- package/scripts/lib/gate-licencias.js +212 -212
- package/scripts/lib/git-metricas.js +257 -257
- package/scripts/lib/jaccard-similarity.js +98 -98
- package/scripts/lib/longmemeval-runner.js +125 -125
- package/scripts/lib/metricas-dora.js +204 -204
- package/scripts/lib/npm-version.js +261 -261
- package/scripts/lib/paquetes-conocidos.js +50 -50
- package/scripts/lib/plan-lock.js +275 -275
- package/scripts/lib/pr-analyzer.js +399 -399
- package/scripts/lib/preservar-usuario.js +39 -5
- package/scripts/lib/prompt-builder.js +264 -264
- package/scripts/lib/reglas-globales-conocidas.json +180 -180
- package/scripts/lib/resolver-plan-fase.js +37 -37
- package/scripts/lib/rrf-fusion.js +175 -175
- package/scripts/lib/schema-version.js +164 -164
- package/scripts/lib/scoring-instintos.js +277 -277
- package/scripts/lib/semantic-search.js +252 -252
- package/scripts/lib/tool-cost-analyzer.js +1 -0
- package/scripts/limpiar-artefactos-python.js +131 -131
- package/scripts/migrar-csv-a-array.js +168 -168
- package/scripts/migrar-fase-dominio.js +200 -200
- package/scripts/publicar.js +497 -497
- package/scripts/run-eval.js +141 -141
- package/scripts/tui/componentes/selector-multi.js +189 -189
- package/scripts/tui/componentes/selector-unico.js +158 -158
- package/scripts/tui/ejecutores.js +375 -375
- package/scripts/tui/index.js +162 -162
- package/scripts/tui/lib/colores.js +129 -129
- package/scripts/tui/lib/render.js +264 -264
- package/scripts/tui/lib/teclas.js +113 -113
- package/scripts/tui/pantallas/inspect.js +173 -173
- package/scripts/tui/pantallas/install-wizard.js +334 -334
- package/scripts/tui/pantallas/menu-principal.js +52 -52
- package/scripts/tui/pantallas/progreso.js +274 -274
- package/scripts/tui/pantallas/resumen.js +132 -132
- package/scripts/tui/pantallas/uninstall-wizard.js +208 -208
- package/scripts/tui/pantallas/update-wizard.js +232 -232
- package/scripts/tui/pantallas/welcome.js +187 -187
- package/scripts/validar-userland-vacio.js +110 -110
- package/scripts/validar.js +1 -1
- package/scripts/verificar-release.js +51 -0
- package/hooks/lib/context-compressor.js +0 -657
- package/hooks/linea-estado.js +0 -326
- package/hooks/monitor-contexto.js +0 -373
|
@@ -1,368 +1,368 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: calidad-anti-patrones-universales
|
|
3
|
-
description: >
|
|
4
|
-
Catálogo de 10 anti-patrones universales de calidad de código, nombrados con
|
|
5
|
-
vocabulario común y ejemplos MAL/BIEN en Python y TypeScript. Cubre auditoría
|
|
6
|
-
de reutilización, proliferación de parámetros, abstracciones con fuga, tipado
|
|
7
|
-
por string, condicionales anidadas, variantes copy-paste, actualizaciones sin
|
|
8
|
-
efecto, race conditions TOCTOU, operaciones demasiado amplias y estado
|
|
9
|
-
redundante. Cargar desde revisor-codigo-swl o revisores especializados cuando
|
|
10
|
-
el código bajo revisión presenta señales (>4 parámetros, magic strings en
|
|
11
|
-
condiciones, if anidadas ≥3 niveles, queries en loops, dos funciones casi
|
|
12
|
-
idénticas, mutaciones de estado sin guard). NO sustituye a los revisores —
|
|
13
|
-
los enriquece con vocabulario nombrado para reportes consistentes.
|
|
14
|
-
version: "1.0.0"
|
|
15
|
-
herramientasPermitidas: [Read, Grep, Glob]
|
|
16
|
-
exclusiones:
|
|
17
|
-
- "No cargar como sustituto de revisor-codigo-swl ni de los revisores especializados — este skill aporta vocabulario y ejemplos, los revisores ejecutan el análisis."
|
|
18
|
-
- "No cargar para code review con foco en seguridad (OWASP, inyección, autenticación) — para eso cargar checklist-seguridad."
|
|
19
|
-
- "No cargar para análisis de rendimiento (queries lentas, profiling) — eso corresponde a rendimiento-swl + performance-baseline."
|
|
20
|
-
- "No cargar para refactor agresivo de código heredado — eso corresponde a legacy-code-rescue."
|
|
21
|
-
evolvable: true
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
# Habilidad: Catálogo de anti-patrones universales de calidad
|
|
25
|
-
|
|
26
|
-
Catálogo de 10 anti-patrones nombrados que aparecen cross-lenguaje. Cada entrada
|
|
27
|
-
incluye señal de detección, ejemplo MAL, ejemplo BIEN y vocabulario para el
|
|
28
|
-
reporte del revisor.
|
|
29
|
-
|
|
30
|
-
## Cuándo cargar
|
|
31
|
-
|
|
32
|
-
Desde `revisor-codigo-swl` o un revisor especializado (`revisor-typescript-swl`,
|
|
33
|
-
`revisor-react-swl`, `revisor-python-swl`, etc.) cuando el código bajo revisión
|
|
34
|
-
muestra al menos una de las señales:
|
|
35
|
-
|
|
36
|
-
- Función con ≥5 parámetros posicionales
|
|
37
|
-
- Condicionales anidadas con ≥3 niveles
|
|
38
|
-
- Magic strings repetidos en condiciones o switches
|
|
39
|
-
- Dos funciones que difieren solo en nombres de campos
|
|
40
|
-
- Acceso a propiedades de un ORM o cliente HTTP desde código de negocio
|
|
41
|
-
- Llamadas a BD dentro de un `for` (loops con `await` en cada iteración)
|
|
42
|
-
- Mutación de estado sin guard previo
|
|
43
|
-
- Función con verbo genérico (`process`, `handle`, `manage`) que afecta múltiples dominios
|
|
44
|
-
|
|
45
|
-
## Cuándo NO cargar
|
|
46
|
-
|
|
47
|
-
- Code review enfocado en seguridad → `checklist-seguridad`
|
|
48
|
-
- Profiling y queries lentas → `rendimiento-swl` + `performance-baseline`
|
|
49
|
-
- Refactor de código heredado → `legacy-code-rescue`
|
|
50
|
-
- Implementación de feature nueva → cargar el skill del stack (`fastapi-experto`, `react-experto`, etc.)
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## Los 10 anti-patrones
|
|
55
|
-
|
|
56
|
-
### 1. Auditoría de reutilización (reuse audit)
|
|
57
|
-
|
|
58
|
-
Antes de aceptar código nuevo, buscar utilidades existentes que ya hagan lo mismo.
|
|
59
|
-
|
|
60
|
-
**MAL** — debounce hecho a mano cuando `utils/debounce.ts` ya existe:
|
|
61
|
-
```typescript
|
|
62
|
-
function debounce(fn: Function, ms: number) {
|
|
63
|
-
let timer: ReturnType<typeof setTimeout>;
|
|
64
|
-
return (...args: unknown[]) => {
|
|
65
|
-
clearTimeout(timer);
|
|
66
|
-
timer = setTimeout(() => fn(...args), ms);
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
**BIEN** — importar la utilidad del proyecto:
|
|
72
|
-
```typescript
|
|
73
|
-
import { debounce } from '@/utils/debounce';
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
**Reporte**: "Reuse audit — `<archivo:línea>` reimplementa `<utilidad-existente>`. Importar en su lugar."
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
### 2. Proliferación de parámetros (parameter sprawl)
|
|
81
|
-
|
|
82
|
-
Una función con ≥5 parámetros posicionales no escala. Cada nueva necesidad agrega otro.
|
|
83
|
-
|
|
84
|
-
**MAL**:
|
|
85
|
-
```python
|
|
86
|
-
def crear_usuario(nombre, email, rol, equipo, activo, avatar_url, zona_horaria):
|
|
87
|
-
...
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
**BIEN** — objeto de parámetros con defaults:
|
|
91
|
-
```python
|
|
92
|
-
from dataclasses import dataclass
|
|
93
|
-
|
|
94
|
-
@dataclass
|
|
95
|
-
class CrearUsuarioParams:
|
|
96
|
-
nombre: str
|
|
97
|
-
email: str
|
|
98
|
-
rol: Rol = Rol.MIEMBRO
|
|
99
|
-
equipo: str | None = None
|
|
100
|
-
activo: bool = True
|
|
101
|
-
avatar_url: str | None = None
|
|
102
|
-
zona_horaria: str = "America/Mexico_City"
|
|
103
|
-
|
|
104
|
-
def crear_usuario(params: CrearUsuarioParams) -> Usuario:
|
|
105
|
-
...
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
**Reporte**: "Parameter sprawl — `<función>` recibe N parámetros. Consolidar en dataclass/interface."
|
|
109
|
-
|
|
110
|
-
Señal adicional: parámetros booleanos mutuamente exclusivos (`activar_x`, `desactivar_y`) → enum o strategy pattern.
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
### 3. Abstracciones con fuga (leaky abstractions)
|
|
115
|
-
|
|
116
|
-
Exponer detalles internos obliga al llamador a conocerlos.
|
|
117
|
-
|
|
118
|
-
**MAL** — el caller recibe un objeto ORM:
|
|
119
|
-
```python
|
|
120
|
-
def listar_usuarios():
|
|
121
|
-
return session.query(Usuario).filter(Usuario.activo == True).all()
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
**BIEN** — el caller recibe un DTO de dominio:
|
|
125
|
-
```python
|
|
126
|
-
def listar_usuarios_activos() -> list[UsuarioDTO]:
|
|
127
|
-
filas = usuario_repo.find_activos()
|
|
128
|
-
return [UsuarioDTO.from_row(f) for f in filas]
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
**Reporte**: "Leaky abstraction — `<función>` retorna objeto ORM/cliente; envolver en DTO."
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
### 4. Tipado por string (stringly-typed)
|
|
136
|
-
|
|
137
|
-
Magic strings esparcidos por el código en lugar de constantes o enums.
|
|
138
|
-
|
|
139
|
-
**MAL**:
|
|
140
|
-
```typescript
|
|
141
|
-
if (usuario.rol === 'admin') { ... }
|
|
142
|
-
if (usuario.rol === 'Admin') { ... } // typo silencioso
|
|
143
|
-
if (pedido.estado === 'pendiente') { ... }
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
**BIEN** — enum tipado:
|
|
147
|
-
```typescript
|
|
148
|
-
enum Rol { Admin = 'admin', Miembro = 'miembro' }
|
|
149
|
-
enum EstadoPedido { Pendiente = 'pendiente', Confirmado = 'confirmado' }
|
|
150
|
-
|
|
151
|
-
if (usuario.rol === Rol.Admin) { ... }
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
**Reporte**: "Stringly-typed — `<archivo:línea>` compara contra string literal repetido. Extraer enum/constante."
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
### 5. Condicionales anidadas (nested conditionals)
|
|
159
|
-
|
|
160
|
-
`if/else` con ≥3 niveles o cadenas ternarias rompen la lectura lineal.
|
|
161
|
-
|
|
162
|
-
**MAL**:
|
|
163
|
-
```python
|
|
164
|
-
if usuario:
|
|
165
|
-
if usuario.activo:
|
|
166
|
-
if usuario.tiene_permiso("editar"):
|
|
167
|
-
if recurso.disponible:
|
|
168
|
-
return editar(usuario, recurso)
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
**BIEN** — early return con guard clauses:
|
|
172
|
-
```python
|
|
173
|
-
def editar_recurso(usuario, recurso):
|
|
174
|
-
if not usuario or not usuario.activo:
|
|
175
|
-
raise UsuarioInvalidoError
|
|
176
|
-
if not usuario.tiene_permiso("editar"):
|
|
177
|
-
raise PermisoDenegadoError
|
|
178
|
-
if not recurso.disponible:
|
|
179
|
-
raise RecursoNoDisponibleError
|
|
180
|
-
return editar(usuario, recurso)
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
**Reporte**: "Nested conditionals — `<función>` tiene N niveles de anidamiento. Aplicar guard clauses con early return."
|
|
184
|
-
|
|
185
|
-
---
|
|
186
|
-
|
|
187
|
-
### 6. Variantes copy-paste (copy-paste variants)
|
|
188
|
-
|
|
189
|
-
Dos bloques de código casi idénticos que solo difieren en nombres de campos o constantes.
|
|
190
|
-
|
|
191
|
-
**MAL**:
|
|
192
|
-
```python
|
|
193
|
-
def calcular_iva(monto):
|
|
194
|
-
return monto * 0.16
|
|
195
|
-
|
|
196
|
-
def calcular_ieps(monto):
|
|
197
|
-
return monto * 0.08
|
|
198
|
-
|
|
199
|
-
def calcular_isr(monto):
|
|
200
|
-
return monto * 0.30
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
**BIEN** — abstracción con tabla de tasas:
|
|
204
|
-
```python
|
|
205
|
-
TASAS = {"iva": 0.16, "ieps": 0.08, "isr": 0.30}
|
|
206
|
-
|
|
207
|
-
def calcular_impuesto(monto: Decimal, tipo: str) -> Decimal:
|
|
208
|
-
return monto * TASAS[tipo]
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
**Reporte**: "Copy-paste variants — funciones `<a>`, `<b>` difieren solo en constantes. Consolidar."
|
|
212
|
-
|
|
213
|
-
Cuidado: NO consolidar si las funciones evolucionan independientemente por razones de negocio distintas (regla de tres).
|
|
214
|
-
|
|
215
|
-
---
|
|
216
|
-
|
|
217
|
-
### 7. Actualizaciones sin efecto (no-op updates)
|
|
218
|
-
|
|
219
|
-
Disparar `setState`, `UPDATE` o re-render sin verificar que el valor cambió.
|
|
220
|
-
|
|
221
|
-
**MAL** — re-render cada vez aunque `usuario` sea el mismo:
|
|
222
|
-
```typescript
|
|
223
|
-
useEffect(() => {
|
|
224
|
-
setUsuarioActivo(usuario);
|
|
225
|
-
}, [usuario]);
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
**BIEN** — comparar antes de actualizar:
|
|
229
|
-
```typescript
|
|
230
|
-
useEffect(() => {
|
|
231
|
-
if (usuario && usuario.id !== usuarioActivoActual?.id) {
|
|
232
|
-
setUsuarioActivo(usuario);
|
|
233
|
-
}
|
|
234
|
-
}, [usuario, usuarioActivoActual]);
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
**Reporte**: "No-op update — `<archivo:línea>` actualiza estado sin guard de cambio. Verificar si el valor difiere."
|
|
238
|
-
|
|
239
|
-
---
|
|
240
|
-
|
|
241
|
-
### 8. TOCTOU — Time-of-Check vs Time-of-Use
|
|
242
|
-
|
|
243
|
-
Entre la verificación y el uso, el estado puede cambiar. Race condition silenciosa.
|
|
244
|
-
|
|
245
|
-
**MAL**:
|
|
246
|
-
```python
|
|
247
|
-
if os.path.exists(ruta):
|
|
248
|
-
with open(ruta) as f: # archivo puede haber desaparecido aquí
|
|
249
|
-
return f.read()
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
**BIEN** — intentar y manejar excepción:
|
|
253
|
-
```python
|
|
254
|
-
try:
|
|
255
|
-
with open(ruta) as f:
|
|
256
|
-
return f.read()
|
|
257
|
-
except FileNotFoundError:
|
|
258
|
-
return None
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
**MAL** en BD — check-then-act sin transacción:
|
|
262
|
-
```python
|
|
263
|
-
saldo = obtener_saldo(cuenta_id)
|
|
264
|
-
if saldo >= monto:
|
|
265
|
-
debitar(cuenta_id, monto) # otro proceso pudo cambiar el saldo
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
**BIEN** — lock pesimista o transacción atómica:
|
|
269
|
-
```python
|
|
270
|
-
async with conn.transaction():
|
|
271
|
-
saldo = await obtener_saldo_for_update(cuenta_id) # SELECT ... FOR UPDATE
|
|
272
|
-
if saldo < monto:
|
|
273
|
-
raise SaldoInsuficienteError
|
|
274
|
-
await debitar(cuenta_id, monto)
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
**Reporte**: "TOCTOU — `<archivo:línea>` verifica condición fuera de transacción/lock. Reordenar a try-catch o SELECT FOR UPDATE."
|
|
278
|
-
|
|
279
|
-
---
|
|
280
|
-
|
|
281
|
-
### 9. Operaciones demasiado amplias (overly broad operations)
|
|
282
|
-
|
|
283
|
-
Funciones con verbos genéricos (`process`, `handle`, `manage`) que tocan múltiples dominios.
|
|
284
|
-
|
|
285
|
-
**MAL**:
|
|
286
|
-
```typescript
|
|
287
|
-
async function procesarPedido(pedido: Pedido) {
|
|
288
|
-
await validarCliente(pedido.clienteId);
|
|
289
|
-
await debitarInventario(pedido.items);
|
|
290
|
-
await cobrarTarjeta(pedido.pago);
|
|
291
|
-
await enviarEmail(pedido.clienteId);
|
|
292
|
-
await registrarAuditoria(pedido);
|
|
293
|
-
await notificarAlmacen(pedido);
|
|
294
|
-
}
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
**BIEN** — fases nombradas, una responsabilidad por función:
|
|
298
|
-
```typescript
|
|
299
|
-
async function emitirPedido(pedido: Pedido) {
|
|
300
|
-
const validado = await validarPedido(pedido);
|
|
301
|
-
const cobrado = await procesarCobro(validado);
|
|
302
|
-
const confirmado = await confirmarPedido(cobrado);
|
|
303
|
-
await notificarParticipantes(confirmado);
|
|
304
|
-
return confirmado;
|
|
305
|
-
}
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
**Reporte**: "Overly broad operation — `<función>` orquesta N dominios distintos. Dividir por fase o extraer use cases."
|
|
309
|
-
|
|
310
|
-
---
|
|
311
|
-
|
|
312
|
-
### 10. Estado redundante (redundant state)
|
|
313
|
-
|
|
314
|
-
Mantener estado derivable de otro estado introduce drift garantizado.
|
|
315
|
-
|
|
316
|
-
**MAL**:
|
|
317
|
-
```typescript
|
|
318
|
-
const [items, setItems] = useState<Item[]>([]);
|
|
319
|
-
const [total, setTotal] = useState(0); // derivable de items
|
|
320
|
-
const [vacio, setVacio] = useState(true); // derivable de items.length
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
**BIEN** — derivar con `useMemo`:
|
|
324
|
-
```typescript
|
|
325
|
-
const [items, setItems] = useState<Item[]>([]);
|
|
326
|
-
const total = useMemo(() => items.reduce((s, i) => s + i.precio, 0), [items]);
|
|
327
|
-
const vacio = items.length === 0;
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
**Reporte**: "Redundant state — `<componente>` mantiene N campos derivables de uno solo. Computar con `useMemo` o getter."
|
|
331
|
-
|
|
332
|
-
---
|
|
333
|
-
|
|
334
|
-
## Formato de reporte sugerido
|
|
335
|
-
|
|
336
|
-
Cuando un revisor detecta uno o más anti-patrones, integrarlo en su reporte
|
|
337
|
-
estándar con esta forma:
|
|
338
|
-
|
|
339
|
-
```markdown
|
|
340
|
-
### Anti-patrones detectados
|
|
341
|
-
|
|
342
|
-
| # | Patrón | Archivo:línea | Severidad | Remediación |
|
|
343
|
-
|---|---|---|---|---|
|
|
344
|
-
| 1 | Parameter sprawl | usuarios/service.py:42 | P1 | Extraer a `CrearUsuarioParams` |
|
|
345
|
-
| 2 | Stringly-typed | pedidos/handler.ts:88 | P2 | Crear `enum EstadoPedido` |
|
|
346
|
-
| 3 | TOCTOU | inventario/repo.py:120 | P0 | Envolver en `SELECT FOR UPDATE` |
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
Mapeo a severidades estándar de revisor-codigo-swl:
|
|
350
|
-
- **P0** (mata credibilidad): TOCTOU sin lock cuando hay concurrencia real
|
|
351
|
-
- **P1** (arreglar antes de merge): parameter sprawl >6, leaky abstraction cross-capa
|
|
352
|
-
- **P2** (pulir): stringly-typed con 2-3 usos, no-op updates cosméticos
|
|
353
|
-
|
|
354
|
-
## Lo que esta skill NO hace
|
|
355
|
-
|
|
356
|
-
- No reemplaza al revisor — el revisor ejecuta el análisis y decide.
|
|
357
|
-
- No verifica seguridad (eso es `checklist-seguridad`).
|
|
358
|
-
- No mide rendimiento (eso es `rendimiento-swl`).
|
|
359
|
-
- No corrige código — solo nombra el patrón y propone forma idiomática.
|
|
360
|
-
|
|
361
|
-
## Origen
|
|
362
|
-
|
|
363
|
-
Adaptación curada en es-MX de `reference/code-quality-universal.md` del repo
|
|
364
|
-
`anthropic-skills/code-review-skill` analizado en `temp/code-review-skill-main/`
|
|
365
|
-
(sesión 2026-05-24). Los 10 anti-patrones del catálogo original se tradujeron
|
|
366
|
-
y se ajustaron al stack Python + TypeScript predominante en proyectos SWL.
|
|
367
|
-
Material original bajo licencia compatible; adaptación con vocabulario
|
|
368
|
-
es-MX y ejemplos contextualizados.
|
|
1
|
+
---
|
|
2
|
+
name: calidad-anti-patrones-universales
|
|
3
|
+
description: >
|
|
4
|
+
Catálogo de 10 anti-patrones universales de calidad de código, nombrados con
|
|
5
|
+
vocabulario común y ejemplos MAL/BIEN en Python y TypeScript. Cubre auditoría
|
|
6
|
+
de reutilización, proliferación de parámetros, abstracciones con fuga, tipado
|
|
7
|
+
por string, condicionales anidadas, variantes copy-paste, actualizaciones sin
|
|
8
|
+
efecto, race conditions TOCTOU, operaciones demasiado amplias y estado
|
|
9
|
+
redundante. Cargar desde revisor-codigo-swl o revisores especializados cuando
|
|
10
|
+
el código bajo revisión presenta señales (>4 parámetros, magic strings en
|
|
11
|
+
condiciones, if anidadas ≥3 niveles, queries en loops, dos funciones casi
|
|
12
|
+
idénticas, mutaciones de estado sin guard). NO sustituye a los revisores —
|
|
13
|
+
los enriquece con vocabulario nombrado para reportes consistentes.
|
|
14
|
+
version: "1.0.0"
|
|
15
|
+
herramientasPermitidas: [Read, Grep, Glob]
|
|
16
|
+
exclusiones:
|
|
17
|
+
- "No cargar como sustituto de revisor-codigo-swl ni de los revisores especializados — este skill aporta vocabulario y ejemplos, los revisores ejecutan el análisis."
|
|
18
|
+
- "No cargar para code review con foco en seguridad (OWASP, inyección, autenticación) — para eso cargar checklist-seguridad."
|
|
19
|
+
- "No cargar para análisis de rendimiento (queries lentas, profiling) — eso corresponde a rendimiento-swl + performance-baseline."
|
|
20
|
+
- "No cargar para refactor agresivo de código heredado — eso corresponde a legacy-code-rescue."
|
|
21
|
+
evolvable: true
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# Habilidad: Catálogo de anti-patrones universales de calidad
|
|
25
|
+
|
|
26
|
+
Catálogo de 10 anti-patrones nombrados que aparecen cross-lenguaje. Cada entrada
|
|
27
|
+
incluye señal de detección, ejemplo MAL, ejemplo BIEN y vocabulario para el
|
|
28
|
+
reporte del revisor.
|
|
29
|
+
|
|
30
|
+
## Cuándo cargar
|
|
31
|
+
|
|
32
|
+
Desde `revisor-codigo-swl` o un revisor especializado (`revisor-typescript-swl`,
|
|
33
|
+
`revisor-react-swl`, `revisor-python-swl`, etc.) cuando el código bajo revisión
|
|
34
|
+
muestra al menos una de las señales:
|
|
35
|
+
|
|
36
|
+
- Función con ≥5 parámetros posicionales
|
|
37
|
+
- Condicionales anidadas con ≥3 niveles
|
|
38
|
+
- Magic strings repetidos en condiciones o switches
|
|
39
|
+
- Dos funciones que difieren solo en nombres de campos
|
|
40
|
+
- Acceso a propiedades de un ORM o cliente HTTP desde código de negocio
|
|
41
|
+
- Llamadas a BD dentro de un `for` (loops con `await` en cada iteración)
|
|
42
|
+
- Mutación de estado sin guard previo
|
|
43
|
+
- Función con verbo genérico (`process`, `handle`, `manage`) que afecta múltiples dominios
|
|
44
|
+
|
|
45
|
+
## Cuándo NO cargar
|
|
46
|
+
|
|
47
|
+
- Code review enfocado en seguridad → `checklist-seguridad`
|
|
48
|
+
- Profiling y queries lentas → `rendimiento-swl` + `performance-baseline`
|
|
49
|
+
- Refactor de código heredado → `legacy-code-rescue`
|
|
50
|
+
- Implementación de feature nueva → cargar el skill del stack (`fastapi-experto`, `react-experto`, etc.)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Los 10 anti-patrones
|
|
55
|
+
|
|
56
|
+
### 1. Auditoría de reutilización (reuse audit)
|
|
57
|
+
|
|
58
|
+
Antes de aceptar código nuevo, buscar utilidades existentes que ya hagan lo mismo.
|
|
59
|
+
|
|
60
|
+
**MAL** — debounce hecho a mano cuando `utils/debounce.ts` ya existe:
|
|
61
|
+
```typescript
|
|
62
|
+
function debounce(fn: Function, ms: number) {
|
|
63
|
+
let timer: ReturnType<typeof setTimeout>;
|
|
64
|
+
return (...args: unknown[]) => {
|
|
65
|
+
clearTimeout(timer);
|
|
66
|
+
timer = setTimeout(() => fn(...args), ms);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**BIEN** — importar la utilidad del proyecto:
|
|
72
|
+
```typescript
|
|
73
|
+
import { debounce } from '@/utils/debounce';
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Reporte**: "Reuse audit — `<archivo:línea>` reimplementa `<utilidad-existente>`. Importar en su lugar."
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### 2. Proliferación de parámetros (parameter sprawl)
|
|
81
|
+
|
|
82
|
+
Una función con ≥5 parámetros posicionales no escala. Cada nueva necesidad agrega otro.
|
|
83
|
+
|
|
84
|
+
**MAL**:
|
|
85
|
+
```python
|
|
86
|
+
def crear_usuario(nombre, email, rol, equipo, activo, avatar_url, zona_horaria):
|
|
87
|
+
...
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**BIEN** — objeto de parámetros con defaults:
|
|
91
|
+
```python
|
|
92
|
+
from dataclasses import dataclass
|
|
93
|
+
|
|
94
|
+
@dataclass
|
|
95
|
+
class CrearUsuarioParams:
|
|
96
|
+
nombre: str
|
|
97
|
+
email: str
|
|
98
|
+
rol: Rol = Rol.MIEMBRO
|
|
99
|
+
equipo: str | None = None
|
|
100
|
+
activo: bool = True
|
|
101
|
+
avatar_url: str | None = None
|
|
102
|
+
zona_horaria: str = "America/Mexico_City"
|
|
103
|
+
|
|
104
|
+
def crear_usuario(params: CrearUsuarioParams) -> Usuario:
|
|
105
|
+
...
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Reporte**: "Parameter sprawl — `<función>` recibe N parámetros. Consolidar en dataclass/interface."
|
|
109
|
+
|
|
110
|
+
Señal adicional: parámetros booleanos mutuamente exclusivos (`activar_x`, `desactivar_y`) → enum o strategy pattern.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### 3. Abstracciones con fuga (leaky abstractions)
|
|
115
|
+
|
|
116
|
+
Exponer detalles internos obliga al llamador a conocerlos.
|
|
117
|
+
|
|
118
|
+
**MAL** — el caller recibe un objeto ORM:
|
|
119
|
+
```python
|
|
120
|
+
def listar_usuarios():
|
|
121
|
+
return session.query(Usuario).filter(Usuario.activo == True).all()
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**BIEN** — el caller recibe un DTO de dominio:
|
|
125
|
+
```python
|
|
126
|
+
def listar_usuarios_activos() -> list[UsuarioDTO]:
|
|
127
|
+
filas = usuario_repo.find_activos()
|
|
128
|
+
return [UsuarioDTO.from_row(f) for f in filas]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Reporte**: "Leaky abstraction — `<función>` retorna objeto ORM/cliente; envolver en DTO."
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### 4. Tipado por string (stringly-typed)
|
|
136
|
+
|
|
137
|
+
Magic strings esparcidos por el código en lugar de constantes o enums.
|
|
138
|
+
|
|
139
|
+
**MAL**:
|
|
140
|
+
```typescript
|
|
141
|
+
if (usuario.rol === 'admin') { ... }
|
|
142
|
+
if (usuario.rol === 'Admin') { ... } // typo silencioso
|
|
143
|
+
if (pedido.estado === 'pendiente') { ... }
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**BIEN** — enum tipado:
|
|
147
|
+
```typescript
|
|
148
|
+
enum Rol { Admin = 'admin', Miembro = 'miembro' }
|
|
149
|
+
enum EstadoPedido { Pendiente = 'pendiente', Confirmado = 'confirmado' }
|
|
150
|
+
|
|
151
|
+
if (usuario.rol === Rol.Admin) { ... }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Reporte**: "Stringly-typed — `<archivo:línea>` compara contra string literal repetido. Extraer enum/constante."
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### 5. Condicionales anidadas (nested conditionals)
|
|
159
|
+
|
|
160
|
+
`if/else` con ≥3 niveles o cadenas ternarias rompen la lectura lineal.
|
|
161
|
+
|
|
162
|
+
**MAL**:
|
|
163
|
+
```python
|
|
164
|
+
if usuario:
|
|
165
|
+
if usuario.activo:
|
|
166
|
+
if usuario.tiene_permiso("editar"):
|
|
167
|
+
if recurso.disponible:
|
|
168
|
+
return editar(usuario, recurso)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**BIEN** — early return con guard clauses:
|
|
172
|
+
```python
|
|
173
|
+
def editar_recurso(usuario, recurso):
|
|
174
|
+
if not usuario or not usuario.activo:
|
|
175
|
+
raise UsuarioInvalidoError
|
|
176
|
+
if not usuario.tiene_permiso("editar"):
|
|
177
|
+
raise PermisoDenegadoError
|
|
178
|
+
if not recurso.disponible:
|
|
179
|
+
raise RecursoNoDisponibleError
|
|
180
|
+
return editar(usuario, recurso)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Reporte**: "Nested conditionals — `<función>` tiene N niveles de anidamiento. Aplicar guard clauses con early return."
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
### 6. Variantes copy-paste (copy-paste variants)
|
|
188
|
+
|
|
189
|
+
Dos bloques de código casi idénticos que solo difieren en nombres de campos o constantes.
|
|
190
|
+
|
|
191
|
+
**MAL**:
|
|
192
|
+
```python
|
|
193
|
+
def calcular_iva(monto):
|
|
194
|
+
return monto * 0.16
|
|
195
|
+
|
|
196
|
+
def calcular_ieps(monto):
|
|
197
|
+
return monto * 0.08
|
|
198
|
+
|
|
199
|
+
def calcular_isr(monto):
|
|
200
|
+
return monto * 0.30
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**BIEN** — abstracción con tabla de tasas:
|
|
204
|
+
```python
|
|
205
|
+
TASAS = {"iva": 0.16, "ieps": 0.08, "isr": 0.30}
|
|
206
|
+
|
|
207
|
+
def calcular_impuesto(monto: Decimal, tipo: str) -> Decimal:
|
|
208
|
+
return monto * TASAS[tipo]
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Reporte**: "Copy-paste variants — funciones `<a>`, `<b>` difieren solo en constantes. Consolidar."
|
|
212
|
+
|
|
213
|
+
Cuidado: NO consolidar si las funciones evolucionan independientemente por razones de negocio distintas (regla de tres).
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### 7. Actualizaciones sin efecto (no-op updates)
|
|
218
|
+
|
|
219
|
+
Disparar `setState`, `UPDATE` o re-render sin verificar que el valor cambió.
|
|
220
|
+
|
|
221
|
+
**MAL** — re-render cada vez aunque `usuario` sea el mismo:
|
|
222
|
+
```typescript
|
|
223
|
+
useEffect(() => {
|
|
224
|
+
setUsuarioActivo(usuario);
|
|
225
|
+
}, [usuario]);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**BIEN** — comparar antes de actualizar:
|
|
229
|
+
```typescript
|
|
230
|
+
useEffect(() => {
|
|
231
|
+
if (usuario && usuario.id !== usuarioActivoActual?.id) {
|
|
232
|
+
setUsuarioActivo(usuario);
|
|
233
|
+
}
|
|
234
|
+
}, [usuario, usuarioActivoActual]);
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Reporte**: "No-op update — `<archivo:línea>` actualiza estado sin guard de cambio. Verificar si el valor difiere."
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
### 8. TOCTOU — Time-of-Check vs Time-of-Use
|
|
242
|
+
|
|
243
|
+
Entre la verificación y el uso, el estado puede cambiar. Race condition silenciosa.
|
|
244
|
+
|
|
245
|
+
**MAL**:
|
|
246
|
+
```python
|
|
247
|
+
if os.path.exists(ruta):
|
|
248
|
+
with open(ruta) as f: # archivo puede haber desaparecido aquí
|
|
249
|
+
return f.read()
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**BIEN** — intentar y manejar excepción:
|
|
253
|
+
```python
|
|
254
|
+
try:
|
|
255
|
+
with open(ruta) as f:
|
|
256
|
+
return f.read()
|
|
257
|
+
except FileNotFoundError:
|
|
258
|
+
return None
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**MAL** en BD — check-then-act sin transacción:
|
|
262
|
+
```python
|
|
263
|
+
saldo = obtener_saldo(cuenta_id)
|
|
264
|
+
if saldo >= monto:
|
|
265
|
+
debitar(cuenta_id, monto) # otro proceso pudo cambiar el saldo
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
**BIEN** — lock pesimista o transacción atómica:
|
|
269
|
+
```python
|
|
270
|
+
async with conn.transaction():
|
|
271
|
+
saldo = await obtener_saldo_for_update(cuenta_id) # SELECT ... FOR UPDATE
|
|
272
|
+
if saldo < monto:
|
|
273
|
+
raise SaldoInsuficienteError
|
|
274
|
+
await debitar(cuenta_id, monto)
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Reporte**: "TOCTOU — `<archivo:línea>` verifica condición fuera de transacción/lock. Reordenar a try-catch o SELECT FOR UPDATE."
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
### 9. Operaciones demasiado amplias (overly broad operations)
|
|
282
|
+
|
|
283
|
+
Funciones con verbos genéricos (`process`, `handle`, `manage`) que tocan múltiples dominios.
|
|
284
|
+
|
|
285
|
+
**MAL**:
|
|
286
|
+
```typescript
|
|
287
|
+
async function procesarPedido(pedido: Pedido) {
|
|
288
|
+
await validarCliente(pedido.clienteId);
|
|
289
|
+
await debitarInventario(pedido.items);
|
|
290
|
+
await cobrarTarjeta(pedido.pago);
|
|
291
|
+
await enviarEmail(pedido.clienteId);
|
|
292
|
+
await registrarAuditoria(pedido);
|
|
293
|
+
await notificarAlmacen(pedido);
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**BIEN** — fases nombradas, una responsabilidad por función:
|
|
298
|
+
```typescript
|
|
299
|
+
async function emitirPedido(pedido: Pedido) {
|
|
300
|
+
const validado = await validarPedido(pedido);
|
|
301
|
+
const cobrado = await procesarCobro(validado);
|
|
302
|
+
const confirmado = await confirmarPedido(cobrado);
|
|
303
|
+
await notificarParticipantes(confirmado);
|
|
304
|
+
return confirmado;
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**Reporte**: "Overly broad operation — `<función>` orquesta N dominios distintos. Dividir por fase o extraer use cases."
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
### 10. Estado redundante (redundant state)
|
|
313
|
+
|
|
314
|
+
Mantener estado derivable de otro estado introduce drift garantizado.
|
|
315
|
+
|
|
316
|
+
**MAL**:
|
|
317
|
+
```typescript
|
|
318
|
+
const [items, setItems] = useState<Item[]>([]);
|
|
319
|
+
const [total, setTotal] = useState(0); // derivable de items
|
|
320
|
+
const [vacio, setVacio] = useState(true); // derivable de items.length
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**BIEN** — derivar con `useMemo`:
|
|
324
|
+
```typescript
|
|
325
|
+
const [items, setItems] = useState<Item[]>([]);
|
|
326
|
+
const total = useMemo(() => items.reduce((s, i) => s + i.precio, 0), [items]);
|
|
327
|
+
const vacio = items.length === 0;
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Reporte**: "Redundant state — `<componente>` mantiene N campos derivables de uno solo. Computar con `useMemo` o getter."
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Formato de reporte sugerido
|
|
335
|
+
|
|
336
|
+
Cuando un revisor detecta uno o más anti-patrones, integrarlo en su reporte
|
|
337
|
+
estándar con esta forma:
|
|
338
|
+
|
|
339
|
+
```markdown
|
|
340
|
+
### Anti-patrones detectados
|
|
341
|
+
|
|
342
|
+
| # | Patrón | Archivo:línea | Severidad | Remediación |
|
|
343
|
+
|---|---|---|---|---|
|
|
344
|
+
| 1 | Parameter sprawl | usuarios/service.py:42 | P1 | Extraer a `CrearUsuarioParams` |
|
|
345
|
+
| 2 | Stringly-typed | pedidos/handler.ts:88 | P2 | Crear `enum EstadoPedido` |
|
|
346
|
+
| 3 | TOCTOU | inventario/repo.py:120 | P0 | Envolver en `SELECT FOR UPDATE` |
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
Mapeo a severidades estándar de revisor-codigo-swl:
|
|
350
|
+
- **P0** (mata credibilidad): TOCTOU sin lock cuando hay concurrencia real
|
|
351
|
+
- **P1** (arreglar antes de merge): parameter sprawl >6, leaky abstraction cross-capa
|
|
352
|
+
- **P2** (pulir): stringly-typed con 2-3 usos, no-op updates cosméticos
|
|
353
|
+
|
|
354
|
+
## Lo que esta skill NO hace
|
|
355
|
+
|
|
356
|
+
- No reemplaza al revisor — el revisor ejecuta el análisis y decide.
|
|
357
|
+
- No verifica seguridad (eso es `checklist-seguridad`).
|
|
358
|
+
- No mide rendimiento (eso es `rendimiento-swl`).
|
|
359
|
+
- No corrige código — solo nombra el patrón y propone forma idiomática.
|
|
360
|
+
|
|
361
|
+
## Origen
|
|
362
|
+
|
|
363
|
+
Adaptación curada en es-MX de `reference/code-quality-universal.md` del repo
|
|
364
|
+
`anthropic-skills/code-review-skill` analizado en `temp/code-review-skill-main/`
|
|
365
|
+
(sesión 2026-05-24). Los 10 anti-patrones del catálogo original se tradujeron
|
|
366
|
+
y se ajustaron al stack Python + TypeScript predominante en proyectos SWL.
|
|
367
|
+
Material original bajo licencia compatible; adaptación con vocabulario
|
|
368
|
+
es-MX y ejemplos contextualizados.
|