@saulwade/swl-ses 2.6.0 → 2.8.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 +209 -197
- package/README.md +647 -600
- package/agentes/accesibilidad-wcag-swl.md +690 -690
- package/agentes/arquitecto-swl.md +267 -267
- package/agentes/auto-evolucion-swl.md +932 -932
- package/agentes/backend-csharp-swl.md +420 -420
- package/agentes/backend-go-swl.md +390 -390
- package/agentes/backend-java-swl.md +281 -281
- package/agentes/backend-rust-swl.md +364 -364
- package/agentes/backend-workers-swl.md +482 -482
- package/agentes/cloud-infra-swl.md +509 -509
- package/agentes/consolidador-swl.md +541 -541
- package/agentes/depurador-swl.md +352 -352
- package/agentes/devops-ci-swl.md +400 -400
- package/agentes/disenador-ui-swl.md +569 -569
- package/agentes/documentador-swl.md +345 -345
- package/agentes/frontend-angular-swl.md +621 -621
- package/agentes/frontend-css-swl.md +716 -716
- package/agentes/frontend-react-swl.md +692 -692
- package/agentes/frontend-swl.md +496 -496
- package/agentes/frontend-tailwind-swl.md +826 -826
- package/agentes/investigador-swl.md +432 -432
- package/agentes/investigador-ux-swl.md +505 -505
- package/agentes/migrador-swl.md +442 -442
- package/agentes/mobile-android-swl.md +511 -511
- package/agentes/mobile-cross-swl.md +541 -541
- package/agentes/mobile-ios-swl.md +502 -502
- package/agentes/mobile-testing-swl.md +302 -302
- package/agentes/nemesis-auditor-swl.md +285 -285
- package/agentes/observabilidad-swl.md +438 -438
- package/agentes/pagos-swl.md +310 -310
- package/agentes/perfilador-usuario-swl.md +321 -321
- package/agentes/planificador-swl.md +399 -399
- package/agentes/producto-prd-swl.md +589 -589
- package/agentes/red-team-swl.md +218 -218
- package/agentes/release-manager-swl.md +590 -590
- package/agentes/rendimiento-swl.md +713 -713
- package/agentes/revisor-angular-swl.md +278 -278
- package/agentes/revisor-csharp-swl.md +264 -264
- package/agentes/revisor-go-swl.md +259 -259
- package/agentes/revisor-java-swl.md +257 -257
- package/agentes/revisor-kotlin-swl.md +273 -273
- package/agentes/revisor-nextjs-swl.md +281 -281
- package/agentes/revisor-php-swl.md +271 -271
- package/agentes/revisor-react-swl.md +278 -278
- package/agentes/revisor-rust-swl.md +346 -346
- package/agentes/revisor-seguridad-swl.md +399 -399
- package/agentes/revisor-swift-swl.md +268 -268
- package/agentes/revisor-typescript-swl.md +346 -346
- package/agentes/tdd-qa-swl.md +393 -393
- package/bin/swl-ses.js +10 -0
- package/comandos/swl/actualizar.md +174 -174
- package/comandos/swl/adoptar-proyecto.md +265 -265
- package/comandos/swl/aprender.md +836 -836
- package/comandos/swl/aprobar-plan.md +146 -146
- package/comandos/swl/auditar-deps.md +134 -134
- package/comandos/swl/autoresearch.md +264 -264
- package/comandos/swl/ayuda.md +224 -224
- package/comandos/swl/brainstorm.md +52 -51
- package/comandos/swl/checkpoint.md +325 -325
- package/comandos/swl/claudemd.md +234 -234
- package/comandos/swl/compactar.md +310 -310
- package/comandos/swl/configurar-ci.md +235 -235
- package/comandos/swl/contexto.md +110 -110
- package/comandos/swl/crear-skill.md +292 -292
- package/comandos/swl/cron.md +194 -194
- package/comandos/swl/deuda-codigo.md +97 -97
- package/comandos/swl/discutir-fase.md +169 -169
- package/comandos/swl/ejecutar-fase.md +233 -233
- package/comandos/swl/evaluar-skill.md +520 -520
- package/comandos/swl/evolucion-continua.md +73 -73
- package/comandos/swl/evolucionar.md +267 -267
- package/comandos/swl/exportar-vault.md +583 -583
- package/comandos/swl/fix.md +118 -118
- package/comandos/swl/gateway.md +158 -158
- package/comandos/swl/inbox.md +116 -116
- package/comandos/swl/instalar.md +220 -220
- package/comandos/swl/instintos.md +86 -86
- package/comandos/swl/mapear-codebase.md +312 -312
- package/comandos/swl/mcp-status.md +176 -175
- package/comandos/swl/modelo.md +100 -100
- package/comandos/swl/nemesis.md +433 -433
- package/comandos/swl/notificaciones.md +299 -299
- package/comandos/swl/nuevo-proyecto.md +251 -251
- package/comandos/swl/planear-fase.md +263 -263
- package/comandos/swl/plugins.md +256 -256
- package/comandos/swl/predecir.md +169 -169
- package/comandos/swl/reflect-skills.md +125 -125
- package/comandos/swl/release.md +450 -450
- package/comandos/swl/revisar-impacto.md +201 -201
- package/comandos/swl/revisar.md +330 -330
- package/comandos/swl/seguridad.md +189 -189
- package/comandos/swl/sesiones.md +200 -200
- package/comandos/swl/skill-search.md +113 -113
- package/comandos/swl/status.md +345 -345
- package/comandos/swl/verificar.md +817 -817
- package/comandos/swl/wiki.md +620 -620
- package/gateway/cron/jobs.example.json +12 -12
- package/gateway/lib/event-channel.js +191 -191
- package/habilidades/agent-deep-links/SKILL.md +148 -148
- package/habilidades/auto-evolucion-protocolo/SKILL.md +294 -294
- package/habilidades/backend-async-postgres-testing/SKILL.md +216 -215
- package/habilidades/backend-error-design/SKILL.md +221 -221
- package/habilidades/backend-production-resilience/SKILL.md +288 -288
- package/habilidades/calidad-anti-patrones-universales/SKILL.md +105 -1
- package/habilidades/calidad-contract-testing/SKILL.md +165 -165
- package/habilidades/calidad-mutation-testing/SKILL.md +25 -1
- package/habilidades/changelog-generator/SKILL.md +174 -174
- package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -60
- package/habilidades/ci-cd-pipelines/SKILL.md +5 -1
- package/habilidades/compactacion-contexto/SKILL.md +2 -1
- package/habilidades/contenedores-docker/SKILL.md +4 -2
- package/habilidades/css-moderno/SKILL.md +7 -1
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/doubt-driven-review/SKILL.md +207 -207
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/drift-detection/SKILL.md +1 -1
- package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -57
- package/habilidades/extractor-de-aprendizajes/SKILL.md +12 -2
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
- package/habilidades/git-worktrees-paralelo/SKILL.md +19 -1
- package/habilidades/harness-claude-code/SKILL.md +315 -314
- package/habilidades/instalar-sistema/SKILL.md +227 -227
- package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
- package/habilidades/perfil-usuario/SKILL.md +200 -200
- package/habilidades/planear-fase/SKILL.md +358 -358
- package/habilidades/prevencion-sobreingenieria/recursos/EXAMPLES.md +580 -580
- package/habilidades/proceso-ddia-streaming/SKILL.md +231 -231
- package/habilidades/proceso-discovery-machote/SKILL.md +157 -157
- package/habilidades/proceso-dynamic-workflows/SKILL.md +60 -0
- package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -65
- package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -65
- package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -147
- package/habilidades/proceso-intent-engineering/SKILL.md +269 -269
- package/habilidades/proceso-modular-split/SKILL.md +256 -256
- package/habilidades/release-semver/SKILL.md +2 -2
- package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
- package/habilidades/swl-claudemd/recursos/contrato-aprender.md +83 -83
- package/habilidades/swl-claudemd/recursos/duplicacion-reglas-globales.md +85 -85
- package/habilidades/swl-claudemd/recursos/plantillas-init.md +94 -94
- package/habilidades/tdd-workflow/SKILL.md +749 -749
- package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -111
- package/hooks/agente-lifecycle.js +1 -1
- package/hooks/audit-trail.js +1 -1
- package/hooks/auto-consolidacion.js +1 -1
- package/hooks/calidad-pre-commit.js +159 -10
- package/hooks/captura-acciones-post.js +1 -1
- package/hooks/captura-acciones-session.js +1 -1
- package/hooks/captura-feedback-usuario.js +1 -1
- package/hooks/ciclo-evolucion-subagente.js +26 -26
- package/hooks/ciclo-evolucion.js +26 -26
- package/hooks/contexto-iteracion.js +1 -1
- package/hooks/degradacion-instintos.js +1 -1
- package/hooks/grafo-contexto.js +1 -1
- package/hooks/guardrail-modelo.js +1 -1
- package/hooks/inbox-aviso.js +1 -1
- package/hooks/inyeccion-contexto.js +1 -1
- package/hooks/lib/agent-matcher.js +1 -1
- package/hooks/lib/agent-routing.js +1 -1
- package/hooks/lib/auto-consolidator.js +335 -335
- package/hooks/lib/captura-acciones.js +1 -1
- package/hooks/lib/ciclo-evolucion.js +47 -47
- package/hooks/lib/deep-links.js +185 -185
- package/hooks/lib/error-classifier.js +308 -308
- package/hooks/lib/etapa-metricas.js +1 -1
- package/hooks/lib/evolution-tracker.js +1 -1
- package/hooks/lib/gateway-notify.js +193 -193
- package/hooks/lib/mcp-health.js +1 -1
- package/hooks/lib/notificacion-formato.js +92 -0
- package/hooks/lib/nudge-tracker.js +1 -1
- package/hooks/lib/otlp-exporter.js +1 -1
- package/hooks/lib/propose-step.js +1 -1
- package/hooks/lib/provenance-tracker.js +191 -191
- package/hooks/lib/raiz-proyecto.js +158 -102
- package/hooks/lib/resource-quota.js +122 -122
- package/hooks/lib/retry-jitter.js +165 -165
- package/hooks/lib/run-log.js +1 -1
- package/hooks/lib/security-net.js +201 -201
- package/hooks/lib/singleton-guard.js +20 -13
- package/hooks/lib/skill-auditor.js +588 -588
- package/hooks/lib/sync-status.js +228 -228
- package/hooks/lib/taint-tracker.js +107 -107
- package/hooks/lib/telegram-cliente.js +11 -3
- package/hooks/lib/text-similarity.js +241 -241
- package/hooks/lib/toon-compressor.js +245 -245
- package/hooks/notificacion-telegram.js +17 -13
- package/hooks/preservar-estado-pre-compact.js +1 -1
- package/hooks/registro-turnos.js +1 -1
- package/hooks/resumen-sesion.js +1 -1
- package/hooks/risk-scoring.js +1 -1
- package/hooks/session-briefing.js +13 -5
- package/hooks/spec-gate.js +1 -1
- package/hooks/sugerir-regenerar-inventario.js +1 -1
- package/hooks/tdd-gate.js +1 -1
- package/hooks/telemetria-agentes.js +1 -1
- package/hooks/telemetria-skill-routing.js +1 -1
- package/hooks/tracking-costos.js +1 -1
- package/hooks/validar-formato-post-subagente.js +1 -1
- package/hooks/validar-intent-spec.js +1 -1
- package/hooks/validar-planning-paths.js +1 -1
- package/instintos/autonomia.yaml +27 -27
- package/instintos/prompt-appendices.yaml +57 -57
- package/llms.txt +29 -29
- package/manifiestos/agent-output-schemas.json +57 -57
- package/manifiestos/canonical-hashes.json +6250 -5257
- package/manifiestos/harness-ir.json +47536 -0
- package/manifiestos/modulos.json +1429 -1428
- package/manifiestos/policy-bundle.json +2065 -0
- package/manifiestos/policy-corpus-w2.json +3926 -0
- package/manifiestos/runtime-adapters-core3.json +208 -0
- package/manifiestos/runtime-conformance.json +139 -0
- package/manifiestos/skills-lock.json +1275 -1275
- package/package.json +94 -94
- package/plantillas/auditor-veto-template.md +105 -105
- package/plantillas/github-workflows/release-please.yml +44 -44
- package/plantillas/github-workflows/swl-ci.yml +107 -107
- package/plantillas/github-workflows/swl-security.yml +51 -51
- package/plugin.json +369 -369
- package/reglas/accesibilidad.md +10 -10
- package/reglas/auditorias-documentales-estructurales.md +7 -7
- package/reglas/cloud-infra.md +8 -8
- package/reglas/consultar-vault-primero.md +195 -195
- package/reglas/git-workflow.md +1 -0
- package/reglas/hooks.md +6 -6
- package/reglas/intent-engineering.md +218 -218
- package/reglas/markitdown.md +8 -8
- package/reglas/monitor-ci.md +12 -0
- package/reglas/patrones.md +6 -6
- package/reglas/testing.md +7 -7
- package/reglas/tests-cleanup.md +224 -224
- package/schemas/agent-message.schema.json +73 -73
- package/schemas/agent-output-implementacion.schema.json +114 -114
- package/schemas/agent-output-planificacion.schema.json +150 -150
- package/schemas/agent-output-review.schema.json +98 -98
- package/schemas/diary-entry.schema.json +112 -112
- package/schemas/gate-state.schema.json +76 -0
- package/schemas/harness-ir.schema.json +369 -0
- package/schemas/hook-profiles.schema.json +54 -54
- package/schemas/hooks-config.schema.json +89 -89
- package/schemas/legacy-gates.schema.json +45 -0
- package/schemas/modulos.schema.json +38 -38
- package/schemas/perfiles.schema.json +36 -36
- package/schemas/plugin.schema.json +77 -77
- package/schemas/policy-bundle.schema.json +140 -0
- package/schemas/policy-enforcement.schema.json +117 -0
- package/schemas/policy-operation.schema.json +261 -0
- package/schemas/runtime-adapter.schema.json +176 -0
- package/schemas/runtime-build-attestation.schema.json +100 -0
- package/schemas/runtime-conformance.schema.json +239 -0
- package/schemas/runtime-diagnostic.schema.json +395 -0
- package/schemas/skill-evals.schema.json +119 -119
- package/schemas/skill-frontmatter.schema.json +245 -245
- package/schemas/w4-certification-request.schema.json +72 -0
- package/schemas/w4-certification-verdict.schema.json +224 -0
- package/schemas/w4-corpus.schema.json +172 -0
- package/schemas/w4-mutation-report.schema.json +116 -0
- package/schemas/w4-replay-result.schema.json +164 -0
- package/schemas/w4-scoring-report.schema.json +89 -0
- package/scripts/audit-tools/audit-history.js +330 -330
- package/scripts/audit-tools/bundle-tracker.js +290 -290
- package/scripts/audit-tools/canary-monitor.js +352 -352
- package/scripts/audit-tools/code-profiler.js +605 -605
- package/scripts/audit-tools/dep-doctor.js +320 -320
- package/scripts/audit-tools/env-validator.js +206 -206
- package/scripts/audit-tools/lib/fs-walk.js +48 -48
- package/scripts/audit-tools/lib/output.js +23 -23
- package/scripts/audit-tools/migration-checker.js +392 -392
- package/scripts/audit-tools/pentest-scanner.js +1436 -1436
- package/scripts/auditar-clases-conocidas.js +134 -134
- package/scripts/bootstrap-instintos.js +88 -14
- package/scripts/canario-hooks.js +166 -166
- package/scripts/cli/aprobar-plan.js +73 -73
- package/scripts/cli/autonomia.js +23 -23
- package/scripts/cli/benchmark-memoria.js +37 -37
- package/scripts/cli/briefing.js +23 -23
- package/scripts/cli/ciclo-autonomo.js +73 -73
- package/scripts/cli/ciclo-evolucion.js +26 -26
- package/scripts/cli/ciclo-fase-b.js +102 -102
- package/scripts/cli/derivar-feature-list.js +25 -25
- package/scripts/cli/detectar-host.js +27 -27
- package/scripts/cli/diary-entry.js +69 -69
- package/scripts/cli/execution-state.js +18 -18
- package/scripts/cli/gateway-notify.js +41 -41
- package/scripts/cli/guardrail-metrics.js +39 -39
- package/scripts/cli/liberar-fase.js +42 -42
- package/scripts/cli/mark-evolved.js +56 -56
- package/scripts/cli/memoria-search.js +69 -69
- package/scripts/cli/metricas-dora.js +26 -26
- package/scripts/cli/near-duplicate.js +55 -55
- package/scripts/cli/notificaciones.js +123 -123
- package/scripts/cli/nudge-accionar.js +39 -39
- package/scripts/cli/propose-step.js +29 -29
- package/scripts/cli/run-eval.js +38 -38
- package/scripts/cli/schedule-parse.js +19 -19
- package/scripts/cli/sugerir-modelo.js +20 -20
- package/scripts/cli/verificar-plan.js +36 -36
- package/scripts/cli/verificar-trazabilidad.js +35 -35
- package/scripts/comandos/install-asistido.js +8 -7
- package/scripts/configurar-branch-protection.js +418 -418
- package/scripts/detectar-aprendizajes-duplicados.js +151 -151
- package/scripts/doctor.js +61 -13
- package/scripts/evidencia-valor.js +101 -101
- package/scripts/field-report.js +16 -16
- package/scripts/generar-checklists-consolidados.js +273 -273
- package/scripts/generar-claims-runtime.js +1342 -0
- package/scripts/generar-harness-ir.js +257 -0
- package/scripts/generar-inventario.js +52 -54
- package/scripts/generar-policy-bundle.js +202 -0
- package/scripts/instalador.js +39 -7
- package/scripts/lib/activar-hooks-proyecto.js +116 -116
- package/scripts/lib/approval-receipts.js +190 -0
- package/scripts/lib/artefactos-python.js +43 -43
- package/scripts/lib/benchmark-metrics.js +160 -160
- package/scripts/lib/budget-enforcer.js +252 -252
- package/scripts/lib/certificacion-loop-state.js +421 -0
- package/scripts/lib/ci-reader.js +193 -193
- package/scripts/lib/ciclo-autonomo/candidatos.js +174 -174
- package/scripts/lib/ciclo-autonomo/config.js +165 -165
- package/scripts/lib/ciclo-autonomo/drenador-feedback.js +174 -174
- package/scripts/lib/ciclo-autonomo/fallback.js +77 -77
- package/scripts/lib/ciclo-autonomo/guard-convivencia.js +139 -139
- package/scripts/lib/ciclo-autonomo/higiene-nudges.js +112 -112
- package/scripts/lib/ciclo-autonomo/index.js +301 -301
- package/scripts/lib/ciclo-autonomo/lock.js +124 -124
- package/scripts/lib/ciclo-autonomo/presupuesto.js +122 -122
- package/scripts/lib/ciclo-autonomo/puente-degradacion.js +240 -240
- package/scripts/lib/ciclo-autonomo/runner-fase-b.js +248 -248
- package/scripts/lib/ciclo-autonomo/writer-instintos.js +190 -190
- package/scripts/lib/ciclo-autonomo/yaml-instintos.js +591 -535
- package/scripts/lib/clasificar-directorio.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -217
- package/scripts/lib/detectar-host-swl.js +175 -175
- package/scripts/lib/detectar-runtime.js +29 -20
- package/scripts/lib/detectar-stack-detallado.js +307 -307
- package/scripts/lib/detector-autoduplicacion-intra-archivo.js +234 -234
- package/scripts/lib/detector-reglas-duplicadas.js +220 -220
- package/scripts/lib/eval-metrics-store.js +218 -218
- package/scripts/lib/eval-quality.js +171 -171
- package/scripts/lib/eval-schemas.js +144 -144
- package/scripts/lib/eval-self-correct.js +106 -106
- package/scripts/lib/eval-validator.js +185 -185
- package/scripts/lib/evidence-verifier.js +192 -0
- package/scripts/lib/evidencia-release.js +322 -322
- package/scripts/lib/evidencia-valor.js +228 -228
- package/scripts/lib/expandir-targets.js +71 -71
- package/scripts/lib/frontmatter-canonico.js +509 -0
- package/scripts/lib/gate-engine.js +871 -0
- package/scripts/lib/gate-hooks-requires.js +249 -249
- package/scripts/lib/gate-licencias.js +212 -212
- package/scripts/lib/git-config-preflight.js +48 -0
- package/scripts/lib/git-metricas.js +257 -257
- package/scripts/lib/harness-ir.js +778 -0
- package/scripts/lib/harness-source-snapshot.js +309 -0
- package/scripts/lib/integrity-ledger.js +1147 -0
- package/scripts/lib/jaccard-similarity.js +98 -98
- package/scripts/lib/legacy-gate-migration.js +324 -0
- package/scripts/lib/limpiar-basura-global.js +204 -0
- package/scripts/lib/longmemeval-runner.js +125 -125
- package/scripts/lib/metricas-dora.js +204 -204
- package/scripts/lib/notificaciones-telegram.js +1 -0
- package/scripts/lib/npm-version.js +1 -0
- package/scripts/lib/paquetes-conocidos.js +50 -50
- package/scripts/lib/plan-lock.js +61 -13
- package/scripts/lib/policy-broker.js +338 -0
- package/scripts/lib/policy-bundle.js +342 -0
- package/scripts/lib/policy-context-provider.js +310 -0
- package/scripts/lib/policy-contract.js +479 -0
- package/scripts/lib/policy-verifier-utils.js +65 -0
- package/scripts/lib/pr-analyzer.js +399 -399
- package/scripts/lib/principal-verifier.js +178 -0
- package/scripts/lib/prompt-builder.js +264 -264
- package/scripts/lib/resolver-plan-fase.js +37 -37
- package/scripts/lib/rrf-fusion.js +175 -175
- package/scripts/lib/runtime-adapter-contract.js +267 -0
- package/scripts/lib/runtime-artifact-verifier.js +426 -0
- package/scripts/lib/runtime-build-attestation.js +127 -0
- package/scripts/lib/runtime-bundle-installer.js +586 -0
- package/scripts/lib/runtime-compiler.js +327 -0
- package/scripts/lib/runtime-conformance.js +202 -0
- package/scripts/lib/runtime-doctor-core3.js +567 -0
- package/scripts/lib/runtime-doctor-input.js +59 -0
- package/scripts/lib/runtime-operation-adapter.js +267 -0
- package/scripts/lib/schema-version.js +164 -164
- package/scripts/lib/semantic-search.js +252 -252
- package/scripts/lib/signed-envelope.js +545 -0
- package/scripts/lib/single-use-store.js +359 -0
- package/scripts/lib/skills-externas.js +31 -0
- package/scripts/lib/toml-merge.js +204 -204
- package/scripts/lib/transformadores/codex.js +15 -8
- package/scripts/lib/transformadores/gemini.js +79 -5
- package/scripts/lib/w4-attestation-adapter.js +158 -0
- package/scripts/lib/w4-canario.js +337 -0
- package/scripts/lib/w4-claims.js +182 -0
- package/scripts/lib/w4-corpus-generador.js +542 -0
- package/scripts/lib/w4-gate-c5.js +115 -0
- package/scripts/lib/w4-harness-bajo-prueba.js +155 -0
- package/scripts/lib/w4-matriz-combos.js +55 -0
- package/scripts/lib/w4-motor-mutacion.js +1348 -0
- package/scripts/lib/w4-motor-replay.js +735 -0
- package/scripts/lib/w4-pin-origen.js +54 -0
- package/scripts/lib/w4-publicar-request.js +132 -0
- package/scripts/lib/w4-revocacion.js +62 -0
- package/scripts/lib/w4-runtimes-core3.js +38 -0
- package/scripts/lib/w4-scorer-certificacion.js +692 -0
- package/scripts/lib/w4-superficie-candidato.js +49 -0
- package/scripts/lib/w4-veredicto.js +452 -0
- package/scripts/lib/w4-verificar-veredicto.js +302 -0
- package/scripts/limpiar-artefactos-python.js +131 -131
- package/scripts/mcp-server/auth.js +105 -105
- package/scripts/mcp-server/cache.js +106 -106
- package/scripts/migrar-csv-a-array.js +168 -168
- package/scripts/migrar-fase-dominio.js +200 -200
- package/scripts/migrar-gates-legacy.js +108 -0
- package/scripts/publicar-certification-request.js +115 -0
- package/scripts/runtime-doctor.js +107 -0
- package/scripts/tui/componentes/selector-multi.js +189 -189
- package/scripts/tui/componentes/selector-unico.js +158 -158
- package/scripts/tui/ejecutores.js +375 -375
- package/scripts/tui/lib/colores.js +129 -129
- package/scripts/tui/lib/render.js +264 -264
- package/scripts/tui/lib/teclas.js +113 -113
- package/scripts/tui/pantallas/install-wizard.js +408 -403
- package/scripts/tui/pantallas/menu-principal.js +52 -52
- package/scripts/tui/pantallas/progreso.js +274 -274
- package/scripts/tui/pantallas/resumen.js +132 -132
- package/scripts/validar-userland-vacio.js +110 -110
- package/scripts/verificar-aislamiento-swl-eval.js +87 -0
- package/scripts/verificar-empaquetado-downstream.js +375 -0
- package/scripts/verificar-loop-constructor.js +215 -0
- package/scripts/verificar-trazabilidad.js +13 -6
- package/scripts/verificar-veredicto-real.js +84 -0
- package/instintos/.backups/perfil-usuario.yaml.2026-07-10-165128.bak +0 -53
- package/instintos/.backups/proyecto.yaml.2026-07-10-165128.bak +0 -372
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Superficie del CANDIDATO bajo prueba (F32/T-01, escindida de
|
|
5
|
+
* `w4-harness-bajo-prueba.js` por ADR-0056:100-106 y
|
|
6
|
+
* `DT-MOTOR-REPLAY-SRP-MUTACIONES-PINEADAS`).
|
|
7
|
+
*
|
|
8
|
+
* Este módulo contiene EXCLUSIVAMENTE la superficie de decisión de `swl-ses`
|
|
9
|
+
* (`runHarnessBajoPrueba`, que envuelve `verifyOperation()`). Se separó del
|
|
10
|
+
* validador del request del juez (`validateCertificationRequest`, que se queda
|
|
11
|
+
* en `w4-harness-bajo-prueba.js`) para que el juez de `swl-eval` pueda resolver
|
|
12
|
+
* la superficie DESDE EL TARBALL bajo prueba sin arrastrar maquinaria del juez
|
|
13
|
+
* — cerrando la mezcla de responsabilidades que la revisión adversarial de T-09
|
|
14
|
+
* señaló (el juez certifica el código que se envía, no una copia pineada).
|
|
15
|
+
*
|
|
16
|
+
* Es la superficie que el motor de replay ejercita contra cada caso del corpus
|
|
17
|
+
* a través del adaptador de candidato: en modo dev la envuelve
|
|
18
|
+
* `crearCandidatoSinteticoDev`; en el tramo real la resolvería
|
|
19
|
+
* `crearCandidatoReal` desde `CANDIDATO_ROOT`.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const { verifyOperation } = require('./policy-contract');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Superficie pura que el juez de `swl-eval` invoca sobre el candidato de
|
|
26
|
+
* `swl-ses`: envuelve `verifyOperation()` (ya puro) sin duplicar su
|
|
27
|
+
* validación ni construir un contrato nuevo (REQ-32-02). Nunca lanza —
|
|
28
|
+
* devuelve un resultado discriminado y sanitizado para que un proceso
|
|
29
|
+
* remoto no reciba un Error nativo con detalle interno de la pila.
|
|
30
|
+
*/
|
|
31
|
+
function runHarnessBajoPrueba(rawOperationBytes) {
|
|
32
|
+
try {
|
|
33
|
+
const operation = verifyOperation(rawOperationBytes);
|
|
34
|
+
return Object.freeze({
|
|
35
|
+
ok: true,
|
|
36
|
+
operationDigest: operation.operationDigest,
|
|
37
|
+
capability: operation.capability,
|
|
38
|
+
effectKind: operation.effectKind,
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
// verifyOperation() garantiza .codigo en todo error que lanza (crearError()
|
|
42
|
+
// lo fija siempre); no se agrega un fallback defensivo no verificable.
|
|
43
|
+
return Object.freeze({ ok: false, codigo: error.codigo });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
runHarnessBajoPrueba,
|
|
49
|
+
};
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Emisor del `CertificationVerdict` (ADR-0053 § Contrato swl-ses <-> swl-eval,
|
|
5
|
+
* F32/T-06, REQ-32-06).
|
|
6
|
+
*
|
|
7
|
+
* `emitirVeredicto(scoringReport, certificationRequest, insumos)` mapea un
|
|
8
|
+
* `ScoringReport` (T-05, `scripts/lib/w4-scorer-certificacion.js`) y un
|
|
9
|
+
* `CertificationRequest` (T-01, `scripts/lib/w4-harness-bajo-prueba.js`) a un
|
|
10
|
+
* `CertificationVerdict` sanitizado (`schemas/w4-certification-verdict.schema.json`):
|
|
11
|
+
* nunca el payload crudo del corpus, PII ni tokens — sólo SLO/medido/pass por
|
|
12
|
+
* dimensión, metadatos escalares y conteos agregados. `certifica` se copia
|
|
13
|
+
* LITERAL del `ScoringReport` (nunca se recomputa ni se "eleva" a partir de
|
|
14
|
+
* las dimensiones sanitizadas — esa es la única fuente de verdad de
|
|
15
|
+
* `certificarDimensiones()` en T-05).
|
|
16
|
+
*
|
|
17
|
+
* Puro: cero `fs`, cero red, cero reloj de pared. `emitidoEn` se recibe ya
|
|
18
|
+
* validado como argumento (`insumos.emitidoEn`) — este módulo nunca consulta
|
|
19
|
+
* `Date.now()`.
|
|
20
|
+
*
|
|
21
|
+
* C5 (sanitización enforzada también por el schema, no sólo aquí): el
|
|
22
|
+
* `medido` crudo de un `DimensionScore` puede traer booleanos
|
|
23
|
+
* (`paridadContractual`), objetos anidados (`ciclosConsecutivosPorRuntime`) o
|
|
24
|
+
* arreglos de categorías (`categoriasSinEvidenciaDeDefensaReal`). `aplanarMedido()`
|
|
25
|
+
* lo reduce a `null` o a un mapa plano de una sola profundidad cuyas claves
|
|
26
|
+
* son rutas con punto y cuyos valores son SIEMPRE `number` — nunca strings,
|
|
27
|
+
* booleanos ni arreglos crudos. Los booleanos se codifican 1/0; los arreglos
|
|
28
|
+
* se reducen a su longitud (un conteo, nunca los nombres de categoría
|
|
29
|
+
* crudos — esos, cuando importan, viajan reducidos en `failures[]`).
|
|
30
|
+
*
|
|
31
|
+
* C6: `firma.dev.nota` es un literal FIJO (`NOTA_DEV`) que este módulo nunca
|
|
32
|
+
* construye dinámicamente — el schema lo fija como `const` y el verificador
|
|
33
|
+
* (`w4-verificar-veredicto.js`) rechaza cualquier otro valor delegando en
|
|
34
|
+
* `validateCertificationVerdict()`.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
const { validateScoringReport, NOMBRES_DIMENSIONES } = require('./w4-scorer-certificacion');
|
|
38
|
+
const { validateCertificationRequest } = require('./w4-harness-bajo-prueba');
|
|
39
|
+
const { CATEGORIAS } = require('./w4-corpus-generador');
|
|
40
|
+
const { validarTimestampIso } = require('./signed-envelope');
|
|
41
|
+
|
|
42
|
+
const SCHEMA_VERSION = '1.0.0';
|
|
43
|
+
const NOMBRE_META_SLO = 'meta-SLO';
|
|
44
|
+
|
|
45
|
+
// C6: literal fijo — DEBE ser idéntico, carácter por carácter, al `const` de
|
|
46
|
+
// schemas/w4-certification-verdict.schema.json#/$defs/firmaDev/properties/nota.
|
|
47
|
+
const NOTA_DEV = 'verificador dev, adaptador de attestation simulado — este veredicto nunca certifica ni implica origen verificado (ADR-0053 C6)';
|
|
48
|
+
|
|
49
|
+
const SHA256 = /^[a-f0-9]{64}$/u;
|
|
50
|
+
const IDENTIFICADOR = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
51
|
+
const CASO_ID = /^(?:mutation|injection)-[a-z][a-z-]*-[0-9]{6}$/u;
|
|
52
|
+
const CATEGORIA_SET = new Set(CATEGORIAS);
|
|
53
|
+
const NOMBRE_DIMENSION_SET = new Set(NOMBRES_DIMENSIONES);
|
|
54
|
+
|
|
55
|
+
const INSUMOS_KEYS_DEV = ['runId', 'emitidoEn', 'corpusAgregados', 'failures', 'modo'];
|
|
56
|
+
const INSUMOS_KEYS_REAL = [...INSUMOS_KEYS_DEV, 'bundleDigest'];
|
|
57
|
+
const CORPUS_AGREGADOS_KEYS = [
|
|
58
|
+
'totalCasos', 'selladosHumano', 'mutationsTotal', 'promptInjectionsTotal', 'pass', 'fail', 'porCategoria',
|
|
59
|
+
];
|
|
60
|
+
const CATEGORIA_AGG_KEYS = ['total', 'fail'];
|
|
61
|
+
const FAILURE_KEYS = ['casoId', 'categoria', 'dimension'];
|
|
62
|
+
|
|
63
|
+
const VERDICT_KEYS = [
|
|
64
|
+
'kind', 'schemaVersion', 'runId', 'request', 'certifica', 'dimensiones',
|
|
65
|
+
'metaSlo', 'metadata', 'corpusAgregados', 'failures', 'firma', 'emitidoEn',
|
|
66
|
+
];
|
|
67
|
+
const REQUEST_KEYS = ['commit', 'tarballDigest', 'matrix'];
|
|
68
|
+
const MATRIX_ENTRY_KEYS = ['runtime', 'os', 'model'];
|
|
69
|
+
const DIMENSION_VERDICT_KEYS = ['dimension', 'slo', 'medido', 'pass'];
|
|
70
|
+
const METADATA_KEYS = ['cobertura', 'mutation', 'cve', 'rollback'];
|
|
71
|
+
const RUNTIMES_CORE3 = new Set(['claude-code', 'codex-cli', 'gemini-cli']);
|
|
72
|
+
const OS_CORE3 = new Set(['win32', 'linux', 'darwin']);
|
|
73
|
+
|
|
74
|
+
function crearError(codigo, mensaje) {
|
|
75
|
+
const error = new Error(mensaje);
|
|
76
|
+
error.codigo = codigo;
|
|
77
|
+
return error;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function fallar(codigo, mensaje) {
|
|
81
|
+
throw crearError(codigo, mensaje);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function esObjetoPlano(valor) {
|
|
85
|
+
return Boolean(valor) && typeof valor === 'object' && !Array.isArray(valor)
|
|
86
|
+
&& Object.getPrototypeOf(valor) === Object.prototype
|
|
87
|
+
&& Object.getOwnPropertySymbols(valor).length === 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function validarClaves(valor, esperadas, etiqueta, codigo = 'VERDICT_EMISION_INVALIDA') {
|
|
91
|
+
if (!esObjetoPlano(valor)) fallar(codigo, `${etiqueta} inválido`);
|
|
92
|
+
const actuales = Object.keys(valor).sort();
|
|
93
|
+
const objetivo = [...esperadas].sort();
|
|
94
|
+
if (JSON.stringify(actuales) !== JSON.stringify(objetivo)) fallar(codigo, `${etiqueta} inválido`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function congelarProfundo(valor) {
|
|
98
|
+
if (valor && typeof valor === 'object' && !Object.isFrozen(valor)) {
|
|
99
|
+
Object.values(valor).forEach(congelarProfundo);
|
|
100
|
+
Object.freeze(valor);
|
|
101
|
+
}
|
|
102
|
+
return valor;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// C5 — sanitización de 'medido': siempre número, null, u objeto plano de números.
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
function aplanarNumero(valor) {
|
|
110
|
+
if (typeof valor === 'number' && Number.isFinite(valor)) return valor;
|
|
111
|
+
if (typeof valor === 'boolean') return valor ? 1 : 0;
|
|
112
|
+
if (Array.isArray(valor)) return valor.length;
|
|
113
|
+
return 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function aplanarMedido(valor, prefijo = '') {
|
|
117
|
+
if (valor === null || valor === undefined) return prefijo ? {} : null;
|
|
118
|
+
if (typeof valor === 'number' || typeof valor === 'boolean' || Array.isArray(valor)) {
|
|
119
|
+
return { [prefijo || 'valor']: aplanarNumero(valor) };
|
|
120
|
+
}
|
|
121
|
+
if (esObjetoPlano(valor)) {
|
|
122
|
+
const acumulado = {};
|
|
123
|
+
for (const [clave, sub] of Object.entries(valor)) {
|
|
124
|
+
Object.assign(acumulado, aplanarMedido(sub, prefijo ? `${prefijo}.${clave}` : clave));
|
|
125
|
+
}
|
|
126
|
+
return acumulado;
|
|
127
|
+
}
|
|
128
|
+
return prefijo ? {} : null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function sanitizarMedidoTope(valor) {
|
|
132
|
+
const aplanado = aplanarMedido(valor);
|
|
133
|
+
if (aplanado === null) return null;
|
|
134
|
+
return Object.keys(aplanado).length === 0 ? null : congelarProfundo(aplanado);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function crearDimensionVerdict(score) {
|
|
138
|
+
return congelarProfundo({
|
|
139
|
+
dimension: score.dimension,
|
|
140
|
+
slo: score.slo,
|
|
141
|
+
medido: sanitizarMedidoTope(score.medido),
|
|
142
|
+
pass: score.pass,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function extraerScalarMap(valor) {
|
|
147
|
+
if (!esObjetoPlano(valor)) return null;
|
|
148
|
+
const salida = {};
|
|
149
|
+
for (const [clave, v] of Object.entries(valor)) {
|
|
150
|
+
if (typeof v === 'number' || typeof v === 'boolean' || typeof v === 'string') salida[clave] = v;
|
|
151
|
+
}
|
|
152
|
+
return salida;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function construirMetadata(metaSlo) {
|
|
156
|
+
const medido = esObjetoPlano(metaSlo.medido) ? metaSlo.medido : {};
|
|
157
|
+
return congelarProfundo({
|
|
158
|
+
cobertura: extraerScalarMap(medido.cobertura),
|
|
159
|
+
mutation: extraerScalarMap(medido.mutation),
|
|
160
|
+
cve: extraerScalarMap(medido.cve),
|
|
161
|
+
rollback: extraerScalarMap(medido.rollback),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
// Validación de insumos del emisor — nunca confía en la forma del caller.
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
|
|
169
|
+
function validarEnteroNoNegativo(valor, etiqueta) {
|
|
170
|
+
if (!Number.isInteger(valor) || valor < 0) fallar('VERDICT_EMISION_INVALIDA', `${etiqueta} inválido`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function validarCorpusAgregados(valor) {
|
|
174
|
+
validarClaves(valor, CORPUS_AGREGADOS_KEYS, 'corpusAgregados');
|
|
175
|
+
['totalCasos', 'selladosHumano', 'mutationsTotal', 'promptInjectionsTotal', 'pass', 'fail']
|
|
176
|
+
.forEach((clave) => validarEnteroNoNegativo(valor[clave], `corpusAgregados.${clave}`));
|
|
177
|
+
if (valor.pass + valor.fail !== valor.totalCasos) {
|
|
178
|
+
fallar('VERDICT_EMISION_INVALIDA', 'corpusAgregados.pass + fail debe igualar totalCasos');
|
|
179
|
+
}
|
|
180
|
+
if (!esObjetoPlano(valor.porCategoria)) fallar('VERDICT_EMISION_INVALIDA', 'corpusAgregados.porCategoria inválido');
|
|
181
|
+
const porCategoria = {};
|
|
182
|
+
for (const [categoria, agregado] of Object.entries(valor.porCategoria)) {
|
|
183
|
+
if (!CATEGORIA_SET.has(categoria)) {
|
|
184
|
+
fallar('VERDICT_EMISION_INVALIDA', `corpusAgregados.porCategoria con categoría desconocida: ${categoria}`);
|
|
185
|
+
}
|
|
186
|
+
validarClaves(agregado, CATEGORIA_AGG_KEYS, `corpusAgregados.porCategoria.${categoria}`);
|
|
187
|
+
validarEnteroNoNegativo(agregado.total, `corpusAgregados.porCategoria.${categoria}.total`);
|
|
188
|
+
validarEnteroNoNegativo(agregado.fail, `corpusAgregados.porCategoria.${categoria}.fail`);
|
|
189
|
+
if (agregado.fail > agregado.total) {
|
|
190
|
+
fallar('VERDICT_EMISION_INVALIDA', `corpusAgregados.porCategoria.${categoria}.fail excede total`);
|
|
191
|
+
}
|
|
192
|
+
porCategoria[categoria] = { total: agregado.total, fail: agregado.fail };
|
|
193
|
+
}
|
|
194
|
+
return congelarProfundo({
|
|
195
|
+
totalCasos: valor.totalCasos,
|
|
196
|
+
selladosHumano: valor.selladosHumano,
|
|
197
|
+
mutationsTotal: valor.mutationsTotal,
|
|
198
|
+
promptInjectionsTotal: valor.promptInjectionsTotal,
|
|
199
|
+
pass: valor.pass,
|
|
200
|
+
fail: valor.fail,
|
|
201
|
+
porCategoria,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function validarFailures(lista) {
|
|
206
|
+
if (!Array.isArray(lista)) fallar('VERDICT_EMISION_INVALIDA', 'failures inválido');
|
|
207
|
+
return congelarProfundo(lista.map((entrada, indice) => {
|
|
208
|
+
validarClaves(entrada, FAILURE_KEYS, `failures[${indice}]`);
|
|
209
|
+
if (typeof entrada.casoId !== 'string' || !CASO_ID.test(entrada.casoId)) {
|
|
210
|
+
fallar('VERDICT_EMISION_INVALIDA', `failures[${indice}].casoId inválido`);
|
|
211
|
+
}
|
|
212
|
+
if (!CATEGORIA_SET.has(entrada.categoria)) {
|
|
213
|
+
fallar('VERDICT_EMISION_INVALIDA', `failures[${indice}].categoria inválido`);
|
|
214
|
+
}
|
|
215
|
+
if (!NOMBRE_DIMENSION_SET.has(entrada.dimension)) {
|
|
216
|
+
fallar('VERDICT_EMISION_INVALIDA', `failures[${indice}].dimension inválido`);
|
|
217
|
+
}
|
|
218
|
+
return { casoId: entrada.casoId, categoria: entrada.categoria, dimension: entrada.dimension };
|
|
219
|
+
}));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Compara la matriz DECLARADA en el request contra la matriz efectivamente
|
|
223
|
+
// scoreada (matrixEntries del ScoringReport, derivada de replayReports) como
|
|
224
|
+
// MULTICONJUNTO por runtime|os|model (reusa `claveMatrixEntry`, definido abajo).
|
|
225
|
+
// Cierra el hueco de que el badge anuncie una matriz distinta a la evaluada: el
|
|
226
|
+
// candidato declara la matriz en su request, pero la fuente de verdad de lo
|
|
227
|
+
// certificado es lo que realmente se replayó/scoreó, no lo que el candidato dice.
|
|
228
|
+
function mismasMatrices(declarada, evaluada) {
|
|
229
|
+
const a = declarada.map(claveMatrixEntry).sort();
|
|
230
|
+
const b = evaluada.map(claveMatrixEntry).sort();
|
|
231
|
+
return a.length === b.length && a.every((clave, indice) => clave === b[indice]);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
// emitirVeredicto — ScoringReport + CertificationRequest + insumos -> Verdict
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
|
|
238
|
+
function emitirVeredicto(scoringReport, certificationRequest, insumos) {
|
|
239
|
+
// Re-validación: el emisor no confía en la forma de lo que recibe, aunque
|
|
240
|
+
// venga de módulos hermanos ya validados en su propio boundary.
|
|
241
|
+
const reporte = validateScoringReport(scoringReport);
|
|
242
|
+
const solicitud = validateCertificationRequest(certificationRequest);
|
|
243
|
+
|
|
244
|
+
if (!esObjetoPlano(insumos) || (insumos.modo !== 'dev' && insumos.modo !== 'real')) {
|
|
245
|
+
fallar('VERDICT_EMISION_INVALIDA', 'insumos.modo debe ser "dev" o "real"');
|
|
246
|
+
}
|
|
247
|
+
const clavesEsperadas = insumos.modo === 'real' ? INSUMOS_KEYS_REAL : INSUMOS_KEYS_DEV;
|
|
248
|
+
validarClaves(insumos, clavesEsperadas, 'insumos');
|
|
249
|
+
|
|
250
|
+
if (typeof insumos.runId !== 'string' || !IDENTIFICADOR.test(insumos.runId)) {
|
|
251
|
+
fallar('VERDICT_EMISION_INVALIDA', 'insumos.runId inválido');
|
|
252
|
+
}
|
|
253
|
+
validarTimestampIso(insumos.emitidoEn, 'insumos.emitidoEn');
|
|
254
|
+
|
|
255
|
+
const corpusAgregados = validarCorpusAgregados(insumos.corpusAgregados);
|
|
256
|
+
const failures = validarFailures(insumos.failures);
|
|
257
|
+
|
|
258
|
+
// Binding matriz declarada ↔ evaluada: la matriz que el badge certificará
|
|
259
|
+
// (request.matrix) debe coincidir exactamente con la que realmente se scoreó
|
|
260
|
+
// (reporte.matrixEntries). Sin esto, un candidato podría declarar una matriz y
|
|
261
|
+
// hacer certificar otra. Fail-closed antes de emitir.
|
|
262
|
+
if (!mismasMatrices(solicitud.matrix, reporte.matrixEntries)) {
|
|
263
|
+
fallar('VERDICT_EMISION_INVALIDA', 'request.matrix no coincide con la matriz efectivamente scoreada (matrixEntries)');
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const dimensiones = reporte.dimensiones.map(crearDimensionVerdict);
|
|
267
|
+
const metaSlo = crearDimensionVerdict(reporte.metaSlo);
|
|
268
|
+
const metadata = construirMetadata(reporte.metaSlo);
|
|
269
|
+
|
|
270
|
+
let firma;
|
|
271
|
+
if (insumos.modo === 'dev') {
|
|
272
|
+
firma = Object.freeze({ modo: 'dev', tipo: 'no-certificante', nota: NOTA_DEV });
|
|
273
|
+
} else {
|
|
274
|
+
if (typeof insumos.bundleDigest !== 'string' || !SHA256.test(insumos.bundleDigest)) {
|
|
275
|
+
fallar('VERDICT_EMISION_INVALIDA', 'insumos.bundleDigest inválido');
|
|
276
|
+
}
|
|
277
|
+
firma = Object.freeze({ modo: 'real', tipo: 'certificante', bundleDigest: insumos.bundleDigest });
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const verdict = congelarProfundo({
|
|
281
|
+
kind: 'swl-certification-verdict',
|
|
282
|
+
schemaVersion: SCHEMA_VERSION,
|
|
283
|
+
runId: insumos.runId,
|
|
284
|
+
request: {
|
|
285
|
+
commit: solicitud.candidate.commit,
|
|
286
|
+
tarballDigest: solicitud.candidate.tarballDigest,
|
|
287
|
+
matrix: solicitud.matrix.map((entrada) => ({ ...entrada })),
|
|
288
|
+
},
|
|
289
|
+
certifica: reporte.certifica, // COPIA LITERAL — nunca se recomputa ni se eleva.
|
|
290
|
+
dimensiones,
|
|
291
|
+
metaSlo,
|
|
292
|
+
metadata,
|
|
293
|
+
corpusAgregados,
|
|
294
|
+
failures,
|
|
295
|
+
firma,
|
|
296
|
+
emitidoEn: insumos.emitidoEn,
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
return validateCertificationVerdict(verdict);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ---------------------------------------------------------------------------
|
|
303
|
+
// validateCertificationVerdict — validador oficial sin efectos.
|
|
304
|
+
// ---------------------------------------------------------------------------
|
|
305
|
+
|
|
306
|
+
function validarMatrixEntry(entry, etiqueta) {
|
|
307
|
+
validarClaves(entry, MATRIX_ENTRY_KEYS, etiqueta, 'CERTIFICATION_VERDICT_INVALID');
|
|
308
|
+
if (typeof entry.runtime !== 'string' || !RUNTIMES_CORE3.has(entry.runtime)) {
|
|
309
|
+
fallar('CERTIFICATION_VERDICT_INVALID', `${etiqueta}.runtime inválido`);
|
|
310
|
+
}
|
|
311
|
+
if (typeof entry.os !== 'string' || !OS_CORE3.has(entry.os)) {
|
|
312
|
+
fallar('CERTIFICATION_VERDICT_INVALID', `${etiqueta}.os inválido`);
|
|
313
|
+
}
|
|
314
|
+
if (typeof entry.model !== 'string' || !IDENTIFICADOR.test(entry.model)) {
|
|
315
|
+
fallar('CERTIFICATION_VERDICT_INVALID', `${etiqueta}.model inválido`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Mismo criterio de identidad que claveMatrixEntry() de
|
|
320
|
+
// w4-verificar-veredicto.js (sin NFKC aquí: en este boundary runtime/os/model
|
|
321
|
+
// ya pasaron por validarMatrixEntry — enum + IDENTIFICADOR ASCII — así que la
|
|
322
|
+
// normalización Unicode no aporta nada adicional).
|
|
323
|
+
function claveMatrixEntry(entrada) {
|
|
324
|
+
return `${entrada.runtime}|${entrada.os}|${entrada.model}`;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function validarRequestVerdict(request) {
|
|
328
|
+
validarClaves(request, REQUEST_KEYS, 'request', 'CERTIFICATION_VERDICT_INVALID');
|
|
329
|
+
if (typeof request.commit !== 'string' || !/^[a-f0-9]{40}$/u.test(request.commit)) {
|
|
330
|
+
fallar('CERTIFICATION_VERDICT_INVALID', 'request.commit inválido');
|
|
331
|
+
}
|
|
332
|
+
if (typeof request.tarballDigest !== 'string' || !SHA256.test(request.tarballDigest)) {
|
|
333
|
+
fallar('CERTIFICATION_VERDICT_INVALID', 'request.tarballDigest inválido');
|
|
334
|
+
}
|
|
335
|
+
if (!Array.isArray(request.matrix) || request.matrix.length === 0) {
|
|
336
|
+
fallar('CERTIFICATION_VERDICT_INVALID', 'request.matrix inválido');
|
|
337
|
+
}
|
|
338
|
+
request.matrix.forEach((entry, i) => validarMatrixEntry(entry, `request.matrix[${i}]`));
|
|
339
|
+
|
|
340
|
+
// Drift schema-vs-validador: el schema declara `request.matrix` con
|
|
341
|
+
// `uniqueItems: true` — se enforza también aquí (mismo criterio de clave
|
|
342
|
+
// que el verificador).
|
|
343
|
+
const clavesVistas = new Set();
|
|
344
|
+
for (const entry of request.matrix) {
|
|
345
|
+
const clave = claveMatrixEntry(entry);
|
|
346
|
+
if (clavesVistas.has(clave)) {
|
|
347
|
+
fallar('CERTIFICATION_VERDICT_INVALID', 'request.matrix con entradas duplicadas');
|
|
348
|
+
}
|
|
349
|
+
clavesVistas.add(clave);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function esEscalarValido(valor) {
|
|
354
|
+
// Un número escalar del veredicto debe ser FINITO: NaN/Infinity se serializan a
|
|
355
|
+
// `null` en I-JSON y corromperían silenciosamente el dato (fail-open de C5).
|
|
356
|
+
if (typeof valor === 'number') return Number.isFinite(valor);
|
|
357
|
+
return typeof valor === 'boolean' || typeof valor === 'string';
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function esMedidoValido(valor) {
|
|
361
|
+
if (valor === null) return true;
|
|
362
|
+
if (typeof valor === 'number') return Number.isFinite(valor);
|
|
363
|
+
if (!esObjetoPlano(valor)) return false;
|
|
364
|
+
return Object.values(valor).every((v) => typeof v === 'number' && Number.isFinite(v));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function validarDimensionVerdict(valor, etiqueta, nombreEsperado) {
|
|
368
|
+
validarClaves(valor, DIMENSION_VERDICT_KEYS, etiqueta, 'CERTIFICATION_VERDICT_INVALID');
|
|
369
|
+
if (nombreEsperado ? valor.dimension !== nombreEsperado : !NOMBRE_DIMENSION_SET.has(valor.dimension)) {
|
|
370
|
+
fallar('CERTIFICATION_VERDICT_INVALID', `${etiqueta}.dimension inválido`);
|
|
371
|
+
}
|
|
372
|
+
if (typeof valor.slo !== 'string' || valor.slo.length === 0) {
|
|
373
|
+
fallar('CERTIFICATION_VERDICT_INVALID', `${etiqueta}.slo inválido`);
|
|
374
|
+
}
|
|
375
|
+
if (!esMedidoValido(valor.medido)) fallar('CERTIFICATION_VERDICT_INVALID', `${etiqueta}.medido inválido`);
|
|
376
|
+
if (typeof valor.pass !== 'boolean') fallar('CERTIFICATION_VERDICT_INVALID', `${etiqueta}.pass inválido`);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function validarMetadataVerdict(metadata) {
|
|
380
|
+
validarClaves(metadata, METADATA_KEYS, 'metadata', 'CERTIFICATION_VERDICT_INVALID');
|
|
381
|
+
for (const clave of METADATA_KEYS) {
|
|
382
|
+
const bloque = metadata[clave];
|
|
383
|
+
if (bloque === null) continue;
|
|
384
|
+
if (!esObjetoPlano(bloque)) fallar('CERTIFICATION_VERDICT_INVALID', `metadata.${clave} inválido`);
|
|
385
|
+
for (const valor of Object.values(bloque)) {
|
|
386
|
+
if (!esEscalarValido(valor)) {
|
|
387
|
+
fallar('CERTIFICATION_VERDICT_INVALID', `metadata.${clave} contiene un valor no escalar o no finito`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function validarFirmaVerdict(firma) {
|
|
394
|
+
if (!esObjetoPlano(firma) || (firma.modo !== 'dev' && firma.modo !== 'real')) {
|
|
395
|
+
fallar('CERTIFICATION_VERDICT_INVALID', 'firma.modo inválido');
|
|
396
|
+
}
|
|
397
|
+
if (firma.modo === 'dev') {
|
|
398
|
+
validarClaves(firma, ['modo', 'tipo', 'nota'], 'firma', 'CERTIFICATION_VERDICT_INVALID');
|
|
399
|
+
if (firma.tipo !== 'no-certificante') fallar('CERTIFICATION_VERDICT_INVALID', 'firma.tipo inválido');
|
|
400
|
+
if (firma.nota !== NOTA_DEV) fallar('CERTIFICATION_VERDICT_INVALID', 'firma.nota inválido');
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
validarClaves(firma, ['modo', 'tipo', 'bundleDigest'], 'firma', 'CERTIFICATION_VERDICT_INVALID');
|
|
404
|
+
if (firma.tipo !== 'certificante') fallar('CERTIFICATION_VERDICT_INVALID', 'firma.tipo inválido');
|
|
405
|
+
if (typeof firma.bundleDigest !== 'string' || !SHA256.test(firma.bundleDigest)) {
|
|
406
|
+
fallar('CERTIFICATION_VERDICT_INVALID', 'firma.bundleDigest inválido');
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Valida un `CertificationVerdict` (ADR-0053, REQ-32-06) sin efectos: no lee
|
|
412
|
+
* disco, no hace red, no consulta el reloj. Lanza `CERTIFICATION_VERDICT_INVALID`
|
|
413
|
+
* si el valor no cumple `schemas/w4-certification-verdict.schema.json` o sus
|
|
414
|
+
* `runtimeOnlyChecks`; retorna un valor deeply frozen equivalente si es válido.
|
|
415
|
+
*/
|
|
416
|
+
function validateCertificationVerdict(value) {
|
|
417
|
+
validarClaves(value, VERDICT_KEYS, 'certificationVerdict', 'CERTIFICATION_VERDICT_INVALID');
|
|
418
|
+
if (value.kind !== 'swl-certification-verdict') fallar('CERTIFICATION_VERDICT_INVALID', 'kind inválido');
|
|
419
|
+
if (value.schemaVersion !== SCHEMA_VERSION) fallar('CERTIFICATION_VERDICT_INVALID', 'schemaVersion inválida');
|
|
420
|
+
if (typeof value.runId !== 'string' || !IDENTIFICADOR.test(value.runId)) {
|
|
421
|
+
fallar('CERTIFICATION_VERDICT_INVALID', 'runId inválido');
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
validarRequestVerdict(value.request);
|
|
425
|
+
|
|
426
|
+
if (typeof value.certifica !== 'boolean') fallar('CERTIFICATION_VERDICT_INVALID', 'certifica inválido');
|
|
427
|
+
|
|
428
|
+
if (!Array.isArray(value.dimensiones) || value.dimensiones.length !== 6) {
|
|
429
|
+
fallar('CERTIFICATION_VERDICT_INVALID', 'dimensiones inválido');
|
|
430
|
+
}
|
|
431
|
+
value.dimensiones.forEach((d, i) => validarDimensionVerdict(d, `dimensiones[${i}]`));
|
|
432
|
+
const nombresRecibidos = [...value.dimensiones.map((d) => d.dimension)].sort();
|
|
433
|
+
const nombresEsperados = [...NOMBRES_DIMENSIONES].sort();
|
|
434
|
+
if (JSON.stringify(nombresRecibidos) !== JSON.stringify(nombresEsperados)) {
|
|
435
|
+
fallar('CERTIFICATION_VERDICT_INVALID', 'dimensiones no cubre exactamente las 6 de ADR-0050 sin duplicados ni faltantes');
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
validarDimensionVerdict(value.metaSlo, 'metaSlo', NOMBRE_META_SLO);
|
|
439
|
+
validarMetadataVerdict(value.metadata);
|
|
440
|
+
validarCorpusAgregados(value.corpusAgregados);
|
|
441
|
+
validarFailures(value.failures);
|
|
442
|
+
validarFirmaVerdict(value.firma);
|
|
443
|
+
validarTimestampIso(value.emitidoEn, 'emitidoEn');
|
|
444
|
+
|
|
445
|
+
return congelarProfundo(JSON.parse(JSON.stringify(value)));
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
module.exports = {
|
|
449
|
+
NOTA_DEV,
|
|
450
|
+
emitirVeredicto,
|
|
451
|
+
validateCertificationVerdict,
|
|
452
|
+
};
|