@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,550 @@
1
+ ---
2
+ name: stripe-pagos
3
+ description: >
4
+ Integración de Stripe: Payment Intents, Checkout Sessions, suscripciones,
5
+ webhooks con verificación de firma, idempotency keys y manejo de eventos
6
+ async. Cargar cuando se implemente cualquier flujo de pago con Stripe:
7
+ cobros únicos, suscripciones recurrentes, reembolsos, o configuración
8
+ de webhooks.
9
+ version: "1.0.0"
10
+ herramientasPermitidas: [Read, Bash]
11
+ evolvable: true # default para skill estandar
12
+ exclusiones:
13
+ - "No cargar para integrar otros procesadores de pago (Conekta, Mercado Pago, PayPal, Adyen) — este skill es exclusivo de la API de Stripe; para otros procesadores cargar o crear el skill correspondiente."
14
+ - "No cargar para análisis de fraude o reglas de detección en Stripe Radar — para configurar Radar y reglas de fraude usar la documentación de Stripe Radar directamente."
15
+ - "No cargar para facturación electrónica fiscal (CFDI en México, facturas SAT) — la factura Stripe no es equivalente al CFDI; para CFDI cargar el skill de facturación fiscal correspondiente."
16
+ - "No cargar para implementar criptomonedas o pagos en cripto con Stripe Crypto — este skill cubre flujos de pago fiat; para cripto consultar la documentación de Stripe Crypto directamente."
17
+ ---
18
+ # Stripe Pagos — Guía de Integración Completa
19
+
20
+ ## Cuándo NO cargar
21
+
22
+ - La tarea es integrar Conekta, Mercado Pago, PayPal o Adyen: cargar el skill del procesador correspondiente.
23
+ - La tarea es facturación electrónica fiscal CFDI (SAT México): la factura Stripe no es CFDI; cargar el skill de facturación fiscal.
24
+ - La tarea es configurar reglas de fraude en Stripe Radar: usar la documentación de Stripe Radar directamente.
25
+ - La tarea es pagos en criptomonedas: usar la documentación de Stripe Crypto directamente.
26
+
27
+
28
+ Stripe es el procesador de pagos más completo disponible. Esta guía cubre
29
+ los patrones de implementación correctos para cada flujo de pago, con énfasis
30
+ en seguridad, idempotencia y manejo correcto del ciclo de vida de los pagos.
31
+
32
+ ---
33
+
34
+ ## 1. Flujos de pago disponibles y cuándo usar cada uno
35
+
36
+ ```
37
+ Payment Intents (API directa) → Control máximo, SPA, móvil nativo
38
+ Checkout Session → Página de pago hosted por Stripe (más simple, más seguro)
39
+ PaymentElement → UI embedding en tu app, Stripe maneja seguridad
40
+ Subscriptions + Price → Cobros recurrentes (mensual, anual, uso medido)
41
+ Connect → Marketplace: pagos entre plataforma y vendedores
42
+ ```
43
+
44
+ ### Matriz de decisión detallada
45
+
46
+ | Criterio | Checkout Session | Payment Intents | Subscriptions |
47
+ |----------|-----------------|-----------------|---------------|
48
+ | Alcance PCI | SAQ-A (mínimo) | SAQ-A-EP | SAQ-A-EP |
49
+ | Control de UI | Ninguno (Stripe UI) | Total | Total |
50
+ | Apple/Google Pay | Automático | Manual | Manual |
51
+ | Cobros recurrentes | No | No (usar Subscriptions) | Sí |
52
+ | Plataformas móviles | Redirección | Nativo (SDK) | Nativo (SDK) |
53
+ | Implementación | Muy simple | Moderada | Moderada-compleja |
54
+
55
+ **Regla**: usar Checkout Session por defecto. Cambiar a Payment Intents solo si
56
+ se requiere control total del UI o la integración es móvil nativa.
57
+
58
+ ---
59
+
60
+ ## 2. Webhook handler seguro (CRÍTICO)
61
+
62
+ El webhook es la fuente de verdad de todos los eventos de pago. La verificación
63
+ de firma es OBLIGATORIA — sin ella cualquiera puede enviar eventos falsos.
64
+
65
+ ```python
66
+ # routes/webhooks.py
67
+ import stripe
68
+ from fastapi import APIRouter, BackgroundTasks, HTTPException, Request
69
+ from app.core.config import settings
70
+ from app.services.pagos import PagosService
71
+
72
+ router = APIRouter()
73
+ stripe.api_key = settings.STRIPE_SECRET_KEY
74
+
75
+
76
+ @router.post("/webhook/stripe")
77
+ async def stripe_webhook(
78
+ request: Request,
79
+ background_tasks: BackgroundTasks,
80
+ ) -> dict:
81
+ payload = await request.body()
82
+ sig_header = request.headers.get("stripe-signature")
83
+
84
+ # SIEMPRE verificar la firma antes de procesar
85
+ try:
86
+ evento = stripe.Webhook.construct_event(
87
+ payload, sig_header, settings.STRIPE_WEBHOOK_SECRET
88
+ )
89
+ except stripe.error.SignatureVerificationError:
90
+ raise HTTPException(status_code=400, detail="Firma inválida")
91
+ except ValueError:
92
+ raise HTTPException(status_code=400, detail="Payload inválido")
93
+
94
+ # Responder 200 inmediatamente — procesar en background
95
+ # Stripe reintenta si no recibe respuesta en 30 segundos
96
+ background_tasks.add_task(PagosService.procesar_evento_webhook, evento)
97
+ return {"status": "recibido"}
98
+
99
+
100
+ # services/pagos.py
101
+ class PagosService:
102
+
103
+ @staticmethod
104
+ async def procesar_evento_webhook(evento: stripe.Event) -> None:
105
+ """Procesa un evento de Stripe. Idempotente por diseño."""
106
+ from app.db.session import AsyncSessionLocal
107
+ from app.models.eventos import EventoStripe
108
+
109
+ async with AsyncSessionLocal() as db:
110
+ # Idempotencia: verificar si ya procesamos este evento
111
+ if await PagosService._evento_ya_procesado(evento.id, db):
112
+ return
113
+
114
+ match evento.type:
115
+ case "checkout.session.completed":
116
+ await PagosService._procesar_checkout_completado(
117
+ evento.data.object, db
118
+ )
119
+ case "customer.subscription.created":
120
+ await PagosService._procesar_subscripcion_creada(
121
+ evento.data.object, db
122
+ )
123
+ case "customer.subscription.updated":
124
+ await PagosService._procesar_subscripcion_actualizada(
125
+ evento.data.object, db
126
+ )
127
+ case "customer.subscription.deleted":
128
+ await PagosService._procesar_subscripcion_cancelada(
129
+ evento.data.object, db
130
+ )
131
+ case "invoice.payment_failed":
132
+ await PagosService._procesar_pago_fallido(
133
+ evento.data.object, db
134
+ )
135
+ case "invoice.payment_succeeded":
136
+ await PagosService._procesar_pago_exitoso(
137
+ evento.data.object, db
138
+ )
139
+ case _:
140
+ pass # Ignorar eventos no manejados — no es un error
141
+
142
+ await PagosService._registrar_evento_procesado(evento.id, db)
143
+ await db.commit()
144
+
145
+ @staticmethod
146
+ async def _evento_ya_procesado(evento_id: str, db: AsyncSession) -> bool:
147
+ from sqlalchemy import select
148
+ from app.models.eventos import EventoStripe
149
+
150
+ resultado = await db.execute(
151
+ select(EventoStripe).where(EventoStripe.stripe_event_id == evento_id)
152
+ )
153
+ return resultado.scalar_one_or_none() is not None
154
+
155
+ @staticmethod
156
+ async def _registrar_evento_procesado(evento_id: str, db: AsyncSession) -> None:
157
+ from app.models.eventos import EventoStripe
158
+
159
+ db.add(EventoStripe(stripe_event_id=evento_id))
160
+ await db.flush()
161
+ ```
162
+
163
+ ---
164
+
165
+ ## 3. Idempotency keys obligatorias
166
+
167
+ Una idempotency key garantiza que si la operación se envía dos veces
168
+ (retry de red, doble clic, worker duplicado), Stripe solo la ejecuta una vez.
169
+ Stripe retiene el resultado por 24 horas.
170
+
171
+ ```python
172
+ import stripe
173
+ from app.core.config import settings
174
+
175
+ stripe.api_key = settings.STRIPE_SECRET_KEY
176
+
177
+
178
+ async def crear_payment_intent(orden: Orden) -> stripe.PaymentIntent:
179
+ """NUNCA crear un PaymentIntent sin idempotency key."""
180
+ return stripe.PaymentIntent.create(
181
+ amount=int(orden.total * 100), # Stripe trabaja en centavos
182
+ currency="mxn",
183
+ customer=orden.usuario.stripe_customer_id,
184
+ description=f"Orden #{orden.numero}",
185
+ metadata={
186
+ "orden_id": str(orden.id),
187
+ "usuario_id": str(orden.usuario_id),
188
+ },
189
+ idempotency_key=f"pi_{orden.id}", # OBLIGATORIO
190
+ )
191
+
192
+
193
+ async def crear_subscripcion(usuario: Usuario, price_id: str) -> stripe.Subscription:
194
+ """Idempotency key incluye usuario Y plan — evita duplicados por plan."""
195
+ return stripe.Subscription.create(
196
+ customer=usuario.stripe_customer_id,
197
+ items=[{"price": price_id}],
198
+ expand=["latest_invoice.payment_intent"],
199
+ metadata={
200
+ "usuario_id": str(usuario.id),
201
+ "price_id": price_id,
202
+ },
203
+ idempotency_key=f"sub_{usuario.id}_{price_id}", # OBLIGATORIO
204
+ )
205
+ ```
206
+
207
+ ### Convención de idempotency keys por operación
208
+
209
+ | Operación | Formato recomendado |
210
+ |-----------|---------------------|
211
+ | PaymentIntent.create | `pi_{orden.id}` |
212
+ | Subscription.create | `sub_{usuario.id}_{price_id}` |
213
+ | checkout.Session.create | `checkout_{orden.id}` |
214
+ | Refund.create (total) | `refund_{pago.id}` |
215
+ | Refund.create (parcial) | `refund_partial_{pago.id}_{monto}` |
216
+ | Customer.create | `customer_{usuario.id}` |
217
+
218
+ ---
219
+
220
+ ## 4. Checkout Session completo
221
+
222
+ ```python
223
+ import time
224
+ import stripe
225
+ from app.core.config import settings
226
+ from app.models.ordenes import Orden
227
+ from app.models.usuarios import Usuario
228
+
229
+ stripe.api_key = settings.STRIPE_SECRET_KEY
230
+
231
+
232
+ async def crear_checkout_session(orden: Orden, usuario: Usuario) -> str:
233
+ """Crea una Checkout Session y retorna la URL de pago."""
234
+ session = stripe.checkout.Session.create(
235
+ payment_method_types=["card"],
236
+ mode="payment", # "subscription" para cobros recurrentes
237
+ customer_email=usuario.email,
238
+ customer=usuario.stripe_customer_id, # Si ya existe el customer
239
+ line_items=[
240
+ {
241
+ "price_data": {
242
+ "currency": "mxn",
243
+ "unit_amount": int(orden.total * 100), # centavos
244
+ "product_data": {
245
+ "name": orden.descripcion,
246
+ "description": f"Orden #{orden.numero}",
247
+ },
248
+ },
249
+ "quantity": 1,
250
+ }
251
+ ],
252
+ # URLs de retorno — NUNCA asumir que success_url = pago completado
253
+ success_url=(
254
+ f"{settings.BASE_URL}/pagos/exitoso"
255
+ "?session_id={CHECKOUT_SESSION_ID}"
256
+ ),
257
+ cancel_url=f"{settings.BASE_URL}/pagos/cancelado",
258
+ metadata={
259
+ "orden_id": str(orden.id),
260
+ "usuario_id": str(usuario.id),
261
+ },
262
+ expires_at=int(time.time()) + 1800, # Expira en 30 minutos
263
+ idempotency_key=f"checkout_{orden.id}", # OBLIGATORIO
264
+ )
265
+ return session.url
266
+
267
+
268
+ async def verificar_checkout_session(session_id: str) -> stripe.checkout.Session:
269
+ """Verificar el estado real de la sesión — no confiar solo en el redirect."""
270
+ return stripe.checkout.Session.retrieve(
271
+ session_id,
272
+ expand=["payment_intent", "customer"],
273
+ )
274
+ ```
275
+
276
+ ---
277
+
278
+ ## 5. Suscripciones con estado correcto
279
+
280
+ Los estados de Stripe tienen semántica específica. Mapearlos correctamente
281
+ es crítico para dar o quitar acceso al servicio:
282
+
283
+ ```python
284
+ from datetime import datetime
285
+ from sqlalchemy.ext.asyncio import AsyncSession
286
+ import stripe
287
+
288
+ # Mapeo canónico de estados de Stripe a estados de la app
289
+ ESTADOS_STRIPE: dict[str, str] = {
290
+ "active": "activa", # Todo correcto — dar acceso
291
+ "trialing": "en_prueba", # Periodo de prueba — dar acceso
292
+ "past_due": "pago_vencido", # Reintentos en progreso — dar acceso temporal
293
+ "unpaid": "suspendida", # Reintentos agotados — restringir acceso
294
+ "canceled": "cancelada", # Cancelada definitivamente — revocar acceso
295
+ "incomplete": "incompleta", # Pago inicial fallido — no dar acceso
296
+ "incomplete_expired": "expirada", # Nunca completó pago inicial
297
+ "paused": "pausada", # Pausada manualmente — sin cobros
298
+ }
299
+
300
+
301
+ async def sincronizar_subscripcion(
302
+ sub: stripe.Subscription, db: AsyncSession
303
+ ) -> None:
304
+ """Sincroniza el estado local con el estado real de Stripe."""
305
+ from sqlalchemy import select, update
306
+ from app.models.subscripciones import Subscripcion
307
+
308
+ nuevo_estado = ESTADOS_STRIPE.get(sub.status, "desconocido")
309
+
310
+ await db.execute(
311
+ update(Subscripcion)
312
+ .where(Subscripcion.stripe_subscription_id == sub.id)
313
+ .values(
314
+ estado=nuevo_estado,
315
+ periodo_actual_inicio=datetime.fromtimestamp(sub.current_period_start),
316
+ periodo_actual_fin=datetime.fromtimestamp(sub.current_period_end),
317
+ cancelar_al_periodo_fin=sub.cancel_at_period_end,
318
+ actualizado_en=datetime.utcnow(),
319
+ )
320
+ )
321
+ await db.flush()
322
+
323
+
324
+ async def cancelar_al_periodo_fin(
325
+ subscripcion_id: str, db: AsyncSession
326
+ ) -> stripe.Subscription:
327
+ """Cancela la suscripción al final del periodo pagado (no inmediatamente)."""
328
+ from sqlalchemy import select
329
+ from app.models.subscripciones import Subscripcion
330
+
331
+ sub_local = await db.scalar(
332
+ select(Subscripcion).where(Subscripcion.id == subscripcion_id)
333
+ )
334
+ if sub_local is None:
335
+ raise ValueError(f"Subscripción {subscripcion_id} no encontrada")
336
+
337
+ sub_stripe = stripe.Subscription.modify(
338
+ sub_local.stripe_subscription_id,
339
+ cancel_at_period_end=True,
340
+ )
341
+ await sincronizar_subscripcion(sub_stripe, db)
342
+ return sub_stripe
343
+ ```
344
+
345
+ ---
346
+
347
+ ## 6. Reembolsos
348
+
349
+ ```python
350
+ import stripe
351
+ from sqlalchemy.ext.asyncio import AsyncSession
352
+ from app.core.config import settings
353
+
354
+ stripe.api_key = settings.STRIPE_SECRET_KEY
355
+
356
+
357
+ async def reembolsar_pago(
358
+ pago_id: str,
359
+ db: AsyncSession,
360
+ monto_parcial_centavos: int | None = None,
361
+ razon: str = "requested_by_customer",
362
+ ) -> stripe.Refund:
363
+ """
364
+ Reembolsa un pago. Si monto_parcial_centavos es None, reembolsa el total.
365
+ razon: 'requested_by_customer' | 'fraudulent' | 'duplicate'
366
+ """
367
+ from sqlalchemy import select
368
+ from app.models.pagos import Pago
369
+
370
+ pago = await db.scalar(select(Pago).where(Pago.id == pago_id))
371
+ if pago is None:
372
+ raise ValueError(f"Pago {pago_id} no encontrado")
373
+ if pago.estado in ("reembolsado", "cancelado"):
374
+ raise ValueError(f"Pago {pago_id} ya fue reembolsado o cancelado")
375
+
376
+ # Construir idempotency key diferenciada por tipo de reembolso
377
+ if monto_parcial_centavos:
378
+ idem_key = f"refund_partial_{pago_id}_{monto_parcial_centavos}"
379
+ else:
380
+ idem_key = f"refund_{pago_id}"
381
+
382
+ kwargs: dict = {
383
+ "payment_intent": pago.stripe_payment_intent_id,
384
+ "reason": razon,
385
+ "idempotency_key": idem_key,
386
+ }
387
+ if monto_parcial_centavos:
388
+ kwargs["amount"] = monto_parcial_centavos
389
+
390
+ reembolso = stripe.Refund.create(**kwargs)
391
+
392
+ # Actualizar estado local — el webhook también llegará, debe ser idempotente
393
+ nuevo_estado = "parcialmente_reembolsado" if monto_parcial_centavos else "reembolsado"
394
+ from sqlalchemy import update
395
+ await db.execute(
396
+ update(Pago)
397
+ .where(Pago.id == pago_id)
398
+ .values(
399
+ estado=nuevo_estado,
400
+ stripe_refund_id=reembolso.id,
401
+ )
402
+ )
403
+ await db.flush()
404
+ return reembolso
405
+ ```
406
+
407
+ ---
408
+
409
+ ## 7. MUST DO / MUST NOT DO
410
+
411
+ ### MUST DO
412
+
413
+ - **SIEMPRE** verificar la firma del webhook con `stripe.Webhook.construct_event`
414
+ antes de procesar cualquier evento.
415
+ - **Idempotency key** en TODA operación de creación de Stripe (`create`).
416
+ - Usar modo `test` (`sk_test_...`) en desarrollo. NUNCA live keys en código.
417
+ - Almacenar en tu BD: `stripe_customer_id`, `stripe_subscription_id`,
418
+ `stripe_payment_intent_id`, `stripe_refund_id`.
419
+ - Manejar webhooks de forma asíncrona: responder 200 rápido, procesar en background.
420
+ - Reconciliar estados: siempre confiar en el webhook, no en el redirect de `success_url`.
421
+ - Verificar el estado de la sesión o intent vía API al mostrar la pantalla de éxito.
422
+ - Registrar todos los eventos procesados en una tabla para garantizar idempotencia.
423
+ - Manejar `invoice.payment_failed` para suspender acceso cuando los reintentos se agotan.
424
+
425
+ ### MUST NOT DO
426
+
427
+ - **NUNCA** almacenar números de tarjeta, CVV ni fechas de expiración.
428
+ - **NUNCA** procesar un webhook sin verificar la firma.
429
+ - **NUNCA** asumir que `success_url` significa que el pago fue completado.
430
+ - **NUNCA** reutilizar idempotency keys entre operaciones distintas.
431
+ - **NUNCA** hardcodear stripe keys — siempre variables de entorno.
432
+ - **NUNCA** ignorar el evento `invoice.payment_failed` en suscripciones.
433
+ - **NUNCA** loggear payloads de webhooks sin filtrar datos sensibles.
434
+ - **NUNCA** hacer `db.commit()` dentro del service — solo en el endpoint o tarea.
435
+ - **NUNCA** construir un formulario que reciba el número de tarjeta en tu servidor.
436
+
437
+ ---
438
+
439
+ ## 8. Testing con Stripe CLI
440
+
441
+ ```bash
442
+ # Paso 1: instalar y autenticar Stripe CLI
443
+ # https://stripe.com/docs/stripe-cli
444
+ stripe login
445
+
446
+ # Paso 2: escuchar webhooks localmente (mantener en terminal aparte)
447
+ stripe listen --forward-to localhost:8000/webhook/stripe
448
+
449
+ # Paso 3: disparar eventos específicos en otra terminal
450
+ stripe trigger checkout.session.completed
451
+ stripe trigger customer.subscription.created
452
+ stripe trigger customer.subscription.updated
453
+ stripe trigger customer.subscription.deleted
454
+ stripe trigger invoice.payment_failed
455
+ stripe trigger invoice.payment_succeeded
456
+ stripe trigger charge.dispute.created
457
+
458
+ # Disparar con datos personalizados (fixture)
459
+ stripe trigger payment_intent.succeeded \
460
+ --override payment_intent:metadata.orden_id=test-123
461
+
462
+ # Ver eventos recientes
463
+ stripe events list --limit 10
464
+
465
+ # Tarjetas de prueba para Payment Intents
466
+ # 4242 4242 4242 4242 → pago exitoso
467
+ # 4000 0000 0000 0002 → tarjeta declinada (insufficient_funds)
468
+ # 4000 0025 0000 3155 → requiere 3D Secure
469
+ # 4000 0000 0000 9995 → fondos insuficientes
470
+ # 4000 0000 0000 0069 → tarjeta expirada
471
+ ```
472
+
473
+ ### Test unitario de webhook con firma simulada
474
+
475
+ ```python
476
+ # tests/test_webhook_stripe.py
477
+ import time
478
+ import json
479
+ import stripe
480
+ import pytest
481
+ from httpx import AsyncClient
482
+
483
+ WEBHOOK_SECRET = "whsec_test_secret"
484
+
485
+ def firmar_payload(payload: dict, secret: str) -> tuple[bytes, str]:
486
+ """Genera un payload firmado para tests de webhook."""
487
+ body = json.dumps(payload).encode()
488
+ timestamp = int(time.time())
489
+ sig = stripe.WebhookSignature.compute_signature(
490
+ f"{timestamp}.{body.decode()}", secret
491
+ )
492
+ header = f"t={timestamp},v1={sig}"
493
+ return body, header
494
+
495
+
496
+ @pytest.mark.asyncio
497
+ async def test_webhook_checkout_completado(client: AsyncClient):
498
+ payload = {
499
+ "id": "evt_test_001",
500
+ "type": "checkout.session.completed",
501
+ "data": {
502
+ "object": {
503
+ "id": "cs_test_abc",
504
+ "payment_status": "paid",
505
+ "metadata": {"orden_id": "orden-123"},
506
+ }
507
+ },
508
+ }
509
+ body, header = firmar_payload(payload, WEBHOOK_SECRET)
510
+ response = await client.post(
511
+ "/webhook/stripe",
512
+ content=body,
513
+ headers={"stripe-signature": header, "content-type": "application/json"},
514
+ )
515
+ assert response.status_code == 200
516
+
517
+
518
+ @pytest.mark.asyncio
519
+ async def test_webhook_firma_invalida_retorna_400(client: AsyncClient):
520
+ response = await client.post(
521
+ "/webhook/stripe",
522
+ json={"type": "checkout.session.completed"},
523
+ headers={"stripe-signature": "firma_invalida"},
524
+ )
525
+ assert response.status_code == 400
526
+ ```
527
+
528
+ ---
529
+
530
+ ## 9. Tabla de referencias
531
+
532
+ | Tema | Archivo |
533
+ |------|---------|
534
+ | Connect: marketplace, transfers, splits de pago | [recursos/stripe-connect.md](recursos/stripe-connect.md) |
535
+ | Manejo de errores Stripe y reintentos | [recursos/errores-reintentos.md](recursos/errores-reintentos.md) |
536
+ | Documentación oficial Stripe | https://docs.stripe.com |
537
+ | Stripe CLI reference | https://docs.stripe.com/stripe-cli |
538
+ | Tarjetas de prueba | https://docs.stripe.com/testing |
539
+
540
+ ---
541
+
542
+ ## Gotchas / Errores comunes no obvios
543
+
544
+ **`checkout.session.completed` llega con `payment_status: "unpaid"` para suscripciones con trial period y el código que asume `payment_status: "paid"` nunca activa el acceso del usuario**: un Checkout Session de suscripción con `trial_period_days: 14` dispara `checkout.session.completed` inmediatamente después del registro, pero el campo `payment_status` es `"unpaid"` porque no hubo cobro real. Causa: para suscripciones con trial, Stripe completa la sesión (el usuario dio sus datos de pago) antes del primer cobro. Fix: al procesar `checkout.session.completed` para suscripciones, verificar `session.mode == "subscription"` y activar el acceso basándose en el estado de la suscripción (campo `subscription`), no en `payment_status`. Escuchar también `customer.subscription.created` con `status: "trialing"` como señal canónica de trial activo.
545
+
546
+ **Las idempotency keys con `idem_key = f"create_payment_{order_id}"` causan errores `IdempotencyError` cuando el mismo endpoint se llama con parámetros diferentes para la misma orden (ej: montos actualizados)**: si el usuario modifica su carrito y vuelve a intentar pagar, la segunda llamada a `PaymentIntent.create` con la misma `order_id` pero diferente `amount` choca con el PaymentIntent ya creado. Stripe retorna error porque los parámetros no coinciden con el primer intento. Causa: la idempotency key en Stripe es una promesa de que "esta llamada idéntica puede enviarse múltiples veces"; si los parámetros cambian, es una operación diferente. Fix: incluir un hash de los parámetros relevantes en la key: `idem_key = f"create_pi_{order_id}_{amount_cents}_{currency}"`, o usar un UUID v4 por intento y manejar idempotencia en tu propio backend comparando el estado de la orden.
547
+
548
+ **Los webhooks de Stripe pueden llegar fuera de orden y procesarlos en secuencia sin verificar el estado actual puede revertir actualizaciones válidas**: el evento `customer.subscription.updated` con `status: "active"` puede llegar después de `customer.subscription.deleted` si hubo reintento de un evento antiguo, sobreescribiendo el estado `canceled` correcto con `active`. Causa: Stripe garantiza entrega at-least-once pero no orden de llegada; los reintentos de eventos fallidos anteriores pueden llegar después que eventos más recientes. Fix: siempre verificar el timestamp del evento (`event.created`) antes de actualizar la BD: solo procesar si `event.created > ultima_actualizacion_en_bd`. Alternativamente, consultar el estado actual vía API Stripe antes de cada actualización: `stripe.Subscription.retrieve(subscription_id)`.
549
+
550
+ **`stripe.Webhook.construct_event` lanza `SignatureVerificationError` en producción con FastAPI porque el body fue parseado como JSON antes de llegar al handler del webhook, y `request.body()` devuelve bytes del JSON serializado en lugar del payload raw original**: el middleware de FastAPI que hace `await request.json()` consume el stream del body; cuando el handler del webhook intenta leer el body raw para verificar la firma, recibe el JSON re-serializado que puede tener diferente formato (ordenamiento de claves, espacios) que el payload original de Stripe. Causa: la firma HMAC de Stripe se calcula sobre el payload binario exacto; cualquier transformación invalida la firma. Fix: en el endpoint de webhook, leer el body raw directamente sin pasar por middleware de parsing: `raw_body = await request.body()` y no declarar el parámetro como `body: dict` en la firma de la función FastAPI.