@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.
- package/CLAUDE.md +3 -3
- package/README.md +5 -5
- package/agentes/orquestador-swl.md +89 -1
- package/agentes/revisor-codigo-swl.md +34 -10
- package/agentes/revisor-seguridad-swl.md +7 -0
- package/agentes/tdd-qa-swl.md +23 -2
- package/comandos/swl/autoresearch.md +102 -6
- package/comandos/swl/metricas.md +34 -0
- package/comandos/swl/nemesis.md +42 -1
- package/comandos/swl/planear-fase.md +8 -0
- package/comandos/swl/predecir.md +139 -0
- package/comandos/swl/verificar.md +50 -7
- package/habilidades/angular-moderno/SKILL.md +44 -1
- package/habilidades/autoresearch/SKILL.md +15 -1
- package/habilidades/calidad-mutation-testing/SKILL.md +170 -0
- package/habilidades/changelog-generator/scripts/parse-commits.js +2 -1
- package/habilidades/checklist-seguridad/SKILL.md +29 -1
- package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -0
- package/habilidades/css-moderno/SKILL.md +3 -1
- package/habilidades/fastapi-experto/SKILL.md +56 -5
- package/habilidades/patrones-python/SKILL.md +8 -5
- package/habilidades/proceso-debate-adversarial/SKILL.md +164 -0
- package/habilidades/proceso-debate-adversarial/recursos/personas.md +105 -0
- package/habilidades/proceso-dynamic-workflows/SKILL.md +138 -0
- package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -0
- package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -0
- package/habilidades/tdd-workflow/SKILL.md +14 -1
- package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -0
- package/hooks/contexto-iteracion.js +144 -0
- package/hooks/lib/loop-telemetry.js +321 -0
- package/hooks/notificacion-telegram.js +11 -3
- package/llms.txt +29 -0
- package/manifiestos/hooks-config.json +10 -1
- package/manifiestos/modulos.json +7 -1
- package/manifiestos/skills-lock.json +45 -24
- package/package.json +4 -3
- package/plugin.json +5 -2
- package/reglas/arquitectura.evolved.json +7 -0
- package/reglas/arquitectura.md +65 -0
- package/reglas/seguridad.evolved.json +7 -0
- package/reglas/seguridad.md +144 -0
- package/scripts/generar-inventario.js +64 -1
- package/scripts/instalador.js +32 -2
- 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
|
|
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 (
|
|
150
|
-
- .planning/fases/0N-PLAN.md (
|
|
151
|
-
|
|
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 —
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|