@polymorphism-tech/morph-spec 8.33.0 → 8.35.0
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.
- package/CLAUDE.md +22 -2
- package/README.md +2 -2
- package/bin/morph-spec.js +43 -5
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +5 -4
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +2 -2
- package/framework/MORPH.md +20 -22
- package/framework/agents.json +198 -44
- package/framework/ai-pin.json +22 -0
- package/framework/commands/morph-media.md +45 -0
- package/framework/docs/CLI.md +238 -10
- package/framework/evals/proof-rubrics/README.md +76 -0
- package/framework/evals/proof-rubrics/eval-de-modelo.md +64 -0
- package/framework/evals/proof-rubrics/fiacao.md +54 -0
- package/framework/evals/proof-rubrics/guard-cego.md +52 -0
- package/framework/evals/proof-rubrics/media-claims.md +109 -0
- package/framework/evals/proof-rubrics/mutation-proof.md +77 -0
- package/framework/evals/proof-rubrics/observabilidade-genai.md +119 -0
- package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +48 -0
- package/framework/evals/rubrics/architecture.md +30 -0
- package/framework/evals/rubrics/code-quality.md +26 -0
- package/framework/evals/rubrics/test-coverage.md +20 -0
- package/framework/hooks/README.md +11 -1
- package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +5 -8
- package/framework/hooks/claude-code/core/block-raw-worktree-add.js +79 -0
- package/framework/hooks/claude-code/core/chain.js +27 -7
- package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
- package/framework/hooks/claude-code/core/worktree-context.js +83 -14
- package/framework/hooks/claude-code/core/worktree-create.js +206 -0
- package/framework/hooks/claude-code/core/worktree-env-inject.js +87 -0
- package/framework/hooks/claude-code/core/worktree-remove.js +81 -0
- package/framework/hooks/shared/command-tokens.js +23 -0
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/git-paths.js +25 -0
- package/framework/hooks/shared/hook-response.js +17 -0
- package/framework/hooks/shared/morph-cli.js +134 -0
- package/framework/rules/ai-agents-standards.md +14 -2
- package/framework/rules/infrastructure-standards.md +3 -1
- package/framework/schemas/ai-pin.schema.json +97 -0
- package/framework/schemas/config.schema.json +107 -0
- package/framework/schemas/feature.schema.json +23 -4
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +28 -7
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
- package/framework/skills/core/morph-implement/SKILL.md +20 -2
- package/framework/skills/core/morph-media/SKILL.md +215 -0
- package/framework/skills/core/morph-plan/SKILL.md +38 -4
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +166 -9
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/PROVENANCE.json +81 -3
- package/framework/standards/STANDARDS.json +1504 -830
- package/framework/standards/ai-agents/agent-archetypes.md +160 -0
- package/framework/standards/ai-agents/agent-session.md +256 -160
- package/framework/standards/ai-agents/agent-spec.md +196 -0
- package/framework/standards/ai-agents/batching.md +217 -193
- package/framework/standards/ai-agents/context-providers.md +261 -188
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
- package/framework/standards/ai-agents/cost-and-budget.md +256 -0
- package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
- package/framework/standards/ai-agents/evals-with-cache.md +289 -0
- package/framework/standards/ai-agents/guardrails.md +222 -0
- package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
- package/framework/standards/ai-agents/mcp-server.md +351 -250
- package/framework/standards/ai-agents/mcp-tools.md +250 -197
- package/framework/standards/ai-agents/media-pipeline.md +352 -0
- package/framework/standards/ai-agents/media-video.md +267 -0
- package/framework/standards/ai-agents/middleware-patterns.md +241 -207
- package/framework/standards/ai-agents/modalities-image-gen.md +422 -173
- package/framework/standards/ai-agents/modalities-speech-to-text.md +177 -171
- package/framework/standards/ai-agents/modalities-text-to-speech.md +189 -181
- package/framework/standards/ai-agents/modalities-vision.md +205 -201
- package/framework/standards/ai-agents/multi-agent-patterns.md +211 -155
- package/framework/standards/ai-agents/observability-patterns.md +227 -17
- package/framework/standards/ai-agents/production.md +260 -231
- package/framework/standards/ai-agents/prompt-sources.md +389 -0
- package/framework/standards/ai-agents/providers/model-registry.md +293 -158
- package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
- package/framework/standards/ai-agents/service-tier-flex.md +143 -135
- package/framework/standards/ai-agents/setup.md +166 -50
- package/framework/standards/ai-agents/structured-output.md +280 -249
- package/framework/standards/ai-agents/sweet-spot.md +129 -109
- package/framework/standards/ai-agents/testing-ai.md +236 -0
- package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
- package/framework/standards/ai-agents/workflows.md +27 -7
- package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
- package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
- package/framework/standards/infrastructure/docker/local-compose-isolation.md +90 -0
- package/framework/templates/REGISTRY.json +14 -1
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
- package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
- package/framework/templates/dotnet/ai-kit/Directory.Build.props +25 -0
- package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
- package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
- package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
- package/framework/templates/dotnet/ai-kit/README.md +128 -0
- package/framework/templates/dotnet/ai-kit/global.json +9 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
- package/framework/templates/infrastructure/docker/docker-compose.template.yml +24 -14
- package/package.json +3 -3
- package/src/commands/e2e/e2e.js +91 -40
- package/src/commands/project/doctor.js +143 -6
- package/src/commands/project/env.js +95 -0
- package/src/commands/project/update.js +469 -153
- package/src/commands/project/worktree.js +274 -53
- package/src/commands/state/advance.js +24 -2
- package/src/commands/state/approve.js +33 -1
- package/src/commands/state/create.js +72 -11
- package/src/commands/state/delete.js +8 -0
- package/src/commands/state/finish.js +360 -53
- package/src/commands/state/gate-check.js +190 -6
- package/src/commands/state/score.js +36 -1
- package/src/commands/validation/verify.js +134 -25
- package/src/core/state/state-manager.js +9 -1
- package/src/dashboard/app/pages/HookInspector.jsx +430 -418
- package/src/dashboard/scanner/hooks-scanner.js +5 -1
- package/src/lib/ai/ai-checks.js +182 -0
- package/src/lib/ai/ai-project-scan.js +347 -0
- package/src/lib/ai/code-audit.js +181 -0
- package/src/lib/ai/comment-stripper.js +184 -0
- package/src/lib/ai/pin-drift.js +138 -0
- package/src/lib/ai/registry-audit.js +285 -0
- package/src/lib/e2e/compose-env.js +55 -14
- package/src/lib/e2e/stack-teardown.js +115 -0
- package/src/lib/evaluator-report.js +269 -15
- package/src/lib/generators/architecture-scanner.js +2 -1
- package/src/lib/git/default-branch.js +92 -4
- package/src/lib/graph/graphifyignore.js +2 -1
- package/src/lib/installers/effects.js +193 -0
- package/src/lib/installers/templates-reconcile.js +3 -3
- package/src/lib/risk-detector.js +284 -0
- package/src/lib/standards/verified-against.js +276 -0
- package/src/lib/tasks/eval-node.js +485 -0
- package/src/lib/tasks/linux-runner.js +297 -0
- package/src/lib/tasks/test-nodes.js +486 -0
- package/src/lib/tasks/test-runner.js +431 -37
- package/src/lib/validators/verify-runner.js +590 -28
- package/src/lib/worktree/dirs.js +32 -0
- package/src/lib/worktree/docker-audit.js +287 -0
- package/src/lib/worktree/env-allocator.js +69 -11
- package/src/lib/worktree/worktree-audit.js +70 -3
- package/src/scripts/setup-infra.js +24 -11
- package/src/utils/agents-installer.js +18 -8
- package/src/utils/claude-md-injector.js +10 -5
- package/src/utils/file-copier.js +28 -16
- package/src/utils/hooks-installer.js +75 -29
- package/src/utils/skills-installer.js +194 -187
- package/src/utils/version-checker.js +68 -3
- package/framework/standards/ai-agents/prompts-in-db.md +0 -214
package/CLAUDE.md
CHANGED
|
@@ -107,13 +107,20 @@ When modifying framework components, verify the full scope of related files.
|
|
|
107
107
|
| When you modify... | Also verify... |
|
|
108
108
|
|----------------------------------|-------------------------------------------------------------------------------------------|
|
|
109
109
|
| `framework/agents.json` | agents-installer.js (test/utils/agents-installer.test.js), doctor.js (REQUIRED_AGENTS) |
|
|
110
|
-
| `framework/standards/**` | STANDARDS.json entry exists, agents reference standard, .md file exists
|
|
110
|
+
| `framework/standards/**` | STANDARDS.json entry exists (o **digest** e o que `standards --find` devolve — corrigir a prosa e esquecer o digest e o caso mais comum), agents reference standard, .md file exists. **Bloco de codigo `csharp` num standard e afirmacao verificavel:** extraia com `node scripts/extract-doc-csharp.mjs <std.md> "## Secao" out.cs` e compile numa sonda com o pin + `TreatWarningsAsErrors` (sem ele `MEAI001` vira aviso e o build fica verde sobre codigo que o consumidor nao compila). Medido: um exemplo carimbado sem compilar tinha 3 erros independentes |
|
|
111
|
+
| `scripts/generate-standards-registry.js` | `framework/standards/STANDARDS.json` (REGENERE, nunca patch textual — tres features escrevem no mesmo arquivo), `src/lib/standards/verified-against.js` (`parseVerifiedAgainst`/`deriveProvedBy`: `verifiedAgainst` e `provedBy` sao DERIVADOS a cada run e NAO entram em `PRESERVE_FIELDS`), `test/framework/standards-registry.test.js`. **Renomear um standard e uma PARADA, nao um exit 0**: path sumido + path novo faz o gerador recusar nomeando os dois conjuntos e prescrevendo a edicao do campo `path` da entrada antiga — ele nao adivinha o par. `MORPH_STANDARDS_BASE` e o unico seam de teste do script e nada em producao o define |
|
|
111
112
|
| `framework/hooks/claude-code/**` | hooks-installer.js MORPH_HOOKS array, hook follows fail-open pattern |
|
|
112
113
|
| `framework/skills/core/**` | MORPH.md skills table, skills-installer.js, SKILL.md frontmatter |
|
|
113
114
|
| `framework/phases.json` | output-schema.js (phase mappings), test/framework/phases.test.js |
|
|
114
115
|
| `framework/templates/**` | REGISTRY.json (template registered), valid Handlebars helpers |
|
|
116
|
+
| `framework/templates/REGISTRY.json` (o campo `kind`) | os QUATRO checks de `scripts/validate-framework.js` que leem `kind`/`path`: **4** (resolve arquivo × diretório), **9** (shape exigido por kind), **10** (só lê `path` que é ARQUIVO — `readFileSync` num diretório derruba o validador inteiro com EISDIR, não vira erro de validação) e **12** (cobertura por prefixo; projeto registrado sem arquivo rastreado é erro). `test/framework/validate-framework-registry.test.js` cobra os quatro |
|
|
117
|
+
| `framework/ai-pin.json` | `scripts/generate-ai-pin-props.js` (gera `Directory.Packages.props` e `global.json` do ai-kit; `--check` roda dentro de `npm run generate:check`), `src/lib/standards/verified-against.js` (idade contra o pin), `framework/schemas/ai-pin.schema.json`, `test/framework/ai-pin.test.js`. Subir uma versao aqui sem regenerar deixa `npm run verify` vermelho -- e esse e o ponto |
|
|
118
|
+
| `framework/templates/dotnet/ai-kit/**` (o projeto .NET) | `REGISTRY.json` (a entrada `ai-kit`, `kind: "project"` — sem ela o Check 12 cobra arquivo por arquivo; com ela apontando para diretorio vazio/inexistente o validate tambem reprova), o **`.gitignore` ANINHADO em `ai-kit/`** (unico jeito de manter `bin/`/`obj/` fora do tarball: `package.json` `files` lista `framework/`, e o npm NAO deixa o `.npmignore` da RAIZ excluir nada sob um diretorio de `files` — medido, 220 arquivos vazavam), `Directory.Packages.props` + `global.json` (GERADOS de `framework/ai-pin.json`, nunca editados a mao) e o job `ai-kit` do CI (T15). O `global.json` carrega `test.runner` porque no SDK .NET 10 `dotnet test` recusa um projeto Microsoft.Testing.Platform (xunit.v3 4.x) sem esse opt-in, e global.json e o unico arquivo de onde o SDK o le. Mexeu em `PackageReference` do `Morph.AiKit.csproj`? `test/framework/ai-kit-package-coverage.test.js` exige que cada pacote esteja OU exercitado por um `using` real em `src/` OU listado na constante `RESTORE_ONLY` do teste (contrato de versao, regua = restore/NU1102) — e a mesma classificacao aparece na tabela de garantias do `README.md` do kit e na Errata E10 do `spec.md`. Desde `src/Morph.AiKit/Media/`, so **um** dos cinco pacotes do pin (`ModelContextProtocol`) segue sem cobertura de compilacao: `OpenAI` e `Google.GenAI` subiram para compilacao quando os adaptadores de midia passaram a usa-los (`using OpenAI.Images;` / `using Google.GenAI.Types;`), e o proprio canario apontou a mudanca ficando vermelho sobre `RESTORE_ONLY`. Mexer no `Media/` que remova esses `using` derruba a garantia de volta |
|
|
119
|
+
| `.github/workflows/*.yml` (o job `ai-kit`) | os DOIS workflows carregam o MESMO job — `ci.yml` (toda PR) e `release.yml`, onde `publish` declara `needs: [test, ai-kit]` e continua **sem matrix** (matrix no job que publica roda `npm publish` 1x por OS). Tres detalhes sao load-bearing: `working-directory: framework/templates/dotnet/ai-kit` (o `dotnet test` resolve o `global.json` pelo CWD, nunca pelo `.sln` do argumento — da raiz ele FALHA, enquanto o `dotnet build` funciona, que e o que torna a armadilha facil), `global-json-file` em vez de `dotnet-version` (a banda do SDK vem do pin, nunca digitada no YAML) e o passo `generate-ai-pin-props.js --check` antes do restore (sem ele o job compila props dessincronizadas do pin e reporta verde). `test/framework/ai-kit-ci-packaging.test.js` cobra a forma do job E mede o tarball |
|
|
120
|
+
| `src/lib/standards/verified-against.js` | os leitores do MESMO fato "quao velho e este standard": `scripts/check-freshness.js` (hard fail por `Last-verified`), `test/framework/standard-header.test.js` (campos obrigatorios no header) e `framework/ai-pin.json` (a data de referencia). Uma segunda copia do regex e como o contador de `// VERIFY:` ficou inerte: `/^\s*\/\/\s*VERIFY:/` exigia inicio de linha e dois-pontos e enxergava 0 de 10 marcadores reais. **`deriveProvedBy` mora aqui pela mesma razao**, e o quarto leitor e `scripts/generate-standards-registry.js`, que DERIVA `verifiedAgainst`/`provedBy` a cada run — **TRES** tipografias da clausula sao reais no acervo e a regua e a SOMA de paths (27 em 16 entradas), nunca a contagem de entradas: a crase abre DEPOIS de "provado por", ANTES dela, e a clausula tambem aparece em negrito no MEIO da frase (`**provado por**`). Ignorar a segunda perdia 4 das 16 provas; ignorar a terceira perdia 2 paths de `llm-runtime-defaults` **sem mover contador nenhum** — a entrada seguia entre as 16 e o exit era 0. Por isso `test/framework/standards-registry.test.js` pina os paths ESCRITOS A MAO, e nunca chama `deriveProvedBy` para gerar a expectativa do acervo real |
|
|
115
121
|
| `src/core/paths/output-schema.js`| Run `npm run generate` to update phase-utils.js |
|
|
116
|
-
| `framework/MORPH.md` | All core skills (cross-references), CLAUDE.md (slash command list)
|
|
122
|
+
| `framework/MORPH.md` | All core skills (cross-references), CLAUDE.md (slash command list), e o **teto de 38 400 chars** (`test/framework/resident-size.test.js`). MORPH.md vive colado no teto: linha nova ali só entra liberando pelo menos o mesmo número de caracteres **na mesma seção**, com o antes/depois medido — `MORPH_MD_LIMIT` não sobe |
|
|
123
|
+
| a divisão loop × suíte (`verify --filter`) | os QUATRO textos que a declaram e não podem discordar: `framework/docs/CLI.md` (seção "Suítes de teste" — a tabela canônica + a forma de `project.tests[]`), `morph-implement` §9, `morph-apply` §3a (o `verify` do loop) e `morph-review` (o Gate 3 roda **sem** filtro). Uma superfície que ensine filtrar no Gate 3 devolve o F30 pela porta da frente; canário: `test/framework/verify-stack-docs-prose.test.js` |
|
|
117
124
|
| `src/lib/worktree/ignored-triage.js` | `worktree.js` (`classifyIgnoredLeftovers`), `test/lib/worktree/ignored-triage.test.js`, e os canários de `test/commands/finish.test.js` que pinam "o exemplar único nunca morre" — mudar um bucket muda o que o `finish` apaga |
|
|
118
125
|
| `src/lib/git/pr-index.js` | os QUATRO leitores do mesmo fato "esta branch tem PR": `fleet-scanner.js` (coluna PR), `branch-classifier.js` (o que NÃO apagar), `worktree-audit.js` (o que NÃO sugerir remover) e `pending-prs.js` (a síntese "aguardando merge"). `null` é UNKNOWN, nunca "sem PR" |
|
|
119
126
|
| `src/lib/git/branch-classifier.js` | `src/commands/project/branch.js`, `worktree-audit.js` (`unintegratedWork` reusa `classifyBranch` — o `doctor` e o `branch prune` não podem discordar sobre a mesma branch), `test/commands/branch-prune.test.js`, e `lifecycle-audit.js` (`abandoned-scaffold` conta commit próprio pelo mesmo `resolveBaseRef` + `commitsAhead`) |
|
|
@@ -121,11 +128,24 @@ When modifying framework components, verify the full scope of related files.
|
|
|
121
128
|
| `src/lib/git/gh.js` | `pr-index.js` e `finish.js` — as DUAS formas de invocar o `gh` viraram uma; uma segunda cópia de `resolveGh` volta a tornar o caminho de sucesso do índice intestável |
|
|
122
129
|
| `src/lib/worktree/feature-truth.js` | The four leaders reading the same "which tree owns this feature" predicate: `fleet-scanner.js`, `list.js`, `handoff.js`, and the mutator guard (`approve.js`/`advance.js`/`score.js`/`gate-decision.js`/`gate-check.js`) |
|
|
123
130
|
| `src/lib/tasks/test-runner.js` | `verify-runner.js` (o nó `tests` repassa o `--timeout` e lê `timedOut`), `src/commands/project/worktree.js` (as constantes `WORKTREES_DIR`/`LEGACY_WORKTREES_DIR` que a descoberta ignora — duplicar as strings aqui é como o bug volta), `test/lib/test-runner.test.js` (o canário do ignore de worktrees e o do timeout escalado). Um worktree é o checkout de OUTRA feature: varrê-lo dobra o relógio e reporta sobre código fora da árvore avaliada |
|
|
131
|
+
| `src/lib/tasks/linux-runner.js` | `verify-runner.js` (`runNodesInLinux` faz as MESMAS pré-decisões do laço local e julga o resultado pelo MESMO `judgeRun` — uma segunda cópia dessa regra é como container e host passam a discordar da mesma suíte), `framework/hooks/shared/e2e-check.js` (`defaultExec`/`isDockerAvailable` são reusados, nunca recriados), `src/lib/worktree/dirs.js` (nomes do contêiner de worktree nas exclusões do `tar`), `framework/schemas/config.schema.json` (`linuxImage`) e `test/lib/tasks/linux-runner.test.js` (o canário do bind mount: montar a árvore em `/work` é v9fs case-insensitive e não reproduz F35) |
|
|
132
|
+
| `--record-baseline` (`recordTestBaselines` em `src/lib/tasks/test-nodes.js`) | `verify-runner.js` (`baselineTargetProblem` recusa ANTES do build; `recordBaselineFrom` só grava com todos os `runs[]` verdes), `src/commands/validation/verify.js` (não persiste stamp: é manutenção de config, não prova de gate), `framework/schemas/config.schema.json` (`expectedCount`) e `atomicWriteJson` de `state-manager.js` — o número é MEDIDO por comando, nunca digitado (D8) |
|
|
133
|
+
| `src/lib/tasks/eval-node.js` | os leitores do MESMO nó `runner: "evals"`: `test-nodes.js` (o enum de `TEST_RUNNERS` e a validação fail-closed do bloco `evals`), `verify-runner.js` (`preDecideRun` faz o pré-voo — os três estados de cache reprovam ANTES de `dotnet test`; `judgeEvalRun` lê o sumário depois), `verify.js` (`evalsStatusOf` deriva `nodes.evals` do stamp) e `framework/schemas/config.schema.json`. O pin tem UM leitor (`readAiPin`), chamado com duas raízes (`framework/` e `.morph/framework/`) — um segundo parser de `ai-pin.json` é como as duas verdades começam. **`null` é DESCONHECIDO, nunca 0**: sumário ilegível não pode fabricar queda contra `expectedCount`, e miss de cache é `fail` nomeado, JAMAIS `skip`. `--linux` com nó de eval é erro de uso: o canal `MORPH_EVAL_*` carrega caminhos absolutos do host e o container roda uma cópia em `/work` |
|
|
134
|
+
| `nodeStatuses()` em `src/commands/validation/verify.js` | os TRÊS blocos `nodes` de `framework/schemas/feature.schema.json`, todos `additionalProperties: false` — `verification.nodes`, `verifications.feature.nodes` e `taskVerifications.*.nodes`. A função é escritora ÚNICA dos três: um campo novo aqui sem os três no schema faz o histórico violar o próprio contrato. Canário: "os DOIS escritores do mapa de nós concordam" em `test/commands/verify.test.js` |
|
|
124
135
|
| `src/lib/graph/**` | `test/lib/graph/*.test.js`, the committed fixture `test/fixtures/graph/namespace-hierarchy.graph.json` (ADR-003 regression — never hand-edit it), `doctor.js` (`codebase graph` check), `architecture-scanner.js` (centrality section), `setup-infra.js` step 18b |
|
|
125
136
|
| `src/lib/validators/reuse/**` | `validation-runner.js` (case + push universal), `framework/rubrics/*.json` (o id `reuse` mapeado numa categoria, senão o achado não pesa no score), `test/fixtures/graph/prospectpro-reuse.graph.json` (recorte do grafo real — regerar com `build-reuse-fixture.mjs`, nunca editar à mão) |
|
|
126
137
|
| o ciclo de reuso (`reuse-map.md`) | `output-schema.js` (+ `npm run generate`), `framework/schemas/tasks.schema.json` + `tasks-json-parser.js` (campo `reuse`), `morph-plan` §1c/§5b, template de dispatch de `morph-implement`/`morph-apply`, personas de `agents.json`, `evals/rubrics/code-quality.md` + `condensed.md`, `morph-review` (insumo do avaliador), `test/framework/graph-fallback.test.js` |
|
|
127
138
|
| `framework/mcp/registry.json` | mcp-installer.js, claude-config-detector.js, agents-installer.js (personas' `mcp` field), `scripts/validate-framework.js` Check 8, `test/framework/mcp-registry.test.js` |
|
|
128
139
|
| Any `framework/` file that calls `morph-spec graph` | The fallback to grep must be declared in the SAME file — `test/framework/graph-fallback.test.js` enforces it (ADR-002: a skill that requires the graph with no fallback is a bug) |
|
|
140
|
+
| `framework/hooks/claude-code/core/worktree-create.js` / `worktree-remove.js` / `block-raw-worktree-add.js` / `worktree-env-inject.js` | `hooks-installer.js` (`MORPH_HOOKS`: eventos `WorktreeCreate`/`WorktreeRemove` + a ORDEM da chain Bash — inject por último, um comando bloqueado nunca é reescrito), `hooks-scanner.js` `EVENT_KEYS`, `chain.js` (`updatedInput` só viaja com rewrite — `permissionDecision:'allow'` incondicional pularia o prompt de todo Bash), `worktree.js` (`runWorktreeProvision`, `--if-clean`, `envKeyForWorktree`), `worktree-audit.js` (`morph-task/*`, `out-of-container`), `worktree-context.js`, MORPH.md §2.2, `morph-apply` §3b-w, `test/framework/worktree-governance-prose.test.js`, `resident-size.test.js` (MORPH.md está NO teto) |
|
|
141
|
+
| `src/lib/worktree/env-allocator.js` (`portLayout`) | os DOIS escritores do bloco — `buildEnvFileContent` (`.morph/worktree.env`) e `compose-env.js` (`buildComposeEnv`, usado por `e2e up`, pelo nó `e2e` do `verify`, por `stack-teardown.js` e por `morph-spec env`) — e os leitores `worktree-context.js`, `handoff-generator.js`, `worktree-env-inject.js`, o template `docker-compose.template.yml` (variáveis que ele publica) e o standard `local-compose-isolation.md` (tabela de offsets). Canário: "worktree.env e compose env concordam byte a byte" em `test/lib/e2e/compose-env.test.js`. Offset novo aqui sem entrar no template é porta que ninguém publica |
|
|
142
|
+
| `src/lib/tasks/test-nodes.js` | os DOIS leitores de `validateTestNodes` — `verify-runner.js` (fail-closed: nó inválido avermelha o gate) e `doctor.js` (`doctor --full`, camada 3 do contrato do spec §2.2: WARN, e **pula sem imprimir nada** sem `config.json` ou sem `project.tests`, senão quebra `test/commands/doctor.test.js:46`). Uma segunda noção de "nó válido" faz o mesmo config passar num lugar e falhar no outro. `morphConfigPath` deriva de `CONFIG_FILE_NAME` (`core/state/state-manager.js`), a mesma constante de `readMorphConfig` — o JSDoc promete "one spelling" e agora é literal |
|
|
143
|
+
| `src/lib/worktree/docker-audit.js` | `worktree-audit.js` (`auditWorktrees` concatena os achados e é quem PASSA as features conhecidas — um segundo scan aqui discordaria sobre o que é órfão), `doctor.js` (a classificação `info`/`warn` = não-falha em `doctorWorktreesCommand`), `env-allocator.js` (`allocatedFeatures` é read-only de propósito: `allocateEnvBlock` ESCREVE, e uma auditoria que aloca inventa o estado que reporta), `test/lib/worktree/docker-audit.test.js`. Nunca no `doctor --full` (D10): `test/commands/doctor.test.js:46` exige zero `✗` neste repo |
|
|
144
|
+
| `src/lib/risk-detector.js` | os DOIS lados da mesma decisão de gate: `gate-check.js` (`collectSignals` COLETA do disco; nenhum sinal que descreva um FATO pode entrar em `OVERRIDABLE_SIGNAL_KEYS` — `gate`/`workType`/`e2e*` são o precedente), `src/commands/validation/verify.js` (o stamp `verification` é a ÚNICA coisa que o gate lê: campo novo aqui só vira sinal se o stamp o gravar), `framework/schemas/feature.schema.json` (`verification` é `additionalProperties: false`), `framework/MORPH.md` §5 (tabela de sinais — ela se declara fonte única) e `framework/docs/CLI.md`. Política escrita no coletor cria duas fontes para o mesmo fato — foi assim que `gate-check` e `approve` divergiram uma vez sobre o score do Gate 3. **`verificationScope` é sinal, não auditoria**: a dispensa de e2e (`project`/`scope`) só conta vinda de um stamp de escopo `feature` — um `verify {f} {task}` de task `group: docs` carimba a razão de dispensa e compraria o Gate 3 da feature inteira |
|
|
145
|
+
| `src/lib/installers/effects.js` | os NOVE pontos de emissão que atravessam o caminho de `update`: `update.js` (clean, payloads, spawn de `generate-refs.js`, `gitIndex`), `skills-installer.js`, `agents-installer.js`, `setup-infra.js` (`installRulesForStack`, `updateClaudeMdAgentsBlock`), `hooks-installer.js` (`installClaudeHooks`, `installGlobalStatusline`), `file-copier.js` (`updateGitignore`, `ensureGitattributes`), `claude-md-injector.js`, `version-checker.js` (`saveProjectMorphVersion`) e `templates-reconcile.js`. **O caminho real também emite** — o resumo de uma execução real sai de `list()`, e é por isso que um ponto de emissão esquecido some das DUAS saídas ao mesmo tempo. Canários: `test/lib/installers/effects.test.js` (igualdade dry × real do MESMO roteiro) e `test/commands/update-dry-run.test.js` — que tem DOIS canários e precisa dos dois: **igualdade** prova que os dois lados percorrem o mesmo caminho, **diferencial** (mudar `--templates` muda a previsão) prova que o caminho lê a flag. Só igualdade aprova uma previsão e uma execução que ignoram a MESMA flag — foi medido nesta feature, por mutação. Um laço de limpeza de órfão novo tem de nascer calado em `fx.dryRun` (D6): o clean o subsome. E a lista de `frameworkDirsToClean` é pinada **à mão** no teste (`DIRETORIOS_APAGADOS_POR_INTEIRO`, dez caminhos, `deepEqual` ordenado): derivar a expectativa chamando a própria função deixou a suíte inteira cega — medido, dava para remover 2 das 10 entradas sem matar nenhum dos 207 arquivos de teste |
|
|
146
|
+
| `src/lib/ai/**` (`doctor --ai`) | `src/commands/project/doctor.js` (`doctorAiCommand` + a guarda de uso indevido), `bin/morph-spec.js` (`--ai`), `framework/docs/CLI.md`. **`--ai` NUNCA entra no `doctor --full` nem no default** — o renderer do `--full` manda tudo que não é `ok`/`warn` para `✗` e `test/commands/doctor.test.js` exige zero `✗` neste repositório. **Nada alcançável por `--ai` pode escrever**: `test/commands/doctor-ai.test.js` varre o grafo de imports E o corpo de `doctorAiCommand` (com os imports dinâmicos fixados nos dois permitidos), reprovando `writeFileSync`/`spawn`/`fs-extra` em CÓDIGO — comentários apagados antes, porque os módulos EXPLICAM por escrito que não fazem isso e medir a menção seria medir uma cópia do objeto. `null` é DESCONHECIDO e vira `skip` **com razão obrigatória**; `[]` é "perguntei e não achei" e vira `ok` |
|
|
147
|
+
| `src/lib/ai/registry-audit.js` | o leitor de PRODUÇÃO do mesmo documento: `framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs` (`CommentHandling = Skip`, `AllowTrailingCommas`, `AllowedAliasProperties` com `pricing`/`pricingWaiver`) e o exemplar `model-registry.v2.json` que o framework manda COPIAR. A auditoria tem de enxergar a **mesma forma** que o leitor de produção enxerga: com `JSON.parse` estrito, duas das cinco checagens saíam `skip` sobre o exemplar canônico — e `skip` não muda exit code, então o silêncio era total. A tolerância a JSONC vive em `src/lib/ai/comment-stripper.js`, ÚNICA (o `code-audit.js` usa o mesmo varredor) — e a paridade é nos DOIS sentidos: `jsoncToJson` **lança** no comentário de bloco não fechado, porque o `JsonCommentHandling.Skip` do .NET lança, e ser mais frouxo que o kit é aprovar documento que a app recusa carregar. Ao mascarar strings, **as aspas delimitadoras ficam**: apagá-las junto faz um elemento-string virar espaço puro e o detector de vírgula sobrando comer um SEPARADOR real (`{"tags":["a","b"]}` saía inválido). Canário obrigatório: array terminado em **string**, com e sem vírgula sobrando — uma suíte só com arrays de número passa dos dois lados dessa inversão. A **REGRA DURA** do exemplar — *todo alias declara `pricing` OU `pricingWaiver`, nunca os dois, nunca nenhum* — é do alias, não de um mapa no topo: ler só o mapa dava 6 falsos positivos sobre um documento correto. O canário **copia o exemplar do disco**, nunca uma paráfrase dele |
|
|
148
|
+
| `src/lib/worktree/dirs.js` | ÚNICA fonte do nome do container (`worktrees/`, sem ponto — Jest esconde diretório com ponto e reporta 0 testes sem erro). `worktree.js` re-exporta; `graphifyignore.js`, `file-copier.js`, `architecture-scanner.js`, `test-runner.js`, `worktree-audit.js`, `state-scanner.js`, `tasks/linux-runner.js` (exclusões do `tar` do `--linux`) importam. `test/lib/worktree/dirs.test.js` cobra cada leitor |
|
|
129
149
|
|
|
130
150
|
### Test Coverage
|
|
131
151
|
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> Spec-driven development framework for multi-stack projects. Turns feature requests into implementation-ready code through structured, AI-orchestrated phases.
|
|
4
4
|
|
|
5
5
|
**Package:** `@polymorphism-tech/morph-spec`
|
|
6
|
-
**Version:** 8.
|
|
6
|
+
**Version:** 8.35.0
|
|
7
7
|
**Requires:** Node.js 22+, Claude Code
|
|
8
8
|
|
|
9
9
|
---
|
|
@@ -379,4 +379,4 @@ Code generated by morph-spec (contracts, templates, implementation output) belon
|
|
|
379
379
|
|
|
380
380
|
---
|
|
381
381
|
|
|
382
|
-
*morph-spec v8.
|
|
382
|
+
*morph-spec v8.35.0 by [Polymorphism Tech](https://polymorphism.tech)*
|
package/bin/morph-spec.js
CHANGED
|
@@ -23,9 +23,10 @@ import { installPluginCommand } from '../src/commands/project/install-plugin-cmd
|
|
|
23
23
|
import { updateCommand } from '../src/commands/project/update.js';
|
|
24
24
|
import { doctorCommand } from '../src/commands/project/doctor.js';
|
|
25
25
|
import { statusCommand } from '../src/commands/project/status.js';
|
|
26
|
-
import { worktreeSetupCommand, worktreeLinkCommand, worktreeListCommand, worktreeRemoveCommand } from '../src/commands/project/worktree.js';
|
|
26
|
+
import { worktreeSetupCommand, worktreeProvisionCommand, worktreeLinkCommand, worktreeListCommand, worktreeRemoveCommand } from '../src/commands/project/worktree.js';
|
|
27
27
|
import { branchPruneCommand } from '../src/commands/project/branch.js';
|
|
28
28
|
import { fleetCommand } from '../src/commands/project/fleet.js';
|
|
29
|
+
import { envCommand } from '../src/commands/project/env.js';
|
|
29
30
|
import { claimCommand } from '../src/commands/project/claim.js';
|
|
30
31
|
import { standardsCommand } from '../src/commands/project/standards.js';
|
|
31
32
|
import { reportCheckCommand } from '../src/commands/state/report-check.js';
|
|
@@ -125,6 +126,8 @@ program
|
|
|
125
126
|
.description('Update MORPH templates and standards to latest version')
|
|
126
127
|
.option('--templates', 'Update only templates')
|
|
127
128
|
.option('--standards', 'Update only standards')
|
|
129
|
+
.option('--dry-run', 'Prever os efeitos sem escrever, apagar ou executar nada — inclui o que acontece fora do projeto e dentro do pacote da CLI')
|
|
130
|
+
.option('--force', 'Dispensar o freio de salto de major (2+ majors), registrando a dispensa no relatório')
|
|
128
131
|
.action(updateCommand);
|
|
129
132
|
|
|
130
133
|
program
|
|
@@ -132,6 +135,7 @@ program
|
|
|
132
135
|
.description('Check MORPH installation health')
|
|
133
136
|
.option('--full', 'Run full health check')
|
|
134
137
|
.option('--mcp', 'Check MCP server configuration')
|
|
138
|
+
.option('--ai', 'Auditar um projeto .NET com agentes: pin × projeto, API renomeada, tarifa e `api` por alias, prompt sem fonte')
|
|
135
139
|
.option('--worktrees', "Reconcile git's worktree registry × the directories on disk × known features")
|
|
136
140
|
.option('--prune', "With --worktrees: drop git records for worktree directories that are already gone, and clear any feature's root worktree registration pointing at one of them")
|
|
137
141
|
.option('--json', 'With --worktrees: output as JSON')
|
|
@@ -188,9 +192,12 @@ program
|
|
|
188
192
|
.description('Close a feature: archive → integrate. --merge merges morph/{f} into the default (local); --pr pushes it + opens a PR. Works with and without a worktree')
|
|
189
193
|
.option('--pr', 'Push morph/{feature} and open a PR against the default branch (no local merge)')
|
|
190
194
|
.option('--merge', 'Merge morph/{feature} into the default branch locally (no push)')
|
|
195
|
+
.option('--push', 'With --merge only: publish the default branch to origin right after the merge (without it, finish only reports how many commits are ahead and the push command). REFUSED with --pr (exit 1): --pr already publishes the feature branch and has no local merge to publish')
|
|
191
196
|
.option('--keep', 'Keep the worktree/branch after integrating (worktree flow only)')
|
|
197
|
+
.option('--keep-volumes', 'Keep the e2e stack\'s named volumes (e.g. a seeded database) instead of reclaiming them with the containers')
|
|
192
198
|
.option('--force', 'Skip the Gate-3-approved precondition')
|
|
193
199
|
.option('--discard-ignored', 'Allow removing the worktree even though it holds gitignored files that exist nowhere else (e.g. .env) — they are destroyed')
|
|
200
|
+
.option('--dry-run', 'PRE-FLIGHT: explain what this finish would archive, back up, discard and remove — and whether the default branch advanced since the feature branched — WITHOUT mutating anything (no commit, no archive, no worktree removal, no gh call, no git fetch). Exits 0 even from inside the worktree, reporting that as a warning')
|
|
194
201
|
.action((feature, options) => finishCommand(feature, options));
|
|
195
202
|
|
|
196
203
|
program
|
|
@@ -247,12 +254,16 @@ program
|
|
|
247
254
|
.option('--request <text>', 'Free-text request classified by the deterministic detector; tie/none exits 2 with candidates for an LLM/user decision (feature NOT created)')
|
|
248
255
|
.option('--detect-source <source>', 'workTypeDetection.source recorded when --type is explicit: deterministic|llm|user (default: user)')
|
|
249
256
|
.option('--worktree', 'Create the feature already inside its own git worktree (branch morph/{feature}) — fails open outside a git repo')
|
|
257
|
+
.option('--no-checkout', 'Create the branch morph/{feature} WITHOUT moving this checkout to it (default: the working tree switches, and says so). The branch is created either way, so finish --pr|--merge stays symmetric. REFUSED with --worktree (exit 1): the worktree flow never moves this checkout, so the flag would be inert')
|
|
250
258
|
.option('--json', 'Output as JSON')
|
|
251
259
|
.action((feature, options) => createCommand(feature, options));
|
|
252
260
|
|
|
253
261
|
program
|
|
254
|
-
|
|
255
|
-
|
|
262
|
+
// `[score]` is declared optional ONLY so a missing value reaches scoreCommand and gets
|
|
263
|
+
// a message that names the argument and the positional order, instead of Commander's
|
|
264
|
+
// raw "missing required argument". The value stays required — a blank one is refused.
|
|
265
|
+
.command('score <feature> <task> [score]')
|
|
266
|
+
.description('Record a task eval score in feature.json (taskScores, server-side timestamp) — <task> must match T<n> and <score> must be a number in 0-10; a blank/missing score is refused, never recorded as 0')
|
|
256
267
|
.option('--dims <dims...>', 'Four dimension scores in order a,c,q,t (architecture,contracts,code-quality,test-coverage) — comma- or space-separated; quote under PowerShell: --dims "9.5,9,9,9"')
|
|
257
268
|
.option('--json', 'Output as JSON')
|
|
258
269
|
.action((feature, task, score, options) => scoreCommand(feature, task, score, options));
|
|
@@ -366,10 +377,15 @@ program
|
|
|
366
377
|
.option('--json', 'Output as JSON')
|
|
367
378
|
.option('--rubric <id>', 'Force a rubric (default: by task group → config → default)')
|
|
368
379
|
.option('--timeout <ms>', 'Timeout in ms for the build AND tests nodes (build default 120000; tests default 120000 per test project, or project.testTimeoutMs)', (v) => parseInt(v, 10))
|
|
380
|
+
.option('--filter <ids>', 'Run only the test nodes whose id matches (comma-separated; exact or substring). Unmatched nodes are reported as skip; matching nothing is a usage error (exit 2)')
|
|
381
|
+
.option('--linux', 'Run the test nodes inside a Linux container, on a COPY of the tree (the host tree is mounted read-only and copied in — a bind mount is case-insensitive and cannot reproduce case defects). No Docker = usage error, never a skip')
|
|
382
|
+
.option('--linux-image <img>', 'Image used by --linux (default: mcr.microsoft.com/dotnet/sdk:10.0)')
|
|
383
|
+
.option('--record-baseline', 'Measure every test node and write expectedCount back into .morph/config/config.json (only from an all-green run; never creates config.json)')
|
|
384
|
+
.option('--refresh-cache', 'Rewrite the response cache of every `runner: "evals"` node against the real provider. NEVER implicit: a cache rewrite is a paid call nobody asked for. Requires the declared envFile; no eval node declared, --skip-tests, or a --filter that excludes them all are usage errors (exit 2), refused BEFORE the cache is touched')
|
|
369
385
|
.option('--skip-tests', 'Skip the test node')
|
|
370
386
|
.option('--skip-build', 'Skip the build node')
|
|
371
387
|
.option('--skip-e2e', 'Skip the e2e node (Docker bring-up + Playwright)')
|
|
372
|
-
.option('--fresh-e2e', '
|
|
388
|
+
.option('--fresh-e2e', 'Recreate the e2e stack from scratch: down -v (named volumes included), drop the freshness stamp, rebuild, re-seed auth')
|
|
373
389
|
.option('--no-persist', 'Do not persist the result to feature.json')
|
|
374
390
|
.action((feature, task, options) =>
|
|
375
391
|
verifyCommand(feature, task, { ...options, noPersist: options.persist === false })
|
|
@@ -430,7 +446,7 @@ const e2eCommand = program
|
|
|
430
446
|
e2eCommand
|
|
431
447
|
.command('up <feature>')
|
|
432
448
|
.description('Bring the stack up (reusing a warm one when it still matches the working tree)')
|
|
433
|
-
.option('--fresh', '
|
|
449
|
+
.option('--fresh', 'Recreate from scratch: down -v (named volumes included), drop the stamp, rebuild, re-seed auth')
|
|
434
450
|
.option('--json', 'Output as JSON')
|
|
435
451
|
.action((feature, options) => e2eUpCommand(feature, options));
|
|
436
452
|
|
|
@@ -456,8 +472,20 @@ worktreeCommand
|
|
|
456
472
|
.command('setup <feature>')
|
|
457
473
|
.description('Create a worktree at worktrees/{feature}/ on branch morph/{feature}')
|
|
458
474
|
.option('--fresh', 'Create a new dated branch even if one already exists')
|
|
475
|
+
.option('--json', 'Output as JSON (always JSON — accepted so the WorktreeCreate hook can call setup and provision uniformly)')
|
|
459
476
|
.action((feature, options) => worktreeSetupCommand(feature, options));
|
|
460
477
|
|
|
478
|
+
// Task isolation — the tree `claude -w`, EnterWorktree and Agent
|
|
479
|
+
// isolation:"worktree" ask for when the name is NOT a feature. Same infra as
|
|
480
|
+
// setup (junctions, port block, git-invisible manifest, primary-root landing),
|
|
481
|
+
// no feature identity. The WorktreeCreate hook is its main caller.
|
|
482
|
+
worktreeCommand
|
|
483
|
+
.command('provision <name>')
|
|
484
|
+
.description('Create a task-isolation worktree at worktrees/{name}/ on branch morph-task/{name} — full morph infra, no feature identity')
|
|
485
|
+
.option('--base <ref>', 'Branch off this ref instead of the default branch')
|
|
486
|
+
.option('--json', 'Output as JSON (always JSON)')
|
|
487
|
+
.action((name, options) => worktreeProvisionCommand(name, options));
|
|
488
|
+
|
|
461
489
|
worktreeCommand
|
|
462
490
|
.command('link')
|
|
463
491
|
.description('Link shared infra (node_modules[, .claude, .morph/framework]) into the current worktree')
|
|
@@ -475,6 +503,8 @@ worktreeCommand
|
|
|
475
503
|
.option('--target <path>', 'Remove the worktree at this path (for worktrees with no feature registration)')
|
|
476
504
|
.option('--discard-ignored', 'Skip the backup: gitignored files unique to the worktree are deleted instead of copied to .git/morph-spec/finish-backup (by default they are backed up and the removal proceeds anyway)')
|
|
477
505
|
.option('--delete-branch', 'Also delete the branch (default: kept — unintegrated commits live there)')
|
|
506
|
+
.option('--if-clean', 'Refuse (exit 1, worktree-dirty) if the tree has any uncommitted or untracked file — nothing is touched on a refusal. What the WorktreeRemove hook passes')
|
|
507
|
+
.option('--json', 'Output as JSON (always JSON)')
|
|
478
508
|
.action((feature, options) => worktreeRemoveCommand(feature, options));
|
|
479
509
|
|
|
480
510
|
worktreeCommand
|
|
@@ -500,6 +530,14 @@ branchCommand
|
|
|
500
530
|
.option('--json', 'Output as JSON')
|
|
501
531
|
.action((options) => branchPruneCommand(options));
|
|
502
532
|
|
|
533
|
+
// ─── Worktree env (shell-loadable port block) ─────────────────────────────
|
|
534
|
+
program
|
|
535
|
+
.command('env [feature]')
|
|
536
|
+
.description('Print the worktree\'s dedicated environment (port block + COMPOSE_PROJECT_NAME), shell-loadable: eval "$(morph-spec env)" outside Claude Code; feature defaults to the morph/{f} or morph-task/{n} branch of cwd')
|
|
537
|
+
.option('--json', 'Output as JSON')
|
|
538
|
+
.option('--powershell', 'Emit $env:K="V" lines instead of POSIX exports')
|
|
539
|
+
.action((feature, options) => envCommand(feature, options));
|
|
540
|
+
|
|
503
541
|
// ─── Fleet ────────────────────────────────────────────────────────────────
|
|
504
542
|
program
|
|
505
543
|
.command('fleet')
|
package/claude-plugin.json
CHANGED
package/docs/CHEATSHEET.md
CHANGED
|
@@ -59,11 +59,11 @@ morph-spec approve {feature} {gate} [--mode auto] [--approver name] [--notes tex
|
|
|
59
59
|
morph-spec advance {feature} [--design] # approve current gate + scaffold next phase folder in one step
|
|
60
60
|
morph-spec approval-status {feature} [--json]
|
|
61
61
|
morph-spec unapprove {feature} {gate} [--reason text] # recovery only
|
|
62
|
-
morph-spec finish {feature} --pr|--merge [--keep] [--force] [--discard-ignored] # normal close: archive + integrate + teardown
|
|
62
|
+
morph-spec finish {feature} --pr|--merge [--push] [--keep] [--force] [--discard-ignored] # normal close: archive + integrate + teardown
|
|
63
63
|
morph-spec archive {feature} [--force] [--no-git] # archive WITHOUT integrating (legacy feature / cleanup)
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
`finish` is the normal way to close a feature (both the worktree flow and the common flow): it archives (committing the move inside `morph/{feature}`), then integrates — `--merge` merges `--no-ff` into the default branch locally (no push); `--pr` pushes `morph/{feature}` + `gh pr create` (needs `origin` + authenticated `gh`). It then tears down the worktree and releases the port block. `archive` alone is reserved for legacy features (no `morph/{feature}` branch) and cleanup.
|
|
66
|
+
`finish` is the normal way to close a feature (both the worktree flow and the common flow): it archives (committing the move inside `morph/{feature}`), then integrates — `--merge` merges `--no-ff` into the default branch locally (no push); `--pr` pushes `morph/{feature}` + `gh pr create` (needs `origin` + authenticated `gh`). After a `--merge` the output reports how many commits the default branch is ahead of `origin/{default}` and the exact `git push origin {default}` that publishes them (in every `--merge` output, `--keep` included); `--push` runs that push for you. It then tears down the worktree and releases the port block. `archive` alone is reserved for legacy features (no `morph/{feature}` branch) and cleanup.
|
|
67
67
|
|
|
68
68
|
---
|
|
69
69
|
|
|
@@ -84,7 +84,8 @@ morph-spec retype {feature} {newType} # change type mid-flig
|
|
|
84
84
|
## CLI — state (server-side, timestamped)
|
|
85
85
|
|
|
86
86
|
```bash
|
|
87
|
-
morph-spec score {feature} {task}
|
|
87
|
+
morph-spec score {feature} {task} [score] [--dims "9.5,9,9,9"] # writes taskScores — {task} must match T<n> and {score} must be a number 0-10
|
|
88
|
+
# a blank/missing score or a dotted taskId is REFUSED (exit 1), never recorded as a fabricated 0
|
|
88
89
|
morph-spec gate-decision {feature} {gate} --pause <bool> [--reason] [--signals json] # writes gateDecisions
|
|
89
90
|
```
|
|
90
91
|
|
|
@@ -186,4 +187,4 @@ Never edited directly — go through CLI commands or `morph-spec update` instead
|
|
|
186
187
|
|
|
187
188
|
---
|
|
188
189
|
|
|
189
|
-
*morph-spec v8.
|
|
190
|
+
*morph-spec v8.35.0 by Polymorphism Tech*
|
package/docs/QUICKSTART.md
CHANGED
package/framework/CLAUDE.md
CHANGED
|
@@ -60,7 +60,7 @@ Se não houver feature ativa, pergunte ao usuário qual feature trabalhar.
|
|
|
60
60
|
| `retype <f> <tipo>` | Muda o workType mid-flight; bloqueado após o Gate 3 |
|
|
61
61
|
| `finish <f> --pr\|--merge` | Encerramento único: arquiva, promove use cases, desmonta worktree. Integra só no `--merge`; `--pr` abre PR e fica `aguardando-merge` até alguém mergear |
|
|
62
62
|
| `archive <f>` | Arquiva sem integrar (legadas/faxina) |
|
|
63
|
-
| `worktree setup\|link\|remove\|list` | Ciclo do worktree; `remove` é a única remoção segura |
|
|
63
|
+
| `worktree setup\|provision\|link\|remove\|list` | Ciclo do worktree; `provision` = isolamento de task; `remove` é a única remoção segura |
|
|
64
64
|
| `branch prune [--dry-run]` | Apaga branch já integrada, inclusive squash-merge; nunca a com PR aberto |
|
|
65
65
|
| `handoff <f>` | Regenera o documento de retomada da feature |
|
|
66
66
|
| `fleet` | Visão agregada de toda feature ativa (raiz + worktrees) |
|
|
@@ -109,6 +109,6 @@ Drift entre `agents.json` e os `.md` gerados é detectado por `morph-spec doctor
|
|
|
109
109
|
|
|
110
110
|
## Regra de precedência de skills
|
|
111
111
|
|
|
112
|
-
Prefira `morph-*` a `superpowers:*` equivalentes (`brainstorming`→`morph-brainstorming`, `writing-plans`→`morph-plan`, `executing-plans`→`morph-apply`, `test-driven-development`→seguir `mandate.md`, TDD embutido): `morph-*` aplica Gates e paths corretos de `.morph/`; `superpowers:*` é genérico, sem esse contexto.
|
|
112
|
+
Prefira `morph-*` a `superpowers:*` equivalentes (`brainstorming`→`morph-brainstorming`, `writing-plans`→`morph-plan`, `executing-plans`→`morph-apply`, `test-driven-development`→seguir `mandate.md`, TDD embutido, `using-git-worktrees`→`morph-spec worktree setup|provision`): `morph-*` aplica Gates e paths corretos de `.morph/`; `superpowers:*` é genérico, sem esse contexto.
|
|
113
113
|
|
|
114
114
|
*MORPH-SPEC v5 by Polymorphism Tech*
|
package/framework/MORPH.md
CHANGED
|
@@ -118,11 +118,10 @@ Features independentes podem ser desenvolvidas **em paralelo, cada uma no seu gi
|
|
|
118
118
|
|
|
119
119
|
- **Uma feature = um worktree = uma instância.** Nunca abra duas instâncias na mesma feature (setup recusa, exit 3).
|
|
120
120
|
- `feature.json` viaja **commitado na branch** `morph/{f}`; a cópia da raiz é esqueleto do nascimento, nunca mais atualizado — leitores (`list`/`handoff`/`fleet`) seguem a branch, mutadores recusam gravar fora da árvore dona (detalhes: CLI.md). `state.json` do worktree é índice derivável — self-heal, nunca sincronizado à mão.
|
|
121
|
-
-
|
|
122
|
-
- **Só o morph remove worktree.** Remoção genérica — `git worktree remove` (com OU sem `--force`), `rm -rf`, `Remove-Item -Recurse`, explorador/IDE — **atravessa a junction** e apaga o conteúdo real
|
|
123
|
-
- **Ambiente
|
|
124
|
-
- **
|
|
125
|
-
- **Limitação conhecida:** `node_modules` compartilhado (junction) — dependência mudada afeta os irmãos; integre (`finish`) antes de seguir em paralelo.
|
|
121
|
+
- **Só o morph cria worktree:** `worktree setup <f>` (feature) ou `worktree provision <n>` (isolamento de task, branch `morph-task/<n>`). `git worktree add` cru é bloqueado; `EnterWorktree`/`-w`/`isolation:"worktree"` passam pelo hook `WorktreeCreate` e caem em `worktrees/`. Fora de `worktrees/` = criado sem o morph (`doctor --worktrees` acusa). Infra (`node_modules`, `.claude`, `.morph/framework`) por junction; faltou → `worktree link --all`.
|
|
122
|
+
- **Só o morph remove worktree.** Remoção genérica — `git worktree remove` (com OU sem `--force`), `rm -rf`, `Remove-Item -Recurse`, explorador/IDE — **atravessa a junction** e apaga o conteúdo real da raiz (`.claude`/`node_modules`/`.morph/framework`), saindo com sucesso (já esvaziou uma raiz). Só `morph-spec` desmonta a junction ANTES de remover (PROVE-or-DECLINE): **fechar a feature** = `morph-spec finish <f> --pr|--merge`; **só desmontar o worktree** = `morph-spec worktree remove <f>` — ou `--target <path>` para worktree sem feature. O hook barra a versão crua, mas a regra vale antes dele.
|
|
123
|
+
- **Ambiente dedicado:** setup escreve `.morph/worktree.env` (`PORT`, `API_PORT`/`ASPNETCORE_URLS`, `POSTGRES_PORT`, `COMPOSE_PROJECT_NAME=morph-{f}`); cada worktree sobe o **seu** compose. O hook `PreToolUse:Bash` injeta as variáveis em dev server/compose; fora do Claude, `eval "$(morph-spec env)"`. Porta fixa ou `container_name` no compose **reprova o nó e2e** em worktree. `finish` derruba o stack **com volumes** (`--keep-volumes` preserva). Neon branch opcional, credencial em `e2e.auth.envFile`, nunca em `worktree.env`. Migration destrutiva → integre antes de abrir irmãos.
|
|
124
|
+
- **Limitação:** `node_modules` é junction compartilhada — dependência mudada afeta os irmãos; integre antes de seguir em paralelo.
|
|
126
125
|
- **Handoff entre sessões:** `.morph/features/{f}/handoff.md` — retomada comprimida, regenerável (`morph-spec handoff <f>`, resolve a árvore dona sozinho), **aponta** para os artefatos em vez de copiá-los. Regenerado em `setup`/`create --worktree`/`advance`/`approve`. **Leia-o antes de re-derivar contexto à mão** — nunca edite manualmente.
|
|
127
126
|
- **Visão da frota:** `fleet` agrega raiz + worktrees (fase, gates, tasks, portas, handoff, commit, sujeira); `worktree list` é a visão enxuta por worktree.
|
|
128
127
|
- **Ownership de arquivos:** sem lock runtime — colisão resolve **em plan-time** (`dag` detecta overlap de `outputs`, recomenda `isolation: "worktree"`) e **por construção** (uma feature = um worktree = um escritor). Arquivos compartilhados convergem no merge do `finish`; conflito ali é escopo sobreposto, não bug.
|
|
@@ -206,7 +205,7 @@ O agente responsável por um domínio está em `.morph/framework/agents.json` (f
|
|
|
206
205
|
|
|
207
206
|
## 5. Gates de Aprovação (Trust Mode)
|
|
208
207
|
|
|
209
|
-
Gates são pontos de **pausa potencial**. Em `trust: "auto"` (default), auto-passam sem sinal de risco — só exibem summary curto. Em `trust: "manual"` OU com sinal de risco,
|
|
208
|
+
Gates são pontos de **pausa potencial**. Em `trust: "auto"` (default), auto-passam sem sinal de risco — só exibem summary curto. Em `trust: "manual"` OU com sinal de risco, pausam via `AskUserQuestion` com options padrão:
|
|
210
209
|
|
|
211
210
|
```
|
|
212
211
|
- "aprovado, prosseguir"
|
|
@@ -220,31 +219,33 @@ Gates são pontos de **pausa potencial**. Em `trust: "auto"` (default), auto-pas
|
|
|
220
219
|
| ------- | ----------- | --------------- |
|
|
221
220
|
| `designSystemDivergence` | true | Brainstorming detecta fontes conflitantes (spec antigo vs bundle local) |
|
|
222
221
|
| `standardsViolations` | array.length > 0 | Mandate ou implementation viola padrões proibidos |
|
|
223
|
-
| `evalScore` | < 9 | score composto da feature (
|
|
224
|
-
| `verificationStatus` | === 'fail' | `
|
|
225
|
-
| `verificationStale` | true | Stamp do `verify` com sha != HEAD: o verde não cobre mais o código. Só no **ship**
|
|
226
|
-
| `
|
|
227
|
-
| `
|
|
222
|
+
| `evalScore` | < 9 | score composto da feature (morph-review) abaixo do mínimo |
|
|
223
|
+
| `verificationStatus` | === 'fail' | `verify` vermelho — build, testes, validadores **ou e2e** (a app não sobe / as specs não passam). Vale em **qualquer** gate |
|
|
224
|
+
| `verificationStale` | true | Stamp do `verify` com sha != HEAD: o verde não cobre mais o código. Só no **ship** |
|
|
225
|
+
| `e2eSkipClass` (derivada) | environment/requested/unknown | e2e pulou sem dispensa legítima (só `project`/`scope`, e só em stamp de escopo `feature`). Só no **ship** |
|
|
226
|
+
| `mutationProof` | seção ausente | Relatório do avaliador sem `## Mutações` numa feature com código de produção. Só no **ship** |
|
|
227
|
+
| `taskCount` | > 20 | Escopo grande — vale revisar antes de implementar |
|
|
228
|
+
| `workType` | === 'hotfix' | Gate 3 pausa SEMPRE (ver "Gates por tipo de trabalho") |
|
|
228
229
|
|
|
229
230
|
| Gate | Sinais | Skill responsável |
|
|
230
231
|
| ------ | -------- | -------------------- |
|
|
231
232
|
| 1 — Proposta | `designSystemDivergence`, `standardsViolations` (improvável) | `morph-brainstorming` |
|
|
232
233
|
| 2 — Plano | Gate 1 + `taskCount`, `standardsViolations` em mandate | `morph-plan` |
|
|
233
|
-
| 3 — Review | `evalScore` composite, `standardsViolations` em implementation, `verificationStale` | `morph-review` |
|
|
234
|
+
| 3 — Review | `evalScore` composite, `standardsViolations` em implementation, `verificationStale`, `e2eSkipClass`, `mutationProof` | `morph-review` |
|
|
234
235
|
|
|
235
|
-
`verificationStatus`
|
|
236
|
+
`verificationStatus` fica fora da tabela por gate porque vale em todos.
|
|
236
237
|
|
|
237
238
|
**Gates por tipo de trabalho:** `chore`/`hotfix` pulam Gates 1 e 2 — carimbados por política no nascimento (`approvedBy: "policy:{tipo}"`, nunca `"auto"`, para não colidir com o gate-guard); a barra do morph-eval e o Gate 3 valem para todos os tipos. `hotfix`: Gate 3 **sempre humano** (mesmo em `trust: auto` — `morph-hotfix` pausa via `AskUserQuestion`, o `risk-detector` força, o backstop server-side recusa `approve ... review --mode auto`) e exige `4-review/review-report.md` em vez de `evaluator-report.md`. Demais tipos exigem `evaluator-report.md`, **enforced server-side** (`morph-spec approve {feature} review` recusa exit 1 sem ele; `--force` não dispensa) — ou `--self-assessed` registrado (`approvalGates.review.selfAssessed`, marcado no `morph-spec list`).
|
|
238
239
|
|
|
239
|
-
Para alterar o modo:
|
|
240
|
+
Para alterar o modo: `.morph/config/config.json → trust` (`"auto"` ou `"manual"`; campo ausente = `"auto"`).
|
|
240
241
|
|
|
241
|
-
**Comportamento padrão fora de gate:** autonomia total — gates só existem nestes três pontos. Não pause
|
|
242
|
+
**Comportamento padrão fora de gate:** autonomia total — gates só existem nestes três pontos. Não pause durante a implementação salvo ambiguidade de escopo que o mandate não cobre — registre em decisions.md, resolva conservadoramente, sinalize na entrega da task.
|
|
242
243
|
|
|
243
|
-
**A aprovação de gate é unificada nos comandos da CLI — nunca edite o estado à mão.** Em `trust: "auto"` (sem `AskUserQuestion`): `morph-spec approve <feature> <gate> --mode auto`; `morph-spec advance <feature>` aprova o gate corrente **e**
|
|
244
|
+
**A aprovação de gate é unificada nos comandos da CLI — nunca edite o estado à mão.** Em `trust: "auto"` (sem `AskUserQuestion`): `morph-spec approve <feature> <gate> --mode auto`; `morph-spec advance <feature>` aprova o gate corrente **e** cria a pasta da próxima fase (`--design` = ramo opcional de uiux). Scores por task: `morph-spec score <feature> <task> <score> [--dims a,c,q,t]` — nunca edite `taskScores` à mão. **O hook state-sync.js** cobre o caminho manual: `AskUserQuestion` respondida com label "aprovado" → registra o gate no `feature.json` autoritativo com `approvedBy: "manual"`. **A feature é identificada pelo nome que a pergunta cita** — grava na árvore que a possui (raiz ou worktree), nunca na "feature ativa" de quem rodou a sessão. Pergunta sem nome numa árvore com mais de uma feature: o hook **recusa gravar** e avisa — aprove por `morph-spec approve`. Gate sempre gravado em `.morph/features/{feature}/feature.json` — nunca via Edit de `state.json`.
|
|
244
245
|
|
|
245
|
-
**Registre quem aprovou (`approvedBy`):** objeto `{ approved, timestamp, approvedBy }`. `"auto"` — política `trust: auto` sem decisão humana. `"manual"` — humano aprovou explicitamente (via `AskUserQuestion`, ou, sem ela em headless,
|
|
246
|
+
**Registre quem aprovou (`approvedBy`):** objeto `{ approved, timestamp, approvedBy }`. `"auto"` — política `trust: auto` sem decisão humana. `"manual"` — humano aprovou explicitamente (via `AskUserQuestion`, ou, sem ela em headless, texto começando em "aprovado"); em `trust: manual` todo gate é `"manual"` — nunca grave `"auto"` num gate que um humano aprovou. Mantém o audit trail honesto em headless (CI, `claude -p`), onde mais importa.
|
|
246
247
|
|
|
247
|
-
**O hook gate-guard.js** confere, sem bloquear, se a ação tomada num gate (pausar vs auto-aprovar) bateu com a decisão persistida. **Default:** `gate-check <feature> <gate> [--signals <json>] [--json]` decide via `shouldPauseGate`; `--signals` sobrescreve só o que o disco não expõe sozinho (`designSystemDivergence`, `standardsViolations`, `evalScore`). **Escape manual** (sinal que `shouldPauseGate` nem representa, ex.: modo de descoberta): `gate-decision <feature> <gate> --pause <bool> [--reason <txt>] [--signals <json>]`. Ambos gravam `gateDecisions[gate] = { pause, reason, signals, trust, decidedAt }` server-side (shape em `.morph/framework/schemas/feature.schema.json`). **Nunca edite `gateDecisions` à mão** — colide com state-sync. Divergência → o guard injeta aviso no contexto; cada conferência registra `coherent`/`divergent` em `.morph/logs/activity.json
|
|
248
|
+
**O hook gate-guard.js** confere, sem bloquear, se a ação tomada num gate (pausar vs auto-aprovar) bateu com a decisão persistida. **Default:** `gate-check <feature> <gate> [--signals <json>] [--json]` decide via `shouldPauseGate`; `--signals` sobrescreve só o que o disco não expõe sozinho (`designSystemDivergence`, `standardsViolations`, `evalScore`). **Escape manual** (sinal que `shouldPauseGate` nem representa, ex.: modo de descoberta): `gate-decision <feature> <gate> --pause <bool> [--reason <txt>] [--signals <json>]`. Ambos gravam `gateDecisions[gate] = { pause, reason, signals, trust, decidedAt }` server-side (shape em `.morph/framework/schemas/feature.schema.json`). **Nunca edite `gateDecisions` à mão** — colide com state-sync. Divergência → o guard injeta aviso no contexto; cada conferência registra `coherent`/`divergent` em `.morph/logs/activity.json`.
|
|
248
249
|
|
|
249
250
|
---
|
|
250
251
|
|
|
@@ -312,10 +313,7 @@ aceito em silêncio. Segunda ausência sem trabalho entregue é falha real: esca
|
|
|
312
313
|
- Problemas encontrados e como foram resolvidos
|
|
313
314
|
- Auto-score 0-10 com justificativa em uma linha
|
|
314
315
|
|
|
315
|
-
**Contrato do relatório final
|
|
316
|
-
1. **GRAVE o relatório no arquivo canônico ANTES de encerrar**, com os 4 itens acima — é o retorno autoritativo, não a sua última mensagem (cortesia best-effort, pode não chegar inteira). Ausente/oco/incompleto é **falha de protocolo** — registrada no recap. **Não chame `SendMessage`**: gera um evento a mais além da notificação de término.
|
|
317
|
-
2. Não tocar em `tasks.json`, `feature.json`, `state.json` nem no board de sessão — todo estado é do orquestrador.
|
|
318
|
-
3. **Verificação condicional ao isolamento:** **sem isolamento** → não rode build/test compartilhado, verificação é do orquestrador pós-batch. **Com `isolation: "worktree"`** (`dag` recomenda por colisão de `outputs`) → build/test **dentro do worktree**, commite na branch como último ato, reporte a branch, **nunca** faça merge.
|
|
316
|
+
**Contrato do relatório final:** as sete cláusulas que todo prompt de dispatch inclui vivem nos DOIS templates — `morph-implement` §4 e `morph-apply` §3b — e não são repetidas aqui: duas cópias da mesma regra divergem, e quem manda é a que o sub-agent recebe. **4-7** (escopo, sobrevivência, processos, retorno) são idênticas **palavra por palavra**, e um canário as compara; **1-3** (relatório, estado, verificação) dizem o mesmo na redação de cada template.
|
|
319
317
|
|
|
320
318
|
Sub-agent deve ser autossuficiente com o que você passou — se precisar de mais contexto, a tarefa não estava bem especificada; refine antes de despachar.
|
|
321
319
|
|