@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,452 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* pod-memory-note.test.cjs — Story SF11.5 / ADR-020 §Revisão 3 (`DF-SF10.21-15..19`).
|
|
5
|
+
*
|
|
6
|
+
* O QUE ESTA SUÍTE PROVA (por EXECUÇÃO real do script, nunca por leitura de código):
|
|
7
|
+
* AC1 O invocador existe, exporta função pura testável, e NÃO importa o motor
|
|
8
|
+
* (`pc-run-pod.cjs`); quando o SHA-base está disponível, o `git diff` do motor
|
|
9
|
+
* é conferido aqui também.
|
|
10
|
+
* AC2 A mensagem NUNCA viaja por argv: o MESMO texto (aspas duplas, aspas simples,
|
|
11
|
+
* acentos e quebra de linha REAL) chega byte a byte ao log cru pelos dois canais
|
|
12
|
+
* legítimos (`--file` e stdin) — e toda flag de texto livre é ERRO DE USO.
|
|
13
|
+
* AC4 `attributed_by` é a string literal "human" (ENUM), NUNCA nome próprio, NUNCA
|
|
14
|
+
* null. Kill-test junto: omitir o campo cairia em `null` em SILÊNCIO.
|
|
15
|
+
* AC5 `approve` com comentário → UMA linha nova, correta; `approve` sem comentário →
|
|
16
|
+
* ZERO linhas novas (prova por CONTAGEM antes/depois, não por parsing).
|
|
17
|
+
* AC6 `revise` captura igual — o caso de maior valor (hoje o motor não grava nada).
|
|
18
|
+
* AC7 Dois vereditos na MESMA etapa produzem `trigger`s distinguíveis.
|
|
19
|
+
* AC8 Comentário que força poda ANUNCIA o que saiu, medido contra o teto REAL do
|
|
20
|
+
* `hn-carousel` (900 tok, `acceptedBy: "Alexa Exemplo"`), com contraprova de que
|
|
21
|
+
* sem estouro nenhum aviso é impresso.
|
|
22
|
+
*
|
|
23
|
+
* Node >= 18, sem dependências externas.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const fs = require('node:fs');
|
|
27
|
+
const os = require('node:os');
|
|
28
|
+
const path = require('node:path');
|
|
29
|
+
const { spawnSync } = require('node:child_process');
|
|
30
|
+
|
|
31
|
+
const podMemory = require('./pod-memory.cjs');
|
|
32
|
+
const note = require('./pod-memory-note.cjs');
|
|
33
|
+
|
|
34
|
+
const SCRIPT = path.join(__dirname, 'pod-memory-note.cjs');
|
|
35
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
36
|
+
// SHA de origem da branch desta story (Dev Notes da SF11.5). Conferido só quando o objeto
|
|
37
|
+
// existe no clone — o resultado do teste nunca depende do histórico local estar completo.
|
|
38
|
+
const BASE_SHA = '27e1546';
|
|
39
|
+
|
|
40
|
+
const failures = [];
|
|
41
|
+
let passed = 0;
|
|
42
|
+
function ok(label, cond, extra) {
|
|
43
|
+
if (cond) { passed += 1; console.log(`[OK ] ${label}`); return; }
|
|
44
|
+
failures.push(label);
|
|
45
|
+
console.log(`[FALHA] ${label}${extra ? ` — ${String(extra).slice(0, 600)}` : ''}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ── Fixtures ────────────────────────────────────────────────────────────────
|
|
49
|
+
function tmpPod(label, { podSpec } = {}) {
|
|
50
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), `sf11.5-${label}-`));
|
|
51
|
+
const podDir = path.join(tmp, 'hn-carousel');
|
|
52
|
+
fs.mkdirSync(path.join(podDir, 'memory'), { recursive: true });
|
|
53
|
+
fs.mkdirSync(path.join(podDir, 'workflows'), { recursive: true });
|
|
54
|
+
if (podSpec) fs.writeFileSync(path.join(podDir, 'pod-spec.json'), JSON.stringify(podSpec, null, 2));
|
|
55
|
+
const statePath = path.join(tmp, 'state.json');
|
|
56
|
+
const state = {
|
|
57
|
+
pod: 'hn-carousel',
|
|
58
|
+
workflow: 'wf-hn-carousel',
|
|
59
|
+
run_id: '2026-08-03T10-00-00Z-sf115',
|
|
60
|
+
mode: 'interactive',
|
|
61
|
+
steps: {
|
|
62
|
+
digest: { status: 'done' },
|
|
63
|
+
visuals: { status: 'done' },
|
|
64
|
+
assembly: { status: 'awaiting_approval' },
|
|
65
|
+
},
|
|
66
|
+
updated_at: new Date().toISOString(),
|
|
67
|
+
};
|
|
68
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
69
|
+
// `podRootFor` é derivação PURA de path: o wf não precisa existir para o teste do
|
|
70
|
+
// invocador (ele não valida workflow — zero acoplamento ao motor).
|
|
71
|
+
const wfPath = path.join(podDir, 'workflows', 'wf-hn-carousel.yaml');
|
|
72
|
+
return { tmp, podDir, statePath, wfPath, state };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** `memoryCost` REAL do hn-carousel (`second-brain/pods/hn-carousel/pod-spec.json`, SF11.4b/ADR-023). */
|
|
76
|
+
const REAL_MEMORY_COST = {
|
|
77
|
+
artifactTokens: 900,
|
|
78
|
+
perRunTokens: 2700,
|
|
79
|
+
steps: 3,
|
|
80
|
+
acceptedBy: 'Alexa Exemplo',
|
|
81
|
+
acceptedAt: '2026-08-03',
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
function rawPath(podDir) {
|
|
85
|
+
return podMemory.memoryPaths('hn-carousel', { podDir }).raw;
|
|
86
|
+
}
|
|
87
|
+
function countLines(podDir) {
|
|
88
|
+
const p = rawPath(podDir);
|
|
89
|
+
if (!fs.existsSync(p)) return 0;
|
|
90
|
+
return fs.readFileSync(p, 'utf8').split('\n').filter((l) => l.trim()).length;
|
|
91
|
+
}
|
|
92
|
+
function readRecords(podDir) {
|
|
93
|
+
const p = rawPath(podDir);
|
|
94
|
+
if (!fs.existsSync(p)) return [];
|
|
95
|
+
return fs.readFileSync(p, 'utf8').split('\n').filter((l) => l.trim()).map((l) => JSON.parse(l));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function runCli(args, { input } = {}) {
|
|
99
|
+
return spawnSync(process.execPath, [SCRIPT, ...args], {
|
|
100
|
+
encoding: 'utf8',
|
|
101
|
+
cwd: REPO_ROOT,
|
|
102
|
+
input: input === undefined ? '' : input, // stdin SEMPRE pipe (nunca TTY) no teste
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Texto do dono: aspas duplas, aspas simples, acentos e QUEBRA DE LINHA real — o conteúdo
|
|
107
|
+
// que quebraria num heredoc/echo e que argv exporia em `ps`.
|
|
108
|
+
const OWNER_TEXT =
|
|
109
|
+
'A capa está "fraca": o título some no fundo e não dá pra ler no feed.\n' +
|
|
110
|
+
"Refaça com contraste alto e mantenha a assinatura do Daniel no CTA (regra que já valeu na rodada passada).";
|
|
111
|
+
|
|
112
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
113
|
+
// AC1 — invocador fino, função pura, motor intocado
|
|
114
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
115
|
+
console.log('--- AC1/DF-SF10.21-15: invocador fino, sem acoplamento ao motor ---');
|
|
116
|
+
{
|
|
117
|
+
ok('exporta função PURA testável (buildNoteEntry), não só CLI',
|
|
118
|
+
typeof note.buildNoteEntry === 'function' && typeof note.noteCheckpointComment === 'function');
|
|
119
|
+
|
|
120
|
+
const src = fs.readFileSync(SCRIPT, 'utf8');
|
|
121
|
+
const requires = [...src.matchAll(/require\(\s*['"]([^'"]+)['"]\s*\)/g)].map((m) => m[1]);
|
|
122
|
+
ok(`NÃO importa pc-run-pod.cjs (requires: ${requires.join(', ')})`,
|
|
123
|
+
!requires.some((r) => r.includes('pc-run-pod')));
|
|
124
|
+
|
|
125
|
+
// Função pura: monta a entrada sem tocar em disco.
|
|
126
|
+
const e = note.buildNoteEntry({
|
|
127
|
+
step: 'assembly', verdict: 'approve', message: OWNER_TEXT, runId: 'run-1',
|
|
128
|
+
});
|
|
129
|
+
ok('buildNoteEntry é pura (sem I/O) e devolve o contrato de append',
|
|
130
|
+
e.trigger && e.recommendation === OWNER_TEXT && e.tier === 'normal' && e.source_run_id === 'run-1');
|
|
131
|
+
|
|
132
|
+
// ── EMENDA SF11.10/ADR-024 `DF-SF11.10-10` ────────────────────────────────
|
|
133
|
+
// Este bloco afirmava `git diff <BASE_SHA> -- scripts/pc-run-pod.cjs` VAZIO. Isso era
|
|
134
|
+
// verdade sobre o diff DAQUELA story e virou, sem querer, uma afirmação sobre TODA story
|
|
135
|
+
// futura ("o motor nunca muda") — o que a SF11.5 nunca provou nem podia provar. A SF11.10
|
|
136
|
+
// tocou o motor conscientemente (gate de texto condicionado ao ritmo: `isBlocking(step,
|
|
137
|
+
// mode)` + 2 chamadores + conjunto fechado de `mode` + `capabilityGaps`), com justificativa
|
|
138
|
+
// PRÓPRIA e enumeração exaustiva no ADR-024 — não herdada da permissão da SF11.2.
|
|
139
|
+
//
|
|
140
|
+
// O que a SF11.5 de fato protegia, e continua protegido aqui: o mecanismo de comentário de
|
|
141
|
+
// checkpoint é INVOCADOR FINO — nem ele conhece o motor (asserção acima), nem o motor
|
|
142
|
+
// conhece ele. A checagem passa a ser exatamente essa propriedade, que é um invariante VIVO
|
|
143
|
+
// (falseável a qualquer momento), em vez de um congelamento de arquivo que qualquer evolução
|
|
144
|
+
// legítima do motor derruba. Ganha-se em verdade; perde-se a auditabilidade barata do "diff
|
|
145
|
+
// vazio" — perda declarada no `DF-SF11.10-10`, cujo contrapeso é a enumeração no ADR.
|
|
146
|
+
const ACOPLAMENTO = ['pod-memory-note', 'noteCheckpointComment', 'buildNoteEntry', 'checkpoint-note'];
|
|
147
|
+
const motorSrc = fs.readFileSync(path.join(REPO_ROOT, 'scripts', 'pc-run-pod.cjs'), 'utf8');
|
|
148
|
+
const vazados = ACOPLAMENTO.filter((n) => motorSrc.includes(n));
|
|
149
|
+
ok('o MOTOR não conhece o invocador de comentário (zero acoplamento na volta) — SF11.5 preservada sob ADR-024',
|
|
150
|
+
vazados.length === 0, `vazou no motor: ${vazados.join(', ')}`);
|
|
151
|
+
|
|
152
|
+
// E o diff do motor desde o SHA-base, quando existe no clone, não pode ter INTRODUZIDO
|
|
153
|
+
// acoplamento nenhum — a evolução do motor é permitida, contaminá-lo com o mecanismo não.
|
|
154
|
+
const has = spawnSync('git', ['rev-parse', '--verify', `${BASE_SHA}^{commit}`], { cwd: REPO_ROOT, encoding: 'utf8' });
|
|
155
|
+
if (has.status === 0) {
|
|
156
|
+
const d = spawnSync('git', ['diff', BASE_SHA, '--', 'scripts/pc-run-pod.cjs'], { cwd: REPO_ROOT, encoding: 'utf8' });
|
|
157
|
+
const sujo = ACOPLAMENTO.filter((n) => d.stdout.includes(n));
|
|
158
|
+
ok(`git diff ${BASE_SHA} -- scripts/pc-run-pod.cjs não introduz acoplamento ao invocador`,
|
|
159
|
+
d.status === 0 && sujo.length === 0, `citações no diff: ${sujo.join(', ')}`);
|
|
160
|
+
} else {
|
|
161
|
+
console.log(`[SKIP ] git diff ${BASE_SHA} -- scripts/pc-run-pod.cjs (SHA-base ausente neste clone; conferido no Dev Agent Record)`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
166
|
+
// AC2 — a mensagem NUNCA vai por argv: --file e stdin, byte a byte
|
|
167
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
168
|
+
console.log('\n--- AC2/DF-SF10.21-15: mensagem por arquivo e por stdin, verbatim ---');
|
|
169
|
+
{
|
|
170
|
+
// (a) --file — com \n final no arquivo (artefato de escrita), que NÃO pode virar conteúdo
|
|
171
|
+
const A = tmpPod('file');
|
|
172
|
+
const msgFile = path.join(A.tmp, 'comentario.txt');
|
|
173
|
+
fs.writeFileSync(msgFile, `${OWNER_TEXT}\n`);
|
|
174
|
+
const rA = runCli(['--state', A.statePath, '--workflow-file', A.wfPath,
|
|
175
|
+
'--step', 'assembly', '--verdict', 'approve', '--file', msgFile]);
|
|
176
|
+
ok(`--file: exit 0 (stderr: ${rA.stderr.trim().slice(0, 120)})`, rA.status === 0, rA.stderr);
|
|
177
|
+
const recA = readRecords(A.podDir)[0];
|
|
178
|
+
ok('--file: recommendation bate BYTE A BYTE com o texto do dono (aspas + \\n reais)',
|
|
179
|
+
recA && Buffer.compare(Buffer.from(recA.recommendation, 'utf8'), Buffer.from(OWNER_TEXT, 'utf8')) === 0,
|
|
180
|
+
JSON.stringify(recA && recA.recommendation));
|
|
181
|
+
ok('--file: a quebra de linha real sobreviveu (não virou espaço nem \\\\n literal)',
|
|
182
|
+
recA && recA.recommendation.includes('\n') && recA.recommendation.split('\n').length === 2);
|
|
183
|
+
ok('--file: as aspas duplas sobreviveram íntegras',
|
|
184
|
+
recA && recA.recommendation.includes('"fraca"'));
|
|
185
|
+
|
|
186
|
+
// (b) stdin — MESMO texto, canal diferente
|
|
187
|
+
const B = tmpPod('stdin');
|
|
188
|
+
const rB = runCli(['--state', B.statePath, '--workflow-file', B.wfPath,
|
|
189
|
+
'--step', 'assembly', '--verdict', 'approve'], { input: OWNER_TEXT });
|
|
190
|
+
ok(`stdin: exit 0 (stderr: ${rB.stderr.trim().slice(0, 120)})`, rB.status === 0, rB.stderr);
|
|
191
|
+
const recB = readRecords(B.podDir)[0];
|
|
192
|
+
ok('stdin: recommendation bate BYTE A BYTE com o texto do dono',
|
|
193
|
+
recB && Buffer.compare(Buffer.from(recB.recommendation, 'utf8'), Buffer.from(OWNER_TEXT, 'utf8')) === 0,
|
|
194
|
+
JSON.stringify(recB && recB.recommendation));
|
|
195
|
+
ok('os DOIS canais produzem a MESMA recommendation (o canal não altera o conteúdo)',
|
|
196
|
+
recA && recB && recA.recommendation === recB.recommendation);
|
|
197
|
+
|
|
198
|
+
// (c) sem --file e sem stdin (input vazio) → ERRO DE USO, nunca entrada fabricada
|
|
199
|
+
const C = tmpPod('vazio');
|
|
200
|
+
const before = countLines(C.podDir);
|
|
201
|
+
const rC = runCli(['--state', C.statePath, '--workflow-file', C.wfPath,
|
|
202
|
+
'--step', 'assembly', '--verdict', 'approve'], { input: '' });
|
|
203
|
+
ok(`sem --file e sem stdin: exit 2 (uso), não 0 — recebido ${rC.status}`, rC.status === 2, rC.stderr);
|
|
204
|
+
ok('sem --file e sem stdin: ZERO linhas gravadas (nada fabricado)', countLines(C.podDir) === before);
|
|
205
|
+
ok('a mensagem de erro é acionável (diz o que fazer)',
|
|
206
|
+
/--file/.test(rC.stderr) && /(vazia|stdin)/i.test(rC.stderr), rC.stderr);
|
|
207
|
+
|
|
208
|
+
// (d) flags de texto livre são RECUSADAS por nome (não aceitas-e-ignoradas)
|
|
209
|
+
const D = tmpPod('argv');
|
|
210
|
+
for (const flag of ['--message', '--comment', '--note', '-m']) {
|
|
211
|
+
const r = runCli(['--state', D.statePath, '--workflow-file', D.wfPath,
|
|
212
|
+
'--step', 'assembly', '--verdict', 'approve', flag, OWNER_TEXT]);
|
|
213
|
+
ok(`"${flag}" é ERRO DE USO explícito (exit 2) e nada é gravado`,
|
|
214
|
+
r.status === 2 && countLines(D.podDir) === 0 && /argv/i.test(r.stderr), `${r.status} ${r.stderr}`);
|
|
215
|
+
}
|
|
216
|
+
// (e) posicional/flag desconhecida também não é porta de entrada de texto
|
|
217
|
+
const rPos = runCli(['--state', D.statePath, '--workflow-file', D.wfPath,
|
|
218
|
+
'--step', 'assembly', '--verdict', 'approve', OWNER_TEXT]);
|
|
219
|
+
ok('texto posicional é recusado (exit 2), não tratado como mensagem',
|
|
220
|
+
rPos.status === 2 && countLines(D.podDir) === 0, `${rPos.status} ${rPos.stderr}`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
224
|
+
// AC4 — attributed_by === "human" (ENUM), nunca nome próprio, nunca null
|
|
225
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
226
|
+
console.log('\n--- AC4/DF-SF10.21-16: attributed_by é o ENUM "human" ---');
|
|
227
|
+
{
|
|
228
|
+
const F = tmpPod('attr', { podSpec: { pod: 'hn-carousel', memoryCost: REAL_MEMORY_COST } });
|
|
229
|
+
const msgFile = path.join(F.tmp, 'c.txt');
|
|
230
|
+
fs.writeFileSync(msgFile, 'Aprovado: a capa ficou legível no feed e o CTA fecha com autoridade.');
|
|
231
|
+
const r = runCli(['--state', F.statePath, '--workflow-file', F.wfPath,
|
|
232
|
+
'--step', 'assembly', '--verdict', 'approve', '--file', msgFile]);
|
|
233
|
+
ok(`grava com pod-spec real presente (exit 0) — stderr: ${r.stderr.trim().slice(0, 120)}`, r.status === 0, r.stderr);
|
|
234
|
+
const rec = readRecords(F.podDir)[0];
|
|
235
|
+
ok('attributed_by === "human" (comparação de string EXATA)', rec && rec.attributed_by === 'human',
|
|
236
|
+
JSON.stringify(rec && rec.attributed_by));
|
|
237
|
+
ok('attributed_by NÃO é null (o default silencioso de tier normal não pegou)',
|
|
238
|
+
rec && rec.attributed_by !== null && rec.attributed_by !== undefined);
|
|
239
|
+
|
|
240
|
+
// CAMPO DIFERENTE, PROPÓSITO DIFERENTE: `attributed_by` (enum de proveniência) NÃO é
|
|
241
|
+
// `pod-spec.json → memoryCost.acceptedBy` (atribuição NOMINAL do dono, SF11.4b).
|
|
242
|
+
const spec = JSON.parse(fs.readFileSync(path.join(F.podDir, 'pod-spec.json'), 'utf8'));
|
|
243
|
+
ok('acceptedBy nominal é "Alexa Exemplo" e NÃO vaza para attributed_by',
|
|
244
|
+
spec.memoryCost.acceptedBy === 'Alexa Exemplo' && rec.attributed_by !== spec.memoryCost.acceptedBy);
|
|
245
|
+
ok('attributed_by pertence ao ENUM fechado VALID_ATTRIBUTION do pod-memory',
|
|
246
|
+
['human', 'deterministic_rule'].includes(rec.attributed_by));
|
|
247
|
+
|
|
248
|
+
// KILL-TEST do footgun: OMITIR o campo cai em null EM SILÊNCIO (pod-memory.cjs, o
|
|
249
|
+
// default só é cobrado em `critical`). É por isso que o literal é fixado no invocador.
|
|
250
|
+
const G = tmpPod('footgun');
|
|
251
|
+
const semAttr = note.buildNoteEntry({ step: 'assembly', verdict: 'approve', message: 'x', runId: 'r' });
|
|
252
|
+
delete semAttr.attributed_by;
|
|
253
|
+
const w = podMemory.append('hn-carousel', semAttr, { podDir: G.podDir });
|
|
254
|
+
ok('KILL-TEST: sem o literal fixado, append aceitaria attributed_by=null EM SILÊNCIO',
|
|
255
|
+
w.entry.attributed_by === null, JSON.stringify(w.entry.attributed_by));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
259
|
+
// AC5 — approve com comentário → 1 linha; sem comentário → ZERO (por CONTAGEM)
|
|
260
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
261
|
+
console.log('\n--- AC5/DF-SF10.21-16,-17: com comentário grava; silêncio não vira learning ---');
|
|
262
|
+
{
|
|
263
|
+
// A: comentário não-vazio
|
|
264
|
+
const A = tmpPod('ac5a');
|
|
265
|
+
const before = countLines(A.podDir);
|
|
266
|
+
const f = path.join(A.tmp, 'c.txt');
|
|
267
|
+
fs.writeFileSync(f, OWNER_TEXT);
|
|
268
|
+
const r = runCli(['--state', A.statePath, '--workflow-file', A.wfPath,
|
|
269
|
+
'--step', 'assembly', '--verdict', 'approve', '--file', f]);
|
|
270
|
+
const after = countLines(A.podDir);
|
|
271
|
+
ok(`approve com comentário: UMA linha nova (${before} → ${after})`, r.status === 0 && after === before + 1, r.stderr);
|
|
272
|
+
const rec = readRecords(A.podDir)[after - 1];
|
|
273
|
+
ok('tier === "normal"', rec.tier === 'normal');
|
|
274
|
+
ok('attributed_by === "human"', rec.attributed_by === 'human');
|
|
275
|
+
ok(`source_run_id === run_id do state ("${A.state.run_id}")`, rec.source_run_id === A.state.run_id);
|
|
276
|
+
ok(`trigger DETERMINÍSTICO: ${JSON.stringify(rec.trigger)}`,
|
|
277
|
+
rec.trigger === 'checkpoint "assembly" aprovado pelo dono');
|
|
278
|
+
ok('trigger NÃO é fabricado do texto do comentário (nenhuma palavra do comentário nele)',
|
|
279
|
+
!/capa|contraste|feed|título/i.test(rec.trigger));
|
|
280
|
+
ok('recommendation === comentário VERBATIM', rec.recommendation === OWNER_TEXT);
|
|
281
|
+
ok('evidence liga a decisão à etapa e ao run (auditoria)',
|
|
282
|
+
rec.evidence && rec.evidence.step === 'assembly' && rec.evidence.verdict === 'approve'
|
|
283
|
+
&& rec.evidence.run_id === A.state.run_id, JSON.stringify(rec.evidence));
|
|
284
|
+
|
|
285
|
+
// B: comentário vazio / só espaço → ZERO linhas novas (prova por CONTAGEM)
|
|
286
|
+
const B = tmpPod('ac5b');
|
|
287
|
+
fs.writeFileSync(rawPath(B.podDir), `${JSON.stringify({ id: 'x', ts: 1, trigger: 't', recommendation: 'r', tier: 'normal' })}\n`);
|
|
288
|
+
const b0 = countLines(B.podDir);
|
|
289
|
+
const vazio = path.join(B.tmp, 'vazio.txt');
|
|
290
|
+
fs.writeFileSync(vazio, ' \n\t\n ');
|
|
291
|
+
const rb = runCli(['--state', B.statePath, '--workflow-file', B.wfPath,
|
|
292
|
+
'--step', 'assembly', '--verdict', 'approve', '--file', vazio]);
|
|
293
|
+
const b1 = countLines(B.podDir);
|
|
294
|
+
ok(`silêncio (--file só com espaço): ZERO linhas novas (${b0} → ${b1})`, b1 === b0, rb.stderr);
|
|
295
|
+
ok('silêncio: exit não-zero (chamada errada, não entrada fabricada)', rb.status !== 0, String(rb.status));
|
|
296
|
+
const rb2 = runCli(['--state', B.statePath, '--workflow-file', B.wfPath,
|
|
297
|
+
'--step', 'assembly', '--verdict', 'approve'], { input: ' \n ' });
|
|
298
|
+
ok(`silêncio (stdin só com espaço): ZERO linhas novas (${b0} → ${countLines(B.podDir)})`,
|
|
299
|
+
countLines(B.podDir) === b0, rb2.stderr);
|
|
300
|
+
ok('a biblioteca trata silêncio como "nada a gravar" (appended:false), sem exceção',
|
|
301
|
+
note.noteCheckpointComment({ pod: 'hn-carousel', podDir: B.podDir, step: 'assembly',
|
|
302
|
+
verdict: 'approve', message: ' ', runId: 'r' }).appended === false);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
306
|
+
// AC6 — revise também captura (o caso de MAIOR valor: hoje o motor não grava nada)
|
|
307
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
308
|
+
console.log('\n--- AC6/DF-SF10.21-18: revise captura fora do motor ---');
|
|
309
|
+
{
|
|
310
|
+
const R = tmpPod('revise');
|
|
311
|
+
const f = path.join(R.tmp, 'c.txt');
|
|
312
|
+
const REPROVA = 'Reprovado mesmo passando em todos os vetos: o slide 3 repete o ângulo do slide 1.\nO carrossel perde ritmo no meio.';
|
|
313
|
+
fs.writeFileSync(f, `${REPROVA}\n`);
|
|
314
|
+
const before = countLines(R.podDir);
|
|
315
|
+
const r = runCli(['--state', R.statePath, '--workflow-file', R.wfPath,
|
|
316
|
+
'--step', 'assembly', '--verdict', 'revise', '--file', f]);
|
|
317
|
+
const after = countLines(R.podDir);
|
|
318
|
+
ok(`revise com comentário: UMA linha nova (${before} → ${after})`, r.status === 0 && after === before + 1, r.stderr);
|
|
319
|
+
const rec = readRecords(R.podDir)[after - 1];
|
|
320
|
+
ok('revise: recommendation VERBATIM (o porquê da reprovação sobrevive)', rec.recommendation === REPROVA);
|
|
321
|
+
ok('revise: tier normal + attributed_by "human" + source_run_id do state',
|
|
322
|
+
rec.tier === 'normal' && rec.attributed_by === 'human' && rec.source_run_id === R.state.run_id);
|
|
323
|
+
ok(`revise: trigger determinístico ${JSON.stringify(rec.trigger)}`,
|
|
324
|
+
rec.trigger === 'checkpoint "assembly" revisado pelo dono');
|
|
325
|
+
|
|
326
|
+
// A captura acontece INTEIRAMENTE fora do motor: nenhum byte de pc-run-pod.cjs é lido,
|
|
327
|
+
// importado ou executado por este caminho (só o state.json que ele já escreveu).
|
|
328
|
+
const runnerSrc = fs.readFileSync(path.join(__dirname, 'pc-run-pod.cjs'), 'utf8');
|
|
329
|
+
ok('pc-run-pod.cjs continua SEM chamar pod-memory-note (o vão é fechado fora do motor)',
|
|
330
|
+
!runnerSrc.includes('pod-memory-note'));
|
|
331
|
+
const iRevise = runnerSrc.indexOf('function revise(ctx, stepId)');
|
|
332
|
+
const iAbort = runnerSrc.indexOf('function abort(', iRevise);
|
|
333
|
+
const reviseBody = runnerSrc.slice(iRevise, iAbort);
|
|
334
|
+
ok('revise() do motor continua sem gravar aprendizado por si (nenhum recordLearning/podMemory no corpo)',
|
|
335
|
+
iRevise > 0 && iAbort > iRevise && !/recordLearning|podMemory/.test(reviseBody),
|
|
336
|
+
reviseBody.slice(0, 200));
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
340
|
+
// AC7 — mesma etapa, dois vereditos, triggers distinguíveis
|
|
341
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
342
|
+
console.log('\n--- AC7: auditoria distingue aprovado de reprovado sem ler o texto livre ---');
|
|
343
|
+
{
|
|
344
|
+
const T = tmpPod('ac7');
|
|
345
|
+
const f1 = path.join(T.tmp, 'a.txt');
|
|
346
|
+
const f2 = path.join(T.tmp, 'b.txt');
|
|
347
|
+
// MESMO texto nos dois: a distinção NÃO pode depender do conteúdo do comentário.
|
|
348
|
+
fs.writeFileSync(f1, 'Comentário idêntico nos dois vereditos, de propósito.');
|
|
349
|
+
fs.writeFileSync(f2, 'Comentário idêntico nos dois vereditos, de propósito.');
|
|
350
|
+
const r1 = runCli(['--state', T.statePath, '--workflow-file', T.wfPath, '--step', 'assembly', '--verdict', 'approve', '--file', f1]);
|
|
351
|
+
const r2 = runCli(['--state', T.statePath, '--workflow-file', T.wfPath, '--step', 'assembly', '--verdict', 'revise', '--file', f2]);
|
|
352
|
+
ok('as duas chamadas gravaram (exit 0)', r1.status === 0 && r2.status === 0, `${r1.stderr}${r2.stderr}`);
|
|
353
|
+
const recs = readRecords(T.podDir);
|
|
354
|
+
ok(`duas linhas (${recs.length})`, recs.length === 2);
|
|
355
|
+
ok(`triggers DIFERENTES: ${JSON.stringify(recs.map((x) => x.trigger))}`, recs[0].trigger !== recs[1].trigger);
|
|
356
|
+
ok('mesmo com recommendation IDÊNTICA, o veredito é auditável por campo estruturado',
|
|
357
|
+
recs[0].recommendation === recs[1].recommendation
|
|
358
|
+
&& recs[0].evidence.verdict === 'approve' && recs[1].evidence.verdict === 'revise');
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
362
|
+
// AC8 — eviction forçada por comentário é ANUNCIADA, contra o teto REAL (900 tok)
|
|
363
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
364
|
+
console.log('\n--- AC8/ADR-021 DF-SF11.2-3: o comentário que empurra a cauda para fora ANUNCIA ---');
|
|
365
|
+
{
|
|
366
|
+
const E = tmpPod('eviction', { podSpec: { pod: 'hn-carousel', memoryCost: REAL_MEMORY_COST } });
|
|
367
|
+
const bulky = (i) => JSON.stringify({
|
|
368
|
+
id: `H${i}`, ts: 1_700_000_000_000 + i * 1000,
|
|
369
|
+
trigger: `heuristica de campo numero ${i} da rodada de producao`,
|
|
370
|
+
recommendation: `recomendacao verificavel numero ${i} — ${'texto com tamanho realista de heuristica de campo '.repeat(2)}`,
|
|
371
|
+
evidence: { count: 1 }, tier: 'normal',
|
|
372
|
+
});
|
|
373
|
+
const seedTo = (n) => fs.writeFileSync(rawPath(E.podDir),
|
|
374
|
+
`${Array.from({ length: n }, (_, i) => bulky(i)).join('\n')}\n`);
|
|
375
|
+
|
|
376
|
+
// Encontra o MAIOR pool que ainda cabe no alvo de 900 tok SEM podar nada — o comentário
|
|
377
|
+
// do dono é então o ÚNICO responsável pelo estouro (a prova exige causalidade, não
|
|
378
|
+
// "havia poda desde antes").
|
|
379
|
+
let n = 1;
|
|
380
|
+
let pre;
|
|
381
|
+
for (; n < 200; n++) {
|
|
382
|
+
seedTo(n);
|
|
383
|
+
pre = podMemory.consolidate('hn-carousel', { podDir: E.podDir });
|
|
384
|
+
if (pre.evicted.length > 0) { n -= 1; break; }
|
|
385
|
+
}
|
|
386
|
+
seedTo(n);
|
|
387
|
+
pre = podMemory.consolidate('hn-carousel', { podDir: E.podDir });
|
|
388
|
+
ok(`estado inicial NÃO poda nada: ${n} heurísticas, ${pre.tokens} tok de ${pre.tokenBudget} (alvo do pod)`,
|
|
389
|
+
pre.evicted.length === 0, JSON.stringify({ evicted: pre.evicted.length, tokens: pre.tokens }));
|
|
390
|
+
ok('o teto medido é o ALVO REAL do hn-carousel (900), não o teto do framework (1500)',
|
|
391
|
+
pre.tokenBudget === 900 && pre.memoryCost && pre.memoryCost.acceptedBy === 'Alexa Exemplo',
|
|
392
|
+
JSON.stringify({ budget: pre.tokenBudget, cost: pre.memoryCost }));
|
|
393
|
+
|
|
394
|
+
const f = path.join(E.tmp, 'c.txt');
|
|
395
|
+
fs.writeFileSync(f, `${OWNER_TEXT}\n`);
|
|
396
|
+
const before = countLines(E.podDir);
|
|
397
|
+
const r = runCli(['--state', E.statePath, '--workflow-file', E.wfPath,
|
|
398
|
+
'--step', 'assembly', '--verdict', 'revise', '--file', f]);
|
|
399
|
+
ok(`comentário gravado mesmo estourando o alvo (${before} → ${countLines(E.podDir)} linhas, exit ${r.status})`,
|
|
400
|
+
r.status === 0 && countLines(E.podDir) === before + 1, r.stderr);
|
|
401
|
+
ok(`o PRÓPRIO script imprime o aviso de poda em stderr: ${JSON.stringify(r.stderr.split('\n')[0].slice(0, 160))}`,
|
|
402
|
+
/^\[memory\] AVISO: \d+ heurística\(s\) NÃO entraram no consolidado/.test(r.stderr.trim()), r.stderr);
|
|
403
|
+
ok('o aviso NOMEIA a causa e o alvo real do pod (900 tok), não um teto inventado',
|
|
404
|
+
/alvo de custo 900 tok/.test(r.stderr), r.stderr);
|
|
405
|
+
ok('o aviso NOMEIA o que saiu (a curadoria sabe o que recuperar)',
|
|
406
|
+
/heuristica de campo numero/.test(r.stderr), r.stderr);
|
|
407
|
+
ok('o log cru continua íntegro (nada foi apagado — só deixou de ser injetado)',
|
|
408
|
+
countLines(E.podDir) === n + 1);
|
|
409
|
+
|
|
410
|
+
// CONTRAPROVA: sem estouro, nenhum aviso é impresso (o aviso não é decorativo).
|
|
411
|
+
const Q = tmpPod('sem-eviction', { podSpec: { pod: 'hn-carousel', memoryCost: REAL_MEMORY_COST } });
|
|
412
|
+
const fq = path.join(Q.tmp, 'c.txt');
|
|
413
|
+
fs.writeFileSync(fq, 'Aprovado sem ressalvas.');
|
|
414
|
+
const rq = runCli(['--state', Q.statePath, '--workflow-file', Q.wfPath,
|
|
415
|
+
'--step', 'assembly', '--verdict', 'approve', '--file', fq]);
|
|
416
|
+
ok('memória folgada: NENHUM aviso de poda (contraprova do sinal)',
|
|
417
|
+
rq.status === 0 && !/AVISO/.test(rq.stderr), rq.stderr);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
421
|
+
// Robustez de uso (superfície que o gate ataca)
|
|
422
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
423
|
+
console.log('\n--- Robustez: veredito inválido, etapa inexistente, tier deliberado ---');
|
|
424
|
+
{
|
|
425
|
+
const S = tmpPod('robustez');
|
|
426
|
+
const f = path.join(S.tmp, 'c.txt');
|
|
427
|
+
fs.writeFileSync(f, 'Texto qualquer do dono.');
|
|
428
|
+
const base = ['--state', S.statePath, '--workflow-file', S.wfPath, '--file', f];
|
|
429
|
+
|
|
430
|
+
const rv = runCli([...base, '--step', 'assembly', '--verdict', 'aprovar']);
|
|
431
|
+
ok('veredito fora do enum é recusado (exit 2) e nada é gravado',
|
|
432
|
+
rv.status === 2 && countLines(S.podDir) === 0, `${rv.status} ${rv.stderr}`);
|
|
433
|
+
|
|
434
|
+
const rs = runCli([...base, '--step', 'inexistente', '--verdict', 'approve']);
|
|
435
|
+
ok('etapa que não existe no run é recusada (exit 2) e nada é gravado',
|
|
436
|
+
rs.status === 2 && countLines(S.podDir) === 0, `${rs.status} ${rs.stderr}`);
|
|
437
|
+
|
|
438
|
+
const rc = runCli([...base, '--step', 'assembly', '--verdict', 'approve', '--tier', 'critical']);
|
|
439
|
+
const recs = readRecords(S.podDir);
|
|
440
|
+
ok('--tier critical é ATO DELIBERADO e é aceito com attributed_by "human"',
|
|
441
|
+
rc.status === 0 && recs.length === 1 && recs[0].tier === 'critical' && recs[0].attributed_by === 'human',
|
|
442
|
+
`${rc.status} ${rc.stderr}`);
|
|
443
|
+
ok('sem --tier, o default é normal (critical nunca entra por engano)',
|
|
444
|
+
note.buildNoteEntry({ step: 'a', verdict: 'approve', message: 'x' }).tier === 'normal');
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
448
|
+
console.log(`\n${failures.length === 0 ? 'OK' : 'FALHA'} — ${passed} asserções passaram, ${failures.length} falharam`);
|
|
449
|
+
if (failures.length > 0) {
|
|
450
|
+
for (const f of failures) console.log(` - ${f}`);
|
|
451
|
+
process.exit(1);
|
|
452
|
+
}
|