@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,607 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* validate-story-acs.test.cjs — suíte real do validador de ACs (Story
|
|
6
|
+
* SF13.1, `ADR-031`). Roda os 47 ACs da story, incluindo os 6 fixtures do
|
|
7
|
+
* Bloco E (comportamentais, não mockados) e o controle negativo do AC-32b.
|
|
8
|
+
*
|
|
9
|
+
* DESVIO DOCUMENTADO (Dev Agent Record da story tem os detalhes completos):
|
|
10
|
+
* os fixtures literais de `AC-14` e `AC-25` usam `test -f package.json`
|
|
11
|
+
* SEM `[Guarda]` como prova/placeholder — mas essa é EXATAMENTE a forma que
|
|
12
|
+
* `AC-32b` rotula, na própria story, como *"óbvio nasce-verde"* (linha 446),
|
|
13
|
+
* e que `AC-5`/Contexto(b) exigem que o validador REPROVE quando referenciada
|
|
14
|
+
* como `[Guarda] (prova: AC-M)` sem pareamento válido. Um validador que
|
|
15
|
+
* deixasse "test -f package.json" sem guarda passar como `ok` (a leitura
|
|
16
|
+
* literal de AC-14/AC-25) reabriria a MESMA classe de defeito que a story
|
|
17
|
+
* inteira existe para fechar — e contradiria AC-5, AC-13, AC-19, AC-22 e o
|
|
18
|
+
* próprio AC-32b. Implementei a regra normativa (Contexto (b), `ADR-031`
|
|
19
|
+
* Decisão 1) e, nestes 2 casos, testo o comportamento CORRETO em vez do
|
|
20
|
+
* literal — reportado como achado, não corrigido silenciosamente na story
|
|
21
|
+
* (fora da minha autoridade de edição nesta rodada).
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const fs = require('node:fs');
|
|
25
|
+
const os = require('node:os');
|
|
26
|
+
const path = require('node:path');
|
|
27
|
+
|
|
28
|
+
const REPO_ROOT = path.resolve(__dirname, '..', '..');
|
|
29
|
+
const MODULE_PATH = path.join(REPO_ROOT, 'scripts', 'validate-story-acs.cjs');
|
|
30
|
+
const FIXTURES_DIR = path.join(REPO_ROOT, 'scripts', '__fixtures__', 'validate-story-acs-corpus');
|
|
31
|
+
|
|
32
|
+
let failures = 0;
|
|
33
|
+
function assert(ok, msg, extra) {
|
|
34
|
+
if (ok) {
|
|
35
|
+
console.log(`[OK ] ${msg}`);
|
|
36
|
+
} else {
|
|
37
|
+
console.error(`[FALHA] ${msg}${extra !== undefined ? ' :: ' + JSON.stringify(extra) : ''}`);
|
|
38
|
+
failures++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function freshModule() {
|
|
43
|
+
delete require.cache[require.resolve(MODULE_PATH)];
|
|
44
|
+
return require(MODULE_PATH);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const f = (lines) => lines.join('\n');
|
|
48
|
+
|
|
49
|
+
function run() {
|
|
50
|
+
process.chdir(REPO_ROOT);
|
|
51
|
+
const m = freshModule();
|
|
52
|
+
|
|
53
|
+
// ---------------------------------------------------------------------
|
|
54
|
+
// Bloco A — Convenção e produtor
|
|
55
|
+
// ---------------------------------------------------------------------
|
|
56
|
+
{
|
|
57
|
+
const r = m.wouldBeRefused === undefined ? null : true;
|
|
58
|
+
assert(fs.existsSync(path.join(REPO_ROOT, 'docs', 'mecanismos', 'validador-de-acs-do-ciclo.md')), 'AC-1: doc de mecanismo existe');
|
|
59
|
+
}
|
|
60
|
+
{
|
|
61
|
+
const c = fs.readFileSync(path.join(REPO_ROOT, 'template', '.claude', 'agents', 'pc-planner.md'), 'utf8');
|
|
62
|
+
assert(/oraculo|oráculo/i.test(c), 'AC-2: pc-planner.md instrui emissão da fence oraculo');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ---------------------------------------------------------------------
|
|
66
|
+
// Bloco B — Parsing
|
|
67
|
+
// ---------------------------------------------------------------------
|
|
68
|
+
{
|
|
69
|
+
const c = f(['exemplo fora da secao:', '```oraculo', 'test -f nada', '```', '', '## Acceptance Criteria', '', '**AC-X.** d', '```oraculo', 'test -f package.json', '```']);
|
|
70
|
+
const r = m.parseAcs(c);
|
|
71
|
+
assert(r.length === 1 && r[0].id === 'AC-X', 'AC-3: parseAcs restrito à seção, sem fence aninhado', r);
|
|
72
|
+
}
|
|
73
|
+
{
|
|
74
|
+
// Achado do QA (gate `sf13.1-validador-de-acs`, finding 1a): o marcador
|
|
75
|
+
// com anotação entre colchetes (`**AC-N [novo, ...].**`) é o estilo
|
|
76
|
+
// PREDOMINANTE já convencionado no projeto — 32 dos 43 cabeçalhos reais
|
|
77
|
+
// desta própria story usam essa forma ou prosa adicional dentro do
|
|
78
|
+
// negrito. `parseAcs` tem de casar as 3 formas.
|
|
79
|
+
const c = f(['## Acceptance Criteria', '', '**AC-1 [novo, B4].** descricao simples', '```oraculo', 'test -f package.json', '```', '', '**AC-2. Corpus 1 — titulo com prosa dentro do negrito.** descricao', '```oraculo', 'test -f package.json', '```']);
|
|
80
|
+
const r = m.parseAcs(c);
|
|
81
|
+
assert(r.length === 2 && r[0].id === 'AC-1' && r[1].id === 'AC-2', 'AC-3b [novo, achado do QA]: parseAcs casa anotação entre colchetes E prosa dentro do negrito', r);
|
|
82
|
+
}
|
|
83
|
+
{
|
|
84
|
+
// Achado do QA (finding 1b): fence-aware — string de fixture embutida
|
|
85
|
+
// (contendo `**AC-A.**`/```oraculo``` como DADO literal, não marcador
|
|
86
|
+
// real) dentro do PRÓPRIO oráculo de um AC não pode virar um AC novo
|
|
87
|
+
// nem truncar o comando real. Reproduz a forma exata do AC-14/AC-5 desta
|
|
88
|
+
// story (fixture com aspas simples aninhadas via `'\''`).
|
|
89
|
+
const c = f(['## Acceptance Criteria', '', "**AC-Y.** constroi fixture em memoria", '```oraculo', `node -e 'const f=(l)=>l.join("\\\\n");const c=f(["## Acceptance Criteria","","**AC-A.** irmao","` + '```' + `oraculo","test -f package.json","` + '```' + `"]);console.log(1)'`, '```']);
|
|
90
|
+
const r = m.parseAcs(c);
|
|
91
|
+
const hasFakeAc = r.find((x) => x.id === 'AC-A');
|
|
92
|
+
assert(r.length === 1 && r[0].id === 'AC-Y' && !hasFakeAc && /console\.log\(1\)/.test(r[0].oracleCmd || ''), 'AC-3c [novo, achado do QA]: fence-aware — marcador embutido em oráculo não vira AC novo, comando não trunca', r);
|
|
93
|
+
}
|
|
94
|
+
{
|
|
95
|
+
// Achado do QA: `'\''` (idioma bash — fecha aspa, aspa literal
|
|
96
|
+
// escapada, reabre aspa) precisa tokenizar como UM caractere de aspa
|
|
97
|
+
// literal inserido no meio da string, não como um backslash espúrio —
|
|
98
|
+
// reproduz o defeito real medido em AC-10c contra a story.
|
|
99
|
+
// Monta literalmente: node -e 'console.log('\''hi'\'')'
|
|
100
|
+
const Q = "'";
|
|
101
|
+
const IDIOM = Q + '\\' + Q + Q; // os 4 chars '\''
|
|
102
|
+
const idiomCmd = 'node -e ' + Q + "console.log(" + IDIOM + 'hi' + IDIOM + ')' + Q;
|
|
103
|
+
const rIdiom = m.runOracle(idiomCmd, { cwd: process.cwd(), timeoutMs: 5000 });
|
|
104
|
+
assert(rIdiom.refused !== true && rIdiom.exitCode === 0 && rIdiom.stdout.trim() === 'hi', "AC-10g [novo, achado do QA]: idioma bash '\\'' tokeniza como aspa literal, não como backslash espúrio", rIdiom);
|
|
105
|
+
|
|
106
|
+
const rSanity = m.runOracle("node -e 'const x=1;console.log(x)'", { cwd: process.cwd(), timeoutMs: 5000 });
|
|
107
|
+
assert(rSanity.refused !== true && rSanity.exitCode === 0 && rSanity.stdout.trim() === '1', 'AC-10h [novo, achado do QA]: sanidade de aspa simples simples continua íntegra após o fix de backslash', rSanity);
|
|
108
|
+
}
|
|
109
|
+
{
|
|
110
|
+
// PROVA NA ROTA REAL (gate `sf13.1-validador-de-acs`, ação sugerida do
|
|
111
|
+
// finding 1): o CLI contra a PRÓPRIA story tem de reconhecer os 47 ACs
|
|
112
|
+
// reais, com ids reais — não 22 fantasmas. Este é o teste que teria
|
|
113
|
+
// pego o FAIL antes do QA.
|
|
114
|
+
const story = fs.readFileSync(path.join(REPO_ROOT, 'docs', 'stories', 'sf13.1.story.md'), 'utf8');
|
|
115
|
+
const acsReal = m.parseAcs(story);
|
|
116
|
+
const idsCorrompidos = acsReal.filter((a) => a.id === 'AC-X' || a.id === 'AC-A' || a.id === 'AC-B' || a.id === 'AC-Z');
|
|
117
|
+
assert(acsReal.length === 47 && idsCorrompidos.length === 0, `ROTA REAL [novo, achado do QA]: parseAcs(sf13.1.story.md).length === 47 (obtido: ${acsReal.length}), zero ids fantasma`, acsReal.map((a) => a.id));
|
|
118
|
+
const r = m.validateStory(story, { cwd: process.cwd() });
|
|
119
|
+
assert(r.total === 47, `ROTA REAL: validateStory(sf13.1.story.md).total === 47 (obtido: ${r.total})`, r);
|
|
120
|
+
}
|
|
121
|
+
{
|
|
122
|
+
const c = f(['## Acceptance Criteria', '', '**AC-X.** d', '[Guarda] (prova: AC-Z)', '```oraculo', 'test -f package.json', '```']);
|
|
123
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
124
|
+
const hit = r.reprovados.find((x) => x.id === 'AC-X' && /prova nomeada n(a|ã)o existe/i.test(x.motivo));
|
|
125
|
+
assert(!!hit, 'AC-4: prova nomeada inexistente reprova', r);
|
|
126
|
+
}
|
|
127
|
+
{
|
|
128
|
+
const c = f(['## Acceptance Criteria', '', '**AC-X.** d', '[Guarda] (prova: AC-A) texto livre depois nao quebra o parser', '```oraculo', 'test -f package.json', '```', '', '**AC-A.** irmao', '```oraculo', 'test -f package.json', '```']);
|
|
129
|
+
const r = m.parseAcs(c);
|
|
130
|
+
const ac = r.find((x) => x.id === 'AC-X');
|
|
131
|
+
assert(!!(ac && ac.guarda && ac.guarda.forma === 'prova' && ac.guarda.provaId === 'AC-A'), 'AC-4b: parser aceita prosa após o grupo reconhecido', ac);
|
|
132
|
+
}
|
|
133
|
+
{
|
|
134
|
+
const c = f(['## Acceptance Criteria', '', '**AC-A.** guarda', '```oraculo', 'test -f package.json', '```', '', '**AC-B.** alvo', '[Guarda] (prova: AC-A)', '```oraculo', 'test -f package.json', '```']);
|
|
135
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
136
|
+
const hit = r.reprovados.find((x) => x.id === 'AC-B' && /cadeia guarda/i.test(x.motivo));
|
|
137
|
+
assert(!!hit, 'AC-5: cadeia guarda→guarda proibida', r);
|
|
138
|
+
}
|
|
139
|
+
{
|
|
140
|
+
const c = f(['## Acceptance Criteria', '', '**AC-X.** d', '[Guarda] (banana)', '```oraculo', 'test -f package.json', '```']);
|
|
141
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
142
|
+
const hit = r.reprovados.find((x) => x.id === 'AC-X' && /forma.*n(a|ã)o reconhecida/i.test(x.motivo));
|
|
143
|
+
assert(!!hit, 'AC-5b: forma de guarda não reconhecida ⇒ REPROVA (destino pinado)', r);
|
|
144
|
+
}
|
|
145
|
+
{
|
|
146
|
+
const c = f(['## Acceptance Criteria', '', '**AC-X.** d', '[Guarda] (sem irmao - ausencia declarada)', '```oraculo', '# espera: stdout-nao-vazio', 'test -f package.json', '```']);
|
|
147
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
148
|
+
const hit = r.reprovados.find((x) => x.id === 'AC-X' && /forma 2|ausencia|ausência/i.test(x.motivo));
|
|
149
|
+
assert(!!hit, 'AC-6: forma "sem irmão" exige asserção de ausência', r);
|
|
150
|
+
}
|
|
151
|
+
{
|
|
152
|
+
const c = f(['## Acceptance Criteria', '', '**AC-X.** d', '[Guarda] (citacao de fato pre-existente, nao prova de trabalho)', '```oraculo', 'test -f package.json', '```']);
|
|
153
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
154
|
+
const inCit = r.citacoes && r.citacoes.find((x) => x.id === 'AC-X');
|
|
155
|
+
const notInOk = !r.ok.find((x) => x.id === 'AC-X');
|
|
156
|
+
assert(!!(inCit && notInOk), 'AC-6b: citação vai para `citacoes`, nunca `ok`', r);
|
|
157
|
+
}
|
|
158
|
+
{
|
|
159
|
+
const c = '## Acceptance Criteria\n\nSem nenhum AC com bloco.';
|
|
160
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
161
|
+
assert(r.naoDeterminados && r.naoDeterminados.length === 1, 'AC-7: arquivo sem nenhum oráculo — relatório fala', r);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ---------------------------------------------------------------------
|
|
165
|
+
// Bloco C — Execução sem shell
|
|
166
|
+
// ---------------------------------------------------------------------
|
|
167
|
+
{
|
|
168
|
+
const r = m.runOracle('test -f package.json', { cwd: process.cwd(), timeoutMs: 5000 });
|
|
169
|
+
assert(r.exitCode === 0 && typeof r.stdout === 'string' && typeof r.durationMs === 'number', 'AC-8: runOracle via execFile-família', r);
|
|
170
|
+
}
|
|
171
|
+
{
|
|
172
|
+
const r = m.runOracle('awk BEGIN{print 1}', { cwd: process.cwd(), timeoutMs: 5000 });
|
|
173
|
+
assert(r.refused === true && /n(a|ã)o consegui determinar/i.test(r.refusalReason || ''), 'AC-9: cabeçalho fora da allow-list recusa falada', r);
|
|
174
|
+
}
|
|
175
|
+
{
|
|
176
|
+
const c = f(['## Acceptance Criteria', '', '**AC-X.** d', '```oraculo', 'awk BEGIN{print 1}', '```']);
|
|
177
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
178
|
+
const hit = r.naoDeterminados.find((x) => x.id === 'AC-X');
|
|
179
|
+
const clean = !r.ok.find((x) => x.id === 'AC-X') && !r.reprovados.find((x) => x.id === 'AC-X') && !r.alertas.find((x) => x.id === 'AC-X');
|
|
180
|
+
assert(!!(hit && clean), 'AC-9b: recusa/timeout ⇒ naoDeterminados no relatório agregado', r);
|
|
181
|
+
}
|
|
182
|
+
{
|
|
183
|
+
const r = m.runOracle('grep -c a package.json | wc -l', { cwd: process.cwd(), timeoutMs: 5000 });
|
|
184
|
+
assert(r.refused === true, 'AC-10: metacaractere fora de aspas ⇒ recusa', r);
|
|
185
|
+
}
|
|
186
|
+
{
|
|
187
|
+
const r = m.runOracle('grep -c "a\\|b" package.json', { cwd: process.cwd(), timeoutMs: 5000 });
|
|
188
|
+
const ran = r.refused !== true && r.exitCode === 0 && typeof r.stdout === 'string' && r.stdout.trim().length > 0;
|
|
189
|
+
assert(ran, 'AC-10b: metacaractere dentro de aspas duplas roda de fato', r);
|
|
190
|
+
}
|
|
191
|
+
{
|
|
192
|
+
const r = m.runOracle("node -e 'console.log(1)'", { cwd: process.cwd(), timeoutMs: 5000 });
|
|
193
|
+
const ran = r.refused !== true && r.exitCode === 0 && r.stdout.trim() === '1';
|
|
194
|
+
assert(ran, 'AC-10c: aspa simples (forma dominante) roda de fato', r);
|
|
195
|
+
}
|
|
196
|
+
{
|
|
197
|
+
// AC-10d ENDURECIDO (gate `sf13.1-validador-de-acs`, findings 1/2): a
|
|
198
|
+
// asserção original (`refusals.length === 0`) é satisfazível por um
|
|
199
|
+
// array CORROMPIDO (parseAcs cortando cabeçalhos errado) tão facilmente
|
|
200
|
+
// quanto por um array correto — 0 recusas sobre 22 fantasmas também é
|
|
201
|
+
// 0. Isso é vacuidade na camada do PARSER, a mesma classe que a regra
|
|
202
|
+
// de convergência existe para impedir, só que um nível abaixo de onde
|
|
203
|
+
// ela mirava. Fecho: cruzar `parseAcs().length` com uma contagem
|
|
204
|
+
// INDEPENDENTE de cabeçalhos reais (`**AC-<id>` em início de linha,
|
|
205
|
+
// fora de fence — mesma definição normativa, mas sem reusar
|
|
206
|
+
// `parseAcs`/`AC_HEADER_RE` internamente: contada aqui por regex
|
|
207
|
+
// própria e comparada ao número publicado pela própria story, 47).
|
|
208
|
+
const story = fs.readFileSync(path.join(REPO_ROOT, 'docs', 'stories', 'sf13.1.story.md'), 'utf8');
|
|
209
|
+
const acs = m.parseAcs(story);
|
|
210
|
+
const refusals = acs.filter((a) => a.oracleCmd && m.wouldBeRefused(a.oracleCmd).refused);
|
|
211
|
+
const section = m.extractAcSection(story);
|
|
212
|
+
const fencedRanges = [];
|
|
213
|
+
{
|
|
214
|
+
const fre = /^```[^\n]*\n[\s\S]*?^```[ \t]*$/gm;
|
|
215
|
+
let fm;
|
|
216
|
+
while ((fm = fre.exec(section))) fencedRanges.push([fm.index, fm.index + fm[0].length]);
|
|
217
|
+
}
|
|
218
|
+
const headerRe = /^\*\*(AC-[A-Za-z0-9]+)\b/gm;
|
|
219
|
+
let hm;
|
|
220
|
+
let independentCount = 0;
|
|
221
|
+
while ((hm = headerRe.exec(section))) {
|
|
222
|
+
const insideFence = fencedRanges.some(([s2, e2]) => hm.index >= s2 && hm.index < e2);
|
|
223
|
+
if (!insideFence) independentCount += 1;
|
|
224
|
+
}
|
|
225
|
+
const noVacuidade = acs.length === independentCount && acs.length === 47;
|
|
226
|
+
assert(refusals.length === 0 && noVacuidade, `AC-10d: anti-vacuidade PURA — parseAcs().length (${acs.length}) === contagem independente (${independentCount}) === 47 publicado na story, E zero recusas`, { refusals, parsedCount: acs.length, independentCount });
|
|
227
|
+
}
|
|
228
|
+
{
|
|
229
|
+
const a = m.wouldBeRefused('awk BEGIN{print 1}');
|
|
230
|
+
const b = m.wouldBeRefused('grep -c a package.json | wc -l');
|
|
231
|
+
assert(a.refused === true && b.refused === true, 'AC-10e: wouldBeRefused — controle negativo (as 2 causas)', [a, b]);
|
|
232
|
+
}
|
|
233
|
+
{
|
|
234
|
+
const cmd1 = 'awk BEGIN{print 1}';
|
|
235
|
+
const cmd2 = 'test -f package.json';
|
|
236
|
+
const wA = m.wouldBeRefused(cmd1).refused;
|
|
237
|
+
const wB = m.wouldBeRefused(cmd2).refused;
|
|
238
|
+
const rA = m.runOracle(cmd1, { cwd: process.cwd(), timeoutMs: 5000 }).refused;
|
|
239
|
+
const rB = m.runOracle(cmd2, { cwd: process.cwd(), timeoutMs: 5000 }).refused;
|
|
240
|
+
assert(wA === true && rA === true && wB !== true && rB !== true, 'AC-10f: runOracle delega a wouldBeRefused (fonte única)', [wA, rA, wB, rB]);
|
|
241
|
+
}
|
|
242
|
+
{
|
|
243
|
+
const r = m.runOracle('git push origin main', { cwd: process.cwd(), timeoutMs: 5000 });
|
|
244
|
+
assert(r.refused === true, 'AC-11: sub-allow-list de git recusa push/commit/checkout/reset', r);
|
|
245
|
+
}
|
|
246
|
+
{
|
|
247
|
+
const r = m.runOracle('node -e "setInterval(function(){},1000)"', { cwd: process.cwd(), timeoutMs: 200 });
|
|
248
|
+
assert(r.timedOut === true, 'AC-12: timeout mata o processo filho', r);
|
|
249
|
+
}
|
|
250
|
+
{
|
|
251
|
+
const prevDepth = process.env.VSA_DEPTH;
|
|
252
|
+
process.env.VSA_DEPTH = '1';
|
|
253
|
+
const m2 = freshModule();
|
|
254
|
+
const c = f(['## Acceptance Criteria', '', '**AC-X.** d', '```oraculo', 'test -f package.json', '```']);
|
|
255
|
+
const r = m2.validateStory(c, { cwd: process.cwd() });
|
|
256
|
+
const hit = r.naoDeterminados.find((x) => x.id === 'AC-X' && x.causa === 'reentrancia');
|
|
257
|
+
assert(!!hit, 'AC-12b: guarda de reentrância — metade CONSUMIDORA', r);
|
|
258
|
+
if (prevDepth === undefined) delete process.env.VSA_DEPTH; else process.env.VSA_DEPTH = prevDepth;
|
|
259
|
+
freshModule();
|
|
260
|
+
}
|
|
261
|
+
{
|
|
262
|
+
const r = m.runOracle('node -e "console.log(process.env.VSA_DEPTH)"', { cwd: process.cwd(), timeoutMs: 5000 });
|
|
263
|
+
assert(r.stdout.trim() === '1', 'AC-12c: guarda de reentrância — metade PRODUTORA (env propagado)', r);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ---------------------------------------------------------------------
|
|
267
|
+
// Bloco D — Classificação
|
|
268
|
+
// ---------------------------------------------------------------------
|
|
269
|
+
{
|
|
270
|
+
const c = f(['## Acceptance Criteria', '', '**AC-X.** d', '```oraculo', '# espera: stdout == 0', 'grep -c zzz-termo-inexistente-xyz package.json', '```']);
|
|
271
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
272
|
+
const hit = r.reprovados.find((x) => x.id === 'AC-X' && /nasce verde/i.test(x.motivo));
|
|
273
|
+
assert(!!hit, 'AC-13: nasce verde é a asserção declarada, não o exit code', r);
|
|
274
|
+
}
|
|
275
|
+
{
|
|
276
|
+
// DESVIO DOCUMENTADO (ver cabeçalho do arquivo): o AC-14 literal da story
|
|
277
|
+
// usa AC-A = `test -f package.json` SEM guarda como "prova" — que é
|
|
278
|
+
// exatamente o padrão que AC-5/AC-32b definem como nasce-verde óbvio.
|
|
279
|
+
// Testo o comportamento CORRETO (cadeia bloqueada) em vez do literal.
|
|
280
|
+
const c = f(['## Acceptance Criteria', '', '**AC-A.** irmao', '```oraculo', 'test -f package.json', '```', '', '**AC-X.** d', '[Guarda] (prova: AC-A)', '```oraculo', '# espera: stdout == 0', 'grep -c zzz-termo-inexistente-xyz package.json', '```']);
|
|
281
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
282
|
+
const acA = r.reprovados.find((x) => x.id === 'AC-A' && /nasce verde/i.test(x.motivo));
|
|
283
|
+
const acX = r.reprovados.find((x) => x.id === 'AC-X' && /cadeia guarda/i.test(x.motivo));
|
|
284
|
+
assert(!!(acA && acX), 'AC-14 [DESVIO — ver cabeçalho]: prova apontando para alvo também nasce-verde é bloqueada, consistente com AC-5/AC-32b', r);
|
|
285
|
+
}
|
|
286
|
+
{
|
|
287
|
+
const s1 = 'node:internal/modules/cjs/loader:1573\n throw err;\nError: Cannot find module x\n at Module._resolveFilename (node:internal/modules/cjs/loader:1569:15)\n at a (node:internal/modules/cjs/loader:1123:27)\n at b (node:internal/modules/cjs/loader:1147:10)\n at c (node:internal/modules/cjs/loader:1174:12)\n at d (node:internal/modules/cjs/loader:1346:5)\n at e (node:internal/modules/cjs/loader:261:19)\n at f (node:internal/main/run_main_module:33:47) {\n code: "MODULE_NOT_FOUND"\n}';
|
|
288
|
+
const r1 = m.isCrash({ exitCode: 1, stderr: s1 });
|
|
289
|
+
const s2 = "TypeError: Cannot read properties of undefined (reading X)\n at Object.buildWorkflowYaml (scripts/forge-generate.cjs:398:9)";
|
|
290
|
+
const r2 = m.isCrash({ exitCode: 1, stderr: s2 });
|
|
291
|
+
assert(r1.crash === false && r2.crash === true, 'AC-15: precedência normativa de isCrash', [r1, r2]);
|
|
292
|
+
}
|
|
293
|
+
{
|
|
294
|
+
const c = f(['## Acceptance Criteria', '', '**AC-X.** d', '```oraculo', 'grep -c zzz-termo-inexistente-xyz package.json', '```']);
|
|
295
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
296
|
+
const hit = r.alertas.find((x) => x.id === 'AC-X' && /no-op/i.test(x.motivo));
|
|
297
|
+
assert(!!hit, 'AC-16: padrão de contagem ingênua ⇒ ALERTA no-op', r);
|
|
298
|
+
}
|
|
299
|
+
{
|
|
300
|
+
const a = m.evaluateAssertion({ exitCode: 1, stdout: '', stderr: '' }, { type: 'exit!=0' });
|
|
301
|
+
const b = m.evaluateAssertion({ exitCode: 0, stdout: '', stderr: '' }, { type: 'exit!=0' });
|
|
302
|
+
const c = m.evaluateAssertion({ exitCode: 0, stdout: 'x', stderr: '' }, { type: 'stdout-nao-vazio' });
|
|
303
|
+
const d = m.evaluateAssertion({ exitCode: 0, stdout: '', stderr: '' }, { type: 'stdout-nao-vazio' });
|
|
304
|
+
assert(a === true && b === false && c === true && d === false, 'AC-16b: as 5 formas de # espera — controle positivo e negativo', [a, b, c, d]);
|
|
305
|
+
}
|
|
306
|
+
{
|
|
307
|
+
const c = f(['## Status', '', 'InReview', '', '## Acceptance Criteria', '', '**AC-X.** d', '```oraculo', 'test -f package.json', '```']);
|
|
308
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
309
|
+
const hit = r.naoDeterminados.find((x) => x.id === 'AC-X' && x.causa === 'nasce-verde-pos-trabalho');
|
|
310
|
+
assert(!!hit, 'AC-16c: nasce verde é classe datada — InReview suspende', r);
|
|
311
|
+
}
|
|
312
|
+
{
|
|
313
|
+
const c = f(['## Acceptance Criteria', '', '**AC-X.** d', '```oraculo', '# espera: stdout-vazia', 'test -f package.json', '```']);
|
|
314
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
315
|
+
const hit = r.naoDeterminados.find((x) => x.id === 'AC-X' && x.causa === 'assercao-desconhecida');
|
|
316
|
+
const notOk = !r.ok.find((x) => x.id === 'AC-X');
|
|
317
|
+
assert(!!(hit && notOk), 'AC-16e: typo em # espera NUNCA cai no default exit0', r);
|
|
318
|
+
}
|
|
319
|
+
{
|
|
320
|
+
const c = f(['## Status', '', 'InReview', '', '## Acceptance Criteria', '', '**AC-X.** d', '```oraculo', 'node -e "null.x"', '```']);
|
|
321
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
322
|
+
const hit = r.reprovados.find((x) => x.id === 'AC-X' && /comando quebrado/i.test(x.motivo));
|
|
323
|
+
assert(!!hit, 'AC-16d: gate por CLASSE — crash continua REPROVA em InReview', r);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ---------------------------------------------------------------------
|
|
327
|
+
// Bloco E — Meta-prova: 5 corpus reais, comportamentais
|
|
328
|
+
// ---------------------------------------------------------------------
|
|
329
|
+
{
|
|
330
|
+
const c = fs.readFileSync(path.join(FIXTURES_DIR, 'corpus-1-noop-state-json.fixture.md'), 'utf8');
|
|
331
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
332
|
+
const hit = r.alertas.find((x) => /no-op/i.test(x.motivo));
|
|
333
|
+
assert(!!hit, 'AC-17: Corpus 1 (sf12.4b, no-op) — rodado de verdade', r);
|
|
334
|
+
}
|
|
335
|
+
{
|
|
336
|
+
const c = fs.readFileSync(path.join(FIXTURES_DIR, 'corpus-2-crash-buildworkflowyaml.fixture.md'), 'utf8');
|
|
337
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
338
|
+
const hit = r.reprovados.find((x) => /comando quebrado/i.test(x.motivo) && /TypeError/i.test(x.motivo));
|
|
339
|
+
assert(!!hit, 'AC-18: Corpus 2 (sf12.5a, crash) — TypeError real citado', r);
|
|
340
|
+
}
|
|
341
|
+
{
|
|
342
|
+
const c = fs.readFileSync(path.join(FIXTURES_DIR, 'corpus-3-nasce-verde-skip-modes.fixture.md'), 'utf8');
|
|
343
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
344
|
+
const hit = r.reprovados.find((x) => x.id === 'AC-3a' && /nasce verde/i.test(x.motivo));
|
|
345
|
+
assert(!!hit, 'AC-19: Corpus 3a (sem guarda) — REPROVA nasce verde', r);
|
|
346
|
+
}
|
|
347
|
+
{
|
|
348
|
+
const c = fs.readFileSync(path.join(FIXTURES_DIR, 'corpus-3-nasce-verde-skip-modes.fixture.md'), 'utf8');
|
|
349
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
350
|
+
const bad = r.reprovados.find((x) => x.id === 'AC-3b');
|
|
351
|
+
assert(!bad, 'AC-20: Corpus 3b (com guarda) — NÃO reprova', r);
|
|
352
|
+
}
|
|
353
|
+
{
|
|
354
|
+
const c = fs.readFileSync(path.join(FIXTURES_DIR, 'corpus-4-guarda-sem-irmao.fixture.md'), 'utf8');
|
|
355
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
356
|
+
const bad = r.reprovados.find((x) => x.id === 'AC-4');
|
|
357
|
+
assert(!bad, 'AC-21: Corpus 4 (guarda sem irmão possível) — NÃO reprova', r);
|
|
358
|
+
}
|
|
359
|
+
{
|
|
360
|
+
const c = fs.readFileSync(path.join(FIXTURES_DIR, 'corpus-5a-diff-stat-sem-guarda.fixture.md'), 'utf8');
|
|
361
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
362
|
+
const hit = r.reprovados.find((x) => x.id === 'AC-5a' && /nasce verde/i.test(x.motivo));
|
|
363
|
+
assert(!!hit, 'AC-22: Corpus 5a (git diff --stat sob exit-code puro) — REPROVA', r);
|
|
364
|
+
}
|
|
365
|
+
{
|
|
366
|
+
const c = fs.readFileSync(path.join(REPO_ROOT, 'docs', 'mecanismos', 'validador-de-acs-do-ciclo.md'), 'utf8');
|
|
367
|
+
assert(/Corpus 5b/.test(c), 'AC-23: fronteira Corpus 5b declarada no doc de mecanismo', null);
|
|
368
|
+
}
|
|
369
|
+
{
|
|
370
|
+
let n = 0;
|
|
371
|
+
try {
|
|
372
|
+
n = fs.readdirSync(FIXTURES_DIR).filter((x) => x.endsWith('.fixture.md')).length;
|
|
373
|
+
} catch (e) { n = 0; }
|
|
374
|
+
assert(n === 6, 'AC-24: os 6 arquivos de fixture existem', n);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ---------------------------------------------------------------------
|
|
378
|
+
// Bloco F — Relatório, CLI, integração com o PO
|
|
379
|
+
// ---------------------------------------------------------------------
|
|
380
|
+
{
|
|
381
|
+
// DESVIO DOCUMENTADO (ver cabeçalho do arquivo): AC-25 usa AC-A = `test
|
|
382
|
+
// -f package.json` SEM guarda esperando `ok` — mesmo padrão do AC-14,
|
|
383
|
+
// contradiz AC-5/AC-32b. Testo a categoria ALERTA (que não depende do
|
|
384
|
+
// caso conflitante) e confirmo que a AC nasce-verde é corretamente
|
|
385
|
+
// reprovada (não silenciada) — total conta as 2 entradas roteadas.
|
|
386
|
+
const c = f(['## Acceptance Criteria', '', '**AC-A.** ok', '```oraculo', 'test -f package.json', '```', '', '**AC-B.** alerta', '```oraculo', 'grep -c zzz-termo-inexistente-xyz package.json', '```']);
|
|
387
|
+
const r = m.validateStory(c, { cwd: process.cwd() });
|
|
388
|
+
const alOk = r.alertas.find((x) => x.id === 'AC-B');
|
|
389
|
+
const acAReprovado = r.reprovados.find((x) => x.id === 'AC-A' && /nasce verde/i.test(x.motivo));
|
|
390
|
+
assert(!!(alOk && acAReprovado && r.total === 2), 'AC-25 [DESVIO — ver cabeçalho]: relatório agregado com total/ok/reprovados/alertas corretos', r);
|
|
391
|
+
}
|
|
392
|
+
{
|
|
393
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'vsa-'));
|
|
394
|
+
// `test -f package.json` sem guarda seria nasce-verde (mesma classe do
|
|
395
|
+
// desvio AC-14/AC-25 — ver cabeçalho do arquivo); aqui a asserção
|
|
396
|
+
// precisa ser genuinamente FALSA hoje para cair em `ok` sem ambiguidade.
|
|
397
|
+
const bodyOk = f(['## Acceptance Criteria', '', '**AC-A.** ok', '```oraculo', 'test -f arquivo-que-nao-existe-vsa-fixture.txt', '```']);
|
|
398
|
+
const bodyAlerta = f(['## Acceptance Criteria', '', '**AC-B.** alerta', '```oraculo', 'grep -c zzz-termo-inexistente-xyz package.json', '```']);
|
|
399
|
+
fs.writeFileSync(path.join(dir, 'a.story.md'), bodyOk);
|
|
400
|
+
fs.writeFileSync(path.join(dir, 'b.story.md'), bodyAlerta);
|
|
401
|
+
const r = m.validateStoryBatch(dir, { cwd: process.cwd() });
|
|
402
|
+
// Positivo: 2 arquivos DIFERENTES agregados de fato (não só a contagem
|
|
403
|
+
// de arquivos) — 1 ok de a.story.md + 1 alerta de b.story.md somados.
|
|
404
|
+
const agregouOk = r.ok.find((x) => x.id === 'AC-A');
|
|
405
|
+
const agregouAlerta = r.alertas.find((x) => x.id === 'AC-B');
|
|
406
|
+
assert(r.files === 2 && r.total === 2 && !!agregouOk && !!agregouAlerta, 'AC-26: validateStoryBatch agrega ok+alertas de 2 arquivos DIFERENTES (não só files===2)', r);
|
|
407
|
+
}
|
|
408
|
+
{
|
|
409
|
+
// AC-26 CONTROLE NEGATIVO (finding 4 do gate — regra de convergência:
|
|
410
|
+
// validateStoryBatch só tinha caso positivo). Diretório real, sem
|
|
411
|
+
// NENHUM `*.story.md` — glob vazio não pode virar exceção nem contar
|
|
412
|
+
// como se tivesse processado algo.
|
|
413
|
+
const emptyDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vsa-empty-'));
|
|
414
|
+
fs.writeFileSync(path.join(emptyDir, 'nota.txt'), 'não é story');
|
|
415
|
+
const r = m.validateStoryBatch(emptyDir, { cwd: process.cwd() });
|
|
416
|
+
assert(r.files === 0 && r.total === 0 && r.ok.length === 0 && r.reprovados.length === 0, 'AC-26 [controle negativo]: diretório sem *.story.md — files=0, sem exceção', r);
|
|
417
|
+
}
|
|
418
|
+
{
|
|
419
|
+
const c = fs.readFileSync(path.join(REPO_ROOT, 'template', '.claude', 'skills', 'pc-validate-story', 'SKILL.md'), 'utf8');
|
|
420
|
+
const i = c.indexOf('ACs testaveis e rastreaveis');
|
|
421
|
+
const i2 = c.indexOf('ACs testáveis e rastreáveis');
|
|
422
|
+
const idx = i >= 0 ? i : i2;
|
|
423
|
+
const near = idx >= 0 ? c.slice(idx, idx + 600) : '';
|
|
424
|
+
assert(idx >= 0 && near.indexOf('validate-story-acs') >= 0, 'AC-27: SKILL.md ancora a instrução no item 3', null);
|
|
425
|
+
}
|
|
426
|
+
{
|
|
427
|
+
const r = m.runOracle('node scripts/validate-story-acs.cjs /caminho/que/nao/existe.story.md', { cwd: process.cwd(), timeoutMs: 5000 });
|
|
428
|
+
const noRawTrace = !/at Object\.|at Module\._compile|node:internal/.test(r.stderr || '');
|
|
429
|
+
assert(r.exitCode !== 0 && noRawTrace, 'AC-28: CLI sobre arquivo inexistente — erro limpo, sem stack cru', r);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// ---------------------------------------------------------------------
|
|
433
|
+
// Bloco G — Guardas gerais / auto-referência com controle negativo
|
|
434
|
+
// ---------------------------------------------------------------------
|
|
435
|
+
{
|
|
436
|
+
// SF12.6/ADR-030 Bloco C/D: `scripts/forge-generate.cjs` deixou de ser "motor congelado"
|
|
437
|
+
// — é o GERADOR de pods (`*new`/`*upgrade-pod`/`*migrate-squad`/`*harden-learning`), que
|
|
438
|
+
// evolui a cada story da linha ADR-030 (SF12.4a/SF12.4b/SF12.5a/SF12.5b/SF12.6...). Um
|
|
439
|
+
// AC permanente que exige "eternamente intocado" quebraria toda story futura que o toque
|
|
440
|
+
// legitimamente — retirado do escopo desta checagem; DF2-1 (zero linha de motor) segue
|
|
441
|
+
// provado para os 2 scripts de RUNTIME (pc-run-pod.cjs/validate-pod-workflow.cjs), que são
|
|
442
|
+
// os que a decisão original (SF11.11) de fato cobria.
|
|
443
|
+
const r = m.runOracle('git diff --stat -- scripts/pc-run-pod.cjs scripts/validate-pod-workflow.cjs', { cwd: process.cwd(), timeoutMs: 5000 });
|
|
444
|
+
assert(r.refused !== true && r.stdout.trim() === '', 'AC-29: motor de runtime intocado (DF2-1) — git diff --stat vazio (pc-run-pod.cjs/validate-pod-workflow.cjs; forge-generate.cjs evolui por story, SF12.6)', r);
|
|
445
|
+
}
|
|
446
|
+
{
|
|
447
|
+
const c = fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf8');
|
|
448
|
+
assert(/validate-story-acs/.test(c), 'AC-30: package.json referencia validate-story-acs no scripts.test', null);
|
|
449
|
+
}
|
|
450
|
+
{
|
|
451
|
+
const c = fs.readFileSync(path.join(REPO_ROOT, 'docs', 'mecanismos', 'validador-de-acs-do-ciclo.md'), 'utf8');
|
|
452
|
+
assert(/vocabulario|vocabulário/i.test(c), 'AC-31: fronteiras declaradas (vocabulário + Corpus 5b) no doc', null);
|
|
453
|
+
}
|
|
454
|
+
{
|
|
455
|
+
const mutant = f(['## Acceptance Criteria', '', '**AC-M.** mutante', '```oraculo', 'test -f package.json', '```']);
|
|
456
|
+
const rm = m.validateStory(mutant, { cwd: process.cwd() });
|
|
457
|
+
const mutantCaught = rm.reprovados.find((x) => x.id === 'AC-M' && /nasce verde/i.test(x.motivo));
|
|
458
|
+
assert(!!mutantCaught, 'AC-32b: controle negativo — mutante nasce-verde é REPROVADO', rm);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// ---------------------------------------------------------------------
|
|
462
|
+
// Story SF13.7 — `parseGuarda` distingue CITAÇÃO (code span / fence) de USO
|
|
463
|
+
// real. Cada caso vem PAREADO: o que NÃO deve ser reconhecido junto com o
|
|
464
|
+
// que DEVE — um fix que simplesmente parasse de reconhecer `[Guarda]`
|
|
465
|
+
// zeraria os falsos positivos e cegaria o instrumento, e é exatamente isso
|
|
466
|
+
// que os controles positivos abaixo impedem de passar.
|
|
467
|
+
// ---------------------------------------------------------------------
|
|
468
|
+
{
|
|
469
|
+
// --- Controle NEGATIVO: citação entre crases não é uso (AC-1) ---
|
|
470
|
+
const body = [
|
|
471
|
+
'descricao cita `[Guarda] (prova: AC-CITADO)` como exemplo, mas o guarda real eh outro:',
|
|
472
|
+
'[Guarda] (sem irmao - ausencia declarada)',
|
|
473
|
+
'```oraculo',
|
|
474
|
+
'# espera: stdout-vazio',
|
|
475
|
+
'test -f arquivo-que-nao-existe-xyz123',
|
|
476
|
+
'```',
|
|
477
|
+
].join('\n');
|
|
478
|
+
const g = m.parseGuarda(body);
|
|
479
|
+
assert(
|
|
480
|
+
!!g && g.forma === 'sem-irmao',
|
|
481
|
+
'SF13.7/AC-1: citação em code span é ignorada e vence o uso REAL da linha seguinte',
|
|
482
|
+
g,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
{
|
|
486
|
+
// --- Controle POSITIVO pareado: uso real SEM citação segue reconhecido ---
|
|
487
|
+
const body = ['descricao real do AC.', '[Guarda] (prova: AC-A)', '```oraculo', 'test -f package.json', '```'].join('\n');
|
|
488
|
+
const g = m.parseGuarda(body);
|
|
489
|
+
assert(
|
|
490
|
+
!!g && g.forma === 'prova' && g.provaId === 'AC-A',
|
|
491
|
+
'SF13.7/AC-2: controle positivo — `[Guarda] (prova: AC-A)` sem citação continua reconhecido',
|
|
492
|
+
g,
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
{
|
|
496
|
+
// --- Controle POSITIVO das outras 2 formas (o fix não cega a família) ---
|
|
497
|
+
const semIrmao = m.parseGuarda('d\n[Guarda] (sem irmão — ausência declarada)\n');
|
|
498
|
+
const citacao = m.parseGuarda('d\n[Guarda] (citação de fato pré-existente, não prova de trabalho)\n');
|
|
499
|
+
const desconhecida = m.parseGuarda('d\n[Guarda] (banana)\n');
|
|
500
|
+
assert(
|
|
501
|
+
semIrmao && semIrmao.forma === 'sem-irmao'
|
|
502
|
+
&& citacao && citacao.forma === 'citacao'
|
|
503
|
+
&& desconhecida && desconhecida.forma === 'desconhecida',
|
|
504
|
+
'SF13.7/AC-2b: as 3 formas + a não reconhecida continuam classificadas quando o uso é real',
|
|
505
|
+
{ semIrmao, citacao, desconhecida },
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
{
|
|
509
|
+
// --- SF13.9/M5: o caso que a restrição de "mesma linha" de
|
|
510
|
+
// `computeInlineCodeRanges` de fato protege. Fixture e asserção exatas
|
|
511
|
+
// do gate `sf13.7-conserto-do-instrumento.yaml`
|
|
512
|
+
// (`finding_4_julgamento.teste_que_mata_M5`), executadas pelo QA nas
|
|
513
|
+
// duas direções: COM a restrição dá `AC-A`; SEM ela dá `null`.
|
|
514
|
+
// Existe porque `AC-29` de `sf13.1` — o caso que o comentário do fonte
|
|
515
|
+
// citava — NÃO exercita a restrição: sob M5 ele continua `sem-irmao` e
|
|
516
|
+
// nenhum AC ficava vermelho, então o mutante sobrevivia. ---
|
|
517
|
+
const body = [
|
|
518
|
+
'prosa com crase orfa ` aberta aqui',
|
|
519
|
+
'[Guarda] (prova: AC-A)',
|
|
520
|
+
'mais prosa com ` outra crase',
|
|
521
|
+
'```oraculo',
|
|
522
|
+
'test -f package.json',
|
|
523
|
+
'```',
|
|
524
|
+
].join('\n');
|
|
525
|
+
const g = m.parseGuarda(body);
|
|
526
|
+
assert(
|
|
527
|
+
!!g && g.forma === 'prova' && g.provaId === 'AC-A',
|
|
528
|
+
'SF13.9/M5: crase órfã não pareia ATRAVÉS de linhas — o guarda REAL entre as duas continua reconhecido (AC-A)',
|
|
529
|
+
g,
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
{
|
|
533
|
+
// --- Citação DENTRO de fence (fixture literal em ```oraculo) não é uso ---
|
|
534
|
+
const body = ['descricao sem guarda propria.', '```oraculo', 'node -e \'const c="[Guarda] (prova: AC-Z)";\'', '```'].join('\n');
|
|
535
|
+
assert(
|
|
536
|
+
m.parseGuarda(body) === null,
|
|
537
|
+
'SF13.7/AC-1b: `[Guarda]` como dado literal dentro da fence do oráculo não é etiqueta aplicada',
|
|
538
|
+
m.parseGuarda(body),
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
{
|
|
542
|
+
// --- Precedência: escolhe a ocorrência REAL, não a primeira TEXTUAL ---
|
|
543
|
+
const body = ['cita `[Guarda] (prova: AC-CITADO)` na prosa', '[Guarda] (prova: AC-REAL)', '```oraculo', 'test -f package.json', '```'].join('\n');
|
|
544
|
+
const g = m.parseGuarda(body);
|
|
545
|
+
assert(
|
|
546
|
+
!!g && g.provaId === 'AC-REAL',
|
|
547
|
+
'SF13.7/AC-1c: citação e uso com textos DIFERENTES — vence o uso real, não o 1º match textual',
|
|
548
|
+
g,
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
{
|
|
552
|
+
// --- Regressão no corpus REAL: AC-29 de sf13.1 (citação e uso idênticos,
|
|
553
|
+
// em linhas consecutivas) continua classificado `sem-irmao` (AC-3) ---
|
|
554
|
+
const c = fs.readFileSync(path.join(REPO_ROOT, 'docs', 'stories', 'sf13.1.story.md'), 'utf8');
|
|
555
|
+
const ac29 = m.parseAcs(c).find((a) => a.id === 'AC-29');
|
|
556
|
+
assert(
|
|
557
|
+
!!ac29 && !!ac29.guarda && ac29.guarda.forma === 'sem-irmao',
|
|
558
|
+
'SF13.7/AC-3: corpus real — AC-29 de sf13.1 (citação + uso idênticos) mantém `sem-irmao`',
|
|
559
|
+
ac29 && ac29.guarda,
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
{
|
|
563
|
+
// --- Corpus real, contabilidade COMPLETA (não amostra): a única guarda
|
|
564
|
+
// REAL de sf13.1 é a do AC-29; as outras 8 eram citação em code span.
|
|
565
|
+
// É o que prova que o fix não removeu nenhum verdadeiro positivo. ---
|
|
566
|
+
const c = fs.readFileSync(path.join(REPO_ROOT, 'docs', 'stories', 'sf13.1.story.md'), 'utf8');
|
|
567
|
+
const comGuarda = m.parseAcs(c).filter((a) => a.guarda).map((a) => a.id);
|
|
568
|
+
assert(
|
|
569
|
+
comGuarda.length === 1 && comGuarda[0] === 'AC-29',
|
|
570
|
+
'SF13.7/AC-4: corpus real sf13.1 — exatamente 1 guarda real reconhecida (AC-29)',
|
|
571
|
+
comGuarda,
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
{
|
|
575
|
+
// --- Campos que o HOOK consome não mudam com o fix (fundamento do
|
|
576
|
+
// gatilho `pc-architect` NÃO ATIVO, AC-6): `parseGuarda` só altera
|
|
577
|
+
// `.guarda`, nunca `hasOraculo`/`oracleCmd`/`oracleEmpty`/`espera`. ---
|
|
578
|
+
const c = f([
|
|
579
|
+
'## Acceptance Criteria',
|
|
580
|
+
'',
|
|
581
|
+
'**AC-X.** cita `[Guarda] (prova: AC-CITADO)` na prosa',
|
|
582
|
+
'```oraculo',
|
|
583
|
+
'# espera: stdout == OK',
|
|
584
|
+
'test -f package.json',
|
|
585
|
+
'```',
|
|
586
|
+
]);
|
|
587
|
+
const ac = m.parseAcs(c).find((a) => a.id === 'AC-X');
|
|
588
|
+
assert(
|
|
589
|
+
!!ac && ac.hasOraculo === true && ac.oracleCmd === 'test -f package.json'
|
|
590
|
+
&& ac.oracleEmpty === false && !!ac.espera && ac.espera.type === 'stdout==',
|
|
591
|
+
'SF13.7/AC-6: campos consumidos pelo hook (hasOraculo/oracleCmd/oracleEmpty/espera) intactos',
|
|
592
|
+
ac,
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// ---------------------------------------------------------------------
|
|
597
|
+
// Sumário
|
|
598
|
+
// ---------------------------------------------------------------------
|
|
599
|
+
if (failures > 0) {
|
|
600
|
+
console.error(`\n${failures} asserção(ões) falharam.`);
|
|
601
|
+
process.exitCode = 1;
|
|
602
|
+
} else {
|
|
603
|
+
console.log('\nTodas as asserções passaram.');
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
run();
|