@saulwade/swl-ses 1.0.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 (702) hide show
  1. package/CLAUDE.md +238 -0
  2. package/README.md +560 -0
  3. package/_userland/agentes/.gitkeep +0 -0
  4. package/_userland/habilidades/.gitkeep +0 -0
  5. package/agentes/.evolved.json +9 -0
  6. package/agentes/accesibilidad-wcag-swl.md +692 -0
  7. package/agentes/arquitecto-swl.md +238 -0
  8. package/agentes/auto-evolucion-swl.md +854 -0
  9. package/agentes/backend-api-swl.md +470 -0
  10. package/agentes/backend-csharp-swl.md +418 -0
  11. package/agentes/backend-go-swl.md +388 -0
  12. package/agentes/backend-java-swl.md +279 -0
  13. package/agentes/backend-node-swl.md +477 -0
  14. package/agentes/backend-python-swl.md +608 -0
  15. package/agentes/backend-rust-swl.md +362 -0
  16. package/agentes/backend-workers-swl.md +480 -0
  17. package/agentes/cloud-infra-swl.md +485 -0
  18. package/agentes/consolidador-swl.md +539 -0
  19. package/agentes/datos-swl.md +584 -0
  20. package/agentes/depurador-swl.md +349 -0
  21. package/agentes/devops-ci-swl.md +374 -0
  22. package/agentes/disenador-ui-swl.md +558 -0
  23. package/agentes/documentador-swl.md +343 -0
  24. package/agentes/evals/arquitecto-swl.evals.json +56 -0
  25. package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
  26. package/agentes/evals/implementador-swl.evals.json +56 -0
  27. package/agentes/evals/orquestador-swl.evals.json +60 -0
  28. package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
  29. package/agentes/evals/red-team-swl.evals.json +59 -0
  30. package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
  31. package/agentes/frontend-angular-swl.md +627 -0
  32. package/agentes/frontend-css-swl.md +720 -0
  33. package/agentes/frontend-react-swl.md +696 -0
  34. package/agentes/frontend-swl.md +500 -0
  35. package/agentes/frontend-tailwind-swl.md +830 -0
  36. package/agentes/implementador-swl.md +328 -0
  37. package/agentes/investigador-swl.md +430 -0
  38. package/agentes/investigador-ux-swl.md +500 -0
  39. package/agentes/llm-apps-swl.md +276 -0
  40. package/agentes/migrador-swl.md +417 -0
  41. package/agentes/mobile-android-swl.md +509 -0
  42. package/agentes/mobile-cross-swl.md +539 -0
  43. package/agentes/mobile-ios-swl.md +500 -0
  44. package/agentes/mobile-testing-swl.md +300 -0
  45. package/agentes/notificador-swl.md +916 -0
  46. package/agentes/observabilidad-swl.md +436 -0
  47. package/agentes/orquestador-swl.md +884 -0
  48. package/agentes/pagos-swl.md +283 -0
  49. package/agentes/perfilador-usuario-swl.md +306 -0
  50. package/agentes/planificador-swl.md +402 -0
  51. package/agentes/producto-prd-swl.md +587 -0
  52. package/agentes/red-team-swl.md +216 -0
  53. package/agentes/release-manager-swl.md +568 -0
  54. package/agentes/rendimiento-swl.md +714 -0
  55. package/agentes/resolutor-build-swl.md +243 -0
  56. package/agentes/revisor-angular-swl.md +276 -0
  57. package/agentes/revisor-codigo-swl.md +348 -0
  58. package/agentes/revisor-csharp-swl.md +262 -0
  59. package/agentes/revisor-go-swl.md +257 -0
  60. package/agentes/revisor-java-swl.md +255 -0
  61. package/agentes/revisor-kotlin-swl.md +271 -0
  62. package/agentes/revisor-nextjs-swl.md +279 -0
  63. package/agentes/revisor-php-swl.md +269 -0
  64. package/agentes/revisor-react-swl.md +276 -0
  65. package/agentes/revisor-rust-swl.md +344 -0
  66. package/agentes/revisor-seguridad-swl.md +390 -0
  67. package/agentes/revisor-swift-swl.md +266 -0
  68. package/agentes/revisor-typescript-swl.md +344 -0
  69. package/agentes/sre-swl.md +265 -0
  70. package/agentes/tdd-qa-swl.md +354 -0
  71. package/agentes/ux-disenador-swl.md +501 -0
  72. package/bin/lib/bot-comandos.js +1030 -0
  73. package/bin/lib/bot-discovery.js +182 -0
  74. package/bin/lib/bot-git.js +142 -0
  75. package/bin/swl-ses.js +325 -0
  76. package/bin/swl-telegram-bot.js +442 -0
  77. package/bin/swl-telegram-bot.plist +21 -0
  78. package/bin/swl-telegram-bot.service +14 -0
  79. package/comandos/swl/.evolved.json +23 -0
  80. package/comandos/swl/actualizar.md +174 -0
  81. package/comandos/swl/adoptar-proyecto.md +207 -0
  82. package/comandos/swl/aprender.md +701 -0
  83. package/comandos/swl/auditar-deps.md +134 -0
  84. package/comandos/swl/autoresearch.md +170 -0
  85. package/comandos/swl/ayuda.md +224 -0
  86. package/comandos/swl/brainstorm.md +50 -0
  87. package/comandos/swl/checkpoint.md +330 -0
  88. package/comandos/swl/compactar.md +283 -0
  89. package/comandos/swl/configurar-ci.md +227 -0
  90. package/comandos/swl/contexto.md +112 -0
  91. package/comandos/swl/contribuir.md +233 -0
  92. package/comandos/swl/crear-skill.md +292 -0
  93. package/comandos/swl/cron.md +196 -0
  94. package/comandos/swl/dashboard.md +146 -0
  95. package/comandos/swl/discutir-fase.md +230 -0
  96. package/comandos/swl/ejecutar-fase.md +135 -0
  97. package/comandos/swl/evaluar-skill.md +487 -0
  98. package/comandos/swl/evolucion-estado.md +142 -0
  99. package/comandos/swl/evolucionar.md +259 -0
  100. package/comandos/swl/exportar-vault.md +189 -0
  101. package/comandos/swl/gateway.md +158 -0
  102. package/comandos/swl/inbox.md +116 -0
  103. package/comandos/swl/instalar.md +220 -0
  104. package/comandos/swl/instintos.md +86 -0
  105. package/comandos/swl/mapear-codebase.md +312 -0
  106. package/comandos/swl/mcp-status.md +175 -0
  107. package/comandos/swl/metricas.md +270 -0
  108. package/comandos/swl/modelo.md +102 -0
  109. package/comandos/swl/notificaciones.md +396 -0
  110. package/comandos/swl/nuevo-proyecto.md +154 -0
  111. package/comandos/swl/planear-fase.md +221 -0
  112. package/comandos/swl/plugins.md +256 -0
  113. package/comandos/swl/reflect-skills.md +125 -0
  114. package/comandos/swl/release.md +217 -0
  115. package/comandos/swl/revisar-impacto.md +206 -0
  116. package/comandos/swl/revisar.md +330 -0
  117. package/comandos/swl/salud.md +363 -0
  118. package/comandos/swl/sesiones.md +200 -0
  119. package/comandos/swl/skill-search.md +113 -0
  120. package/comandos/swl/verificar.md +585 -0
  121. package/comandos/swl/wiki.md +620 -0
  122. package/contextos/dev.md +32 -0
  123. package/contextos/research.md +30 -0
  124. package/contextos/review.md +31 -0
  125. package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
  126. package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
  127. package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
  128. package/habilidades/agent-browser/SKILL.md +218 -0
  129. package/habilidades/agentes-como-servicio/SKILL.md +218 -0
  130. package/habilidades/ai-runtime-security/SKILL.md +273 -0
  131. package/habilidades/angular-avanzado/SKILL.md +164 -0
  132. package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
  133. package/habilidades/angular-moderno/SKILL.md +186 -0
  134. package/habilidades/angular-moderno/evals/evals.json +45 -0
  135. package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
  136. package/habilidades/api-rest-diseno/SKILL.md +191 -0
  137. package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
  138. package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
  139. package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
  140. package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
  141. package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
  142. package/habilidades/async-python/SKILL.md +149 -0
  143. package/habilidades/async-python/evals/evals.json +47 -0
  144. package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
  145. package/habilidades/auth-patrones/.evolved.json +9 -0
  146. package/habilidades/auth-patrones/SKILL.md +413 -0
  147. package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
  148. package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
  149. package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
  150. package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
  151. package/habilidades/autoresearch/SKILL.md +268 -0
  152. package/habilidades/autoresearch/evals/evals.json +41 -0
  153. package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
  154. package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
  155. package/habilidades/azure-cloud/SKILL.md +308 -0
  156. package/habilidades/azure-cloud/recursos/aks.md +327 -0
  157. package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
  158. package/habilidades/backend-production-resilience/SKILL.md +288 -0
  159. package/habilidades/brainstorming/SKILL.md +295 -0
  160. package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
  161. package/habilidades/build-errors-cpp/SKILL.md +270 -0
  162. package/habilidades/build-errors-csharp/SKILL.md +265 -0
  163. package/habilidades/build-errors-go/SKILL.md +306 -0
  164. package/habilidades/build-errors-java/SKILL.md +278 -0
  165. package/habilidades/build-errors-kotlin/SKILL.md +303 -0
  166. package/habilidades/build-errors-nextjs/SKILL.md +312 -0
  167. package/habilidades/build-errors-php/SKILL.md +270 -0
  168. package/habilidades/build-errors-python/SKILL.md +292 -0
  169. package/habilidades/build-errors-rust/SKILL.md +284 -0
  170. package/habilidades/build-errors-swift/SKILL.md +272 -0
  171. package/habilidades/build-errors-typescript/SKILL.md +369 -0
  172. package/habilidades/checklist-calidad/SKILL.md +271 -0
  173. package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
  174. package/habilidades/checklist-seguridad/SKILL.md +285 -0
  175. package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
  176. package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
  177. package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
  178. package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
  179. package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
  180. package/habilidades/cloud-aws/SKILL.md +142 -0
  181. package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
  182. package/habilidades/compactacion-contexto/SKILL.md +247 -0
  183. package/habilidades/contenedores-docker/SKILL.md +137 -0
  184. package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
  185. package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
  186. package/habilidades/context-builder/SKILL.md +170 -0
  187. package/habilidades/control-profundidad/SKILL.md +128 -0
  188. package/habilidades/csharp-experto/SKILL.md +322 -0
  189. package/habilidades/csharp-patrones/SKILL.md +316 -0
  190. package/habilidades/csharp-testing/SKILL.md +286 -0
  191. package/habilidades/css-moderno/SKILL.md +166 -0
  192. package/habilidades/css-moderno/evals/evals.json +43 -0
  193. package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
  194. package/habilidades/datos-etl/SKILL.md +129 -0
  195. package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
  196. package/habilidades/dbml-experto/SKILL.md +339 -0
  197. package/habilidades/dbml-experto/evals/evals.json +56 -0
  198. package/habilidades/dependencias-auditoria/SKILL.md +320 -0
  199. package/habilidades/deprecacion-migracion/SKILL.md +169 -0
  200. package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
  201. package/habilidades/design-tokens/SKILL.md +158 -0
  202. package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
  203. package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
  204. package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
  205. package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
  206. package/habilidades/discutir-fase/SKILL.md +188 -0
  207. package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
  208. package/habilidades/diseno-responsivo/SKILL.md +186 -0
  209. package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
  210. package/habilidades/django-experto/SKILL.md +205 -0
  211. package/habilidades/django-experto/recursos/async-django.md +390 -0
  212. package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
  213. package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
  214. package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
  215. package/habilidades/django-experto/recursos/testing-django.md +415 -0
  216. package/habilidades/doc-sync/SKILL.md +280 -0
  217. package/habilidades/drift-detection/SKILL.md +179 -0
  218. package/habilidades/ejecutar-fase/SKILL.md +468 -0
  219. package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
  220. package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
  221. package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
  222. package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
  223. package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
  224. package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
  225. package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
  226. package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
  227. package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
  228. package/habilidades/evaluacion-agentes/SKILL.md +314 -0
  229. package/habilidades/event-driven/SKILL.md +153 -0
  230. package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
  231. package/habilidades/extraccion-documentos/SKILL.md +221 -0
  232. package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
  233. package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
  234. package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
  235. package/habilidades/fastapi-experto/SKILL.md +221 -0
  236. package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
  237. package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
  238. package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
  239. package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
  240. package/habilidades/filament-admin/SKILL.md +290 -0
  241. package/habilidades/frontend-avanzado/SKILL.md +257 -0
  242. package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
  243. package/habilidades/gcp-cloud/SKILL.md +260 -0
  244. package/habilidades/gcp-cloud/recursos/gke.md +234 -0
  245. package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
  246. package/habilidades/generacion-mermaid/SKILL.md +229 -0
  247. package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
  248. package/habilidades/go-experto/SKILL.md +305 -0
  249. package/habilidades/go-patrones/SKILL.md +299 -0
  250. package/habilidades/go-testing/SKILL.md +291 -0
  251. package/habilidades/graphql-experto/SKILL.md +323 -0
  252. package/habilidades/guardrail-semantico/SKILL.md +282 -0
  253. package/habilidades/harness-claude-code/SKILL.md +299 -0
  254. package/habilidades/iam-secretos/SKILL.md +265 -0
  255. package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
  256. package/habilidades/infra-github-actions/SKILL.md +166 -0
  257. package/habilidades/instalar-sistema/.evolved.json +9 -0
  258. package/habilidades/instalar-sistema/SKILL.md +221 -0
  259. package/habilidades/java-experto/SKILL.md +290 -0
  260. package/habilidades/java-patrones/SKILL.md +275 -0
  261. package/habilidades/java-testing/SKILL.md +288 -0
  262. package/habilidades/kotlin-compose/SKILL.md +278 -0
  263. package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
  264. package/habilidades/kotlin-experto/SKILL.md +318 -0
  265. package/habilidades/kotlin-testing/SKILL.md +267 -0
  266. package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
  267. package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
  268. package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
  269. package/habilidades/langchain-langraph/SKILL.md +386 -0
  270. package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
  271. package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
  272. package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
  273. package/habilidades/legacy-code-rescue/SKILL.md +267 -0
  274. package/habilidades/likec4-experto/SKILL.md +412 -0
  275. package/habilidades/likec4-experto/evals/evals.json +69 -0
  276. package/habilidades/manejo-errores/.evolved.json +9 -0
  277. package/habilidades/manejo-errores/SKILL.md +407 -0
  278. package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
  279. package/habilidades/mapear-codebase/SKILL.md +275 -0
  280. package/habilidades/memoria-busqueda/SKILL.md +194 -0
  281. package/habilidades/memoria-busqueda/evals/evals.json +44 -0
  282. package/habilidades/meta-skills-estandar/SKILL.md +298 -0
  283. package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
  284. package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
  285. package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
  286. package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
  287. package/habilidades/microservicios/SKILL.md +155 -0
  288. package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
  289. package/habilidades/mobile-flutter/SKILL.md +199 -0
  290. package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
  291. package/habilidades/mobile-react-native/SKILL.md +176 -0
  292. package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
  293. package/habilidades/mongodb-experto/SKILL.md +302 -0
  294. package/habilidades/monitoring-alertas/SKILL.md +201 -0
  295. package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
  296. package/habilidades/nestjs-experto/SKILL.md +307 -0
  297. package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
  298. package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
  299. package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
  300. package/habilidades/nextjs-experto/SKILL.md +335 -0
  301. package/habilidades/nextjs-patrones/SKILL.md +303 -0
  302. package/habilidades/nextjs-testing/SKILL.md +331 -0
  303. package/habilidades/node-experto/.evolved.json +9 -0
  304. package/habilidades/node-experto/SKILL.md +266 -0
  305. package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
  306. package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
  307. package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
  308. package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
  309. package/habilidades/nuevo-proyecto/SKILL.md +204 -0
  310. package/habilidades/orquestacion-async/SKILL.md +303 -0
  311. package/habilidades/paid-media-tracking/SKILL.md +269 -0
  312. package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
  313. package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
  314. package/habilidades/patrones-python/SKILL.md +228 -0
  315. package/habilidades/patrones-python/evals/evals.json +56 -0
  316. package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
  317. package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
  318. package/habilidades/perfil-usuario/SKILL.md +200 -0
  319. package/habilidades/perfil-usuario/evals/evals.json +55 -0
  320. package/habilidades/performance-baseline/SKILL.md +297 -0
  321. package/habilidades/php-experto/SKILL.md +291 -0
  322. package/habilidades/php-patrones/SKILL.md +306 -0
  323. package/habilidades/php-testing/SKILL.md +280 -0
  324. package/habilidades/planear-fase/SKILL.md +269 -0
  325. package/habilidades/postgresql-experto/SKILL.md +151 -0
  326. package/habilidades/postgresql-experto/evals/evals.json +53 -0
  327. package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
  328. package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
  329. package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
  330. package/habilidades/privacy-memoria/SKILL.md +141 -0
  331. package/habilidades/privacy-memoria/evals/evals.json +43 -0
  332. package/habilidades/prompt-engineering/SKILL.md +518 -0
  333. package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
  334. package/habilidades/rag-arquitectura/SKILL.md +338 -0
  335. package/habilidades/rails-experto/SKILL.md +237 -0
  336. package/habilidades/rails-experto/recursos/active-record.md +260 -0
  337. package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
  338. package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
  339. package/habilidades/react-experto/SKILL.md +209 -0
  340. package/habilidades/react-experto/evals/evals.json +55 -0
  341. package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
  342. package/habilidades/react-optimizacion/SKILL.md +174 -0
  343. package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
  344. package/habilidades/redis-experto/SKILL.md +305 -0
  345. package/habilidades/release-semver/.evolved.json +9 -0
  346. package/habilidades/release-semver/SKILL.md +248 -0
  347. package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
  348. package/habilidades/rust-experto/SKILL.md +400 -0
  349. package/habilidades/rust-patrones/SKILL.md +296 -0
  350. package/habilidades/rust-testing/SKILL.md +311 -0
  351. package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
  352. package/habilidades/sql-optimizacion/SKILL.md +200 -0
  353. package/habilidades/sql-optimizacion/evals/evals.json +54 -0
  354. package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
  355. package/habilidades/sre-patrones/SKILL.md +333 -0
  356. package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
  357. package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
  358. package/habilidades/stripe-pagos/SKILL.md +550 -0
  359. package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
  360. package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
  361. package/habilidades/structured-outputs/SKILL.md +343 -0
  362. package/habilidades/swift-experto/SKILL.md +320 -0
  363. package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
  364. package/habilidades/swift-patrones/SKILL.md +313 -0
  365. package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
  366. package/habilidades/swift-testing/SKILL.md +254 -0
  367. package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
  368. package/habilidades/swl-dashboard/SKILL.md +370 -0
  369. package/habilidades/swl-markitdown/SKILL.md +285 -0
  370. package/habilidades/swl-markitdown/evals/evals.json +52 -0
  371. package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
  372. package/habilidades/tailwind-experto/SKILL.md +240 -0
  373. package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
  374. package/habilidades/tdd-workflow/SKILL.md +293 -0
  375. package/habilidades/terraform-experto/SKILL.md +321 -0
  376. package/habilidades/testing-python/SKILL.md +340 -0
  377. package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
  378. package/habilidades/threat-model-lite/SKILL.md +246 -0
  379. package/habilidades/tracing-processor/SKILL.md +212 -0
  380. package/habilidades/tracking-measurement/SKILL.md +239 -0
  381. package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
  382. package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
  383. package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
  384. package/habilidades/typescript-avanzado/SKILL.md +144 -0
  385. package/habilidades/typescript-avanzado/evals/evals.json +55 -0
  386. package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
  387. package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
  388. package/habilidades/ux-diseno/SKILL.md +116 -0
  389. package/habilidades/ux-diseno/evals/evals.json +43 -0
  390. package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
  391. package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
  392. package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
  393. package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
  394. package/habilidades/verificacion-evidencia/SKILL.md +160 -0
  395. package/habilidades/verificar-trabajo/SKILL.md +303 -0
  396. package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
  397. package/habilidades/wiki-conocimiento/SKILL.md +276 -0
  398. package/habilidades/wireframes-flujos/SKILL.md +212 -0
  399. package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
  400. package/habilidades/workflow-claude-code/SKILL.md +260 -0
  401. package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
  402. package/hooks/_run-hook.sh +57 -0
  403. package/hooks/actualizar-perfil-usuario.js +364 -0
  404. package/hooks/agente-lifecycle.js +71 -0
  405. package/hooks/aiisms-detector.js +173 -0
  406. package/hooks/audit-trail.js +204 -0
  407. package/hooks/auto-background.js +97 -0
  408. package/hooks/auto-consolidacion.js +178 -0
  409. package/hooks/auto-evolucion.js +666 -0
  410. package/hooks/auto-restaurar-settings.js +360 -0
  411. package/hooks/calidad-pre-commit.js +929 -0
  412. package/hooks/calidad-typescript.js +511 -0
  413. package/hooks/captura-feedback-usuario.js +148 -0
  414. package/hooks/check-update.js +211 -0
  415. package/hooks/clasificador-mensajes.js +271 -0
  416. package/hooks/degradacion-instintos.js +272 -0
  417. package/hooks/escaneo-secretos.js +389 -0
  418. package/hooks/extraccion-aprendizajes.js +763 -0
  419. package/hooks/grafo-contexto.js +129 -0
  420. package/hooks/graph-update.js +67 -0
  421. package/hooks/guardrail-modelo.js +247 -0
  422. package/hooks/inbox-aviso.js +75 -0
  423. package/hooks/inyeccion-contexto.js +246 -0
  424. package/hooks/lib/abort-registry.js +214 -0
  425. package/hooks/lib/agent-backend.js +210 -0
  426. package/hooks/lib/agent-comms.js +263 -0
  427. package/hooks/lib/agent-issue-codes.js +284 -0
  428. package/hooks/lib/agent-matcher.js +189 -0
  429. package/hooks/lib/async-hook-registry.js +252 -0
  430. package/hooks/lib/atomic-write.js +130 -0
  431. package/hooks/lib/auto-consolidator.js +335 -0
  432. package/hooks/lib/canary-skills.js +187 -0
  433. package/hooks/lib/consolidation-lock.js +291 -0
  434. package/hooks/lib/context-builder.js +430 -0
  435. package/hooks/lib/context-compressor.js +657 -0
  436. package/hooks/lib/convergence-detector.js +105 -0
  437. package/hooks/lib/delegation-tracker.js +198 -0
  438. package/hooks/lib/detectar-package-manager.js +423 -0
  439. package/hooks/lib/edit-accumulator.js +171 -0
  440. package/hooks/lib/error-classifier.js +308 -0
  441. package/hooks/lib/event-bus.js +112 -0
  442. package/hooks/lib/evolution-tracker.js +442 -0
  443. package/hooks/lib/execution-state.js +316 -0
  444. package/hooks/lib/fingerprint-id.js +135 -0
  445. package/hooks/lib/gateway-notify.js +116 -0
  446. package/hooks/lib/graph-security.js +75 -0
  447. package/hooks/lib/guardrail-metrics.js +202 -0
  448. package/hooks/lib/hook-circuit-breaker.js +206 -0
  449. package/hooks/lib/loop-detector.js +267 -0
  450. package/hooks/lib/mcp-health.js +184 -0
  451. package/hooks/lib/mcp-pool.js +436 -0
  452. package/hooks/lib/memory-search.js +506 -0
  453. package/hooks/lib/merkle-audit.js +96 -0
  454. package/hooks/lib/model-router.js +222 -0
  455. package/hooks/lib/normalize-error.js +324 -0
  456. package/hooks/lib/normalize-input.js +65 -0
  457. package/hooks/lib/nudge-tracker.js +306 -0
  458. package/hooks/lib/otlp-exporter.js +365 -0
  459. package/hooks/lib/performance-marks.js +239 -0
  460. package/hooks/lib/privacy-filter.js +128 -0
  461. package/hooks/lib/prompt-injection-scanner.js +209 -0
  462. package/hooks/lib/provenance-tracker.js +183 -0
  463. package/hooks/lib/rate-limit-tracker.js +253 -0
  464. package/hooks/lib/reflect-classifier.js +164 -0
  465. package/hooks/lib/resource-quota.js +122 -0
  466. package/hooks/lib/retry-jitter.js +165 -0
  467. package/hooks/lib/risk-engine.js +368 -0
  468. package/hooks/lib/run-log.js +408 -0
  469. package/hooks/lib/session-fts.js +379 -0
  470. package/hooks/lib/session-store.js +293 -0
  471. package/hooks/lib/singleton-guard.js +159 -0
  472. package/hooks/lib/skill-auditor.js +588 -0
  473. package/hooks/lib/sync-status.js +228 -0
  474. package/hooks/lib/taint-tracker.js +107 -0
  475. package/hooks/lib/task-service.js +295 -0
  476. package/hooks/lib/tech-skills-map.js +146 -0
  477. package/hooks/lib/telegram-cliente.js +159 -0
  478. package/hooks/lib/telegram-config.js +170 -0
  479. package/hooks/lib/token-budget.js +156 -0
  480. package/hooks/lib/token-estimator.js +420 -0
  481. package/hooks/lib/toon-compressor.js +245 -0
  482. package/hooks/lib/usage-model.js +183 -0
  483. package/hooks/lib/variable-resolver.js +230 -0
  484. package/hooks/linea-estado.js +324 -0
  485. package/hooks/metricas-evolucion.js +209 -0
  486. package/hooks/monitor-contexto.js +325 -0
  487. package/hooks/notificacion-sesion-stop.js +198 -0
  488. package/hooks/notificacion-telegram-notification.js +4 -0
  489. package/hooks/notificacion-telegram-subagent.js +4 -0
  490. package/hooks/notificacion-telegram.js +267 -0
  491. package/hooks/preservar-estado-pre-compact.js +150 -0
  492. package/hooks/proteccion-rutas.js +366 -0
  493. package/hooks/registro-turnos.js +209 -0
  494. package/hooks/resumen-sesion.js +249 -0
  495. package/hooks/risk-scoring.js +323 -0
  496. package/hooks/rotar-audit-auto.js +122 -0
  497. package/hooks/sugerir-regenerar-inventario.js +170 -0
  498. package/hooks/telemetria-agentes.js +167 -0
  499. package/hooks/tracking-costos.js +688 -0
  500. package/instintos/global.yaml +8 -0
  501. package/instintos/perfil-usuario.yaml +53 -0
  502. package/instintos/prompt-appendices.yaml +57 -0
  503. package/instintos/proyecto.yaml +372 -0
  504. package/manifiestos/gateway-config.json +77 -0
  505. package/manifiestos/handoff-context.json +223 -0
  506. package/manifiestos/hook-profiles.json +44 -0
  507. package/manifiestos/hooks-config.json +360 -0
  508. package/manifiestos/modulos.json +1173 -0
  509. package/manifiestos/perfiles.json +404 -0
  510. package/package.json +86 -0
  511. package/plantillas/ESTADO.md +109 -0
  512. package/plantillas/HOJA-RUTA.md +143 -0
  513. package/plantillas/PROYECTO.md +122 -0
  514. package/plantillas/REQUISITOS.md +132 -0
  515. package/plantillas/auditor-veto-template.md +105 -0
  516. package/plantillas/github-workflows/README.md +47 -0
  517. package/plantillas/github-workflows/release-please.yml +44 -0
  518. package/plantillas/github-workflows/swl-ci.yml +107 -0
  519. package/plantillas/github-workflows/swl-security.yml +51 -0
  520. package/plantillas/mcp-mineru.json +13 -0
  521. package/plantillas/research/ARQUITECTURA.md +220 -0
  522. package/plantillas/research/FUNCIONALIDADES.md +175 -0
  523. package/plantillas/research/RESUMEN.md +165 -0
  524. package/plantillas/research/STACK.md +233 -0
  525. package/plantillas/research/TRAMPAS.md +299 -0
  526. package/plantillas/skill-evals-template.json +44 -0
  527. package/plugin.json +343 -0
  528. package/reglas/accesibilidad.md +269 -0
  529. package/reglas/api-diseno.md +400 -0
  530. package/reglas/arquitectura.md +352 -0
  531. package/reglas/brevedad-output.md +124 -0
  532. package/reglas/cloud-infra.md +247 -0
  533. package/reglas/docs.md +245 -0
  534. package/reglas/estilo-codigo.md +201 -0
  535. package/reglas/git-workflow.md +245 -0
  536. package/reglas/gobernanza.md +271 -0
  537. package/reglas/harness-claude-code.md +213 -0
  538. package/reglas/hooks.md +186 -0
  539. package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
  540. package/reglas/lenguajes/csharp/hooks.md +281 -0
  541. package/reglas/lenguajes/csharp/patrones.md +226 -0
  542. package/reglas/lenguajes/csharp/seguridad.md +258 -0
  543. package/reglas/lenguajes/csharp/testing.md +176 -0
  544. package/reglas/lenguajes/go/estilo-codigo.md +195 -0
  545. package/reglas/lenguajes/go/hooks.md +249 -0
  546. package/reglas/lenguajes/go/patrones.md +249 -0
  547. package/reglas/lenguajes/go/seguridad.md +225 -0
  548. package/reglas/lenguajes/go/testing.md +272 -0
  549. package/reglas/lenguajes/java/estilo-codigo.md +217 -0
  550. package/reglas/lenguajes/java/hooks.md +251 -0
  551. package/reglas/lenguajes/java/patrones.md +226 -0
  552. package/reglas/lenguajes/java/seguridad.md +233 -0
  553. package/reglas/lenguajes/java/testing.md +238 -0
  554. package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
  555. package/reglas/lenguajes/kotlin/hooks.md +245 -0
  556. package/reglas/lenguajes/kotlin/patrones.md +201 -0
  557. package/reglas/lenguajes/kotlin/seguridad.md +202 -0
  558. package/reglas/lenguajes/kotlin/testing.md +236 -0
  559. package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
  560. package/reglas/lenguajes/nextjs/hooks.md +186 -0
  561. package/reglas/lenguajes/nextjs/patrones.md +225 -0
  562. package/reglas/lenguajes/nextjs/seguridad.md +216 -0
  563. package/reglas/lenguajes/nextjs/testing.md +193 -0
  564. package/reglas/lenguajes/php/estilo-codigo.md +228 -0
  565. package/reglas/lenguajes/php/hooks.md +165 -0
  566. package/reglas/lenguajes/php/patrones.md +233 -0
  567. package/reglas/lenguajes/php/seguridad.md +186 -0
  568. package/reglas/lenguajes/php/testing.md +205 -0
  569. package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
  570. package/reglas/lenguajes/rust/hooks.md +240 -0
  571. package/reglas/lenguajes/rust/patrones.md +250 -0
  572. package/reglas/lenguajes/rust/seguridad.md +221 -0
  573. package/reglas/lenguajes/rust/testing.md +194 -0
  574. package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
  575. package/reglas/lenguajes/swift/hooks.md +257 -0
  576. package/reglas/lenguajes/swift/patrones.md +235 -0
  577. package/reglas/lenguajes/swift/seguridad.md +248 -0
  578. package/reglas/lenguajes/swift/testing.md +242 -0
  579. package/reglas/markitdown.md +60 -0
  580. package/reglas/memoria-consolidada.md +209 -0
  581. package/reglas/patrones.md +225 -0
  582. package/reglas/performance.md +195 -0
  583. package/reglas/pruebas.md +159 -0
  584. package/reglas/seguridad-agentes.md +351 -0
  585. package/reglas/seguridad.md +151 -0
  586. package/reglas/skills-estandar.md +373 -0
  587. package/reglas/testing.md +193 -0
  588. package/schemas/agent-contract.json +176 -0
  589. package/schemas/agent-frontmatter.schema.json +149 -0
  590. package/schemas/agent-message.schema.json +53 -0
  591. package/schemas/agent-output-implementacion.schema.json +85 -0
  592. package/schemas/agent-output-planificacion.schema.json +113 -0
  593. package/schemas/agent-output-review.schema.json +78 -0
  594. package/schemas/diary-entry.schema.json +80 -0
  595. package/schemas/hook-profiles.schema.json +39 -0
  596. package/schemas/hooks-config.schema.json +74 -0
  597. package/schemas/instinct.schema.json +115 -0
  598. package/schemas/modulos.schema.json +29 -0
  599. package/schemas/perfiles.schema.json +28 -0
  600. package/schemas/plugin.schema.json +64 -0
  601. package/schemas/skill-evals.schema.json +95 -0
  602. package/schemas/skill-frontmatter.schema.json +170 -0
  603. package/scripts/actualizar.js +145 -0
  604. package/scripts/audit-skills.sh +78 -0
  605. package/scripts/auditar-agentes-gaps.js +149 -0
  606. package/scripts/auditar-cobertura-frameworks.js +241 -0
  607. package/scripts/auditar-skills-gaps.js +206 -0
  608. package/scripts/bootstrap-instintos.js +259 -0
  609. package/scripts/check-update.js +109 -0
  610. package/scripts/comandos/agents.js +105 -0
  611. package/scripts/comandos/info.js +108 -0
  612. package/scripts/comandos/install-asistido.js +186 -0
  613. package/scripts/comandos/skills.js +211 -0
  614. package/scripts/configurar-branch-protection.js +418 -0
  615. package/scripts/daemon-swl.py +388 -0
  616. package/scripts/desinstalar.js +130 -0
  617. package/scripts/doctor.js +559 -0
  618. package/scripts/field-report.js +199 -0
  619. package/scripts/generar-inventario.js +317 -0
  620. package/scripts/inbox-tmux-inject.js +161 -0
  621. package/scripts/inferir-herramientas-permitidas.js +586 -0
  622. package/scripts/inicializar.js +133 -0
  623. package/scripts/instalador.js +1031 -0
  624. package/scripts/instalar-git-hook.js +122 -0
  625. package/scripts/lib/agp-frontmatter.js +222 -0
  626. package/scripts/lib/append-con-marcadores.js +199 -0
  627. package/scripts/lib/artefactos-python.js +43 -0
  628. package/scripts/lib/audit-query.js +221 -0
  629. package/scripts/lib/autostart-linux.js +347 -0
  630. package/scripts/lib/autostart-macos.js +360 -0
  631. package/scripts/lib/autostart-windows.js +307 -0
  632. package/scripts/lib/budget-enforcer.js +252 -0
  633. package/scripts/lib/claude-sessions.js +285 -0
  634. package/scripts/lib/configurar-ci.js +380 -0
  635. package/scripts/lib/console-span-exporter.js +92 -0
  636. package/scripts/lib/contadores-inventario.js +217 -0
  637. package/scripts/lib/dashboard-widgets.js +290 -0
  638. package/scripts/lib/detectar-runtime.js +279 -0
  639. package/scripts/lib/detectar-stack.js +187 -0
  640. package/scripts/lib/diary-entry.js +234 -0
  641. package/scripts/lib/drift-detector.js +545 -0
  642. package/scripts/lib/estado.js +124 -0
  643. package/scripts/lib/gestor-componentes.js +243 -0
  644. package/scripts/lib/gitignore-manifest.js +305 -0
  645. package/scripts/lib/graph-analyze.py +556 -0
  646. package/scripts/lib/graph-builder.py +485 -0
  647. package/scripts/lib/graph-cluster.py +259 -0
  648. package/scripts/lib/health-row.js +168 -0
  649. package/scripts/lib/hooks-settings.js +789 -0
  650. package/scripts/lib/manifiestos.js +138 -0
  651. package/scripts/lib/mc-client.js +137 -0
  652. package/scripts/lib/notificaciones-telegram.js +1107 -0
  653. package/scripts/lib/npm-version.js +261 -0
  654. package/scripts/lib/paquetes-conocidos.js +50 -0
  655. package/scripts/lib/preservar-usuario.js +586 -0
  656. package/scripts/lib/prompt-builder.js +264 -0
  657. package/scripts/lib/resolver-externo.js +332 -0
  658. package/scripts/lib/schedule-parser.js +305 -0
  659. package/scripts/lib/scoring-instintos.js +240 -0
  660. package/scripts/lib/seguridad.js +160 -0
  661. package/scripts/lib/selector-interactivo.js +152 -0
  662. package/scripts/lib/semantic-search.js +242 -0
  663. package/scripts/lib/skill-discovery.js +234 -0
  664. package/scripts/lib/skill-metrics.js +246 -0
  665. package/scripts/lib/skill-normalizer.js +112 -0
  666. package/scripts/lib/skills-hub.js +340 -0
  667. package/scripts/lib/span-schema.js +134 -0
  668. package/scripts/lib/tool-cost-analyzer.js +255 -0
  669. package/scripts/lib/tracing-processor-interface.js +286 -0
  670. package/scripts/lib/transformadores/base.js +80 -0
  671. package/scripts/lib/transformadores/claude.js +124 -0
  672. package/scripts/lib/transformadores/codex.js +115 -0
  673. package/scripts/lib/transformadores/copilot.js +106 -0
  674. package/scripts/lib/transformadores/gemini.js +74 -0
  675. package/scripts/lib/transformadores/index.js +35 -0
  676. package/scripts/lib/transformadores/opencode.js +75 -0
  677. package/scripts/lib/ui.js +259 -0
  678. package/scripts/limpiar-artefactos-python.js +131 -0
  679. package/scripts/mcp-orchestrator.py +386 -0
  680. package/scripts/mcp-pool-manager.py +352 -0
  681. package/scripts/mcp-telemetry.py +378 -0
  682. package/scripts/poblar-evolvable.js +226 -0
  683. package/scripts/publicar.js +287 -0
  684. package/scripts/reflect-skills.js +403 -0
  685. package/scripts/rotar-audit-logs.js +185 -0
  686. package/scripts/run-skill-evals.js +242 -0
  687. package/scripts/smoke-test.js +374 -0
  688. package/scripts/token-analysis.py +471 -0
  689. package/scripts/validar-manifest.js +195 -0
  690. package/scripts/validar-memoria.js +321 -0
  691. package/scripts/validar-tests-aislamiento.js +184 -0
  692. package/scripts/validar-tokens-test.js +208 -0
  693. package/scripts/validar.js +147 -0
  694. package/scripts/validate-markdown.py +339 -0
  695. package/scripts/validate-skills.py +385 -0
  696. package/scripts/vendor/claude-usage/README.md +116 -0
  697. package/scripts/vendor/claude-usage/cli.py +334 -0
  698. package/scripts/vendor/claude-usage/dashboard.py +795 -0
  699. package/scripts/vendor/claude-usage/scanner.py +467 -0
  700. package/scripts/vendor/markitdown/cli.py +194 -0
  701. package/scripts/verificar-evolucion.js +289 -0
  702. package/scripts/verificar-release.js +494 -0
