@saulwade/swl-ses 1.8.0 → 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 (44) hide show
  1. package/CLAUDE.md +3 -3
  2. package/README.md +5 -5
  3. package/agentes/orquestador-swl.md +89 -1
  4. package/agentes/revisor-codigo-swl.md +34 -10
  5. package/agentes/revisor-seguridad-swl.md +7 -0
  6. package/agentes/tdd-qa-swl.md +23 -2
  7. package/comandos/swl/autoresearch.md +102 -6
  8. package/comandos/swl/metricas.md +34 -0
  9. package/comandos/swl/nemesis.md +42 -1
  10. package/comandos/swl/planear-fase.md +8 -0
  11. package/comandos/swl/predecir.md +139 -0
  12. package/comandos/swl/verificar.md +50 -7
  13. package/habilidades/angular-moderno/SKILL.md +44 -1
  14. package/habilidades/autoresearch/SKILL.md +15 -1
  15. package/habilidades/calidad-mutation-testing/SKILL.md +170 -0
  16. package/habilidades/changelog-generator/scripts/parse-commits.js +2 -1
  17. package/habilidades/checklist-seguridad/SKILL.md +29 -1
  18. package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -0
  19. package/habilidades/css-moderno/SKILL.md +3 -1
  20. package/habilidades/fastapi-experto/SKILL.md +56 -5
  21. package/habilidades/patrones-python/SKILL.md +8 -5
  22. package/habilidades/proceso-debate-adversarial/SKILL.md +164 -0
  23. package/habilidades/proceso-debate-adversarial/recursos/personas.md +105 -0
  24. package/habilidades/proceso-dynamic-workflows/SKILL.md +138 -0
  25. package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -0
  26. package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -0
  27. package/habilidades/tdd-workflow/SKILL.md +14 -1
  28. package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -0
  29. package/hooks/contexto-iteracion.js +144 -0
  30. package/hooks/lib/loop-telemetry.js +321 -0
  31. package/hooks/notificacion-telegram.js +11 -3
  32. package/llms.txt +29 -0
  33. package/manifiestos/hooks-config.json +10 -1
  34. package/manifiestos/modulos.json +7 -1
  35. package/manifiestos/skills-lock.json +45 -24
  36. package/package.json +4 -3
  37. package/plugin.json +5 -2
  38. package/reglas/arquitectura.evolved.json +7 -0
  39. package/reglas/arquitectura.md +65 -0
  40. package/reglas/seguridad.evolved.json +7 -0
  41. package/reglas/seguridad.md +144 -0
  42. package/scripts/generar-inventario.js +64 -1
  43. package/scripts/instalador.js +32 -2
  44. package/scripts/smoke-test.js +24 -2
@@ -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.
@@ -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
 
