@saulwade/swl-ses 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. package/CLAUDE.md +241 -199
  2. package/README.md +597 -597
  3. package/agentes/_intent-spec.md +73 -73
  4. package/agentes/_propose-step.md +90 -90
  5. package/agentes/accesibilidad-wcag-swl.md +2 -2
  6. package/agentes/arquitecto-swl.md +2 -2
  7. package/agentes/auto-evolucion-swl.md +2 -2
  8. package/agentes/backend-api-swl.md +2 -2
  9. package/agentes/backend-csharp-swl.md +2 -2
  10. package/agentes/backend-go-swl.md +2 -2
  11. package/agentes/backend-java-swl.md +2 -2
  12. package/agentes/backend-node-swl.md +2 -2
  13. package/agentes/backend-python-swl.md +2 -2
  14. package/agentes/backend-rust-swl.md +2 -2
  15. package/agentes/backend-workers-swl.md +2 -2
  16. package/agentes/cloud-infra-swl.md +2 -2
  17. package/agentes/consolidador-swl.md +2 -2
  18. package/agentes/datos-swl.md +2 -2
  19. package/agentes/depurador-swl.md +2 -2
  20. package/agentes/devops-ci-swl.md +2 -2
  21. package/agentes/disenador-ui-swl.md +2 -2
  22. package/agentes/documentador-swl.md +2 -2
  23. package/agentes/frontend-angular-swl.md +2 -2
  24. package/agentes/frontend-css-swl.md +2 -2
  25. package/agentes/frontend-react-swl.md +2 -2
  26. package/agentes/frontend-swl.md +2 -2
  27. package/agentes/frontend-tailwind-swl.md +2 -2
  28. package/agentes/gh-fix-ci-swl.md +275 -275
  29. package/agentes/implementador-swl.md +2 -2
  30. package/agentes/investigador-swl.md +2 -2
  31. package/agentes/investigador-ux-swl.md +2 -2
  32. package/agentes/llm-apps-swl.md +2 -2
  33. package/agentes/migrador-swl.md +2 -2
  34. package/agentes/mobile-android-swl.md +2 -2
  35. package/agentes/mobile-cross-swl.md +2 -2
  36. package/agentes/mobile-ios-swl.md +2 -2
  37. package/agentes/mobile-testing-swl.md +2 -2
  38. package/agentes/nemesis-auditor-swl.md +1 -1
  39. package/agentes/notificador-swl.md +2 -2
  40. package/agentes/observabilidad-swl.md +2 -2
  41. package/agentes/orquestador-swl.md +41 -14
  42. package/agentes/pagos-swl.md +2 -2
  43. package/agentes/perfilador-usuario-swl.md +2 -2
  44. package/agentes/planificador-swl.md +2 -2
  45. package/agentes/producto-prd-swl.md +2 -2
  46. package/agentes/red-team-swl.md +218 -218
  47. package/agentes/release-manager-swl.md +2 -2
  48. package/agentes/rendimiento-swl.md +2 -2
  49. package/agentes/resolutor-build-swl.md +2 -2
  50. package/agentes/revisor-angular-swl.md +2 -2
  51. package/agentes/revisor-codigo-swl.md +36 -3
  52. package/agentes/revisor-csharp-swl.md +2 -2
  53. package/agentes/revisor-go-swl.md +2 -2
  54. package/agentes/revisor-java-swl.md +2 -2
  55. package/agentes/revisor-kotlin-swl.md +2 -2
  56. package/agentes/revisor-nextjs-swl.md +2 -2
  57. package/agentes/revisor-php-swl.md +2 -2
  58. package/agentes/revisor-react-swl.md +2 -2
  59. package/agentes/revisor-rust-swl.md +2 -2
  60. package/agentes/revisor-seguridad-swl.md +2 -2
  61. package/agentes/revisor-swift-swl.md +2 -2
  62. package/agentes/revisor-typescript-swl.md +2 -2
  63. package/agentes/sre-swl.md +2 -2
  64. package/agentes/tdd-qa-swl.md +2 -2
  65. package/comandos/swl/briefing.md +119 -119
  66. package/comandos/swl/contexto.md +0 -2
  67. package/comandos/swl/contribuir.md +233 -233
  68. package/comandos/swl/deuda-codigo.md +97 -0
  69. package/comandos/swl/predecir.md +139 -139
  70. package/comandos/swl/sesiones.md +1 -1
  71. package/gateway/agent-executor.js +1 -1
  72. package/gateway/lib/event-channel.js +191 -191
  73. package/habilidades/agent-deep-links/SKILL.md +148 -148
  74. package/habilidades/agentes-como-servicio/SKILL.md +2 -2
  75. package/habilidades/angular-moderno/SKILL.md +24 -1
  76. package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -276
  77. package/habilidades/backend-async-postgres-testing/SKILL.md +215 -215
  78. package/habilidades/backend-error-design/SKILL.md +221 -221
  79. package/habilidades/backend-production-resilience/SKILL.md +288 -288
  80. package/habilidades/benchmark-memoria/SKILL.md +186 -186
  81. package/habilidades/calidad-anti-patrones-universales/SKILL.md +368 -368
  82. package/habilidades/calidad-contract-testing/SKILL.md +165 -165
  83. package/habilidades/calidad-mutation-testing/SKILL.md +170 -170
  84. package/habilidades/changelog-generator/scripts/parse-commits.js +367 -367
  85. package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -60
  86. package/habilidades/contenedores-docker/SKILL.md +3 -1
  87. package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
  88. package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
  89. package/habilidades/drift-detection/SKILL.md +179 -179
  90. package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +1 -1
  91. package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -57
  92. package/habilidades/eval-framework/SKILL.md +212 -212
  93. package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
  94. package/habilidades/harness-claude-code/SKILL.md +4 -4
  95. package/habilidades/harness-claude-code/recursos/disciplina-harness-regla.md +253 -252
  96. package/habilidades/legacy-code-rescue/SKILL.md +268 -267
  97. package/habilidades/meta-skills-estandar/SKILL.md +1 -1
  98. package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
  99. package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +2 -2
  100. package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
  101. package/habilidades/perfil-usuario/SKILL.md +200 -200
  102. package/habilidades/postgresql-experto/SKILL.md +3 -1
  103. package/habilidades/prevencion-sobreingenieria/SKILL.md +70 -92
  104. package/habilidades/prevencion-sobreingenieria/recursos/EXAMPLES.md +580 -580
  105. package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -0
  106. package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -0
  107. package/habilidades/proceso-ddia-fundamentos/SKILL.md +255 -255
  108. package/habilidades/proceso-ddia-streaming/SKILL.md +231 -231
  109. package/habilidades/proceso-debate-adversarial/recursos/personas.md +105 -105
  110. package/habilidades/proceso-discovery-machote/SKILL.md +157 -157
  111. package/habilidades/proceso-dynamic-workflows/SKILL.md +138 -138
  112. package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -65
  113. package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -65
  114. package/habilidades/proceso-intent-engineering/SKILL.md +269 -269
  115. package/habilidades/proceso-modular-split/SKILL.md +256 -256
  116. package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +2 -2
  117. package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
  118. package/habilidades/structured-outputs/SKILL.md +2 -2
  119. package/habilidades/swl-claudemd/recursos/contrato-aprender.md +83 -83
  120. package/habilidades/swl-claudemd/recursos/duplicacion-reglas-globales.md +85 -85
  121. package/habilidades/swl-claudemd/recursos/plantillas-init.md +94 -94
  122. package/habilidades/swl-dashboard/SKILL.md +2 -2
  123. package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -111
  124. package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +1 -1
  125. package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +1 -1
  126. package/hooks/audit-trail.js +4 -4
  127. package/hooks/calidad-pre-commit.js +15 -11
  128. package/hooks/captura-acciones-post.js +3 -2
  129. package/hooks/captura-acciones-session.js +3 -2
  130. package/hooks/ciclo-evolucion-subagente.js +26 -26
  131. package/hooks/ciclo-evolucion.js +26 -26
  132. package/hooks/claudemd-bloat-detector.js +161 -161
  133. package/hooks/claudemd-duplicacion-detector.js +170 -170
  134. package/hooks/contexto-iteracion.js +145 -144
  135. package/hooks/contexto-subagente.js +68 -0
  136. package/hooks/guardrail-modelo.js +14 -4
  137. package/hooks/inyeccion-contexto.js +12 -12
  138. package/hooks/lib/agent-routing.js +107 -107
  139. package/hooks/lib/auto-consolidator.js +335 -335
  140. package/hooks/lib/autonomia.js +208 -208
  141. package/hooks/lib/ciclo-evolucion.js +47 -47
  142. package/hooks/lib/deep-links.js +185 -185
  143. package/hooks/lib/error-classifier.js +308 -308
  144. package/hooks/lib/etapa-auto-evolucion.js +701 -701
  145. package/hooks/lib/etapa-metricas.js +388 -388
  146. package/hooks/lib/etapa-perfil-usuario.js +376 -376
  147. package/hooks/lib/loop-telemetry.js +321 -321
  148. package/hooks/lib/merkle-audit.js +96 -96
  149. package/hooks/lib/model-router.js +2 -2
  150. package/hooks/lib/propose-step.js +358 -358
  151. package/hooks/lib/provenance-tracker.js +191 -191
  152. package/hooks/lib/rate-limit-tracker.js +253 -253
  153. package/hooks/lib/resource-quota.js +122 -122
  154. package/hooks/lib/retry-jitter.js +165 -165
  155. package/hooks/lib/security-net.js +201 -201
  156. package/hooks/lib/skill-auditor.js +588 -588
  157. package/hooks/lib/sync-status.js +228 -228
  158. package/hooks/lib/taint-tracker.js +107 -107
  159. package/hooks/lib/text-similarity.js +241 -241
  160. package/hooks/lib/token-estimator.js +1 -0
  161. package/hooks/lib/toon-compressor.js +245 -245
  162. package/hooks/lib/usage-model.js +1 -1
  163. package/hooks/registro-turnos.js +210 -209
  164. package/hooks/session-briefing.js +98 -98
  165. package/hooks/spec-gate.js +212 -211
  166. package/hooks/sugerir-contribuir.js +2 -1
  167. package/hooks/sugerir-regenerar-inventario.js +171 -170
  168. package/hooks/tdd-gate.js +242 -241
  169. package/hooks/telemetria-skill-routing.js +100 -100
  170. package/hooks/validar-formato-post-subagente.js +140 -140
  171. package/hooks/validar-intent-spec.js +242 -242
  172. package/hooks/validar-memoria-hook.js +218 -218
  173. package/hooks/validar-planning-paths.js +134 -134
  174. package/instintos/autonomia.yaml +27 -27
  175. package/instintos/prompt-appendices.yaml +57 -57
  176. package/llms.txt +29 -29
  177. package/manifiestos/agent-output-schemas.json +57 -57
  178. package/manifiestos/canonical-hashes.json +2948 -1964
  179. package/manifiestos/hook-profiles.json +0 -2
  180. package/manifiestos/hooks-config.json +469 -477
  181. package/manifiestos/invariantes-criticos.json +30 -0
  182. package/manifiestos/modulos.json +1390 -1390
  183. package/manifiestos/planning-paths.json +44 -44
  184. package/manifiestos/skills-lock.json +1282 -1282
  185. package/package.json +93 -93
  186. package/plantillas/auditor-veto-template.md +105 -105
  187. package/plantillas/github-workflows/README.md +47 -47
  188. package/plantillas/github-workflows/release-please.yml +44 -44
  189. package/plantillas/github-workflows/swl-ci.yml +107 -107
  190. package/plantillas/github-workflows/swl-security.yml +51 -51
  191. package/plugin.json +369 -371
  192. package/reglas/accesibilidad.md +10 -10
  193. package/reglas/analisis-previo-tareas-grandes.md +172 -172
  194. package/reglas/api-diseno.md +9 -9
  195. package/reglas/arreglar-al-detectar.md +240 -240
  196. package/reglas/auditorias-documentales-estructurales.md +7 -7
  197. package/reglas/cloud-infra.md +8 -8
  198. package/reglas/consultar-vault-primero.md +195 -195
  199. package/reglas/debatir-antes-de-aceptar.md +158 -158
  200. package/reglas/fragmentos-compartidos.md +183 -183
  201. package/reglas/hooks.md +6 -6
  202. package/reglas/intent-engineering.md +218 -218
  203. package/reglas/markitdown.md +8 -8
  204. package/reglas/monitor-ci.md +309 -309
  205. package/reglas/patrones.md +6 -6
  206. package/reglas/sesiones-paralelas.md +180 -180
  207. package/reglas/sin-duplicacion-reglas-globales.md +182 -182
  208. package/reglas/skills-estandar.md +6 -6
  209. package/reglas/testing.md +7 -7
  210. package/reglas/tests-cleanup.md +224 -224
  211. package/reglas/usar-code-review-graph.md +155 -155
  212. package/reglas/usar-context7.md +226 -226
  213. package/reglas/verificar-citas-normativas.md +548 -548
  214. package/schemas/agent-frontmatter.schema.json +5 -3
  215. package/schemas/agent-message.schema.json +73 -73
  216. package/schemas/agent-output-implementacion.schema.json +114 -114
  217. package/schemas/agent-output-planificacion.schema.json +150 -150
  218. package/schemas/agent-output-review.schema.json +98 -98
  219. package/schemas/diary-entry.schema.json +112 -112
  220. package/schemas/hook-profiles.schema.json +54 -54
  221. package/schemas/hooks-config.schema.json +89 -89
  222. package/schemas/modulos.schema.json +38 -38
  223. package/schemas/perfiles.schema.json +36 -36
  224. package/schemas/plugin.schema.json +77 -77
  225. package/schemas/skill-evals.schema.json +119 -119
  226. package/schemas/skill-frontmatter.schema.json +245 -245
  227. package/scripts/audit-tools/audit-history.js +330 -330
  228. package/scripts/audit-tools/bundle-tracker.js +290 -290
  229. package/scripts/audit-tools/canary-monitor.js +352 -352
  230. package/scripts/audit-tools/code-profiler.js +605 -605
  231. package/scripts/audit-tools/dep-doctor.js +320 -320
  232. package/scripts/audit-tools/env-validator.js +206 -206
  233. package/scripts/audit-tools/lib/fs-walk.js +48 -48
  234. package/scripts/audit-tools/lib/output.js +23 -23
  235. package/scripts/audit-tools/migration-checker.js +392 -392
  236. package/scripts/audit-tools/pentest-scanner.js +1436 -1436
  237. package/scripts/benchmark-memoria.js +167 -167
  238. package/scripts/cli/aprobar-plan.js +73 -73
  239. package/scripts/cli/briefing.js +23 -23
  240. package/scripts/cli/ciclo-evolucion.js +26 -26
  241. package/scripts/cli/configurar-ci.js +40 -40
  242. package/scripts/cli/derivar-feature-list.js +25 -25
  243. package/scripts/cli/detectar-host.js +27 -27
  244. package/scripts/cli/diary-entry.js +69 -69
  245. package/scripts/cli/execution-state.js +18 -18
  246. package/scripts/cli/gateway-notify.js +41 -41
  247. package/scripts/cli/liberar-fase.js +42 -42
  248. package/scripts/cli/loop-telemetry.js +125 -125
  249. package/scripts/cli/mark-evolved.js +56 -56
  250. package/scripts/cli/metricas-dora.js +26 -26
  251. package/scripts/cli/near-duplicate.js +55 -55
  252. package/scripts/cli/notificaciones.js +123 -123
  253. package/scripts/cli/propose-step.js +29 -29
  254. package/scripts/cli/schedule-parse.js +19 -19
  255. package/scripts/cli/sugerir-modelo.js +20 -20
  256. package/scripts/cli/verificar-plan.js +36 -36
  257. package/scripts/cli/verificar-trazabilidad.js +35 -35
  258. package/scripts/configurar-branch-protection.js +418 -418
  259. package/scripts/detectar-aprendizajes-duplicados.js +151 -151
  260. package/scripts/field-report.js +199 -199
  261. package/scripts/generar-checklists-consolidados.js +273 -273
  262. package/scripts/generar-matriz-lenguajes.js +271 -271
  263. package/scripts/instalador.js +4 -1
  264. package/scripts/lib/artefactos-python.js +43 -43
  265. package/scripts/lib/auditar-invocaciones-comandos.js +104 -104
  266. package/scripts/lib/benchmark-metrics.js +160 -160
  267. package/scripts/lib/budget-enforcer.js +252 -252
  268. package/scripts/lib/ci-reader.js +193 -193
  269. package/scripts/lib/claude-sessions.js +1 -0
  270. package/scripts/lib/configurar-ci.js +380 -380
  271. package/scripts/lib/contadores-inventario.js +217 -217
  272. package/scripts/lib/detectar-host-swl.js +175 -175
  273. package/scripts/lib/detectar-stack-detallado.js +307 -307
  274. package/scripts/lib/detector-autoduplicacion-intra-archivo.js +234 -234
  275. package/scripts/lib/detector-reglas-duplicadas.js +220 -220
  276. package/scripts/lib/diary-entry.js +234 -234
  277. package/scripts/lib/eval-metrics-store.js +218 -218
  278. package/scripts/lib/eval-quality.js +171 -171
  279. package/scripts/lib/eval-schemas.js +144 -144
  280. package/scripts/lib/eval-self-correct.js +106 -106
  281. package/scripts/lib/eval-validator.js +185 -185
  282. package/scripts/lib/evidencia-release.js +322 -322
  283. package/scripts/lib/gate-hooks-requires.js +249 -249
  284. package/scripts/lib/gate-licencias.js +212 -212
  285. package/scripts/lib/git-metricas.js +257 -257
  286. package/scripts/lib/jaccard-similarity.js +98 -98
  287. package/scripts/lib/longmemeval-runner.js +125 -125
  288. package/scripts/lib/metricas-dora.js +204 -204
  289. package/scripts/lib/npm-version.js +261 -261
  290. package/scripts/lib/paquetes-conocidos.js +50 -50
  291. package/scripts/lib/plan-lock.js +275 -275
  292. package/scripts/lib/pr-analyzer.js +399 -399
  293. package/scripts/lib/preservar-usuario.js +39 -5
  294. package/scripts/lib/prompt-builder.js +264 -264
  295. package/scripts/lib/reglas-globales-conocidas.json +180 -180
  296. package/scripts/lib/resolver-plan-fase.js +37 -37
  297. package/scripts/lib/rrf-fusion.js +175 -175
  298. package/scripts/lib/schema-version.js +164 -164
  299. package/scripts/lib/scoring-instintos.js +277 -277
  300. package/scripts/lib/semantic-search.js +252 -252
  301. package/scripts/lib/tool-cost-analyzer.js +1 -0
  302. package/scripts/limpiar-artefactos-python.js +131 -131
  303. package/scripts/migrar-csv-a-array.js +168 -168
  304. package/scripts/migrar-fase-dominio.js +200 -200
  305. package/scripts/publicar.js +497 -497
  306. package/scripts/run-eval.js +141 -141
  307. package/scripts/tui/componentes/selector-multi.js +189 -189
  308. package/scripts/tui/componentes/selector-unico.js +158 -158
  309. package/scripts/tui/ejecutores.js +375 -375
  310. package/scripts/tui/index.js +162 -162
  311. package/scripts/tui/lib/colores.js +129 -129
  312. package/scripts/tui/lib/render.js +264 -264
  313. package/scripts/tui/lib/teclas.js +113 -113
  314. package/scripts/tui/pantallas/inspect.js +173 -173
  315. package/scripts/tui/pantallas/install-wizard.js +334 -334
  316. package/scripts/tui/pantallas/menu-principal.js +52 -52
  317. package/scripts/tui/pantallas/progreso.js +274 -274
  318. package/scripts/tui/pantallas/resumen.js +132 -132
  319. package/scripts/tui/pantallas/uninstall-wizard.js +208 -208
  320. package/scripts/tui/pantallas/update-wizard.js +232 -232
  321. package/scripts/tui/pantallas/welcome.js +187 -187
  322. package/scripts/validar-userland-vacio.js +110 -110
  323. package/scripts/validar.js +1 -1
  324. package/scripts/verificar-release.js +51 -0
  325. package/hooks/lib/context-compressor.js +0 -657
  326. package/hooks/linea-estado.js +0 -326
  327. package/hooks/monitor-contexto.js +0 -373
