@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.
- package/CLAUDE.md +238 -0
- package/README.md +560 -0
- package/_userland/agentes/.gitkeep +0 -0
- package/_userland/habilidades/.gitkeep +0 -0
- package/agentes/.evolved.json +9 -0
- package/agentes/accesibilidad-wcag-swl.md +692 -0
- package/agentes/arquitecto-swl.md +238 -0
- package/agentes/auto-evolucion-swl.md +854 -0
- package/agentes/backend-api-swl.md +470 -0
- package/agentes/backend-csharp-swl.md +418 -0
- package/agentes/backend-go-swl.md +388 -0
- package/agentes/backend-java-swl.md +279 -0
- package/agentes/backend-node-swl.md +477 -0
- package/agentes/backend-python-swl.md +608 -0
- package/agentes/backend-rust-swl.md +362 -0
- package/agentes/backend-workers-swl.md +480 -0
- package/agentes/cloud-infra-swl.md +485 -0
- package/agentes/consolidador-swl.md +539 -0
- package/agentes/datos-swl.md +584 -0
- package/agentes/depurador-swl.md +349 -0
- package/agentes/devops-ci-swl.md +374 -0
- package/agentes/disenador-ui-swl.md +558 -0
- package/agentes/documentador-swl.md +343 -0
- package/agentes/evals/arquitecto-swl.evals.json +56 -0
- package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
- package/agentes/evals/implementador-swl.evals.json +56 -0
- package/agentes/evals/orquestador-swl.evals.json +60 -0
- package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
- package/agentes/evals/red-team-swl.evals.json +59 -0
- package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
- package/agentes/frontend-angular-swl.md +627 -0
- package/agentes/frontend-css-swl.md +720 -0
- package/agentes/frontend-react-swl.md +696 -0
- package/agentes/frontend-swl.md +500 -0
- package/agentes/frontend-tailwind-swl.md +830 -0
- package/agentes/implementador-swl.md +328 -0
- package/agentes/investigador-swl.md +430 -0
- package/agentes/investigador-ux-swl.md +500 -0
- package/agentes/llm-apps-swl.md +276 -0
- package/agentes/migrador-swl.md +417 -0
- package/agentes/mobile-android-swl.md +509 -0
- package/agentes/mobile-cross-swl.md +539 -0
- package/agentes/mobile-ios-swl.md +500 -0
- package/agentes/mobile-testing-swl.md +300 -0
- package/agentes/notificador-swl.md +916 -0
- package/agentes/observabilidad-swl.md +436 -0
- package/agentes/orquestador-swl.md +884 -0
- package/agentes/pagos-swl.md +283 -0
- package/agentes/perfilador-usuario-swl.md +306 -0
- package/agentes/planificador-swl.md +402 -0
- package/agentes/producto-prd-swl.md +587 -0
- package/agentes/red-team-swl.md +216 -0
- package/agentes/release-manager-swl.md +568 -0
- package/agentes/rendimiento-swl.md +714 -0
- package/agentes/resolutor-build-swl.md +243 -0
- package/agentes/revisor-angular-swl.md +276 -0
- package/agentes/revisor-codigo-swl.md +348 -0
- package/agentes/revisor-csharp-swl.md +262 -0
- package/agentes/revisor-go-swl.md +257 -0
- package/agentes/revisor-java-swl.md +255 -0
- package/agentes/revisor-kotlin-swl.md +271 -0
- package/agentes/revisor-nextjs-swl.md +279 -0
- package/agentes/revisor-php-swl.md +269 -0
- package/agentes/revisor-react-swl.md +276 -0
- package/agentes/revisor-rust-swl.md +344 -0
- package/agentes/revisor-seguridad-swl.md +390 -0
- package/agentes/revisor-swift-swl.md +266 -0
- package/agentes/revisor-typescript-swl.md +344 -0
- package/agentes/sre-swl.md +265 -0
- package/agentes/tdd-qa-swl.md +354 -0
- package/agentes/ux-disenador-swl.md +501 -0
- package/bin/lib/bot-comandos.js +1030 -0
- package/bin/lib/bot-discovery.js +182 -0
- package/bin/lib/bot-git.js +142 -0
- package/bin/swl-ses.js +325 -0
- package/bin/swl-telegram-bot.js +442 -0
- package/bin/swl-telegram-bot.plist +21 -0
- package/bin/swl-telegram-bot.service +14 -0
- package/comandos/swl/.evolved.json +23 -0
- package/comandos/swl/actualizar.md +174 -0
- package/comandos/swl/adoptar-proyecto.md +207 -0
- package/comandos/swl/aprender.md +701 -0
- package/comandos/swl/auditar-deps.md +134 -0
- package/comandos/swl/autoresearch.md +170 -0
- package/comandos/swl/ayuda.md +224 -0
- package/comandos/swl/brainstorm.md +50 -0
- package/comandos/swl/checkpoint.md +330 -0
- package/comandos/swl/compactar.md +283 -0
- package/comandos/swl/configurar-ci.md +227 -0
- package/comandos/swl/contexto.md +112 -0
- package/comandos/swl/contribuir.md +233 -0
- package/comandos/swl/crear-skill.md +292 -0
- package/comandos/swl/cron.md +196 -0
- package/comandos/swl/dashboard.md +146 -0
- package/comandos/swl/discutir-fase.md +230 -0
- package/comandos/swl/ejecutar-fase.md +135 -0
- package/comandos/swl/evaluar-skill.md +487 -0
- package/comandos/swl/evolucion-estado.md +142 -0
- package/comandos/swl/evolucionar.md +259 -0
- package/comandos/swl/exportar-vault.md +189 -0
- package/comandos/swl/gateway.md +158 -0
- package/comandos/swl/inbox.md +116 -0
- package/comandos/swl/instalar.md +220 -0
- package/comandos/swl/instintos.md +86 -0
- package/comandos/swl/mapear-codebase.md +312 -0
- package/comandos/swl/mcp-status.md +175 -0
- package/comandos/swl/metricas.md +270 -0
- package/comandos/swl/modelo.md +102 -0
- package/comandos/swl/notificaciones.md +396 -0
- package/comandos/swl/nuevo-proyecto.md +154 -0
- package/comandos/swl/planear-fase.md +221 -0
- package/comandos/swl/plugins.md +256 -0
- package/comandos/swl/reflect-skills.md +125 -0
- package/comandos/swl/release.md +217 -0
- package/comandos/swl/revisar-impacto.md +206 -0
- package/comandos/swl/revisar.md +330 -0
- package/comandos/swl/salud.md +363 -0
- package/comandos/swl/sesiones.md +200 -0
- package/comandos/swl/skill-search.md +113 -0
- package/comandos/swl/verificar.md +585 -0
- package/comandos/swl/wiki.md +620 -0
- package/contextos/dev.md +32 -0
- package/contextos/research.md +30 -0
- package/contextos/review.md +31 -0
- package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
- package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
- package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
- package/habilidades/agent-browser/SKILL.md +218 -0
- package/habilidades/agentes-como-servicio/SKILL.md +218 -0
- package/habilidades/ai-runtime-security/SKILL.md +273 -0
- package/habilidades/angular-avanzado/SKILL.md +164 -0
- package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
- package/habilidades/angular-moderno/SKILL.md +186 -0
- package/habilidades/angular-moderno/evals/evals.json +45 -0
- package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
- package/habilidades/api-rest-diseno/SKILL.md +191 -0
- package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
- package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
- package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
- package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
- package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
- package/habilidades/async-python/SKILL.md +149 -0
- package/habilidades/async-python/evals/evals.json +47 -0
- package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
- package/habilidades/auth-patrones/.evolved.json +9 -0
- package/habilidades/auth-patrones/SKILL.md +413 -0
- package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
- package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
- package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
- package/habilidades/autoresearch/SKILL.md +268 -0
- package/habilidades/autoresearch/evals/evals.json +41 -0
- package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
- package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
- package/habilidades/azure-cloud/SKILL.md +308 -0
- package/habilidades/azure-cloud/recursos/aks.md +327 -0
- package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
- package/habilidades/backend-production-resilience/SKILL.md +288 -0
- package/habilidades/brainstorming/SKILL.md +295 -0
- package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
- package/habilidades/build-errors-cpp/SKILL.md +270 -0
- package/habilidades/build-errors-csharp/SKILL.md +265 -0
- package/habilidades/build-errors-go/SKILL.md +306 -0
- package/habilidades/build-errors-java/SKILL.md +278 -0
- package/habilidades/build-errors-kotlin/SKILL.md +303 -0
- package/habilidades/build-errors-nextjs/SKILL.md +312 -0
- package/habilidades/build-errors-php/SKILL.md +270 -0
- package/habilidades/build-errors-python/SKILL.md +292 -0
- package/habilidades/build-errors-rust/SKILL.md +284 -0
- package/habilidades/build-errors-swift/SKILL.md +272 -0
- package/habilidades/build-errors-typescript/SKILL.md +369 -0
- package/habilidades/checklist-calidad/SKILL.md +271 -0
- package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
- package/habilidades/checklist-seguridad/SKILL.md +285 -0
- package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
- package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
- package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
- package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
- package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
- package/habilidades/cloud-aws/SKILL.md +142 -0
- package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
- package/habilidades/compactacion-contexto/SKILL.md +247 -0
- package/habilidades/contenedores-docker/SKILL.md +137 -0
- package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
- package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
- package/habilidades/context-builder/SKILL.md +170 -0
- package/habilidades/control-profundidad/SKILL.md +128 -0
- package/habilidades/csharp-experto/SKILL.md +322 -0
- package/habilidades/csharp-patrones/SKILL.md +316 -0
- package/habilidades/csharp-testing/SKILL.md +286 -0
- package/habilidades/css-moderno/SKILL.md +166 -0
- package/habilidades/css-moderno/evals/evals.json +43 -0
- package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
- package/habilidades/datos-etl/SKILL.md +129 -0
- package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
- package/habilidades/dbml-experto/SKILL.md +339 -0
- package/habilidades/dbml-experto/evals/evals.json +56 -0
- package/habilidades/dependencias-auditoria/SKILL.md +320 -0
- package/habilidades/deprecacion-migracion/SKILL.md +169 -0
- package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
- package/habilidades/design-tokens/SKILL.md +158 -0
- package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
- package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
- package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
- package/habilidades/discutir-fase/SKILL.md +188 -0
- package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
- package/habilidades/diseno-responsivo/SKILL.md +186 -0
- package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
- package/habilidades/django-experto/SKILL.md +205 -0
- package/habilidades/django-experto/recursos/async-django.md +390 -0
- package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
- package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
- package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
- package/habilidades/django-experto/recursos/testing-django.md +415 -0
- package/habilidades/doc-sync/SKILL.md +280 -0
- package/habilidades/drift-detection/SKILL.md +179 -0
- package/habilidades/ejecutar-fase/SKILL.md +468 -0
- package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
- package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
- package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
- package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
- package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
- package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
- package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
- package/habilidades/evaluacion-agentes/SKILL.md +314 -0
- package/habilidades/event-driven/SKILL.md +153 -0
- package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
- package/habilidades/extraccion-documentos/SKILL.md +221 -0
- package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
- package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
- package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
- package/habilidades/fastapi-experto/SKILL.md +221 -0
- package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
- package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
- package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
- package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
- package/habilidades/filament-admin/SKILL.md +290 -0
- package/habilidades/frontend-avanzado/SKILL.md +257 -0
- package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
- package/habilidades/gcp-cloud/SKILL.md +260 -0
- package/habilidades/gcp-cloud/recursos/gke.md +234 -0
- package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
- package/habilidades/generacion-mermaid/SKILL.md +229 -0
- package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
- package/habilidades/go-experto/SKILL.md +305 -0
- package/habilidades/go-patrones/SKILL.md +299 -0
- package/habilidades/go-testing/SKILL.md +291 -0
- package/habilidades/graphql-experto/SKILL.md +323 -0
- package/habilidades/guardrail-semantico/SKILL.md +282 -0
- package/habilidades/harness-claude-code/SKILL.md +299 -0
- package/habilidades/iam-secretos/SKILL.md +265 -0
- package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
- package/habilidades/infra-github-actions/SKILL.md +166 -0
- package/habilidades/instalar-sistema/.evolved.json +9 -0
- package/habilidades/instalar-sistema/SKILL.md +221 -0
- package/habilidades/java-experto/SKILL.md +290 -0
- package/habilidades/java-patrones/SKILL.md +275 -0
- package/habilidades/java-testing/SKILL.md +288 -0
- package/habilidades/kotlin-compose/SKILL.md +278 -0
- package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
- package/habilidades/kotlin-experto/SKILL.md +318 -0
- package/habilidades/kotlin-testing/SKILL.md +267 -0
- package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
- package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
- package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
- package/habilidades/langchain-langraph/SKILL.md +386 -0
- package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
- package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
- package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
- package/habilidades/legacy-code-rescue/SKILL.md +267 -0
- package/habilidades/likec4-experto/SKILL.md +412 -0
- package/habilidades/likec4-experto/evals/evals.json +69 -0
- package/habilidades/manejo-errores/.evolved.json +9 -0
- package/habilidades/manejo-errores/SKILL.md +407 -0
- package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
- package/habilidades/mapear-codebase/SKILL.md +275 -0
- package/habilidades/memoria-busqueda/SKILL.md +194 -0
- package/habilidades/memoria-busqueda/evals/evals.json +44 -0
- package/habilidades/meta-skills-estandar/SKILL.md +298 -0
- package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
- package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
- package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
- package/habilidades/microservicios/SKILL.md +155 -0
- package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
- package/habilidades/mobile-flutter/SKILL.md +199 -0
- package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
- package/habilidades/mobile-react-native/SKILL.md +176 -0
- package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
- package/habilidades/mongodb-experto/SKILL.md +302 -0
- package/habilidades/monitoring-alertas/SKILL.md +201 -0
- package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
- package/habilidades/nestjs-experto/SKILL.md +307 -0
- package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
- package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
- package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
- package/habilidades/nextjs-experto/SKILL.md +335 -0
- package/habilidades/nextjs-patrones/SKILL.md +303 -0
- package/habilidades/nextjs-testing/SKILL.md +331 -0
- package/habilidades/node-experto/.evolved.json +9 -0
- package/habilidades/node-experto/SKILL.md +266 -0
- package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
- package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
- package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
- package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
- package/habilidades/nuevo-proyecto/SKILL.md +204 -0
- package/habilidades/orquestacion-async/SKILL.md +303 -0
- package/habilidades/paid-media-tracking/SKILL.md +269 -0
- package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
- package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
- package/habilidades/patrones-python/SKILL.md +228 -0
- package/habilidades/patrones-python/evals/evals.json +56 -0
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
- package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
- package/habilidades/perfil-usuario/SKILL.md +200 -0
- package/habilidades/perfil-usuario/evals/evals.json +55 -0
- package/habilidades/performance-baseline/SKILL.md +297 -0
- package/habilidades/php-experto/SKILL.md +291 -0
- package/habilidades/php-patrones/SKILL.md +306 -0
- package/habilidades/php-testing/SKILL.md +280 -0
- package/habilidades/planear-fase/SKILL.md +269 -0
- package/habilidades/postgresql-experto/SKILL.md +151 -0
- package/habilidades/postgresql-experto/evals/evals.json +53 -0
- package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
- package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
- package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
- package/habilidades/privacy-memoria/SKILL.md +141 -0
- package/habilidades/privacy-memoria/evals/evals.json +43 -0
- package/habilidades/prompt-engineering/SKILL.md +518 -0
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
- package/habilidades/rag-arquitectura/SKILL.md +338 -0
- package/habilidades/rails-experto/SKILL.md +237 -0
- package/habilidades/rails-experto/recursos/active-record.md +260 -0
- package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
- package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
- package/habilidades/react-experto/SKILL.md +209 -0
- package/habilidades/react-experto/evals/evals.json +55 -0
- package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
- package/habilidades/react-optimizacion/SKILL.md +174 -0
- package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
- package/habilidades/redis-experto/SKILL.md +305 -0
- package/habilidades/release-semver/.evolved.json +9 -0
- package/habilidades/release-semver/SKILL.md +248 -0
- package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
- package/habilidades/rust-experto/SKILL.md +400 -0
- package/habilidades/rust-patrones/SKILL.md +296 -0
- package/habilidades/rust-testing/SKILL.md +311 -0
- package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
- package/habilidades/sql-optimizacion/SKILL.md +200 -0
- package/habilidades/sql-optimizacion/evals/evals.json +54 -0
- package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
- package/habilidades/sre-patrones/SKILL.md +333 -0
- package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
- package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
- package/habilidades/stripe-pagos/SKILL.md +550 -0
- package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
- package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
- package/habilidades/structured-outputs/SKILL.md +343 -0
- package/habilidades/swift-experto/SKILL.md +320 -0
- package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
- package/habilidades/swift-patrones/SKILL.md +313 -0
- package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
- package/habilidades/swift-testing/SKILL.md +254 -0
- package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
- package/habilidades/swl-dashboard/SKILL.md +370 -0
- package/habilidades/swl-markitdown/SKILL.md +285 -0
- package/habilidades/swl-markitdown/evals/evals.json +52 -0
- package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
- package/habilidades/tailwind-experto/SKILL.md +240 -0
- package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
- package/habilidades/tdd-workflow/SKILL.md +293 -0
- package/habilidades/terraform-experto/SKILL.md +321 -0
- package/habilidades/testing-python/SKILL.md +340 -0
- package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
- package/habilidades/threat-model-lite/SKILL.md +246 -0
- package/habilidades/tracing-processor/SKILL.md +212 -0
- package/habilidades/tracking-measurement/SKILL.md +239 -0
- package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
- package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
- package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
- package/habilidades/typescript-avanzado/SKILL.md +144 -0
- package/habilidades/typescript-avanzado/evals/evals.json +55 -0
- package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
- package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
- package/habilidades/ux-diseno/SKILL.md +116 -0
- package/habilidades/ux-diseno/evals/evals.json +43 -0
- package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
- package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
- package/habilidades/verificacion-evidencia/SKILL.md +160 -0
- package/habilidades/verificar-trabajo/SKILL.md +303 -0
- package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
- package/habilidades/wiki-conocimiento/SKILL.md +276 -0
- package/habilidades/wireframes-flujos/SKILL.md +212 -0
- package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
- package/habilidades/workflow-claude-code/SKILL.md +260 -0
- package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
- package/hooks/_run-hook.sh +57 -0
- package/hooks/actualizar-perfil-usuario.js +364 -0
- package/hooks/agente-lifecycle.js +71 -0
- package/hooks/aiisms-detector.js +173 -0
- package/hooks/audit-trail.js +204 -0
- package/hooks/auto-background.js +97 -0
- package/hooks/auto-consolidacion.js +178 -0
- package/hooks/auto-evolucion.js +666 -0
- package/hooks/auto-restaurar-settings.js +360 -0
- package/hooks/calidad-pre-commit.js +929 -0
- package/hooks/calidad-typescript.js +511 -0
- package/hooks/captura-feedback-usuario.js +148 -0
- package/hooks/check-update.js +211 -0
- package/hooks/clasificador-mensajes.js +271 -0
- package/hooks/degradacion-instintos.js +272 -0
- package/hooks/escaneo-secretos.js +389 -0
- package/hooks/extraccion-aprendizajes.js +763 -0
- package/hooks/grafo-contexto.js +129 -0
- package/hooks/graph-update.js +67 -0
- package/hooks/guardrail-modelo.js +247 -0
- package/hooks/inbox-aviso.js +75 -0
- package/hooks/inyeccion-contexto.js +246 -0
- package/hooks/lib/abort-registry.js +214 -0
- package/hooks/lib/agent-backend.js +210 -0
- package/hooks/lib/agent-comms.js +263 -0
- package/hooks/lib/agent-issue-codes.js +284 -0
- package/hooks/lib/agent-matcher.js +189 -0
- package/hooks/lib/async-hook-registry.js +252 -0
- package/hooks/lib/atomic-write.js +130 -0
- package/hooks/lib/auto-consolidator.js +335 -0
- package/hooks/lib/canary-skills.js +187 -0
- package/hooks/lib/consolidation-lock.js +291 -0
- package/hooks/lib/context-builder.js +430 -0
- package/hooks/lib/context-compressor.js +657 -0
- package/hooks/lib/convergence-detector.js +105 -0
- package/hooks/lib/delegation-tracker.js +198 -0
- package/hooks/lib/detectar-package-manager.js +423 -0
- package/hooks/lib/edit-accumulator.js +171 -0
- package/hooks/lib/error-classifier.js +308 -0
- package/hooks/lib/event-bus.js +112 -0
- package/hooks/lib/evolution-tracker.js +442 -0
- package/hooks/lib/execution-state.js +316 -0
- package/hooks/lib/fingerprint-id.js +135 -0
- package/hooks/lib/gateway-notify.js +116 -0
- package/hooks/lib/graph-security.js +75 -0
- package/hooks/lib/guardrail-metrics.js +202 -0
- package/hooks/lib/hook-circuit-breaker.js +206 -0
- package/hooks/lib/loop-detector.js +267 -0
- package/hooks/lib/mcp-health.js +184 -0
- package/hooks/lib/mcp-pool.js +436 -0
- package/hooks/lib/memory-search.js +506 -0
- package/hooks/lib/merkle-audit.js +96 -0
- package/hooks/lib/model-router.js +222 -0
- package/hooks/lib/normalize-error.js +324 -0
- package/hooks/lib/normalize-input.js +65 -0
- package/hooks/lib/nudge-tracker.js +306 -0
- package/hooks/lib/otlp-exporter.js +365 -0
- package/hooks/lib/performance-marks.js +239 -0
- package/hooks/lib/privacy-filter.js +128 -0
- package/hooks/lib/prompt-injection-scanner.js +209 -0
- package/hooks/lib/provenance-tracker.js +183 -0
- package/hooks/lib/rate-limit-tracker.js +253 -0
- package/hooks/lib/reflect-classifier.js +164 -0
- package/hooks/lib/resource-quota.js +122 -0
- package/hooks/lib/retry-jitter.js +165 -0
- package/hooks/lib/risk-engine.js +368 -0
- package/hooks/lib/run-log.js +408 -0
- package/hooks/lib/session-fts.js +379 -0
- package/hooks/lib/session-store.js +293 -0
- package/hooks/lib/singleton-guard.js +159 -0
- package/hooks/lib/skill-auditor.js +588 -0
- package/hooks/lib/sync-status.js +228 -0
- package/hooks/lib/taint-tracker.js +107 -0
- package/hooks/lib/task-service.js +295 -0
- package/hooks/lib/tech-skills-map.js +146 -0
- package/hooks/lib/telegram-cliente.js +159 -0
- package/hooks/lib/telegram-config.js +170 -0
- package/hooks/lib/token-budget.js +156 -0
- package/hooks/lib/token-estimator.js +420 -0
- package/hooks/lib/toon-compressor.js +245 -0
- package/hooks/lib/usage-model.js +183 -0
- package/hooks/lib/variable-resolver.js +230 -0
- package/hooks/linea-estado.js +324 -0
- package/hooks/metricas-evolucion.js +209 -0
- package/hooks/monitor-contexto.js +325 -0
- package/hooks/notificacion-sesion-stop.js +198 -0
- package/hooks/notificacion-telegram-notification.js +4 -0
- package/hooks/notificacion-telegram-subagent.js +4 -0
- package/hooks/notificacion-telegram.js +267 -0
- package/hooks/preservar-estado-pre-compact.js +150 -0
- package/hooks/proteccion-rutas.js +366 -0
- package/hooks/registro-turnos.js +209 -0
- package/hooks/resumen-sesion.js +249 -0
- package/hooks/risk-scoring.js +323 -0
- package/hooks/rotar-audit-auto.js +122 -0
- package/hooks/sugerir-regenerar-inventario.js +170 -0
- package/hooks/telemetria-agentes.js +167 -0
- package/hooks/tracking-costos.js +688 -0
- package/instintos/global.yaml +8 -0
- package/instintos/perfil-usuario.yaml +53 -0
- package/instintos/prompt-appendices.yaml +57 -0
- package/instintos/proyecto.yaml +372 -0
- package/manifiestos/gateway-config.json +77 -0
- package/manifiestos/handoff-context.json +223 -0
- package/manifiestos/hook-profiles.json +44 -0
- package/manifiestos/hooks-config.json +360 -0
- package/manifiestos/modulos.json +1173 -0
- package/manifiestos/perfiles.json +404 -0
- package/package.json +86 -0
- package/plantillas/ESTADO.md +109 -0
- package/plantillas/HOJA-RUTA.md +143 -0
- package/plantillas/PROYECTO.md +122 -0
- package/plantillas/REQUISITOS.md +132 -0
- package/plantillas/auditor-veto-template.md +105 -0
- package/plantillas/github-workflows/README.md +47 -0
- package/plantillas/github-workflows/release-please.yml +44 -0
- package/plantillas/github-workflows/swl-ci.yml +107 -0
- package/plantillas/github-workflows/swl-security.yml +51 -0
- package/plantillas/mcp-mineru.json +13 -0
- package/plantillas/research/ARQUITECTURA.md +220 -0
- package/plantillas/research/FUNCIONALIDADES.md +175 -0
- package/plantillas/research/RESUMEN.md +165 -0
- package/plantillas/research/STACK.md +233 -0
- package/plantillas/research/TRAMPAS.md +299 -0
- package/plantillas/skill-evals-template.json +44 -0
- package/plugin.json +343 -0
- package/reglas/accesibilidad.md +269 -0
- package/reglas/api-diseno.md +400 -0
- package/reglas/arquitectura.md +352 -0
- package/reglas/brevedad-output.md +124 -0
- package/reglas/cloud-infra.md +247 -0
- package/reglas/docs.md +245 -0
- package/reglas/estilo-codigo.md +201 -0
- package/reglas/git-workflow.md +245 -0
- package/reglas/gobernanza.md +271 -0
- package/reglas/harness-claude-code.md +213 -0
- package/reglas/hooks.md +186 -0
- package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
- package/reglas/lenguajes/csharp/hooks.md +281 -0
- package/reglas/lenguajes/csharp/patrones.md +226 -0
- package/reglas/lenguajes/csharp/seguridad.md +258 -0
- package/reglas/lenguajes/csharp/testing.md +176 -0
- package/reglas/lenguajes/go/estilo-codigo.md +195 -0
- package/reglas/lenguajes/go/hooks.md +249 -0
- package/reglas/lenguajes/go/patrones.md +249 -0
- package/reglas/lenguajes/go/seguridad.md +225 -0
- package/reglas/lenguajes/go/testing.md +272 -0
- package/reglas/lenguajes/java/estilo-codigo.md +217 -0
- package/reglas/lenguajes/java/hooks.md +251 -0
- package/reglas/lenguajes/java/patrones.md +226 -0
- package/reglas/lenguajes/java/seguridad.md +233 -0
- package/reglas/lenguajes/java/testing.md +238 -0
- package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
- package/reglas/lenguajes/kotlin/hooks.md +245 -0
- package/reglas/lenguajes/kotlin/patrones.md +201 -0
- package/reglas/lenguajes/kotlin/seguridad.md +202 -0
- package/reglas/lenguajes/kotlin/testing.md +236 -0
- package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
- package/reglas/lenguajes/nextjs/hooks.md +186 -0
- package/reglas/lenguajes/nextjs/patrones.md +225 -0
- package/reglas/lenguajes/nextjs/seguridad.md +216 -0
- package/reglas/lenguajes/nextjs/testing.md +193 -0
- package/reglas/lenguajes/php/estilo-codigo.md +228 -0
- package/reglas/lenguajes/php/hooks.md +165 -0
- package/reglas/lenguajes/php/patrones.md +233 -0
- package/reglas/lenguajes/php/seguridad.md +186 -0
- package/reglas/lenguajes/php/testing.md +205 -0
- package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
- package/reglas/lenguajes/rust/hooks.md +240 -0
- package/reglas/lenguajes/rust/patrones.md +250 -0
- package/reglas/lenguajes/rust/seguridad.md +221 -0
- package/reglas/lenguajes/rust/testing.md +194 -0
- package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
- package/reglas/lenguajes/swift/hooks.md +257 -0
- package/reglas/lenguajes/swift/patrones.md +235 -0
- package/reglas/lenguajes/swift/seguridad.md +248 -0
- package/reglas/lenguajes/swift/testing.md +242 -0
- package/reglas/markitdown.md +60 -0
- package/reglas/memoria-consolidada.md +209 -0
- package/reglas/patrones.md +225 -0
- package/reglas/performance.md +195 -0
- package/reglas/pruebas.md +159 -0
- package/reglas/seguridad-agentes.md +351 -0
- package/reglas/seguridad.md +151 -0
- package/reglas/skills-estandar.md +373 -0
- package/reglas/testing.md +193 -0
- package/schemas/agent-contract.json +176 -0
- package/schemas/agent-frontmatter.schema.json +149 -0
- package/schemas/agent-message.schema.json +53 -0
- package/schemas/agent-output-implementacion.schema.json +85 -0
- package/schemas/agent-output-planificacion.schema.json +113 -0
- package/schemas/agent-output-review.schema.json +78 -0
- package/schemas/diary-entry.schema.json +80 -0
- package/schemas/hook-profiles.schema.json +39 -0
- package/schemas/hooks-config.schema.json +74 -0
- package/schemas/instinct.schema.json +115 -0
- package/schemas/modulos.schema.json +29 -0
- package/schemas/perfiles.schema.json +28 -0
- package/schemas/plugin.schema.json +64 -0
- package/schemas/skill-evals.schema.json +95 -0
- package/schemas/skill-frontmatter.schema.json +170 -0
- package/scripts/actualizar.js +145 -0
- package/scripts/audit-skills.sh +78 -0
- package/scripts/auditar-agentes-gaps.js +149 -0
- package/scripts/auditar-cobertura-frameworks.js +241 -0
- package/scripts/auditar-skills-gaps.js +206 -0
- package/scripts/bootstrap-instintos.js +259 -0
- package/scripts/check-update.js +109 -0
- package/scripts/comandos/agents.js +105 -0
- package/scripts/comandos/info.js +108 -0
- package/scripts/comandos/install-asistido.js +186 -0
- package/scripts/comandos/skills.js +211 -0
- package/scripts/configurar-branch-protection.js +418 -0
- package/scripts/daemon-swl.py +388 -0
- package/scripts/desinstalar.js +130 -0
- package/scripts/doctor.js +559 -0
- package/scripts/field-report.js +199 -0
- package/scripts/generar-inventario.js +317 -0
- package/scripts/inbox-tmux-inject.js +161 -0
- package/scripts/inferir-herramientas-permitidas.js +586 -0
- package/scripts/inicializar.js +133 -0
- package/scripts/instalador.js +1031 -0
- package/scripts/instalar-git-hook.js +122 -0
- package/scripts/lib/agp-frontmatter.js +222 -0
- package/scripts/lib/append-con-marcadores.js +199 -0
- package/scripts/lib/artefactos-python.js +43 -0
- package/scripts/lib/audit-query.js +221 -0
- package/scripts/lib/autostart-linux.js +347 -0
- package/scripts/lib/autostart-macos.js +360 -0
- package/scripts/lib/autostart-windows.js +307 -0
- package/scripts/lib/budget-enforcer.js +252 -0
- package/scripts/lib/claude-sessions.js +285 -0
- package/scripts/lib/configurar-ci.js +380 -0
- package/scripts/lib/console-span-exporter.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -0
- package/scripts/lib/dashboard-widgets.js +290 -0
- package/scripts/lib/detectar-runtime.js +279 -0
- package/scripts/lib/detectar-stack.js +187 -0
- package/scripts/lib/diary-entry.js +234 -0
- package/scripts/lib/drift-detector.js +545 -0
- package/scripts/lib/estado.js +124 -0
- package/scripts/lib/gestor-componentes.js +243 -0
- package/scripts/lib/gitignore-manifest.js +305 -0
- package/scripts/lib/graph-analyze.py +556 -0
- package/scripts/lib/graph-builder.py +485 -0
- package/scripts/lib/graph-cluster.py +259 -0
- package/scripts/lib/health-row.js +168 -0
- package/scripts/lib/hooks-settings.js +789 -0
- package/scripts/lib/manifiestos.js +138 -0
- package/scripts/lib/mc-client.js +137 -0
- package/scripts/lib/notificaciones-telegram.js +1107 -0
- package/scripts/lib/npm-version.js +261 -0
- package/scripts/lib/paquetes-conocidos.js +50 -0
- package/scripts/lib/preservar-usuario.js +586 -0
- package/scripts/lib/prompt-builder.js +264 -0
- package/scripts/lib/resolver-externo.js +332 -0
- package/scripts/lib/schedule-parser.js +305 -0
- package/scripts/lib/scoring-instintos.js +240 -0
- package/scripts/lib/seguridad.js +160 -0
- package/scripts/lib/selector-interactivo.js +152 -0
- package/scripts/lib/semantic-search.js +242 -0
- package/scripts/lib/skill-discovery.js +234 -0
- package/scripts/lib/skill-metrics.js +246 -0
- package/scripts/lib/skill-normalizer.js +112 -0
- package/scripts/lib/skills-hub.js +340 -0
- package/scripts/lib/span-schema.js +134 -0
- package/scripts/lib/tool-cost-analyzer.js +255 -0
- package/scripts/lib/tracing-processor-interface.js +286 -0
- package/scripts/lib/transformadores/base.js +80 -0
- package/scripts/lib/transformadores/claude.js +124 -0
- package/scripts/lib/transformadores/codex.js +115 -0
- package/scripts/lib/transformadores/copilot.js +106 -0
- package/scripts/lib/transformadores/gemini.js +74 -0
- package/scripts/lib/transformadores/index.js +35 -0
- package/scripts/lib/transformadores/opencode.js +75 -0
- package/scripts/lib/ui.js +259 -0
- package/scripts/limpiar-artefactos-python.js +131 -0
- package/scripts/mcp-orchestrator.py +386 -0
- package/scripts/mcp-pool-manager.py +352 -0
- package/scripts/mcp-telemetry.py +378 -0
- package/scripts/poblar-evolvable.js +226 -0
- package/scripts/publicar.js +287 -0
- package/scripts/reflect-skills.js +403 -0
- package/scripts/rotar-audit-logs.js +185 -0
- package/scripts/run-skill-evals.js +242 -0
- package/scripts/smoke-test.js +374 -0
- package/scripts/token-analysis.py +471 -0
- package/scripts/validar-manifest.js +195 -0
- package/scripts/validar-memoria.js +321 -0
- package/scripts/validar-tests-aislamiento.js +184 -0
- package/scripts/validar-tokens-test.js +208 -0
- package/scripts/validar.js +147 -0
- package/scripts/validate-markdown.py +339 -0
- package/scripts/validate-skills.py +385 -0
- package/scripts/vendor/claude-usage/README.md +116 -0
- package/scripts/vendor/claude-usage/cli.py +334 -0
- package/scripts/vendor/claude-usage/dashboard.py +795 -0
- package/scripts/vendor/claude-usage/scanner.py +467 -0
- package/scripts/vendor/markitdown/cli.py +194 -0
- package/scripts/verificar-evolucion.js +289 -0
- package/scripts/verificar-release.js +494 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Regla: Patrones de Diseño — Rust
|
|
2
|
+
|
|
3
|
+
Patrones idiomáticos de Rust para código de producción. El objetivo es aprovechar
|
|
4
|
+
el sistema de tipos y el ownership model para escribir código correcto por
|
|
5
|
+
construcción, no solo por convención.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Error handling: thiserror y anyhow
|
|
10
|
+
|
|
11
|
+
**thiserror** para librerías (errores tipados que el llamador puede inspeccionar):
|
|
12
|
+
|
|
13
|
+
```rust
|
|
14
|
+
use thiserror::Error;
|
|
15
|
+
|
|
16
|
+
#[derive(Debug, Error)]
|
|
17
|
+
pub enum FacturaError {
|
|
18
|
+
#[error("Factura no encontrada: {id}")]
|
|
19
|
+
NoEncontrada { id: u64 },
|
|
20
|
+
|
|
21
|
+
#[error("Total inválido: {total} (debe ser > 0)")]
|
|
22
|
+
TotalInvalido { total: f64 },
|
|
23
|
+
|
|
24
|
+
#[error("Error de base de datos")]
|
|
25
|
+
BaseDatos(#[from] sqlx::Error),
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**anyhow** para aplicaciones (propagación de errores con contexto):
|
|
30
|
+
|
|
31
|
+
```rust
|
|
32
|
+
use anyhow::{Context, Result};
|
|
33
|
+
|
|
34
|
+
async fn cargar_config() -> Result<Config> {
|
|
35
|
+
let ruta = env::var("CONFIG_PATH")
|
|
36
|
+
.context("Variable CONFIG_PATH no definida")?;
|
|
37
|
+
|
|
38
|
+
let contenido = fs::read_to_string(&ruta)
|
|
39
|
+
.with_context(|| format!("No se pudo leer el archivo: {ruta}"))?;
|
|
40
|
+
|
|
41
|
+
toml::from_str(&contenido)
|
|
42
|
+
.context("Formato de configuración inválido")
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- NUNCA mezclar: `thiserror` en librerías, `anyhow` en binarios/aplicaciones.
|
|
47
|
+
- NUNCA retornar `Box<dyn Error>` — usar `anyhow::Error` o un tipo específico.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Builder pattern para structs complejos
|
|
52
|
+
|
|
53
|
+
Cuando un struct tiene más de 4 campos o campos opcionales, usar builder:
|
|
54
|
+
|
|
55
|
+
```rust
|
|
56
|
+
// MAL — constructor con muchos parámetros, difícil de leer
|
|
57
|
+
let factura = Factura::new(123, "cliente@email.com", 1500.0, None, true, "MXN");
|
|
58
|
+
|
|
59
|
+
// BIEN — builder con nombres explícitos
|
|
60
|
+
let factura = Factura::builder()
|
|
61
|
+
.id(123)
|
|
62
|
+
.cliente("cliente@email.com")
|
|
63
|
+
.total(1500.0)
|
|
64
|
+
.moneda("MXN")
|
|
65
|
+
.build()?;
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
- El método `build()` retorna `Result<T, Error>` para validar invariantes.
|
|
69
|
+
- Usar el crate `derive_builder` para casos simples.
|
|
70
|
+
- Para builders complejos con validación, implementar manualmente.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Newtype pattern para type safety
|
|
75
|
+
|
|
76
|
+
Envolver tipos primitivos para que el compilador detecte usos incorrectos:
|
|
77
|
+
|
|
78
|
+
```rust
|
|
79
|
+
// MAL — dos u64 intercambiables, el compilador no detecta el error
|
|
80
|
+
fn transferir(origen: u64, destino: u64, monto: f64) { ... }
|
|
81
|
+
transferir(cuenta_destino, cuenta_origen, 100.0); // invertidos, sin error
|
|
82
|
+
|
|
83
|
+
// BIEN — tipos distintos que el compilador distingue
|
|
84
|
+
struct CuentaId(u64);
|
|
85
|
+
struct Monto(f64);
|
|
86
|
+
|
|
87
|
+
fn transferir(origen: CuentaId, destino: CuentaId, monto: Monto) { ... }
|
|
88
|
+
// transferir(cuenta_destino, cuenta_origen, monto); // ERROR DE COMPILACIÓN
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
- Implementar `Display`, `Debug`, `From<u64>` y `Into<u64>` según necesidad.
|
|
92
|
+
- Implementar `Deref` solo cuando el newtype ES el tipo interno (no solo lo contiene).
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Trait objects vs generics
|
|
97
|
+
|
|
98
|
+
| Situación | Usar | Razón |
|
|
99
|
+
|-----------|------|-------|
|
|
100
|
+
| Tipo conocido en compilación, performance crítica | `impl Trait` / genéricos | Monomorphization, sin overhead |
|
|
101
|
+
| Colección heterogénea de implementadores | `Box<dyn Trait>` | Dispatch dinámico necesario |
|
|
102
|
+
| Trait object en función | `&dyn Trait` | Sin heap allocation |
|
|
103
|
+
| Tamaño del binario importa | Genéricos con cuidado | Monomorphization puede inflarlo |
|
|
104
|
+
|
|
105
|
+
```rust
|
|
106
|
+
// Genéricos — dispatch estático, cero overhead
|
|
107
|
+
fn procesar<T: Pagable>(item: &T) -> Resultado { ... }
|
|
108
|
+
|
|
109
|
+
// Trait object — dispatch dinámico, cuando el tipo varía en runtime
|
|
110
|
+
fn registrar_handler(handler: Box<dyn EventHandler>) { ... }
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## From/Into para conversiones idiomáticas
|
|
116
|
+
|
|
117
|
+
Implementar `From<T>` automáticamente proporciona `Into<T>`:
|
|
118
|
+
|
|
119
|
+
```rust
|
|
120
|
+
impl From<FacturaDb> for Factura {
|
|
121
|
+
fn from(db: FacturaDb) -> Self {
|
|
122
|
+
Factura {
|
|
123
|
+
id: FacturaId(db.id),
|
|
124
|
+
total: Monto(db.total),
|
|
125
|
+
estatus: db.estatus.parse().unwrap_or_default(),
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// El llamador puede usar From o Into indistintamente
|
|
131
|
+
let factura = Factura::from(fila_db);
|
|
132
|
+
let factura: Factura = fila_db.into();
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
- NUNCA implementar `Into<T>` directamente — implementar `From<T>` y dejar que
|
|
136
|
+
el compilador derive `Into<T>` automáticamente.
|
|
137
|
+
- Implementar `TryFrom<T>` cuando la conversión puede fallar.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Option combinators
|
|
142
|
+
|
|
143
|
+
```rust
|
|
144
|
+
// MAL — if-let verboso para transformaciones simples
|
|
145
|
+
let nombre_upper = if let Some(n) = usuario.nombre {
|
|
146
|
+
Some(n.to_uppercase())
|
|
147
|
+
} else {
|
|
148
|
+
None
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// BIEN — combinators
|
|
152
|
+
let nombre_upper = usuario.nombre.map(|n| n.to_uppercase());
|
|
153
|
+
|
|
154
|
+
// MAL — unwrap con default innecesariamente verboso
|
|
155
|
+
let total = factura.total.unwrap_or(0.0);
|
|
156
|
+
|
|
157
|
+
// BIEN — unwrap_or_default cuando el default del tipo es correcto
|
|
158
|
+
let total = factura.total.unwrap_or_default(); // 0.0 para f64
|
|
159
|
+
|
|
160
|
+
// Cadena de operaciones con Option
|
|
161
|
+
let descuento = usuario
|
|
162
|
+
.membresia
|
|
163
|
+
.filter(|m| m.esta_activa())
|
|
164
|
+
.map(|m| m.porcentaje_descuento())
|
|
165
|
+
.unwrap_or(0.0);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
- `map` para transformar el valor interno.
|
|
169
|
+
- `and_then` para operaciones que pueden retornar `None`.
|
|
170
|
+
- `or_else` para proveer un alternativo si el valor es `None`.
|
|
171
|
+
- `unwrap_or_default` cuando el default del tipo es el valor correcto.
|
|
172
|
+
- `ok_or_else` para convertir `Option<T>` en `Result<T, E>`.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Async con Tokio
|
|
177
|
+
|
|
178
|
+
```rust
|
|
179
|
+
use tokio::{join, select, spawn};
|
|
180
|
+
|
|
181
|
+
// Ejecutar tareas independientes en paralelo
|
|
182
|
+
async fn cargar_datos(id: u64) -> Result<DatoCompleto> {
|
|
183
|
+
let (usuario, facturas) = join!(
|
|
184
|
+
repo.obtener_usuario(id),
|
|
185
|
+
repo.listar_facturas(id)
|
|
186
|
+
)?;
|
|
187
|
+
Ok(DatoCompleto { usuario, facturas })
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Spawn para background tasks
|
|
191
|
+
spawn(async move {
|
|
192
|
+
if let Err(e) = enviar_notificacion(evento).await {
|
|
193
|
+
tracing::error!("Error enviando notificación: {e}");
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Select para timeout o cancelación
|
|
198
|
+
select! {
|
|
199
|
+
resultado = operacion_lenta() => manejar(resultado),
|
|
200
|
+
_ = tokio::time::sleep(Duration::from_secs(30)) => {
|
|
201
|
+
return Err(Error::Timeout);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
- NUNCA usar `std::thread::sleep` en código async — usar `tokio::time::sleep`.
|
|
207
|
+
- NUNCA bloquear el thread de Tokio con operaciones sincrónicas largas.
|
|
208
|
+
Usar `tokio::task::spawn_blocking` para código CPU-intensivo o IO síncrono.
|
|
209
|
+
- `#[tokio::main]` solo en `main()`. El resto son funciones `async fn` normales.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## RAII: Drop trait para cleanup
|
|
214
|
+
|
|
215
|
+
```rust
|
|
216
|
+
struct ConexionBd {
|
|
217
|
+
inner: pg::Connection,
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
impl Drop for ConexionBd {
|
|
221
|
+
fn drop(&mut self) {
|
|
222
|
+
// Se ejecuta automáticamente al salir del scope
|
|
223
|
+
if let Err(e) = self.inner.cerrar() {
|
|
224
|
+
tracing::warn!("Error cerrando conexión: {e}");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// El cleanup es automático — no hay finally ni try/catch necesario
|
|
230
|
+
{
|
|
231
|
+
let conn = ConexionBd::conectar(&url)?;
|
|
232
|
+
conn.ejecutar(query)?;
|
|
233
|
+
} // conn.drop() se llama aquí automáticamente
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
- Usar RAII para recursos que necesiten cleanup garantizado.
|
|
237
|
+
- Los guardas de Mutex (`MutexGuard`) son RAII — liberan el lock al salir del scope.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Checklist de patrones antes de hacer merge
|
|
242
|
+
|
|
243
|
+
- [ ] Errores de librería usan `thiserror`, errores de aplicación usan `anyhow`
|
|
244
|
+
- [ ] Sin `Box<dyn Error>` como tipo de retorno
|
|
245
|
+
- [ ] Structs complejos (>4 campos opcionales) usan builder pattern
|
|
246
|
+
- [ ] IDs y valores de dominio usan newtype pattern
|
|
247
|
+
- [ ] Sin `unwrap()` en `src/` fuera de tests (ver regla de estilo)
|
|
248
|
+
- [ ] Option manejado con combinators, no con if-let cuando es una transformación
|
|
249
|
+
- [ ] Tareas async independientes usand `join!` para ejecución paralela
|
|
250
|
+
- [ ] Sin bloqueo del runtime async con operaciones síncronas largas
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# Regla: Seguridad — Rust
|
|
2
|
+
|
|
3
|
+
Rust elimina por diseño clases enteras de vulnerabilidades (buffer overflows,
|
|
4
|
+
use-after-free, data races). Sin embargo, existen vectores de ataque específicos
|
|
5
|
+
de Rust que requieren disciplina explícita. Esta regla cubre lo que el compilador
|
|
6
|
+
no puede garantizar por sí solo.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## cargo-audit para CVEs en dependencias
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Instalar
|
|
14
|
+
cargo install cargo-audit
|
|
15
|
+
|
|
16
|
+
# Ejecutar auditoría
|
|
17
|
+
cargo audit
|
|
18
|
+
|
|
19
|
+
# Con política estricta — falla si hay cualquier vulnerabilidad
|
|
20
|
+
cargo audit --deny warnings
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- `cargo audit` debe ejecutarse en CI **semanalmente** como job independiente.
|
|
24
|
+
- También ejecutar en el pipeline de PR si `Cargo.lock` cambia.
|
|
25
|
+
- Si un CVE no tiene fix disponible:
|
|
26
|
+
1. Documentar en `Cargo.toml` como una excepción justificada con ticket.
|
|
27
|
+
2. Evaluar si el vector de ataque aplica al uso real de la dependencia.
|
|
28
|
+
3. Definir fecha límite para migrar o reemplazar la dependencia.
|
|
29
|
+
- NUNCA ignorar un CVE HIGH o CRITICAL sin aprobación explícita del equipo.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## cargo-deny para licencias y vulnerabilidades
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
cargo install cargo-deny
|
|
37
|
+
cargo deny check
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`deny.toml` en la raíz del proyecto:
|
|
41
|
+
|
|
42
|
+
```toml
|
|
43
|
+
[advisories]
|
|
44
|
+
vulnerability = "deny"
|
|
45
|
+
unmaintained = "warn"
|
|
46
|
+
unsound = "deny"
|
|
47
|
+
|
|
48
|
+
[licenses]
|
|
49
|
+
# Solo licencias compatibles con el proyecto
|
|
50
|
+
allow = ["MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause", "ISC"]
|
|
51
|
+
deny = ["GPL-2.0", "AGPL-3.0"]
|
|
52
|
+
|
|
53
|
+
[bans]
|
|
54
|
+
# Prohibir crates con historial de problemas de seguridad
|
|
55
|
+
deny = [
|
|
56
|
+
{ name = "openssl", reason = "Usar rustls o native-tls verificados" },
|
|
57
|
+
]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- `cargo-deny` en CI detecta tanto vulnerabilidades como conflictos de licencia.
|
|
61
|
+
- Revisar y actualizar `deny.toml` cuando se agregan dependencias nuevas.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## unsafe: prohibido sin justificación en ADR
|
|
66
|
+
|
|
67
|
+
- `unsafe` desactiva las garantías del compilador. Todo bloque `unsafe` es
|
|
68
|
+
responsabilidad explícita del desarrollador — el compilador ya no verifica.
|
|
69
|
+
- **Regla**: todo uso de `unsafe` en el código del proyecto (no en dependencias)
|
|
70
|
+
requiere:
|
|
71
|
+
1. Un comentario inmediatamente antes del bloque explicando POR QUÉ es seguro.
|
|
72
|
+
2. Un ADR documentando la decisión si el `unsafe` es en código de librería.
|
|
73
|
+
3. Revisión de seguridad explícita en el PR.
|
|
74
|
+
|
|
75
|
+
```rust
|
|
76
|
+
// MAL — unsafe sin justificación
|
|
77
|
+
unsafe {
|
|
78
|
+
*ptr = valor;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// BIEN — unsafe con safety comment obligatorio
|
|
82
|
+
// SAFETY: ptr apunta a memoria válida y alineada porque
|
|
83
|
+
// fue obtenido de Box::into_raw() en la misma función y
|
|
84
|
+
// no ha sido liberado ni aliasado desde entonces.
|
|
85
|
+
unsafe {
|
|
86
|
+
*ptr = valor;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- `#![forbid(unsafe_code)]` en crates que no necesitan `unsafe` — el compilador
|
|
91
|
+
rechaza cualquier bloque `unsafe` y protege contra PRs accidentales.
|
|
92
|
+
- Si se necesita `unsafe` en un módulo específico, aislar en un módulo dedicado
|
|
93
|
+
con interfaz safe hacia afuera.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Miri para detectar undefined behavior
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Instalar (requiere toolchain nightly)
|
|
101
|
+
rustup +nightly component add miri
|
|
102
|
+
|
|
103
|
+
# Ejecutar tests bajo Miri
|
|
104
|
+
cargo +nightly miri test
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- Miri ejecuta el código en un intérprete que detecta UB, accesos inválidos
|
|
108
|
+
a memoria y data races que ocurren en runtime.
|
|
109
|
+
- Ejecutar Miri en todo código que contiene `unsafe`.
|
|
110
|
+
- Miri puede ser lento — ejecutarlo como job separado en CI, no en cada PR.
|
|
111
|
+
- Si Miri reporta un error: es un bug real que debe corregirse, no ignorarse.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## No transmute sin revisión de seguridad
|
|
116
|
+
|
|
117
|
+
- `std::mem::transmute` reinterpreta los bits de un valor como otro tipo.
|
|
118
|
+
Es el operador más peligroso de Rust — puede violar todas las garantías del sistema de tipos.
|
|
119
|
+
- **Regla**: `transmute` está prohibido sin revisión explícita de seguridad
|
|
120
|
+
documentada en el PR y en el código.
|
|
121
|
+
- Alternativas que no requieren `transmute`:
|
|
122
|
+
- Conversión de números: `as` cast o `From`/`Into`
|
|
123
|
+
- Conversión de punteros: `pointer::cast()`
|
|
124
|
+
- Conversión de referencias: `pointer::cast()` con `unsafe` justificado
|
|
125
|
+
- Cambio de lifetime: rediseñar la API para que el compilador la acepte
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Secretos: no en const/static
|
|
130
|
+
|
|
131
|
+
```rust
|
|
132
|
+
// MAL — la API key queda en el binario compilado y en el historial de git
|
|
133
|
+
const API_KEY: &str = "sk-prod-abc123xyz789";
|
|
134
|
+
|
|
135
|
+
// MAL — static mutable tampoco es seguro
|
|
136
|
+
static mut TOKEN: String = String::new();
|
|
137
|
+
|
|
138
|
+
// BIEN — leer de variable de entorno en runtime
|
|
139
|
+
fn cargar_config() -> Result<Config> {
|
|
140
|
+
Ok(Config {
|
|
141
|
+
api_key: env::var("API_KEY")
|
|
142
|
+
.context("Variable API_KEY no definida")?,
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
- Las constantes en Rust se embeben en el binario. Un secreto en `const` puede
|
|
148
|
+
extraerse del ejecutable con herramientas básicas de análisis binario.
|
|
149
|
+
- Usar variables de entorno para secretos, inyectadas por el sistema de deployment.
|
|
150
|
+
- En desarrollo local: archivo `.env` (en `.gitignore`) con `dotenvy` crate.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Validar inputs en boundaries del sistema
|
|
155
|
+
|
|
156
|
+
```rust
|
|
157
|
+
use garde::Validate;
|
|
158
|
+
|
|
159
|
+
#[derive(Validate)]
|
|
160
|
+
pub struct NuevaFactura {
|
|
161
|
+
#[garde(length(min = 1, max = 255))]
|
|
162
|
+
pub descripcion: String,
|
|
163
|
+
|
|
164
|
+
#[garde(range(min = 0.01, max = 1_000_000.0))]
|
|
165
|
+
pub total: f64,
|
|
166
|
+
|
|
167
|
+
#[garde(email)]
|
|
168
|
+
pub cliente_email: String,
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
pub async fn crear_factura(
|
|
172
|
+
State(repo): State<Arc<FacturaRepo>>,
|
|
173
|
+
Json(input): Json<NuevaFactura>,
|
|
174
|
+
) -> Result<Json<Factura>, AppError> {
|
|
175
|
+
input.validate(&())?; // Retorna error si algún campo es inválido
|
|
176
|
+
let factura = repo.crear(input).await?;
|
|
177
|
+
Ok(Json(factura))
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
- Validar toda entrada externa (HTTP, archivos, CLI) en el boundary de entrada.
|
|
182
|
+
- No asumir que los datos de la base de datos son válidos si pueden haber sido
|
|
183
|
+
escritos por otros sistemas.
|
|
184
|
+
- Usar el crate `garde` o `validator` para validación declarativa.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Pin para futures auto-referenciales
|
|
189
|
+
|
|
190
|
+
```rust
|
|
191
|
+
use std::pin::Pin;
|
|
192
|
+
use futures::Future;
|
|
193
|
+
|
|
194
|
+
// Cuando un future contiene referencias a sí mismo, Pin garantiza
|
|
195
|
+
// que no se moverá en memoria mientras está pendiente.
|
|
196
|
+
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
|
|
197
|
+
|
|
198
|
+
// En traits async con objetos (trait objects de futures)
|
|
199
|
+
trait Procesador: Send {
|
|
200
|
+
fn procesar<'a>(&'a self, item: &'a Item) -> BoxFuture<'a, Result<()>>;
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
- Usar `Pin<Box<dyn Future>>` para almacenar futures en structs o como parámetros.
|
|
205
|
+
- No implementar `Unpin` manualmente en futures a menos que se pueda demostrar
|
|
206
|
+
que son seguros de mover.
|
|
207
|
+
- El compilador detectará la mayoría de los errores relacionados con Pin —
|
|
208
|
+
si hay que combatir al compilador para que acepte el código, revisar el diseño.
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Checklist de seguridad antes de hacer merge
|
|
213
|
+
|
|
214
|
+
- [ ] `cargo audit` pasa sin vulnerabilidades HIGH o CRITICAL
|
|
215
|
+
- [ ] `cargo deny check` pasa (licencias y vulnerabilidades)
|
|
216
|
+
- [ ] Todo bloque `unsafe` tiene safety comment explicando por qué es seguro
|
|
217
|
+
- [ ] Sin `transmute` sin revisión de seguridad documentada
|
|
218
|
+
- [ ] Sin secretos en `const`, `static` o en código fuente
|
|
219
|
+
- [ ] Inputs externos validados con esquemas (garde/validator)
|
|
220
|
+
- [ ] `#![forbid(unsafe_code)]` en crates que no lo necesitan
|
|
221
|
+
- [ ] Miri ejecutado en todo código nuevo con `unsafe`
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Regla: Pruebas — Rust
|
|
2
|
+
|
|
3
|
+
Las pruebas en Rust son ciudadanos de primera clase: viven junto al código que
|
|
4
|
+
prueban y el compilador las verifica. El sistema de tipos ya elimina clases
|
|
5
|
+
enteras de bugs — los tests cubren la lógica de negocio y los contratos públicos.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## cargo test como runner principal
|
|
10
|
+
|
|
11
|
+
- `cargo test` ejecuta todos los tests: unitarios, de integración y doctests.
|
|
12
|
+
- `cargo test nombre` para ejecutar un test específico.
|
|
13
|
+
- `cargo test -- --nocapture` para ver salida en tests que pasan.
|
|
14
|
+
- CI siempre ejecuta `cargo test --all-targets --all-features` antes del merge.
|
|
15
|
+
- Los benchmarks no corren con `cargo test` — usar `cargo bench`.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## rstest para tests parametrizados y fixtures
|
|
20
|
+
|
|
21
|
+
```rust
|
|
22
|
+
use rstest::{fixture, rstest};
|
|
23
|
+
|
|
24
|
+
#[fixture]
|
|
25
|
+
fn factura_valida() -> Factura {
|
|
26
|
+
Factura::builder().id(FacturaId(1)).total(Monto(1500.0)).build().unwrap()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Test parametrizado — evita duplicar el mismo test con distintos valores
|
|
30
|
+
#[rstest]
|
|
31
|
+
#[case(0.16, 240.0)]
|
|
32
|
+
#[case(0.08, 120.0)]
|
|
33
|
+
#[case(0.0, 0.0)]
|
|
34
|
+
fn test_calcular_iva_por_tasa(factura_valida: Factura, #[case] tasa: f64, #[case] esperado: f64) {
|
|
35
|
+
assert_eq!(factura_valida.calcular_iva(tasa).0, esperado);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- Usar `#[fixture]` para objetos complejos reutilizados entre tests.
|
|
40
|
+
- Usar `#[rstest]` con `#[case]` en lugar de duplicar tests con distintos inputs.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## proptest para property-based testing
|
|
45
|
+
|
|
46
|
+
```rust
|
|
47
|
+
use proptest::prelude::*;
|
|
48
|
+
|
|
49
|
+
proptest! {
|
|
50
|
+
#[test]
|
|
51
|
+
fn iva_nunca_supera_el_total(total in 0.01f64..1_000_000.0) {
|
|
52
|
+
let factura = FacturaFactory::con_total(total);
|
|
53
|
+
prop_assert!(factura.calcular_iva(0.16).0 <= total);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- Usar proptest para invariantes que deben cumplirse para cualquier input válido.
|
|
59
|
+
- Especialmente útil para: serialización/deserialización, algoritmos matemáticos y parsers.
|
|
60
|
+
- Complementa los tests unitarios — no los reemplaza.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## mockall para mocks de traits
|
|
65
|
+
|
|
66
|
+
```rust
|
|
67
|
+
use mockall::mock;
|
|
68
|
+
|
|
69
|
+
mock! {
|
|
70
|
+
RepoMock {}
|
|
71
|
+
impl FacturaRepo for RepoMock {
|
|
72
|
+
async fn obtener(&self, id: FacturaId) -> Result<Factura, FacturaError>;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#[tokio::test]
|
|
77
|
+
async fn test_servicio_propaga_error_de_repo() {
|
|
78
|
+
// Arrange
|
|
79
|
+
let mut repo = MockRepoMock::new();
|
|
80
|
+
repo.expect_obtener()
|
|
81
|
+
.returning(|_| Err(FacturaError::NoEncontrada { id: 99 }));
|
|
82
|
+
|
|
83
|
+
// Act
|
|
84
|
+
let resultado = FacturaServicio::new(Arc::new(repo))
|
|
85
|
+
.obtener(FacturaId(99)).await;
|
|
86
|
+
|
|
87
|
+
// Assert
|
|
88
|
+
assert!(matches!(resultado, Err(FacturaError::NoEncontrada { .. })));
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- Mockear solo dependencias externas (BD, APIs, filesystem) — nunca código propio del dominio.
|
|
93
|
+
- Verificar el número de llamadas con `.times(N)` para side effects esperados.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## cargo-llvm-cov para cobertura
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
cargo install cargo-llvm-cov
|
|
101
|
+
cargo llvm-cov --fail-under-lines 80
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- Cobertura mínima: **80%** de líneas en módulos de lógica de negocio.
|
|
105
|
+
- CI debe fallar si la cobertura cae por debajo del umbral.
|
|
106
|
+
- Excluir código de arranque y configuración con `#[cfg(not(tarpaulin_include))]`.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Tests unitarios en el mismo archivo (#[cfg(test)] mod tests)
|
|
111
|
+
|
|
112
|
+
```rust
|
|
113
|
+
// src/facturacion/calculo.rs
|
|
114
|
+
pub fn calcular_iva(base: f64, tasa: f64) -> f64 { base * tasa }
|
|
115
|
+
|
|
116
|
+
#[cfg(test)]
|
|
117
|
+
mod tests {
|
|
118
|
+
use super::*; // accede también a funciones privadas
|
|
119
|
+
|
|
120
|
+
#[test]
|
|
121
|
+
fn iva_con_tasa_estandar() {
|
|
122
|
+
// Arrange
|
|
123
|
+
let (base, tasa) = (1000.0, 0.16);
|
|
124
|
+
// Act
|
|
125
|
+
let resultado = calcular_iva(base, tasa);
|
|
126
|
+
// Assert
|
|
127
|
+
assert_eq!(resultado, 160.0);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
- `use super::*` permite probar funciones privadas del módulo.
|
|
133
|
+
- `#[cfg(test)]` garantiza que el código de test no se incluye en el binario.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Tests de integración en tests/
|
|
138
|
+
|
|
139
|
+
Los tests de integración viven en `tests/` en la raíz del crate y solo acceden
|
|
140
|
+
a la API pública:
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
mi-crate/
|
|
144
|
+
├── src/
|
|
145
|
+
└── tests/
|
|
146
|
+
└── facturacion_integration.rs
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
- Usar una BD aislada por test (transacción que se revierte, o BD en memoria).
|
|
150
|
+
- Los tests de integración son más lentos — ejecutar en job CI separado si es necesario.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Benchmarks con criterion
|
|
155
|
+
|
|
156
|
+
```rust
|
|
157
|
+
// benches/calculo_bench.rs
|
|
158
|
+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
159
|
+
|
|
160
|
+
fn benchmark_calcular_totales(c: &mut Criterion) {
|
|
161
|
+
let facturas: Vec<Factura> = (0..1000).map(FacturaFactory::nueva).collect();
|
|
162
|
+
c.bench_function("calcular_totales_1000", |b| {
|
|
163
|
+
b.iter(|| calcular_totales(black_box(&facturas)))
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
criterion_group!(benchmarks, benchmark_calcular_totales);
|
|
168
|
+
criterion_main!(benchmarks);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- Los benchmarks van en `benches/` — no en `src/` ni `tests/`.
|
|
172
|
+
- `black_box` previene que el compilador optimice el código de benchmark.
|
|
173
|
+
- No corren en CI normal — solo al investigar regresiones de performance.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Patrón Arrange-Act-Assert
|
|
178
|
+
|
|
179
|
+
- Los tres bloques siempre separados con comentario o línea en blanco.
|
|
180
|
+
- Nombre del test: `test_[unidad]_[condicion]_[resultado_esperado]`.
|
|
181
|
+
- Un solo concepto por test. Si el Arrange es extenso, extraer a fixture de rstest.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Checklist de pruebas antes de hacer merge
|
|
186
|
+
|
|
187
|
+
- [ ] `cargo test --all-targets` pasa completamente
|
|
188
|
+
- [ ] Tests nuevos para toda lógica de negocio nueva
|
|
189
|
+
- [ ] Test de regresión escrito antes del fix para todo bug
|
|
190
|
+
- [ ] `cargo llvm-cov --fail-under-lines 80` pasa
|
|
191
|
+
- [ ] Tests unitarios en `#[cfg(test)] mod tests` del mismo archivo
|
|
192
|
+
- [ ] Tests de integración en `tests/`
|
|
193
|
+
- [ ] Sin `time::sleep` en tests — usar mocks del reloj
|
|
194
|
+
- [ ] Tests parametrizados con `rstest` en lugar de tests duplicados
|