@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,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schemas/skill-evals.schema.json",
|
|
3
|
+
"skill_name": "patrones-python",
|
|
4
|
+
"artifact_type": "skill",
|
|
5
|
+
"schema_version": 1,
|
|
6
|
+
"description": "Evals para patrones-python — type hints, dataclasses, context managers, patrones modernos.",
|
|
7
|
+
"evals": [
|
|
8
|
+
{
|
|
9
|
+
"id": 0,
|
|
10
|
+
"prompt": "Dame la firma mínima y strict de una función que toma un dict de config y retorna una lista tipada, usando type hints modernos (Python 3.10+).",
|
|
11
|
+
"files": [],
|
|
12
|
+
"expectations": [
|
|
13
|
+
"Usa `dict[str, X]` (no `Dict[str, X]` del typing antiguo).",
|
|
14
|
+
"Usa `list[Y]` (no `List[Y]`).",
|
|
15
|
+
"Tipos específicos (no `Any` genérico).",
|
|
16
|
+
"NO importa `Dict`, `List` de typing (usar builtins desde Python 3.9+)."
|
|
17
|
+
],
|
|
18
|
+
"tags": ["type-hints"],
|
|
19
|
+
"weight": 1.5
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "anti-pattern-mutable-default",
|
|
23
|
+
"prompt": "¿Qué está mal con `def f(items: list = []): ...`?",
|
|
24
|
+
"files": [],
|
|
25
|
+
"expectations": [
|
|
26
|
+
"La respuesta identifica el bug de default mutable compartido entre llamadas.",
|
|
27
|
+
"La respuesta da la solución: `items: list | None = None` y `if items is None: items = []` dentro del cuerpo."
|
|
28
|
+
],
|
|
29
|
+
"grading_guidance": "Failure si no reconoce el bug.",
|
|
30
|
+
"tags": ["anti-pattern"],
|
|
31
|
+
"weight": 1.5
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "context-manager",
|
|
35
|
+
"prompt": "Abrir un archivo y procesar su contenido — snippet paste-ready.",
|
|
36
|
+
"files": [],
|
|
37
|
+
"expectations": [
|
|
38
|
+
"Usa `with open(...) as f:` (context manager).",
|
|
39
|
+
"Especifica encoding explícito (`encoding='utf-8'`).",
|
|
40
|
+
"NO usa `f = open(...)` sin cleanup."
|
|
41
|
+
],
|
|
42
|
+
"tags": ["primary-flow"]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "dataclass-vs-dict",
|
|
46
|
+
"prompt": "Tengo datos con 4 campos fijos. ¿Uso dict o dataclass?",
|
|
47
|
+
"files": [],
|
|
48
|
+
"expectations": [
|
|
49
|
+
"La respuesta recomienda dataclass (o TypedDict/Pydantic según uso).",
|
|
50
|
+
"La respuesta explica: type safety, autocompletado, immutabilidad con `frozen=True`.",
|
|
51
|
+
"Cita el beneficio sobre dict: errores de llave detectados por el type checker."
|
|
52
|
+
],
|
|
53
|
+
"tags": ["design"]
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
# Patrones avanzados — Python
|
|
2
|
+
|
|
3
|
+
Recurso de profundidad cargado bajo demanda desde `SKILL.md`. Contiene 7 patrones
|
|
4
|
+
que aparecen al integrar Python con pipelines reales: conversores de documentos,
|
|
5
|
+
clientes heterogéneos, cachés determinísticos, soft imports, detectores de
|
|
6
|
+
texto y duplicación deliberada de lógica.
|
|
7
|
+
|
|
8
|
+
## Índice
|
|
9
|
+
|
|
10
|
+
1. [Normalizadores: colapsar al formato canónico del proyecto](#normalizadores)
|
|
11
|
+
2. [kwargs opcionales entre clientes hermanos: try/except TypeError](#kwargs-opcionales)
|
|
12
|
+
3. [Caché content-addressable por SHA256](#cache-sha256)
|
|
13
|
+
4. [F401 en archivos con soft imports es intencional](#f401-soft-imports)
|
|
14
|
+
5. [Detectores regex multi-pattern: extender scope sin refinar](#regex-multi-pattern)
|
|
15
|
+
6. [Tracer/replicador paralelo del motor: marca SYNC obligatoria](#tracer-sync)
|
|
16
|
+
7. [Fixtures con datos pre-procesados NO ejercen el path crudo](#fixtures-crudos)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<a id="normalizadores"></a>
|
|
21
|
+
## 1. Normalizadores: colapsar al formato canónico del PROYECTO, no al estándar genérico
|
|
22
|
+
|
|
23
|
+
### SIEMPRE: el normalizador debe conocer la convención del proyecto
|
|
24
|
+
|
|
25
|
+
**Cuándo aplicar**: cuando un módulo externo (MarkItDown, Pandoc, mammoth, pdfminer) produce artefactos de conversión y hay que limpiarlos antes del pipeline interno.
|
|
26
|
+
|
|
27
|
+
**Problema**: es tentador colapsar los artefactos al formato "más estándar" según la spec de CommonMark / JSON / el estándar de turno. Pero si el proyecto ya tiene una convención distinta (ej. puntuación FUERA del bold en vez de dentro), el normalizador debe colapsar a ESA convención, no al genérico.
|
|
28
|
+
|
|
29
|
+
**Regla**: antes de escribir un normalizador, verificar la convención real del proyecto en docs internos o en un fixture "canónico" existente. Si la convención del proyecto contradice la intuición genérica, registrar en el docstring del normalizador POR QUÉ se eligió esa dirección.
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
# MAL — colapsa al estándar genérico sin verificar la convención del proyecto
|
|
33
|
+
def _normalizar(texto: str) -> str:
|
|
34
|
+
# "Mover puntuación al interior del bold" (parece "más correcto")
|
|
35
|
+
return re.sub(r"\*\*([^*]+?)\*\*([:;.,])", r"**\1\2**", texto)
|
|
36
|
+
# Resultado: `**ACTIVIDAD**:` → `**ACTIVIDAD:**` ← pero el proyecto usa el primero
|
|
37
|
+
|
|
38
|
+
# BIEN — conoce la convención: "puntuación terminal FUERA del bold"
|
|
39
|
+
def _normalizar(texto: str) -> str:
|
|
40
|
+
"""Normaliza a la convención del proyecto: puntuación fuera del bold.
|
|
41
|
+
|
|
42
|
+
CommonMark genérico prefiere mover la puntuación al interior del bold,
|
|
43
|
+
pero algunos proyectos adoptan la convención opuesta para preservar
|
|
44
|
+
la semántica visual del documento de origen (DOCX, PDF). Cubrir el
|
|
45
|
+
caso con un test de ground truth antes de modificar el regex.
|
|
46
|
+
"""
|
|
47
|
+
# Artefacto `**ACTIVIDAD****:**` → `**ACTIVIDAD**:` (puntuación fuera)
|
|
48
|
+
return re.sub(
|
|
49
|
+
r"\*\*([^\n*]+?)\*{2,}([:;,.!?\-—)])\*{2,}",
|
|
50
|
+
r"**\1**\2",
|
|
51
|
+
texto,
|
|
52
|
+
)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Verificación previa obligatoria**: en una PR que introduzca un normalizador, agregar un test con la convención canónica del proyecto como ground truth. Si no existe fixture, preguntarle al autor del proyecto antes de inventar la dirección.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
<a id="kwargs-opcionales"></a>
|
|
60
|
+
## 2. kwargs opcionales entre clientes hermanos: try/except TypeError
|
|
61
|
+
|
|
62
|
+
### Patrón: propagar kwargs a implementaciones heterogéneas con degradación silenciosa
|
|
63
|
+
|
|
64
|
+
**Cuándo aplicar**: cuando dos o más clientes implementan la misma interfaz de alto nivel (ej. `OllamaClient.generate()` y `NIMClient.generate()`) pero uno acepta un kwarg nuevo y el otro aún no. Migración incremental sin versionar la interfaz.
|
|
65
|
+
|
|
66
|
+
**Problema**: si el wrapper de alto nivel pasa siempre el kwarg, falla con `TypeError` en el cliente que aún no lo acepta. Si el wrapper nunca lo pasa, los clientes que sí lo aceptan pierden la funcionalidad.
|
|
67
|
+
|
|
68
|
+
**Solución idiomática**: crear la coroutine (o call sync) dentro de `try`; capturar `TypeError` solo cuando ocurre al CONSTRUIR la llamada (signature mismatch); en el `except` re-llamar sin el kwarg.
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
# BIEN — degradación silenciosa compatible con clientes heterogéneos
|
|
72
|
+
async def llamar_con_timeout_opcional(cliente, modelo, prompt, timeout_s):
|
|
73
|
+
try:
|
|
74
|
+
# Cliente moderno (acepta `timeout` kwarg)
|
|
75
|
+
call = cliente.generate(model=modelo, prompt=prompt, timeout=timeout_s)
|
|
76
|
+
except TypeError:
|
|
77
|
+
# Cliente legacy (no acepta `timeout`); fallback silencioso
|
|
78
|
+
call = cliente.generate(model=modelo, prompt=prompt)
|
|
79
|
+
return await asyncio.wait_for(call, timeout=timeout_s)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Detalle importante para async**: en `async def f(**kwargs)` los kwargs se aceptan siempre. El `TypeError` solo ocurre con signature fija (`async def f(model, prompt, ...)`) y se lanza en la creación de la coroutine, ANTES del `await`. Probar con mocks de signature fija (no `MagicMock(**kwargs)`).
|
|
83
|
+
|
|
84
|
+
**Aplicabilidad**: migraciones de librerías incrementales, plugins con versiones heterogéneas, strategy pattern donde las implementaciones evolucionan a distinto ritmo.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
<a id="cache-sha256"></a>
|
|
89
|
+
## 3. Caché content-addressable por SHA256 para llamadas determinísticas costosas
|
|
90
|
+
|
|
91
|
+
### Patrón
|
|
92
|
+
|
|
93
|
+
Cuando una función pura (mismo input → mismo output) es costosa (>1 s, llamada
|
|
94
|
+
externa, IO pesado) y se invoca repetidamente con la misma entrada (pipelines
|
|
95
|
+
de ingesta, suites E2E, recompilación incremental), cachear el resultado por
|
|
96
|
+
el **SHA256 del contenido** del input convierte re-ejecuciones en operaciones
|
|
97
|
+
prácticamente gratuitas y hace el pipeline resumible.
|
|
98
|
+
|
|
99
|
+
### Por qué SHA256 del contenido y no `(path, mtime, size)`
|
|
100
|
+
|
|
101
|
+
- `mtime` se rompe al copiar archivos entre sistemas (rsync, git checkout).
|
|
102
|
+
- `size` colisiona trivialmente con archivos distintos del mismo tamaño.
|
|
103
|
+
- `path` cambia al reorganizar el dataset.
|
|
104
|
+
|
|
105
|
+
El SHA256 del **contenido** identifica la entrada de forma reproducible aunque
|
|
106
|
+
se mueva, renombre o clone.
|
|
107
|
+
|
|
108
|
+
### Implementación canónica
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
import hashlib
|
|
112
|
+
import os
|
|
113
|
+
from pathlib import Path
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _flag_off(env_var: str) -> bool:
|
|
117
|
+
"""True si la env var está en {1, true, yes, on} (case-insensitive)."""
|
|
118
|
+
return os.environ.get(env_var, "").lower() in {"1", "true", "yes", "on"}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def sha256_bytes(contenido: bytes) -> str:
|
|
122
|
+
return hashlib.sha256(contenido).hexdigest()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def sha256_archivo(ruta: Path) -> str:
|
|
126
|
+
"""SHA256 del contenido completo en bloques de 64KB."""
|
|
127
|
+
h = hashlib.sha256()
|
|
128
|
+
with ruta.open("rb") as f:
|
|
129
|
+
for chunk in iter(lambda: f.read(65536), b""):
|
|
130
|
+
h.update(chunk)
|
|
131
|
+
return h.hexdigest()
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def procesar_con_cache(
|
|
135
|
+
contenido: bytes,
|
|
136
|
+
dir_cache: Path,
|
|
137
|
+
procesar,
|
|
138
|
+
*,
|
|
139
|
+
bypass_env: str = "CACHE_OFF",
|
|
140
|
+
dimension: str | None = None,
|
|
141
|
+
) -> str:
|
|
142
|
+
"""Ejecuta `procesar(contenido)` solo si el resultado no está en caché.
|
|
143
|
+
|
|
144
|
+
Layout en disco con sharding de 2 chars: `dir_cache/[dim/]ab/abcdef...txt`.
|
|
145
|
+
El sharding evita carpetas con 10k+ archivos en NTFS/ext4.
|
|
146
|
+
"""
|
|
147
|
+
sha = sha256_bytes(contenido)
|
|
148
|
+
base = dir_cache if dimension is None else dir_cache / dimension
|
|
149
|
+
ruta_cache = base / sha[:2] / f"{sha}.txt"
|
|
150
|
+
|
|
151
|
+
if ruta_cache.exists() and ruta_cache.stat().st_size > 0 and not _flag_off(bypass_env):
|
|
152
|
+
return ruta_cache.read_text(encoding="utf-8")
|
|
153
|
+
|
|
154
|
+
# Recalcular (operación costosa: OCR, LLM, transcripción, build, etc.)
|
|
155
|
+
resultado = procesar(contenido)
|
|
156
|
+
|
|
157
|
+
# Escritura atómica: temp + rename para evitar entradas parciales por kill
|
|
158
|
+
ruta_cache.parent.mkdir(parents=True, exist_ok=True)
|
|
159
|
+
tmp = ruta_cache.with_suffix(".tmp")
|
|
160
|
+
tmp.write_text(resultado, encoding="utf-8")
|
|
161
|
+
tmp.rename(ruta_cache)
|
|
162
|
+
|
|
163
|
+
return resultado
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Reglas de diseño
|
|
167
|
+
|
|
168
|
+
- **Sharding de 2 chars** (`{sha[:2]}/{sha}.txt`) evita degradación del filesystem
|
|
169
|
+
cuando el caché crece a decenas de miles de entradas (NTFS, ext4, APFS).
|
|
170
|
+
- **Un directorio por tipo de operación**: `cache/ocr/`, `cache/vision/`,
|
|
171
|
+
`cache/transcripcion/`. Mezclar tipos hace imposible invalidar uno solo.
|
|
172
|
+
- **Escritura atómica obligatoria**: `tmp → rename` previene que un kill del proceso
|
|
173
|
+
deje entradas parciales que se interpretan como éxito en la próxima corrida.
|
|
174
|
+
- **Verificar tamaño > 0 al leer**: archivos de 0 bytes son ejecuciones abortadas,
|
|
175
|
+
no "resultado vacío válido".
|
|
176
|
+
- **Bypass por variable de entorno** (`CACHE_OFF=1` aceptando `1/true/yes/on`):
|
|
177
|
+
crítico para tests que validan el procesador real, no el caché. Sin bypass,
|
|
178
|
+
imposible reproducir bugs del extractor real durante pruebas.
|
|
179
|
+
- **Key multi-dimensión cuando aplica**: si la función es determinística sobre
|
|
180
|
+
`(input, modelo)` —caso típico de síntesis LLM con distinto modelo— usar el
|
|
181
|
+
parámetro `dimension` para particionar el caché:
|
|
182
|
+
`cache/sintesis/{modelo_safe}/{sha[:2]}/{sha}.txt`. Sin esto, cambiar de modelo
|
|
183
|
+
devuelve resultados del modelo viejo con semántica nueva.
|
|
184
|
+
- **Versionar el caché cuando cambia el procesamiento**: si actualizas el modelo de
|
|
185
|
+
OCR o la versión del prompt LLM, bumpear `dimension` (`v1` → `v2`) o invalidar
|
|
186
|
+
el directorio completo.
|
|
187
|
+
- **No cachear errores**: si `procesar()` lanza excepción, el caché queda vacío
|
|
188
|
+
y la siguiente corrida reintenta. Cachear el error convierte errores transitorios
|
|
189
|
+
en permanentes.
|
|
190
|
+
- **Idempotencia natural**: la escritura siempre puede sobreescribir porque el SHA
|
|
191
|
+
garantiza mismo contenido por construcción. No requiere lock entre procesos.
|
|
192
|
+
|
|
193
|
+
### Tests obligatorios
|
|
194
|
+
|
|
195
|
+
Toda implementación de caché content-addressable debe cubrir:
|
|
196
|
+
|
|
197
|
+
1. **Roundtrip write→read**: invocar dos veces con mismo input verifica que
|
|
198
|
+
la segunda lectura no llama al procesador (mock con counter).
|
|
199
|
+
2. **Bypass por flag**: con `CACHE_OFF=1` siempre llama al procesador aunque exista entrada.
|
|
200
|
+
3. **Keys distintas para inputs distintos**: dos inputs con SHA distinto no se pisan.
|
|
201
|
+
4. **Fixture aislado**: `monkeypatch.setenv("CACHE_DIR", str(tmp_path))` evita
|
|
202
|
+
contaminación entre tests.
|
|
203
|
+
5. **Atomicidad**: simular kill durante escritura (interrupción del `tmp.write_text`)
|
|
204
|
+
y verificar que la siguiente corrida no lee un archivo parcial.
|
|
205
|
+
|
|
206
|
+
### Aplicabilidad
|
|
207
|
+
|
|
208
|
+
- Pipelines de ingesta de documentos (PDF → texto, imagen → OCR, audio → transcripción).
|
|
209
|
+
- Extracción con LLM costoso (vision, clasificación, extracción estructurada).
|
|
210
|
+
- Suites E2E donde el dataset es fijo y se ejecutan repetidamente —típicamente
|
|
211
|
+
reduce el tiempo de la corrida en 70-90% si la función cacheada domina.
|
|
212
|
+
- Compilaciones incrementales (aunque los build systems ya tienen este patrón).
|
|
213
|
+
- Deduplicación en walkers resumables (ver `testing-python`: "tests de
|
|
214
|
+
idempotencia requieren 2 ejecuciones + diff").
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
<a id="f401-soft-imports"></a>
|
|
219
|
+
## 4. F401 en archivos con soft imports es intencional, no ruido
|
|
220
|
+
|
|
221
|
+
### Contexto
|
|
222
|
+
|
|
223
|
+
`ruff --select=F401` (y `flake8 --select=F401`) reportan "imported but unused"
|
|
224
|
+
cuando un módulo se importa pero no se usa. En archivos con **soft imports**
|
|
225
|
+
(intentar importar una dependencia opcional dentro de `try/except ImportError`)
|
|
226
|
+
el import **debe quedarse** aunque lint lo marque como no usado — es parte del
|
|
227
|
+
patrón de detección de disponibilidad.
|
|
228
|
+
|
|
229
|
+
### Patrón de soft import canónico
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
# El módulo puede funcionar con o sin la dependencia opcional.
|
|
233
|
+
# La presencia del símbolo habilita un code path; su ausencia cambia al fallback.
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
from markitdown import MarkItDown # noqa: F401 — soft import
|
|
237
|
+
_MARKITDOWN_DISPONIBLE = True
|
|
238
|
+
except ImportError:
|
|
239
|
+
_MARKITDOWN_DISPONIBLE = False
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def extraer_texto(ruta: Path) -> str:
|
|
243
|
+
if _MARKITDOWN_DISPONIBLE:
|
|
244
|
+
from markitdown import MarkItDown # re-import local, ya sabemos que existe
|
|
245
|
+
return MarkItDown().convert(str(ruta)).text_content
|
|
246
|
+
# Fallback: usar parser básico
|
|
247
|
+
return _extraer_con_parser_basico(ruta)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Regla
|
|
251
|
+
|
|
252
|
+
- Agregar `# noqa: F401` en la línea del import top-level dentro del `try`.
|
|
253
|
+
- Alternativa: configurar `ruff.toml` / `pyproject.toml` con `per-file-ignores` para los archivos de soft import si son muchos:
|
|
254
|
+
```toml
|
|
255
|
+
[tool.ruff.per-file-ignores]
|
|
256
|
+
"core/adapters/*.py" = ["F401"] # todos los adapters usan soft imports
|
|
257
|
+
```
|
|
258
|
+
- NO importar dentro del `try` sin usar: usar el símbolo (`MarkItDown`) como sonda de disponibilidad es el patrón correcto; el warning F401 es el ruido.
|
|
259
|
+
- NO reemplazar con `importlib.util.find_spec("markitdown")` salvo que la librería tenga side effects al importar — `find_spec` no valida que la versión instalada exponga los símbolos esperados.
|
|
260
|
+
|
|
261
|
+
### Anti-patrón
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
# MAL — el F401 se "soluciona" pero la detección se rompe
|
|
265
|
+
try:
|
|
266
|
+
import markitdown # noqa — "no se usa, pero quiero saber si está"
|
|
267
|
+
_DISPONIBLE = True
|
|
268
|
+
except ImportError:
|
|
269
|
+
_DISPONIBLE = False
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
El problema: si `markitdown` se instala pero la API cambió (el símbolo
|
|
273
|
+
`MarkItDown` ya no existe), el import sigue pasando y `_DISPONIBLE = True`
|
|
274
|
+
pero el code path fallará más tarde al usar el símbolo ausente. Importar
|
|
275
|
+
el símbolo específico que vas a usar es más robusto que importar el módulo
|
|
276
|
+
y esperar que todo lo demás funcione.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
<a id="regex-multi-pattern"></a>
|
|
281
|
+
## 5. Detectores regex multi-pattern: extender scope sin refinar genera falsos positivos
|
|
282
|
+
|
|
283
|
+
### NUNCA: agregar un nuevo input a un detector multi-pattern sin re-evaluar la sensibilidad de cada pattern individual
|
|
284
|
+
|
|
285
|
+
**Problema**: tienes una función `detectar(texto)` que aplica una lista de regex
|
|
286
|
+
con OR (`any(p.search(texto) for p in PATTERNS)`). Originalmente operaba sobre
|
|
287
|
+
texto curado (título, etiquetas, campos cortos). Ahora extiendes el scope a un
|
|
288
|
+
texto más ruidoso (prosa larga, descripciones libres, contenido de usuario).
|
|
289
|
+
Patterns genéricos que funcionaban en el texto curado empiezan a generar falsos
|
|
290
|
+
positivos en el ruidoso.
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
# Caso típico: detector de "enumeración múltiple de items relacionados"
|
|
294
|
+
PATTERNS = [
|
|
295
|
+
re.compile(r"(?:,\s+\w[\w\s]{3,45}){3,}"), # P1 generico: 3+ comas
|
|
296
|
+
re.compile(r"(?:^|\n)\s*[•\-]\s+.{10,}", re.M), # P2 generico: bullets
|
|
297
|
+
re.compile(r"(?:anexos|evidencias|listas){2,}", re.I), # P3 especifico
|
|
298
|
+
]
|
|
299
|
+
|
|
300
|
+
# MAL — extender scope sin discriminar patterns
|
|
301
|
+
def enumera_multiples(registro):
|
|
302
|
+
texto = " ".join([
|
|
303
|
+
registro.titulo, registro.resumen, # texto curado
|
|
304
|
+
registro.descripcion_libre, # texto ruidoso (prosa larga)
|
|
305
|
+
])
|
|
306
|
+
return any(p.search(texto) for p in PATTERNS)
|
|
307
|
+
# → P1 (3+ comas) matchea series de citas o referencias en prosa larga
|
|
308
|
+
# ("art. 5, art. 10, art. 23, art. 138 y art. 141") → falso positivo
|
|
309
|
+
# regresión típica observada: baja precisión sobre el dataset golden.
|
|
310
|
+
|
|
311
|
+
# BIEN — patterns por scope, refinados según ruido tolerado
|
|
312
|
+
def enumera_multiples(registro):
|
|
313
|
+
texto_curado = " ".join([registro.titulo, registro.resumen])
|
|
314
|
+
if any(p.search(texto_curado) for p in PATTERNS):
|
|
315
|
+
return True
|
|
316
|
+
# Sobre texto ruidoso, solo el pattern especifico (P3)
|
|
317
|
+
texto_ruidoso = " ".join([registro.descripcion_libre, registro.notas_libres])
|
|
318
|
+
return PATTERNS[2].search(texto_ruidoso) is not None
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Regla operativa
|
|
322
|
+
|
|
323
|
+
Cuando se extiende un detector regex a un nuevo scope textual, agregar un test de
|
|
324
|
+
regresión específico que verifique que NO se introducen falsos positivos sobre
|
|
325
|
+
muestras del nuevo scope que NO deberían matchear. Si los patterns genéricos
|
|
326
|
+
hacen FP sobre el scope nuevo, **discriminarlos por scope** (no aplicarlos al
|
|
327
|
+
scope ruidoso) en lugar de intentar refinarlos en una sola lista global.
|
|
328
|
+
|
|
329
|
+
**Aplicabilidad**: clasificadores de texto, detectores de PII, filtros de spam,
|
|
330
|
+
sistemas de moderación, extracción de entidades cuando el scope crece de campos
|
|
331
|
+
estructurados a contenido libre.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
<a id="tracer-sync"></a>
|
|
336
|
+
## 6. Tracer/replicador paralelo del motor: marca SYNC obligatoria en cada cambio
|
|
337
|
+
|
|
338
|
+
### Patrón: cuando duplicas lógica del original, marca el SYNC y agrega test de paridad
|
|
339
|
+
|
|
340
|
+
**Problema**: en sistemas con motores complejos (cascadas de reglas, clasificadores
|
|
341
|
+
con prioridad, motores de decisión), suele crearse un "tracer" que replica la
|
|
342
|
+
lógica paso a paso para producir telemetría, explicación o shadow runs. El tracer
|
|
343
|
+
es **duplicación** del motor — si cambias el motor sin tocar el tracer, los
|
|
344
|
+
outputs divergen silenciosamente y los tests del tracer pasan con datos viejos
|
|
345
|
+
mientras el motor real ya cambió.
|
|
346
|
+
|
|
347
|
+
```python
|
|
348
|
+
# Motor real (motor_decision.py)
|
|
349
|
+
def resolver_resultado(self, registro):
|
|
350
|
+
resultado = self._resolver_core(registro)
|
|
351
|
+
# Ajuste 1: suavización por condición A
|
|
352
|
+
if cond_a(registro): return "ACEPTADO"
|
|
353
|
+
# Ajustes 2-4: endurecimientos
|
|
354
|
+
if cond_b(registro): return "RECHAZADO"
|
|
355
|
+
# Ajuste 5 (NUEVO): endurecimiento por condición compuesta
|
|
356
|
+
if resultado == "ACEPTADO" and registro._compuesta:
|
|
357
|
+
return "RECHAZADO"
|
|
358
|
+
return resultado
|
|
359
|
+
|
|
360
|
+
# Tracer paralelo (motor_decision_tracer.py)
|
|
361
|
+
def replicar_resultado(...):
|
|
362
|
+
# SYNC con: motor_decision.py::resolver_resultado
|
|
363
|
+
# Si agregas un Ajuste, AGREGARLO TAMBIÉN aquí en el orden correcto.
|
|
364
|
+
if cond_a(registro): ...
|
|
365
|
+
if cond_b(registro): ...
|
|
366
|
+
# Olvidé sincronizar Ajuste 5 aquí → tracer reporta ACEPTADO
|
|
367
|
+
# pero motor real reporta RECHAZADO → tests ground truth fallan
|
|
368
|
+
# silenciosamente porque el tracer es lo que se compara.
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### Reglas obligatorias para código duplicado deliberado
|
|
372
|
+
|
|
373
|
+
1. **Marca de SYNC**: comentario `# SYNC con: <archivo>:<función>` visible en la
|
|
374
|
+
cabecera del replicador. La búsqueda `grep -rn "SYNC con:"` lista todos los
|
|
375
|
+
puntos de duplicación del repositorio en una corrida.
|
|
376
|
+
2. **Test de paridad**: para casos representativos del dataset golden, comparar
|
|
377
|
+
`motor.resolver(x) == tracer.resolver(x)` y fallar si difieren. Es el único
|
|
378
|
+
gate que detecta la divergencia sin esperar a producción.
|
|
379
|
+
3. **Convención de naming**: el archivo que duplica la lógica se nombra explícitamente
|
|
380
|
+
como derivado (`_tracer.py`, `_replicador.py`, `_explainer.py`, `_shadow.py`).
|
|
381
|
+
NUNCA esconderlo bajo nombre genérico — el nombre es la primera línea de defensa
|
|
382
|
+
contra que alguien lo edite sin saber que es duplicación.
|
|
383
|
+
4. **Owner único**: el motor y su tracer cambian en el mismo PR. Code review rechaza
|
|
384
|
+
PRs que tocan el motor sin tocar el tracer (o que justifiquen explícitamente
|
|
385
|
+
por qué la divergencia es intencional, ej. "el tracer no necesita el ajuste de
|
|
386
|
+
performance").
|
|
387
|
+
|
|
388
|
+
**Aplicabilidad**: sistemas con explainability, dual-track production+shadow,
|
|
389
|
+
motores de reglas con logging detallado, A/B testing de algoritmos, migración
|
|
390
|
+
incremental de un motor legacy a uno nuevo donde ambos corren en paralelo.
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
<a id="fixtures-crudos"></a>
|
|
395
|
+
## 7. Fixtures de test con datos pre-procesados NO ejercen el path de datos crudos
|
|
396
|
+
|
|
397
|
+
### Anti-patrón: fixtures construidos a mano que reflejan la salida del extractor, no su entrada
|
|
398
|
+
|
|
399
|
+
**Problema**: el sistema en producción procesa input crudo (PDFs, HTMLs, JSON
|
|
400
|
+
externos, mensajes raw) que pasa por extractores que producen un dict condensado.
|
|
401
|
+
Los fixtures de test se construyen "a mano" copiando lo que el extractor produce
|
|
402
|
+
(o aproximándolo). Resultado: cualquier path del motor que solo se activa con
|
|
403
|
+
campos del input crudo (presentes solo cuando hay extractor real arriba) NO se
|
|
404
|
+
ejercita por los tests, y los bugs aparecen únicamente en producción.
|
|
405
|
+
|
|
406
|
+
```python
|
|
407
|
+
# Fixture típico hecho a mano (apariencia inocente)
|
|
408
|
+
{
|
|
409
|
+
"id": "REG-001",
|
|
410
|
+
"registro": {
|
|
411
|
+
"titulo": "Falta de evidencia documental",
|
|
412
|
+
"descripcion_corta": "El operador manifiesta que el oficio acredita...", # condensada
|
|
413
|
+
# NOTAR: no hay `descripcion_original`
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
# Motor con fix nuevo
|
|
418
|
+
def _clasificar_postura(registro):
|
|
419
|
+
# Fix: prefiere texto crudo cuando está disponible
|
|
420
|
+
texto = (
|
|
421
|
+
registro.get("descripcion_original")
|
|
422
|
+
or registro.get("descripcion_corta")
|
|
423
|
+
)
|
|
424
|
+
return any(p in texto.lower() for p in patrones_subsanadores)
|
|
425
|
+
|
|
426
|
+
# Test del fixture pasa "por casualidad" (descripcion_corta condensada
|
|
427
|
+
# casualmente contiene "se anexa") → falsa confianza.
|
|
428
|
+
# En producción, descripcion_original sería 5000 chars con verbos
|
|
429
|
+
# canónicos y descripcion_corta sería paráfrasis sin esos verbos.
|
|
430
|
+
# Los tests no ejercitan el path real.
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Defensa
|
|
434
|
+
|
|
435
|
+
Cuando se introduce un nuevo campo opcional que el motor prefiere leer
|
|
436
|
+
(`descripcion_original`, `metadata_completa`, `raw_input`, `body_unparsed`,
|
|
437
|
+
etc.), agregar **al menos un fixture** que tenga ese campo poblado con una
|
|
438
|
+
muestra representativa del input crudo real — idealmente extraída del caché de
|
|
439
|
+
un pipeline E2E ejecutado, no inventada a mano.
|
|
440
|
+
|
|
441
|
+
```python
|
|
442
|
+
# Mejorado: fixture con ambos campos, con datos representativos del scope crudo
|
|
443
|
+
{
|
|
444
|
+
"registro": {
|
|
445
|
+
"descripcion_corta": "El operador manifiesta...", # condensada (lo que el extractor produce)
|
|
446
|
+
"descripcion_original": (
|
|
447
|
+
"OFICIO 12345/2026 — DEPARTAMENTO DE OPERACIONES ... "
|
|
448
|
+
"se anexa el oficio mediante correo institucional ... "
|
|
449
|
+
"[texto crudo extraído del PDF, 5000 chars con jerga canónica]"
|
|
450
|
+
),
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
### Regla operativa
|
|
456
|
+
|
|
457
|
+
- **Dos niveles de fixtures**: condensados (rápidos, para lógica de negocio) y
|
|
458
|
+
crudos (lentos, para paths que dependen del input real). Marcar cada fixture
|
|
459
|
+
con su nivel: `nombre.condensado.json` vs `nombre.crudo.json`.
|
|
460
|
+
- **Snapshot del extractor real**: si el extractor es determinístico, ejecutarlo
|
|
461
|
+
una vez sobre datos reales y persistir su output como fixture crudo. No inventarlo.
|
|
462
|
+
- **Test de "campo prioritario nuevo"**: cada vez que el motor agrega un campo
|
|
463
|
+
con prioridad sobre uno existente, agregar un test que verifique el comportamiento
|
|
464
|
+
con AMBOS campos poblados con valores **divergentes** (que producen resultados
|
|
465
|
+
distintos). Si el test pasa con valores iguales, no prueba la priorización.
|
|
466
|
+
|
|
467
|
+
**Aplicabilidad**: pipelines de ingesta con extractores upstream, sistemas con
|
|
468
|
+
adaptadores que normalizan inputs heterogéneos, motores que prefieren campos
|
|
469
|
+
crudos sobre derivados, tests de regresión de migraciones de schema.
|