@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,433 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* phash-gate.test.cjs — suíte do script BLESSED de MEDIDA da não-cópia.
|
|
5
|
+
* Story SF10.8 (origem) → **Story SF10.19 / ADR-018 Adendo F6-b (DF-SF10.19-1/-2/-4)**.
|
|
6
|
+
*
|
|
7
|
+
* O QUE MUDOU DE OBJETO NESTA SUÍTE (e por quê): até a SF10.19 este script tinha uma metade
|
|
8
|
+
* BLOQUEANTE (proveniência) e uma metade de medida. A metade bloqueante FOI EMBORA daqui — não
|
|
9
|
+
* porque afrouxou, mas porque ela é uma invariante de ORIGEM e o `wf-*.yaml` que declara este
|
|
10
|
+
* `command_check` é consumido por DOIS drivers, um deles não-confinado (`pc-run-pod.cjs`, agente
|
|
11
|
+
* com Bash/Write). Ela agora vive em `pod-export-tools.cjs` (`assertRunProvenance`) e é asserida
|
|
12
|
+
* pelo `pod-export-executor.cjs` antes de `motor.advance` — com suíte própria em
|
|
13
|
+
* `pod-export-executor.test.cjs` (§SF10.19), que prova o BLOQUEIO real em `run`, `resume` e
|
|
14
|
+
* tentativa guiada, inclusive com a camada 1 de INTEG-1 contornada por escrita direta com `fs`.
|
|
15
|
+
*
|
|
16
|
+
* O QUE ESTA SUÍTE PROVA AGORA:
|
|
17
|
+
* (AC5) PROPRIEDADE, não caso pontual: NENHUM estado de insumo faz este script sair não-zero —
|
|
18
|
+
* referência ausente, `assets/` vazio, ledger ausente/ilegível/de versão desconhecida, sha
|
|
19
|
+
* divergente, asset intruso, entrada registrada sumida, Chrome ausente. Todos exit 0, com
|
|
20
|
+
* `measure.status` DECLARADO e motivo. Estático + comportamental, pela rota REAL do motor;
|
|
21
|
+
* (AC5) o único exit não-zero remanescente é 2 (uso/config: artefato inexistente, dir escapando);
|
|
22
|
+
* (AC6) SUBSTITUTA da antiga asserção de "duas cópias do contrato do ledger não divergem": o
|
|
23
|
+
* contrato agora tem UMA implementação (a duplicação sumiu), e o que resta a vigiar é que
|
|
24
|
+
* o script de medida NÃO REGREDIU para bloquear + as duas pontas concordam no PATH do
|
|
25
|
+
* ledger (que o script ainda usa para gravar a MEDIDA);
|
|
26
|
+
* (AC5) NENHUM ramo condicional dev/export, flag, env var ou campo de modo nasceu aqui;
|
|
27
|
+
* (INTEG-1 camada 1) as tools continuam NEGANDO escrita sob `<runDir>/inputs/` — inalterado;
|
|
28
|
+
* (AC3b) degradação DECLARADA: Chrome ausente vira medida ausente no artefato e no ledger;
|
|
29
|
+
* (AC10) o bloco do artefato DECLARA o que não foi verificado (proveniência), em todo status;
|
|
30
|
+
* (DF5-6/e2) similaridade como MEDIDA REPORTADA: distância computada e gravada, sem pass/fail;
|
|
31
|
+
* (DF5-1) materialização da referência pelo EXECUTOR + registro da proveniência.
|
|
32
|
+
*
|
|
33
|
+
* A aritmética do hash roda SEM Chrome. As provas com Chrome REAL registram SKIP HONESTO onde ele
|
|
34
|
+
* não existe. A fronteira `command_check` herdada é provada em `veto-checks.test.cjs`.
|
|
35
|
+
*
|
|
36
|
+
* Node >= 18. Exit 0/1.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
const fs = require('node:fs');
|
|
40
|
+
const os = require('node:os');
|
|
41
|
+
const path = require('node:path');
|
|
42
|
+
const crypto = require('node:crypto');
|
|
43
|
+
const { execFileSync } = require('node:child_process');
|
|
44
|
+
|
|
45
|
+
const rp = require('./pc-run-pod.cjs');
|
|
46
|
+
const gate = require('./veto-checks/phash-gate.cjs');
|
|
47
|
+
const exec = require('./pod-export-executor.cjs');
|
|
48
|
+
const tools = require('./pod-export-tools.cjs');
|
|
49
|
+
|
|
50
|
+
const FIX = path.join(__dirname, '__fixtures__', 'veto-checks', 'phash');
|
|
51
|
+
const GATE_PATH = path.join(__dirname, 'veto-checks', 'phash-gate.cjs');
|
|
52
|
+
const SIDE = gate.SIDE;
|
|
53
|
+
|
|
54
|
+
let passed = 0;
|
|
55
|
+
const failures = [];
|
|
56
|
+
function ok(cond, label) {
|
|
57
|
+
if (cond) { passed++; console.log(`[OK ] ${label}`); }
|
|
58
|
+
else { failures.push(label); console.error(`[FALHA] ${label}`); }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Helpers: runDir sintético no layout REAL do motor (runDir/artifacts|assets|inputs) + o
|
|
63
|
+
// registro de proveniência escrito pela MESMA função de produção (`tools.recordProvenance`).
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
const ARTIFACT_MD = '# visual-set\n\n## Arquivos Gerados\n- assets/cover-bg.png\n\nreferencia_copiada: nao\nconfianca: alta\n';
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* @param provenance 'full' (registra refs+assets, o caminho do export) | 'none' (nenhum ledger —
|
|
70
|
+
* o estado NORMAL de um run de DESENVOLVIMENTO) | 'refs-only' | 'assets-only'
|
|
71
|
+
*/
|
|
72
|
+
function makeRunDir({ refs = [], assets = [], label = 'phash', provenance = 'full' }) {
|
|
73
|
+
const runDir = fs.mkdtempSync(path.join(os.tmpdir(), `sf10.19-${label}-`));
|
|
74
|
+
fs.mkdirSync(path.join(runDir, 'artifacts'), { recursive: true });
|
|
75
|
+
fs.mkdirSync(path.join(runDir, 'assets'), { recursive: true });
|
|
76
|
+
if (refs.length > 0) fs.mkdirSync(path.join(runDir, 'inputs'), { recursive: true });
|
|
77
|
+
fs.writeFileSync(path.join(runDir, 'artifacts', 'visuals.md'), ARTIFACT_MD, 'utf8');
|
|
78
|
+
for (const r of refs) {
|
|
79
|
+
const dst = path.join(runDir, 'inputs', r);
|
|
80
|
+
fs.copyFileSync(path.join(FIX, r), dst);
|
|
81
|
+
if (provenance === 'full' || provenance === 'refs-only') tools.recordProvenance(runDir, 'inputs', dst, { source: 'materializeInputs' });
|
|
82
|
+
}
|
|
83
|
+
for (const a of assets) {
|
|
84
|
+
const dst = path.join(runDir, 'assets', a);
|
|
85
|
+
fs.copyFileSync(path.join(FIX, a), dst);
|
|
86
|
+
if (provenance === 'full' || provenance === 'assets-only') tools.recordProvenance(runDir, 'assets', dst, { source: 'openrouter_image' });
|
|
87
|
+
}
|
|
88
|
+
return runDir;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Invoca o script pela MESMA porta do motor (evalVeto/command_check), como em produção. */
|
|
92
|
+
function runGate(runDir, args = ['--refs-dir', '../inputs', '--assets-dir', '../assets']) {
|
|
93
|
+
return rp.evalVeto(
|
|
94
|
+
{ type: 'command_check', command: 'phash-gate.cjs', args, timeout_ms: 120000 },
|
|
95
|
+
fs.readFileSync(path.join(runDir, 'artifacts', 'visuals.md'), 'utf8'),
|
|
96
|
+
path.join(runDir, 'artifacts', 'visuals.md'),
|
|
97
|
+
{ runDir, podRoot: runDir },
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Invocação DIRETA (sem o motor) — devolve o exit code real do processo. */
|
|
102
|
+
function rawExit(argv) {
|
|
103
|
+
try {
|
|
104
|
+
execFileSync(process.execPath, [GATE_PATH, ...argv], { stdio: 'pipe', timeout: 120000 });
|
|
105
|
+
return 0;
|
|
106
|
+
} catch (e) { return typeof e.status === 'number' ? e.status : -1; }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function artifactOf(runDir) { return fs.readFileSync(path.join(runDir, 'artifacts', 'visuals.md'), 'utf8'); }
|
|
110
|
+
function ledgerOf(runDir) { return JSON.parse(fs.readFileSync(gate.provenancePathFor(runDir), 'utf8')); }
|
|
111
|
+
|
|
112
|
+
function grayFrom(fn) {
|
|
113
|
+
const g = new Uint8Array(SIDE * SIDE);
|
|
114
|
+
for (let y = 0; y < SIDE; y++) for (let x = 0; x < SIDE; x++) g[y * SIDE + x] = Math.max(0, Math.min(255, Math.round(fn(x, y))));
|
|
115
|
+
return g;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ===========================================================================
|
|
119
|
+
// 1. Contrato do ledger: a DUPLICAÇÃO acabou (DF-SF10.19-4). O que resta a vigiar é o PATH.
|
|
120
|
+
// ===========================================================================
|
|
121
|
+
console.log('--- 1. contrato do ledger: uma única implementação (a duplicação foi removida) ---');
|
|
122
|
+
{
|
|
123
|
+
const rd = fs.mkdtempSync(path.join(os.tmpdir(), 'sf10.19-contrato-'));
|
|
124
|
+
ok(tools.provenancePathFor(rd) === gate.provenancePathFor(rd),
|
|
125
|
+
'tools e blessed derivam o MESMO path de registro (o script ainda GRAVA a medida nele)');
|
|
126
|
+
ok(gate.provenancePathFor(rd) === path.resolve(rd) + '.provenance.json',
|
|
127
|
+
'o registro é IRMÃO do runDir (fora da árvore gravável pelas tools por construção)');
|
|
128
|
+
let threwSibling = false;
|
|
129
|
+
try { tools.confinedResolve(rd, `../${path.basename(rd)}.provenance.json`); } catch { threwSibling = true; }
|
|
130
|
+
ok(threwSibling, 'nenhuma tool alcança o registro: o path do irmão é traversal para fora do runDir → RECUSADO');
|
|
131
|
+
ok(tools.RUN_INPUTS_DIRNAME === 'inputs' && exec.RUN_INPUTS_DIRNAME === tools.RUN_INPUTS_DIRNAME,
|
|
132
|
+
'RUN_INPUTS_DIRNAME tem fonte ÚNICA (tools) e o executor a reexporta — sem literal duplicado');
|
|
133
|
+
|
|
134
|
+
// AC2/AC6 — a VERIFICAÇÃO existe uma vez só, e não é mais aqui.
|
|
135
|
+
ok(typeof gate.checkProvenance === 'undefined' && typeof gate.loadProvenance === 'undefined',
|
|
136
|
+
'AC2: o blessed NÃO expõe mais verificação de proveniência (checkProvenance/loadProvenance removidos)');
|
|
137
|
+
ok(typeof tools.checkRunProvenance === 'function' && typeof tools.assertRunProvenance === 'function',
|
|
138
|
+
'AC2: a checagem canônica vive em pod-export-tools.cjs, ao lado de recordProvenance');
|
|
139
|
+
const gateSrc = fs.readFileSync(GATE_PATH, 'utf8');
|
|
140
|
+
ok(!/\bsha256\s*\(|createHash/.test(gateSrc),
|
|
141
|
+
'AC2: o blessed não recalcula sha256 de nada — ele não tem mais o que decidir com isso');
|
|
142
|
+
|
|
143
|
+
const f = path.join(rd, 'x.bin');
|
|
144
|
+
fs.writeFileSync(f, Buffer.from('conteudo'));
|
|
145
|
+
const rec = tools.recordProvenance(rd, 'assets', f);
|
|
146
|
+
ok(rec.sha256 === crypto.createHash('sha256').update(fs.readFileSync(f)).digest('hex'),
|
|
147
|
+
'sha256 do registro = sha256 do arquivo em disco (a gravação do ledger não mudou)');
|
|
148
|
+
fs.writeFileSync(gate.provenancePathFor(rd), '{ isso não é json', 'utf8');
|
|
149
|
+
let threwCorrupt = false;
|
|
150
|
+
try { tools.recordProvenance(rd, 'assets', f); } catch { threwCorrupt = true; }
|
|
151
|
+
ok(threwCorrupt, 'registro corrompido: recordProvenance RECUSA gravar por cima (fail-loud, não reseta proveniência)');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ===========================================================================
|
|
155
|
+
// 2. AC5 — PROPRIEDADE: nenhum estado de insumo produz exit não-zero.
|
|
156
|
+
// Isto SUBSTITUI (não apaga) a antiga asserção anti-divergência das duas cópias do contrato:
|
|
157
|
+
// o risco que ela protegia deixou de existir com a implementação única; o risco que EXISTE
|
|
158
|
+
// agora é este script REGREDIR para bloquear e travar o driver de dev de novo.
|
|
159
|
+
// ===========================================================================
|
|
160
|
+
console.log('--- 2. AC5 (PROPRIEDADE): nenhum estado de insumo bloqueia ---');
|
|
161
|
+
{
|
|
162
|
+
// (a) ESTÁTICO: não há caminho de bloqueio no fonte.
|
|
163
|
+
const src = fs.readFileSync(GATE_PATH, 'utf8');
|
|
164
|
+
const exits = [...src.matchAll(/process\.exit\((\d+)\)/g)].map((m) => m[1]);
|
|
165
|
+
ok(exits.every((c) => c === '0' || c === '2') && exits.includes('0') && exits.includes('2'),
|
|
166
|
+
`AC5 (estático): os únicos process.exit do script são 0 e 2 (encontrados: ${[...new Set(exits)].join(', ')})`);
|
|
167
|
+
ok(!/process\.exit\(1\)|process\.exit\(3\)/.test(src),
|
|
168
|
+
'AC5 (estático): exit 1 (proveniência violada) e exit 3 (fail-loud de insumo) não existem mais');
|
|
169
|
+
|
|
170
|
+
// (b) ESTÁTICO: nenhum ramo condicional dev/export, flag, env ou campo de modo (Escopo OUT).
|
|
171
|
+
const envs = [...new Set([...src.matchAll(/process\.env\.([A-Z_0-9]+)/g)].map((m) => m[1]))];
|
|
172
|
+
ok(envs.join(',') === 'CHROME_BIN', `Escopo OUT: a única env var lida continua sendo CHROME_BIN (${envs.join(', ') || 'nenhuma'})`);
|
|
173
|
+
ok(!/--(dev|mode|export|skip|allow)[-\w]*/.test(src), 'Escopo OUT: nenhum arg de CLI de modo/skip nasceu no script');
|
|
174
|
+
ok(!/\b(isDev|devMode|inExport|driverIsDev|IS_DEV)\b/.test(src), 'Escopo OUT: nenhum identificador de "modo dev vs export" no script');
|
|
175
|
+
const parsed = gate.parseArgs(['--refs-dir', 'a', '--assets-dir', 'b']);
|
|
176
|
+
ok(Object.keys(parsed).sort().join(',') === 'assetsDir,refsDir,revokedArgs',
|
|
177
|
+
`Escopo OUT: parseArgs não ganhou opção nova (${Object.keys(parsed).sort().join(', ')}) — args de CLI INALTERADOS`);
|
|
178
|
+
|
|
179
|
+
// (c) COMPORTAMENTAL: a matriz de estados de insumo, TODA pela rota real do motor.
|
|
180
|
+
const estados = [
|
|
181
|
+
['tudo íntegro (o caminho do export)', () => makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'p-ok' })],
|
|
182
|
+
['referência NÃO materializada (o estado NORMAL do driver de dev)', () => makeRunDir({ refs: [], assets: ['distinct.png'], label: 'p-norefs' })],
|
|
183
|
+
['assets/ vazio (etapa ainda não gerou imagem)', () => makeRunDir({ refs: ['ref.png'], assets: [], label: 'p-noassets' })],
|
|
184
|
+
['assets/ e inputs/ vazios (run recém-criado)', () => makeRunDir({ refs: [], assets: [], label: 'p-vazio' })],
|
|
185
|
+
['ledger AUSENTE (dev: ninguém escreve ledger)', () => makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'p-noledger', provenance: 'none' })],
|
|
186
|
+
['ledger ILEGÍVEL', () => { const rd = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'p-badledger' }); fs.writeFileSync(gate.provenancePathFor(rd), '{ quebrado', 'utf8'); return rd; }],
|
|
187
|
+
['ledger de VERSÃO DESCONHECIDA', () => { const rd = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'p-verledger' }); fs.writeFileSync(gate.provenancePathFor(rd), JSON.stringify({ version: 99, inputs: {}, assets: {} }), 'utf8'); return rd; }],
|
|
188
|
+
['sha DIVERGENTE em inputs/ (referência trocada)', () => { const rd = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'p-div' }); fs.copyFileSync(path.join(FIX, 'copy.png'), path.join(rd, 'inputs', 'ref.png')); return rd; }],
|
|
189
|
+
['imagem INTRUSA em assets/ (fora do ledger)', () => { const rd = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'p-intrusa' }); fs.copyFileSync(path.join(FIX, 'copy.png'), path.join(rd, 'assets', 'intrusa.png')); return rd; }],
|
|
190
|
+
['entrada registrada que SUMIU do disco', () => { const rd = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'p-sumiu' }); fs.rmSync(path.join(rd, 'assets', 'distinct.png')); return rd; }],
|
|
191
|
+
['ledger só com refs (assets sem registro)', () => makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'p-refsonly', provenance: 'refs-only' })],
|
|
192
|
+
];
|
|
193
|
+
const bloquearam = [];
|
|
194
|
+
for (const [nome, mk] of estados) {
|
|
195
|
+
const rd = mk();
|
|
196
|
+
const r = runGate(rd);
|
|
197
|
+
if (r.ok !== true) bloquearam.push(`${nome} → ${String(r.reason).slice(0, 120)}`);
|
|
198
|
+
// Em TODO estado o artefato recebe o bloco de medida, e ele DECLARA o que não foi verificado.
|
|
199
|
+
const art = artifactOf(rd);
|
|
200
|
+
if (!/pc:medida-similaridade:inicio/.test(art) || !/NAO verifica PROVENIENCIA/.test(art)) {
|
|
201
|
+
bloquearam.push(`${nome} → bloco de medida ausente ou sem a declaração do que não foi verificado`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
ok(bloquearam.length === 0,
|
|
205
|
+
`AC5 (comportamental): NENHUM dos ${estados.length} estados de insumo bloqueia, e todos declaram a degradação${bloquearam.length ? ' — VIOLAÇÕES: ' + bloquearam.join(' | ') : ''}`);
|
|
206
|
+
|
|
207
|
+
// (c2) F1 do gate `pc-qa` da SF10.19: diretório de insumo ILEGÍVEL (EACCES). `listImages` faz IO
|
|
208
|
+
// e estava FORA do try — a exceção escapava e o processo saía 1, BLOQUEANDO, contra a promessa
|
|
209
|
+
// escrita duas linhas acima dela. Regressão vigiada aqui, no mesmo lugar da propriedade.
|
|
210
|
+
for (const dir of ['assets', 'inputs']) {
|
|
211
|
+
const rd = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: `eacces-${dir}` });
|
|
212
|
+
const alvo = path.join(rd, dir);
|
|
213
|
+
fs.chmodSync(alvo, 0o000);
|
|
214
|
+
let legivelMesmoAssim = true;
|
|
215
|
+
try { fs.readdirSync(alvo); } catch { legivelMesmoAssim = false; }
|
|
216
|
+
if (legivelMesmoAssim) { // root ignora o modo: SKIP HONESTO em vez de asserção vazia
|
|
217
|
+
fs.chmodSync(alvo, 0o755);
|
|
218
|
+
console.log(`[SKIP ] EACCES em ${dir}/ não é reproduzível neste ambiente (usuário ignora o modo do diretório)`);
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
const r = runGate(rd);
|
|
222
|
+
fs.chmodSync(alvo, 0o755);
|
|
223
|
+
const art = artifactOf(rd);
|
|
224
|
+
ok(r.ok === true, `AC5/F1: ${dir}/ ILEGÍVEL (EACCES) NÃO bloqueia — antes do fix o script saía 1 aqui`);
|
|
225
|
+
ok(/Medida AUSENTE/.test(art) && /EACCES/.test(art),
|
|
226
|
+
`AC5/F1: a falha de leitura de ${dir}/ vira DEGRADAÇÃO DECLARADA com o errno no artefato (nunca silêncio, nunca veto)`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// (d) O estado que HOJE trava o pod no uso interativo, nomeado: é o motivo desta story.
|
|
230
|
+
const rdDev = makeRunDir({ refs: [], assets: [], label: 'p-dev', provenance: 'none' });
|
|
231
|
+
const rDev = runGate(rdDev);
|
|
232
|
+
ok(rDev.ok === true,
|
|
233
|
+
'AC5 (o defeito que a story conserta): run de DEV sem inputs/ e sem ledger — o mesmo estado que dava "exit 3: nenhuma imagem de REFERÊNCIA" — PASSA');
|
|
234
|
+
ok(/Medida NAO CALCULADA/.test(artifactOf(rdDev)) && /REFERENCIA/.test(artifactOf(rdDev)),
|
|
235
|
+
'AC5: e o artefato DIZ por que não houve medida (degradação declarada, nunca omissão)');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ===========================================================================
|
|
239
|
+
// 3. AC5 — o único exit não-zero que sobra: 2 (uso/config inválida, erro de WIRING)
|
|
240
|
+
// ===========================================================================
|
|
241
|
+
console.log('--- 3. exit 2 (uso/config) é o único não-zero remanescente ---');
|
|
242
|
+
{
|
|
243
|
+
ok(rawExit([path.join(os.tmpdir(), 'nao-existe-artefato-xyz.md')]) === 2, 'artefato inexistente → exit 2 (uso inválido)');
|
|
244
|
+
ok(rawExit([]) === 2, 'sem argumento de artefato → exit 2');
|
|
245
|
+
const rd = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'e-badarg' });
|
|
246
|
+
const art = path.join(rd, 'artifacts', 'visuals.md');
|
|
247
|
+
ok(rawExit([art, '--refs-dir', '../../../etc']) === 2, '--refs-dir que escapa do runDir → exit 2, nunca lido');
|
|
248
|
+
ok(rawExit([art, '--assets-dir', '../../..']) === 2, '--assets-dir que escapa do runDir → exit 2');
|
|
249
|
+
ok(runGate(rd, ['--refs-dir', '../../../etc', '--assets-dir', '../assets']).ok === false,
|
|
250
|
+
'pela rota do motor, o arg inválido também é RECUSADO (erro de wiring é idêntico nos dois drivers)');
|
|
251
|
+
ok(rawExit([art]) === 0, 'com wiring válido, exit 0 (defaults ../inputs e ../assets)');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ===========================================================================
|
|
255
|
+
// 4. INTEG-1 — CAMADA 1 (denylist de escrita nas tools) segue INTACTA.
|
|
256
|
+
// A CAMADA 2 (registro sha256) mudou de HOSPEDEIRO, não de força: ela é provada, com a camada 1
|
|
257
|
+
// CONTORNADA por escrita direta com `fs`, em `pod-export-executor.test.cjs` §SF10.19 — onde o
|
|
258
|
+
// run é HALTADO. Aqui provamos que o script de medida, sozinho, não é mais o guardião disso.
|
|
259
|
+
// ===========================================================================
|
|
260
|
+
console.log('--- 4. INTEG-1: camada 1 intacta (camada 2 provada no executor) ---');
|
|
261
|
+
const PNG_1X1 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+M8AAAMBAQDJ/pLvAAAAAElFTkSuQmCC';
|
|
262
|
+
const imageTransport = async () => ({ choices: [{ message: { images: [{ image_url: { url: PNG_1X1 } }] } }] });
|
|
263
|
+
|
|
264
|
+
(async () => {
|
|
265
|
+
const rd = makeRunDir({ refs: ['ref.png'], assets: [], label: 'integ-c1' });
|
|
266
|
+
const antes = tools.sha256File(path.join(rd, 'inputs', 'ref.png'));
|
|
267
|
+
const r = await tools.openrouterImage('desenhe', 'inputs/ref.png', { runDir: rd, model: 'm', imageTransport });
|
|
268
|
+
const depois = tools.sha256File(path.join(rd, 'inputs', 'ref.png'));
|
|
269
|
+
ok(r.ok === false && /PROIBIDA/.test(r.error) && /inputs/.test(r.error),
|
|
270
|
+
'CAMADA 1: openrouter_image(out_path:"inputs/<ref>") é RECUSADO pela denylist (cenário exato do QA, INTEG-1)');
|
|
271
|
+
ok(antes === depois, 'CAMADA 1: a referência em disco fica INTACTA (a tool nem chegou a escrever)');
|
|
272
|
+
const rUp = await tools.openrouterImage('desenhe', 'INPUTS/ref.png', { runDir: rd, model: 'm', imageTransport });
|
|
273
|
+
ok(rUp.ok === false && /PROIBIDA/.test(rUp.error),
|
|
274
|
+
'CAMADA 1: variação de CAIXA ("INPUTS/") também é recusada (filesystem case-insensitive não abre buraco)');
|
|
275
|
+
const rDot = await tools.openrouterImage('desenhe', 'assets/../inputs/ref.png', { runDir: rd, model: 'm', imageTransport });
|
|
276
|
+
ok(rDot.ok === false && /PROIBIDA/.test(rDot.error), 'CAMADA 1: caminho indireto ("assets/../inputs/") também é recusado');
|
|
277
|
+
let threwWrite = false;
|
|
278
|
+
try { tools.writeFile('inputs/ref.png', 'texto', { runDir: rd }); } catch (e) { threwWrite = /PROIBIDA/.test(e.message); }
|
|
279
|
+
ok(threwWrite, 'CAMADA 1: write_file sob inputs/ também é recusado (a denylist vale para TODA tool de escrita)');
|
|
280
|
+
const rOk = await tools.openrouterImage('desenhe', 'assets/cover-bg.png', { runDir: rd, model: 'm', imageTransport });
|
|
281
|
+
ok(rOk.ok === true && fs.existsSync(path.join(rd, 'assets', 'cover-bg.png')),
|
|
282
|
+
'CAMADA 1 não é bloqueio geral: gravar em assets/ continua funcionando (mudança aditiva)');
|
|
283
|
+
ok(ledgerOf(rd).assets['assets/cover-bg.png'].sha256 === tools.sha256File(path.join(rd, 'assets', 'cover-bg.png')),
|
|
284
|
+
'toda gravação por openrouter_image é REGISTRADA no ledger com o sha256 do que ficou em disco');
|
|
285
|
+
|
|
286
|
+
// A CAMADA 2 continua detectando a mesma classe — só que no EXECUTOR, e agora com HALT.
|
|
287
|
+
const rd2 = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'integ-c2' });
|
|
288
|
+
ok(tools.checkRunProvenance({ runDir: rd2 }).ok === true, 'CAMADA 2 (baseline): com a referência íntegra, a checagem canônica PASSA');
|
|
289
|
+
fs.copyFileSync(path.join(FIX, 'copy.png'), path.join(rd2, 'inputs', 'ref.png')); // denylist contornada com fs
|
|
290
|
+
const v2 = tools.checkRunProvenance({ runDir: rd2 });
|
|
291
|
+
ok(v2.ok === false && /DIVERGE/.test(v2.violations.join(' ')) && /ref\.png/.test(v2.violations.join(' ')),
|
|
292
|
+
'CAMADA 2: referência SUBSTITUÍDA por fora das tools → detectada por divergência de sha256 (fecha a CLASSE)');
|
|
293
|
+
ok(runGate(rd2).ok === true,
|
|
294
|
+
'e o script de MEDIDA não é mais quem recusa isso (quem HALTA é o executor — pod-export-executor.test.cjs §SF10.19)');
|
|
295
|
+
|
|
296
|
+
// =========================================================================
|
|
297
|
+
// 5. MEDIDA REPORTADA (DF5-6/e2) e DEGRADAÇÃO DECLARADA (AC3b/AC10)
|
|
298
|
+
// =========================================================================
|
|
299
|
+
console.log('--- 5. medida reportada e degradação declarada ---');
|
|
300
|
+
{
|
|
301
|
+
const rd4 = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'degrada' });
|
|
302
|
+
const saved = process.env.CHROME_BIN;
|
|
303
|
+
process.env.CHROME_BIN = '/nao/existe/chrome-xyz';
|
|
304
|
+
const r4 = runGate(rd4);
|
|
305
|
+
if (saved === undefined) delete process.env.CHROME_BIN; else process.env.CHROME_BIN = saved;
|
|
306
|
+
ok(r4.ok === true, 'AC3b: Chrome ausente NÃO bloqueia a etapa');
|
|
307
|
+
const art = artifactOf(rd4);
|
|
308
|
+
ok(/Medida AUSENTE/.test(art) && /Chrome/.test(art),
|
|
309
|
+
'AC3b: a medida é declarada AUSENTE no artefato (nunca omitida, nunca substituída por um valor)');
|
|
310
|
+
const m = ledgerOf(rd4).measures.visuals;
|
|
311
|
+
ok(m && m.status === 'ausente' && typeof m.reason === 'string',
|
|
312
|
+
'AC3b: a ausência fica registrada no ledger com o motivo (degradação DECLARADA, não silenciosa)');
|
|
313
|
+
ok(m.provenance_checked_here === false && /pod-export-executor/.test(String(m.provenance_enforced_by)),
|
|
314
|
+
'AC10: o registro da medida DIZ que a proveniência não foi verificada aqui e nomeia quem a assere');
|
|
315
|
+
ok(/NAO verifica PROVENIENCIA/.test(art) && /pc-run-pod/.test(art) && /NAO EXISTE/.test(art),
|
|
316
|
+
'AC10: o bloco do artefato declara, por extenso, que no driver de dev a garantia de origem NÃO existe');
|
|
317
|
+
}
|
|
318
|
+
{
|
|
319
|
+
const rd5 = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'revogado' });
|
|
320
|
+
const r5 = runGate(rd5, ['--refs-dir', '../inputs', '--assets-dir', '../assets', '--max-distance', '10']);
|
|
321
|
+
ok(r5.ok === true, '--max-distance (resíduo de R4 revogada) NÃO altera o veredito — é ignorado, não é gate');
|
|
322
|
+
const m = ledgerOf(rd5).measures.visuals;
|
|
323
|
+
ok(Array.isArray(m.ignored_args) && /max-distance/.test(m.ignored_args.join(' ')),
|
|
324
|
+
'o argumento revogado fica REGISTRADO como ignorado (nunca silencioso)');
|
|
325
|
+
}
|
|
326
|
+
if (gate.probeChrome()) {
|
|
327
|
+
const rd6 = makeRunDir({ refs: ['ref.png'], assets: ['copy.png', 'distinct.png'], label: 'medida' });
|
|
328
|
+
const r6 = runGate(rd6);
|
|
329
|
+
ok(r6.ok === true,
|
|
330
|
+
'peça quase-idêntica à referência (dist. baixa) PASSA: similaridade NÃO é veredito [Chrome real]');
|
|
331
|
+
const m = ledgerOf(rd6).measures.visuals;
|
|
332
|
+
ok(m.status === 'ok' && m.blocking === false && m.rows.length === 2 && m.rows.every((x) => Number.isInteger(x.distance)),
|
|
333
|
+
'a distância é computada por peça e gravada no ledger como medida NÃO-bloqueante [Chrome real]');
|
|
334
|
+
const byName = Object.fromEntries(m.rows.map((x) => [path.basename(x.name), x.distance]));
|
|
335
|
+
console.log(`[MEDIDA REPORTADA] copy.png=${byName['copy.png']}/64 · distinct.png=${byName['distinct.png']}/64 ` +
|
|
336
|
+
'(sem pass/fail: nenhum limiar separa as classes no conteúdo real — DF5-5)');
|
|
337
|
+
ok(byName['copy.png'] < byName['distinct.png'],
|
|
338
|
+
'a medida ORDENA como se espera (cópia mais perto que peça distinta) sem virar veredito [Chrome real]');
|
|
339
|
+
const art = artifactOf(rd6);
|
|
340
|
+
ok(/Medida de similaridade/.test(art) && /NAO e veto/.test(art) && /copy\.png/.test(art),
|
|
341
|
+
'o artefato que alimenta o checkpoint humano de assembly recebe a medida, rotulada como não-veto [Chrome real]');
|
|
342
|
+
const antesArt = artifactOf(rd6);
|
|
343
|
+
runGate(rd6);
|
|
344
|
+
const depoisArt = artifactOf(rd6);
|
|
345
|
+
ok((depoisArt.match(/pc:medida-similaridade:inicio/g) || []).length === 1 && depoisArt.length === antesArt.length,
|
|
346
|
+
'o bloco de medida é IDEMPOTENTE entre retentativas (substituído, nunca duplicado) [Chrome real]');
|
|
347
|
+
// AC10 — a MEDIDA passa a funcionar TAMBÉM no dev (DF5-6/e2 AMPLIADA): sem ledger nenhum.
|
|
348
|
+
const rd7 = makeRunDir({ refs: ['ref.png'], assets: ['distinct.png'], label: 'medida-dev', provenance: 'none' });
|
|
349
|
+
const r7 = runGate(rd7);
|
|
350
|
+
const art7 = artifactOf(rd7);
|
|
351
|
+
ok(r7.ok === true && /Distancia perceptual/.test(art7),
|
|
352
|
+
'DF5-6/e2 AMPLIADA: em run SEM ledger (dev) a medida é calculada e gravada no artefato [Chrome real]');
|
|
353
|
+
ok(!fs.existsSync(gate.provenancePathFor(rd7)),
|
|
354
|
+
'e o script NÃO cria um ledger por conta própria (fabricar proveniência seria pior que não ter)');
|
|
355
|
+
} else {
|
|
356
|
+
console.log('[SKIP ] medida com Chrome real ausente neste ambiente (a degradação declarada já foi provada acima)');
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// =========================================================================
|
|
360
|
+
// 6. Aritmética da medida (JS puro, sem Chrome)
|
|
361
|
+
// =========================================================================
|
|
362
|
+
console.log('--- 6. aritmética do hash perceptual (medida, não veredito) ---');
|
|
363
|
+
const gA = grayFrom((x, y) => (x < 16 ? 40 : 200) + ((y * 3) % 17) + (x * y) % 11);
|
|
364
|
+
const gB = grayFrom((x, y) => 255 - ((x < 16 ? 40 : 200) + ((y * 3) % 17)));
|
|
365
|
+
const hA = gate.hashFromGray(gA);
|
|
366
|
+
ok(/^[0-9a-f]{16}$/.test(hA), 'hashFromGray devolve hex de 64 bits');
|
|
367
|
+
ok(hA === gate.hashFromGray(gA), 'hashFromGray é determinístico (mesma entrada, mesmo hash)');
|
|
368
|
+
ok(gate.hamming(hA, hA) === 0, 'Hamming de hashes iguais = 0');
|
|
369
|
+
ok(gate.hamming('0000000000000000', 'ffffffffffffffff') === 64, 'Hamming de hashes opostos = 64');
|
|
370
|
+
ok(gate.hamming(hA, gate.hashFromGray(gB)) > 0, 'imagens de estrutura diferente têm hashes diferentes');
|
|
371
|
+
let threwShort = false;
|
|
372
|
+
try { gate.hashFromGray(new Uint8Array(10)); } catch { threwShort = true; }
|
|
373
|
+
ok(threwShort, 'hashFromGray recusa grayscale de tamanho inesperado (nunca hash silencioso)');
|
|
374
|
+
const rows = gate.measureDistances(
|
|
375
|
+
[{ name: 'assets/a.png', hash: '0000000000000003' }, { name: 'assets/b.png', hash: 'ffffffff0000ffff' }],
|
|
376
|
+
[{ name: 'inputs/ref.png', hash: '0000000000000000' }],
|
|
377
|
+
);
|
|
378
|
+
ok(rows.length === 2 && rows[0].distance === 2 && rows[1].distance === 48,
|
|
379
|
+
'measureDistances devolve a MENOR distância por peça (por-imagem), sem campo de veredito');
|
|
380
|
+
ok(rows.every((r) => !('copy' in r) && !('ok' in r)), 'nenhuma linha da medida carrega pass/fail — o veredito saiu do caminho');
|
|
381
|
+
ok(typeof gate.decide === 'undefined', 'a função de veredito por limiar (decide) foi REMOVIDA do módulo (R4 revogada)');
|
|
382
|
+
ok(gate.parseArgs(['--max-distance', '10']).revokedArgs.length === 1 && gate.parseArgs([]).maxDistance === undefined,
|
|
383
|
+
'parseArgs não expõe limiar: --max-distance vira argumento REVOGADO registrado');
|
|
384
|
+
ok(gate.parseMarker(`<html data-phash-gate="OK;g0:${Buffer.from(gA).toString('hex')}">`).ok === true, 'parseMarker lê o grayscale do marcador OK');
|
|
385
|
+
ok(gate.parseMarker('<html>').ok === false, 'parseMarker: marcador AUSENTE → falha (nunca green-fake)');
|
|
386
|
+
let threwOut = false;
|
|
387
|
+
try { gate.resolveWithin('/run', '/run/artifacts', '../../etc', '--refs-dir'); } catch { threwOut = true; }
|
|
388
|
+
ok(threwOut, 'resolveWithin RECUSA dir que escapa do runDir (defesa em profundidade sobre o arg literal)');
|
|
389
|
+
|
|
390
|
+
// =========================================================================
|
|
391
|
+
// 7. Materialização + registro da referência pelo EXECUTOR (DF5-1 + DF5-6) — INALTERADO
|
|
392
|
+
// =========================================================================
|
|
393
|
+
console.log('--- 7. materialização e registro da referência (executor) ---');
|
|
394
|
+
const fakeBundle = ({ vetoScripts }) => {
|
|
395
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'sf10.19-bundle-'));
|
|
396
|
+
fs.mkdirSync(path.join(root, 'phases', 'visuals'), { recursive: true });
|
|
397
|
+
fs.writeFileSync(path.join(root, 'phases', 'visuals', 'meta.json'), JSON.stringify({ agent: 'carousel-visual', veto_scripts: vetoScripts }, null, 2));
|
|
398
|
+
return root;
|
|
399
|
+
};
|
|
400
|
+
const bundleRoot = fakeBundle({ vetoScripts: ['phash-gate.cjs'] });
|
|
401
|
+
ok(exec.phasesRequiringRefs(bundleRoot).join(',') === 'visuals',
|
|
402
|
+
'phasesRequiringRefs lê o veto do meta.json do bundle (escrito pelo compilador, não por texto de agente)');
|
|
403
|
+
const inputsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sf10.19-inputs-'));
|
|
404
|
+
fs.copyFileSync(path.join(FIX, 'ref.png'), path.join(inputsDir, 'ref-pinterest.png'));
|
|
405
|
+
fs.mkdirSync(path.join(inputsDir, 'sub'), { recursive: true }); // diretório é ignorado (só arquivos regulares)
|
|
406
|
+
const runDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sf10.19-run-'));
|
|
407
|
+
const rMat = exec.materializeInputs({ bundleRoot, inputsDir, runDir });
|
|
408
|
+
ok(fs.existsSync(path.join(runDir, 'inputs', 'ref-pinterest.png')) && rMat.copied.length === 1,
|
|
409
|
+
'materializeInputs COPIA a referência para <runDir>/inputs/ por CÓDIGO (não depende de read_image do modelo)');
|
|
410
|
+
ok(ledgerOf(runDir).inputs['inputs/ref-pinterest.png'].sha256 === tools.sha256File(path.join(runDir, 'inputs', 'ref-pinterest.png')),
|
|
411
|
+
'materializeInputs REGISTRA o sha256 da referência materializada (camada 2 nasce no arranque do run)');
|
|
412
|
+
exec.materializeInputs({ bundleRoot, inputsDir, runDir });
|
|
413
|
+
ok(tools.checkRunProvenance({ runDir }).ok,
|
|
414
|
+
'materializeInputs é idempotente (run e resume) e mantém a proveniência íntegra');
|
|
415
|
+
let msg = '';
|
|
416
|
+
try { exec.materializeInputs({ bundleRoot, inputsDir: null, runDir: fs.mkdtempSync(path.join(os.tmpdir(), 'sf10.19-run2-')) }); }
|
|
417
|
+
catch (e) { msg = e.message; }
|
|
418
|
+
ok(/phash-gate\.cjs/.test(msg) && /inputs_dir/.test(msg),
|
|
419
|
+
'fase que declara o veto SEM inputs_dir → ABORTA fail-loud antes de gastar API');
|
|
420
|
+
const plainBundle = fakeBundle({ vetoScripts: ['lexical-check.cjs'] });
|
|
421
|
+
let threw = false;
|
|
422
|
+
try { exec.materializeInputs({ bundleRoot: plainBundle, inputsDir: null, runDir: fs.mkdtempSync(path.join(os.tmpdir(), 'sf10.19-run3-')) }); }
|
|
423
|
+
catch { threw = true; }
|
|
424
|
+
ok(!threw, 'pod SEM o veto de não-cópia não passa a exigir inputs_dir (mudança ADITIVA, sem regressão)');
|
|
425
|
+
|
|
426
|
+
if (failures.length > 0) {
|
|
427
|
+
console.error(`\nSuíte phash-gate FALHOU: ${failures.length} de ${passed + failures.length}.`);
|
|
428
|
+
process.exit(1);
|
|
429
|
+
}
|
|
430
|
+
console.log(`\n${passed} asserções verdes. phash-gate.cjs é MEDIDA-ONLY (nenhum estado de insumo bloqueia); ` +
|
|
431
|
+
'a PROVENIÊNCIA bloqueia no executor de export (pod-export-executor.test.cjs §SF10.19).');
|
|
432
|
+
process.exit(0);
|
|
433
|
+
})().catch((e) => { console.error('[FALHA] exceção não tratada na suíte:', e); process.exit(1); });
|