@saulwade/swl-ses 1.7.4 → 1.9.0

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.
Files changed (97) hide show
  1. package/CLAUDE.md +196 -196
  2. package/README.md +579 -579
  3. package/agentes/auto-evolucion-swl.md +7 -7
  4. package/agentes/disenador-ui-swl.md +12 -0
  5. package/agentes/investigador-ux-swl.md +9 -0
  6. package/agentes/orquestador-swl.md +89 -1
  7. package/agentes/perfilador-usuario-swl.md +2 -2
  8. package/agentes/revisor-codigo-swl.md +34 -10
  9. package/agentes/revisor-seguridad-swl.md +7 -0
  10. package/agentes/tdd-qa-swl.md +23 -2
  11. package/agentes/ux-disenador-swl.md +6 -0
  12. package/comandos/swl/autoresearch.md +102 -6
  13. package/comandos/swl/evaluar-skill.md +1 -1
  14. package/comandos/swl/evolucion-estado.md +5 -5
  15. package/comandos/swl/evolucionar.md +2 -2
  16. package/comandos/swl/inbox.md +1 -1
  17. package/comandos/swl/metricas.md +34 -0
  18. package/comandos/swl/nemesis.md +42 -1
  19. package/comandos/swl/planear-fase.md +8 -0
  20. package/comandos/swl/predecir.md +139 -0
  21. package/comandos/swl/reflect-skills.md +2 -2
  22. package/comandos/swl/salud.md +1 -1
  23. package/comandos/swl/verificar.md +50 -7
  24. package/habilidades/ai-runtime-security/SKILL.md +2 -2
  25. package/habilidades/angular-moderno/SKILL.md +44 -1
  26. package/habilidades/auto-evolucion-protocolo/SKILL.md +2 -2
  27. package/habilidades/autoresearch/SKILL.md +15 -1
  28. package/habilidades/benchmark-memoria/SKILL.md +2 -2
  29. package/habilidades/calidad-mutation-testing/SKILL.md +170 -0
  30. package/habilidades/changelog-generator/scripts/parse-commits.js +2 -1
  31. package/habilidades/checklist-seguridad/SKILL.md +29 -1
  32. package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -0
  33. package/habilidades/css-moderno/SKILL.md +3 -1
  34. package/habilidades/drift-detection/SKILL.md +3 -3
  35. package/habilidades/eval-framework/SKILL.md +1 -1
  36. package/habilidades/fastapi-experto/SKILL.md +56 -5
  37. package/habilidades/guardrail-semantico/SKILL.md +4 -4
  38. package/habilidades/patrones-python/SKILL.md +8 -5
  39. package/habilidades/proceso-ddia-streaming/SKILL.md +4 -4
  40. package/habilidades/proceso-debate-adversarial/SKILL.md +164 -0
  41. package/habilidades/proceso-debate-adversarial/recursos/personas.md +105 -0
  42. package/habilidades/proceso-dynamic-workflows/SKILL.md +138 -0
  43. package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -0
  44. package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -0
  45. package/habilidades/swl-claudemd/SKILL.md +2 -2
  46. package/habilidades/tdd-workflow/SKILL.md +14 -1
  47. package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -0
  48. package/habilidades/testing-python/SKILL.md +1 -1
  49. package/habilidades/tracing-processor/SKILL.md +1 -1
  50. package/hooks/actualizar-perfil-usuario.js +2 -2
  51. package/hooks/aiisms-detector.js +2 -2
  52. package/hooks/auto-evolucion.js +1 -1
  53. package/hooks/captura-feedback-usuario.js +2 -2
  54. package/hooks/claudemd-bloat-detector.js +2 -2
  55. package/hooks/claudemd-duplicacion-detector.js +1 -1
  56. package/hooks/contexto-iteracion.js +144 -0
  57. package/hooks/guardrail-modelo.js +2 -2
  58. package/hooks/lib/loop-telemetry.js +321 -0
  59. package/hooks/lib/memory-search.js +1 -1
  60. package/hooks/lib/nudge-tracker.js +1 -1
  61. package/hooks/metricas-evolucion.js +3 -3
  62. package/hooks/notificacion-telegram.js +11 -3
  63. package/hooks/rotar-audit-auto.js +2 -2
  64. package/hooks/validar-formato-post-subagente.js +2 -2
  65. package/hooks/validar-intent-spec.js +1 -1
  66. package/hooks/validar-planning-paths.js +134 -0
  67. package/llms.txt +29 -0
  68. package/manifiestos/hooks-config.json +30 -12
  69. package/manifiestos/modulos.json +1358 -1351
  70. package/manifiestos/planning-paths.json +44 -0
  71. package/manifiestos/skills-lock.json +1275 -1254
  72. package/package.json +93 -92
  73. package/plugin.json +375 -372
  74. package/reglas/arquitectura.evolved.json +7 -0
  75. package/reglas/arquitectura.md +65 -0
  76. package/reglas/gobernanza.md +1 -1
  77. package/reglas/memoria-consolidada.md +7 -7
  78. package/reglas/seguridad.evolved.json +7 -0
  79. package/reglas/seguridad.md +144 -0
  80. package/reglas/sin-duplicacion-reglas-globales.md +1 -1
  81. package/scripts/auditar-agentes-gaps.js +1 -1
  82. package/scripts/auditar-cobertura-frameworks.js +2 -2
  83. package/scripts/auditar-skills-gaps.js +2 -2
  84. package/scripts/benchmark-memoria.js +3 -3
  85. package/scripts/generar-inventario.js +64 -1
  86. package/scripts/inferir-herramientas-permitidas.js +1 -1
  87. package/scripts/instalador.js +80 -2
  88. package/scripts/lib/dashboard-widgets.js +3 -3
  89. package/scripts/lib/drift-detector.js +3 -3
  90. package/scripts/lib/eval-metrics-store.js +3 -3
  91. package/scripts/lib/gitignore-manifest.js +3 -3
  92. package/scripts/mcp-server/README.md +1 -1
  93. package/scripts/mcp-server/telemetry.js +2 -2
  94. package/scripts/reflect-skills.js +4 -4
  95. package/scripts/rotar-audit-logs.js +2 -2
  96. package/scripts/run-skill-evals.js +2 -2
  97. package/scripts/smoke-test.js +24 -2
@@ -8,7 +8,7 @@ description: >
8
8
  automático para scope > 1500 LOC o > 5 archivos en módulos distintos.
9
9
  Persiste hallazgos en .planning/audit/findings/iter-N/.
