@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,382 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* migration-manifest-sf3.2.test.cjs — suíte das EXTENSÕES SF3.2 do manifest:
|
|
5
|
+
* - AC5: feature-diff decide no advance→gates (exit 4 ANTES de pagar runs); backstop.
|
|
6
|
+
* - AC6: motor pinado (motor_files[]/motor_hash); diff de 1 byte → exit 4 até decisão
|
|
7
|
+
* registrada (--approved-by) ou re-âncora; alterar motor_files[] fora de decisão
|
|
8
|
+
* (hand-edit do YAML) → exit 3 (integrity).
|
|
9
|
+
* - AC7: close-line/verify RE-EXECUTAM o sweep (não releem report); report adulterado
|
|
10
|
+
* não muda o veredito; re-execução é a fonte de verdade.
|
|
11
|
+
* - AC9: waiver de legado inexecutável (tentativa real + declarados + aprovação).
|
|
12
|
+
*
|
|
13
|
+
* Arquivo separado da suíte SF3.1 (isola território, evita colisão de expectativa). Roda
|
|
14
|
+
* a partir da raiz do repo (motor_files[] default são relativos à raiz). Node >= 18.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('node:fs');
|
|
18
|
+
const os = require('node:os');
|
|
19
|
+
const path = require('node:path');
|
|
20
|
+
const crypto = require('node:crypto');
|
|
21
|
+
const M = require('./migration-manifest.cjs');
|
|
22
|
+
|
|
23
|
+
let passed = 0;
|
|
24
|
+
const failures = [];
|
|
25
|
+
function ok(cond, label) {
|
|
26
|
+
if (cond) { passed++; console.log(`[OK ] ${label}`); }
|
|
27
|
+
else { failures.push(label); console.log(`[FALHA] ${label}`); }
|
|
28
|
+
}
|
|
29
|
+
function exitOf(fn) {
|
|
30
|
+
try { fn(); return 0; } catch (e) { return e instanceof M.ManifestError ? e.exitCode : -1; }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const REPO = process.cwd();
|
|
34
|
+
const FORMS_DIR = path.join(REPO, 'scripts', '__fixtures__', 'sweep-forms');
|
|
35
|
+
const FORMS_WF = path.join(FORMS_DIR, 'workflows', 'wf-forms.yaml');
|
|
36
|
+
const FORMS_SPEC = path.join(FORMS_DIR, 'specs', 'wf-forms.spec.json');
|
|
37
|
+
const sha256File = (p) => crypto.createHash('sha256').update(fs.readFileSync(p)).digest('hex');
|
|
38
|
+
|
|
39
|
+
function tmp() { return fs.mkdtempSync(path.join(os.tmpdir(), 'pc-mm32-')); }
|
|
40
|
+
// Pós-QA sf3.3: init exige --squad-dir (inventory nunca null) e open-line exige
|
|
41
|
+
// triagem 'migrate' APROVADA (sem caminho dormente). Fixtures dão aprovação sintética.
|
|
42
|
+
function initForms(mfv) { return M.cmdInit(mfv, { squad: 'demo', squadDir: FORMS_DIR }); }
|
|
43
|
+
function openForms(mfv) {
|
|
44
|
+
M.cmdTriageSet(mfv, { workflow: 'wf-forms', disposition: 'migrate', purpose: 'fixture:1', basis: 'dado' });
|
|
45
|
+
M.cmdTriageApprove(mfv, { workflow: 'wf-forms', approvedBy: 'daniel' });
|
|
46
|
+
return M.cmdOpenLine(mfv, { workflow: 'wf-forms', spec: FORMS_SPEC, podDir: FORMS_DIR });
|
|
47
|
+
}
|
|
48
|
+
function advanceTo(mf, workflow, phase, extra = {}) {
|
|
49
|
+
const seq = ['generated', 'distilled', 'linted', 'gates'];
|
|
50
|
+
for (const p of seq) {
|
|
51
|
+
M.cmdAdvance(mf, { workflow, to: p, ...(p === phase ? extra : {}) });
|
|
52
|
+
if (p === phase) return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ===========================================================================
|
|
57
|
+
// AC5 — feature-diff → exit 4 no advance (ANTES de pagar runs).
|
|
58
|
+
// ===========================================================================
|
|
59
|
+
{
|
|
60
|
+
const dir = tmp();
|
|
61
|
+
const mf = path.join(dir, 'm.yaml');
|
|
62
|
+
initForms(mf);
|
|
63
|
+
// Âncora cobre SÓ count_gte/field_matches (como a âncora r1 real). wf-forms traz
|
|
64
|
+
// json_schema_valid/section_exists/file_referenced_exists → fora de features_covered.
|
|
65
|
+
M.cmdSetAnchor(mf, {
|
|
66
|
+
decision: 'ancora SF1.5 (fixture)', assertionTypes: ['count_gte', 'field_matches'],
|
|
67
|
+
dagShapes: ['linear'], checkpointPositions: ['final'],
|
|
68
|
+
});
|
|
69
|
+
openForms(mf);
|
|
70
|
+
// advance generated/distilled/linted OK (hook só em gates).
|
|
71
|
+
M.cmdAdvance(mf, { workflow: 'wf-forms', to: 'generated' });
|
|
72
|
+
M.cmdAdvance(mf, { workflow: 'wf-forms', to: 'distilled' });
|
|
73
|
+
M.cmdAdvance(mf, { workflow: 'wf-forms', to: 'linted' });
|
|
74
|
+
const code = exitOf(() => M.cmdAdvance(mf, { workflow: 'wf-forms', to: 'gates', wfPath: FORMS_WF }));
|
|
75
|
+
ok(code === 4, `AC5 advance→gates com feature fora de features_covered → exit 4 (obtido ${code})`);
|
|
76
|
+
// A linha NÃO avançou para gates (exit 4 ANTES de escrever a fase).
|
|
77
|
+
const doc = M.readManifest(mf);
|
|
78
|
+
ok(doc.lines[0].phase === 'linted', 'AC5 exit 4 é ANTES de pagar runs: a linha permanece em "linted" (não escreveu gates)');
|
|
79
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// AC5 backstop — checkReanchorGate re-aplicado (close-line usa o MESMO check).
|
|
83
|
+
{
|
|
84
|
+
const dir = tmp();
|
|
85
|
+
const mf = path.join(dir, 'm.yaml');
|
|
86
|
+
initForms(mf);
|
|
87
|
+
M.cmdSetAnchor(mf, { decision: 'ancora estreita', assertionTypes: ['count_gte'], dagShapes: ['linear'], checkpointPositions: ['final'] });
|
|
88
|
+
openForms(mf);
|
|
89
|
+
const doc = M.readManifest(mf);
|
|
90
|
+
const line = doc.lines[0];
|
|
91
|
+
const code = exitOf(() => M.checkReanchorGate(doc, line, { wfPath: FORMS_WF }, REPO));
|
|
92
|
+
ok(code === 4, `AC5 backstop: checkReanchorGate (o check do close-line) também dá exit 4 (obtido ${code})`);
|
|
93
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// AC5 — CALIBRAÇÃO 2026-07-25 (ADR-006 §Consequências): `agents_shared` SAIU do tuple.
|
|
97
|
+
// Teste INVERTIDO: agente reusado em 2 etapas do MESMO workflow → NÃO dispara re-âncora
|
|
98
|
+
// (o motor é agent-agnóstico, keyed por stepId; prova código-verificada f3@f9b49b7).
|
|
99
|
+
{
|
|
100
|
+
const dir = tmp();
|
|
101
|
+
const wfShared = path.join(dir, 'wf-shared.yaml');
|
|
102
|
+
fs.writeFileSync(wfShared, [
|
|
103
|
+
'state_machine:', ' states: [init, running, complete, failed]', ' initial: init',
|
|
104
|
+
' terminal: [complete, failed]', 'steps:',
|
|
105
|
+
' - id: s1', ' agent: shared-agent', ' template: t.md', ' inputs: [x]', ' outputs: [y]',
|
|
106
|
+
' depends_on: []', ' checkpoint: null', ' veto:', ' assertions:',
|
|
107
|
+
' - {"type":"count_gte","field":"Itens","n":2}',
|
|
108
|
+
' - id: s2', ' agent: shared-agent', ' template: t.md', ' inputs: [y]', ' outputs: [z]',
|
|
109
|
+
' depends_on: [s1]', ' checkpoint: null', ' veto:', ' assertions:',
|
|
110
|
+
' - {"type":"count_gte","field":"Itens","n":2}', '',
|
|
111
|
+
].join('\n'));
|
|
112
|
+
// features do wf-shared: {count_gte, linear, [], fix_loop:false} — TODAS cobertas.
|
|
113
|
+
const feat = M.computeFeatureSet(require('./validate-pod-workflow.cjs').parseYaml(fs.readFileSync(wfShared, 'utf8')));
|
|
114
|
+
ok(!('agents_shared' in feat), 'AC5-calibração: computeFeatureSet NÃO emite mais `agents_shared` (tuple: assertion_types, dag_shape, checkpoint_positions, fix_loop)');
|
|
115
|
+
const doc = { squad: 'x', anchor: { features_covered: { assertion_types: ['count_gte'], dag_shapes: ['linear'], checkpoint_positions: [], fix_loop: false }, motor: { files: M.DEFAULT_MOTOR_FILES, hash: M.computeMotorHash(M.DEFAULT_MOTOR_FILES, REPO) } }, lines: [] };
|
|
116
|
+
const line = { workflow: 'wf-shared', pod: 'p', pod_dir: dir, wf_path: wfShared };
|
|
117
|
+
const code = exitOf(() => M.checkReanchorGate(doc, line, { wfPath: wfShared }, REPO));
|
|
118
|
+
ok(code === 0, `AC5-calibração: agente reusado em 2 etapas → NÃO dispara re-âncora, prossegue LITE (exit ${code})`);
|
|
119
|
+
// Gatilho remanescente CONTINUA firme: um assertion_type novo (json_schema_valid) → exit 4.
|
|
120
|
+
const wfNewFeat = path.join(dir, 'wf-json.yaml');
|
|
121
|
+
fs.writeFileSync(wfNewFeat, [
|
|
122
|
+
'state_machine:', ' states: [init, running, complete, failed]', ' initial: init',
|
|
123
|
+
' terminal: [complete, failed]', 'steps:',
|
|
124
|
+
' - id: s1', ' agent: a1', ' template: t.md', ' inputs: [x]', ' outputs: [y]',
|
|
125
|
+
' depends_on: []', ' checkpoint: null', ' veto:', ' assertions:',
|
|
126
|
+
' - {"type":"json_schema_valid","schema":["k"]}', '',
|
|
127
|
+
].join('\n'));
|
|
128
|
+
const line2 = { workflow: 'wf-json', pod: 'p', pod_dir: dir, wf_path: wfNewFeat };
|
|
129
|
+
const code2 = exitOf(() => M.checkReanchorGate(doc, line2, { wfPath: wfNewFeat }, REPO));
|
|
130
|
+
ok(code2 === 4, `AC5-calibração: gatilho remanescente firme — assertion_type novo (json_schema_valid) fora de features_covered → exit 4 (obtido ${code2})`);
|
|
131
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ===========================================================================
|
|
135
|
+
// AC6 — motor pinado.
|
|
136
|
+
// ===========================================================================
|
|
137
|
+
// (a) motor_files[] default reflete pc-run-pod.cjs PÓS-fix da SF3.1.
|
|
138
|
+
{
|
|
139
|
+
ok(M.DEFAULT_MOTOR_FILES.includes('scripts/pc-run-pod.cjs'), 'AC6 motor_files[] inclui pc-run-pod.cjs');
|
|
140
|
+
const runnerSrc = fs.readFileSync(path.join(REPO, 'scripts', 'pc-run-pod.cjs'), 'utf8');
|
|
141
|
+
ok(/M-r2-5|contagem\s+REAL|caminho\s+`extractField`/.test(runnerSrc),
|
|
142
|
+
'AC6 pc-run-pod.cjs é o PÓS-fix (marca M-r2-5 do count_gte presente — hash sobre a versão correta)');
|
|
143
|
+
const h = M.computeMotorHash(M.DEFAULT_MOTOR_FILES, REPO);
|
|
144
|
+
ok(/^[0-9a-f]{64}$/.test(h), 'AC6 motor_hash = sha256 de 64 hex sobre a lista de motor_files real');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// (b) diff de 1 byte em arquivo de motor_files[] → exit 4 até decisão registrada.
|
|
148
|
+
{
|
|
149
|
+
const dir = tmp();
|
|
150
|
+
const mf = path.join(dir, 'm.yaml');
|
|
151
|
+
const motorFix = path.join(dir, 'motor-fixture.cjs');
|
|
152
|
+
fs.writeFileSync(motorFix, '// motor fixture v1\n');
|
|
153
|
+
initForms(mf);
|
|
154
|
+
// Âncora cobre TODAS as features do wf-forms (via --from-wf) para ISOLAR o check de motor.
|
|
155
|
+
M.cmdSetAnchor(mf, { decision: 'ancora com motor fixture', fromWf: FORMS_WF, motorFiles: [motorFix] });
|
|
156
|
+
openForms(mf);
|
|
157
|
+
M.cmdAdvance(mf, { workflow: 'wf-forms', to: 'generated' });
|
|
158
|
+
M.cmdAdvance(mf, { workflow: 'wf-forms', to: 'distilled' });
|
|
159
|
+
M.cmdAdvance(mf, { workflow: 'wf-forms', to: 'linted' });
|
|
160
|
+
// sem mudança: advance→gates passa (feature coberto + motor íntegro).
|
|
161
|
+
const okCode = exitOf(() => M.cmdAdvance(mf, { workflow: 'wf-forms', to: 'gates', wfPath: FORMS_WF }));
|
|
162
|
+
ok(okCode === 0, `AC6 motor íntegro + features cobertas → advance→gates OK (obtido ${okCode})`);
|
|
163
|
+
// Retrocede reabrindo a linha (nova spec_hash força fase spec) para re-testar advance.
|
|
164
|
+
// Em vez disso: novo manifest, muta 1 byte ANTES do advance→gates.
|
|
165
|
+
const dir2 = tmp();
|
|
166
|
+
const mf2 = path.join(dir2, 'm.yaml');
|
|
167
|
+
const motorFix2 = path.join(dir2, 'motor.cjs');
|
|
168
|
+
fs.writeFileSync(motorFix2, '// motor v1\n');
|
|
169
|
+
initForms(mf2);
|
|
170
|
+
M.cmdSetAnchor(mf2, { decision: 'ancora', fromWf: FORMS_WF, motorFiles: [motorFix2] });
|
|
171
|
+
openForms(mf2);
|
|
172
|
+
M.cmdAdvance(mf2, { workflow: 'wf-forms', to: 'generated' });
|
|
173
|
+
M.cmdAdvance(mf2, { workflow: 'wf-forms', to: 'distilled' });
|
|
174
|
+
M.cmdAdvance(mf2, { workflow: 'wf-forms', to: 'linted' });
|
|
175
|
+
fs.appendFileSync(motorFix2, 'X'); // 1 byte a mais
|
|
176
|
+
const code = exitOf(() => M.cmdAdvance(mf2, { workflow: 'wf-forms', to: 'gates', wfPath: FORMS_WF }));
|
|
177
|
+
ok(code === 4, `AC6 diff de 1 byte em motor_files[] → recusa LITE (exit 4) (obtido ${code})`);
|
|
178
|
+
// decisão registrada: --approved-by libera e REGISTRA a aceitação.
|
|
179
|
+
const okApproved = exitOf(() => M.cmdAdvance(mf2, { workflow: 'wf-forms', to: 'gates', wfPath: FORMS_WF, approvedBy: 'Daniel: revisei, motor sem mudança de verificação' }));
|
|
180
|
+
ok(okApproved === 0, `AC6 --approved-by libera o advance após motor diff (obtido ${okApproved})`);
|
|
181
|
+
const d2 = M.readManifest(mf2);
|
|
182
|
+
ok(d2.lines[0].motor_approval && /Daniel/.test(d2.lines[0].motor_approval.approved_by),
|
|
183
|
+
'AC6 aceitação de motor fica REGISTRADA na linha (motor_approval.approved_by)');
|
|
184
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
185
|
+
fs.rmSync(dir2, { recursive: true, force: true });
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// (c) alterar motor_files[] fora de decisão de re-âncora (hand-edit do YAML) → exit 3.
|
|
189
|
+
{
|
|
190
|
+
const dir = tmp();
|
|
191
|
+
const mf = path.join(dir, 'm.yaml');
|
|
192
|
+
initForms(mf);
|
|
193
|
+
M.cmdSetAnchor(mf, { decision: 'ancora', assertionTypes: ['count_gte'], dagShapes: ['linear'] });
|
|
194
|
+
// hand-edit: injeta um motor_file extra direto no YAML (fora do set-anchor).
|
|
195
|
+
let text = fs.readFileSync(mf, 'utf8');
|
|
196
|
+
text = text.replace('"scripts/pc-run-pod.cjs"', '"scripts/pc-run-pod.cjs"\n - "scripts/INJETADO.cjs"');
|
|
197
|
+
fs.writeFileSync(mf, text);
|
|
198
|
+
const code = exitOf(() => M.readManifest(mf));
|
|
199
|
+
ok(code === 3, `AC6 alterar motor_files[] à mão (fora de set-anchor) → integrity exit 3 (obtido ${code})`);
|
|
200
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ===========================================================================
|
|
204
|
+
// AC7 — close-line/verify RE-EXECUTAM o sweep; report adulterado não muda veredito.
|
|
205
|
+
// ===========================================================================
|
|
206
|
+
function fakeRunState(dir, workflow, pod) {
|
|
207
|
+
const p = path.join(dir, 'state.json');
|
|
208
|
+
fs.writeFileSync(p, JSON.stringify({ workflow, pod, run_id: 'r1', steps: {} }));
|
|
209
|
+
return p;
|
|
210
|
+
}
|
|
211
|
+
{
|
|
212
|
+
const dir = tmp();
|
|
213
|
+
const mf = path.join(dir, 'm.yaml');
|
|
214
|
+
initForms(mf);
|
|
215
|
+
// sem âncora → gate de re-âncora é no-op; foco no sweep re-executado.
|
|
216
|
+
openForms(mf);
|
|
217
|
+
advanceTo(mf, 'wf-forms', 'gates', { wfPath: FORMS_WF });
|
|
218
|
+
const runId = fakeRunState(dir, 'wf-forms', 'sweep-forms');
|
|
219
|
+
// Report ADULTERADO em disco (alegando falha) — close-line NUNCA o lê.
|
|
220
|
+
fs.writeFileSync(FORMS_WF.replace(/\.yaml$/, '.smoke.report.json'),
|
|
221
|
+
JSON.stringify({ proofs: [{ step: 's_field', assertion: '0:field_matches', blocked: false }] }));
|
|
222
|
+
const code = exitOf(() => M.cmdCloseLine(mf, { workflow: 'wf-forms', wfPath: FORMS_WF, runIds: [runId] }));
|
|
223
|
+
ok(code === 0, `AC7 close-line com sweep re-executado (report adulterado presente, ignorado) → sucesso (obtido ${code})`);
|
|
224
|
+
const doc = M.readManifest(mf);
|
|
225
|
+
ok(doc.lines[0].phase === 'closed' && doc.lines[0].sweep && doc.lines[0].sweep.proofs === 9,
|
|
226
|
+
'AC7 close-line REALMENTE re-executou o sweep (9 provas gravadas) — veredito da re-execução, não do report');
|
|
227
|
+
// F3 verify re-executa e mantém a linha válida (report adulterado segue inerte).
|
|
228
|
+
const v = M.cmdVerify(mf);
|
|
229
|
+
ok(v.stale.length === 0, 'AC7 verify (F3) re-executa o sweep; report adulterado NÃO torna a linha stale');
|
|
230
|
+
fs.rmSync(FORMS_WF.replace(/\.yaml$/, '.smoke.report.json'), { force: true });
|
|
231
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// AC7 — a re-execução é a FONTE: um sweep que vaza/underivável faz reExecuteSweep recusar.
|
|
235
|
+
{
|
|
236
|
+
const dir = tmp();
|
|
237
|
+
fs.mkdirSync(path.join(dir, 'workflows'));
|
|
238
|
+
fs.mkdirSync(path.join(dir, 'templates'));
|
|
239
|
+
fs.writeFileSync(path.join(dir, 'templates', 't.md'), '## Sec\n');
|
|
240
|
+
const wf = ['state_machine:', ' states: [init, running, complete, failed]', ' initial: init',
|
|
241
|
+
' terminal: [complete, failed]', 'steps:', ' - id: s1', ' agent: a1', ' template: templates/t.md',
|
|
242
|
+
' inputs: [x]', ' outputs: [y]', ' depends_on: []', ' checkpoint: null', ' veto:',
|
|
243
|
+
' assertions:', ' - {"type":"field_matches","field":"v","pattern":".*"}', ''].join('\n');
|
|
244
|
+
const wfPath = path.join(dir, 'workflows', 'wf-u.yaml');
|
|
245
|
+
fs.writeFileSync(wfPath, wf);
|
|
246
|
+
fs.writeFileSync(wfPath.replace(/\.yaml$/, '.smoke.json'), JSON.stringify({ target_step: 's1', artifacts: { s1: '## Sec\nv: x\n' } }));
|
|
247
|
+
const line = { workflow: 'wf-u', pod: path.basename(dir), pod_dir: dir, wf_path: wfPath };
|
|
248
|
+
const sw = M.reExecuteSweep(line, { wfPath }, REPO);
|
|
249
|
+
ok(sw.ran === true && sw.ok === false && /underiv/i.test(sw.failures.join(' ')),
|
|
250
|
+
'AC7 reExecuteSweep é a fonte de verdade: sweep underivável → ran:true, ok:false (recusaria o close)');
|
|
251
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// ===========================================================================
|
|
255
|
+
// AC9 — waiver de legado inexecutável (mecanismo).
|
|
256
|
+
// ===========================================================================
|
|
257
|
+
{
|
|
258
|
+
const dir = tmp();
|
|
259
|
+
const mf = path.join(dir, 'm.yaml');
|
|
260
|
+
initForms(mf);
|
|
261
|
+
openForms(mf);
|
|
262
|
+
// sem transcript de tentativa → RECUSA ("não rodei" não é "não roda").
|
|
263
|
+
const noAttempt = exitOf(() => M.cmdWaiverSet(mf, { workflow: 'wf-forms', approvedBy: 'Daniel', declared: ['out.md'] }));
|
|
264
|
+
ok(noAttempt === 2, `AC9 waiver sem --transcript (tentativa registrada) → recusa exit 2 (obtido ${noAttempt})`);
|
|
265
|
+
// transcript inexistente → RECUSA.
|
|
266
|
+
const badTr = exitOf(() => M.cmdWaiverSet(mf, { workflow: 'wf-forms', transcript: path.join(dir, 'nope.txt'), approvedBy: 'Daniel', declared: ['out.md'] }));
|
|
267
|
+
ok(badTr === 2, `AC9 waiver com transcript inexistente → recusa exit 2 (obtido ${badTr})`);
|
|
268
|
+
// tentativa real registrada + aprovação + declarados → grava o waiver.
|
|
269
|
+
const tr = path.join(dir, 'attempt.log');
|
|
270
|
+
fs.writeFileSync(tr, 'tentativa real do legado full-sdc: 16 personas, sem runner, não completou.\n');
|
|
271
|
+
M.cmdWaiverSet(mf, { workflow: 'wf-forms', transcript: tr, approvedBy: 'Daniel: precedente full-sdc do ledger', declared: ['offer.md', 'model.md'], partial: [path.join(dir, 'p1.md')] });
|
|
272
|
+
const doc = M.readManifest(mf);
|
|
273
|
+
const w = doc.lines[0].legacy_waiver;
|
|
274
|
+
ok(w && w.approved_by && w.declared_artifacts.length === 2 && w.transcript,
|
|
275
|
+
'AC9 waiver registrado com tentativa + aprovação + artefatos DECLARADOS (completude passa a comparar contra os declarados)');
|
|
276
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ===========================================================================
|
|
280
|
+
// SF3.4 (ADR-006 §Consequências) — reopen-line + verify vê drift em linha closed.
|
|
281
|
+
// ===========================================================================
|
|
282
|
+
function fakeRun(dir, workflow, pod) {
|
|
283
|
+
const p = path.join(dir, 'state.json');
|
|
284
|
+
fs.writeFileSync(p, JSON.stringify({ workflow, pod, run_id: 'r1', steps: {} }));
|
|
285
|
+
return p;
|
|
286
|
+
}
|
|
287
|
+
function closeWideLine(dir, mf) {
|
|
288
|
+
initForms(mf);
|
|
289
|
+
M.cmdSetAnchor(mf, { decision: 'ancora wide (fixture)', fromWf: FORMS_WF });
|
|
290
|
+
openForms(mf);
|
|
291
|
+
advanceTo(mf, 'wf-forms', 'gates', { wfPath: FORMS_WF });
|
|
292
|
+
const runId = fakeRun(dir, 'wf-forms', 'sweep-forms');
|
|
293
|
+
M.cmdCloseLine(mf, { workflow: 'wf-forms', wfPath: FORMS_WF, runIds: [runId] });
|
|
294
|
+
return runId;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// (a) RECUSAS — sem approved-by / sem decision-ref / linha não-closed / reason inválido.
|
|
298
|
+
{
|
|
299
|
+
const dir = tmp();
|
|
300
|
+
const mf = path.join(dir, 'm.yaml');
|
|
301
|
+
// linha NÃO-closed → recusa.
|
|
302
|
+
initForms(mf);
|
|
303
|
+
M.cmdSetAnchor(mf, { decision: 'w', fromWf: FORMS_WF });
|
|
304
|
+
openForms(mf);
|
|
305
|
+
const notClosed = exitOf(() => M.cmdReopenLine(mf, { workflow: 'wf-forms', reason: 'reanchor', feature: 'checkpoint:mid', approvedBy: 'Daniel', decisionRef: 'docs/adr/ADR-006.md' }));
|
|
306
|
+
ok(notClosed === 2, `SF3.4 reopen recusa linha NÃO-closed → exit 2 (obtido ${notClosed})`);
|
|
307
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
308
|
+
|
|
309
|
+
const dir2 = tmp();
|
|
310
|
+
const mf2 = path.join(dir2, 'm.yaml');
|
|
311
|
+
closeWideLine(dir2, mf2);
|
|
312
|
+
const badReason = exitOf(() => M.cmdReopenLine(mf2, { workflow: 'wf-forms', reason: 'porque-sim', feature: 'x', approvedBy: 'D', decisionRef: 'p' }));
|
|
313
|
+
ok(badReason === 2, `SF3.4 reopen recusa --reason ≠ reanchor → exit 2 (obtido ${badReason})`);
|
|
314
|
+
const noApprove = exitOf(() => M.cmdReopenLine(mf2, { workflow: 'wf-forms', reason: 'reanchor', feature: 'checkpoint:mid', decisionRef: 'p' }));
|
|
315
|
+
ok(noApprove === 2, `SF3.4 reopen recusa SEM --approved-by → exit 2 (obtido ${noApprove})`);
|
|
316
|
+
const noRef = exitOf(() => M.cmdReopenLine(mf2, { workflow: 'wf-forms', reason: 'reanchor', feature: 'checkpoint:mid', approvedBy: 'Daniel' }));
|
|
317
|
+
ok(noRef === 2, `SF3.4 reopen recusa SEM --decision-ref → exit 2 (obtido ${noRef})`);
|
|
318
|
+
// após as recusas a linha continua closed (nenhuma escreveu).
|
|
319
|
+
ok(M.readManifest(mf2).lines[0].phase === 'closed', 'SF3.4 recusas de reopen NÃO mutam a linha (segue closed)');
|
|
320
|
+
fs.rmSync(dir2, { recursive: true, force: true });
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// (b) SUPERSEDED[] preservado byte-a-byte + linha viva limpa + phase=linted.
|
|
324
|
+
{
|
|
325
|
+
const dir = tmp();
|
|
326
|
+
const mf = path.join(dir, 'm.yaml');
|
|
327
|
+
closeWideLine(dir, mf);
|
|
328
|
+
const before = M.readManifest(mf).lines[0];
|
|
329
|
+
const snapExpect = {};
|
|
330
|
+
// mesma lista que cmdReopenLine snapshota (só os campos PRESENTES na linha viva).
|
|
331
|
+
for (const f of ['wf_path', 'run_ids', 'pair', 'closed_at', 'verify', 'feature_set', 'sweep', 'motor_approval', 'advanced_at', 'stale', 'stale_at']) if (f in before) snapExpect[f] = before[f];
|
|
332
|
+
const specHashBefore = before.spec_hash; const baselineBefore = before.baseline;
|
|
333
|
+
M.cmdReopenLine(mf, { workflow: 'wf-forms', reason: 'reanchor', feature: 'checkpoint:mid', approvedBy: 'Daniel: checkpoint mid-DAG regenerado', decisionRef: 'docs/adr/ADR-006.md#consequencias' });
|
|
334
|
+
const after = M.readManifest(mf).lines[0];
|
|
335
|
+
ok(after.phase === 'linted', 'SF3.4 reopen devolve a linha à fase pré-gates (linted) para o pre-gates-check re-decidir');
|
|
336
|
+
ok(Array.isArray(after.superseded) && after.superseded.length === 1, 'SF3.4 reopen faz append em superseded[] (1 entrada)');
|
|
337
|
+
const sup = after.superseded[0];
|
|
338
|
+
ok(sup.reason === 'reanchor' && sup.feature === 'checkpoint:mid' && /Daniel/.test(sup.approved_by) && /ADR-006/.test(sup.decision_ref) && sup.superseded_at,
|
|
339
|
+
'SF3.4 superseded[] registra reason/feature/approved_by/decision_ref/superseded_at');
|
|
340
|
+
const canon = (o) => JSON.stringify(o, Object.keys(o).sort()); // ordem-insensível no topo
|
|
341
|
+
ok(canon(sup.snapshot) === canon(snapExpect),
|
|
342
|
+
'SF3.4 snapshot da adjudicação anterior preservado BYTE-A-BYTE (wf_path/run_ids/closed_at/verify/feature_set/sweep)');
|
|
343
|
+
ok(!('closed_at' in after) && !('sweep' in after) && !('feature_set' in after) && after.run_ids.length === 0,
|
|
344
|
+
'SF3.4 linha VIVA limpa da adjudicação (closed_at/sweep/feature_set removidos; run_ids zerado)');
|
|
345
|
+
ok(after.spec_hash === specHashBefore && JSON.stringify(after.baseline) === JSON.stringify(baselineBefore),
|
|
346
|
+
'SF3.4 identidade da linha PRESERVADA (spec_hash/baseline intactos) — NUNCA apaga histórico');
|
|
347
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// (c) VERIFY vê drift em linha CLOSED (feature-set do wf ATUAL vs covered ATUAL) → stale ruidoso.
|
|
351
|
+
{
|
|
352
|
+
const dir = tmp();
|
|
353
|
+
const mf = path.join(dir, 'm.yaml');
|
|
354
|
+
closeWideLine(dir, mf); // fechada sob âncora WIDE (cobre tudo).
|
|
355
|
+
// âncora ESTREITA depois (drift: covered vigente já não cobre field_matches/json/etc do wf).
|
|
356
|
+
M.cmdSetAnchor(mf, { decision: 're-âncora estreita', assertionTypes: ['count_gte'], dagShapes: ['linear'], checkpointPositions: ['final'] });
|
|
357
|
+
const v = M.cmdVerify(mf);
|
|
358
|
+
ok(v.stale.length === 1, 'SF3.4 verify detecta drift de feature-set em linha CLOSED → 1 linha stale (antes era invisível)');
|
|
359
|
+
const drift = v.report[0].failures.join(' | ');
|
|
360
|
+
ok(/feature drift/i.test(drift) && /reopen-line/.test(drift),
|
|
361
|
+
`SF3.4 verify falha RUIDOSA apontando reopen-line ("${drift.slice(0, 70)}…")`);
|
|
362
|
+
ok(M.readManifest(mf).lines[0].phase === 'gates', 'SF3.4 linha driftada volta a stale via a via existente (phase=gates)');
|
|
363
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// (d) FLUXO reopen→advance→exit 4 (a re-adjudicação roteia para FULL).
|
|
367
|
+
{
|
|
368
|
+
const dir = tmp();
|
|
369
|
+
const mf = path.join(dir, 'm.yaml');
|
|
370
|
+
closeWideLine(dir, mf);
|
|
371
|
+
M.cmdSetAnchor(mf, { decision: 're-âncora estreita', assertionTypes: ['count_gte'], dagShapes: ['linear'], checkpointPositions: ['final'] });
|
|
372
|
+
M.cmdReopenLine(mf, { workflow: 'wf-forms', reason: 'reanchor', feature: 'assertion_type:field_matches', approvedBy: 'Daniel', decisionRef: 'docs/adr/ADR-006.md' });
|
|
373
|
+
const code = exitOf(() => M.cmdAdvance(mf, { workflow: 'wf-forms', to: 'gates', wfPath: FORMS_WF }));
|
|
374
|
+
ok(code === 4, `SF3.4 reopen→advance→gates com feature descoberto → exit 4 (roteia FULL) (obtido ${code})`);
|
|
375
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// ===========================================================================
|
|
379
|
+
console.log(`\n${passed} asserções OK; ${failures.length} falha(s).`);
|
|
380
|
+
if (failures.length) { for (const f of failures) console.error(` ✗ ${f}`); process.exit(1); }
|
|
381
|
+
console.log('migration-manifest-sf3.2: feature-diff/exit 4 + motor pinado + sweep re-executado + waiver + reopen/drift provados.');
|
|
382
|
+
process.exit(0);
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* migration-manifest-sf3.3.test.cjs — suíte das EXTENSÕES F0/F1/VIRAR-COMANDO da
|
|
5
|
+
* SF3.3 sobre o escritor único (não reimplementa nada da SF3.1/3.2).
|
|
6
|
+
* NÃO-fake-green: cada recusa é provada por estado real em disco.
|
|
7
|
+
* Cobre:
|
|
8
|
+
* AC1 F0 inventário: init --squad-dir escaneia TODAS as famílias + grep de comandos.
|
|
9
|
+
* AC2 F1 STOP: open-line RECUSA sem triagem aprovada (num manifest de migração);
|
|
10
|
+
* gate dormente sem inventory (compat SF3.1).
|
|
11
|
+
* AC4 disposição EXPLÍCITA de scripts/checklists (3 destinos) registrada no manifest.
|
|
12
|
+
* AC9 VIRAR-COMANDO: sem os 3 → pendente; única saída é dispensar; com os 3 → fecha.
|
|
13
|
+
*
|
|
14
|
+
* Node >= 18. Exit 0/1.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('node:fs');
|
|
18
|
+
const os = require('node:os');
|
|
19
|
+
const path = require('node:path');
|
|
20
|
+
|
|
21
|
+
const m = require('./migration-manifest.cjs');
|
|
22
|
+
|
|
23
|
+
const FIX = path.join(__dirname, '__fixtures__', 'migrate-squad');
|
|
24
|
+
const LEGACY = path.join(FIX, 'legacy-squad');
|
|
25
|
+
const AUTH = path.join(FIX, 'authored');
|
|
26
|
+
|
|
27
|
+
let passed = 0;
|
|
28
|
+
const failures = [];
|
|
29
|
+
function ok(cond, label) {
|
|
30
|
+
if (cond) { passed++; console.log(`[OK ] ${label}`); }
|
|
31
|
+
else { failures.push(label); console.log(`[FALHA] ${label}`); }
|
|
32
|
+
}
|
|
33
|
+
function refuses(fn, code, label) {
|
|
34
|
+
let got = null;
|
|
35
|
+
try { fn(); } catch (e) { got = e.exitCode; }
|
|
36
|
+
ok(got === code, `${label} (exit ${code}${got === code ? '' : ` — obtido ${got}`})`);
|
|
37
|
+
}
|
|
38
|
+
function tmp(n) { return fs.mkdtempSync(path.join(os.tmpdir(), `mm33-${n}-`)); }
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// AC1 — F0 inventário determinístico (init --squad-dir).
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
{
|
|
44
|
+
const dir = tmp('f0');
|
|
45
|
+
const mf = path.join(dir, 'MIGRATION-hormozi.yaml');
|
|
46
|
+
const out = m.cmdInit(mf, { squad: 'hormozi', squadDir: LEGACY, now: 'T0' });
|
|
47
|
+
const EXPECTED = ['agents', 'checklists', 'config', 'data', 'loose', 'scripts', 'sops', 'tasks', 'templates', 'workflows'];
|
|
48
|
+
ok(EXPECTED.every((f) => out.inventory.families.includes(f)), 'AC1 inventário cobre TODAS as 10 famílias (workflows..config + loose)');
|
|
49
|
+
// grep de comandos embutidos no agente legado (B.5).
|
|
50
|
+
const doc = m.readManifest(mf); // re-lê → prova que a integridade sobrevive ao inventário nested
|
|
51
|
+
const cmds = doc.inventory.commands.filter((c) => c.agent.includes('hormozi-offer')).map((c) => c.command).sort();
|
|
52
|
+
ok(JSON.stringify(cmds) === JSON.stringify(['*build-offer', '*diagnose', '*value-stack']), 'AC1 grep \\*[a-z-]+ captura os 3 comandos embutidos do agente legado');
|
|
53
|
+
// squad-io.yaml / README / HEADLINE na raiz caem em loose.
|
|
54
|
+
const loose = doc.inventory.items.filter((i) => i.family === 'loose').map((i) => i.path);
|
|
55
|
+
ok(loose.includes('squad-io.yaml') && loose.includes('README.md') && loose.includes('HEADLINE.md'), 'AC1 arquivos soltos da raiz → família loose');
|
|
56
|
+
// integridade: re-escrita (triage) sobre o manifest com inventory não corrompe.
|
|
57
|
+
m.cmdTriageSet(mf, { workflow: 'wf-sample', disposition: 'migrate', purpose: 'legacy/workflows/wf-sample.yaml:1', basis: 'julgamento', now: 'T' });
|
|
58
|
+
ok(m.readManifest(mf).inventory.families.length === 10, 'AC1 inventário round-trip (integrity) intacto após escrita subsequente');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// AC2 — F1 STOP: sem aprovação do Daniel, open-line NÃO abre linha (migração real).
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
{
|
|
65
|
+
const dir = tmp('f1');
|
|
66
|
+
const mf = path.join(dir, 'MIGRATION-hormozi.yaml');
|
|
67
|
+
const pod = path.join(dir, 'pod'); fs.mkdirSync(pod, { recursive: true });
|
|
68
|
+
const spec = path.join(AUTH, 'specs', 'wf-sample.spec.json');
|
|
69
|
+
m.cmdInit(mf, { squad: 'hormozi', squadDir: LEGACY, now: 'T0' });
|
|
70
|
+
|
|
71
|
+
// (a) sem triagem → recusa (F1 não executada).
|
|
72
|
+
refuses(() => m.cmdOpenLine(mf, { workflow: 'wf-sample', spec, podDir: pod, now: 'T' }), 2, 'AC2 open-line sem triagem → RECUSA (PARA no Daniel)');
|
|
73
|
+
|
|
74
|
+
// (b) triagem migrate mas NÃO aprovada → recusa.
|
|
75
|
+
m.cmdTriageSet(mf, { workflow: 'wf-sample', disposition: 'migrate', purpose: 'wf-sample.yaml:1', basis: 'julgamento', now: 'T' });
|
|
76
|
+
refuses(() => m.cmdOpenLine(mf, { workflow: 'wf-sample', spec, podDir: pod, now: 'T' }), 2, 'AC2 triagem sem approved_by → open-line RECUSA');
|
|
77
|
+
|
|
78
|
+
// (c) aprovada pelo Daniel → open-line abre a linha.
|
|
79
|
+
const appr = m.cmdTriageApprove(mf, { workflow: 'wf-sample', approvedBy: 'daniel', now: 'T' });
|
|
80
|
+
ok(appr.approved_by === 'daniel', 'AC2 triage-approve registra aprovação humana (regra 5)');
|
|
81
|
+
const opened = m.cmdOpenLine(mf, { workflow: 'wf-sample', spec, podDir: pod, now: 'T' });
|
|
82
|
+
ok(opened.phase === 'spec', 'AC2 após aprovação registrada → open-line PROSSEGUE');
|
|
83
|
+
|
|
84
|
+
// (d) reclassificar para dispense ZERA a aprovação (mudar de disposição = decisão nova).
|
|
85
|
+
m.cmdTriageSet(mf, { workflow: 'wf-other', disposition: 'migrate', purpose: 'x:1', basis: 'dado', now: 'T' });
|
|
86
|
+
m.cmdTriageApprove(mf, { workflow: 'wf-other', approvedBy: 'daniel', now: 'T' });
|
|
87
|
+
m.cmdTriageSet(mf, { workflow: 'wf-other', disposition: 'dispense', purpose: 'x:1', basis: 'dado', now: 'T' });
|
|
88
|
+
const doc = m.readManifest(mf);
|
|
89
|
+
ok(!doc.triage.find((t) => t.workflow === 'wf-other').approved_by, 'AC2 reclassificar disposição ZERA approved_by (sem herdar aprovação antiga)');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// AC2 — REPRODUÇÃO DO ATAQUE DO QA (permanente): não pode existir caminho dormente.
|
|
93
|
+
// O finding GRAVE: `init` sem `--squad-dir` → inventory null → gate F1 adormecido →
|
|
94
|
+
// open-line sem aprovação. Fix ESTRUTURAL provado nos dois pontos:
|
|
95
|
+
{
|
|
96
|
+
const dir = tmp('attack');
|
|
97
|
+
const mf = path.join(dir, 'MIGRATION-x.yaml');
|
|
98
|
+
const pod = path.join(dir, 'pod'); fs.mkdirSync(pod, { recursive: true });
|
|
99
|
+
const spec = path.join(dir, 'wf.spec.json'); fs.writeFileSync(spec, '{"id":"wf-x"}');
|
|
100
|
+
|
|
101
|
+
// (1) init SEM --squad-dir → RECUSA (exit 2). O inventário nunca nasce null.
|
|
102
|
+
refuses(() => m.cmdInit(mf, { squad: 'x', now: 'T0' }), 2, 'AC2/QA init SEM --squad-dir → RECUSA (inventário nunca null)');
|
|
103
|
+
|
|
104
|
+
// (2) mesmo um manifest hand-forjado com inventory AUSENTE (via escritor único,
|
|
105
|
+
// integrity válido) NÃO abre o caminho dormente: open-line RECUSA sem triagem
|
|
106
|
+
// aprovada — o gate F1 é INCONDICIONAL, não keyed em `inventory`.
|
|
107
|
+
const mf2 = path.join(dir, 'MIGRATION-noinv.yaml');
|
|
108
|
+
m.writeManifest(mf2, { squad: 'x', created_at: 'T0', triage: [], lines: [] }); // sem inventory
|
|
109
|
+
ok(m.readManifest(mf2) && !m.readManifest(mf2).inventory, 'AC2/QA manifest com inventory ausente é legível (integrity válido)');
|
|
110
|
+
refuses(() => m.cmdOpenLine(mf2, { workflow: 'wf-x', spec, podDir: pod, now: 'T' }), 2, 'AC2/QA inventory ausente + sem triagem → open-line RECUSA (gate incondicional, sem caminho dormente)');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// AC4 — disposição EXPLÍCITA de scripts/checklists (nunca prosa; endereço no manifest).
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
{
|
|
117
|
+
const dir = tmp('disp');
|
|
118
|
+
const mf = path.join(dir, 'MIGRATION-hormozi.yaml');
|
|
119
|
+
m.cmdInit(mf, { squad: 'hormozi', squadDir: LEGACY, now: 'T0' });
|
|
120
|
+
// Validador Python: disposição entre veto/script-do-pod/óbito (dimensão 5). Aqui: script do pod.
|
|
121
|
+
m.cmdTriageSet(mf, { workflow: 'scripts/validate-mvn.py', disposition: 'migrate', purpose: 'portado como script executável do pod, referenciado por checkpoint (B.4 dim.5)', basis: 'julgamento', now: 'T' });
|
|
122
|
+
// Checklists nos 3 destinos.
|
|
123
|
+
m.cmdTriageSet(mf, { workflow: 'checklists/veto-screen.md', disposition: 'knowledge', purpose: 'redutível → veto.assertions count_gte (B.2 destino 1)', basis: 'dado', now: 'T' });
|
|
124
|
+
m.cmdTriageSet(mf, { workflow: 'checklists/method-guide.md', disposition: 'knowledge', purpose: 'metodológico → seções de template + knowledge (B.2 destino 2)', basis: 'dado', now: 'T' });
|
|
125
|
+
m.cmdTriageSet(mf, { workflow: 'checklists/dead-redundant.md', disposition: 'dispense', purpose: 'redundante/morto → DROP com justificativa (B.2 destino 3)', basis: 'dado', now: 'T' });
|
|
126
|
+
const doc = m.readManifest(mf);
|
|
127
|
+
const py = doc.triage.find((t) => t.workflow === 'scripts/validate-mvn.py');
|
|
128
|
+
ok(py && py.purpose.length > 10 && py.disposition === 'migrate', 'AC4 validador Python recebe disposição EXPLÍCITA (não prosa) com endereço');
|
|
129
|
+
const destinos = new Set(doc.triage.filter((t) => t.workflow.startsWith('checklists/')).map((t) => t.disposition));
|
|
130
|
+
ok(destinos.has('knowledge') && destinos.has('dispense'), 'AC4 checklists classificados nos 3 destinos (veto/template+knowledge/DROP) registrados');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// AC9 — VIRAR-COMANDO: regra de fechamento (fecha G6-comando).
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
{
|
|
137
|
+
const dir = tmp('cmd');
|
|
138
|
+
const mf = path.join(dir, 'MIGRATION-hormozi.yaml');
|
|
139
|
+
m.cmdInit(mf, { squad: 'hormozi', squadDir: LEGACY, now: 'T0' });
|
|
140
|
+
m.cmdTriageSet(mf, { workflow: 'wf-growth-decision', disposition: 'command', purpose: 'wf-growth-decision.yaml:1 (135 linhas, árvore de decisão)', basis: 'dado', now: 'T' });
|
|
141
|
+
|
|
142
|
+
// (a) sem os 3 → permanece pendente-comando (command-close recusa).
|
|
143
|
+
refuses(() => m.cmdCommandClose(mf, { workflow: 'wf-growth-decision', now: 'T' }), 2, 'AC9 command-close sem os 3 → RECUSA (permanece pendente-comando)');
|
|
144
|
+
ok(!(m.readManifest(mf).triage.find((t) => t.workflow === 'wf-growth-decision').command_status === 'closed'), 'AC9 linha NÃO fecha sem os 3 itens');
|
|
145
|
+
|
|
146
|
+
// (b) command-close aplica só a disposição 'command'.
|
|
147
|
+
m.cmdTriageSet(mf, { workflow: 'wf-mig', disposition: 'migrate', purpose: 'x:1', basis: 'dado', now: 'T' });
|
|
148
|
+
refuses(() => m.cmdCommandClose(mf, { workflow: 'wf-mig', commandPath: mf, smoke: mf, approvedBy: 'daniel', now: 'T' }), 2, 'AC9 command-close em disposição ≠ command → RECUSA');
|
|
149
|
+
|
|
150
|
+
// (c) única saída sem os 3: reclassificar como dispensar (sempre disponível).
|
|
151
|
+
const re = m.cmdTriageSet(mf, { workflow: 'wf-growth-decision', disposition: 'dispense', purpose: 'reclassificado — não virou comando', basis: 'julgamento', now: 'T' });
|
|
152
|
+
ok(re.disposition === 'dispense', 'AC9 única saída sem os 3 é reclassificar para dispensar (regra 5)');
|
|
153
|
+
|
|
154
|
+
// (d) com os 3 (comando em disco + smoke próprio não-vazio + aprovação) → fecha.
|
|
155
|
+
m.cmdTriageSet(mf, { workflow: 'wf-opportunity', disposition: 'command', purpose: 'wf-opportunity.yaml:1', basis: 'julgamento', now: 'T' });
|
|
156
|
+
const cmdPath = path.join(dir, 'the-command.md'); fs.writeFileSync(cmdPath, '# comando destino\n');
|
|
157
|
+
const smokePath = path.join(dir, 'smoke-out.txt'); fs.writeFileSync(smokePath, 'ativação + 1 execução real: OK\n');
|
|
158
|
+
const closed = m.cmdCommandClose(mf, { workflow: 'wf-opportunity', commandPath: cmdPath, smoke: smokePath, approvedBy: 'daniel', now: 'T' });
|
|
159
|
+
ok(closed.command_status === 'closed', 'AC9 com os 3 (path em disco + smoke próprio + aprovação) → linha FECHA');
|
|
160
|
+
|
|
161
|
+
// (e) smoke vazio (sem output conferível) → recusa (regra 1 do ledger: teste real).
|
|
162
|
+
m.cmdTriageSet(mf, { workflow: 'wf-empty', disposition: 'command', purpose: 'x:1', basis: 'dado', now: 'T' });
|
|
163
|
+
const emptySmoke = path.join(dir, 'empty.txt'); fs.writeFileSync(emptySmoke, '');
|
|
164
|
+
refuses(() => m.cmdCommandClose(mf, { workflow: 'wf-empty', commandPath: cmdPath, smoke: emptySmoke, approvedBy: 'daniel', now: 'T' }), 2, 'AC9 smoke vazio (sem output conferível) → RECUSA');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
console.log(`\n${passed} verificações OK, ${failures.length} falha(s).`);
|
|
169
|
+
if (failures.length) { for (const f of failures) console.error(` - ${f}`); process.exit(1); }
|
|
170
|
+
process.exit(0);
|