@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,296 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-patrones
|
|
3
|
+
description: >
|
|
4
|
+
Patrones idiomaticos de Rust: newtype, builder con typestate, From/Into,
|
|
5
|
+
RAII con Drop, iteradores custom, smart pointers y interior mutability.
|
|
6
|
+
Cargar cuando se diseñe arquitectura Rust o se refactorice código existente.
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
herramientasPermitidas: [Read, Glob, Grep]
|
|
9
|
+
exclusiones:
|
|
10
|
+
- "No cargar para implementar servicios Rust, APIs HTTP o lógica concurrente — para implementación cargar `rust-experto`."
|
|
11
|
+
- "No cargar para escribir tests Rust — para testing cargar `rust-testing`."
|
|
12
|
+
- "No cargar para errores de compilación Rust — para build errors cargar `build-errors-rust`."
|
|
13
|
+
- "No cargar para patrones de diseño en otros lenguajes — newtype y typestate son patrones idiomáticos de Rust no directamente aplicables en lenguajes con GC."
|
|
14
|
+
evolvable: true # default para skill estandar
|
|
15
|
+
---
|
|
16
|
+
# Rust Patrones — Diseño Idiomático Rust
|
|
17
|
+
|
|
18
|
+
Cubre los patrones que producen código Rust seguro, expresivo y mantenible:
|
|
19
|
+
newtype para tipos fuertes, builder con typestate, conversiones con From/Into,
|
|
20
|
+
RAII con Drop, iteradores custom y uso correcto de smart pointers.
|
|
21
|
+
|
|
22
|
+
## Cuándo cargar este skill
|
|
23
|
+
|
|
24
|
+
Invoca `Skill("rust-patrones")` cuando:
|
|
25
|
+
|
|
26
|
+
- Se diseñen tipos de dominio en Rust (IDs, cantidades, valores monetarios)
|
|
27
|
+
- Se implemente el patrón builder para structs con muchos campos opcionales
|
|
28
|
+
- Se revise código con clonaciones excesivas o unsafe innecesario
|
|
29
|
+
- Se diseñen iteradores custom o adaptadores de iterador
|
|
30
|
+
- Se elija entre Box, Rc, Arc, Cell y RefCell
|
|
31
|
+
|
|
32
|
+
## Cuándo NO cargar
|
|
33
|
+
|
|
34
|
+
- La pregunta es sobre implementar servicios Rust, APIs HTTP o async con Tokio — para implementación cargar `rust-experto`.
|
|
35
|
+
- La tarea es escribir tests Rust — cargar `rust-testing`.
|
|
36
|
+
- Los errores son de compilación Rust (borrow checker, lifetime errors) — cargar `build-errors-rust`.
|
|
37
|
+
- Los patrones buscados son de otro lenguaje — newtype y typestate son específicos de Rust; en lenguajes con GC los patrones equivalentes son distintos.
|
|
38
|
+
|
|
39
|
+
## Conceptos clave
|
|
40
|
+
|
|
41
|
+
### Newtype Pattern
|
|
42
|
+
|
|
43
|
+
Envuelve un tipo primitivo en un struct de un campo (`struct UserId(Uuid)`).
|
|
44
|
+
Aporta type safety en compilación sin costo en runtime. El compilador rechaza
|
|
45
|
+
pasar un `UserId` donde se espera un `OrderId`, aunque ambos sean `Uuid` internamente.
|
|
46
|
+
|
|
47
|
+
### Typestate Pattern
|
|
48
|
+
|
|
49
|
+
Codifica el estado válido de un objeto en el tipo, no en campos de estado.
|
|
50
|
+
Las transiciones inválidas son errores de compilación, no de runtime.
|
|
51
|
+
|
|
52
|
+
### RAII (Resource Acquisition Is Initialization)
|
|
53
|
+
|
|
54
|
+
El trait `Drop` garantiza que los recursos se liberan cuando el dueño sale de
|
|
55
|
+
scope, incluso en presencia de panic. Conexiones, archivos y locks se cierran
|
|
56
|
+
automáticamente.
|
|
57
|
+
|
|
58
|
+
## Reglas obligatorias
|
|
59
|
+
|
|
60
|
+
### Newtype para todo ID de dominio — nunca Uuid crudo como parámetro
|
|
61
|
+
|
|
62
|
+
Pasar `Uuid` directamente permite confundir IDs de distintas entidades. Un
|
|
63
|
+
newtype con `#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]` y conversión
|
|
64
|
+
desde Uuid cuesta cero en runtime.
|
|
65
|
+
|
|
66
|
+
```rust
|
|
67
|
+
// MAL — nada impide pasar client_id donde se espera order_id
|
|
68
|
+
fn transferir(desde: Uuid, hacia: Uuid, monto: Decimal) { ... }
|
|
69
|
+
|
|
70
|
+
// BIEN — el compilador rechaza el orden equivocado
|
|
71
|
+
fn transferir(desde: CuentaId, hacia: CuentaId, monto: Dinero) { ... }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Implementar From — NUNCA conversiones con unwrap en el sitio de uso
|
|
75
|
+
|
|
76
|
+
`impl From<A> for B` permite `B::from(a)` y habilita el operador `?` para
|
|
77
|
+
`Into`. Centraliza la lógica de conversión y elimina conversiones repetidas.
|
|
78
|
+
|
|
79
|
+
### Cow<str> para funciones que a veces alocan y a veces no
|
|
80
|
+
|
|
81
|
+
`Cow<'a, str>` retorna una referencia cuando el input no necesita modificarse
|
|
82
|
+
y un String cuando sí. Evita alocar siempre o cambiar la firma según el caso.
|
|
83
|
+
|
|
84
|
+
### RefCell solo en contextos single-thread — Mutex en multi-thread
|
|
85
|
+
|
|
86
|
+
`RefCell` paniquea en runtime si hay más de un borrow mutable simultáneo.
|
|
87
|
+
Solo es correcto en código single-thread (sin `Send`). En multi-thread usar `Mutex`.
|
|
88
|
+
|
|
89
|
+
## Patrones recomendados
|
|
90
|
+
|
|
91
|
+
### Newtype con conversiones
|
|
92
|
+
|
|
93
|
+
```rust
|
|
94
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
|
95
|
+
pub struct PedidoId(Uuid);
|
|
96
|
+
|
|
97
|
+
impl PedidoId {
|
|
98
|
+
pub fn nuevo() -> Self { Self(Uuid::new_v4()) }
|
|
99
|
+
pub fn inner(self) -> Uuid { self.0 }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
impl From<Uuid> for PedidoId {
|
|
103
|
+
fn from(id: Uuid) -> Self { Self(id) }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
impl fmt::Display for PedidoId {
|
|
107
|
+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
108
|
+
write!(f, "{}", self.0)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Builder con typestate
|
|
114
|
+
|
|
115
|
+
```rust
|
|
116
|
+
pub struct Borrador;
|
|
117
|
+
pub struct Listo;
|
|
118
|
+
|
|
119
|
+
pub struct PedidoBuilder<Estado> {
|
|
120
|
+
cliente_id: Option<ClienteId>,
|
|
121
|
+
items: Vec<ItemPedido>,
|
|
122
|
+
_estado: PhantomData<Estado>,
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
impl PedidoBuilder<Borrador> {
|
|
126
|
+
pub fn nuevo() -> Self {
|
|
127
|
+
Self { cliente_id: None, items: vec![], _estado: PhantomData }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
pub fn cliente(mut self, id: ClienteId) -> Self {
|
|
131
|
+
self.cliente_id = Some(id);
|
|
132
|
+
self
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
pub fn item(mut self, item: ItemPedido) -> Self {
|
|
136
|
+
self.items.push(item);
|
|
137
|
+
self
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Solo disponible cuando hay cliente Y al menos un item
|
|
141
|
+
pub fn listo(self) -> Result<PedidoBuilder<Listo>, BuildError> {
|
|
142
|
+
if self.cliente_id.is_none() { return Err(BuildError::SinCliente); }
|
|
143
|
+
if self.items.is_empty() { return Err(BuildError::SinItems); }
|
|
144
|
+
Ok(PedidoBuilder { cliente_id: self.cliente_id, items: self.items, _estado: PhantomData })
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
impl PedidoBuilder<Listo> {
|
|
149
|
+
pub fn construir(self) -> Pedido {
|
|
150
|
+
Pedido::new(self.cliente_id.unwrap(), self.items) // safe: typestate garantiza que existe
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### From/Into para conversiones de dominio
|
|
156
|
+
|
|
157
|
+
```rust
|
|
158
|
+
impl From<PedidoRow> for Pedido {
|
|
159
|
+
fn from(row: PedidoRow) -> Self {
|
|
160
|
+
Pedido {
|
|
161
|
+
id: PedidoId::from(row.id),
|
|
162
|
+
cliente_id: ClienteId::from(row.cliente_id),
|
|
163
|
+
total: row.total,
|
|
164
|
+
estado: Estado::from(row.estado_str.as_str()),
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Uso con operador ? en contextos que retornan Result<_, ConversionError>
|
|
170
|
+
impl TryFrom<&str> for Estado {
|
|
171
|
+
type Error = ParseEstadoError;
|
|
172
|
+
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
|
173
|
+
match s {
|
|
174
|
+
"borrador" => Ok(Estado::Borrador),
|
|
175
|
+
"confirmado" => Ok(Estado::Confirmado),
|
|
176
|
+
"cancelado" => Ok(Estado::Cancelado),
|
|
177
|
+
other => Err(ParseEstadoError(other.to_string())),
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### RAII con Drop para recursos
|
|
184
|
+
|
|
185
|
+
```rust
|
|
186
|
+
pub struct ConexionBD {
|
|
187
|
+
conn: Option<PgConnection>,
|
|
188
|
+
pool: Arc<Pool>,
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
impl Drop for ConexionBD {
|
|
192
|
+
fn drop(&mut self) {
|
|
193
|
+
if let Some(conn) = self.conn.take() {
|
|
194
|
+
self.pool.devolver(conn); // se ejecuta incluso en panic
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Iterador custom
|
|
201
|
+
|
|
202
|
+
```rust
|
|
203
|
+
pub struct PaginaIter<'a> {
|
|
204
|
+
items: &'a [Pedido],
|
|
205
|
+
pos: usize,
|
|
206
|
+
tamano_pagina: usize,
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
impl<'a> Iterator for PaginaIter<'a> {
|
|
210
|
+
type Item = &'a [Pedido];
|
|
211
|
+
|
|
212
|
+
fn next(&mut self) -> Option<Self::Item> {
|
|
213
|
+
if self.pos >= self.items.len() { return None; }
|
|
214
|
+
let fin = (self.pos + self.tamano_pagina).min(self.items.len());
|
|
215
|
+
let pagina = &self.items[self.pos..fin];
|
|
216
|
+
self.pos = fin;
|
|
217
|
+
Some(pagina)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Cow para funciones mixtas
|
|
223
|
+
|
|
224
|
+
```rust
|
|
225
|
+
use std::borrow::Cow;
|
|
226
|
+
|
|
227
|
+
fn normalizar_email(email: &str) -> Cow<str> {
|
|
228
|
+
if email.chars().any(|c| c.is_uppercase()) {
|
|
229
|
+
Cow::Owned(email.to_lowercase()) // aloca solo cuando es necesario
|
|
230
|
+
} else {
|
|
231
|
+
Cow::Borrowed(email) // referencia directa sin aloca
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Anti-patrones conocidos
|
|
237
|
+
|
|
238
|
+
### Stringly-typed — strings para conceptos con dominio cerrado
|
|
239
|
+
|
|
240
|
+
```rust
|
|
241
|
+
// MAL — cualquier string es valido en compilacion
|
|
242
|
+
fn cambiar_estado(pedido: &mut Pedido, estado: &str) {
|
|
243
|
+
pedido.estado = estado.to_string(); // "activo", "Activo", "ACTIVO"... todos pasan
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// BIEN — enum exhaustivo
|
|
247
|
+
fn cambiar_estado(pedido: &mut Pedido, estado: EstadoPedido) { ... }
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Clone excesivo para satisfacer al borrow checker
|
|
251
|
+
|
|
252
|
+
```rust
|
|
253
|
+
// MAL — clonar solo para evitar mover
|
|
254
|
+
let nombre = usuario.nombre.clone();
|
|
255
|
+
let respuesta = construir_respuesta(nombre);
|
|
256
|
+
enviar_log(usuario.nombre.clone()); // ya podria haber usado &usuario.nombre
|
|
257
|
+
|
|
258
|
+
// BIEN — restructurar para minimizar clones
|
|
259
|
+
enviar_log(&usuario.nombre);
|
|
260
|
+
let respuesta = construir_respuesta(&usuario.nombre);
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Ignorar Drop al usar ManuallyDrop
|
|
264
|
+
|
|
265
|
+
```rust
|
|
266
|
+
// MAL — ManuallyDrop sin plan de liberacion
|
|
267
|
+
let valor = ManuallyDrop::new(recurso_importante);
|
|
268
|
+
// recurso_importante nunca se libera si no se llama ManuallyDrop::drop
|
|
269
|
+
|
|
270
|
+
// BIEN — Solo ManuallyDrop cuando se transfiere ownership a FFI con
|
|
271
|
+
// documentacion explicita de quien es responsable de liberar
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Checklist de verificación
|
|
275
|
+
|
|
276
|
+
- [ ] Cada ID de dominio es un newtype, no un Uuid/u64 crudo
|
|
277
|
+
- [ ] Builder pattern con typestate cuando hay precondiciones de construcción
|
|
278
|
+
- [ ] From/Into implementado para conversiones entre capas (row -> domain)
|
|
279
|
+
- [ ] TryFrom para conversiones que pueden fallar, no unwrap en el sitio
|
|
280
|
+
- [ ] Drop implementado para structs que manejan recursos externos
|
|
281
|
+
- [ ] Cow<str> en funciones que a veces modifican y a veces no
|
|
282
|
+
- [ ] RefCell solo en single-thread; Mutex en multi-thread
|
|
283
|
+
- [ ] Sin unsafe sin comentario explicando invariante que lo justifica
|
|
284
|
+
|
|
285
|
+
## Gotchas / Errores comunes no obvios
|
|
286
|
+
|
|
287
|
+
**Newtype que implementa `Deref<Target=T>` puede confundirse con `T` en inferencia de tipos**: si `struct UserId(Uuid)` implementa `Deref<Target=Uuid>`, el compilador puede inferir el tipo `Uuid` en contextos donde se espera `UserId`, anulando la protección del newtype. Fix: no implementar `Deref` en newtypes de dominio cuyo propósito es distinguir tipos; si se necesita acceso al inner, exponer un método `fn inner(&self) -> &Uuid`.
|
|
288
|
+
|
|
289
|
+
**Builder con typestate no compila con `Box<dyn Builder<State>>` para builders almacenados dinámicamente**: el typestate usa tipos genéricos como phantom data, lo que hace que diferentes estados del builder sean tipos distintos que no tienen un ancestro común en el type system. Fix: si se necesita almacenar builders dinámicamente, usar un enum en lugar de typestate, o aceptar que el builder con typestate solo funciona en contextos donde el tipo completo es conocido en compile time.
|
|
290
|
+
|
|
291
|
+
**`From<T> for U` no implementa automáticamente `TryFrom<T> for U`**: si se define `From<RawRow> for Entidad`, esto da `Into<Entidad>` automáticamente, pero `TryFrom` no se infiere — hay que implementarlo por separado si la conversión puede fallar. Causa: `From` es infallible por definición. Fix: implementar `TryFrom<RawRow> for Entidad` con error tipado cuando la conversión puede fallar, y usar `From` solo cuando la conversión es garantizada.
|
|
292
|
+
|
|
293
|
+
**`impl Iterator for MiTipo` con `type Item = &'a T` requiere lifetime explícito en la implementación**: si el iterador retorna referencias a datos que viven en la colección que itera, el lifetime debe ser explícito tanto en la struct del iterador como en el `impl`. El compilador puede sugerir lifetimes incorrectos en mensajes de error. Fix: anotar el lifetime de la referencia al dato origen en la struct del iterador: `struct Iter<'a, T> { inner: &'a [T], pos: usize }`.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
*Skill creado con swl:crear-skill el 2026-03-31. Versión 1.0.0.*
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-testing
|
|
3
|
+
description: >
|
|
4
|
+
Testing Rust con rstest, proptest, mockall y cargo-llvm-cov. Cubre tests
|
|
5
|
+
inline con #[cfg(test)], async tests con tokio::test, integration tests
|
|
6
|
+
y doc tests. Cargar cuando se escriban tests Rust o se configure cobertura.
|
|
7
|
+
version: "1.0.0"
|
|
8
|
+
herramientasPermitidas: [Read, Grep]
|
|
9
|
+
exclusiones:
|
|
10
|
+
- "No cargar para implementar el código Rust de producción — primero implementar con `rust-experto`, luego escribir tests."
|
|
11
|
+
- "No cargar para errores de compilación Rust en los tests — para build errors cargar `build-errors-rust`."
|
|
12
|
+
- "No cargar para benchmarks avanzados con criterion o divan — esas herramientas requieren configuración específica no cubierta en este skill de testing estándar."
|
|
13
|
+
- "No cargar para tests de otros lenguajes — este skill cubre el ecosistema de testing de Rust específicamente."
|
|
14
|
+
evolvable: true # default para skill estandar
|
|
15
|
+
---
|
|
16
|
+
# Rust Testing — rstest, proptest y Cobertura
|
|
17
|
+
|
|
18
|
+
Cubre el ecosistema de testing Rust: tests inline, rstest para fixtures y
|
|
19
|
+
parametrizados, proptest para property-based testing, mockall para mocks de
|
|
20
|
+
traits, async tests con tokio::test y cargo-llvm-cov para cobertura.
|
|
21
|
+
|
|
22
|
+
## Cuándo cargar este skill
|
|
23
|
+
|
|
24
|
+
Invoca `Skill("rust-testing")` cuando:
|
|
25
|
+
|
|
26
|
+
- Se escriban tests unitarios o de integración en Rust
|
|
27
|
+
- Se use rstest para fixtures compartidos o tests parametrizados
|
|
28
|
+
- Se implemente property-based testing con proptest
|
|
29
|
+
- Se mocken traits con mockall
|
|
30
|
+
- Se configure cobertura con cargo-llvm-cov
|
|
31
|
+
|
|
32
|
+
## Cuándo NO cargar
|
|
33
|
+
|
|
34
|
+
- El código Rust de producción aún no está implementado — primero implementar con `rust-experto`, luego escribir tests.
|
|
35
|
+
- Los errores son de compilación Rust en los archivos de test — cargar `build-errors-rust`.
|
|
36
|
+
- La pregunta es sobre benchmarks avanzados con criterion o divan — esas herramientas tienen su propio flujo de configuración no cubierto en este skill.
|
|
37
|
+
- Los tests son de otro lenguaje — este skill cubre el ecosistema de testing específico de Rust.
|
|
38
|
+
|
|
39
|
+
## Conceptos clave
|
|
40
|
+
|
|
41
|
+
### Tests inline con #[cfg(test)]
|
|
42
|
+
|
|
43
|
+
El módulo `#[cfg(test)]` en el mismo archivo que el código bajo prueba tiene
|
|
44
|
+
acceso a items privados. Es el lugar correcto para tests unitarios de implementación.
|
|
45
|
+
Los integration tests en `tests/` prueban solo la API pública del crate.
|
|
46
|
+
|
|
47
|
+
### rstest
|
|
48
|
+
|
|
49
|
+
`rstest` permite fixtures inyectados automáticamente y casos de prueba declarativos
|
|
50
|
+
con `#[rstest]` y `#[case(...)]`. Reduce el boilerplate de setup compartido.
|
|
51
|
+
|
|
52
|
+
### proptest
|
|
53
|
+
|
|
54
|
+
Genera inputs aleatorios que satisfacen una estrategia y ejecuta el test cientos
|
|
55
|
+
de veces. Encoge (shrinks) el input fallido al caso más pequeño que reproduce el fallo.
|
|
56
|
+
|
|
57
|
+
## Reglas obligatorias
|
|
58
|
+
|
|
59
|
+
### assert_eq! con mensaje — facilita debugging
|
|
60
|
+
|
|
61
|
+
Siempre agregar un mensaje de contexto en assertions no triviales:
|
|
62
|
+
`assert_eq!(got, want, "al calcular descuento con precio={}", precio)`
|
|
63
|
+
|
|
64
|
+
### #[tokio::test] para tests async — no block_on manual
|
|
65
|
+
|
|
66
|
+
```rust
|
|
67
|
+
// MAL
|
|
68
|
+
#[test]
|
|
69
|
+
fn test_crear_pedido() {
|
|
70
|
+
let result = tokio::runtime::Runtime::new()
|
|
71
|
+
.unwrap()
|
|
72
|
+
.block_on(crear_pedido(req));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// BIEN
|
|
76
|
+
#[tokio::test]
|
|
77
|
+
async fn test_crear_pedido() {
|
|
78
|
+
let result = crear_pedido(req).await;
|
|
79
|
+
assert!(result.is_ok());
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Integration tests usan solo API pública del crate
|
|
84
|
+
|
|
85
|
+
Los tests en `tests/` no importan módulos internos con `use mi_crate::internal::`.
|
|
86
|
+
Si necesitas acceder a internos, el test debe estar en un módulo `#[cfg(test)]`.
|
|
87
|
+
|
|
88
|
+
### mockall solo en el módulo de test — no en producción
|
|
89
|
+
|
|
90
|
+
Los mocks generados por `#[automock]` aumentan el binario. El atributo
|
|
91
|
+
`#[cfg_attr(test, automock)]` aplica la macro solo al compilar tests.
|
|
92
|
+
|
|
93
|
+
## Patrones recomendados
|
|
94
|
+
|
|
95
|
+
### Test unitario inline con acceso a privados
|
|
96
|
+
|
|
97
|
+
```rust
|
|
98
|
+
// src/pedido.rs
|
|
99
|
+
pub struct Pedido {
|
|
100
|
+
id: Uuid,
|
|
101
|
+
estado: Estado,
|
|
102
|
+
items: Vec<Item>,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
impl Pedido {
|
|
106
|
+
fn calcular_subtotal(&self) -> Decimal { /* ... */ }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
#[cfg(test)]
|
|
110
|
+
mod tests {
|
|
111
|
+
use super::*; // accede a calcular_subtotal aunque sea privada
|
|
112
|
+
|
|
113
|
+
#[test]
|
|
114
|
+
fn subtotal_suma_precio_por_cantidad() {
|
|
115
|
+
let pedido = Pedido {
|
|
116
|
+
id: Uuid::new_v4(),
|
|
117
|
+
estado: Estado::Borrador,
|
|
118
|
+
items: vec![
|
|
119
|
+
Item::new(Decimal::new(100, 0), 2),
|
|
120
|
+
Item::new(Decimal::new(50, 0), 1),
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
assert_eq!(
|
|
124
|
+
pedido.calcular_subtotal(),
|
|
125
|
+
Decimal::new(250, 0),
|
|
126
|
+
"subtotal debe ser suma de precio*cantidad"
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### rstest con fixtures y casos parametrizados
|
|
133
|
+
|
|
134
|
+
```rust
|
|
135
|
+
use rstest::*;
|
|
136
|
+
|
|
137
|
+
#[fixture]
|
|
138
|
+
fn pedido_borrador() -> Pedido {
|
|
139
|
+
Pedido::nuevo(ClienteId::new_v4())
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#[fixture]
|
|
143
|
+
fn pedido_confirmado(pedido_borrador: Pedido) -> Pedido {
|
|
144
|
+
pedido_borrador.confirmar().unwrap()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#[rstest]
|
|
148
|
+
#[case(Estado::Borrador, true)]
|
|
149
|
+
#[case(Estado::Confirmado, false)]
|
|
150
|
+
#[case(Estado::Cancelado, false)]
|
|
151
|
+
fn puede_cancelar_solo_en_estado_borrador(
|
|
152
|
+
#[case] estado: Estado,
|
|
153
|
+
#[case] esperado: bool,
|
|
154
|
+
pedido_borrador: Pedido,
|
|
155
|
+
) {
|
|
156
|
+
let pedido = pedido_borrador.con_estado(estado);
|
|
157
|
+
assert_eq!(pedido.puede_cancelar(), esperado);
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### proptest para invariantes de dominio
|
|
162
|
+
|
|
163
|
+
```rust
|
|
164
|
+
use proptest::prelude::*;
|
|
165
|
+
|
|
166
|
+
proptest! {
|
|
167
|
+
#[test]
|
|
168
|
+
fn descuento_nunca_supera_precio(
|
|
169
|
+
precio in 0.01f64..10_000.0,
|
|
170
|
+
porcentaje in 0u8..=100,
|
|
171
|
+
) {
|
|
172
|
+
let descuento = calcular_descuento(precio, porcentaje);
|
|
173
|
+
prop_assert!(
|
|
174
|
+
descuento <= precio,
|
|
175
|
+
"descuento {} supero precio {}", descuento, precio
|
|
176
|
+
);
|
|
177
|
+
prop_assert!(descuento >= 0.0);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### mockall para traits
|
|
183
|
+
|
|
184
|
+
```rust
|
|
185
|
+
use mockall::automock;
|
|
186
|
+
|
|
187
|
+
#[cfg_attr(test, automock)]
|
|
188
|
+
pub trait PedidoRepository: Send + Sync {
|
|
189
|
+
async fn obtener(&self, id: Uuid) -> Result<Pedido, AppError>;
|
|
190
|
+
async fn guardar(&self, pedido: &Pedido) -> Result<(), AppError>;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
#[cfg(test)]
|
|
194
|
+
mod tests {
|
|
195
|
+
use super::*;
|
|
196
|
+
use mockall::predicate::*;
|
|
197
|
+
|
|
198
|
+
#[tokio::test]
|
|
199
|
+
async fn service_retorna_error_cuando_repo_falla() {
|
|
200
|
+
let mut mock = MockPedidoRepository::new();
|
|
201
|
+
mock.expect_obtener()
|
|
202
|
+
.with(eq(id_prueba()))
|
|
203
|
+
.returning(|_| Err(AppError::NotFound("no existe".into())));
|
|
204
|
+
|
|
205
|
+
let service = PedidoService::new(Arc::new(mock));
|
|
206
|
+
let resultado = service.obtener(id_prueba()).await;
|
|
207
|
+
|
|
208
|
+
assert!(matches!(resultado, Err(AppError::NotFound(_))));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### assert_matches! para pattern matching en assertions
|
|
214
|
+
|
|
215
|
+
```rust
|
|
216
|
+
use std::assert_matches::assert_matches;
|
|
217
|
+
|
|
218
|
+
let resultado = service.crear(req_invalido).await;
|
|
219
|
+
assert_matches!(
|
|
220
|
+
resultado,
|
|
221
|
+
Err(AppError::Validation(msg)) if msg.contains("cliente_id")
|
|
222
|
+
);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Configurar cargo-llvm-cov
|
|
226
|
+
|
|
227
|
+
```toml
|
|
228
|
+
# .cargo/config.toml
|
|
229
|
+
[alias]
|
|
230
|
+
cov = "llvm-cov --lcov --output-path lcov.info"
|
|
231
|
+
cov-html = "llvm-cov --html"
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info
|
|
236
|
+
# Verificar cobertura mínima del 80%
|
|
237
|
+
cargo llvm-cov --all-features --workspace --fail-under-lines 80
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Anti-patrones conocidos
|
|
241
|
+
|
|
242
|
+
### unwrap() en tests sin mensaje de contexto
|
|
243
|
+
|
|
244
|
+
```rust
|
|
245
|
+
// MAL — panic con mensaje generico "called unwrap on None"
|
|
246
|
+
let pedido = repo.obtener(id).await.unwrap();
|
|
247
|
+
|
|
248
|
+
// BIEN — mensaje que indica que estaba probando
|
|
249
|
+
let pedido = repo.obtener(id).await
|
|
250
|
+
.expect("deberia encontrar el pedido insertado en el fixture");
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Tests que dependen de orden de ejecución
|
|
254
|
+
|
|
255
|
+
```rust
|
|
256
|
+
// MAL — modifica estado global, falla si otro test corre primero
|
|
257
|
+
static CONTADOR: AtomicU32 = AtomicU32::new(0);
|
|
258
|
+
#[test]
|
|
259
|
+
fn test_a() { CONTADOR.fetch_add(1, Ordering::SeqCst); }
|
|
260
|
+
#[test]
|
|
261
|
+
fn test_b() { assert_eq!(CONTADOR.load(Ordering::SeqCst), 1); } // fragil
|
|
262
|
+
|
|
263
|
+
// BIEN — cada test es autocontenido
|
|
264
|
+
#[test]
|
|
265
|
+
fn test_b() {
|
|
266
|
+
let mut contador = 0u32;
|
|
267
|
+
incrementar(&mut contador);
|
|
268
|
+
assert_eq!(contador, 1);
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Doc tests para ejemplos no compilables
|
|
273
|
+
|
|
274
|
+
```rust
|
|
275
|
+
/// Calcula el descuento.
|
|
276
|
+
///
|
|
277
|
+
/// # Examples
|
|
278
|
+
/// ```no_run
|
|
279
|
+
/// // MAL — no_run significa que nunca se verifica que compile
|
|
280
|
+
/// let d = calcular_descuento(100.0, 10);
|
|
281
|
+
/// ```
|
|
282
|
+
///
|
|
283
|
+
/// ```
|
|
284
|
+
/// // BIEN — el ejemplo compila y se ejecuta en cargo test
|
|
285
|
+
/// use mi_crate::calcular_descuento;
|
|
286
|
+
/// assert_eq!(calcular_descuento(100.0, 10), 90.0);
|
|
287
|
+
/// ```
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Checklist de verificación
|
|
291
|
+
|
|
292
|
+
- [ ] Tests unitarios en módulo #[cfg(test)] en el mismo archivo
|
|
293
|
+
- [ ] Tests async usan #[tokio::test], no block_on manual
|
|
294
|
+
- [ ] rstest para fixtures compartidos y casos parametrizados
|
|
295
|
+
- [ ] proptest para invariantes de dominio con inputs generados
|
|
296
|
+
- [ ] mockall con #[cfg_attr(test, automock)], no en código de producción
|
|
297
|
+
- [ ] assert_eq! con mensaje descriptivo en assertions no triviales
|
|
298
|
+
- [ ] cargo-llvm-cov configurado con umbral mínimo del 80%
|
|
299
|
+
|
|
300
|
+
## Gotchas / Errores comunes no obvios
|
|
301
|
+
|
|
302
|
+
**`#[tokio::test]` sin `flavor = "multi_thread"` limita el paralelismo en tests async**: por defecto `#[tokio::test]` usa el runtime current-thread — si un test lanza múltiples tareas que esperan entre sí, puede producir un deadlock en el runtime single-thread que no ocurre en producción. Fix: usar `#[tokio::test(flavor = "multi_thread", worker_threads = 2)]` para tests que simulan concurrencia real.
|
|
303
|
+
|
|
304
|
+
**`mockall::automock` en un trait con métodos de retorno de tipo genérico requiere declarar el tipo concreto al configurar la expectativa**: `mock.expect_obtener().returning(|| vec![...])` puede fallar si el compilador no infiere el tipo de retorno genérico. Fix: especificar el tipo explícitamente en el `returning` con turbofish si es necesario, o definir un tipo concreto de retorno en el trait en lugar de genérico.
|
|
305
|
+
|
|
306
|
+
**Tests de integración en `tests/` no tienen acceso a funciones privadas o internas del crate**: si el test necesita inspeccionar estado interno que no es `pub`, el test de integración no puede hacerlo directamente. Causa: `tests/` es un crate separado que solo ve la API pública. Fix: mover el test a un módulo `#[cfg(test)]` inline en el módulo que necesita inspeccionar, o exponer una función de test pública con `#[doc(hidden)] pub fn __test_only_estado(&self)`.
|
|
307
|
+
|
|
308
|
+
**`proptest!` genera casos aleatorios que pueden no reproducirse sin la semilla**: cuando proptest encuentra un contraejemplo, lo imprime y lo guarda en `.proptest-regressions/`. Si el archivo no se commitea, el CI puede pasar sin el contraejemplo pero el bug persiste. Fix: committear el directorio `.proptest-regressions/` al repositorio para que el CI reproduzca los casos que fallaron en desarrollo.
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
*Skill creado con swl:crear-skill el 2026-03-31. Versión 1.0.0.*
|