10
10
  allowed-tools: [Read, Grep, Glob, Bash, Write, Agent, Skill]
11
- argument-hint: "[--remediar] [--pass1 | --pass2 | --continue] [--modulo <ruta>] [--redistribuir] [--reset-plan]"
11
+ argument-hint: "[--remediar] [--pass1 | --pass2 | --continue] [--modulo <ruta>] [--redistribuir] [--reset-plan] [--cross-model]"
12
12
  ---
13
13
 
14
14
  # /swl:nemesis — Auditoría iterativa con remediación opt-in
@@ -54,6 +54,29 @@ y el ciclo continúa hasta convergencia o agotar el guardrail de 3 iteraciones.
54
54
  | Acotar módulo | `--modulo <ruta>` | Limita el scope a un archivo o subdirectorio específico. Se combina con cualquier otro flag. |
55
55
  | Forzar redistribución | `--redistribuir` | Activa `Skill("nemesis-redistribuir")` aunque scope sea menor al umbral. |
56
56
  | Reset del plan | `--reset-plan` | Regenera `nemesis-plan.json` desde cero (descarta plan previo). |
57
+ | **Revisión cross-modelo** | `--cross-model` | Opt-in: rutea la evaluación a un reviewer en OTRO modelo (vía MCP, p.ej. `gemini-review`/`codex-review`) para combatir *self-preferential bias*. Degrada al reviewer same-model si no hay MCP configurado (anuncia la degradación). Combina con `--remediar`. Ver `Skill("proceso-dynamic-workflows") § Revisión cross-modelo`. |
58
+
59
+ ## Revisión cross-modelo (`--cross-model`)
60
+
61
+ El reviewer adversarial en el MISMO modelo aún arrastra *self-preferential bias*
62
+ (uno de los 3 modos de falla nombrados en el blog oficial de dynamic workflows).
63
+ `--cross-model` hace que la evaluación la emita un modelo DISTINTO al ejecutor:
64
+
65
+ - **Wiring (opt-in, ligero)**: si hay un MCP reviewer configurado (patrón ARIS
66
+ `gemini-review`/`codex-review`: expone `review`/`review_reply`, devuelve JSON con
67
+ `threadId` + `response`), el paso de evaluación se rutea a ese MCP. swl-ses NO
68
+ embebe el servidor — lo provee el usuario con su API key del otro modelo.
69
+ - **Degradación explícita** (regla `arreglar-al-detectar.md` / no-fallback-silencioso):
70
+ si el MCP no está disponible, NO falla — usa el reviewer same-model y **anuncia**
71
+ "cross-model solicitado pero MCP ausente → degradado a same-model".
72
+ - **Reviewer memory + debate** (de ARIS `auto-review-loop`): el reviewer externo
73
+ arrastra sospechas entre iteraciones (un `threadId`); el ejecutor puede rebatir,
74
+ el reviewer falla el veredicto final — *"it can drive, never acquit"*.
75
+ - **Trazabilidad**: el JSON del reviewer (`threadId`, `response`, score) se persiste
76
+ junto a `evaluacion.json` en `.planning/audit/findings/iter-N/` → veredicto
77
+ independiente auditable.
78
+
79
+ Detalle del patrón: `Skill("proceso-dynamic-workflows") § Revisión cross-modelo`.
57
80
 
58
81
  ## Flujo completo con `--remediar`
59
82
 
@@ -207,6 +230,24 @@ Estructura de salida bajo `.planning/audit/findings/`:
207
230
 
208
231
  Cada `evaluacion.json` sigue el schema `nemesis-evaluacion-json` v1.0.0.
209
232
 
233
+ ### Telemetría de loop (obligatoria con `--remediar`)
234
+
235
+ En modo `--remediar`, además de los `iter-N/` el comando registra la
236
+ trayectoria en el formato estándar de telemetría de loops
237
+ (`hooks/lib/loop-telemetry.js`). Esto habilita: inyección de estado por el
238
+ hook `contexto-iteracion.js` durante las ejecuciones largas (8-30 turnos),
239
+ detección de plateau, y lectura de la corrida por `/swl:metricas`.
240
+
241
+ - Al iniciar iter-1: `iniciarCorrida({tipo: 'nemesis', direccion: 'lower_is_better', config: {modulo, maxIter: 3}})`.
242
+ - Tras cada iteración: `registrarIteracion(dir, {iteracion: N, metrica: criticos+altos, delta, estado: 'keep', descripcion: 'iter N: status=<status>, X criticos, Y altos'})`.
243
+ - Al cerrar (PASS, FAIL o Recovery Catalog): `escribirHandoff(dir, {source: 'swl:nemesis', status, findings: <hallazgos residuales con archivo_linea>, config})`.
244
+ Mapeo de status: PASS → `COMPLETO`, max iteraciones → `ACOTADO`, Recovery
245
+ Catalog/escalada → `INTERRUMPIDO`.
246
+
247
+ El `handoff.json` resultante es consumible por una corrida posterior de
248
+ `/swl:verificar --until-converge` o por el orquestador (los `findings`
249
+ traen `archivo_linea` verificable según `verificar-citas-normativas.md § Familia 2`).
250
+
210
251
  ## Cómo interpretar el reporte
211
252
 
212
253
  ### Severidades
@@ -161,6 +161,14 @@ El agente planificador-swl debe generar el plan con esta estructura exacta:
161
161
  ## Tests requeridos
162
162
  [lista de tests que deben existir al finalizar la fase]
163
163
 
164
+ ## Escenarios Gherkin (opt-in — solo si la fase tiene criterios de aceptación de negocio)
165
+ [Si el CONTEXTO.md/PRD trae criterios de aceptación con reglas de negocio
166
+ distinguibles, convertirlos en escenarios Given–When–Then siguiendo
167
+ `habilidades/tdd-workflow/recursos/gherkin-bdd.md` y presentarlos al usuario
168
+ para validación ANTES de aprobar el plan. Cada escenario validado se referencia
169
+ desde la tarea que lo implementa (será su test RED). Omitir esta sección en
170
+ fases técnicas puras — Gherkin sin lector de negocio es ceremonia.]
171
+
164
172
  ## Riesgos y mitigaciones
165
173
  | Riesgo | Impacto | Probabilidad | Mitigación |