@@ -1,267 +1,268 @@
1
- ---
2
- name: legacy-code-rescue
3
- description: >
4
- Técnicas para trabajar con código heredado sin tests, siguiendo la metodología
5
- de Michael Feathers ("Working Effectively with Legacy Code"). Cubre
6
- identificación de seams, characterization tests para capturar comportamiento
7
- real (no el deseado), patrones para introducir cambios sin romper
8
- (sprout method, sprout class, wrap method, wrap class), técnicas para romper
9
- dependencias problemáticas, y orden de prioridad cuando se hereda código
10
- sin cobertura. Cargar cuando se herede código sin tests, cuando un módulo
11
- crítico tenga cobertura <30%, o cuando se planee refactoring de un sistema
12
- heredado.
13
- version: "1.0.0"
14
- evolved: false
15
- herramientasPermitidas: [Read]
16
- exclusiones:
17
- - "No cargar para refactoring de código moderno con buena cobertura — si los tests existen y cubren el área a refactorear, basta con `tdd-workflow`. Este skill es específico para código sin red de seguridad."
18
- - "No cargar para migración entre versiones de framework — usar `deprecacion-migracion`. Este skill cubre rescate de código heredado en general, no actualizaciones de stack."
19
- - "No cargar para deprecación planificada de features — usar `deprecacion-migracion`. Este skill cubre el problema inverso: código que NO se quiere deprecar pero hay que cambiar con seguridad."
20
- - "No cargar para optimización de rendimiento de código moderno — los patrones aquí (especialmente characterization tests) priorizan seguridad sobre velocidad. Si la prioridad es perf, usar `performance-baseline` y profilers."
21
- evolvable: true
22
- ---
23
-
24
- # Legacy Code Rescue
25
-
26
- Adaptado de "Working Effectively with Legacy Code" (Michael Feathers, 2004).
27
- Definición operativa de Feathers: **legacy code es código sin tests**, sin
28
- importar su edad o calidad aparente.
29
-
30
- ## Cuándo cargar
31
-
32
- - Se hereda un módulo crítico con cobertura <30% y hay que cambiarlo.
33
- - Se diagnostica un bug en código que nadie ha tocado en meses/años.
34
- - Se planea un refactor de un sistema sin red de seguridad de tests.
35
- - Se necesita agregar una feature en código que actualmente no se puede
36
- testear de forma aislada.
37
- - Se reciben quejas tipo "tengo miedo de tocar X porque puede romper Y".
38
-
39
- ## Cuándo NO cargar
40
-
41
- - El código tiene cobertura ≥80% y los tests pasan — usar `tdd-workflow`.
42
- - Se está migrando entre versiones de framework — usar `deprecacion-migracion`.
43
- - Se está deprecando una feature intencionalmente — usar `deprecacion-migracion`.
44
- - El objetivo es optimizar rendimiento — los patrones aquí priorizan seguridad
45
- sobre velocidad; usar `performance-baseline` y profilers.
46
-
47
- ## Directiva primaria
48
-
49
- **Antes de cambiar código heredado, capturar lo que hace**, no lo que se
50
- supone que debe hacer. El comportamiento actual (incluidos sus bugs) es
51
- la fuente de verdad — algún caller probablemente depende de cada peculiaridad.
52
-
53
- Orden estricto:
54
- 1. **Caracterizar** el comportamiento actual con tests.
55
- 2. **Romper dependencias** lo mínimo necesario para que los tests sean posibles.
56
- 3. **Cambiar** el código.
57
- 4. **Refactorizar** ya con red de seguridad.
58
-
59
- NO empezar refactorizando "porque el código está feo". Sin tests, cada cambio
60
- es una apuesta.
61
-
62
- ---
63
-
64
- ## Identificar seams (costuras)
65
-
66
- Un **seam** es un punto donde el comportamiento del programa puede cambiarse
67
- sin editar el código original. Los seams son la palanca para introducir
68
- tests sin romper nada.
69
-
70
- ### Tipos de seams
71
-
72
- | Tipo | Cuándo aplica | Cómo se activa |
73
- |------|---------------|----------------|
74
- | **Object seam** | OOP con polimorfismo | Inyectar una subclase/mock que herede |
75
- | **Preprocessing seam** | C/C++ con `#define` | Macros o preprocesador |
76
- | **Link seam** | Lenguajes compilados con linker | Sustituir librería en build |
77
- | **Method seam** (Python/JS) | Lenguajes dinámicos | Monkeypatching, importlib |
78
-
79
- En Python/TypeScript modernos, el object seam es el predominante:
80
- inyectar dependencias en lugar de instanciarlas dentro del constructor.
81
-
82
- ### Identificar seams en código existente
83
-
84
- Buscar:
85
- - `new SomeClass()` dentro de constructores → object seam latente al refactorizar.
86
- - Llamadas estáticas a clases globales → buscar wrappers o usar dependency injection.
87
- - Imports de módulos con efectos secundarios → candidato a method seam.
88
- - Funciones puras escondidas dentro de métodos largos → extraer es seam barato.
89
-
90
- ---
91
-
92
- ## Characterization tests — capturar el comportamiento real
93
-
94
- Un **characterization test** documenta lo que el código HACE, no lo que
95
- debería hacer. Son la red de seguridad mínima antes de cualquier cambio.
96
-
97
- ### Receta
98
-
99
- 1. Tomar el código y ejecutarlo con un input concreto.
100
- 2. Capturar el output exacto (incluido errores, side effects, state final).
101
- 3. Escribir un test que assert ese output específico.
102
- 4. Repetir con varios inputs representativos: caso típico, edge cases
103
- conocidos, inputs malformados, valores extremos.
104
- 5. Cuando el test pasa, **es la verdad** — incluso si revela un bug.
105
-
106
- ```python
107
- # Ejemplo: función legacy sin tests
108
- def calcular_descuento(precio, tipo_cliente):
109
- # ... 80 líneas de if/else, redondeos extraños, edge cases ocultos
110
- return total
111
-
112
- # Characterization test — captura el comportamiento ACTUAL
113
- def test_caracterizacion_descuento():
114
- # Input típico
115
- assert calcular_descuento(100, "VIP") == 85.0
116
- # Edge case observado: tipo_cliente vacío
117
- assert calcular_descuento(100, "") == 100.0
118
- # Bug aparente, pero callers pueden depender de él
119
- assert calcular_descuento(0, "VIP") == 0.0
120
- # Negativos: el código devuelve negativos sin validar — documentarlo
121
- assert calcular_descuento(-50, "VIP") == -42.5
122
- ```
123
-
124
- ### Reglas para characterization tests
125
-
126
- - **No "arreglar" bugs** mientras se caracteriza — eso viene después.
127
- - Si el comportamiento parece incorrecto, escribir un test que lo
128
- documente Y abrir un ticket separado para discutir el cambio.
129
- - Apuntar a cubrir los flujos que se van a tocar — no toda la base de
130
- código.
131
- - Tests rápidos > tests perfectos. Un test feo que corre es mejor que
132
- uno elegante que no se escribió.
133
-
134
- ---
135
-
136
- ## Patrones para cambio seguro
137
-
138
- Cuando hay que agregar comportamiento sin tocar código existente.
139
-
140
- ### Sprout Method
141
-
142
- Si necesitas lógica nueva dentro de un método legacy difícil de testear,
143
- **escribe la lógica nueva como método aparte** (con tests propios) y
144
- llámalo desde el método legacy.
145
-
146
- ```python
147
- # Antes — quieres agregar validación al método legacy
148
- def procesar_orden(orden):
149
- # 200 líneas legacy intocables
150
- ...
151
-
152
- # Después — la nueva validación vive aparte y SÍ es testeable
153
- def procesar_orden(orden):
154
- # 200 líneas legacy intocables
155
- if not _validar_disponibilidad_inventario(orden): # nuevo
156
- return ResultadoOrden.fallo("sin stock")
157
- ...
158
-
159
- def _validar_disponibilidad_inventario(orden):
160
- """Nuevo método con tests propios (no toca el legacy)."""
161
- return all(item.cantidad <= item.producto.stock for item in orden.items)
162
- ```
163
-
164
- ### Sprout Class
165
-
166
- Cuando la lógica nueva es suficientemente grande, va en una **clase nueva**
167
- en lugar de un método. Misma idea: lógica nueva con tests, llamada desde
168
- el legacy.
169
-
170
- ### Wrap Method
171
-
172
- Si necesitas ejecutar algo ANTES o DESPUÉS de un método legacy, renombra
173
- el original a algo interno (`_procesar_orden_original`) y crea uno nuevo
174
- con la firma original que llame al wrap + el original.
175
-
176
- ```python
177
- def procesar_orden(orden): # firma pública intacta
178
- _registrar_intento(orden) # nueva pre-acción, testeable
179
- resultado = _procesar_orden_original(orden)
180
- _registrar_resultado(resultado) # nueva post-acción, testeable
181
- return resultado
182
-
183
- def _procesar_orden_original(orden):
184
- # 200 líneas legacy intocables, ahora son privadas
185
- ...
186
- ```
187
-
188
- ### Wrap Class
189
-
190
- Para wrap de un sistema más grande: una clase nueva con la misma interfaz
191
- delega al legacy y agrega comportamiento alrededor (decorator pattern).
192
-
193
- ---
194
-
195
- ## Romper dependencias
196
-
197
- Algunos legacy methods son intratables por dependencias:
198
- - Conexiones a BD/red en el constructor.
199
- - Singletons globales que se acceden en cualquier parte.
200
- - Llamadas a `time.now()`, `random()`, filesystem.
201
-
202
- Técnicas (en orden de invasividad creciente):
203
-
204
- 1. **Subclass and Override Method**: hereda de la clase legacy, sobreescribe
205
- el método problemático con un mock para los tests.
206
- 2. **Extract Interface / Extract Class**: extrae una interfaz pequeña con
207
- solo los métodos que el código usa, e inyecta una implementación de prueba.
208
- 3. **Parameterize Method/Constructor**: inyecta como parámetro lo que antes
209
- se obtenía globalmente (clock, random, IO).
210
- 4. **Replace Function with Function Pointer / Strategy**: cambiar funciones
211
- estáticas por callables inyectables.
212
-
213
- Aplicar la técnica MENOS invasiva que resuelva el problema. Cuanto más
214
- invasiva, más riesgo de romper algo durante el rescate.
215
-
216
- ---
217
-
218
- ## Anti-patrones
219
-
220
- - **Refactorizar antes de tener characterization tests**: cualquier cambio
221
- estructural sin red de seguridad es una apuesta.
222
- - **"Mejorar" el comportamiento mientras se caracteriza**: si parece un
223
- bug, documéntalo en un ticket y déjalo intacto en el characterization
224
- test. Cambios funcionales van en commits separados con su propia revisión.
225
- - **Apuntar a 100% de cobertura del módulo entero**: el objetivo es
226
- cubrir lo que se va a tocar. Cobertura completa puede tomar meses;
227
- cubrir el slice de cambio toma horas.
228
- - **Borrar código "muerto" sin verificar**: en legacy, algo que parece
229
- muerto puede ser invocado por reflection o cron. Buscar referencias
230
- con `grep -r` antes de borrar.
231
- - **Sustituir "todo" con un mock**: si el test pasa solo porque mockeaste
232
- todas las dependencias, ya no testea nada. Mockear solo lo necesario
233
- para aislar el código bajo prueba.
234
-
235
- ---
236
-
237
- ## Gotchas / Errores comunes no obvios
238
-
239
- - **Characterization test "perfecto" que se rompe en CI por orden no determinista**: el código legacy depende del orden de iteración de un dict (Python <3.7) o del timezone del servidor. Causa: comportamiento dependiente de entorno. Solución: capturar la dependencia (forzar timezone UTC en el test, ordenar collections antes de assert) y documentar la dependencia ambiental como bug a discutir.
240
- - **Sprout Method que sí toca el legacy "solo un poquito"**: el desarrollador agrega un `if condicion_nueva` dentro del legacy en lugar de extraer. Causa: parece más simple. Solución: si tocas el legacy, ya no es sprout; o caracterizas primero, o aplicas wrap method que NO modifica el cuerpo original.
241
- - **Inyectar dependencia con un default que llama al global**: `def __init__(self, db=None): self.db = db or get_global_db()`. Causa: querer mantener compatibilidad con callers viejos. Solución: el default escondido invalida la inyección — los tests acaban tocando el global. Aceptar que romper la firma es parte del rescate; agregar wrappers de compatibilidad fuera de la clase si es necesario.
242
- - **Cobertura como métrica engañosa**: 80% de cobertura de líneas pero los asserts solo verifican que "no lanza excepción". Causa: tests escritos para subir el número, no para capturar comportamiento. Solución: cada characterization test debe tener al menos un assert sobre el output o side effect concreto, no solo `assert resultado is not None`.
243
- - **Mock de la BD que devuelve datos perfectos donde el legacy maneja datos sucios**: el código legacy tiene defensas contra datos inconsistentes que el mock no reproduce. Causa: el mock idealiza la realidad. Solución: el mock debe reproducir la sucidad observada en producción (NULLs inesperados, encodings raros, duplicados) — caracterizar la entrada real es parte del rescate.
244
-
245
- ## Orden de prioridad cuando se hereda código
246
-
247
- 1. **Estabilizar**: identificar el módulo más crítico, escribir
248
- characterization tests sobre los flujos que se van a tocar pronto.
249
- 2. **Aislar**: romper dependencias problemáticas con seams para que el
250
- módulo crítico pueda testearse en isolation.
251
- 3. **Cubrir**: agregar tests sobre código nuevo (Sprout/Wrap) y sobre
252
- regresiones detectadas.
253
- 4. **Cambiar**: hacer el cambio funcional pedido, ya con red de seguridad.
254
- 5. **Refactorizar**: mejorar la estructura ya que está cubierta. NO antes.
255
-
256
- NO refactorices código que no piensas tocar. La cobertura no es un fin
257
- en mismo es palanca para cambios futuros.
258
-
259
- ## Checklist antes de tocar código heredado
260
-
261
- - [ ] ¿Existen characterization tests sobre la zona de cambio?
262
- - [ ] Si no: ¿se escribieron antes de cualquier modificación?
263
- - [ ] ¿Las dependencias bloqueantes (DB, red, time, random) están aisladas?
264
- - [ ] ¿El cambio funcional va en un commit separado del refactor estructural?
265
- - [ ] ¿Se documentaron en tickets los bugs detectados durante la caracterización?
266
- - [ ] ¿La cobertura nueva es del slice tocado, no del módulo completo?
267
- - [ ] ¿El sprout/wrap se queda fuera del cuerpo legacy original?
1
+ ---
2
+ name: legacy-code-rescue
3
+ description: >
4
+ Técnicas para trabajar con código heredado sin tests, siguiendo la metodología
5
+ de Michael Feathers ("Working Effectively with Legacy Code"). Cubre
6
+ identificación de seams, characterization tests para capturar comportamiento
7
+ real (no el deseado), patrones para introducir cambios sin romper
8
+ (sprout method, sprout class, wrap method, wrap class), técnicas para romper
9
+ dependencias problemáticas, y orden de prioridad cuando se hereda código
10
+ sin cobertura. Cargar cuando se herede código sin tests, cuando un módulo
11
+ crítico tenga cobertura <30%, o cuando se planee refactoring de un sistema
12
+ heredado.
13
+ version: "1.0.1"
14
+ evolved: false
15
+ herramientasPermitidas: [Read]
16
+ exclusiones:
17
+ - "No cargar para refactoring de código moderno con buena cobertura — si los tests existen y cubren el área a refactorear, basta con `tdd-workflow`. Este skill es específico para código sin red de seguridad."
18
+ - "No cargar para migración entre versiones de framework — usar `deprecacion-migracion`. Este skill cubre rescate de código heredado en general, no actualizaciones de stack."
19
+ - "No cargar para deprecación planificada de features — usar `deprecacion-migracion`. Este skill cubre el problema inverso: código que NO se quiere deprecar pero hay que cambiar con seguridad."
20
+ - "No cargar para optimización de rendimiento de código moderno — los patrones aquí (especialmente characterization tests) priorizan seguridad sobre velocidad. Si la prioridad es perf, usar `performance-baseline` y profilers."
21
+ evolvable: true
22
+ ---
23
+
24
+ # Legacy Code Rescue
25
+
26
+ Adaptado de "Working Effectively with Legacy Code" (Michael Feathers, 2004).
27
+ Definición operativa de Feathers: **legacy code es código sin tests**, sin
28
+ importar su edad o calidad aparente.
29
+
30
+ ## Cuándo cargar
31
+
32
+ - Se hereda un módulo crítico con cobertura <30% y hay que cambiarlo.
33
+ - Se diagnostica un bug en código que nadie ha tocado en meses/años.
34
+ - Se planea un refactor de un sistema sin red de seguridad de tests.
35
+ - Se necesita agregar una feature en código que actualmente no se puede
36
+ testear de forma aislada.
37
+ - Se reciben quejas tipo "tengo miedo de tocar X porque puede romper Y".
38
+
39
+ ## Cuándo NO cargar
40
+
41
+ - El código tiene cobertura ≥80% y los tests pasan — usar `tdd-workflow`.
42
+ - Se está migrando entre versiones de framework — usar `deprecacion-migracion`.
43
+ - Se está deprecando una feature intencionalmente — usar `deprecacion-migracion`.
44
+ - El objetivo es optimizar rendimiento — los patrones aquí priorizan seguridad
45
+ sobre velocidad; usar `performance-baseline` y profilers.
46
+
47
+ ## Directiva primaria
48
+
49
+ **Antes de cambiar código heredado, capturar lo que hace**, no lo que se
50
+ supone que debe hacer. El comportamiento actual (incluidos sus bugs) es
51
+ la fuente de verdad — algún caller probablemente depende de cada peculiaridad.
52
+
53
+ Orden estricto:
54
+ 1. **Caracterizar** el comportamiento actual con tests.
55
+ 2. **Romper dependencias** lo mínimo necesario para que los tests sean posibles.
56
+ 3. **Cambiar** el código.
57
+ 4. **Refactorizar** ya con red de seguridad.
58
+
59
+ NO empezar refactorizando "porque el código está feo". Sin tests, cada cambio
60
+ es una apuesta.
61
+
62
+ ---
63
+
64
+ ## Identificar seams (costuras)
65
+
66
+ Un **seam** es un punto donde el comportamiento del programa puede cambiarse
67
+ sin editar el código original. Los seams son la palanca para introducir
68
+ tests sin romper nada.
69
+
70
+ ### Tipos de seams
71
+
72
+ | Tipo | Cuándo aplica | Cómo se activa |
73
+ |------|---------------|----------------|
74
+ | **Object seam** | OOP con polimorfismo | Inyectar una subclase/mock que herede |
75
+ | **Preprocessing seam** | C/C++ con `#define` | Macros o preprocesador |
76
+ | **Link seam** | Lenguajes compilados con linker | Sustituir librería en build |
77
+ | **Method seam** (Python/JS) | Lenguajes dinámicos | Monkeypatching, importlib |
78
+
79
+ En Python/TypeScript modernos, el object seam es el predominante:
80
+ inyectar dependencias en lugar de instanciarlas dentro del constructor.
81
+
82
+ ### Identificar seams en código existente
83
+
84
+ Buscar:
85
+ - `new SomeClass()` dentro de constructores → object seam latente al refactorizar.
86
+ - Llamadas estáticas a clases globales → buscar wrappers o usar dependency injection.
87
+ - Imports de módulos con efectos secundarios → candidato a method seam.
88
+ - Funciones puras escondidas dentro de métodos largos → extraer es seam barato.
89
+
90
+ ---
91
+
92
+ ## Characterization tests — capturar el comportamiento real
93
+
94
+ Un **characterization test** documenta lo que el código HACE, no lo que
95
+ debería hacer. Son la red de seguridad mínima antes de cualquier cambio.
96
+
97
+ ### Receta
98
+
99
+ 1. Tomar el código y ejecutarlo con un input concreto.
100
+ 2. Capturar el output exacto (incluido errores, side effects, state final).
101
+ 3. Escribir un test que assert ese output específico.
102
+ 4. Repetir con varios inputs representativos: caso típico, edge cases
103
+ conocidos, inputs malformados, valores extremos.
104
+ 5. Cuando el test pasa, **es la verdad** — incluso si revela un bug.
105
+
106
+ ```python
107
+ # Ejemplo: función legacy sin tests
108
+ def calcular_descuento(precio, tipo_cliente):
109
+ # ... 80 líneas de if/else, redondeos extraños, edge cases ocultos
110
+ return total
111
+
112
+ # Characterization test — captura el comportamiento ACTUAL
113
+ def test_caracterizacion_descuento():
114
+ # Input típico
115
+ assert calcular_descuento(100, "VIP") == 85.0
116
+ # Edge case observado: tipo_cliente vacío
117
+ assert calcular_descuento(100, "") == 100.0
118
+ # Bug aparente, pero callers pueden depender de él
119
+ assert calcular_descuento(0, "VIP") == 0.0
120
+ # Negativos: el código devuelve negativos sin validar — documentarlo
121
+ assert calcular_descuento(-50, "VIP") == -42.5
122
+ ```
123
+
124
+ ### Reglas para characterization tests
125
+
126
+ - **No "arreglar" bugs** mientras se caracteriza — eso viene después.
127
+ - Si el comportamiento parece incorrecto, escribir un test que lo
128
+ documente Y abrir un ticket separado para discutir el cambio.
129
+ - Apuntar a cubrir los flujos que se van a tocar — no toda la base de
130
+ código.
131
+ - Tests rápidos > tests perfectos. Un test feo que corre es mejor que
132
+ uno elegante que no se escribió.
133
+
134
+ ---
135
+
136
+ ## Patrones para cambio seguro
137
+
138
+ Cuando hay que agregar comportamiento sin tocar código existente.
139
+
140
+ ### Sprout Method
141
+
142
+ Si necesitas lógica nueva dentro de un método legacy difícil de testear,
143
+ **escribe la lógica nueva como método aparte** (con tests propios) y
144
+ llámalo desde el método legacy.
145
+
146
+ ```python
147
+ # Antes — quieres agregar validación al método legacy
148
+ def procesar_orden(orden):
149
+ # 200 líneas legacy intocables
150
+ ...
151
+
152
+ # Después — la nueva validación vive aparte y SÍ es testeable
153
+ def procesar_orden(orden):
154
+ # 200 líneas legacy intocables
155
+ if not _validar_disponibilidad_inventario(orden): # nuevo
156
+ return ResultadoOrden.fallo("sin stock")
157
+ ...
158
+
159
+ def _validar_disponibilidad_inventario(orden):
160
+ """Nuevo método con tests propios (no toca el legacy)."""
161
+ return all(item.cantidad <= item.producto.stock for item in orden.items)
162
+ ```
163
+
164
+ ### Sprout Class
165
+
166
+ Cuando la lógica nueva es suficientemente grande, va en una **clase nueva**
167
+ en lugar de un método. Misma idea: lógica nueva con tests, llamada desde
168
+ el legacy.
169
+
170
+ ### Wrap Method
171
+
172
+ Si necesitas ejecutar algo ANTES o DESPUÉS de un método legacy, renombra
173
+ el original a algo interno (`_procesar_orden_original`) y crea uno nuevo
174
+ con la firma original que llame al wrap + el original.
175
+
176
+ ```python
177
+ def procesar_orden(orden): # firma pública intacta
178
+ _registrar_intento(orden) # nueva pre-acción, testeable
179
+ resultado = _procesar_orden_original(orden)
180
+ _registrar_resultado(resultado) # nueva post-acción, testeable
181
+ return resultado
182
+
183
+ def _procesar_orden_original(orden):
184
+ # 200 líneas legacy intocables, ahora son privadas
185
+ ...
186
+ ```
187
+
188
+ ### Wrap Class
189
+
190
+ Para wrap de un sistema más grande: una clase nueva con la misma interfaz
191
+ delega al legacy y agrega comportamiento alrededor (decorator pattern).
192
+
193
+ ---
194
+
195
+ ## Romper dependencias
196
+
197
+ Algunos legacy methods son intratables por dependencias:
198
+ - Conexiones a BD/red en el constructor.
199
+ - Singletons globales que se acceden en cualquier parte.
200
+ - Llamadas a `time.now()`, `random()`, filesystem.
201
+
202
+ Técnicas (en orden de invasividad creciente):
203
+
204
+ 1. **Subclass and Override Method**: hereda de la clase legacy, sobreescribe
205
+ el método problemático con un mock para los tests.
206
+ 2. **Extract Interface / Extract Class**: extrae una interfaz pequeña con
207
+ solo los métodos que el código usa, e inyecta una implementación de prueba.
208
+ 3. **Parameterize Method/Constructor**: inyecta como parámetro lo que antes
209
+ se obtenía globalmente (clock, random, IO).
210
+ 4. **Replace Function with Function Pointer / Strategy**: cambiar funciones
211
+ estáticas por callables inyectables.
212
+
213
+ Aplicar la técnica MENOS invasiva que resuelva el problema. Cuanto más
214
+ invasiva, más riesgo de romper algo durante el rescate.
215
+
216
+ ---
217
+
218
+ ## Anti-patrones
219
+
220
+ - **Refactorizar antes de tener characterization tests**: cualquier cambio
221
+ estructural sin red de seguridad es una apuesta.
222
+ - **"Mejorar" el comportamiento mientras se caracteriza**: si parece un
223
+ bug, documéntalo en un ticket y déjalo intacto en el characterization
224
+ test. Cambios funcionales van en commits separados con su propia revisión.
225
+ - **Apuntar a 100% de cobertura del módulo entero**: el objetivo es
226
+ cubrir lo que se va a tocar. Cobertura completa puede tomar meses;
227
+ cubrir el slice de cambio toma horas.
228
+ - **Borrar código "muerto" sin verificar**: en legacy, algo que parece
229
+ muerto puede ser invocado por reflection o cron. Buscar referencias
230
+ con `grep -r` antes de borrar.
231
+ - **Sustituir "todo" con un mock**: si el test pasa solo porque mockeaste
232
+ todas las dependencias, ya no testea nada. Mockear solo lo necesario
233
+ para aislar el código bajo prueba.
234
+
235
+ ---
236
+
237
+ ## Gotchas / Errores comunes no obvios
238
+
239
+ - **Characterization test "perfecto" que se rompe en CI por orden no determinista**: el código legacy depende del orden de iteración de un dict (Python <3.7) o del timezone del servidor. Causa: comportamiento dependiente de entorno. Solución: capturar la dependencia (forzar timezone UTC en el test, ordenar collections antes de assert) y documentar la dependencia ambiental como bug a discutir.
240
+ - **Sprout Method que sí toca el legacy "solo un poquito"**: el desarrollador agrega un `if condicion_nueva` dentro del legacy en lugar de extraer. Causa: parece más simple. Solución: si tocas el legacy, ya no es sprout; o caracterizas primero, o aplicas wrap method que NO modifica el cuerpo original.
241
+ - **Inyectar dependencia con un default que llama al global**: `def __init__(self, db=None): self.db = db or get_global_db()`. Causa: querer mantener compatibilidad con callers viejos. Solución: el default escondido invalida la inyección — los tests acaban tocando el global. Aceptar que romper la firma es parte del rescate; agregar wrappers de compatibilidad fuera de la clase si es necesario.
242
+ - **Cobertura como métrica engañosa**: 80% de cobertura de líneas pero los asserts solo verifican que "no lanza excepción". Causa: tests escritos para subir el número, no para capturar comportamiento. Solución: cada characterization test debe tener al menos un assert sobre el output o side effect concreto, no solo `assert resultado is not None`.
243
+ - **Mock de la BD que devuelve datos perfectos donde el legacy maneja datos sucios**: el código legacy tiene defensas contra datos inconsistentes que el mock no reproduce. Causa: el mock idealiza la realidad. Solución: el mock debe reproducir la sucidad observada en producción (NULLs inesperados, encodings raros, duplicados) — caracterizar la entrada real es parte del rescate.
244
+ - **Codemod por regex sin balanceo de llaves inserta en el bloque estructural equivocado cuando el ancla no es única**: un codemod que inserta tras "el `],` de cierre" asume que esa ancla aparece una sola vez — si el archivo tiene otra (`FormBuilder.group({...})`, arrays anidados), la inserción cae dentro del bloque equivocado y el archivo queda silenciosamente corrupto. Causa: regex no entiende estructura; cuenta patrones, no llaves. Solución: balancear llaves/corchetes desde el ancla (parser mínimo o AST real tipo `ts-morph`/`libcst`) y SIEMPRE cerrar con build completo (`ng build`, `tsc`, `pyflakes`) + auditoría del 100% de las inserciones — el build atrapa la corrupción sintáctica; la auditoría manual, la semántica. Origen: SIGAF 2026-07-02 — 4 de 43 archivos corruptos, detectados solo por `ng build`.
245
+
246
+ ## Orden de prioridad cuando se hereda código
247
+
248
+ 1. **Estabilizar**: identificar el módulo más crítico, escribir
249
+ characterization tests sobre los flujos que se van a tocar pronto.
250
+ 2. **Aislar**: romper dependencias problemáticas con seams para que el
251
+ módulo crítico pueda testearse en isolation.
252
+ 3. **Cubrir**: agregar tests sobre código nuevo (Sprout/Wrap) y sobre
253
+ regresiones detectadas.
254
+ 4. **Cambiar**: hacer el cambio funcional pedido, ya con red de seguridad.
255
+ 5. **Refactorizar**: mejorar la estructura ya que está cubierta. NO antes.
256
+
257
+ NO refactorices código que no piensas tocar. La cobertura no es un fin
258
+ en sí mismo — es palanca para cambios futuros.
259
+
260
+ ## Checklist antes de tocar código heredado
261
+
262
+ - [ ] ¿Existen characterization tests sobre la zona de cambio?
263
+ - [ ] Si no: ¿se escribieron antes de cualquier modificación?
264
+ - [ ] ¿Las dependencias bloqueantes (DB, red, time, random) están aisladas?
265
+ - [ ] ¿El cambio funcional va en un commit separado del refactor estructural?
266
+ - [ ] ¿Se documentaron en tickets los bugs detectados durante la caracterización?
267
+ - [ ] ¿La cobertura nueva es del slice tocado, no del módulo completo?
268
+ - [ ] ¿El sprout/wrap se queda fuera del cuerpo legacy original?
@@ -9,7 +9,7 @@ description: >
9
9
  idiomas de framework y mapeo a frameworks de seguridad. Cargar cuando se
10
10
  esté escribiendo o auditando un SKILL.md y se necesiten patrones avanzados
11
11
  que no están en la regla core.
12
- version: "1.1.1"
12
+ version: "1.1.2"
13
13
  herramientasPermitidas: [Read, Write, Edit]
14
14
  exclusiones:
15
15
  - "No cargar si solo se necesita el frontmatter obligatorio, el límite de líneas o la estructura de directorio — eso está en la regla core `reglas/skills-estandar.md` que se carga siempre."