@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.
Files changed (253) hide show
  1. package/CLAUDE.md +22 -2
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +43 -5
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +5 -4
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +2 -2
  8. package/framework/MORPH.md +20 -22
  9. package/framework/agents.json +198 -44
  10. package/framework/ai-pin.json +22 -0
  11. package/framework/commands/morph-media.md +45 -0
  12. package/framework/docs/CLI.md +238 -10
  13. package/framework/evals/proof-rubrics/README.md +76 -0
  14. package/framework/evals/proof-rubrics/eval-de-modelo.md +64 -0
  15. package/framework/evals/proof-rubrics/fiacao.md +54 -0
  16. package/framework/evals/proof-rubrics/guard-cego.md +52 -0
  17. package/framework/evals/proof-rubrics/media-claims.md +109 -0
  18. package/framework/evals/proof-rubrics/mutation-proof.md +77 -0
  19. package/framework/evals/proof-rubrics/observabilidade-genai.md +119 -0
  20. package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +48 -0
  21. package/framework/evals/rubrics/architecture.md +30 -0
  22. package/framework/evals/rubrics/code-quality.md +26 -0
  23. package/framework/evals/rubrics/test-coverage.md +20 -0
  24. package/framework/hooks/README.md +11 -1
  25. package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +5 -8
  26. package/framework/hooks/claude-code/core/block-raw-worktree-add.js +79 -0
  27. package/framework/hooks/claude-code/core/chain.js +27 -7
  28. package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
  29. package/framework/hooks/claude-code/core/worktree-context.js +83 -14
  30. package/framework/hooks/claude-code/core/worktree-create.js +206 -0
  31. package/framework/hooks/claude-code/core/worktree-env-inject.js +87 -0
  32. package/framework/hooks/claude-code/core/worktree-remove.js +81 -0
  33. package/framework/hooks/shared/command-tokens.js +23 -0
  34. package/framework/hooks/shared/e2e-check.js +0 -0
  35. package/framework/hooks/shared/git-paths.js +25 -0
  36. package/framework/hooks/shared/hook-response.js +17 -0
  37. package/framework/hooks/shared/morph-cli.js +134 -0
  38. package/framework/rules/ai-agents-standards.md +14 -2
  39. package/framework/rules/infrastructure-standards.md +3 -1
  40. package/framework/schemas/ai-pin.schema.json +97 -0
  41. package/framework/schemas/config.schema.json +107 -0
  42. package/framework/schemas/feature.schema.json +23 -4
  43. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  44. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  45. package/framework/skills/core/morph-apply/SKILL.md +28 -7
  46. package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
  47. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  48. package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
  49. package/framework/skills/core/morph-implement/SKILL.md +20 -2
  50. package/framework/skills/core/morph-media/SKILL.md +215 -0
  51. package/framework/skills/core/morph-plan/SKILL.md +38 -4
  52. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  53. package/framework/skills/core/morph-review/SKILL.md +166 -9
  54. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  55. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  56. package/framework/skills/core/morph-uiux/SKILL.md +1 -1
  57. package/framework/standards/PROVENANCE.json +81 -3
  58. package/framework/standards/STANDARDS.json +1504 -830
  59. package/framework/standards/ai-agents/agent-archetypes.md +160 -0
  60. package/framework/standards/ai-agents/agent-session.md +256 -160
  61. package/framework/standards/ai-agents/agent-spec.md +196 -0
  62. package/framework/standards/ai-agents/batching.md +217 -193
  63. package/framework/standards/ai-agents/context-providers.md +261 -188
  64. package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
  65. package/framework/standards/ai-agents/cost-and-budget.md +256 -0
  66. package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
  67. package/framework/standards/ai-agents/evals-with-cache.md +289 -0
  68. package/framework/standards/ai-agents/guardrails.md +222 -0
  69. package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
  70. package/framework/standards/ai-agents/mcp-server.md +351 -250
  71. package/framework/standards/ai-agents/mcp-tools.md +250 -197
  72. package/framework/standards/ai-agents/media-pipeline.md +352 -0
  73. package/framework/standards/ai-agents/media-video.md +267 -0
  74. package/framework/standards/ai-agents/middleware-patterns.md +241 -207
  75. package/framework/standards/ai-agents/modalities-image-gen.md +422 -173
  76. package/framework/standards/ai-agents/modalities-speech-to-text.md +177 -171
  77. package/framework/standards/ai-agents/modalities-text-to-speech.md +189 -181
  78. package/framework/standards/ai-agents/modalities-vision.md +205 -201
  79. package/framework/standards/ai-agents/multi-agent-patterns.md +211 -155
  80. package/framework/standards/ai-agents/observability-patterns.md +227 -17
  81. package/framework/standards/ai-agents/production.md +260 -231
  82. package/framework/standards/ai-agents/prompt-sources.md +389 -0
  83. package/framework/standards/ai-agents/providers/model-registry.md +293 -158
  84. package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
  85. package/framework/standards/ai-agents/service-tier-flex.md +143 -135
  86. package/framework/standards/ai-agents/setup.md +166 -50
  87. package/framework/standards/ai-agents/structured-output.md +280 -249
  88. package/framework/standards/ai-agents/sweet-spot.md +129 -109
  89. package/framework/standards/ai-agents/testing-ai.md +236 -0
  90. package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
  91. package/framework/standards/ai-agents/workflows.md +27 -7
  92. package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
  93. package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
  94. package/framework/standards/infrastructure/docker/local-compose-isolation.md +90 -0
  95. package/framework/templates/REGISTRY.json +14 -1
  96. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
  97. package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
  98. package/framework/templates/dotnet/ai-kit/Directory.Build.props +25 -0
  99. package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
  100. package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
  101. package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
  102. package/framework/templates/dotnet/ai-kit/README.md +128 -0
  103. package/framework/templates/dotnet/ai-kit/global.json +9 -0
  104. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
  105. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
  106. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
  107. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
  108. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
  109. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
  110. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
  111. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
  112. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
  113. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
  114. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
  115. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
  116. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
  117. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
  118. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
  119. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
  120. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
  121. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
  122. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
  123. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
  124. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
  125. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
  126. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
  127. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
  128. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
  129. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
  130. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
  131. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
  132. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
  133. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
  134. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
  135. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
  136. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
  137. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
  138. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
  139. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
  140. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
  141. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
  142. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
  143. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
  144. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
  145. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
  146. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
  147. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
  148. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
  149. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
  150. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
  151. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
  152. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
  153. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
  154. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
  155. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
  156. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
  157. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
  158. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
  159. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
  160. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
  161. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
  162. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
  163. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
  164. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
  165. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
  166. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
  167. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
  168. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
  169. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
  170. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
  171. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
  172. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
  173. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
  174. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
  175. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
  176. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
  177. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
  178. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
  179. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
  180. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
  181. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
  182. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
  183. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
  184. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
  185. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
  186. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
  187. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
  188. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
  189. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
  190. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
  191. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
  192. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
  193. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
  194. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
  195. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
  196. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
  197. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
  198. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
  199. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
  200. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
  201. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
  202. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
  203. package/framework/templates/infrastructure/docker/docker-compose.template.yml +24 -14
  204. package/package.json +3 -3
  205. package/src/commands/e2e/e2e.js +91 -40
  206. package/src/commands/project/doctor.js +143 -6
  207. package/src/commands/project/env.js +95 -0
  208. package/src/commands/project/update.js +469 -153
  209. package/src/commands/project/worktree.js +274 -53
  210. package/src/commands/state/advance.js +24 -2
  211. package/src/commands/state/approve.js +33 -1
  212. package/src/commands/state/create.js +72 -11
  213. package/src/commands/state/delete.js +8 -0
  214. package/src/commands/state/finish.js +360 -53
  215. package/src/commands/state/gate-check.js +190 -6
  216. package/src/commands/state/score.js +36 -1
  217. package/src/commands/validation/verify.js +134 -25
  218. package/src/core/state/state-manager.js +9 -1
  219. package/src/dashboard/app/pages/HookInspector.jsx +430 -418
  220. package/src/dashboard/scanner/hooks-scanner.js +5 -1
  221. package/src/lib/ai/ai-checks.js +182 -0
  222. package/src/lib/ai/ai-project-scan.js +347 -0
  223. package/src/lib/ai/code-audit.js +181 -0
  224. package/src/lib/ai/comment-stripper.js +184 -0
  225. package/src/lib/ai/pin-drift.js +138 -0
  226. package/src/lib/ai/registry-audit.js +285 -0
  227. package/src/lib/e2e/compose-env.js +55 -14
  228. package/src/lib/e2e/stack-teardown.js +115 -0
  229. package/src/lib/evaluator-report.js +269 -15
  230. package/src/lib/generators/architecture-scanner.js +2 -1
  231. package/src/lib/git/default-branch.js +92 -4
  232. package/src/lib/graph/graphifyignore.js +2 -1
  233. package/src/lib/installers/effects.js +193 -0
  234. package/src/lib/installers/templates-reconcile.js +3 -3
  235. package/src/lib/risk-detector.js +284 -0
  236. package/src/lib/standards/verified-against.js +276 -0
  237. package/src/lib/tasks/eval-node.js +485 -0
  238. package/src/lib/tasks/linux-runner.js +297 -0
  239. package/src/lib/tasks/test-nodes.js +486 -0
  240. package/src/lib/tasks/test-runner.js +431 -37
  241. package/src/lib/validators/verify-runner.js +590 -28
  242. package/src/lib/worktree/dirs.js +32 -0
  243. package/src/lib/worktree/docker-audit.js +287 -0
  244. package/src/lib/worktree/env-allocator.js +69 -11
  245. package/src/lib/worktree/worktree-audit.js +70 -3
  246. package/src/scripts/setup-infra.js +24 -11
  247. package/src/utils/agents-installer.js +18 -8
  248. package/src/utils/claude-md-injector.js +10 -5
  249. package/src/utils/file-copier.js +28 -16
  250. package/src/utils/hooks-installer.js +75 -29
  251. package/src/utils/skills-installer.js +194 -187
  252. package/src/utils/version-checker.js +68 -3
  253. 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.33.0
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.33.0 by [Polymorphism Tech](https://polymorphism.tech)*
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
- .command('score <feature> <task> <score>')
255
- .description('Record a task eval score in feature.json (taskScores, server-side timestamp)')
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', 'Rebuild the e2e stack instead of reusing a warm one')
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', 'Rebuild instead of reusing a warm stack')
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')
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "morph-spec",
3
- "version": "8.33.0",
3
+ "version": "8.35.0",
4
4
  "displayName": "MORPH-SPEC Framework",
5
5
  "description": "Spec-driven development with 38 agents and 8-phase workflow for .NET/Blazor/Next.js/Azure",
6
6
  "publisher": "polymorphism-tech",
@@ -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} {score} [--dims "9.5,9,9,9"] # writes taskScores
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.33.0 by Polymorphism Tech*
190
+ *morph-spec v8.35.0 by Polymorphism Tech*
@@ -249,4 +249,4 @@ morph-spec doctor
249
249
 