166
174
  |--------|---------|-------------|-----------|
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: swl:predecir
3
+ description: >
4
+ Análisis predictivo pre-implementación: 5 personas expertas (Arquitecto,
5
+ Seguridad, Rendimiento, Confiabilidad, Abogado del Diablo) analizan EN FRÍO
6
+ un cambio propuesto antes de implementarlo, un sintetizador deduplica con
7
+ anti-herd check y entrega hallazgos rankeados por severidad × confianza ×
8
+ acuerdo. Usar antes de /swl:planear-fase en fases de riesgo, antes de un
9
+ refactor grande, o cuando el costo de descubrir un problema DESPUÉS de
10
+ implementar es alto. Con --adversarial usa el set atacante (Rompedor,
11
+ Tramposo, Escalador, Novato, Insider).
12
+ argument-hint: "[descripción del cambio] [--scope <glob>] [--adversarial] [--presupuesto N] [--chain planear-fase]"
13
+ allowed-tools: [Read, Grep, Glob, Bash, Write, Agent, Skill]
14
+ ---
15
+
16
+ # /swl:predecir — Análisis predictivo pre-implementación
17
+
18
+ Eres el coordinador de un panel de personas expertas que evalúan un cambio
19
+ propuesto ANTES de que se implemente. El valor del comando está en el
20
+ aislamiento: cada persona analiza en frío, sin ver a las demás — los sesgos
21
+ de manada y de confirmación se eliminan por construcción.
22
+
23
+ Complementa (no reemplaza) a `/swl:verificar` y `/swl:nemesis`: esos auditan
24
+ código que YA existe; `predecir` ataca el plan cuando corregirlo cuesta una
25
+ conversación, no un refactor.
26
+
27
+ ## Cuándo usar
28
+
29
+ - Antes de `/swl:planear-fase` en fases que tocan auth, dinero, datos
30
+ productivos o contratos públicos de API.
31
+ - Antes de un refactor cross-módulo o una migración de schema.
32
+ - Cuando el usuario duda entre implementar o no un cambio con blast radius alto.
33
+
34
+ **Cuándo NO usar**: cambios triviales (1-2 archivos), código ya implementado
35
+ (usar `/swl:verificar`), o decisiones entre 2+ alternativas (usar el debate
36
+ adversarial de `Skill("proceso-debate-adversarial")` — predecir analiza UNA
37
+ propuesta, el debate compara varias).
38
+
39
+ ## Flags
40
+
41
+ ```
42
+ [descripción] La propuesta de cambio a analizar (obligatoria; si falta, preguntar)
43
+ --scope <glob> Archivos relevantes para grounding (default: derivar del texto)
44
+ --adversarial Set de personas atacantes en vez del set default
45
+ --presupuesto N Máximo de hallazgos totales (default: 40 → 8 por persona)
46
+ --chain planear-fase Al terminar, ofrecer arrancar /swl:planear-fase con los hallazgos como contexto
47
+ ```
48
+
49
+ ## Paso 0 — Carga y configuración
50
+
51
+ ```
52
+ Skill("proceso-debate-adversarial")
53
+ ```
54
+
55
+ El skill define el protocolo COLD START, el anti-herd check y el formato de
56
+ síntesis. Las definiciones de personas viven en
57
+ `habilidades/proceso-debate-adversarial/recursos/personas.md`.
58
+
59
+ Confirmar con el usuario: propuesta, scope, set de personas, presupuesto.
60
+
61
+ ## Paso 1 — Reconocimiento del codebase
62
+
63
+ Construir el paquete de conocimiento que recibirá CADA persona (idéntico para
64
+ todas): descripción de la propuesta + inventario de archivos del scope +
65
+ dependencias relevantes + superficie de API afectada + cobertura de tests del
66
+ área. Usar `code-review-graph` si está disponible (blast radius, callers);
67
+ si no, Grep/Glob dirigidos. Máximo ~1,500 tokens — las personas analizan, no
68
+ exploran.
69
+
70
+ ## Paso 2 — Análisis en frío (5 invocaciones Agent independientes)
71
+
72
+ Por cada persona, UNA invocación del Agent tool (general-purpose o el agente
73
+ afín al dominio) con prompt autocontenido:
74
+
75
+ ```
76
+ Eres [persona] — [enfoque de recursos/personas.md].
77
+ Propuesta: [descripción]
78
+ Contexto del codebase: [paquete del Paso 1]
79
+ Tu tarea: encuentra hasta [presupuesto/5] problemas que esta propuesta
80
+ causaría, desde tu perspectiva. Por cada uno: título, severidad
81
+ (crítico/alto/medio/bajo), confianza 0-100%, archivo:línea si aplica,
82
+ recomendación concreta. Preguntas guía: [de la persona]. Red flags: [de la
83
+ persona]. NO incluyas elogios ni evaluación general — solo hallazgos.
84
+ ```
85
+
86
+ Las 5 invocaciones pueden correr en paralelo. NUNCA pasar el output de una
87
+ persona a otra — el aislamiento es el mecanismo del comando.
88
+
89
+ ## Paso 3 — Síntesis con anti-herd check
90
+
91
+ Aplicar el protocolo de síntesis del skill:
92
+
93
+ 1. Deduplicar (mismo archivo:línea + mismo problema → fusionar, severidad más alta gana).
94
+ 2. Registrar disensos (dos personas en desacuerdo → ambas posturas visibles).
95
+ 3. **Anti-herd check**: si todas las personas coinciden en el hallazgo top,
96
+ generar explícitamente ≥1 contraargumento antes de aceptarlo.
97
+ 4. Rankear: `severidad × confianza promedio × número de personas que coinciden`.
98
+
99
+ ## Paso 4 — Reporte y persistencia
100
+
101
+ Persistir en `.planning/loops/predecir-[timestamp]/` con
102
+ `hooks/lib/loop-telemetry.js` (tipo `predecir`, columnas `iteracion,
103
+ timestamp, hallazgo, severidad, confianza, personas, archivo_linea`; una fila
104
+ por hallazgo consensuado) + `escribirHandoff` con `source: 'swl:predecir'`,
105
+ `findings` rankeados y `config: {propuesta, scope}`.
106
+
107
+ Reportar al usuario:
108
+
109
+ ```
110
+ === Predicción — [propuesta resumida] ===
111
+ Personas: [set] | Hallazgos brutos: N | Tras dedup: M
112
+
113
+ ## Top hallazgos (rankeados)
114
+ | # | Hallazgo | Severidad | Confianza | Acuerdo | archivo:línea | Recomendación |
115
+
116
+ ## Disensos registrados
117
+ - [persona X sostiene A; persona Y sostiene B — evidencia de cada una]
118
+
119
+ ## Veredicto del panel
120
+ [PROCEDER | PROCEDER CON AJUSTES (lista) | REPLANTEAR (razón)]
121
+ ```
122
+
123
+ ## Paso 5 — Encadenamiento (si `--chain planear-fase`)
124
+
125
+ Ofrecer arrancar `/swl:planear-fase` indicando el directorio del handoff. El
126
+ planificador incorpora los hallazgos `crítico`/`alto` como restricciones del
127
+ PLAN.md — cada uno se atiende con una tarea o se descarta con justificación
128
+ explícita (nunca silenciosamente).
129
+
130
+ ## Reglas de comportamiento
131
+
132
+ - NUNCA compartir contexto entre personas — una invocación Agent por persona.
133
+ - NUNCA omitir el anti-herd check cuando hay unanimidad.
134
+ - Los hallazgos con archivo:línea citan código REAL verificado en el Paso 1 —
135
+ regla `verificar-citas-normativas.md § Familia 2` aplica al propio output.
136
+ - El comando NO modifica código — produce análisis. Implementar es del flujo
137
+ planear → ejecutar.
138
+ - Con 0 hallazgos crítico/alto: decirlo claramente y no inflar hallazgos
139
+ menores para justificar el costo del panel.
@@ -6,7 +6,7 @@ allowed_tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
6
6
 