@@ -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.
@@ -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
  ```
@@ -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.
@@ -51,7 +51,7 @@ const { execSync } = require('node:child_process');
51
51
  * refactor(hooks/lib): split evolution-tracker
52
52
  * chore(release): bump version
53
53
  */
54
- const RE_CONVENTIONAL = /^(feat|fix|perf|refactor|docs|style|test|ci|build|chore|revert|evolucion)(?:\(([^)]+)\))?(!)?:\s*(.+)$/;
54
+ const RE_CONVENTIONAL = /^(feat|fix|perf|refactor|docs|style|test|ci|build|chore|revert|evolucion|evolve)(?:\(([^)]+)\))?(!)?:\s*(.+)$/;
55
55
 
56
56
  /** Mapa tipo CC → categoría Keep a Changelog en es-MX. */
57
57
  const CATEGORIAS = Object.freeze({
@@ -61,6 +61,7 @@ const CATEGORIAS = Object.freeze({
61
61
  refactor: 'Cambios internos',
62
62
  revert: 'Reversiones',
63
63
  evolucion: 'Evoluciones de skills/agentes',
64
+ evolve: 'Evoluciones de skills/agentes',
64
65
  docs: 'Mantenimiento',
65
66
  style: 'Mantenimiento',
66
67
  test: 'Mantenimiento',
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: checklist-seguridad
3
3
  description: Checklist de seguridad basado en OWASP Top 10 + seguridad de agentes autónomos (A11). Cubre inyección, autenticación, exposición de datos, control de acceso, configuración insegura, XSS, deserialización, componentes vulnerables, logging y agencia excesiva de IA. Produce reporte con hallazgos y remediaciones.
4
- version: "1.1.1"
4
+ version: "1.2.0"
5
5
  evolved: true
6
6
  evolved-from: "1.1.0"
7
7
  evolved-at: "2026-05-04"
@@ -297,6 +297,34 @@ grep -rn "\.env\|credentials\|secret" --include="*.md" agentes/ | head -10
297
297
 
298
298
  ---
299
299
 
300
+ ## Modo cobertura — STRIDE + score compuesto (auditorías iterativas)
301
+
302
+ Para auditorías en profundidad (no el checklist de un solo PR), complementar
303
+ el barrido OWASP con el modelo **STRIDE** y medir la auditoría con un **score
304
+ compuesto de cobertura** — convierte "auditamos seguridad" en un número
305
+ verificable y permite usar la auditoría como loop iterativo:
306
+
307
+ ```
308
+ score = (categorías_OWASP_auditadas / 10) × 50
309
+ + (categorías_STRIDE_auditadas / 6) × 30
310
+ + min(hallazgos_únicos, 20)
311
+ ```
312
+
313
+ Score perfecto = 100 (OWASP completo + STRIDE completo + 20 hallazgos). Cada
314
+ hallazgo se etiqueta con AMBAS taxonomías (`OWASP: A03, STRIDE: T`). Reportar
315
+ la cobertura cada 5 iteraciones:
316
+
317
+ ```
318
+ OWASP: [A01✓ A02✓ A03✗ ...] 4/10 | STRIDE: [S✓ T✓ R✗ I✓ D✗ E✗] 3/6 | Score: 48
319
+ ```
320
+
321
+ Tabla STRIDE→OWASP, qué buscar por categoría, y rotación de personas red-team
322
+ (Adversario, Supply Chain, Insider, Infra — definidas en
323
+ `habilidades/proceso-debate-adversarial/recursos/personas.md`) en
324
+ [recursos/stride-cobertura.md](recursos/stride-cobertura.md). Registrar las
325
+ iteraciones de la auditoría con `hooks/lib/loop-telemetry.js` (tipo
326
+ `seguridad`, direccion `higher_is_better`, métrica = score compuesto).
327
+
300
328
  ## Gotchas / Errores comunes no obvios
301
329
 
302
330
  **El grep de búsqueda de secrets hardcodeados devuelve cero resultados pero hay credenciales en archivos de configuración YAML**: el patrón de búsqueda usa `password\s*=` (sintaxis Python), pero los archivos YAML usan `password:` (sin signo igual). Causa: las búsquedas de código están optimizadas para un lenguaje y pierden variantes de otro formato. Fix: expandir el patrón de búsqueda a `password[\s=:]+['\"][^'\"]{4,}` para capturar asignaciones en Python, YAML y JSON simultáneamente. Verificar también `docker-compose.yml`, `.env.example` y archivos de configuración de CI.
@@ -0,0 +1,60 @@
1
+ # STRIDE — modelo de amenazas para el modo cobertura
2
+
3
+ Complemento del checklist OWASP de `SKILL.md`. STRIDE clasifica por **tipo de
4
+ amenaza** (qué quiere lograr el atacante); OWASP por **tipo de debilidad**
5
+ (qué error del código lo permite). Auditar con ambas taxonomías cierra los
6
+ huecos que cada una deja sola: repudio y DoS casi no aparecen en OWASP Top 10;
7
+ componentes desactualizados (A06) no mapean limpio a STRIDE.
8
+
9
+ ## Las 6 categorías
10
+
11
+ | Letra | Amenaza | Qué buscar | OWASP relacionadas |
12
+ |-------|---------|-----------|--------------------|
13
+ | **S**poofing | Suplantación de identidad | Auth débil, tokens predecibles, session fixation, falta de MFA | A07 |
14
+ | **T**ampering | Modificación de datos | Input sin validar, falta de checks de integridad, inyección SQL/NoSQL, deserialización insegura | A03, A08 |
15
+ | **R**epudiation | Acciones negables | Audit logs faltantes, transacciones sin firma, logs mutables, cambios de privilegio sin registro | A09 |
16
+ | **I**nformation Disclosure | Fuga de información | Stack traces al cliente, logging verboso con PII, env vars expuestas, mensajes de error que revelan existencia de recursos | A01, A02, A05 |
17
+ | **D**enial of Service | Ataques a disponibilidad | Queries sin cota ni paginación, rate limits faltantes, regex DoS (ReDoS), uploads sin límite de tamaño | A04 |
18
+ | **E**levation of Privilege | Acceso no autorizado | Checks de authz faltantes, IDOR, rutas de escalación admin, confusión autenticación/autorización | A01, A04 |
19
+
20
+ ## Protocolo de auditoría iterativa con cobertura
21
+
22
+ 1. **Reconocimiento (una vez)**: mapear superficie de ataque — manifest de
23
+ dependencias, `.env.example`, Dockerfile, rutas de API, módulos de auth,
24
+ schemas de BD, configuración de CI/CD. Producir threat model inicial:
25
+ qué activos, qué trust boundaries, qué entry points.
26
+ 2. **Por iteración**: elegir el vector MENOS cubierto (OWASP sin auditar →
27
+ STRIDE sin auditar → profundizar en hallazgos existentes). Adoptar la
28
+ persona red-team que corresponde al vector (rotación: Adversario de
29
+ Seguridad → Supply Chain → Insider → Infraestructura — definiciones en
30
+ `habilidades/proceso-debate-adversarial/recursos/personas.md`).
31
+ 3. **Validar cada hallazgo**: evidencia archivo:línea + escenario de ataque
32
+ concreto + reproducción. Sin escenario de ataque no es hallazgo, es
33
+ especulación (regla `verificar-citas-normativas.md § Familia 2`).
34
+ 4. **Registrar**: fila en la corrida de `loop-telemetry` (columnas sugeridas:
35
+ `iteracion, timestamp, hallazgo, severidad, owasp, stride, archivo_linea`)
36
+ y recalcular el score compuesto.
37
+ 5. **Salida**: OWASP 10/10 + STRIDE 6/6 cubiertos, o max iteraciones (default
38
+ 15), o plateau de hallazgos (3 iteraciones sin hallazgo nuevo).
39
+
40
+ ## Formato de hallazgo (obligatorio, 7 campos)
41
+
42
+ ```markdown
43
+ ### [Título de una línea]
44
+ - **Severidad**: Crítico | Alto | Medio | Bajo | Informativo
45
+ - **OWASP**: A01-A10
46
+ - **STRIDE**: S | T | R | I | D | E
47
+ - **Evidencia**: archivo:línea + escenario de ataque (sin especulación teórica)
48
+ - **Reproducción**: pasos para disparar el problema
49
+ - **Remediación**: fix concreto para ESTE código
50
+ ```
51
+
52
+ ## Severidad — criterios
53
+
54
+ | Severidad | Criterio | Ejemplos |
55
+ |-----------|----------|----------|
56
+ | Crítico | Explotable remoto, sin auth, brecha de datos | RCE, SQL injection, bypass de auth |
57
+ | Alto | Requiere algún acceso, impacto severo | XSS almacenado, IDOR, escalación de privilegios |
58
+ | Medio | Impacto limitado o requiere interacción | CSRF, XSS reflejado, divulgación de info |
59
+ | Bajo | Impacto mínimo | Headers faltantes, errores verbosos |
60
+ | Informativo | Recomendación de hardening | Defensa en profundidad |
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: css-moderno
3
3
  description: CSS moderno 2024+. Cubre Container Queries, CSS Layers (@layer), Nesting nativo, Custom Properties avanzadas, funciones min/max/clamp/color-mix, propiedades lógicas (block/inline), View Transitions API, animaciones performantes solo-compositor, dark mode patterns y anti-patrones críticos.
4
- version: "1.0.0"
4
+ version: "1.1.0"
5
5
  herramientasPermitidas: [Read, Grep]
6
6
  exclusiones:
7
7
  - "No cargar para Tailwind CSS (clases utilitarias, @theme, cva, responsive) — para Tailwind cargar `tailwind-experto`."
@@ -164,3 +164,5 @@ Para ejemplos completos de Container Queries, CSS Layers, Nesting, Custom Proper
164
164
  **`container-type: inline-size` en un elemento con `position: absolute/fixed` puede no funcionar como contenedor de queries en algunos navegadores**: el contenedor crea un nuevo stacking context y en ciertos casos la query no se propaga correctamente a hijos con posicionamiento absoluto en Safari <17. Causa: bug de implementación en Safari relacionado con contenedores posicionados. Fix: en elementos con posicionamiento absoluto dentro de container queries, probar en Safari y usar un wrapper div sin posicionamiento como contenedor si hay problemas.
165
165
 
166
166
  **`clamp()` con `vw` en la función intermedia no escala correctamente en pantallas muy anchas si no se acota con `max()`**: `font-size: clamp(1rem, 2vw, 2rem)` en un monitor de 2560px da `2vw = 51.2px`, que es mayor que el máximo de `2rem = 32px` — el clamp lo atrapa pero el cálculo puede ser confuso al depurar. Causa: el valor de `vw` crece sin límite. Fix: entender que `clamp(min, preferido, max)` garantiza que el resultado siempre está entre min y max — el valor preferido puede ser cualquier expresión, incluso mayor que max, y el clamp simplemente retorna max en ese caso. Verificar los tres valores en los tamaños de viewport objetivo.
167
+
168
+ **`var(--token)` NO resuelve cuando el valor lo consume JavaScript pintando a `<canvas>`**: las librerías que renderizan a canvas (Chart.js, OpenLayers, three.js/WebGL, o `ctx.fillStyle`/`strokeStyle`/`ctx.font` directos) NO reciben el contexto CSS del documento → el color sale negro o invisible **sin error en consola**. Causa: el canvas es un buffer de píxeles fuera del árbol CSS; la cascada y `getComputedStyle` no aplican al contexto 2D/WebGL — `var()` queda como string literal que el motor de canvas no interpreta. La frontera es: un color es `var(--x)` SOLO si lo consume CSS (`.css`/`.module.scss` o `style={{}}` sobre HTML); si lo consume JS pintando a canvas, debe ser hex/rgb concreto. Fix: pasar hex/rgb literal a esos objetos, con comentario anti-recurrencia (`// canvas: NO resuelve var()`). Si el color debe ser theme-aware, resolverlo primero en JS — `getComputedStyle(document.documentElement).getPropertyValue('--color-x').trim()` — y pasar el valor ya resuelto al canvas, re-leyéndolo al cambiar de tema.