@@ -0,0 +1,321 @@
1
+ ---
2
+ name: terraform-experto
3
+ description: >
4
+ Terraform: module design, remote state con S3+DynamoDB, workspaces, import,
5
+ moved blocks, lifecycle rules, for_each y seguridad con checkov/tfsec. Cargar
6
+ cuando se escriba infraestructura como código o se diseñen modules Terraform.
7
+ version: "1.0.0"
8
+ herramientasPermitidas: [Read, Grep]
9
+ exclusiones:
10
+ - "No cargar para Kubernetes manifiestos YAML o Helm charts — para Kubernetes cargar `kubernetes-orquestacion`."
11
+ - "No cargar para Pulumi, CDK o CloudFormation — son herramientas IaC distintas con APIs y DSLs incompatibles con Terraform HCL."
12
+ - "No cargar para Docker y containerización — para Docker cargar `contenedores-docker`."
13
+ - "No cargar para recursos cloud específicos (políticas IAM de AWS, redes de Azure) sin contexto Terraform — para cloud sin IaC cargar `cloud-aws`, `azure-cloud` o `gcp-cloud`."
14
+ evolvable: true # default para skill estandar
15
+ ---
16
+ # Terraform Experto — IaC Moderno
17
+
18
+ Terraform es el estándar de IaC multi-cloud. Un módulo bien diseñado es pequeño,
19
+ reutilizable y con interfaz minimal. El estado remoto con locking es obligatorio
20
+ en equipos. Este skill cubre el diseño de módulos, estrategias de estado, patrones
21
+ de seguridad y el flujo correcto de trabajo.
22
+
23
+ ## Cuándo NO cargar
24
+
25
+ - La tarea es Kubernetes YAML o Helm charts — cargar `kubernetes-orquestacion`.
26
+ - La herramienta IaC es Pulumi, AWS CDK o CloudFormation — tienen DSLs incompatibles con HCL.
27
+ - El trabajo es Docker y containerización — cargar `contenedores-docker`.
28
+ - La pregunta es sobre recursos cloud (IAM, networking) fuera del contexto de Terraform — cargar `cloud-aws`, `azure-cloud` o `gcp-cloud`.
29
+
30
+ ## Cuándo cargar este skill
31
+
32
+ Invoca `Skill("terraform-experto")` cuando:
33
+
34
+ - Se escriban resources, modules o data sources de Terraform
35
+ - Se diseñe la estructura de módulos para un proyecto nuevo
36
+ - Se configure remote state con locking
37
+ - Se importe infraestructura existente con `terraform import` o import blocks
38
+ - Se evaluen estrategias de workspaces vs multiple state files
39
+ - Se configure checkov o tfsec para seguridad
40
+
41
+ ## Conceptos clave
42
+
43
+ ### Modules — la unidad de reutilización
44
+
45
+ Un módulo es un directorio con archivos `.tf`. El módulo raíz es el que se aplica
46
+ directamente. Los módulos hijo encapsulan recursos relacionados con una interfaz
47
+ de `variables.tf` (inputs) y `outputs.tf` (outputs). Un buen módulo tiene más
48
+ implementación que interfaz.
49
+
50
+ ### Remote State con Locking
51
+
52
+ El estado de Terraform contiene la información de todos los recursos gestionados.
53
+ En equipos, debe almacenarse en backend remoto (S3, GCS, Terraform Cloud) con
54
+ locking habilitado para evitar applies concurrentes. DynamoDB como lock en AWS,
55
+ GCS nativo en GCP.
56
+
57
+ ### for_each vs count
58
+
59
+ `count` genera recursos por índice numérico — frágil porque cambiar el orden
60
+ recrea recursos. `for_each` genera recursos por clave de mapa o set — estable
61
+ porque la clave identifica el recurso. Preferir `for_each` siempre que sea posible.
62
+
63
+ ## Reglas obligatorias
64
+
65
+ ### Terraform plan SIEMPRE antes de apply — nunca apply directo
66
+
67
+ ```bash
68
+ # MAL — apply sin revisar el plan
69
+ terraform apply
70
+
71
+ # BIEN — plan con output a archivo, luego apply del mismo plan
72
+ terraform plan -out=tfplan
73
+ # Revisar el plan: terraform show -json tfplan | jq '.resource_changes[]'
74
+ terraform apply tfplan
75
+ ```
76
+
77
+ **Por qué**: Un `terraform apply` sin plan puede destruir recursos si el estado
78
+ está desactualizado o si hay cambios de configuración inesperados.
79
+
80
+ ### NUNCA hardcodear valores — usar variables con validación
81
+
82
+ ```hcl
83
+ # MAL — valores hardcodeados no reutilizables
84
+ resource "aws_instance" "web" {
85
+ instance_type = "t3.micro"
86
+ ami = "ami-0c55b159cbfafe1f0"
87
+ }
88
+
89
+ # BIEN — variables con validacion y descripcion
90
+ variable "instance_type" {
91
+ type = string
92
+ description = "Tipo de instancia EC2"
93
+ default = "t3.micro"
94
+
95
+ validation {
96
+ condition = contains(["t3.micro", "t3.small", "t3.medium"], var.instance_type)
97
+ error_message = "Solo se permiten instancias t3.micro, t3.small o t3.medium."
98
+ }
99
+ }
100
+ ```
101
+
102
+ ### Modules con versión pinneada — nunca rangos abiertos
103
+
104
+ ```hcl
105
+ # MAL — version no pinneada, puede romper en el proximo apply
106
+ module "vpc" {
107
+ source = "terraform-aws-modules/vpc/aws"
108
+ version = "~> 5.0" # cualquier 5.x puede incluir breaking changes
109
+ }
110
+
111
+ # BIEN — version exacta, actualizar conscientemente
112
+ module "vpc" {
113
+ source = "terraform-aws-modules/vpc/aws"
114
+ version = "5.5.3"
115
+ }
116
+ ```
117
+
118
+ ### prevent_destroy para recursos críticos de datos
119
+
120
+ ```hcl
121
+ resource "aws_db_instance" "principal" {
122
+ # ...configuracion...
123
+
124
+ lifecycle {
125
+ prevent_destroy = true # falla el plan si algo intenta destruir esta BD
126
+ }
127
+ }
128
+ ```
129
+
130
+ ## Patrones recomendados
131
+
132
+ ### Estructura de módulo bien organizado
133
+
134
+ ```
135
+ modulo-vpc/
136
+ ├── main.tf # Resources principales
137
+ ├── variables.tf # Inputs con descripcion y validacion
138
+ ├── outputs.tf # Outputs documentados
139
+ ├── versions.tf # required_providers y terraform version
140
+ └── README.md # Generado con terraform-docs
141
+ ```
142
+
143
+ ```hcl
144
+ # versions.tf
145
+ terraform {
146
+ required_version = ">= 1.6.0"
147
+
148
+ required_providers {
149
+ aws = {
150
+ source = "hashicorp/aws"
151
+ version = "~> 5.0"
152
+ }
153
+ }
154
+ }
155
+ ```
156
+
157
+ ### Remote State con S3 + DynamoDB (AWS)
158
+
159
+ ```hcl
160
+ # backend.tf
161
+ terraform {
162
+ backend "s3" {
163
+ bucket = "mi-empresa-terraform-state"
164
+ key = "produccion/vpc/terraform.tfstate"
165
+ region = "us-east-1"
166
+ encrypt = true # cifrado en reposo OBLIGATORIO
167
+ dynamodb_table = "terraform-state-locks" # locking
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### for_each para múltiples recursos similares
173
+
174
+ ```hcl
175
+ variable "ambientes" {
176
+ type = map(object({
177
+ cidr_block = string
178
+ enable_nat = bool
179
+ }))
180
+ default = {
181
+ staging = { cidr_block = "10.1.0.0/16", enable_nat = false }
182
+ prod = { cidr_block = "10.0.0.0/16", enable_nat = true }
183
+ }
184
+ }
185
+
186
+ resource "aws_vpc" "ambientes" {
187
+ for_each = var.ambientes
188
+ cidr_block = each.value.cidr_block
189
+
190
+ tags = {
191
+ Name = "vpc-${each.key}"
192
+ Ambiente = each.key
193
+ }
194
+ }
195
+ ```
196
+
197
+ ### Import block (Terraform 1.5+) para infraestructura existente
198
+
199
+ ```hcl
200
+ # import.tf — declarativo, incluible en el codigo
201
+ import {
202
+ to = aws_s3_bucket.logs
203
+ id = "mi-bucket-logs-existente"
204
+ }
205
+
206
+ resource "aws_s3_bucket" "logs" {
207
+ bucket = "mi-bucket-logs-existente"
208
+ # terraform genera el codigo inicial con: terraform plan -generate-config-out=generated.tf
209
+ }
210
+ ```
211
+
212
+ ### moved block para refactorizar sin destruir recursos
213
+
214
+ ```hcl
215
+ # Al renombrar un resource o moverlo a un modulo
216
+ moved {
217
+ from = aws_security_group.web
218
+ to = module.web_server.aws_security_group.this
219
+ }
220
+ ```
221
+
222
+ ### Dynamic blocks para configuración variable
223
+
224
+ ```hcl
225
+ resource "aws_security_group" "web" {
226
+ name = "sg-web"
227
+
228
+ dynamic "ingress" {
229
+ for_each = var.puertos_permitidos
230
+ content {
231
+ from_port = ingress.value
232
+ to_port = ingress.value
233
+ protocol = "tcp"
234
+ cidr_blocks = ["0.0.0.0/0"]
235
+ }
236
+ }
237
+ }
238
+ ```
239
+
240
+ ### Locals para expresiones reutilizables
241
+
242
+ ```hcl
243
+ locals {
244
+ tags_comunes = {
245
+ proyecto = var.nombre_proyecto
246
+ ambiente = var.ambiente
247
+ gestionado = "terraform"
248
+ equipo = var.equipo
249
+ }
250
+
251
+ prefijo = "${var.nombre_proyecto}-${var.ambiente}"
252
+ }
253
+
254
+ resource "aws_s3_bucket" "datos" {
255
+ bucket = "${local.prefijo}-datos"
256
+ tags = local.tags_comunes
257
+ }
258
+ ```
259
+
260
+ ## Anti-patrones conocidos
261
+
262
+ ### Estado local en equipo — siempre usar backend remoto
263
+
264
+ ```hcl
265
+ # MAL — estado en disco local (default si no se configura backend)
266
+ # El estado se pierde si el disco falla y no se puede trabajar en equipo
267
+
268
+ # BIEN — siempre configurar backend remoto antes del primer apply
269
+ terraform {
270
+ backend "s3" { ... }
271
+ }
272
+ ```
273
+
274
+ ### Módulos monolíticos con 500+ líneas
275
+
276
+ Un módulo con 500 resources mezcla responsabilidades y es imposible de reutilizar.
277
+ Dividir por dominio: modulo-red, modulo-compute, modulo-bd. La interfaz de cada
278
+ módulo debe ser pequeña comparada con su implementación.
279
+
280
+ ### ignore_changes para ocultar drift — investigar la causa en su lugar
281
+
282
+ ```hcl
283
+ # SOLO usar ignore_changes cuando el recurso se modifica por un proceso externo
284
+ # documentado. Nunca para ocultar conflictos sin entender la causa.
285
+ lifecycle {
286
+ ignore_changes = [
287
+ tags["LastModified"], # etiqueta que AWS actualiza automaticamente
288
+ ]
289
+ }
290
+ ```
291
+
292
+ ## Gotchas / Errores comunes no obvios
293
+
294
+ **`count` en lugar de `for_each` causa recreación de recursos si se elimina un elemento del medio de la lista**: `count = length(var.servidores)` crea recursos indexados `aws_instance.web[0]`, `[1]`, `[2]` — si se elimina `servidores[1]`, Terraform recrea `[1]` (con los valores de `[2]`) y destruye `[2]`. Causa: los recursos con `count` son identificados por índice numérico, no por valor. Fix: siempre usar `for_each = toset(var.servidores)` para colecciones — los recursos se identifican por la clave del mapa/set y la eliminación de un elemento no afecta a los demás.
295
+
296
+ **`terraform apply` en CI sin `-auto-approve` bloquea esperando input interactivo**: si el pipeline no pasa `-auto-approve`, Terraform espera `yes` del usuario — en CI no hay terminal interactivo y el job se congela hasta el timeout. Causa: comportamiento por defecto de Terraform para prevenir applies accidentales. Fix: en CI SIEMPRE usar `terraform apply -auto-approve tfplan` donde `tfplan` es el archivo de plan generado previamente con `terraform plan -out=tfplan` — nunca `terraform apply -auto-approve` sin plan previo.
297
+
298
+ **`terraform state` modificado manualmente (mv, rm) sin un `moved` block crea drift que otros membres del equipo no ven**: `terraform state mv` modifica el state file remoto pero no deja evidencia en el código HCL — otros miembros que ejecuten `terraform plan` ven diferencias inesperadas. Causa: el state file es el source of truth pero no está versionado junto con el código. Fix: para renombrar o mover recursos, usar siempre `moved {}` blocks en el HCL (Terraform 1.1+) que se commitean al repositorio — son la forma declarativa y rastreable de refactorizar recursos.
299
+
300
+ **`for_each` con un `map` que contiene valores de otro resource que no existe aún causa error de "value not known until apply"**: `for_each = var.ips_elasticas` donde `var.ips_elasticas` es un output de otro resource que se crea en el mismo apply lanza error porque el set de `for_each` debe ser conocido antes del apply. Causa: Terraform necesita conocer las claves del `for_each` en la fase de plan para saber cuántos recursos crear. Fix: usar valores estáticos como claves de `for_each` (strings conocidos) y referenciar el resource dinámico como atributo del objeto, no como clave.
301
+
302
+ ## Checklist de verificación
303
+
304
+ - [ ] Plan revisado antes de cada apply
305
+ - [ ] Backend remoto con locking configurado desde el inicio
306
+ - [ ] Módulos con versión exacta pinneada
307
+ - [ ] Variables con `description` y `validation` donde aplica
308
+ - [ ] `prevent_destroy` en recursos críticos (BD, buckets con datos)
309
+ - [ ] `for_each` en lugar de `count` para recursos en colecciones
310
+ - [ ] Tags obligatorios definidos en `locals` y aplicados a todos los recursos
311
+ - [ ] checkov o tfsec ejecutado en CI sin errores HIGH/CRITICAL
312
+
313
+ ## Referencias
314
+
315
+ - [Terraform Documentation](https://developer.hashicorp.com/terraform/docs)
316
+ - [terraform-aws-modules](https://registry.terraform.io/namespaces/terraform-aws-modules)
317
+ - [checkov](https://www.checkov.io)
318
+ - [tfsec](https://aquasecurity.github.io/tfsec)
319
+
320
+ ---
321
+ *Skill creado con swl:crear-skill el 2026-03-31. Versión 1.0.0.*
@@ -0,0 +1,340 @@
1
+ ---
2
+ name: testing-python
3
+ description: Testing Python con pytest. Fixtures, mocking, parametrize, cobertura, factories, testing async y patrones de test doubles. TDD y testing de capas separadas.
4
+ version: "1.2.1"
5
+ herramientasPermitidas: [Read, Bash]
6
+ exclusiones:
7
+ - "No cargar para tests de integración específicos de FastAPI (TestClient, AsyncClient con httpx) — esos tienen fixtures específicos del framework; cargar `fastapi-experto` que incluye la sección de testing con httpx."
8
+ - "No cargar para tests de Django (pytest-django, `@pytest.mark.django_db`, factory-boy para modelos Django) — cargar `django-experto` que cubre el testing con el setup de settings y base de datos."
9
+ - "No cargar para métricas de calidad del código (cobertura, complejidad ciclomática, análisis estático) — esas métricas se cubren en `checklist-calidad`; este skill es para escribir tests, no para analizar su cobertura."
10
+ - "No cargar para evaluar la calidad de un test suite existente de un proyecto — para auditoría de tests cargar `checklist-calidad` o invocar `revisor-codigo-swl`."
11
+ evolvable: true # default para skill estandar
12
+ evolved: true
13
+ evolved-from: "5.12.3"
14
+ evolved-at: "2026-04-25"
15
+ evolved-by: "aprender"
16
+ evolved-note: "2 gotchas nuevos: chdir vs __dirname y sanitizar-antes-de-truncar"
17
+ ---
18
+ # Testing Python con pytest
19
+
20
+ ## Cuándo NO cargar
21
+
22
+ - Los tests son de FastAPI con AsyncClient/httpx — cargar `fastapi-experto` para el contexto de fixtures de ese framework.
23
+ - Los tests son de Django con pytest-django y `@pytest.mark.django_db` — cargar `django-experto`.
24
+ - La tarea es auditar la cobertura existente — cargar `checklist-calidad` para métricas de calidad.
25
+
26
+ ## Principios de testing
27
+
28
+ - **Un test verifica un solo comportamiento** — no múltiples cosas a la vez.
29
+ - **Los tests son documentación** — el nombre del test debe describir QUÉ se prueba.
30
+ - **Test doubles solo cuando es necesario** — no mockear lo que puedes usar real.
31
+ - **Tests rápidos > tests lentos** — unitarios son milisegundos; de integración, segundos.
32
+ - **Cobertura de líneas no es meta** — cobertura de comportamientos sí lo es.
33
+
34
+ ---
35
+
36
+ ## Estructura de proyecto de tests
37
+
38
+ ```
39
+ tests/
40
+ ├── conftest.py # Fixtures compartidos globalmente
41
+ ├── unit/ # Tests unitarios (sin I/O)
42
+ │ ├── conftest.py
43
+ │ ├── test_factura_service.py
44
+ │ └── test_validaciones.py
45
+ ├── integration/ # Tests con BD real (o en memoria)
46
+ │ ├── conftest.py
47
+ │ └── test_factura_api.py
48
+ └── e2e/ # Tests end-to-end (opcional)
49
+ └── test_flujo_facturacion.py
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Nomenclatura de tests
55
+
56
+ ```python
57
+ # Patrón: test_<qué>_<condición>_<resultado_esperado>
58
+ def test_calcular_iva_monto_positivo_retorna_monto_correcto(): ...
59
+ def test_calcular_iva_monto_negativo_lanza_valor_error(): ...
60
+ def test_crear_factura_cliente_inactivo_lanza_error_negocio(): ...
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Fixtures
66
+
67
+ ```python
68
+ # conftest.py
69
+ import pytest
70
+ from decimal import Decimal
71
+
72
+ @pytest.fixture
73
+ def monto_valido() -> Decimal:
74
+ return Decimal("1000.00")
75
+
76
+ @pytest.fixture
77
+ def factura_data() -> dict:
78
+ return {
79
+ "folio": "F-001",
80
+ "fecha": "2026-03-25",
81
+ "subtotal": Decimal("1000.00"),
82
+ "cliente_id": "cliente-123",
83
+ }
84
+
85
+ # Fixture con scope para BD — se crea una vez por sesión
86
+ @pytest.fixture(scope="session")
87
+ def engine():
88
+ from sqlalchemy import create_engine
89
+ engine = create_engine("sqlite:///:memory:")
90
+ Base.metadata.create_all(engine)
91
+ yield engine
92
+ Base.metadata.drop_all(engine)
93
+
94
+ @pytest.fixture
95
+ def db(engine):
96
+ from sqlalchemy.orm import Session
97
+ with Session(engine) as session:
98
+ yield session
99
+ session.rollback() # Limpiar después de cada test
100
+ ```
101
+
102
+ ---
103
+
104
+ ## Parametrize — probar múltiples casos
105
+
106
+ ```python
107
+ import pytest
108
+ from decimal import Decimal
109
+
110
+ @pytest.mark.parametrize("monto,tasa,esperado", [
111
+ (Decimal("100.00"), 0.16, Decimal("16.00")),
112
+ (Decimal("0.00"), 0.16, Decimal("0.00")),
113
+ (Decimal("999.99"), 0.16, Decimal("159.998")),
114
+ ])
115
+ def test_calcular_iva(monto, tasa, esperado):
116
+ resultado = calcular_iva(monto, tasa)
117
+ assert resultado == pytest.approx(float(esperado), rel=1e-4)
118
+
119
+ # Parametrize con IDs descriptivos
120
+ @pytest.mark.parametrize("estatus,puede_cancelar", [
121
+ pytest.param("borrador", True, id="borrador-puede-cancelar"),
122
+ pytest.param("cancelada", False, id="cancelada-ya-cancelada"),
123
+ ])
124
+ def test_factura_puede_cancelar(estatus, puede_cancelar):
125
+ factura = Factura(estatus=estatus)
126
+ assert factura.puede_cancelar() == puede_cancelar
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Mocking — reglas clave
132
+
133
+ - Mockear en el boundary: BD, APIs externas, filesystem, reloj.
134
+ - NUNCA mockear código propio — señal de acoplamiento excesivo.
135
+ - Usar `pytest-mock` (mocker) sobre `unittest.mock.patch` para mayor limpieza.
136
+ - `AsyncMock` para funciones async.
137
+
138
+ Para ejemplos completos de mocking, testing async y factories, ver [recursos/ejemplos-completos.md](recursos/ejemplos-completos.md).
139
+
140
+ ---
141
+
142
+ ## Factories con factory_boy — resumen
143
+
144
+ Usar factories sobre fixtures hardcodeados. Permiten sobreescribir solo lo relevante:
145
+
146
+ ```python
147
+ # tests/factories.py — definir factories centralizados
148
+ class FacturaFactory(factory.Factory):
149
+ class Meta:
150
+ model = Factura
151
+ estatus = "borrador"
152
+ cliente = factory.SubFactory(ClienteFactory)
153
+
154
+ # En el test — solo los datos que importan
155
+ factura = FacturaFactory(estatus="pagada", total=Decimal("1000.00"))
156
+ ```
157
+
158
+ Para ejemplos completos de factories con factory_boy, ver [recursos/ejemplos-completos.md](recursos/ejemplos-completos.md).
159
+
160
+ ---
161
+
162
+ ## Cobertura de tests
163
+
164
+ ```bash
165
+ # Ejecutar con cobertura
166
+ pytest --cov=app --cov-report=term-missing --cov-report=html
167
+
168
+ # Requerir cobertura mínima (falla si no se alcanza)
169
+ pytest --cov=app --cov-fail-under=85
170
+ ```
171
+
172
+ ```toml
173
+ # pyproject.toml
174
+ [tool.coverage.run]
175
+ source = ["app"]
176
+ omit = ["app/migrations/*", "app/main.py", "*/tests/*"]
177
+
178
+ [tool.coverage.report]
179
+ exclude_lines = [
180
+ "pragma: no cover",
181
+ "def __repr__",
182
+ "if TYPE_CHECKING:",
183
+ "raise NotImplementedError",
184
+ ]
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Markers y organización
190
+
191
+ ```python
192
+ # Registrar markers en pyproject.toml
193
+ # [tool.pytest.ini_options]
194
+ # markers = [
195
+ # "slow: tests que tardan más de 1 segundo",
196
+ # "integration: tests que requieren BD o red",
197
+ # "unit: tests puramente unitarios",
198
+ # ]
199
+
200
+ @pytest.mark.slow
201
+ @pytest.mark.integration
202
+ async def test_proceso_completo_facturacion(): ...
203
+
204
+ # pytest -m "not integration" # Ejecutar solo unitarios
205
+ # pytest -x # Parar al primer fallo
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Anti-patrones principales
211
+
212
+ - **Test que verifica demasiado**: un solo test con 10+ asserts sobre comportamientos distintos. Dividir en tests separados.
213
+ - **Lógica de negocio en tests**: duplicar if/else del código de producción en el test. Usar valores concretos con parametrize.
214
+ - **Sleep en tests**: NUNCA `time.sleep()`. Mockear el reloj con `freezegun`.
215
+
216
+ Para ejemplos detallados MAL vs BIEN de anti-patrones, ver [recursos/ejemplos-completos.md](recursos/ejemplos-completos.md).
217
+
218
+ ## Gotchas / Errores comunes no obvios
219
+
220
+ - **`@pytest.fixture(scope="session")` con base de datos SQLAlchemy falla cuando un test modifica datos y el siguiente test los asume en el estado original**: el scope `session` significa que el fixture se crea una vez para toda la sesión de tests — si un test modifica la BD, los tests posteriores ven los datos modificados. Causa: `scope="session"` no hace rollback entre tests, a diferencia de `scope="function"`. Solución: usar `scope="function"` (default) para fixtures de BD que necesitan aislamiento, o envolver cada test en una transacción que se revierte con `db.rollback()` en el teardown del fixture.
221
+ - **`mock.patch` parcheado en el módulo de tests en lugar de en el módulo que lo usa**: el mock no tiene efecto porque la función ya fue importada en el módulo objetivo antes del patch. Causa: `mock.patch("tests.test_factura.calcular_iva")` parchea la referencia en el módulo de tests, pero `factura_service.py` ya importó `calcular_iva` directamente y sigue usando la original. Solución: patchear siempre en el lugar donde se usa la función: `mock.patch("factura_service.calcular_iva")` — el destino del patch debe ser la ruta del módulo que importó la función, no donde está definida.
222
+ - **`pytest-asyncio` marca el test como `async def` y pasa, pero el `await` dentro no se ejecuta**: el test parece correr sin errores pero la coroutine interna nunca se ejecuta. Causa: sin `@pytest.mark.asyncio` o sin `asyncio_mode = "auto"` en pytest.ini, pytest ejecuta la función async como síncrona — la coroutine se crea y se descarta sin ejecutar. Solución: agregar `@pytest.mark.asyncio` al test o configurar `asyncio_mode = "auto"` en `pytest.ini`; verificar con `pytest --tb=short -v` que el test no termina instantáneamente.
223
+ - **Factory Boy `SubFactory` genera objetos nuevos en cada test aunque el fixture del objeto padre ya existe**: la factory crea una instancia nueva del modelo relacionado en la BD aunque ya exista el objeto padre en el test. Causa: `factory.SubFactory(ClienteFactory)` siempre instancia un nuevo `Cliente` — no reutiliza el fixture del test. Solución: pasar el objeto padre existente al instanciar la factory: `FacturaFactory(cliente=cliente_existente)` — la factory sobreescribe el campo `cliente` con el objeto ya creado en lugar de crear uno nuevo.
224
+ - **`os.chdir()` (Python) o `process.chdir()` (Node) en tests no afecta módulos cargados con paths relativos basados en `__dirname`/`__file__`**: si un módulo calcula su ruta de datos al cargar con `path.resolve(__dirname, ...)` o `Path(__file__).parent`, los tests no pueden redirigir esa ruta cambiando el cwd — el path se evaluó al `require`/`import` y queda fijado. Caso real: test que cambia `process.chdir(tmpDir)` antes de llamar funciones que escriben a `.planning/evolucion/nudges.jsonl` pero `RUTA_NUDGES = path.resolve(__dirname, '..', '..', '.planning', ...)` apunta al proyecto real. Solución: dos opciones: (1) test de integración con backup/restore del archivo real (más simple cuando son pocos tests), o (2) refactor del módulo para aceptar override de ruta vía parámetro o variable de entorno (preferible si el módulo es muy testeable). Aplica también a Python con `pathlib.Path(__file__).parent`.
225
+ - **Sanitizar antes de truncar invalida assertions de longitud en tests**: un test que verifica `truncar('a'.repeat(300), 100).length === 100` falla porque `'a'.repeat(300)` matchea la regex de redact `\b[A-Za-z0-9_-]{32,}\b` y la función sanitiza primero produciendo `[REDACTED]` (10 chars) que no se trunca. Causa: el orden `sanitizar → truncar` reduce el texto antes de que truncar opere. Solución en tests: usar fixtures que NO triggeren patrones de redact (ej: texto con espacios cada N chars como `'palabra corta '.repeat(N)`); separar tests de sanitización y truncado en casos disjuntos. NO modificar la función para reordenar — sanitizar antes es correcto en producción.
226
+
227
+ ## Refactorizar parsers: fixtures multi-formato ANTES del cambio
228
+
229
+ ### SIEMPRE: tener fixtures de cada formato soportado antes de modificar un parser
230
+
231
+ **Cuándo aplicar**: antes de cambiar un regex, gramática o heurística que ya pasa tests para un formato A, y se quiere extender para cubrir un formato B distinto (ej. otro convertidor produce markdown con artefactos diferentes, u otro proveedor genera JSON con shape alternativa).
232
+
233
+ **Problema que previene**: al hacer un regex "más permisivo" para aceptar el formato B, es frecuente romper silenciosamente el formato A porque el match se solapa o el grupo captura la estructura equivocada. Sin un fixture explícito de A, la regresión no se detecta hasta producción.
234
+
235
+ **Regla operativa**:
236
+
237
+ 1. Crear `tests/fixtures/[dominio]/[nombre]-[formato].ext` para CADA formato conocido **antes** de tocar el parser.
238
+ 2. Escribir tests de conteo/identidad para AMBOS formatos (ej: "produce exactamente 13 IDs canónicos") ANTES del cambio.
239
+ 3. Modificar el regex/parser.
240
+ 4. Verificar que AMBOS tests siguen verdes. Si uno se rompe, revertir y acotar más el cambio.
241
+
242
+ ```python
243
+ # BIEN — fixtures explícitos de cada formato soportado, test antes del fix
244
+ FIXTURE_CANONICO = Path("tests/fixtures/cedulas/cedula-formato-v1.md")
245
+ FIXTURE_REEXTRAIDO = Path("tests/fixtures/cedulas/cedula-formato-v2.md")
246
+
247
+ @pytest.mark.parametrize("fixture", [FIXTURE_CANONICO, FIXTURE_REEXTRAIDO])
248
+ def test_parser_produce_13_ids_canonicos(fixture):
249
+ texto = fixture.read_text(encoding="utf-8")
250
+ ids = [h.get("id") for h in extraer(texto)]
251
+ assert len(ids) == 13
252
+ assert "X.X.x" not in ids # no debe caer al fallback legacy
253
+ ```
254
+
255
+ **Beneficio medible**: tener fixtures explícitos de cada formato soportado permite aplicar un fix en un modo secundario sin romper el modo primario. Caso real: al extender un parser de markdown para un segundo convertidor con artefactos distintos, 31 tests nuevos pasaron con 0 regresión en 24 tests previos.
256
+
257
+ **Relacionado**: patrón "characterization test" de Michael Feathers — capturar el comportamiento actual como fixture byte-exact antes de refactorizar.
258
+
259
+
260
+
261
+ ---
262
+
263
+ ## Tests de idempotencia requieren 2 ejecuciones + diff del estado
264
+
265
+ ### Regla
266
+
267
+ Para cualquier pipeline **resumable**, **reentrante** o **idempotente por diseño**
268
+ (walkers que marcan estado en cada paso, workers que dedupean por clave, jobs que
269
+ continúan donde se interrumpieron), el test unitario que pasa con 1 ejecución es
270
+ insuficiente. Se necesitan **2 ejecuciones consecutivas del mismo input** y un
271
+ assert sobre el **diff del estado**.
272
+
273
+ ### Por qué
274
+
275
+ El bug más frecuente en pipelines resumables es que el dedupe solo considera
276
+ estado terminal (`estado == "ok"`), ignorando estados intermedios (`descubierto`,
277
+ `en_proceso`). En la segunda corrida, los ítems en estado intermedio se duplican
278
+ aunque el walker "sabe" que ya los vio. Este bug **nunca aparece** en tests
279
+ unitarios que solo verifican una corrida — se necesita la corrida N+1 para
280
+ observar la duplicación.
281
+
282
+ ### Patrón canónico
283
+
284
+ ```python
285
+ def test_walker_resumable_no_duplica_en_corridas_sucesivas(tmp_path):
286
+ # Arrange — dataset con 100 archivos
287
+ fuente = crear_fuente_con_100_archivos(tmp_path)
288
+ manifest = tmp_path / "manifest.jsonl"
289
+
290
+ # Act corrida 1
291
+ walker = Walker(fuente=fuente, manifest=manifest)
292
+ walker.ejecutar()
293
+ manifest_despues_1 = manifest.read_text().splitlines()
294
+
295
+ # Act corrida 2 (re-ejecución completa, sin reset)
296
+ walker2 = Walker(fuente=fuente, manifest=manifest)
297
+ walker2.ejecutar()
298
+ manifest_despues_2 = manifest.read_text().splitlines()
299
+
300
+ # Assert 1: la segunda corrida NO agrega entradas duplicadas
301
+ diff = len(manifest_despues_2) - len(manifest_despues_1)
302
+ assert diff == 0, (
303
+ f"Corrida 2 agregó {diff} entradas. El dedupe está ignorando "
304
+ f"algún estado intermedio. Manifest antes={len(manifest_despues_1)}, "
305
+ f"después={len(manifest_despues_2)}."
306
+ )
307
+
308
+ # Assert 2: todas las entradas son únicas por su clave de dedupe (SHA)
309
+ shas = [json.loads(l)["sha256"] for l in manifest_despues_2]
310
+ assert len(shas) == len(set(shas)), "Hay SHAs duplicados en manifest"
311
+
312
+ # Assert 3: el count final coincide con el dataset fuente
313
+ assert len(manifest_despues_2) == 100
314
+ ```
315
+
316
+ ### Reglas
317
+
318
+ - **Dos corridas exactas** — mismo input, mismo código, diferente momento. No resetear estado entre corridas; eso simula el caso "pipeline interrumpido y retomado".
319
+ - **Assert sobre el DIFF**, no solo sobre el estado final. Un test que solo valida `len == 100` pasa aunque internamente haya 100 buenos + 50 duplicados si el dedupe corre al final.
320
+ - **Interrumpir una corrida a mitad** como variante avanzada: matar el proceso en un estado intermedio (`descubierto`, `en_proceso`) y verificar que la corrida 2 continúa sin duplicar ni perder items.
321
+ - **Dedupear por clave de contenido** (SHA256) no por clave secundaria (nombre, path, id secuencial) — ver también `patrones-python` "Caché por SHA256 en filesystem para idempotencia de pipelines costosos".
322
+ - **NO confiar en tests con mock del storage**: los bugs de idempotencia se manifiestan solo con I/O real al filesystem o BD. Usar `tmp_path` o base de datos in-memory, pero nunca mock del walker mismo.
323
+
324
+ ### Anti-patrón
325
+
326
+ ```python
327
+ # MAL — una sola corrida; el bug de dedupe parcial pasa desapercibido
328
+ def test_walker_procesa_100_archivos(tmp_path):
329
+ walker = Walker(fuente=crear_100_archivos(tmp_path))
330
+ walker.ejecutar()
331
+ assert len(walker.manifest) == 100 # pasa aunque dedupe solo cubra estado "ok"
332
+ ```
333
+
334
+ ### Aplicabilidad
335
+
336
+ - Walkers de filesystem que marcan progreso en un manifest
337
+ - Workers con dead-letter queue que reintentan mensajes fallidos
338
+ - ETL con checkpoints parciales
339
+ - Migradores de datos con strategy `upsert` o `insert or ignore`
340
+ - Cualquier job que tolere interrupción y reanudación