7
7
  # /swl:reflect-skills — Descubrimiento de skills emergentes
8
8
 
9
- Analiza los archivos JSONL del historial de Claude Code (`~/.claude/projects/<proyecto>/*.jsonl`) y la cola de feedback del usuario (`.planning/evolucion/feedback-queue.jsonl`) para detectar intenciones repetidas que podrían formalizarse como skills, comandos o agentes nuevos del sistema SWL.
9
+ Analiza los archivos JSONL del historial de Claude Code (`~/.claude/projects/<proyecto>/*.jsonl`) y la cola de feedback del usuario (`.planning/evolution/feedback-queue.jsonl`) para detectar intenciones repetidas que podrían formalizarse como skills, comandos o agentes nuevos del sistema SWL.
10
10
 
11
11
  Complementa a `/swl:aprender` (que trabaja sobre la sesión actual) y a `/swl:evolucionar` (que opera sobre metadatos de agentes/skills existentes). Este comando mira el **historial acumulado** y propone componentes emergentes basándose en la frecuencia real de uso.
12
12
 
@@ -41,7 +41,7 @@ Parámetros:
41
41
 
42
42
  El script produce:
43
43
  - Reporte textual en stdout
44
- - Archivo estructurado en `.planning/evolucion/reflect-skills-report.json`
44
+ - Archivo estructurado en `.planning/evolution/reflect-skills-report.json`
45
45
 
46
46
  ### Paso 2 — Leer y clasificar los candidatos
47
47
 
@@ -290,7 +290,7 @@ SWL_AUDIT_FRAMEWORKS=1 npx -y @saulwade/swl-ses@latest audit-coverage-frameworks
290
290
  npx -y @saulwade/swl-ses@latest audit-coverage-frameworks --save
291
291
  ```
292
292
 
293
- Persiste en `.planning/evolucion/cobertura-frameworks.json` para comparación
293
+ Persiste en `.planning/evolution/cobertura-frameworks.json` para comparación
294
294
  histórica tras incorporar nuevos skills de seguridad.
295
295
 
296
296
  Si `SWL_AUDIT_FRAMEWORKS` no está definida, este paso se omite sin mensaje
@@ -137,18 +137,30 @@ Verifica que los mensajes de commit siguen la convención del proyecto (si está
137
137
 
138
138
  Delega al agente `revisor-codigo-swl` para revisión de código en profundidad.
139
139
 
140
+ **Presupuesto de contexto (anti-thrashing):** el subagente hereda `CLAUDE.md` +
141
+ reglas globales del proyecto; en proyectos rule-heavy eso consume buena parte de
142
+ su ventana antes de leer código (causa de autocompact thrashing con 0 tokens
143
+ útiles, observado 2026-06-05). Para evitarlo:
144
+ - Pasa al agente SOLO el diff / los archivos del alcance — nunca "revisa el proyecto".
145
+ - Instruye leer los archivos del alcance PRIMERO y cargar skills bajo demanda (solo
146
+ si el alcance lo amerita), no al inicio.
147
+ - Si el alcance > ~15 archivos o > ~2000 LOC, divídelo en lotes y delega uno por
148
+ invocación (cada subagente arranca con ventana limpia).
149
+
140
150
  **Instrucción al agente revisor-codigo-swl:**
141
151
 
142
152
  ```
143
- Revisa el código de la Fase N del proyecto [nombre].
153
+ Revisa SOLO los archivos del alcance de la Fase N del proyecto [nombre].
154
+ No explores el codebase completo: tu ventana ya hereda CLAUDE.md + reglas
155
+ globales; lee primero los archivos del alcance para no saturarla.
144
156
 
145
157
  Archivos a revisar (en orden de prioridad):
146
- [lista del RESUMEN.md]
158
+ [lista del RESUMEN.md / git diff del alcance]
147
159
 
148
- Lee también:
149
- - .planning/fases/0N-CONTEXTO.md (para entender requisitos)
150
- - .planning/fases/0N-PLAN.md (para entender qué se debía hacer)
151
- - CLAUDE.md (para convenciones del proyecto)
160
+ Lee también (solo lo necesario, bajo demanda):
161
+ - .planning/fases/0N-CONTEXTO.md (requisitos)
162
+ - .planning/fases/0N-PLAN.md (qué se debía hacer)
163
+ (CLAUDE.md ya está en tu contexto heredado — no lo releas.)
152
164
 
153
165
  Para cada archivo revisado, verifica:
154
166
 
@@ -391,7 +403,38 @@ El VERIFICACION.md reportado al usuario al final del loop incluye una sección a
391
403
  - Estado persistido: `.planning/fases/0N-converge-run-[timestamp].json`
