@daniellins/power-claude 0.16.3
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.
Potentially problematic release.
This version of @daniellins/power-claude might be problematic. Click here for more details.
- package/LICENSE +21 -0
- package/README.md +121 -0
- package/bin/cli.js +124 -0
- package/installer/__tests__/doctor-ready-oracles.test.cjs +140 -0
- package/installer/__tests__/merge-settings.test.cjs +330 -0
- package/installer/adopt.js +161 -0
- package/installer/copy.js +203 -0
- package/installer/doctor.js +266 -0
- package/installer/install.js +155 -0
- package/installer/manifest.js +102 -0
- package/installer/motor-scripts.js +50 -0
- package/installer/motor-scripts.json +39 -0
- package/installer/uninstall.js +99 -0
- package/installer/update.js +376 -0
- package/installer/util.js +113 -0
- package/installer/wizard.js +64 -0
- package/package.json +26 -0
- package/scripts/__fixtures__/anti-path-demo/agents/ap-writer.md +13 -0
- package/scripts/__fixtures__/anti-path-demo/templates/write-tmpl.md +7 -0
- package/scripts/__fixtures__/anti-path-demo/workflows/wf-ap.smoke.json +10 -0
- package/scripts/__fixtures__/anti-path-demo/workflows/wf-ap.yaml +25 -0
- package/scripts/__fixtures__/assess-tier/retrofit-leve/pod/agents/content-chief.md +1 -0
- package/scripts/__fixtures__/assess-tier/retrofit-leve/pod/workflows/wf-criacao-redteam.yaml +3 -0
- package/scripts/__fixtures__/assess-tier/retrofit-leve/pod-spec.json +13 -0
- package/scripts/__fixtures__/fidelity/fake-green-average-in-band.yaml +21 -0
- package/scripts/__fixtures__/fidelity/fake-green-average.yaml +18 -0
- package/scripts/__fixtures__/fidelity/fake-green-denominator.yaml +19 -0
- package/scripts/__fixtures__/fidelity/fake-green-missing-evidence.yaml +18 -0
- package/scripts/__fixtures__/fidelity/fake-green-threshold.yaml +18 -0
- package/scripts/__fixtures__/fidelity/fake-green-weight.yaml +18 -0
- package/scripts/__fixtures__/fidelity/golden.yaml +31 -0
- package/scripts/__fixtures__/fidelity/trindade-incoherent.yaml +15 -0
- package/scripts/__fixtures__/forge-canonical/pod-spec-example.json +37 -0
- package/scripts/__fixtures__/migrate-squad/authored/agents/offer-engineer.md +17 -0
- package/scripts/__fixtures__/migrate-squad/authored/knowledge/no-source.md +7 -0
- package/scripts/__fixtures__/migrate-squad/authored/knowledge/value-stack-method.md +8 -0
- package/scripts/__fixtures__/migrate-squad/authored/specs/wf-sample.smoke.json +24 -0
- package/scripts/__fixtures__/migrate-squad/authored/specs/wf-sample.spec.json +45 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/HEADLINE.md +3 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/README.md +4 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/agents/hormozi-offer.md +14 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/checklists/dead-redundant.md +4 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/checklists/method-guide.md +6 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/checklists/veto-screen.md +4 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/config/config.yaml +2 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/data/case-library.md +3 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/scripts/validate-mvn.py +16 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/sops/sop-sample.md +3 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/squad-io.yaml +14 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/tasks/gather-context.md +7 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/templates/output-tmpl.md +5 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/workflows/wf-sample.yaml +24 -0
- package/scripts/__fixtures__/pipeline/pipelines/pipeline-checkpoint.yaml +21 -0
- package/scripts/__fixtures__/pipeline/pipelines/pipeline-demo.yaml +22 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-a/agents/maker.md +13 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-a/memory/learnings.consolidated.md +8 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-a/memory/learnings.jsonl +83 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-a/templates/make-tmpl.md +8 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-a/workflows/wf-a.yaml +16 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-b/agents/user.md +13 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-b/memory/learnings.consolidated.md +8 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-b/memory/learnings.jsonl +14 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-b/templates/use-tmpl.md +6 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-b/workflows/wf-b.yaml +16 -0
- package/scripts/__fixtures__/pod-run/agents/forge-chief.md +13 -0
- package/scripts/__fixtures__/pod-run/agents/pod-critic.md +13 -0
- package/scripts/__fixtures__/pod-run/templates/build-tmpl.md +8 -0
- package/scripts/__fixtures__/pod-run/templates/gate-tmpl.md +6 -0
- package/scripts/__fixtures__/pod-run/workflows/wf-min.yaml +43 -0
- package/scripts/__fixtures__/pod-run/workflows/wf-skip-modes.yaml +50 -0
- package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-all-skippable.yaml +30 -0
- package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-criteria-escalar-de-bloco.yaml +40 -0
- package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-skip-mode-desconhecido.yaml +30 -0
- package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-unknown-key.yaml +29 -0
- package/scripts/__fixtures__/pod-workflow/invalid-cycle.yaml +26 -0
- package/scripts/__fixtures__/pod-workflow/invalid-fix-loop-backedge.yaml +29 -0
- package/scripts/__fixtures__/pod-workflow/invalid-fix-loop-forward.yaml +29 -0
- package/scripts/__fixtures__/pod-workflow/invalid-handoff-open.yaml +27 -0
- package/scripts/__fixtures__/pod-workflow/invalid-knowledge-shape.yaml +18 -0
- package/scripts/__fixtures__/pod-workflow/invalid-missing-agent.yaml +15 -0
- package/scripts/__fixtures__/pod-workflow/invalid-missing-outputs.yaml +15 -0
- package/scripts/__fixtures__/pod-workflow/invalid-missing-template.yaml +15 -0
- package/scripts/__fixtures__/pod-workflow/invalid-missing-veto.yaml +13 -0
- package/scripts/__fixtures__/pod-workflow/invalid-template-not-on-disk.yaml +16 -0
- package/scripts/__fixtures__/pod-workflow/invalid-veto-prose.yaml +17 -0
- package/scripts/__fixtures__/pod-workflow/knowledge/a.md +4 -0
- package/scripts/__fixtures__/pod-workflow/knowledge/b.md +4 -0
- package/scripts/__fixtures__/pod-workflow/knowledge/c.md +4 -0
- package/scripts/__fixtures__/pod-workflow/templates/step-tmpl.md +7 -0
- package/scripts/__fixtures__/pod-workflow/valid-checkpoint-skip-modes.yaml +29 -0
- package/scripts/__fixtures__/pod-workflow/valid-fix-loop.yaml +30 -0
- package/scripts/__fixtures__/pod-workflow/valid-knowledge.yaml +30 -0
- package/scripts/__fixtures__/pod-workflow/valid-veto-always-true.yaml +20 -0
- package/scripts/__fixtures__/pod-workflow/valid.yaml +27 -0
- package/scripts/__fixtures__/smoke-canary/agents/canary-reporter.md +13 -0
- package/scripts/__fixtures__/smoke-canary/agents/canary-researcher.md +13 -0
- package/scripts/__fixtures__/smoke-canary/agents/canary-synth.md +13 -0
- package/scripts/__fixtures__/smoke-canary/memory/learnings.consolidated.md +10 -0
- package/scripts/__fixtures__/smoke-canary/memory/learnings.jsonl +448 -0
- package/scripts/__fixtures__/smoke-canary/templates/report-tmpl.md +9 -0
- package/scripts/__fixtures__/smoke-canary/templates/research-tmpl.md +7 -0
- package/scripts/__fixtures__/smoke-canary/templates/synth-tmpl.md +9 -0
- package/scripts/__fixtures__/smoke-canary/workflows/wf-canary.smoke.json +11 -0
- package/scripts/__fixtures__/smoke-canary/workflows/wf-canary.yaml +53 -0
- package/scripts/__fixtures__/source-audit/fake-green-bronze-unsignaled.yaml +10 -0
- package/scripts/__fixtures__/source-audit/fake-green-counts.yaml +9 -0
- package/scripts/__fixtures__/source-audit/fake-green-missing-evidence.yaml +9 -0
- package/scripts/__fixtures__/source-audit/fake-green-unclassified.yaml +10 -0
- package/scripts/__fixtures__/source-audit/fake-green-verdict.yaml +10 -0
- package/scripts/__fixtures__/source-audit/golden-blocked.yaml +10 -0
- package/scripts/__fixtures__/source-audit/golden.yaml +11 -0
- package/scripts/__fixtures__/sweep-forms/agents/forms-count.md +13 -0
- package/scripts/__fixtures__/sweep-forms/agents/forms-field.md +13 -0
- package/scripts/__fixtures__/sweep-forms/agents/forms-fileref.md +13 -0
- package/scripts/__fixtures__/sweep-forms/agents/forms-json.md +13 -0
- package/scripts/__fixtures__/sweep-forms/agents/forms-section.md +13 -0
- package/scripts/__fixtures__/sweep-forms/specs/wf-forms.spec.json +5 -0
- package/scripts/__fixtures__/sweep-forms/templates/t_count.md +5 -0
- package/scripts/__fixtures__/sweep-forms/templates/t_field.md +3 -0
- package/scripts/__fixtures__/sweep-forms/templates/t_fileref.md +3 -0
- package/scripts/__fixtures__/sweep-forms/templates/t_json.md +0 -0
- package/scripts/__fixtures__/sweep-forms/templates/t_section.md +3 -0
- package/scripts/__fixtures__/sweep-forms/workflows/wf-forms.smoke.json +13 -0
- package/scripts/__fixtures__/sweep-forms/workflows/wf-forms.yaml +67 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-1-noop-state-json.fixture.md +18 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-2-crash-buildworkflowyaml.fixture.md +26 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-3-nasce-verde-skip-modes.fixture.md +29 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-4-guarda-sem-irmao.fixture.md +17 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-5a-diff-stat-sem-guarda.fixture.md +17 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-5b-test-f-sobre-diretorio.fixture.md +20 -0
- package/scripts/__fixtures__/veto-checks/copy-clean.md +4 -0
- package/scripts/__fixtures__/veto-checks/copy-dashes.md +4 -0
- package/scripts/__fixtures__/veto-checks/n8n-bad.md +18 -0
- package/scripts/__fixtures__/veto-checks/n8n-ok.md +22 -0
- package/scripts/__fixtures__/veto-checks/page-bad.html +7 -0
- package/scripts/__fixtures__/veto-checks/phash/copy.png +0 -0
- package/scripts/__fixtures__/veto-checks/phash/distinct.png +0 -0
- package/scripts/__fixtures__/veto-checks/phash/distinct2.png +0 -0
- package/scripts/__fixtures__/veto-checks/phash/make-fixtures.cjs +203 -0
- package/scripts/__fixtures__/veto-checks/phash/ref.png +0 -0
- package/scripts/__fixtures__/veto-checks/slide-ok.html +15 -0
- package/scripts/__fixtures__/veto-checks/slide-overflow.html +14 -0
- package/scripts/__fixtures__/veto-checks/sweep-pod/agents/vc-checker.md +13 -0
- package/scripts/__fixtures__/veto-checks/sweep-pod/templates/check-tmpl.md +6 -0
- package/scripts/__fixtures__/veto-checks/sweep-pod/workflows/wf-vc.smoke.json +10 -0
- package/scripts/__fixtures__/veto-checks/sweep-pod/workflows/wf-vc.yaml +19 -0
- package/scripts/__fixtures__/voz-do-dono/README.md +23 -0
- package/scripts/__fixtures__/voz-do-dono/dono-escalar.yaml +9 -0
- package/scripts/__fixtures__/voz-do-dono/dono-guia.yaml +10 -0
- package/scripts/__fixtures__/voz-do-dono/peca-3a-pessoa.md +6 -0
- package/scripts/__fixtures__/voz-do-dono/peca-com-lexico-proibido.md +6 -0
- package/scripts/__fixtures__/voz-do-dono/peca-limpa-1a-pessoa.md +6 -0
- package/scripts/__tests__/derive-ready-transitions.test.cjs +269 -0
- package/scripts/__tests__/enforce-cycle-authority.test.cjs +869 -0
- package/scripts/__tests__/enforce-git-push-authority.test.cjs +701 -0
- package/scripts/__tests__/enforce-ready-oracles.test.cjs +745 -0
- package/scripts/__tests__/motor-scripts.test.cjs +339 -0
- package/scripts/__tests__/pc-run-pod-counter.test.cjs +58 -0
- package/scripts/__tests__/pc-run-pod.test.cjs +578 -0
- package/scripts/__tests__/validate-pod-workflow.test.cjs +90 -0
- package/scripts/__tests__/validate-story-acs.test.cjs +607 -0
- package/scripts/anti-path.test.cjs +163 -0
- package/scripts/arena.cjs +514 -0
- package/scripts/arena.test.cjs +213 -0
- package/scripts/brief-leitura-obrigatoria.test.cjs +364 -0
- package/scripts/consolidate-knowledge-runner.test.cjs +249 -0
- package/scripts/default-funcional.test.cjs +153 -0
- package/scripts/derive-ready-transitions.cjs +325 -0
- package/scripts/forge-additive.test.cjs +158 -0
- package/scripts/forge-assess-tier.cjs +205 -0
- package/scripts/forge-assess-tier.test.cjs +114 -0
- package/scripts/forge-canonical.test.cjs +624 -0
- package/scripts/forge-generate.cjs +1303 -0
- package/scripts/forge-harden-learning.cjs +921 -0
- package/scripts/forge-harden-learning.test.cjs +242 -0
- package/scripts/forge-ingest-memory.cjs +136 -0
- package/scripts/forge-upgrade-pod.cjs +368 -0
- package/scripts/forge.test.cjs +609 -0
- package/scripts/harden-knowledge.test.cjs +612 -0
- package/scripts/harness-g5-lite.cjs +243 -0
- package/scripts/harness-g5-lite.test.cjs +134 -0
- package/scripts/hn-carousel-contrato-entrada.test.cjs +96 -0
- package/scripts/migrate-squad-orchestration.test.cjs +146 -0
- package/scripts/migration-manifest-sf3.2.test.cjs +382 -0
- package/scripts/migration-manifest-sf3.3.test.cjs +170 -0
- package/scripts/migration-manifest-sf5.5.test.cjs +189 -0
- package/scripts/migration-manifest.cjs +1146 -0
- package/scripts/migration-manifest.test.cjs +186 -0
- package/scripts/npm-scope-invocation.test.cjs +194 -0
- package/scripts/owner-layer.cjs +442 -0
- package/scripts/owner-layer.test.cjs +358 -0
- package/scripts/pc-run-pipeline.cjs +289 -0
- package/scripts/pc-run-pipeline.test.cjs +256 -0
- package/scripts/pc-run-pod-countgte.test.cjs +66 -0
- package/scripts/pc-run-pod.cjs +1355 -0
- package/scripts/phash-gate.test.cjs +433 -0
- package/scripts/pod-export-compile.cjs +487 -0
- package/scripts/pod-export-compile.test.cjs +312 -0
- package/scripts/pod-export-executor.cjs +678 -0
- package/scripts/pod-export-executor.test.cjs +1341 -0
- package/scripts/pod-export-hardening.test.cjs +531 -0
- package/scripts/pod-export-postprocess.cjs +427 -0
- package/scripts/pod-export-postprocess.test.cjs +558 -0
- package/scripts/pod-export-queue-race.test.cjs +865 -0
- package/scripts/pod-export-release.cjs +473 -0
- package/scripts/pod-export-release.test.cjs +267 -0
- package/scripts/pod-export-service.cjs +1297 -0
- package/scripts/pod-export-service.test.cjs +489 -0
- package/scripts/pod-export-tools.cjs +470 -0
- package/scripts/pod-export-ui.cjs +805 -0
- package/scripts/pod-export-ui.test.cjs +301 -0
- package/scripts/pod-memory-budget.test.cjs +309 -0
- package/scripts/pod-memory-note.cjs +357 -0
- package/scripts/pod-memory-note.test.cjs +452 -0
- package/scripts/pod-memory.cjs +1252 -0
- package/scripts/pod-memory.test.cjs +951 -0
- package/scripts/render-png.test.cjs +307 -0
- package/scripts/smoke-isolation.test.cjs +100 -0
- package/scripts/smoke-pod-workflow.cjs +755 -0
- package/scripts/smoke-sweep.test.cjs +170 -0
- package/scripts/validate-adopt.js +235 -0
- package/scripts/validate-branding.js +84 -0
- package/scripts/validate-budgets.js +140 -0
- package/scripts/validate-fidelity-output.cjs +267 -0
- package/scripts/validate-fidelity-output.test.cjs +101 -0
- package/scripts/validate-install.js +230 -0
- package/scripts/validate-no-clone.cjs +220 -0
- package/scripts/validate-no-clone.test.cjs +77 -0
- package/scripts/validate-pipeline.cjs +145 -0
- package/scripts/validate-pod-workflow.cjs +878 -0
- package/scripts/validate-source-audit.cjs +170 -0
- package/scripts/validate-source-audit.test.cjs +90 -0
- package/scripts/validate-story-acs.cjs +862 -0
- package/scripts/validate-update-scope-motor.js +421 -0
- package/scripts/veto-checks/html-valid.cjs +92 -0
- package/scripts/veto-checks/lexical-check.cjs +62 -0
- package/scripts/veto-checks/phash-gate.cjs +589 -0
- package/scripts/veto-checks/render-gate.cjs +165 -0
- package/scripts/veto-checks/render-png.cjs +358 -0
- package/scripts/veto-checks.test.cjs +219 -0
- package/scripts/watcher-audit.cjs +178 -0
- package/template/.claude/CLAUDE.md +103 -0
- package/template/.claude/agents/pc-analyst.md +100 -0
- package/template/.claude/agents/pc-architect.md +32 -0
- package/template/.claude/agents/pc-dev.md +27 -0
- package/template/.claude/agents/pc-devops.md +45 -0
- package/template/.claude/agents/pc-planner.md +32 -0
- package/template/.claude/agents/pc-po.md +25 -0
- package/template/.claude/agents/pc-qa.md +25 -0
- package/template/.claude/commands/power/academy.md +9 -0
- package/template/.claude/commands/power/automation.md +9 -0
- package/template/.claude/commands/power/content-carousel.md +267 -0
- package/template/.claude/commands/power/content.md +9 -0
- package/template/.claude/commands/power/dev.md +9 -0
- package/template/.claude/commands/power/forge.md +224 -0
- package/template/.claude/commands/power/hormozi.md +221 -0
- package/template/.claude/commands/power/modo.md +57 -0
- package/template/.claude/hooks/README.md +114 -0
- package/template/.claude/hooks/context-budget.cjs +64 -0
- package/template/.claude/hooks/enforce-cycle-authority.cjs +457 -0
- package/template/.claude/hooks/enforce-git-push-authority.cjs +925 -0
- package/template/.claude/hooks/enforce-ready-oracles.cjs +502 -0
- package/template/.claude/rules/authority.md +76 -0
- package/template/.claude/rules/curadoria-de-conhecimento.md +30 -0
- package/template/.claude/rules/model-matrix.md +34 -0
- package/template/.claude/rules/orchestration.md +133 -0
- package/template/.claude/settings.json +50 -0
- package/template/.claude/skills/pc-apply-qa-fixes/SKILL.md +108 -0
- package/template/.claude/skills/pc-apply-qa-fixes/references/fix-loop.md +40 -0
- package/template/.claude/skills/pc-apply-qa-fixes/references/fix-request-template.md +70 -0
- package/template/.claude/skills/pc-arena/SKILL.md +96 -0
- package/template/.claude/skills/pc-close-story/SKILL.md +105 -0
- package/template/.claude/skills/pc-commit/SKILL.md +108 -0
- package/template/.claude/skills/pc-develop-story/SKILL.md +116 -0
- package/template/.claude/skills/pc-full-cycle/SKILL.md +150 -0
- package/template/.claude/skills/pc-pipeline/SKILL.md +63 -0
- package/template/.claude/skills/pc-pipeline/references/gate-templates.md +46 -0
- package/template/.claude/skills/pc-review-story/SKILL.md +129 -0
- package/template/.claude/skills/pc-review-story/references/false-positive-detection.md +50 -0
- package/template/.claude/skills/pc-review-story/references/nfr-assess.md +47 -0
- package/template/.claude/skills/pc-review-story/references/risk-profile.md +75 -0
- package/template/.claude/skills/pc-review-story/references/security-checklist.md +69 -0
- package/template/.claude/skills/pc-review-story/references/test-design.md +37 -0
- package/template/.claude/skills/pc-review-story/references/trace-requirements.md +46 -0
- package/template/.claude/skills/pc-run-pod/SKILL.md +123 -0
- package/template/.claude/skills/pc-validate-story/SKILL.md +114 -0
- package/template/.claude/skills/pc-wave/SKILL.md +133 -0
- package/template/.env.example +10 -0
- package/template/knowledge/analyst/brainstorming.md +40 -0
- package/template/knowledge/analyst/brief-skeleton.md +32 -0
- package/template/knowledge/analyst/competitor-skeleton.md +39 -0
- package/template/knowledge/analyst/elicitation-menu.md +49 -0
- package/template/knowledge/analyst/market-research-skeleton.md +36 -0
- package/template/knowledge/analyst/research-prompt-structure.md +48 -0
- package/template/knowledge/analyst/roi-skeleton.md +51 -0
- package/template/knowledge/voice-dna/README.md +99 -0
- package/template/knowledge/voice-dna/voice-dna.example.yaml +157 -0
- package/template/pods/README.md +64 -0
- package/template/pods/academy/README.md +37 -0
- package/template/pods/academy/agents/academy-chief.md +27 -0
- package/template/pods/academy/examples/palestra.example.md +142 -0
- package/template/pods/academy/pod-spec.json +44 -0
- package/template/pods/academy/templates/materiais-tmpl.md +17 -0
- package/template/pods/academy/templates/revisao-didatica-tmpl.md +20 -0
- package/template/pods/academy/workflows/wf-materiais-revisao.yaml +30 -0
- package/template/pods/authority-content/README.md +43 -0
- package/template/pods/authority-content/agents/content-chief.md +28 -0
- package/template/pods/authority-content/pod-spec.json +45 -0
- package/template/pods/authority-content/templates/criacao-na-voz-tmpl.md +17 -0
- package/template/pods/authority-content/templates/red-team-factual-tmpl.md +23 -0
- package/template/pods/authority-content/workflows/wf-criacao-redteam.yaml +30 -0
- package/template/pods/automation/README.md +37 -0
- package/template/pods/automation/agents/langgraph-architect.md +30 -0
- package/template/pods/automation/agents/n8n-architect.md +30 -0
- package/template/pods/automation/examples/README.md +46 -0
- package/template/pods/automation/examples/n8n-content-radar.example.json +380 -0
- package/template/pods/automation/knowledge/langgraph-patterns.md +126 -0
- package/template/pods/automation/knowledge/n8n-patterns.md +131 -0
- package/template/pods/automation/memory/README.md +16 -0
- package/template/pods/automation/memory/learnings.consolidated.md +8 -0
- package/template/pods/automation/memory/learnings.jsonl +0 -0
- package/template/pods/automation/pod-spec.json +109 -0
- package/template/pods/automation/specs/wf-langgraph-build.spec.json +107 -0
- package/template/pods/automation/squad-io.yaml +28 -0
- package/template/pods/automation/templates/lg-build-tmpl.md +17 -0
- package/template/pods/automation/templates/lg-design-tmpl.md +23 -0
- package/template/pods/automation/templates/lg-discover-tmpl.md +20 -0
- package/template/pods/automation/templates/lg-handoff-tmpl.md +20 -0
- package/template/pods/automation/templates/lg-test-tmpl.md +20 -0
- package/template/pods/automation/templates/n8n-build-tmpl.md +14 -0
- package/template/pods/automation/templates/n8n-design-tmpl.md +23 -0
- package/template/pods/automation/templates/n8n-discover-tmpl.md +20 -0
- package/template/pods/automation/templates/n8n-handoff-tmpl.md +20 -0
- package/template/pods/automation/templates/n8n-test-tmpl.md +20 -0
- package/template/pods/automation/workflows/wf-langgraph-build.smoke.json +11 -0
- package/template/pods/automation/workflows/wf-langgraph-build.yaml +64 -0
- package/template/pods/automation/workflows/wf-n8n-build.smoke.json +11 -0
- package/template/pods/automation/workflows/wf-n8n-build.yaml +65 -0
- package/template/pods/content-carousel/README.md +91 -0
- package/template/pods/content-carousel/agents/carousel-builder.md +28 -0
- package/template/pods/content-carousel/agents/carousel-visual.md +24 -0
- package/template/pods/content-carousel/agents/hn-curator.md +74 -0
- package/template/pods/content-carousel/config/heuristic-watcher-rubric.yaml +59 -0
- package/template/pods/content-carousel/knowledge/aquisicao-ancora.md +443 -0
- package/template/pods/content-carousel/knowledge/cta-brief.md +25 -0
- package/template/pods/content-carousel/knowledge/dono.example.yaml +45 -0
- package/template/pods/content-carousel/knowledge/identidade-visual-mascote.md +62 -0
- package/template/pods/content-carousel/knowledge/image-generation.md +62 -0
- package/template/pods/content-carousel/knowledge/selecao-de-ancora.md +60 -0
- package/template/pods/content-carousel/knowledge/slides-html.md +56 -0
- package/template/pods/content-carousel/memory/README.md +18 -0
- package/template/pods/content-carousel/memory/learnings.consolidated.md +6 -0
- package/template/pods/content-carousel/memory/learnings.jsonl +0 -0
- package/template/pods/content-carousel/pod-spec.json +100 -0
- package/template/pods/content-carousel/squad-io.yaml +10 -0
- package/template/pods/content-carousel/templates/assembly-tmpl.md +23 -0
- package/template/pods/content-carousel/templates/digest-tmpl.md +29 -0
- package/template/pods/content-carousel/templates/visuals-tmpl.md +20 -0
- package/template/pods/content-carousel/workflows/wf-content-carousel.smoke.json +23 -0
- package/template/pods/content-carousel/workflows/wf-content-carousel.yaml +80 -0
- package/template/pods/dev-ia/README.md +45 -0
- package/template/pods/dev-ia/agents/db-architect.md +33 -0
- package/template/pods/dev-ia/agents/ux-architect.md +29 -0
- package/template/pods/dev-ia/knowledge/db/migration-protocol.md +95 -0
- package/template/pods/dev-ia/knowledge/db/rls-patterns.md +101 -0
- package/template/pods/dev-ia/knowledge/db/schema-review-checklist.md +76 -0
- package/template/pods/dev-ia/memory/README.md +16 -0
- package/template/pods/dev-ia/memory/learnings.consolidated.md +8 -0
- package/template/pods/dev-ia/memory/learnings.jsonl +0 -0
- package/template/pods/dev-ia/pod-spec.json +34 -0
- package/template/pods/dev-ia/templates/schema-review-tmpl.md +23 -0
- package/template/pods/dev-ia/templates/ux-flow-review-tmpl.md +23 -0
- package/template/pods/dev-ia/tools/db-ops/backup-manager.sh +321 -0
- package/template/pods/dev-ia/tools/db-ops/best-practices-auditor.sh +534 -0
- package/template/pods/dev-ia/tools/db-ops/bootstrap-runner.sh +255 -0
- package/template/pods/dev-ia/tools/db-ops/data-loader.sh +616 -0
- package/template/pods/dev-ia/tools/db-ops/detect-database.sh +113 -0
- package/template/pods/dev-ia/tools/db-ops/explain-analyzer.sh +285 -0
- package/template/pods/dev-ia/tools/db-ops/health-checker.sh +323 -0
- package/template/pods/dev-ia/tools/db-ops/migration-runner.sh +308 -0
- package/template/pods/dev-ia/tools/db-ops/postgresql-schema-loader.sh +334 -0
- package/template/pods/dev-ia/tools/db-ops/query-runner.sh +171 -0
- package/template/pods/dev-ia/tools/db-ops/rls-policy-installer.sh +480 -0
- package/template/pods/dev-ia/tools/db-ops/rls-test-suite.sh +172 -0
- package/template/pods/dev-ia/tools/db-ops/schema-context-loader.sh +176 -0
- package/template/pods/hormozi-method/README.md +52 -0
- package/template/pods/hormozi-method/agents/acquisition-strategist.md +33 -0
- package/template/pods/hormozi-method/agents/conversion-copywriter.md +34 -0
- package/template/pods/hormozi-method/agents/monetization-architect.md +35 -0
- package/template/pods/hormozi-method/agents/offer-engineer.md +37 -0
- package/template/pods/hormozi-method/knowledge/core-four-leads.md +51 -0
- package/template/pods/hormozi-method/knowledge/grand-slam-offer.md +66 -0
- package/template/pods/hormozi-method/knowledge/growth-decision.md +38 -0
- package/template/pods/hormozi-method/knowledge/hooks-and-ads.md +56 -0
- package/template/pods/hormozi-method/knowledge/launch-email.md +31 -0
- package/template/pods/hormozi-method/knowledge/money-model.md +46 -0
- package/template/pods/hormozi-method/knowledge/opportunity-screening.md +44 -0
- package/template/pods/hormozi-method/knowledge/pages.md +25 -0
- package/template/pods/hormozi-method/knowledge/pos-lancamento-leads.md +56 -0
- package/template/pods/hormozi-method/knowledge/pricing.md +36 -0
- package/template/pods/hormozi-method/knowledge/retention-ltv.md +37 -0
- package/template/pods/hormozi-method/knowledge/scale-roadmap.md +35 -0
- package/template/pods/hormozi-method/knowledge/swipefiles-curados.md +44 -0
- package/template/pods/hormozi-method/knowledge/value-equation-diagnostic.md +77 -0
- package/template/pods/hormozi-method/memory/README.md +16 -0
- package/template/pods/hormozi-method/memory/learnings.consolidated.md +6 -0
- package/template/pods/hormozi-method/memory/learnings.jsonl +0 -0
- package/template/pods/hormozi-method/pod-spec.json +50 -0
- package/template/pods/hormozi-method/specs/wf-full-launch-sequence.spec.json +149 -0
- package/template/pods/hormozi-method/specs/wf-lead-magnet-pipeline.spec.json +125 -0
- package/template/pods/hormozi-method/specs/wf-money-model-design.spec.json +117 -0
- package/template/pods/hormozi-method/specs/wf-paid-ads-campaign.spec.json +132 -0
- package/template/pods/hormozi-method/specs/wf-scaling-diagnostic.spec.json +121 -0
- package/template/pods/hormozi-method/squad-io.yaml +43 -0
- package/template/pods/hormozi-method/templates/conversion-copywriter-tmpl.md +20 -0
- package/template/pods/hormozi-method/templates/launch-execucao-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/launch-fechamento-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/launch-pos-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/launch-preparacao-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/lm-copy-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/lm-distribuicao-tmpl.md +18 -0
- package/template/pods/hormozi-method/templates/lm-estrategia-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/mm-arquitetura-tmpl.md +18 -0
- package/template/pods/hormozi-method/templates/mm-copy-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/mm-diagnostico-tmpl.md +14 -0
- package/template/pods/hormozi-method/templates/monetization-architect-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/offer-engineer-tmpl.md +20 -0
- package/template/pods/hormozi-method/templates/paid-criativos-tmpl.md +19 -0
- package/template/pods/hormozi-method/templates/paid-fundacao-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/paid-teste-escala-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/scaling-diagnostico-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/scaling-priorizacao-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/scaling-roadmap-tmpl.md +17 -0
- package/template/pods/hormozi-method/workflows/wf-full-launch-sequence.smoke.json +12 -0
- package/template/pods/hormozi-method/workflows/wf-full-launch-sequence.yaml +56 -0
- package/template/pods/hormozi-method/workflows/wf-grand-slam-offer.smoke.json +11 -0
- package/template/pods/hormozi-method/workflows/wf-grand-slam-offer.yaml +45 -0
- package/template/pods/hormozi-method/workflows/wf-lead-magnet-pipeline.smoke.json +9 -0
- package/template/pods/hormozi-method/workflows/wf-lead-magnet-pipeline.yaml +45 -0
- package/template/pods/hormozi-method/workflows/wf-money-model-design.smoke.json +11 -0
- package/template/pods/hormozi-method/workflows/wf-money-model-design.yaml +45 -0
- package/template/pods/hormozi-method/workflows/wf-paid-ads-campaign.smoke.json +9 -0
- package/template/pods/hormozi-method/workflows/wf-paid-ads-campaign.yaml +46 -0
- package/template/pods/hormozi-method/workflows/wf-scaling-diagnostic.smoke.json +11 -0
- package/template/pods/hormozi-method/workflows/wf-scaling-diagnostic.yaml +44 -0
- package/template/pods/squad-forge/README.md +53 -0
- package/template/pods/squad-forge/agents/forge-chief.md +31 -0
- package/template/pods/squad-forge/agents/mind-extractor.md +29 -0
- package/template/pods/squad-forge/agents/pod-critic.md +26 -0
- package/template/pods/squad-forge/config/heuristic-watcher-rubric.yaml +74 -0
- package/template/pods/squad-forge/knowledge/fidelity-rubric.yaml +176 -0
- package/template/pods/squad-forge/knowledge/g6-memory-check.md +17 -0
- package/template/pods/squad-forge/knowledge/memory-ingest.md +16 -0
- package/template/pods/squad-forge/knowledge/source-audit-rubric.yaml +60 -0
- package/template/pods/squad-forge/memory/README.md +16 -0
- package/template/pods/squad-forge/memory/learnings.consolidated.md +8 -0
- package/template/pods/squad-forge/memory/learnings.jsonl +0 -0
- package/template/pods/squad-forge/pod-spec.json +166 -0
- package/template/pods/squad-forge/squad-io.yaml +13 -0
- package/template/pods/squad-forge/tasks/pipeline.md +158 -0
- package/template/pods/squad-forge/templates/discovery-tmpl.md +40 -0
- package/template/pods/squad-forge/templates/generation-tmpl.md +18 -0
- package/template/pods/squad-forge/templates/red-team-tmpl.md +17 -0
- package/template/pods/squad-forge/templates/register-tmpl.md +17 -0
- package/template/pods/squad-forge/templates/workflow-tmpl.yaml +101 -0
- package/template/pods/squad-forge/workflows/wf-forge.smoke.json +12 -0
- package/template/pods/squad-forge/workflows/wf-forge.yaml +60 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* arena.cjs — MOTOR determinístico da skill `pc-arena` (harness de comparação cega
|
|
5
|
+
* reutilizável). ADR-009 Decisão 1/2. Generaliza o protocolo do benchmark 4-braços
|
|
6
|
+
* (second-brain docs/benchmark/PROTOCOLO-4-bracos.md; RELATORIO-FINAL.md) para N≥2
|
|
7
|
+
* braços quaisquer.
|
|
8
|
+
*
|
|
9
|
+
* FRONTEIRA (ADR-002 reaplicada à AVALIAÇÃO): este motor faz o DETERMINÍSTICO e
|
|
10
|
+
* propenso-a-bug — permutação de rótulos com uniquidade validada (bijeção braço↔rótulo),
|
|
11
|
+
* mapa selado com permissão restrita (chmod 600), REVEAL-GATE (recusa revelar até todas
|
|
12
|
+
* as rodadas pontuadas), hash de congelamento de insumos, soma de tokens, e o veredito
|
|
13
|
+
* (diferença ≥ limiar sustentada em K de N; empate é resultado válido). A SKILL faz o
|
|
14
|
+
* JULGAMENTO/orquestração — brief verbatim, dispatch do operador fresco, notas 0-5 cegas.
|
|
15
|
+
* O motor NUNCA julga conteúdo, só recomputa e valida forma.
|
|
16
|
+
*
|
|
17
|
+
* Os 2 bugs reais da operação MANUAL em zsh viram fixture de regressão (arena.test.cjs):
|
|
18
|
+
* (bug 1) indexação 1-based portada p/ linguagem 0-based → braço perdido / rótulo
|
|
19
|
+
* undefined. Guarda: validatePermutation exige bijeção total (0-indexed).
|
|
20
|
+
* (bug 2) estado/contador perdido entre iterações → reveal-gate nunca destrava (ou
|
|
21
|
+
* destrava cedo). Guarda: fonte única em disco, escrita atômica, recarga fresca;
|
|
22
|
+
* o gate lê a CONTAGEM PERSISTIDA, não um contador em memória.
|
|
23
|
+
* NOTA de causa-raiz (Task 2/AC4): a mecânica zsh relatada (pipe|while perdendo contador)
|
|
24
|
+
* NÃO reproduz no zsh moderno (última etapa do pipe roda no shell atual); a CLASSE real e
|
|
25
|
+
* portável — "estado não persistido entre iterações/invocações" — reproduz no Node (alvo
|
|
26
|
+
* deste motor) e é o que a fixture trava. Divergência registrada no Dev Record da SF7.4.
|
|
27
|
+
*
|
|
28
|
+
* Uso (CLI): node scripts/arena.cjs <cmd> <expDir> [flags] — ver help() para os cmds.
|
|
29
|
+
* Node >= 18, sem dependências externas.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const fs = require('node:fs');
|
|
33
|
+
const os = require('node:os');
|
|
34
|
+
const path = require('node:path');
|
|
35
|
+
const crypto = require('node:crypto');
|
|
36
|
+
|
|
37
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
38
|
+
|
|
39
|
+
class ArenaError extends Error {}
|
|
40
|
+
function fail(msg) { throw new ArenaError(msg); }
|
|
41
|
+
|
|
42
|
+
// Rótulos cegos neutros (não ordenados como os braços A1..An).
|
|
43
|
+
const DEFAULT_LABELS = ['W', 'X', 'Y', 'Z', 'V', 'U', 'T', 'S', 'R', 'Q', 'P', 'N'];
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// PRNG determinístico (mulberry32) — permutação reprodutível por seed (testável).
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
function mulberry32(seed) {
|
|
49
|
+
let a = seed >>> 0;
|
|
50
|
+
return function () {
|
|
51
|
+
a |= 0; a = (a + 0x6D2B79F5) | 0;
|
|
52
|
+
let t = Math.imul(a ^ (a >>> 15), 1 | a);
|
|
53
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
54
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function seedFor(baseSeed, round) {
|
|
58
|
+
// Seed distinta e determinística por rodada (evita permutação idêntica acidental).
|
|
59
|
+
return (crypto.createHash('sha256').update(`${baseSeed}:${round}`).digest().readUInt32BE(0)) >>> 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Permutação e sua VALIDAÇÃO (guarda do bug-class 1: bijeção total, 0-indexed).
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
/** Fisher-Yates 0-indexed (guarda estrutural contra a indexação 1-based). */
|
|
66
|
+
function shuffle(arr, rnd) {
|
|
67
|
+
const a = arr.slice();
|
|
68
|
+
for (let i = a.length - 1; i > 0; i--) {
|
|
69
|
+
const j = Math.floor(rnd() * (i + 1)); // 0..i inclusive — nunca acessa a[len]
|
|
70
|
+
[a[i], a[j]] = [a[j], a[i]];
|
|
71
|
+
}
|
|
72
|
+
return a;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Gera o mapa rótulo→braço para uma rodada. N≥3 rejeita a permutação identidade (tell óbvio). */
|
|
76
|
+
function permute(arms, labels, seed) {
|
|
77
|
+
if (arms.length !== labels.length) {
|
|
78
|
+
fail(`permute: #braços (${arms.length}) != #rótulos (${labels.length})`);
|
|
79
|
+
}
|
|
80
|
+
const rnd = mulberry32(seed);
|
|
81
|
+
let shuffled = shuffle(arms, rnd);
|
|
82
|
+
// N≥3: se saiu a identidade (rótulo i → braço i na ordem de declaração), re-embaralha.
|
|
83
|
+
if (arms.length >= 3) {
|
|
84
|
+
let guard = 0;
|
|
85
|
+
while (shuffled.every((arm, i) => arm === arms[i]) && guard++ < 16) {
|
|
86
|
+
shuffled = shuffle(shuffled, rnd);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const map = {};
|
|
90
|
+
labels.forEach((label, i) => { map[label] = shuffled[i]; });
|
|
91
|
+
validatePermutation(map, arms, labels);
|
|
92
|
+
return map;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Bijeção total: cada braço exatamente uma vez, cada rótulo usado, sem undefined/duplicata. */
|
|
96
|
+
function validatePermutation(map, arms, labels) {
|
|
97
|
+
const mappedLabels = Object.keys(map);
|
|
98
|
+
if (mappedLabels.length !== labels.length) {
|
|
99
|
+
fail(`permutação inválida: ${mappedLabels.length} rótulos mapeados, esperado ${labels.length}`);
|
|
100
|
+
}
|
|
101
|
+
for (const label of labels) {
|
|
102
|
+
if (!(label in map)) fail(`permutação inválida: rótulo "${label}" sem braço (bug de indexação?)`);
|
|
103
|
+
const arm = map[label];
|
|
104
|
+
if (arm === undefined || arm === null) {
|
|
105
|
+
fail(`permutação inválida: rótulo "${label}" → braço undefined (indexação 1-based portada p/ 0-based?)`);
|
|
106
|
+
}
|
|
107
|
+
if (!arms.includes(arm)) fail(`permutação inválida: rótulo "${label}" → braço desconhecido "${arm}"`);
|
|
108
|
+
}
|
|
109
|
+
const armsCovered = new Set(Object.values(map));
|
|
110
|
+
if (armsCovered.size !== arms.length) {
|
|
111
|
+
fail(`permutação inválida: bijeção quebrada — ${armsCovered.size} braços distintos cobertos de ${arms.length} (braço duplicado ou perdido)`);
|
|
112
|
+
}
|
|
113
|
+
for (const arm of arms) {
|
|
114
|
+
if (!armsCovered.has(arm)) fail(`permutação inválida: braço "${arm}" não recebeu rótulo (perdido)`);
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
// Estado durável em disco (guarda do bug-class 2: fonte única, escrita atômica).
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
function statePath(expDir) { return path.join(expDir, 'state.json'); }
|
|
123
|
+
function sealedPath(expDir) { return path.join(expDir, 'sealed-map.json'); }
|
|
124
|
+
|
|
125
|
+
function loadState(expDir) {
|
|
126
|
+
const p = statePath(expDir);
|
|
127
|
+
if (!fs.existsSync(p)) fail(`experimento não inicializado: ${p} não existe (rode 'init')`);
|
|
128
|
+
let raw;
|
|
129
|
+
try { raw = fs.readFileSync(p, 'utf8'); } catch (e) { fail(`falha ao ler state.json: ${e.message}`); }
|
|
130
|
+
let s;
|
|
131
|
+
try { s = JSON.parse(raw); } catch (e) { fail(`state.json corrompido (JSON inválido): ${e.message}`); }
|
|
132
|
+
for (const k of ['arms', 'labels', 'rounds', 'rubric', 'scores']) {
|
|
133
|
+
if (!(k in s)) fail(`state.json inválido: campo "${k}" ausente`);
|
|
134
|
+
}
|
|
135
|
+
return s;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Escrita ATÔMICA (tmp + rename): nunca deixa um state.json parcial entre iterações. */
|
|
139
|
+
function saveState(expDir, state) {
|
|
140
|
+
state.updated_at = new Date().toISOString();
|
|
141
|
+
const p = statePath(expDir);
|
|
142
|
+
const tmp = `${p}.tmp`;
|
|
143
|
+
fs.writeFileSync(tmp, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
|
|
144
|
+
fs.renameSync(tmp, p);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
// Rubrica — fronteira máquina (PASS/FAIL) vs julgamento humano (0-5), configurável.
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
function validateRubric(rubric) {
|
|
151
|
+
if (!rubric || typeof rubric !== 'object') fail('rubrica ausente ou inválida');
|
|
152
|
+
if (!Array.isArray(rubric.dimensions) || rubric.dimensions.length === 0) {
|
|
153
|
+
fail('rubrica.dimensions ausente ou vazio');
|
|
154
|
+
}
|
|
155
|
+
const scale = rubric.scale || 5;
|
|
156
|
+
let sumW = 0;
|
|
157
|
+
for (const d of rubric.dimensions) {
|
|
158
|
+
if (!d.name) fail('dimensão sem name');
|
|
159
|
+
if (typeof d.weight !== 'number' || d.weight <= 0) fail(`dimensão "${d.name}": weight deve ser número > 0`);
|
|
160
|
+
if (d.type !== 'machine' && d.type !== 'human') fail(`dimensão "${d.name}": type deve ser machine|human`);
|
|
161
|
+
if (d.type === 'machine' && (!Number.isInteger(d.checks) || d.checks < 1)) {
|
|
162
|
+
fail(`dimensão "${d.name}" (machine): checks deve ser inteiro >= 1`);
|
|
163
|
+
}
|
|
164
|
+
sumW += d.weight;
|
|
165
|
+
}
|
|
166
|
+
if (Math.abs(sumW - 1) > 1e-6) fail(`soma dos pesos = ${sumW.toFixed(4)}, esperado 1.0`);
|
|
167
|
+
const v = rubric.verdict || {};
|
|
168
|
+
if (typeof v.minDiff !== 'number' || v.minDiff < 0) fail('rubrica.verdict.minDiff deve ser número >= 0');
|
|
169
|
+
if (!Number.isInteger(v.kOfN) || v.kOfN < 1) fail('rubrica.verdict.kOfN deve ser inteiro >= 1');
|
|
170
|
+
return { scale };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Score ponderado de UMA rodada de UM rótulo, RECOMPUTADO da rubrica (nunca confia no reportado). */
|
|
174
|
+
function weightedRoundScore(dimScores, rubric) {
|
|
175
|
+
const scale = rubric.scale || 5;
|
|
176
|
+
let acc = 0;
|
|
177
|
+
for (const d of rubric.dimensions) {
|
|
178
|
+
const raw = dimScores[d.name];
|
|
179
|
+
let s;
|
|
180
|
+
if (d.type === 'machine') {
|
|
181
|
+
// PASS/FAIL: espera { passed: <int> } → proporção × escala.
|
|
182
|
+
if (!raw || typeof raw.passed !== 'number') fail(`dimensão máquina "${d.name}": esperado { passed: int }`);
|
|
183
|
+
if (raw.passed < 0 || raw.passed > d.checks) fail(`dimensão "${d.name}": passed ${raw.passed} fora de 0..${d.checks}`);
|
|
184
|
+
s = (raw.passed / d.checks) * scale;
|
|
185
|
+
} else {
|
|
186
|
+
if (typeof raw !== 'number') fail(`dimensão humana "${d.name}": esperado nota numérica 0-${scale}`);
|
|
187
|
+
if (raw < 0 || raw > scale) fail(`dimensão "${d.name}": nota ${raw} fora de 0..${scale}`);
|
|
188
|
+
s = raw;
|
|
189
|
+
}
|
|
190
|
+
acc += s * d.weight;
|
|
191
|
+
}
|
|
192
|
+
return acc; // pesos somam 1 → já é a média ponderada
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
// Veredito por eixo — diferença ≥ minDiff sustentada em K de N; empate é válido.
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
function verdictForAxis(perRoundA, perRoundB, minDiff, kOfN) {
|
|
199
|
+
if (perRoundA.length !== perRoundB.length) fail('veredito: #rodadas divergente entre os dois braços');
|
|
200
|
+
const n = perRoundA.length;
|
|
201
|
+
const diffs = perRoundA.map((a, i) => a - perRoundB[i]);
|
|
202
|
+
const meanA = perRoundA.reduce((x, y) => x + y, 0) / n;
|
|
203
|
+
const meanB = perRoundB.reduce((x, y) => x + y, 0) / n;
|
|
204
|
+
const aWins = diffs.filter((d) => d >= minDiff).length; // A vence a rodada por ≥ limiar
|
|
205
|
+
const bWins = diffs.filter((d) => -d >= minDiff).length; // B vence a rodada por ≥ limiar
|
|
206
|
+
let winner = 'tie';
|
|
207
|
+
if (aWins >= kOfN && aWins > bWins) winner = 'A';
|
|
208
|
+
else if (bWins >= kOfN && bWins > aWins) winner = 'B';
|
|
209
|
+
return {
|
|
210
|
+
winner, meanA: round2(meanA), meanB: round2(meanB), meanDiff: round2(meanA - meanB),
|
|
211
|
+
perRoundDiff: diffs.map(round2), aRoundsOverThreshold: aWins, bRoundsOverThreshold: bWins,
|
|
212
|
+
minDiff, kOfN, tie: winner === 'tie',
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function round2(x) { return Math.round(x * 100) / 100; }
|
|
216
|
+
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// Reveal-gate — só destrava com TODAS as rodadas pontuadas (contagem PERSISTIDA).
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
function scoredRoundsCount(state) {
|
|
221
|
+
let done = 0;
|
|
222
|
+
for (let r = 1; r <= state.rounds; r++) {
|
|
223
|
+
const byLabel = state.scores[String(r)];
|
|
224
|
+
if (byLabel && state.labels.every((l) => l in byLabel)) done++;
|
|
225
|
+
}
|
|
226
|
+
return done;
|
|
227
|
+
}
|
|
228
|
+
function canReveal(state) { return scoredRoundsCount(state) === state.rounds; }
|
|
229
|
+
|
|
230
|
+
// ---------------------------------------------------------------------------
|
|
231
|
+
// Comandos (mutam o estado em disco; salvam após cada mutação).
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
function init(expDir, { arms, rounds, rubric, labels, seed }) {
|
|
234
|
+
if (!Array.isArray(arms) || arms.length < 2) fail('init: --arms exige N >= 2 braços');
|
|
235
|
+
if (new Set(arms).size !== arms.length) fail('init: rótulos de braço duplicados');
|
|
236
|
+
if (!Number.isInteger(rounds) || rounds < 1) fail('init: --rounds deve ser inteiro >= 1');
|
|
237
|
+
validateRubric(rubric);
|
|
238
|
+
const lbls = labels || DEFAULT_LABELS.slice(0, arms.length);
|
|
239
|
+
if (lbls.length !== arms.length) fail(`init: #rótulos (${lbls.length}) != #braços (${arms.length})`);
|
|
240
|
+
if (new Set(lbls).size !== lbls.length) fail('init: rótulos cegos duplicados');
|
|
241
|
+
fs.mkdirSync(expDir, { recursive: true });
|
|
242
|
+
const state = {
|
|
243
|
+
version: 1,
|
|
244
|
+
arms, labels: lbls, rounds, rubric,
|
|
245
|
+
seed: seed == null ? (crypto.randomBytes(4).readUInt32BE(0) >>> 0) : (seed >>> 0),
|
|
246
|
+
created_at: new Date().toISOString(),
|
|
247
|
+
pinned: {}, scores: {}, tokens: { creation: {}, rounds: {} },
|
|
248
|
+
revealed: false,
|
|
249
|
+
};
|
|
250
|
+
// Sela TODAS as permutações na inicialização (uma por rodada), arquivo com chmod 600.
|
|
251
|
+
const sealed = {};
|
|
252
|
+
for (let r = 1; r <= rounds; r++) {
|
|
253
|
+
sealed[String(r)] = permute(arms, lbls, seedFor(state.seed, r));
|
|
254
|
+
}
|
|
255
|
+
writeSealed(expDir, sealed);
|
|
256
|
+
saveState(expDir, state);
|
|
257
|
+
return state;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function writeSealed(expDir, sealed) {
|
|
261
|
+
const p = sealedPath(expDir);
|
|
262
|
+
const tmp = `${p}.tmp`;
|
|
263
|
+
fs.writeFileSync(tmp, `${JSON.stringify(sealed, null, 2)}\n`, 'utf8');
|
|
264
|
+
fs.renameSync(tmp, p);
|
|
265
|
+
try { fs.chmodSync(p, 0o600); } catch { /* FS sem permissões POSIX — best-effort */ }
|
|
266
|
+
}
|
|
267
|
+
function readSealed(expDir) {
|
|
268
|
+
const p = sealedPath(expDir);
|
|
269
|
+
if (!fs.existsSync(p)) fail(`mapa selado ausente: ${p}`);
|
|
270
|
+
return JSON.parse(fs.readFileSync(p, 'utf8'));
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function pin(expDir, round, inputs) {
|
|
274
|
+
const state = loadState(expDir);
|
|
275
|
+
assertRound(state, round);
|
|
276
|
+
const hash = crypto.createHash('sha256').update(JSON.stringify(inputs)).digest('hex');
|
|
277
|
+
state.pinned[String(round)] = { hash, inputs, frozen_at: new Date().toISOString() };
|
|
278
|
+
saveState(expDir, state);
|
|
279
|
+
return hash;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function recordScore(expDir, round, label, dimScores) {
|
|
283
|
+
const state = loadState(expDir);
|
|
284
|
+
assertRound(state, round);
|
|
285
|
+
if (!state.labels.includes(label)) fail(`rótulo "${label}" não pertence ao experimento`);
|
|
286
|
+
weightedRoundScore(dimScores, state.rubric); // valida a forma antes de gravar
|
|
287
|
+
state.scores[String(round)] = state.scores[String(round)] || {};
|
|
288
|
+
state.scores[String(round)][label] = dimScores;
|
|
289
|
+
saveState(expDir, state);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function recordTokens(expDir, { arm, round, tokens }) {
|
|
293
|
+
const state = loadState(expDir);
|
|
294
|
+
if (!state.arms.includes(arm)) fail(`braço "${arm}" não pertence ao experimento`);
|
|
295
|
+
if (typeof tokens !== 'number' || tokens < 0) fail('tokens deve ser número >= 0');
|
|
296
|
+
if (round == null) state.tokens.creation[arm] = tokens;
|
|
297
|
+
else {
|
|
298
|
+
assertRound(state, round);
|
|
299
|
+
state.tokens.rounds[String(round)] = state.tokens.rounds[String(round)] || {};
|
|
300
|
+
state.tokens.rounds[String(round)][arm] = tokens;
|
|
301
|
+
}
|
|
302
|
+
saveState(expDir, state);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function assertRound(state, round) {
|
|
306
|
+
if (!Number.isInteger(round) || round < 1 || round > state.rounds) {
|
|
307
|
+
fail(`rodada ${round} fora de 1..${state.rounds}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** REVEAL-GATE: recusa (fail-loud) até todas as rodadas pontuadas; só então lê o mapa selado. */
|
|
312
|
+
function reveal(expDir) {
|
|
313
|
+
const state = loadState(expDir);
|
|
314
|
+
const done = scoredRoundsCount(state);
|
|
315
|
+
if (done !== state.rounds) {
|
|
316
|
+
fail(`REVEAL-GATE bloqueado: ${done}/${state.rounds} rodadas pontuadas — revelação proibida até todas ` +
|
|
317
|
+
`estarem completas (evita calibrar o julgamento sabendo quem está ganhando). Nenhum mapa lido.`);
|
|
318
|
+
}
|
|
319
|
+
const sealed = readSealed(expDir);
|
|
320
|
+
state.revealed = true;
|
|
321
|
+
saveState(expDir, state);
|
|
322
|
+
return sealed;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** Agregação: só após reveal. Junta scores(por rótulo) aos braços e recomputa tudo. */
|
|
326
|
+
function tally(expDir) {
|
|
327
|
+
const state = loadState(expDir);
|
|
328
|
+
if (!canReveal(state)) fail(`tally: experimento incompleto (${scoredRoundsCount(state)}/${state.rounds} rodadas)`);
|
|
329
|
+
const sealed = readSealed(expDir);
|
|
330
|
+
const rubric = state.rubric;
|
|
331
|
+
const machineDims = rubric.dimensions.filter((d) => d.type === 'machine');
|
|
332
|
+
// perRoundByArm[arm] = [score_r1, ..., score_rN]
|
|
333
|
+
const perRoundByArm = {};
|
|
334
|
+
// machineAggregate[arm] = { passed, total, pass, byDim } — checks de MÁQUINA somados por
|
|
335
|
+
// braço sobre todas as rodadas, PASS/FAIL SEPARADO da média ponderada (§7.1 do protocolo:
|
|
336
|
+
// uma falha estrutural desqualificante fica VISÍVEL, não escondida na média).
|
|
337
|
+
const machineAggregate = {};
|
|
338
|
+
for (const arm of state.arms) {
|
|
339
|
+
perRoundByArm[arm] = [];
|
|
340
|
+
machineAggregate[arm] = { passed: 0, total: 0, byDim: {} };
|
|
341
|
+
for (const md of machineDims) machineAggregate[arm].byDim[md.name] = { passed: 0, total: 0 };
|
|
342
|
+
}
|
|
343
|
+
for (let r = 1; r <= state.rounds; r++) {
|
|
344
|
+
const map = sealed[String(r)]; // rótulo → braço
|
|
345
|
+
const byLabel = state.scores[String(r)];
|
|
346
|
+
for (const label of state.labels) {
|
|
347
|
+
const arm = map[label];
|
|
348
|
+
const dimScores = byLabel[label];
|
|
349
|
+
perRoundByArm[arm].push(round2(weightedRoundScore(dimScores, rubric)));
|
|
350
|
+
for (const md of machineDims) {
|
|
351
|
+
const passed = dimScores[md.name].passed;
|
|
352
|
+
machineAggregate[arm].passed += passed;
|
|
353
|
+
machineAggregate[arm].total += md.checks;
|
|
354
|
+
machineAggregate[arm].byDim[md.name].passed += passed;
|
|
355
|
+
machineAggregate[arm].byDim[md.name].total += md.checks;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
for (const arm of state.arms) {
|
|
360
|
+
machineAggregate[arm].pass = machineAggregate[arm].total > 0
|
|
361
|
+
&& machineAggregate[arm].passed === machineAggregate[arm].total;
|
|
362
|
+
}
|
|
363
|
+
const means = {};
|
|
364
|
+
for (const arm of state.arms) {
|
|
365
|
+
const xs = perRoundByArm[arm];
|
|
366
|
+
means[arm] = { mean: round2(xs.reduce((a, b) => a + b, 0) / xs.length), median: round2(median(xs)) };
|
|
367
|
+
}
|
|
368
|
+
const axes = [];
|
|
369
|
+
for (const ax of (rubric.axes || [])) {
|
|
370
|
+
const v = verdictForAxis(perRoundByArm[ax.a], perRoundByArm[ax.b], rubric.verdict.minDiff, rubric.verdict.kOfN);
|
|
371
|
+
axes.push({ name: ax.name, a: ax.a, b: ax.b, ...v });
|
|
372
|
+
}
|
|
373
|
+
return { perRoundByArm, means, machineAggregate, axes, tokens: state.tokens };
|
|
374
|
+
}
|
|
375
|
+
function median(xs) {
|
|
376
|
+
const s = xs.slice().sort((a, b) => a - b);
|
|
377
|
+
const m = Math.floor(s.length / 2);
|
|
378
|
+
return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Relatório final com revelação (texto markdown + objeto). */
|
|
382
|
+
function report(expDir) {
|
|
383
|
+
const state = loadState(expDir);
|
|
384
|
+
const sealed = reveal(expDir); // aplica o gate; falha se incompleto
|
|
385
|
+
const t = tally(expDir);
|
|
386
|
+
const lines = [];
|
|
387
|
+
lines.push(`# Arena — relatório final (revelação ${new Date().toISOString().slice(0, 10)})`);
|
|
388
|
+
lines.push('');
|
|
389
|
+
lines.push('## 1. Revelação dos mapas (rótulo → braço)');
|
|
390
|
+
lines.push(`| Rodada | ${state.labels.join(' | ')} |`);
|
|
391
|
+
lines.push(`|${'---|'.repeat(state.labels.length + 1)}`);
|
|
392
|
+
for (let r = 1; r <= state.rounds; r++) {
|
|
393
|
+
lines.push(`| R${r} | ${state.labels.map((l) => sealed[String(r)][l]).join(' | ')} |`);
|
|
394
|
+
}
|
|
395
|
+
lines.push('');
|
|
396
|
+
lines.push('## 2. Scores ponderados por rodada');
|
|
397
|
+
lines.push(`| Braço | ${Array.from({ length: state.rounds }, (_, i) => `R${i + 1}`).join(' | ')} | Média | Mediana |`);
|
|
398
|
+
lines.push(`|${'---|'.repeat(state.rounds + 3)}`);
|
|
399
|
+
for (const arm of state.arms) {
|
|
400
|
+
lines.push(`| ${arm} | ${t.perRoundByArm[arm].join(' | ')} | **${t.means[arm].mean}** | ${t.means[arm].median} |`);
|
|
401
|
+
}
|
|
402
|
+
lines.push('');
|
|
403
|
+
const machineDims = state.rubric.dimensions.filter((d) => d.type === 'machine');
|
|
404
|
+
if (machineDims.length > 0) {
|
|
405
|
+
lines.push('## 3. Estrutura verificável por máquina — PASS/FAIL agregado (SEPARADO da média ponderada)');
|
|
406
|
+
lines.push('_Uma falha estrutural desqualificante fica visível aqui, não escondida na média — um braço pode vencer no score e ainda reprovar aqui._');
|
|
407
|
+
lines.push(`| Braço | ${machineDims.map((d) => d.name).join(' | ')} | Agregado | PASS? |`);
|
|
408
|
+
lines.push(`|${'---|'.repeat(machineDims.length + 3)}`);
|
|
409
|
+
for (const arm of state.arms) {
|
|
410
|
+
const agg = t.machineAggregate[arm];
|
|
411
|
+
const cols = machineDims.map((d) => `${agg.byDim[d.name].passed}/${agg.byDim[d.name].total}`);
|
|
412
|
+
lines.push(`| ${arm} | ${cols.join(' | ')} | ${agg.passed}/${agg.total} | ${agg.pass ? 'SIM' : '**NÃO**'} |`);
|
|
413
|
+
}
|
|
414
|
+
lines.push('');
|
|
415
|
+
}
|
|
416
|
+
lines.push(`## 4. Veredito por eixo (critério: diferença ≥ ${state.rubric.verdict.minDiff} em ≥ ${state.rubric.verdict.kOfN}/${state.rounds} rodadas; empate é válido)`);
|
|
417
|
+
for (const ax of t.axes) {
|
|
418
|
+
const verd = ax.tie ? 'EMPATE (resultado válido, não forçado)'
|
|
419
|
+
: `VITÓRIA DE ${ax.winner === 'A' ? ax.a : ax.b}`;
|
|
420
|
+
lines.push(`- **${ax.name}** (${ax.a} vs ${ax.b}): ${verd} — diferença média ${ax.meanDiff}; por rodada [${ax.perRoundDiff.join(', ')}]; ≥limiar ${ax.aRoundsOverThreshold}(${ax.a})/${ax.bRoundsOverThreshold}(${ax.b}).`);
|
|
421
|
+
}
|
|
422
|
+
lines.push('');
|
|
423
|
+
lines.push('## 5. Tokens por braço/rodada');
|
|
424
|
+
lines.push(`| Braço | Criação | ${Array.from({ length: state.rounds }, (_, i) => `R${i + 1}`).join(' | ')} |`);
|
|
425
|
+
lines.push(`|${'---|'.repeat(state.rounds + 2)}`);
|
|
426
|
+
for (const arm of state.arms) {
|
|
427
|
+
const rr = Array.from({ length: state.rounds }, (_, i) => (state.tokens.rounds[String(i + 1)] || {})[arm] ?? '—');
|
|
428
|
+
lines.push(`| ${arm} | ${state.tokens.creation[arm] ?? '—'} | ${rr.join(' | ')} |`);
|
|
429
|
+
}
|
|
430
|
+
lines.push('');
|
|
431
|
+
if (state.rubric.prediction) {
|
|
432
|
+
lines.push('## 6. Conferência da previsão (registrada ANTES do experimento — viés de confirmação declarado)');
|
|
433
|
+
lines.push(`> ${state.rubric.prediction}`);
|
|
434
|
+
lines.push('');
|
|
435
|
+
lines.push('_Limitação honesta: uma previsão vista antes do julgamento é viés conhecido; a conferência é autoavaliação declarada, não validação cega de terceiro._');
|
|
436
|
+
}
|
|
437
|
+
return { text: lines.join('\n'), tally: t, sealed };
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// ---------------------------------------------------------------------------
|
|
441
|
+
// CLI
|
|
442
|
+
// ---------------------------------------------------------------------------
|
|
443
|
+
function parseFlags(argv) {
|
|
444
|
+
const f = {};
|
|
445
|
+
for (let i = 0; i < argv.length; i++) {
|
|
446
|
+
const a = argv[i];
|
|
447
|
+
if (a.startsWith('--')) { const k = a.slice(2); const v = argv[i + 1]; if (v && !v.startsWith('--')) { f[k] = v; i++; } else f[k] = true; }
|
|
448
|
+
}
|
|
449
|
+
return f;
|
|
450
|
+
}
|
|
451
|
+
function readJson(spec) {
|
|
452
|
+
if (spec === '-' ) return JSON.parse(fs.readFileSync(0, 'utf8'));
|
|
453
|
+
if (spec && (spec.startsWith('{') || spec.startsWith('['))) return JSON.parse(spec);
|
|
454
|
+
return JSON.parse(fs.readFileSync(spec, 'utf8'));
|
|
455
|
+
}
|
|
456
|
+
function help() {
|
|
457
|
+
return [
|
|
458
|
+
'arena.cjs — motor determinístico da skill pc-arena. Comandos:',
|
|
459
|
+
' init <expDir> --arms A1,A2,.. --rounds N --rubric <f.json> [--labels W,X,..] [--seed S]',
|
|
460
|
+
' pin <expDir> --round R --inputs <f.json|-> (congela insumos c/ hash)',
|
|
461
|
+
' score <expDir> --round R --label W --scores <f.json|->',
|
|
462
|
+
' tokens <expDir> --arm A1 [--round R] --tokens N',
|
|
463
|
+
' status <expDir> (rodadas pontuadas / reveal liberado?)',
|
|
464
|
+
' reveal <expDir> (REVEAL-GATE: só com todas as rodadas pontuadas)',
|
|
465
|
+
' report <expDir> (relatório final com revelação)',
|
|
466
|
+
].join('\n');
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function main() {
|
|
470
|
+
const [cmd, expDir, ...rest] = process.argv.slice(2);
|
|
471
|
+
if (!cmd || cmd === 'help' || cmd === '--help') { console.log(help()); process.exit(0); }
|
|
472
|
+
if (!expDir) { console.error('erro: <expDir> obrigatório\n' + help()); process.exit(2); }
|
|
473
|
+
const f = parseFlags(rest);
|
|
474
|
+
try {
|
|
475
|
+
if (cmd === 'init') {
|
|
476
|
+
const arms = String(f.arms || '').split(',').map((s) => s.trim()).filter(Boolean);
|
|
477
|
+
const labels = f.labels ? String(f.labels).split(',').map((s) => s.trim()) : null;
|
|
478
|
+
init(expDir, { arms, rounds: parseInt(f.rounds, 10), rubric: readJson(f.rubric), labels, seed: f.seed != null ? parseInt(f.seed, 10) : null });
|
|
479
|
+
console.log(`[OK] experimento iniciado em ${expDir} — ${arms.length} braços × ${f.rounds} rodadas; mapa selado (chmod 600).`);
|
|
480
|
+
} else if (cmd === 'pin') {
|
|
481
|
+
const h = pin(expDir, parseInt(f.round, 10), readJson(f.inputs));
|
|
482
|
+
console.log(`[OK] insumos da rodada ${f.round} congelados — hash ${h}`);
|
|
483
|
+
} else if (cmd === 'score') {
|
|
484
|
+
recordScore(expDir, parseInt(f.round, 10), f.label, readJson(f.scores));
|
|
485
|
+
console.log(`[OK] notas cegas registradas — rodada ${f.round}, rótulo ${f.label}`);
|
|
486
|
+
} else if (cmd === 'tokens') {
|
|
487
|
+
recordTokens(expDir, { arm: f.arm, round: f.round != null ? parseInt(f.round, 10) : null, tokens: parseInt(f.tokens, 10) });
|
|
488
|
+
console.log(`[OK] tokens registrados — braço ${f.arm}${f.round != null ? `, rodada ${f.round}` : ' (criação)'}`);
|
|
489
|
+
} else if (cmd === 'status') {
|
|
490
|
+
const s = loadState(expDir);
|
|
491
|
+
console.log(`rodadas pontuadas: ${scoredRoundsCount(s)}/${s.rounds} · reveal ${canReveal(s) ? 'LIBERADO' : 'BLOQUEADO'}`);
|
|
492
|
+
} else if (cmd === 'reveal') {
|
|
493
|
+
console.log(JSON.stringify(reveal(expDir), null, 2));
|
|
494
|
+
} else if (cmd === 'report') {
|
|
495
|
+
console.log(report(expDir).text);
|
|
496
|
+
} else {
|
|
497
|
+
console.error(`comando desconhecido: ${cmd}\n` + help()); process.exit(2);
|
|
498
|
+
}
|
|
499
|
+
process.exit(0);
|
|
500
|
+
} catch (e) {
|
|
501
|
+
if (e instanceof ArenaError) { console.error(`[FALHA] ${e.message}`); process.exit(1); }
|
|
502
|
+
throw e;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (require.main === module) main();
|
|
507
|
+
|
|
508
|
+
module.exports = {
|
|
509
|
+
init, pin, recordScore, recordTokens, reveal, tally, report,
|
|
510
|
+
permute, validatePermutation, shuffle, mulberry32, seedFor,
|
|
511
|
+
weightedRoundScore, verdictForAxis, validateRubric,
|
|
512
|
+
canReveal, scoredRoundsCount, loadState, saveState, sealedPath, statePath,
|
|
513
|
+
DEFAULT_LABELS, ArenaError,
|
|
514
|
+
};
|