250
250
  ---
251
251
 
252
- *morph-spec v8.33.0 by Polymorphism Tech*
252
+ *morph-spec v8.35.0 by Polymorphism Tech*
@@ -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*
@@ -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
- - Infra compartilhada (`node_modules`, `.claude`, `.morph/framework`) linkada por junction; `memory/`/`logs/` são locais de cada worktree. Faltou infra (worktree aberto com `git worktree add` puro) → `morph-spec 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 compartilhado da raiz (`.claude`/`node_modules`/`.morph/framework`), não só o link, saindo com sucesso. Foi assim que uma raiz teve `.claude/` e `.morph/framework/` esvaziados. 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** (feature segue aberta) = `morph-spec worktree remove <f>` — ou `--target <path>` para worktree sem feature. O hook `block-destructive-worktree-removal` barra a versão crua, mas a regra vale antes dele.
123
- - **Ambiente separado (portas):** setup aloca **bloco de portas determinístico** por feature em `.morph/worktree.env` (`PORT`, `MORPH_PORT_RANGE`; `ASPNETCORE_URLS` se dotnet). **Suba dev servers SEMPRE nas portas do bloco** — as padrão (3000/5000) pertencem à raiz. Local, git-invisível; SessionStart injeta as portas. Override: `config.json → fleet.basePort/blockSize`.
124
- - **Banco de dados:** compartilhado por padrão; isolar via Neon MCP: branch de DB `morph/{f}` + connection string em `.morph/worktree.env` (sem Neon, prefixe schema/DB pelo nome da feature). Migration destrutiva → integre antes de abrir worktrees irmãos.
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, o gate pausa via `AskUserQuestion` com options padrão:
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 (via morph-review) abaixo do mínimo |
224
- | `verificationStatus` | === 'fail' | `morph-spec verify` vermelho — build, testes, validadores **ou e2e** (a app não sobe / as specs não passam). Vale em **qualquer** gate |
225
- | `verificationStale` | true | Stamp do `verify` com sha != HEAD: o verde não cobre mais o código. Só no **ship** (Gate 3) |
226
- | `taskCount` | > 20 | Escopo grande — provavelmente vale revisar antes de implementar |
227
- | `workType` | === 'hotfix' | Gate 3 pausa SEMPRE (detalhe abaixo, "Gates por tipo de trabalho") |
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` não está numa linha só porque vale em todas — verify vermelho pausa qualquer gate.
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: editar `.morph/config/config.json → trust` (`"auto"` ou `"manual"`). Configs sem o campo `trust` defaultam para `"auto"`.
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 no meio de implementação a menos que encontre ambiguidade de escopo que o mandate não cobre — registre em decisions.md, resolva conservadoramente, sinalize na entrega da task.
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** já cria a pasta da próxima fase (`--design` para o 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, árvore com mais de uma feature: o hook **recusa gravar** e avisa — aprove por `morph-spec approve <feature> <gate>`. Gate sempre gravado em `.morph/features/{feature}/feature.json` — nunca via Edit de `state.json`.
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, via 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 nos contextos headless (CI, `claude -p`) onde mais importa.
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` — nunca bloqueia.
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** (cláusulas que todo prompt de dispatch inclui — ver templates em `morph-implement` §4 e `morph-apply` §3b):
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