392
404
  ```
393
405
 
394
- ### 4.6.7 — Protocolo `--ci-aware` (Señal D)
406
+ ### 4.6.7 — Telemetría de loop (obligatoria en `--until-converge`)
407
+
408
+ Además del estado estructurado de 4.6.5, cada corrida del loop registra su
409
+ trayectoria en el formato estándar de telemetría de loops
410
+ (`hooks/lib/loop-telemetry.js`), que habilita: inyección de estado por el hook
411
+ `contexto-iteracion.js` (anti-context-rot en sesiones largas), detección de
412
+ plateau, y lectura por `/swl:metricas`.
413
+
414
+ Al iniciar el loop (antes de la pasada 1):
415
+
416
+ ```bash
417
+ node -e "const lt=require('./hooks/lib/loop-telemetry');const r=lt.iniciarCorrida({tipo:'verificar',direccion:'lower_is_better',config:{fase:'0N',maxIter:5}});console.log(r.dir)"
418
+ ```
419
+
420
+ Tras CADA pasada, registrar una fila (métrica = hallazgos CRÍTICO+ALTO+MAYOR):
421
+
422
+ ```bash
423
+ node -e "const lt=require('./hooks/lib/loop-telemetry');lt.registrarIteracion('<dir>',{iteracion:N,metrica:M,delta:D,estado:'keep',descripcion:'pasada N: X criticos, Y altos, Z mayores'})"
424
+ ```
425
+
426
+ Al cerrar el loop (cualquier señal de salida), escribir el handoff:
427
+
428
+ ```bash
429
+ node -e "const lt=require('./hooks/lib/loop-telemetry');lt.escribirHandoff('<dir>',{source:'swl:verificar',status:'COMPLETO',findings:[/* hallazgos MEDIO/BAJO residuales */],config:{fase:'0N'}})"
430
+ ```
431
+
432
+ `status` según la señal: A/D → `COMPLETO`, B → `INTERRUMPIDO`, C → `ACOTADO`.
433
+ Si `analizarTrayectoria()` reporta plateau antes de `--max-iter`, tratarlo como
434
+ señal C anticipada: seguir iterando sin mejora de métrica quema tokens sin
435
+ reducir hallazgos.
436
+
437
+ ### 4.6.8 — Protocolo `--ci-aware` (Señal D)
395
438
 
396
439
  Cuando `--ci-aware` está activo, el bucle de convergencia se extiende con un gate adicional ANTES de declarar Señal A como cierre definitivo:
397
440
 
@@ -123,12 +123,12 @@ Checklist para cualquier aplicación LLM en producción:
123
123
  - [ ] Canary token en system prompt + validación en output (capa 2)
124
124
  - [ ] Tool whitelist por agente documentada en frontmatter (capa 3)
125
125
  - [ ] Confirmación humana para acciones irreversibles (capa 3)
126
- - [ ] Logs de intentos detectados en `.planning/auto-evolucion/agentes.jsonl` con campo `tipo_fallo: prompt_injection`
126
+ - [ ] Logs de intentos detectados en `.planning/auto-evolution/agentes.jsonl` con campo `tipo_fallo: prompt_injection`
127
127
 
128
128
  ## Gotchas / Errores comunes no obvios
129
129
 
130
130
  - **Confiar solo en regex**: los atacantes reescriben payloads trivialmente (sinónimos, ofuscación base64, division de strings, caracteres Unicode similares). Causa: las firmas son conocidas y públicas; cualquier evasión simple las burla. Solución: combinar siempre capa 1 con capa 2 + capa 3; nunca tratar la detección de la capa 1 como suficiente. Si el regex pasa pero el heurístico marca anomalía estructural, escalar a clasificador o a humano.
131
- - **Ignorar indirect injection porque "los usuarios son confiables"**: el input legítimo del usuario puede contener contenido externo no confiable (URL que se fetchea, archivo subido, documento RAG). Causa: el autor del payload no es quien interactúa — es quien puso el contenido en la ruta del agente. Solución: tratar TODO contenido externo como datos, nunca como instrucciones; auditar especialmente ingesta de URLs, fetching de páginas web, y documentos en pipelines RAG.
131
+ - **Ignorar indirect injection porque "los usuarios son confiables"**: el input legítimo del usuario puede contener contenido externo no confiable (URL que se fetchea, archivo subido, documento RAG). Causa: el autor del payload no es quien interactúa — es quien puso el contenido en la ruta del agente. Solución: tratar todo el contenido externo como datos, nunca como instrucciones; auditar especialmente ingesta de URLs, fetching de páginas web, y documentos en pipelines RAG.
132
132
  - **Tratar el clasificador como oráculo binario**: `protectai/deberta-v3-base-prompt-injection-v2` es un modelo, no una verdad absoluta. Tiene falsos positivos y falsos negativos. Causa: los clasificadores son entrenados con datasets específicos; inputs legítimos de dominios no representados en el training pueden marcarse. Solución: usar el score como una señal entre varias, no como veredicto; calibrar el umbral contra un dataset propio de inputs legítimos antes de desplegar.
133
133
  - **Canary tokens estáticos en el código**: incluir el mismo canary en repo público o en logs permite al atacante conocerlo y evitar filtrarlo. Causa: si el canary es predecible, el atacante lo filtra del output antes de devolverlo. Solución: generar canary por sesión o por deploy, nunca hardcodeado en el repo visible; rotarlo al menos por release.
134
134
  - **Confiar en el frontmatter `tools:` del agente como único control**: el frontmatter es declaración leída por Claude Code, pero un agente con `tools: [Read]` todavía puede pedir `Bash` en su output y el runtime podría ejecutarlo si no hay enforcement. Causa: pre-aprobación ≠ restricción real. Solución: verificar que el permission mode de Claude Code o los hooks PreToolUse enforsan la restricción; no confiar solo en la declaración.
@@ -1,7 +1,12 @@
1
1
  ---
2
2
  name: angular-moderno
3
3
  description: Angular v17+/v20+. Signals, standalone components, OnPush, host bindings, nueva sintaxis de control flow (@if/@for/@switch), defer blocks y patrones modernos.
4
- version: "1.0.0"
4
+ version: "1.0.1"
5
+ evolved: true
6
+ evolved-from: "1.0.0"
7
+ evolved-at: "2026-06-04"
8
+ evolved-by: "evolucionar"
9
+ evolved-note: "PE-009 patrón Angular 19+ ErrorHandler custom con provideBrowserGlobalErrorListeners (NO listeners manuales window.onerror). Origen: OIC v1.5 Slice 6 2026-06-04."
5
10
  herramientasPermitidas: [Read]
6
11
  exclusiones:
7
12
  - "No cargar para patrones Angular avanzados (zoneless, SSR, Resource API, interceptores funcionales) — para eso cargar `angular-avanzado`."
@@ -184,3 +189,41 @@ Para ejemplos completos de host bindings con clases dinámicas, services store c
184
189
  **`input.required<T>()` accedido fuera del contexto de renderizado (en `constructor`) lanza error de runtime**: `this.factura()` dentro del `constructor` de un componente que usa `input.required<Factura>()` lanza `NG0950: Input is required but no value is available yet`. Causa: los inputs signal no tienen valor hasta que Angular completa la inicialización del componente. Fix: acceder a inputs en `ngOnInit`, en `computed()`, o en métodos del template — nunca en el constructor.
185
190
 
186
191
  **`takeUntilDestroyed()` usado fuera del contexto de inyección lanza error**: `takeUntilDestroyed()` sin argumentos requiere un `DestroyRef` del contexto de inyección activo — si se llama dentro de un callback asíncrono (como `.then()` o `setTimeout`), el injection context ya no está activo. Causa: `inject()` solo funciona en contextos de inyección síncronos. Fix: capturar `DestroyRef` en el constructor con `private destroyRef = inject(DestroyRef)` y pasarlo explícitamente: `takeUntilDestroyed(this.destroyRef)`.
192
+
193
+ **Para captura global de errores runtime (window.onerror + unhandledrejection), usar `ErrorHandler` custom con `provideBrowserGlobalErrorListeners` — NO `window.addEventListener('error', ...)` manual** (Angular 19+; patrón portable OIC v1.5 2026-06-04): Angular 19+ provee `provideBrowserGlobalErrorListeners()` que ya registra los listeners nativos. Para reportar errores no controlados al backend (Sentry-style, audit handler, logs centralizados), proveer un `ErrorHandler` custom — listeners manuales duplican el registro y rompen la integración con el ciclo de DI/zone de Angular.
194
+
195
+ ```typescript
196
+ // app.config.ts
197
+ import { ApplicationConfig, ErrorHandler, provideBrowserGlobalErrorListeners } from '@angular/core';
198
+
199
+ export const appConfig: ApplicationConfig = {
200
+ providers: [
201
+ provideBrowserGlobalErrorListeners(), // 1. Listeners nativos
202
+ { provide: ErrorHandler, useClass: GlobalErrorHandler }, // 2. Tu handler custom
203
+ // ...
204
+ ],
205
+ };
206
+
207
+ // global-error-handler.service.ts
208
+ @Injectable({ providedIn: 'root' })
209
+ export class GlobalErrorHandler implements ErrorHandler {
210
+ private readonly reporter = inject(ErrorReporterService);
211
+
212
+ handleError(error: unknown): void {
213
+ try {
214
+ this.reporter.reportarErrorGlobal(error, 'global-error-handler');
215
+ } catch {
216
+ // Silenciar fallos del reporter — un handler global NUNCA debe propagar.
217
+ }
218
+ console.error(error); // Preservar visibilidad en DevTools.
219
+ }
220
+ }
221
+ ```
222
+
223
+ **Causa**: con `provideBrowserGlobalErrorListeners` activo, Angular ya escucha `window.onerror`/`unhandledrejection` y los enruta a `ErrorHandler.handleError()`. Registrar listeners manuales propios duplica el callback (cada error se reporta dos veces) y se pierde la integración con el lifecycle Angular (zone tracking, DI context). **Fix**: usar EXCLUSIVAMENTE el `ErrorHandler` custom + `provideBrowserGlobalErrorListeners`.
224
+
225
+ **Reglas del handler**:
226
+ - `try/except` agresivo: el reporter NUNCA debe propagar al `handleError` (riesgo de recursión si el propio POST de reporte falla).
227
+ - Delegar a `console.error(error)` para preservar DevTools (no silenciar para devs).
228
+ - El reporter debe tener throttle propio (ej: 10 eventos/5s) y silenciar respuestas esperadas (401/403/404/429) — los detalles del reporter viven en su propio service, no en el `ErrorHandler`.
229
+ - Anti-bucle: el `ErrorReporterInterceptor` (si existe) debe excluir llamadas al propio endpoint POST de reportes.
@@ -194,7 +194,7 @@ ver [recursos/referencia-completa.md](recursos/referencia-completa.md).
194
194
  ## Parser de señales de fricción (v1.1)
195
195
 
196
196
  El hook `hooks/auto-evolucion.js` (SubagentStop) alimenta el log
197
- `.planning/auto-evolucion/agentes.jsonl` y emite *nudges* hacia
197
+ `.planning/auto-evolution/agentes.jsonl` y emite *nudges* hacia
198
198
  `auto-evolucion-swl` cuando detecta umbrales cruzados. Este skill define
199
199
  **qué cuenta como fricción** para que el agente tenga criterio uniforme al
200
200
  interpretar el log.
@@ -233,7 +233,7 @@ Al invocar `auto-evolucion-swl` o `/swl:evolucionar <agente>`:
233
233
 
234
234
  1. **Leer el log filtrado por agente:**
235
235
  ```bash
