@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
@@ -0,0 +1,52 @@
1
+ # Prova: Guard Cego
2
+
3
+ > Escopo: Gate 3 (avaliador independente). Não é dimensão do score composto — impõe **teto** em
4
+ > Cobertura de Testes (`evals/rubrics/test-coverage.md`, seção "Tetos de prova").
5
+
6
+ ## O que esta prova responde
7
+
8
+ Um guard só vale contra o ataque que ele consegue VER. O jeito de descobrir o que ele não vê não é
9
+ mudar o conteúdo que ele já inspeciona — é mudar a **FORMA** do que chega até ele.
10
+
11
+ A pergunta é: **qual entrada válida este guard deixa passar sem enxergar, e o ramo que ele abriu
12
+ tem teste próprio?**
13
+
14
+ ## Bandas 0-10
15
+
16
+ | 0-3 | 4-6 | 7-8 | 9-10 |
17
+ |---|---|---|---|
18
+ | Guard sem teste próprio. Ou testado só com o conteúdo que ele já rejeita, nunca com forma diferente | Ataque por conteúdo apenas. Guard que compara `Serialize(A) == Serialize(B)` aceito sem cross-check | Ataque por forma feito; falta o cross-check por contador independente, ou o predicado do guard continua mais estreito que a ação que ele governa | Forma atacada (multi-linha, aninhamento, ordem, codificação), cross-check por contador independente, predicado tão largo quanto a ação, e todo ramo recém-alcançável com teste próprio |
19
+
20
+ ## Anti-padrões literais
21
+
22
+ - **Atacar o guard só pelo conteúdo** — mude a **FORMA**. Medido: o guard era um parser linha a
23
+ linha e o YAML **multi-linha** era perfeitamente válido; o conteúdo proibido passou inteiro
24
+ porque chegou numa forma que o parser não montava.
25
+ - **`Serialize(A) == Serialize(B)` como prova de igualdade** — o guard é cego ao próprio
26
+ serializador: se ele perde um campo, perde nos dois lados e a comparação dá igual. Faça
27
+ **cross-check por um contador independente** (número de itens, soma, hash de um campo-chave).
28
+ - **Predicado mais estreito que a ação que ele governa** — um publish que só olhava o *spec* e
29
+ virava no-op sobre tudo o mais. Afirme sobre o **texto publicado**, não sobre a intenção de
30
+ publicar.
31
+ - **Early-return depois do filtro** — o `return` sai antes da limpeza e o estado fica meio mutado.
32
+ Quando o filtro é um `skip`, transforme-o em `else`: o caminho de saída precisa passar pelo
33
+ mesmo fecho.
34
+ - **Ramo antes inalcançável que passou a ser alcançável** — isso é **código NOVO**, ainda que a
35
+ linha seja antiga e o diff não a toque. Ele precisa de teste próprio; nenhuma cobertura anterior
36
+ responde por ele.
37
+ - **Guard novo sem prova de que morde** — canário que não morde é canário errado, e canário que
38
+ morde pelo motivo errado é pior: mute a produção, exija que o teste FALHE **nomeando o que
39
+ quebrou**, e restaure por cópia de bytes feita antes.
40
+
41
+ ## Como registrar no relatório
42
+
43
+ Uma linha por guard tocado, dizendo a forma atacada e o resultado:
44
+
45
+ ```markdown
46
+ - `chain.js:blockRawWorktreeAdd` — atacado por FORMA: comando com `\` de continuação em duas linhas
47
+ e com aspas simples. Bloqueou nas duas. Cross-check: contador de comandos bloqueados subiu 2.
48
+ - Ramo `options.discardIgnored === true` era inalcançável antes de T4 — agora é alcançável e ganhou
49
+ teste próprio (`finish.test.js:412`).
50
+ ```
51
+
52
+ E no `**Proof-Scores:**`, a chave `guard`.
@@ -0,0 +1,109 @@
1
+ # Prova: Media Claims
2
+
3
+ > Escopo: Gate 3 (avaliador independente), **somente** em feature que gera mídia. Não é dimensão
4
+ > do score composto — o composto continua `arquitetura + contratos + qualidade + testes`. Esta prova
5
+ > impõe **teto** em Arquitetura (tabela em `evals/rubrics/architecture.md`, seção "Tetos de prova de
6
+ > mídia").
7
+
8
+ ## O que esta prova responde
9
+
10
+ Uma feature que gera imagem ou vídeo faz **quatro afirmações** que custam caro quando são falsas, e
11
+ as quatro são fáceis de escrever e difíceis de provar: *controlamos o custo*, *tem revisão humana*,
12
+ *a mídia é marcada*, *o hot path não bloqueia*.
13
+
14
+ A pergunta desta rubrica é sempre a mesma: **onde está o código que torna a afirmação verdadeira,
15
+ e o que acontece se alguém tentar burlá-la?**
16
+
17
+ Ela vive em Arquitetura, e não em Cobertura, porque as quatro são **propriedades estruturais** —
18
+ onde a chamada mora, que estados existem, o que é persistido, o que é publicado. Uma feature que
19
+ gera mídia dentro do turno de WhatsApp está arquiteturalmente errada, não mal testada; contá-la como
20
+ falha de teste diria a coisa errada a quem lê o relatório.
21
+
22
+ As quatro afirmações, com o que conta e o que não conta:
23
+
24
+ | Afirmação | Evidência que conta | Evidência que **não** conta |
25
+ |---|---|---|
26
+ | **Custo** | Custo estimado gravado **antes** da chamada, com a tarifa e a data da tabela de preços; teto por tenant/dia exercitado em teste, com o caso que ESTOURA | "usamos o modelo mais barato"; uma constante de preço sem fonte datada |
27
+ | **Revisão humana** | Teste que prova que a publicação falha a partir de **todo** estado que não seja aprovado, e que aprovar carimba quem e quando | Um comentário dizendo que há revisão; um campo booleano `approved` |
28
+ | **Marcação** | A publicação **recusa** quando a finalidade exige rótulo e ele não veio — com texto e superfície nomeados, gravados junto do artefato — mais a proveniência persistida e o C2PA preservado sem re-encode. No exemplar: `MediaJob.Publish(MediaDisclosure?, at)`, terceira porta | "o SynthID vem embutido" — vem, e cai no primeiro re-encode ou screenshot; um campo de rótulo que a publicação aceita vazio; a obrigação escrita só no comentário do estado `Published` |
29
+ | **Hot path não bloqueado** | O tipo que produz bytes é **inacessível** do handler (teste de acessibilidade por reflexão) **e** o handler de mensagem devolve id de job | "o handler chama o serviço assíncrono"; um `Task.Run` |
30
+
31
+ O conhecimento por trás das quatro está em `.morph/framework/standards/ai-agents/media-pipeline.md`.
32
+ Esta rubrica não o repete: ela cobra a prova.
33
+
34
+ ## Bandas 0-10
35
+
36
+ | 0-3 | 4-6 | 7-8 | 9-10 |
37
+ |---|---|---|---|
38
+ | Nenhuma das quatro afirmações tem código apontado. Ou a geração acontece dentro do turno de conversa, ou a publicação é alcançável sem aprovação humana — qualquer um dos dois é **bloqueante**, independentemente do resto | As quatro estão implementadas, mas a prova é leitura de código: nenhum teste exercita o caminho de recusa. Teto de custo declarado e nunca estourado em teste; marcação prometida na prosa e ausente no ponto de publicação | As quatro provadas por teste, com o caminho de recusa exercitado ao menos uma vez cada. Falta a mutação: nenhuma delas foi vista MORDENDO, ou a proveniência grava menos campos do que o standard nomeia | As quatro provadas, cada caminho de recusa com teste próprio, **e a acessibilidade do tipo que produz bytes asserida por reflexão com a mutação rodada** (tornar público, ver o teste falhar nomeando o defeito, restaurar por bytes e conferir por md5). Custo estimado antes da chamada, com tarifa datada; teto exercitado no caso que estoura. A marcação é **parâmetro da transição de publicação**, não campo opcional: existe o teste que publica sem rótulo e vê a recusa |
39
+
40
+ ## Anti-padrões literais
41
+
42
+ - **Prender a regra dura só na prosa.** "O standard diz para não gerar no turno" não impede nada. O
43
+ que impede é a acessibilidade do tipo: se um handler consegue **nomear** o tipo que produz bytes,
44
+ a regra não está presa — mesmo que ninguém a tenha violado ainda. (memória: é a diferença entre
45
+ "o standard diz para não fazer" e "o compilador recusa")
46
+ - **Testar a fachada em vez do dono do estado.** Se `Review.Publish(job)` reimplementa a regra em
47
+ vez de delegar a `job.Publish()`, o teste da fachada mede uma **cópia** do objeto — e as duas
48
+ divergem no primeiro conserto. Exercite as duas contra o MESMO job e compare.
49
+ - **Confundir a chave de idempotência do PEDIDO com o hash do CONTEÚDO.** Uma dedupe chamada paga, a
50
+ outra dedupe storage. Um teste que só confere "o hash é o mesmo" **não distingue dedupe de
51
+ regravação**: as duas produzem o mesmo hash. Conte as gravações.
52
+ - **Aceitar `estimatedCostUsd` gravado DEPOIS da chamada.** Isso é contabilidade, não controle: o
53
+ dinheiro já saiu. A prova é a ordem, e a ordem é verificável.
54
+ - **Preço em código sem fonte datada.** Uma constante `0.211m` sem a página e a data de consulta é
55
+ folclore com força de orçamento. A tarifa vem da tabela do standard da modalidade.
56
+ - **Tratar bloqueio de moderação como erro técnico.** Se o estado de bloqueio for retryable, um laço
57
+ de retry vira uma fatura — e no provedor que cobra o bloqueio, cobra duas vezes. Exija dois
58
+ estados distintos e um teste por estado.
59
+ - **`not_detected` lido como "feito por humano".** Ausência de marca é ausência de informação. Um
60
+ verificador de proveniência que devolve "não detectado" não prova origem humana.
61
+ - **Marcação delegada ao provedor.** C2PA e SynthID vêm embutidos e **caem** com screenshot ou
62
+ re-encode. A marcação visível é obrigação separada, e ela mora no ponto de publicação — não no de
63
+ geração.
64
+ - **Marcação presa só por prosa.** É o anti-padrão mais fácil de cometer porque parece resolvido: o
65
+ comentário do estado `Published` diz "com a marcação aplicada", a finalidade `Marketing` diz
66
+ "marcação visível obrigatória", e um `grep` por rótulo, watermark ou disclosure no código volta
67
+ **vazio**. Se as outras três afirmações estão presas por tipo ou por estado e a marcação — que é a
68
+ obrigação legal — está presa por nada, a assimetria é o achado. Prova mínima: a publicação recusa
69
+ sem rótulo.
70
+ - **Ler "o tipo prende" como "nada mais é possível".** O `internal` fecha *obter bytes* e *nomear o
71
+ produtor*; ele **não** fecha *aguardar inline*. O gatilho do worker (`IMediaJobRunner.RunAsync` no
72
+ exemplar) é público por necessidade — quem o dispara é o `BackgroundService` do projeto — e um
73
+ `await runner.RunAsync(id)` dentro de um handler de turno **compila** e paga a latência inteira.
74
+ Procure por esse `await`: é o que o compilador não procura. Uma prova que só cita a acessibilidade
75
+ e não olha os call sites do runner cobriu metade da afirmação.
76
+ - **Teste que toca API paga.** Uma chave de API num teste é uma fatura por execução de CI e um teste
77
+ que fica vermelho quando o provedor tem incidente. `grep` por chave, host do provedor e leitura de
78
+ ambiente nos arquivos de teste tem de voltar vazio.
79
+ - **Aceitar o número de testes sem a suíte inteira.** "Derruba 4" medido sobre um arquivo e "derruba
80
+ 4 de 203" são afirmações diferentes. Só a suíte inteira autoriza a frase.
81
+ - **Declarar as quatro afirmações numa feature que não gera mídia.** A isenção é automática: se
82
+ nenhuma task pina um standard de mídia, a seção não é exigida. Escrever a seção "por precaução"
83
+ gasta o Gate 3 com cerimônia vazia, que é como uma regra vira ruído e depois é desligada.
84
+
85
+ ## Como registrar no relatório
86
+
87
+ Na seção `## Mídia gerada` do `evaluator-report.md`, uma linha por afirmação, com os quatro campos:
88
+
89
+ ```markdown
90
+ ## Mídia gerada
91
+
92
+ | Afirmação | Onde está presa (arquivo:linha) | Teste que a prova | Rodada de mutação |
93
+ |---|---|---|---|
94
+ | Custo | src/…/MediaGenerator.cs:88 (reserva ANTES da chamada) | MediaGeneratorTests.ABudgetOverrun… | — |
95
+ | Revisão humana | src/…/MediaJob.cs:… (Publish só de Approved) | MediaJobStateTests.PublishFails… (6 estados) | — |
96
+ | Marcação | src/…/MediaJob.cs:… (3ª porta de Publish) + MediaDisclosure.cs | MediaDisclosureTests.PublishFailsWithoutADisclosure… | porta removida → 2 de 220 caem, motivo lido, md5 restaurado |
97
+ | Hot path | src/…/IMediaProvider.cs (internal) | MediaAccessibilityTests.TheTypeThat… | público → 4 de 220 caem, motivo lido, md5 restaurado |
98
+ ```
99
+
100
+ E a linha machine-readable, no mesmo estilo do `**Composite-Score:**`, junto das demais provas:
101
+
102
+ ```
103
+ **Proof-Scores:** mutation=9 verde=8 fiacao=9 guard=7 media=9
104
+ ```
105
+
106
+ **A chave `media` só entra quando a feature gera mídia.** Feature que não pina nenhum standard de
107
+ mídia não declara a seção e não declara a chave — e o gate não a cobra. Feature que gera mídia **sem
108
+ a seção** pausa o Gate 3 por conta própria (`src/lib/risk-detector.js`), antes de qualquer discussão
109
+ de nota.
@@ -0,0 +1,77 @@
1
+ # Prova: Mutação
2
+
3
+ > Escopo: Gate 3 (avaliador independente). Não é dimensão do score composto — o composto continua
4
+ > `arquitetura + contratos + qualidade + testes`. Esta prova impõe **teto** em Cobertura de Testes
5
+ > (tabela em `evals/rubrics/test-coverage.md`, seção "Tetos de prova").
6
+
7
+ ## O que esta prova responde
8
+
9
+ Um teste verde prova que o código roda. Só a **mutação** prova que o teste MORDE: quebre de
10
+ propósito a linha que carrega a decisão e veja quem grita. Se ninguém grita, a suíte é decoração —
11
+ e foi assim que 11 testes verdes cobriram um artefato que o build recusava.
12
+
13
+ A pergunta desta rubrica é sempre a mesma: **você mutou o call site que carrega a decisão, rodou a
14
+ suíte inteira, leu o MOTIVO da falha, e devolveu o arquivo byte a byte?**
15
+
16
+ ## Bandas 0-10
17
+
18
+ | 0-3 | 4-6 | 7-8 | 9-10 |
19
+ |---|---|---|---|
20
+ | Nenhuma mutação. Ou mutação declarada sem diff, sem md5 e sem testes nomeados — afirmação, não prova. Ou revert por `git checkout --`, que descarta trabalho não commitado de terceiros | Mutou, mas no lugar errado (o `if` refatorado, não o call site que decide) ou com filtro estreito ("derrubou 3" medido sobre 40 testes de um arquivo só). Reportou md5 sem ler o motivo da falha | Mutação no call site certo, suíte inteira, diff e md5 antes/depois. Falta o MOTIVO literal da falha, ou uma cláusula de um predicado composto ficou sem rodada própria | Uma rodada por cláusula, cada uma com arquivo:linha, diff, md5 antes/depois, contagem sobre a suíte INTEIRA e a mensagem literal de falha. Revert por snapshot de bytes + `os.utime`, com `git status --porcelain src/` vazio ao fim |
21
+
22
+ ## Anti-padrões literais
23
+
24
+ - **Mutar o `if` refatorado em vez do call site que carrega a decisão** — o extract-method moveu a
25
+ regra; o teste continua batendo no invólucro. Ancore onde o valor é DECIDIDO. (memória: guard do
26
+ remédio, cuja checagem real vivia duas camadas acima do `if` mutado)
27
+ - **Rodar com filtro e reportar "derruba N"** — "3 de 40" e "3 de 2684" são afirmações diferentes.
28
+ Só a suíte **inteira** autoriza a frase "derruba N". (memória: F30, filtro no Gate 3)
29
+ - **Filtro tão estreito que a prova fica vácua** — mutar e rodar só o teste que você já sabia que
30
+ quebraria não testa nada além da sua própria expectativa.
31
+ - **Aceitar um seed sem perguntar "que sequência real produz este seed?"** — fixture que só existe
32
+ no teste prova o teste, não o sistema.
33
+ - **Imprimir `diff` + md5 e parar por aí** — md5 prova que ALGO mudou, nunca O QUÊ. Sem a mensagem
34
+ literal de falha (`expected 3, got 0` em `x.test.js:88`), a prova é de que o arquivo mudou, não de
35
+ que o teste morde a regra. (memória: três rodadas de correção nesta epic)
36
+ - **Reverter por replace reverso, ou por `git checkout --`** — o replace reverso erra em arquivo com
37
+ ocorrências repetidas; o `git checkout --` **apaga alterações não commitadas de outra pessoa** e
38
+ aconteceu de verdade num Gate 3 desta epic. Reverta por **snapshot/restore de bytes** (cópia feita
39
+ ANTES) + `os.utime` para devolver o mtime, e confirme por `md5sum`.
40
+ - **Escrever a mutação por heredoc do shell quando ela contém barra invertida** — o transporte come
41
+ o escape: `\b` vira o byte `0x08`, `\n` vira quebra de linha real, e o regex mutado **não é o que
42
+ você escreveu**. Sintoma: a mutação parece aplicada e o resultado não muda, ou o arquivo quebra
43
+ num ponto que você não tocou. Diagnóstico em um comando: `cat -A` mostra `^H` onde devia estar
44
+ `\b`. Saída: patch por **índice de linha** com o conteúdo montado sem barra invertida no fonte
45
+ (`String.fromCharCode(92)`), ou ferramenta de edição estrutural — nunca heredoc.
46
+ (memória: **três agentes** desta epic tropeçaram nisto; dois descartaram o resultado, um só
47
+ descobriu ao conferir os bytes)
48
+ - **Mutar antes de commitar o fix** — se a sessão morrer no meio, o que sobrevive é a mutação, não a
49
+ correção. **Commite o fix ANTES de mutar**, sempre.
50
+ - **Ler mais do que a primeira assertiva que falha** — a mutação só prova até ali; o resto do teste
51
+ nem rodou. Não conte cobertura que a mutação não exercitou.
52
+ - **Uma rodada só para um predicado `A && B`** — derrubar `A` não diz nada sobre `B`. **Uma rodada
53
+ por cláusula.** O mesmo vale para um guard de duas classes: toque **cada** classe.
54
+ - **Deixar loader, validador e superfície de publicação fora do alvo** — o defeito costuma estar em
55
+ quem LÊ o arquivo, não em quem o escreve. (memória: 11 testes verdes contra o render do próprio
56
+ gerador, nenhum deles CARREGANDO o artefato)
57
+ - **Fixture fora da ordem de grandeza da tese** — tese sobre 2 600 testes provada num fixture de 3.
58
+ - **Mutação de prosa presa por regex** — texto de skill/rubrica não se prende por `assert.match` de
59
+ vocabulário: mude a FORMA (mova a seção, troque o cabeçalho) e veja se o canário ainda morde.
60
+ - **Número de mutação sem SHA e sem data** — "derruba 12" envelhece em uma semana. Anote o SHA
61
+ revisado e a data ao lado do número.
62
+ - **Terminar sem `git status --porcelain src/` vazio** — mutação esquecida em produção é o pior
63
+ desfecho possível deste método, e já aconteceu com avaliador morto no meio da rodada.
64
+
65
+ ## Como registrar no relatório
66
+
67
+ Na seção `## Mutações` do `evaluator-report.md`, uma linha por mutação, com os cinco campos:
68
+
69
+ ```markdown
70
+ | # | Arquivo:linha | Mutação (diff) | md5 antes | md5 depois | Testes derrubados | Motivo da falha |
71
+ |---|---|---|---|---|---|---|
72
+ | M1 | src/lib/x.js:42 | `- if (a && b)` / `+ if (a)` | abc… | def… | 3 de 2684 | `expected 3 got 0` em x.test.js:88 |
73
+ ```
74
+
75
+ E, ao fim da seção: **Reversão:** snapshot/restore de bytes + `os.utime`; `git status --porcelain
76
+ src/` vazio. Feature sem código de produção declara a seção com a linha
77
+ `não aplicável — feature sem código de produção`.
@@ -0,0 +1,119 @@
1
+ # Prova: Observabilidade GenAI
2
+
3
+ > Escopo: Gate 3 (avaliador independente). Não é dimensão do score composto — impõe **teto** em
4
+ > Qualidade de Código (`evals/rubrics/code-quality.md`, seção "Teto de prova de observabilidade
5
+ > GenAI"). Aplica-se **somente** a feature que chama LLM; feature sem LLM é `not_evaluated`, e
6
+ > `not_evaluated` **não** aplica teto.
7
+
8
+ ## O que esta prova responde
9
+
10
+ Uma feature que chama um modelo gasta dinheiro, pode falhar de formas que nenhum teste cobre, e
11
+ produz texto que ninguém revisou. A pergunta que importa depois do incidente é sempre a mesma, e
12
+ raramente tem resposta:
13
+
14
+ **Dá para reconstruir o que foi ao provedor, e o que ele respondeu, neste turno?**
15
+
16
+ Repare no que a pergunta **não** é. Ela não é "tem span OpenTelemetry?". Essa formulação foi medida
17
+ contra o acervo e reprova **5 de 5** repositórios — e, pior, daria a mesma nota a um projeto cuja
18
+ observabilidade inteira é a mensagem da exceção e a outro que tem hash por bloco de prompt, vocabulário
19
+ fechado de desfecho de tool, veredito ternário de guard, sete testes provando que a telemetria é
20
+ inerte, e a invariante escrita de que o texto enviado é derivado sem cache *"para a telemetria não
21
+ poder mentir"*. **Régua que pune o melhor aluno não é régua.**
22
+
23
+ Span com as convenções GenAI é a forma **recomendada** (`ai-agents-observability-patterns`) e alcança
24
+ a faixa mais alta. Telemetria própria também alcança — desde que exista **teste de fidelidade**, isto
25
+ é, algo que prove que o registrado é o enviado. O que a rubrica cobra é o **resultado**; o standard é
26
+ quem recomenda o meio.
27
+
28
+ ### Aplicabilidade — filtro mecânico, e depois uma determinação nomeada
29
+
30
+ **Esta rubrica NÃO se declara determinística, e a razão é medida:** nenhuma leitura de `tasks.json`
31
+ ou do `mandate.md` mede a propriedade que importa — *esta feature entrega código que chama um
32
+ modelo?*. A versão anterior deste bloco prometia determinismo e **errou no primeiro cliente que
33
+ encontrou**: a própria feature que criou esta rubrica satisfazia as duas condições (tasks com
34
+ `group: "tests"`, mandate citando `ai-agents` dez vezes) e não chama LLM nenhum.
35
+
36
+ São **duas etapas**, e a segunda não é opcional:
37
+
38
+ **1. Filtro mecânico, de alta recall** (barato, lido do disco):
39
+
40
+ > o `mandate.md` cita ao menos um standard `ai-agents`.
41
+
42
+ Falso ⇒ `not_evaluated`, sem mais discussão. É deliberadamente **largo**: erra para o lado de
43
+ convocar a determinação, não para o de dispensá-la.
44
+
45
+ **2. Determinação, escrita pelo avaliador.** Passado o filtro, a pergunta é
46
+ *a feature entrega código que chama um modelo?* — e o relatório **registra a resposta com o motivo**:
47
+
48
+ ```markdown
49
+ - Aplicabilidade: LLM SIM — T4 acrescenta `TriagemAgent` sobre `IChatClient` (`AgentCatalog.cs:31`).
50
+ - Aplicabilidade: `not_evaluated` — o mandate cita `ai-agents`, mas o diff é 100% markdown de
51
+ standard; nenhuma chamada a modelo entra no produto.
52
+ ```
53
+
54
+ **Sinal auxiliar, não determinação:** toda task com `group` em `{docs, tests}` é indício **contra**
55
+ código de produção que chama modelo. Indício, porque um harness de agente pode viver inteiro numa
56
+ task `tests` — por isso ele informa a determinação em vez de substituí-la.
57
+
58
+ **Um `not_evaluated` sem motivo escrito não é dispensa: é o escape que o standard
59
+ `ai-agents-guardrails` proíbe.** O motivo é o que torna a decisão auditável na revisão seguinte, e é o que impede que
60
+ `not_evaluated` vire a saída fácil.
61
+
62
+ ## Bandas 0-10
63
+
64
+ | 0-3 | 4-6 | 7-8 | 9-10 |
65
+ |---|---|---|---|
66
+ | A feature chama LLM e **nada** permite saber o que foi enviado, quanto custou, ou se falhou. Observabilidade é a mensagem da exceção | Chamada de LLM registrada **só por log de texto**: sem contagem de tokens, sem correlação com a feature ou a requisição, sem forma de amarrar o registro ao turno | Instrumentação presente e correta — mas a evidência no relatório é a **linha de wiring**, não a saída. O avaliador leu o `AddSource`, não leu um span | Span por chamada com `gen_ai.operation.name` e `gen_ai.provider.name`, tokens registrados, correlação com a feature, e sensível desligado fora de dev — **ou** telemetria própria equivalente cuja fidelidade tem teste. Nos dois casos, o relatório **mostra um span ou registro capturado** |
67
+
68
+ A fronteira que decide 7-8 × 9-10 é uma só, e é a mesma de toda rubrica desta classe: **evidência
69
+ capturada, não evidência declarada.** Ler o código que instrumenta prova que alguém escreveu o
70
+ wiring; ler um span prova que ele emite.
71
+
72
+ ## Anti-padrões literais
73
+
74
+ - **Pontuar o wiring como se fosse a saída** — `builder.AddSource(...)` no diff é 7-8, nunca 9-10.
75
+ Para subir, capture: rode o caminho, pegue **um** span ou **uma** linha de registro, e cole no
76
+ relatório com os atributos que ela carrega.
77
+ - **Aceitar "temos logs"** — log de texto sem tokens e sem correlação é banda 4-6. A pergunta
78
+ operacional é "quanto custou este turno e o que foi enviado nele"; um log que não responde nenhuma
79
+ das duas não é observabilidade, é rastro.
80
+ - **Reprovar telemetria própria por não ser OpenTelemetry** — a rubrica cobra a propriedade. Um
81
+ registro próprio com **teste de fidelidade** vale 9-10. Sem teste de fidelidade, não vale: é uma
82
+ afirmação sobre o que o código faz, feita pelo mesmo código.
83
+ - **Aceitar hash sem a invariante** — um hash do prompt só prova algo se o texto de que ele é hash
84
+ **é** o texto enviado. Se existe cache entre a montagem e o envio, telemetria e requisição podem
85
+ divergir em silêncio. Procure a derivação sem cache; sem ela, o hash é decoração e a nota não passa
86
+ de 6.
87
+ - **Prompt cru em produção contado como ponto a favor** — é o oposto: dado sensível persistido é
88
+ achado, não evidência. Cru só em dev ou harness, com opt-in; em produção, hash.
89
+ - **Confundir "não tem LLM" com "tem e não instrumentou"** — o primeiro é `not_evaluated` e **não**
90
+ aplica teto; o segundo é 0-3. Colapsar os dois num booleano é o mesmo defeito que o veredito
91
+ ternário de `ai-agents-guardrails` existe para impedir.
92
+ - **Aplicar teto sem ter avaliado** — sem a linha da chave `obs` no `**Proof-Scores:**` não há teto a
93
+ aplicar. Um teto inventado a partir de impressão é pior que teto nenhum.
94
+ - **Pontuar telemetria de turno cancelado como cobertura** — registro de algo que não aconteceu é
95
+ achado, não evidência.
96
+
97
+ ## Como registrar no relatório
98
+
99
+ Uma linha dizendo o que foi capturado e como, e — quando a nota for 9-10 — o artefato capturado:
100
+
101
+ ```markdown
102
+ - Aplicabilidade: filtro passou (mandate cita `ai-agents-cost-and-budget`); determinação: LLM SIM — T4 acrescenta `TriagemAgent` sobre `IChatClient` (`AgentCatalog.cs:31`).
103
+ - Capturado 1 span de `Morph.Agents.Triagem` rodando o caminho real com o fake:
104
+ `chat gpt-5-mini` · gen_ai.operation.name=chat · gen_ai.provider.name=openai ·
105
+ gen_ai.usage.input_tokens=1841 · output_tokens=212 · morph.feature=triagem-lead
106
+ - Fidelidade: `PromptDecompositionTests.TextoEnviadoEhAConcatenacaoDosBlocos` prova que o hash
107
+ registrado é o do texto enviado (derivação sem cache).
108
+ - EnableSensitiveData=false confirmado fora de dev (`appsettings.Production.json`).
109
+ ```
110
+
111
+ E no `**Proof-Scores:**`, a chave `obs`.
112
+
113
+ Quando não se aplica, uma linha basta — e ela precisa dizer **o que** foi determinado, e por quê. Um `not_evaluated` mudo não é dispensa:
114
+
115
+ ```markdown
116
+ - Observabilidade GenAI: `not_evaluated` — o filtro passou (o mandate cita `ai-agents`), mas o
117
+ diff é 100% markdown de standard: nenhuma chamada a modelo entra no produto. Sem teto sobre
118
+ code-quality.
119
+ ```
@@ -0,0 +1,48 @@
1
+ # Prova: Verde Não É Coberto
2
+
3
+ > Escopo: Gate 3 (avaliador independente). Não é dimensão do score composto — impõe **teto** em
4
+ > Cobertura de Testes (`evals/rubrics/test-coverage.md`, seção "Tetos de prova").
5
+
6
+ ## O que esta prova responde
7
+
8
+ Um teste que **nasce verde** nunca teve fase RED: ele afirma uma pós-condição que o backend já
9
+ garantia antes da mudança. Ele não está errado — está **vazio**. E é indistinguível, no relatório de
10
+ execução, de um teste que protege alguma coisa.
11
+
12
+ A pergunta é: **qual asserção deste teste teria falhado ANTES da mudança?** Se nenhuma, o teste
13
+ documenta, não cobre — e isso precisa estar **declarado**, não escondido no verde.
14
+
15
+ ## Bandas 0-10
16
+
17
+ | 0-3 | 4-6 | 7-8 | 9-10 |
18
+ |---|---|---|---|
19
+ | Testes novos apresentados como cobertura sem que nenhum tenha tido fase RED. Pré-condições afirmadas em prosa/comentário, nunca medidas | Alguns testes nascem verdes e isso não é declarado. `DoesNotContain` de um item só, deixando os irmãos abertos | O relatório reconhece pelo enunciado quais testes nascem verdes e os declara. Falta a asserção positiva no campo novo ao lado do `DoesNotContain` | Cada teste que nasce verde está declarado como tal, com o motivo. Pré-condições medidas (`Assert.NotNull`), listas EXATAS em vez de negativas pontuais, e mudança de semântica coberta pelo par positivo+negativo |
20
+
21
+ ## Anti-padrões literais
22
+
23
+ - **Pós-condição que o backend já garante apresentada como cobertura nova** — a fase RED não
24
+ aconteceu. Reconheça pelo ENUNCIADO ("o campo X nunca vem nulo" num campo `NOT NULL` desde a
25
+ migração) e **declare no relatório**. (memória: pós-condição verde-de-nascença numa feature cujo
26
+ contrato já a garantia no schema)
27
+ - **Comentário que afirma um fato em vez de asserção** — `// aqui o id já existe` não falha nunca.
28
+ Comentário que afirma fato vira asserção **ou some**.
29
+ - **`DoesNotContain` de UM item** — provar que "banana" sumiu deixa "maçã" e "pera" livres. Quando o
30
+ contrato é "só isto e nada mais", asserte a **lista exata**.
31
+ - **Pré-condição afirmada em prosa** — "o registro existe neste ponto" precisa ser
32
+ `Assert.NotNull(x)`. Sem isso, um teste que passa por vacuidade (coleção vazia, nulo silencioso)
33
+ se lê como verde legítimo.
34
+ - **Mudar semântica e asserir só o lado novo** — ao trocar o texto/o campo, o par é obrigatório:
35
+ asserção **positiva** no campo novo **e** `DoesNotContain` do texto substituído. Sem o negativo, o
36
+ teste passa com os dois presentes.
37
+
38
+ ## Como registrar no relatório
39
+
40
+ Na seção de análise de cobertura, uma linha por teste que nasce verde:
41
+
42
+ ```markdown
43
+ - `test/x.test.js:41` — nasce VERDE: a pós-condição P3 já era garantida pelo `NOT NULL` da coluna
44
+ desde a migração 0007. Documenta, não cobre. Não conta para a faixa 9-10 de Cobertura.
45
+ ```
46
+
47
+ E no `**Proof-Scores:**`, a chave `verde`. Um relatório que não distingue "cobre" de "documenta"
48
+ não pode passar de 8 nesta prova, por mais testes que tenha.
@@ -71,3 +71,33 @@ que o mandate não as mencione explicitamente. Uma violação em qualquer uma de
71
71
  `AddTransient` correspondente em `Program.cs`?
72
72
  7. Se o diff tem chamada server-direct ao backend E chamada client-side via proxy para o mesmo
73
73
  recurso, elas usam duas constantes de prefixo distintas — nenhuma reusada para o outro propósito?
74
+
75
+ ## Tetos de prova de mídia (Gate 3)
76
+
77
+ Quando — e **somente** quando — a feature gera mídia (alguma task de `tasks.json` cita, em
78
+ `standards[]`, um dos três standards de mídia de `ai-agents/`), o avaliador independente também
79
+ aplica `.morph/framework/evals/proof-rubrics/media-claims.md` e grava ` media={n}` na linha
80
+ `**Proof-Scores:**`.
81
+
82
+ Ela **não** é uma quinta dimensão do composto — nenhum peso muda por causa dela. Ela entra aqui,
83
+ como teto sobre esta dimensão, pelo mesmo mecanismo do teto de prova em Cobertura.
84
+
85
+ **Por que aqui e não em Cobertura:** as quatro afirmações que ela cobra — custo, revisão humana,
86
+ marcação, hot path não bloqueado — são **propriedades estruturais**: onde a chamada mora, que
87
+ estados existem, o que é persistido, o que é publicado. Uma feature que gera mídia dentro do turno
88
+ de conversa está arquiteturalmente errada, não mal testada. E há uma consequência técnica: o `min`
89
+ que limita Cobertura é calculado sobre a lista explícita das quatro provas de evidência, com `media`
90
+ **fora** dela — senão um `media=4` derrubaria o teto de teste por um motivo que não tem nada a ver
91
+ com teste.
92
+
93
+ | Proof-Score de media | teto nesta dimensão |
94
+ |---|---|
95
+ | 9 a 10 | sem teto |
96
+ | 7 a 8 | 8 |
97
+ | 4 a 6 | 6 |
98
+ | 0 a 3 | 3, e o item entra como **bloqueante** listado no relatório |
99
+
100
+ Sem a chave `media`, não há teto a aplicar. Mas a ausência da seção `## Mídia gerada` num relatório
101
+ de feature que gera mídia **pausa o Gate 3** por conta própria (`src/lib/risk-detector.js`), antes
102
+ de qualquer discussão de nota. Feature que não gera mídia é isenta automaticamente — a chave não
103
+ aparece e o sinal é falso.
@@ -57,6 +57,32 @@ Avalia naming, ausência de code smells e aderência aos padrões do stack do pr
57
57
  > `reuse`. Um símbolo criado contra um veredito `REUSAR` é achado desta
58
58
  > dimensão, mesmo que o código esteja impecável por dentro.
59
59
 
60
+ ## Teto de prova de observabilidade GenAI
61
+
62
+ Quando a feature **chama LLM**, o avaliador aplica também
63
+ `.morph/framework/evals/proof-rubrics/observabilidade-genai.md` e grava a nota sob a chave `obs` na
64
+ linha `**Proof-Scores:**`. Ela **não** é dimensão do composto — nenhum peso muda — e entra aqui como
65
+ teto sobre esta dimensão:
66
+
67
+ | Proof-Score `obs` | teto nesta dimensão |
68
+ |---|---|
69
+ | 9 a 10 | sem teto |
70
+ | 7 a 8 | 9 |
71
+ | 4 a 6 | 7 |
72
+ | 0 a 3 | 5 |
73
+
74
+ A rubrica pergunta a **propriedade** ("dá para reconstruir o que foi ao provedor, e o que ele
75
+ respondeu, neste turno?"), não a tecnologia: telemetria própria com teste de fidelidade alcança a
76
+ faixa mais alta tanto quanto um span OpenTelemetry.
77
+
78
+ **Aplicabilidade tem duas etapas, e ela NÃO se declara determinística** (a versão anterior se
79
+ declarava, e errava na primeira feature que encontrou): (1) **filtro mecânico de alta recall** — o
80
+ `mandate.md` cita ao menos um standard `ai-agents`; falso ⇒ `not_evaluated`. (2) **determinação
81
+ escrita pelo avaliador** — a feature entrega código que **chama um modelo**? — registrada **com o
82
+ motivo** no relatório. Tasks com `group` em `{docs, tests}` são **indício** contra, não veredito.
83
+ `not_evaluated` **não aplica teto**, e um `not_evaluated` sem motivo escrito não é dispensa. Sem a
84
+ chave `obs` no `**Proof-Scores:**`, também não há teto a aplicar.
85
+
60
86
  ## Perguntas de avaliação
61
87
 
62
88
  1. É possível entender o que uma função faz apenas pelo seu nome e assinatura?
@@ -58,3 +58,23 @@ Avalia se os testes cobrem os comportamentos esperados, são isolados e têm nom
58
58
  min; o fecho de um fail-open abriu um P1; a correção desse P1 saiu com meio predicado. Nenhuma
59
59
  apareceu no score, porque score não pergunta isso. **Sem resposta a esta pergunta numa correção,
60
60
  o teto de Cobertura é 8.**
61
+
62
+ ## Tetos de prova (Gate 3)
63
+
64
+ No Gate 3 o avaliador independente pontua **a própria evidência** 0-10 nas cinco rubricas de
65
+ `.morph/framework/evals/proof-rubrics/` (`mutation-proof.md`, `verde-nao-e-coberto.md`,
66
+ `fiacao.md`, `guard-cego.md`, `eval-de-modelo.md`) e grava a linha `**Proof-Scores:**` no `evaluator-report.md`.
67
+
68
+ Elas **não** são dimensões do composto — nenhum peso muda por causa delas. Elas entram aqui, como
69
+ teto sobre esta dimensão, pelo mesmo mecanismo que "pós-condição sem teste impede a faixa 9-10":
70
+
71
+ | menor Proof-Score das cinco | teto nesta dimensão |
72
+ |---|---|
73
+ | 9 a 10 | sem teto |
74
+ | 7 a 8 | 8 |
75
+ | 4 a 6 | 6 |
76
+ | 0 a 3 | 3, e o item entra como **bloqueante** listado no relatório |
77
+
78
+ Sem a linha `**Proof-Scores:**`, não há teto a aplicar — mas a ausência da seção `## Mutações` num
79
+ relatório de feature com código de produção **pausa o Gate 3** por conta própria
80
+ (`src/lib/risk-detector.js`), antes de qualquer discussão de nota.
@@ -8,7 +8,11 @@ Comprehensive hooks system for enforcing spec-driven development at the Claude C
8
8
  framework/hooks/
9
9
  ├── claude-code/ # Claude Code native hooks
10
10
  │ ├── core/
11
- │ │ └── worktree-context.js # SessionStart: worktree feature identity / active-feature summary
11
+ │ │ ├── worktree-context.js # SessionStart: worktree feature identity / active-feature summary
12
+ │ │ ├── worktree-create.js # WorktreeCreate: governed tree via `morph-spec worktree setup|provision`
13
+ │ │ ├── worktree-remove.js # WorktreeRemove: safe teardown via `worktree remove --if-clean`
14
+ │ │ ├── block-destructive-worktree-removal.js # PreToolUse(Bash): raw removal follows junctions out
15
+ │ │ └── block-raw-worktree-add.js # PreToolUse(Bash): raw `git worktree add` is ungoverned
12
16
  │ ├── user-prompt/
13
17
  │ │ └── enrich-prompt.js # Context-aware prompt enrichment
14
18
  │ ├── pre-tool-use/
@@ -46,6 +50,10 @@ framework/hooks/
46
50
  | **PreToolUse** (Write\|Edit) | protect-spec-files.js | Block | Blocks edits to spec files after approval; for tasks.json validates the mutable-field diff, the status enum, and requires a `notes` when `outputs` diverge from the plan |
47
51
  | **PreToolUse** (Write\|Edit) | enforce-phase-writes.js | Block | Ensures writes go to current phase directory |
48
52
  | **PreToolUse** (Bash) | pre-bash-denylist.js | Block | Blocks `rm -rf .morph/` and direct state edits |
53
+ | **PreToolUse** (Bash) | block-destructive-worktree-removal.js | Block | Blocks `git worktree remove` / `rm -rf` / `Remove-Item -Recurse` on a directory holding reparse points (the infra junctions a raw removal would FOLLOW out, emptying the root's `.claude/`); names `morph-spec worktree remove` |
54
+ | **PreToolUse** (Bash) | block-raw-worktree-add.js | Block | Blocks raw `git worktree add` (a tree with no junctions → no hooks, no port block, no identity, outside `worktrees/`); names `morph-spec worktree setup <feature>` / `worktree provision <name> --base <ref>`. `list`/`prune`/`remove`/`lock`/`move`/`repair` pass |
55
+ | **WorktreeCreate** | worktree-create.js | Replaces native | Fires for `claude -w`, EnterWorktree and `Agent isolation:"worktree"`; replaces Claude Code's bare `git worktree add`. Runs `morph-spec worktree setup <n>` (known feature) or `worktree provision <n>` (task tree, branch `morph-task/<n>`), honours `worktree.baseRef:"head"`, prints the path as its last stdout line. CLI unreachable → plain git, still under `<root>/worktrees/` |
56
+ | **WorktreeRemove** | worktree-remove.js | Fail-open | Routes Claude Code's own cleanup through `morph-spec worktree remove --target --if-clean` (junctions dropped first; a dirty tree is left alone). Always exit 0. Secondary net — the event was observed NOT to fire headless; the Bash guard above stays the primary defense |
49
57
  | **PostToolUse** (Write\|Edit) | post-edit-typecheck.js | Advisory | Debounced `tsc --noEmit` after TS/TSX edits; silent on success. Also touches `.morph/memory/build-dirty.json` on every source-file edit — the write side of validate-completion.js's Stop-hook build-dirty gate |
50
58
  | **PostToolUse** (Write\|Edit) | tasks-json-guard.js | Advisory | Validates the written tasks.json schema (status/effort enums); warns so the LLM fixes it immediately |
51
59
  | **PostToolUse** (Write\|Edit) | trace-autogen.js | State sync | Auto-generates `.morph/traces/YYYY-MM-DD-{feature}-implement.json` from tasks.json + recap.md + taskScores on every tasks.json write — the skills never write traces by hand |
@@ -115,6 +123,8 @@ All Claude Code hooks import from `framework/hooks/shared/`:
115
123
  | `hook-response.js` | `block(reason)`, `approve(context)`, `injectContext(text)`, `pass()` |
116
124
  | `stdin-reader.js` | `readStdin()` — Promise-based stdin JSON reader |
117
125
  | `telemetry-logger.js` | `appendTelemetryEvent()`, `readTelemetryEvents()` — append-only JSONL event stream (`.morph/logs/events.jsonl`) |
126
+ | `morph-cli.js` | `runMorphSpec(args, { cwd, timeoutMs, env })` — spawns the morph-spec CLI from a hook (`MORPH_SPEC_BIN` → `morph-spec` on PATH → `npx --no-install`); `unavailable: true` when none resolves, never a throw. Hooks may never import from `src/` |
127
+ | `command-tokens.js` | `tokenize(command)` — quote-aware shell tokenizer shared by the Bash guards (a hook must never import a sibling hook: its standalone tail would fire) |
118
128
 
119
129
  `injectContext(text)` is how `worktree-context.js` (and any other SessionStart hook) delivers context: it emits `{ "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": text } }` on stdout. Claude Code only honors additional context nested under `hookSpecificOutput` — a bare top-level field is ignored.
120
130
 
@@ -4,6 +4,7 @@ import { resolve, isAbsolute } from 'path';
4
4
  import { blockResult, runStandalone } from '../../shared/hook-response.js';
5
5
  import { stateExists } from '../../shared/state-reader.js';
6
6
  import { scanForBlockers } from '../../shared/reparse-scan.js';
7
+ import { tokenize } from '../../shared/command-tokens.js';
7
8
 
8
9
  /**
9
10
  * block-destructive-worktree-removal — the only defense that does not depend on
@@ -32,14 +33,10 @@ import { scanForBlockers } from '../../shared/reparse-scan.js';
32
33
  * nothing to traverse is not blocked for looking dangerous.
33
34
  */
34
35
 
35
- /** Split a shell-ish command into tokens, honoring single and double quotes. */
36
- function tokenize(command) {
37
- const tokens = [];
38
- const re = /"([^"]*)"|'([^']*)'|(\S+)/g;
39
- let m;
40
- while ((m = re.exec(command)) !== null) tokens.push(m[1] ?? m[2] ?? m[3]);
41
- return tokens;
42
- }
36
+ // The tokenizer lives in shared/command-tokens.js — block-raw-worktree-add.js
37
+ // reads `git worktree add` off the same tokens, and a hook must never import a
38
+ // sibling hook (its standalone tail would fire in the importer's process).
39
+ export { tokenize };
43
40
 
44
41
  /**
45
42
  * The path a recursive-removal command would destroy, or null when this is not