236
- grep "\"agente\":\"<nombre>\"" .planning/auto-evolucion/agentes.jsonl | tail -50
236
+ grep "\"agente\":\"<nombre>\"" .planning/auto-evolution/agentes.jsonl | tail -50
237
237
  ```
238
238
 
239
239
  2. **Cuantificar las 6 categorías** (fallo duro, run vacío, trivial recurrente,
@@ -7,7 +7,9 @@ description: >
7
7
  y mejorar skills hasta 95%+ de score. Cargar cuando se quiera mejorar la calidad
8
8
  de un skill o agente existente de forma medible y automatizada, o cuando
9
9
  auto-evolucion-swl necesite una metodología de mejora iterativa con scoring.
10
- version: "1.0.0"
10
+ La disciplina del loop (mutación atómica, keep/revert, condiciones de salida)
11
+ aplica también al modo --codigo de /swl:autoresearch sobre código del usuario.
12
+ version: "1.1.0"
11
13
  herramientasPermitidas: [Read, Bash]
12
14
  exclusiones:
13
15
  - "No cargar para mejorar el output de una sola sesión; el loop de autoresearch opera sobre el SKILL.md del skill, no sobre outputs puntuales."
@@ -210,6 +212,18 @@ Mutaciones KEEP: [N] | Mutaciones REVERT: [N]
210
212
  | 3 reverts consecutivos | **Estancamiento** — cambiar estrategia de mutación |
211
213
  | Score baja 2 rounds seguidos | **Degradación** — revertir al mejor score alcanzado |
212
214
 
215
+ ## Variante: loop sobre código del usuario (modo `--codigo`)
216
+
217
+ La misma disciplina aplica cuando el objetivo es código del proyecto en lugar
218
+ de un SKILL.md: el checklist se sustituye por un **comando Verify numérico**
219
+ (mutation score, cobertura, conteo de errores, latencia) y un **Guard** de
220
+ regresión (la suite). El protocolo completo del modo vive en
221
+ `comandos/swl/autoresearch.md § Modo --codigo`; la telemetría de iteraciones
222
+ en `hooks/lib/loop-telemetry.js` (corridas en `.planning/loops/`); las
223
+ métricas de mutación en `Skill("calidad-mutation-testing")`. Las reglas
224
+ invariantes son las mismas: UNA mutación por round, revert sin excepciones si
225
+ la métrica no mejora, salida por plateau.
226
+
213
227
  ## Integración con auto-evolución SWL
214
228
 
215
229
  ```
@@ -122,7 +122,7 @@ node scripts/benchmark-memoria.js --verbose
122
122
  ### Tracking histórico opcional
123
123
 
124
124
  Si se setea `SWL_BENCHMARK_PERSIST=1`, el benchmark escribe el resumen
125
- agregado a `.planning/evolucion/benchmark-memoria.jsonl` (append-only)
125
+ agregado a `.planning/evolution/benchmark-memoria.jsonl` (append-only)
126
126
  para detectar regresión entre releases:
127
127
 
128
128
  ```bash
@@ -131,7 +131,7 @@ SWL_BENCHMARK_PERSIST=1 node scripts/benchmark-memoria.js
131
131
 
132
132
  Comparar entre releases:
133
133
  ```bash
134
- tail -5 .planning/evolucion/benchmark-memoria.jsonl | jq -c '{ts: .timestamp, r5: .promedio.recall_at_5}'
134
+ tail -5 .planning/evolution/benchmark-memoria.jsonl | jq -c '{ts: .timestamp, r5: .promedio.recall_at_5}'
135
135
  ```
136
136
 
137
137
  ---
@@ -0,0 +1,170 @@
1
+ ---
2
+ name: calidad-mutation-testing
3
+ description: >
4
+ Mutation testing: medir la calidad real de una suite de tests inyectando
5
+ mutantes (cambios sintácticos pequeños) en el código y verificando que los
6
+ tests los maten. Cubre herramientas por stack (Stryker, mutmut, cargo-mutants,
7
+ PIT, Stryker.NET, Infection), interpretación de mutantes sobrevivientes,
8
+ modo incremental para que el costo sea viable, y uso del mutation score como
9
+ métrica Verify/Guard en loops de autoresearch o como gate opcional de
10
+ tdd-qa-swl. Cargar cuando la cobertura de líneas es alta pero se sospecha de
11
+ asserts débiles, al endurecer la suite de un módulo crítico, o al configurar
12
+ el gate de mutación en CI.
13
+ version: "1.0.0"
14
+ herramientasPermitidas: [Read, Bash, Grep, Glob]
15
+ exclusiones:
16
+ - "No cargar si la suite no está verde y estable — el mutation testing presupone tests deterministas que pasan; con tests flaky el score es ruido."
17
+ - "No cargar para subir cobertura de líneas — eso es tdd-workflow; la mutación mide calidad de asserts, no cantidad de tests."
18
+ - "No cargar en proyectos sin tests — primero tdd-qa-swl construye la suite; mutar sin tests produce 100% de sobrevivientes sin información."
19
+ evolvable: true
20
+ ---
21
+ # Mutation Testing — La Suite que Vigila a la Suite
22
+
23
+ La cobertura de líneas responde "¿qué código ejecutan los tests?". El mutation
24
+ testing responde la pregunta importante: **"¿los tests detectarían un bug?"**.
25
+ Una suite con 90% de cobertura y asserts débiles pasa el gate de `pruebas.md`
26
+ sin proteger nada — los mutantes sobrevivientes lo exponen.
27
+
28
+ **Principio**: un test que no mata mutantes documenta ejecución, no comportamiento.
29
+
30
+ ## Cuándo cargar este skill
31
+
32
+ - Módulo crítico (pagos, auth, cálculo) con cobertura alta pero bugs que se
33
+ filtran a producción — sospecha de asserts débiles.
34
+ - Cerrar el ciclo TDD estilo Uncle Bob: spec → tests → código → revisión →
35
+ **mutación** como verificación final de la suite.
36
+ - Configurar mutation score como métrica de un loop `/swl:autoresearch --codigo`
37
+ o como gate opcional en CI.
38
+ - Auditar la suite que entrega `tdd-qa-swl` antes de declarar una fase verde.
39
+
40
+ ## Cómo funciona
41
+
42
+ 1. La herramienta genera **mutantes**: copias del código con un cambio mínimo
43
+ (`>` → `>=`, `+` → `-`, borrar una llamada, `true` → `false`).
44
+ 2. Corre la suite contra cada mutante.
45
+ 3. Clasifica: **muerto** (algún test falló — bien), **sobreviviente** (la suite
46
+ pasó con el bug inyectado — gap real), **timeout** (cuenta como muerto),
47
+ **no cubierto** (ningún test lo ejecuta — gap de cobertura clásico).
48
+
49
+ ```
50
+ mutation score = mutantes muertos / (mutantes totales − equivalentes) × 100
51
+ ```
52
+
53
+ ## Herramientas por stack
54
+
55
+ Antes de instalar, verificar versión vigente con Context7
56
+ (regla `usar-context7.md`) — los nombres de paquete cambian entre majors.
57
+
58
+ | Stack | Herramienta | Comando típico | Score en JSON |
59
+ |-------|------------|----------------|---------------|
60
+ | JS/TS | Stryker (`@stryker-mutator/core`) | `npx stryker run` | `reports/mutation/mutation.json` → `.thresholds` / score en summary |
61
+ | Python | `mutmut` | `mutmut run && mutmut results` | `mutmut junitxml` o parsear `mutmut results` |
62
+ | Python (alterno) | `cosmic-ray` | `cosmic-ray init/exec/dump` | `cr-report --json` |
63
+ | Rust | `cargo-mutants` | `cargo mutants` | `mutants.out/outcomes.json` |
64
+ | Java/Kotlin | PIT (`pitest`) | `mvn org.pitest:pitest-maven:mutationCoverage` | `target/pit-reports/mutations.xml` |
65
+ | C#/.NET | Stryker.NET (`dotnet-stryker`) | `dotnet stryker` | `StrykerOutput/**/mutation-report.json` |
66
+ | PHP | Infection | `vendor/bin/infection` | `infection-log.json` → MSI |
67
+ | Go | `gremlins` | `gremlins unleash` | salida estructurada con `--output` |
68
+
69
+ ## Hacer viable el costo — modo incremental SIEMPRE
70
+
71
+ Mutar el proyecto completo es O(mutantes × duración de suite). En un repo
72
+ mediano son horas. Reglas para que sea operable:
73
+
74
+ - **Mutar solo lo que cambió**: Stryker `--since`/modo incremental, `mutmut`
75
+ con `--paths-to-mutate`, `cargo mutants --in-diff <(git diff main)`. El gate
76
+ de PR muta el diff, no el repo.
77
+ - **Acotar al módulo crítico**: configurar `mutate:` solo sobre
78
+ `src/pagos/**`, no sobre todo `src/`. El score global de un repo grande es
79
+ una métrica vanidosa; el score del módulo de dinero es accionable.
80
+ - **Suite rápida primero**: si la suite tarda >2 min, mutar solo con los tests
81
+ unitarios del módulo (los runners permiten filtrar la suite que ejecutan).
82
+ - **Paralelizar**: todos los runners soportan concurrencia
83
+ (`--concurrency`, `--jobs`); default razonable: núcleos − 1.
84
+
85
+ ## Interpretar mutantes sobrevivientes
86
+
87
+ Cada sobreviviente es una de tres cosas — diagnosticar antes de actuar:
88
+
89
+ | Diagnóstico | Señal | Acción |
90
+ |-------------|-------|--------|
91
+ | **Assert débil** | el test ejecuta la línea pero no verifica el resultado mutado | Endurecer el assert (caso típico: verifica que no lanza, no el valor) |
92
+ | **Test faltante** | ningún test cubre el comportamiento de esa rama | Escribir test de frontera dirigido al mutante (`tdd-qa-swl`) |
93
+ | **Mutante equivalente** | el mutante no cambia el comportamiento observable (ej: optimización interna) | Excluirlo/anotarlo — NO escribir un test artificial para matarlo |
94
+
95
+ Anti-patrón crítico: escribir tests que asertan detalles de implementación
96
+ solo para matar mutantes — eso acopla la suite y degrada el refactor. El
97
+ mutante manda la pregunta; el test responde al **comportamiento**.
98
+
99
+ ## Umbrales recomendados
100
+
101
+ | Contexto | Score objetivo | Justificación |
102
+ |----------|---------------|---------------|
103
+ | Módulo crítico (dinero, auth, cálculo regulatorio) | ≥ 85% | Un bug aquí cuesta más que el CI lento |
104
+ | Lógica de negocio estándar | ≥ 70% | Equilibrio costo/valor |
105
+ | Glue code, configs, controllers delgados | sin gate | El esfuerzo no paga; cubrir con tests de integración |
106
+
107
+ No imponer un score global de repo: produce esfuerzo uniforme sobre código de
108
+ valor desigual. Gates por módulo, declarados en la config del runner.
109
+
110
+ ## Uso como métrica en loops SWL
111
+
112
+ El mutation score es la métrica ideal para `/swl:autoresearch --codigo` porque
113
+ es numérica, determinista y su Guard natural es la propia suite:
114
+
115
+ ```
116
+ Goal: subir mutation score de src/pagos/ de 62% a 85%
117
+ Scope: tests/pagos/**
118
+ Metric: mutation score (higher_is_better)
119
+ Verify: npx stryker run --mutate "src/pagos/**" --incremental && <extraer score del JSON>
120
+ Guard: npm test (la suite completa sigue verde)
121
+ ```
122
+
123
+ Cada iteración: agregar/endurecer UN test → correr Verify → keep si el score
124
+ sube y el Guard pasa. Registrar con `hooks/lib/loop-telemetry.js`.
125
+
126
+ **Gate opcional en tdd-qa-swl**: tras alcanzar cobertura ≥80%, correr mutación
127
+ incremental sobre el diff de la fase; sobrevivientes con diagnóstico "assert
128
+ débil" o "test faltante" se atienden antes del cierre (regla
129
+ `arreglar-al-detectar.md`). Es opt-in: requiere runner instalado y suite <2 min.
130
+
131
+ ## Cuándo NO cargar
132
+
133
+ - Suite roja o flaky — primero estabilizar (`pruebas.md § deterministas`); el
134
+ mutation testing amplifica el ruido de tests no deterministas.
135
+ - Prototipo o spike de descarte — el costo del setup no se recupera.
136
+ - Presupuesto de CI ya saturado — correr mutación local/nightly, no por PR,
137
+ hasta resolver el presupuesto.
138
+
139
+ ## Gotchas / Errores comunes no obvios
140
+
141
+ - **El score baja al agregar código nuevo bien testeado**: el denominador
142
+ crece con mutantes del código nuevo; si el módulo viejo tenía deuda, el
143
+ score agregado oscila. Causa: medir score global en vez de por módulo/diff.
144
+ Solución: gates incrementales (`--since`, `--in-diff`) — el código nuevo se
145
+ evalúa contra su propio diff.
146
+ - **Timeouts contados como éxito inflan el score**: un mutante que cuelga la
147
+ suite cuenta como "muerto" aunque ningún assert lo detectó. Si el módulo
148
+ tiene loops sensibles, revisar el desglose `timeout` vs `killed` antes de
149
+ celebrar — un ratio de timeouts >10% amerita bajar el timeout factor.
150
+ - **Mutación sobre código generado**: mutar archivos generados (protobuf,
151
+ cliente OpenAPI, migraciones) quema horas sin información. Excluirlos
152
+ explícitamente en la config del runner desde el día uno.
153
+ - **mutmut y el cache stale**: `mutmut` cachea resultados en `.mutmut-cache`;
154
+ tras un refactor grande el cache puede reportar resultados de código que ya
155
+ no existe. Ante números inverosímiles: borrar el cache y re-correr.
156
+ - **Stryker incremental tras rebase**: el archivo `.stryker-tmp`/incremental
157
+ referencia commits que el rebase reescribió — el modo incremental se
158
+ degrada a corrida completa sin avisar. Presupuestar la primera corrida
159
+ post-rebase como completa.
160
+
161
+ ## Anti-patrones
162
+
163
+ - **Tests escritos para matar mutantes, no para verificar comportamiento** —
164
+ acoplan la suite a la implementación.
165
+ - **Score global de repo como KPI de equipo** — métrica vanidosa; gates por
166
+ módulo crítico.
167
+ - **Correr mutación completa en cada PR** — CI de horas; incremental por diff
168
+ en PR, completa nightly.
169
+ - **Ignorar el desglose y mirar solo el porcentaje** — los sobrevivientes
170
+ individuales son la información; el score es solo el resumen.