@polymorphism-tech/morph-spec 8.34.2 → 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 (325) hide show
  1. package/CLAUDE.md +20 -3
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +18 -4
  4. package/bin/validate.js +379 -379
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +5 -4
  7. package/docs/QUICKSTART.md +1 -1
  8. package/framework/MORPH.md +16 -17
  9. package/framework/agents.json +197 -44
  10. package/framework/ai-pin.json +22 -0
  11. package/framework/commands/morph-media.md +45 -0
  12. package/framework/docs/CLI.md +234 -9
  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/claude-code/core/protect-spec-files.js +41 -4
  25. package/framework/hooks/claude-code/statusline.sh +11 -11
  26. package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
  27. package/framework/hooks/git/pre-commit/agents.sh +25 -25
  28. package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
  29. package/framework/hooks/git/pre-commit/specs.sh +50 -50
  30. package/framework/hooks/git/pre-push/run-tests.sh +44 -44
  31. package/framework/hooks/shared/e2e-check.js +135 -22
  32. package/framework/hooks/shared/stdin-reader.js +26 -26
  33. package/framework/rules/ai-agents-standards.md +14 -2
  34. package/framework/schemas/ai-pin.schema.json +97 -0
  35. package/framework/schemas/config.schema.json +107 -0
  36. package/framework/schemas/feature.schema.json +23 -4
  37. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  38. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  39. package/framework/skills/core/morph-apply/SKILL.md +26 -5
  40. package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
  41. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  42. package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
  43. package/framework/skills/core/morph-implement/SKILL.md +18 -2
  44. package/framework/skills/core/morph-media/SKILL.md +215 -0
  45. package/framework/skills/core/morph-plan/SKILL.md +33 -2
  46. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  47. package/framework/skills/core/morph-review/SKILL.md +166 -9
  48. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  49. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  50. package/framework/skills/core/morph-uiux/SKILL.md +1 -1
  51. package/framework/standards/PROVENANCE.json +81 -3
  52. package/framework/standards/STANDARDS.json +1483 -839
  53. package/framework/standards/ai-agents/agent-archetypes.md +160 -0
  54. package/framework/standards/ai-agents/agent-session.md +164 -68
  55. package/framework/standards/ai-agents/agent-spec.md +196 -0
  56. package/framework/standards/ai-agents/batching.md +61 -37
  57. package/framework/standards/ai-agents/context-providers.md +97 -24
  58. package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
  59. package/framework/standards/ai-agents/cost-and-budget.md +256 -0
  60. package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
  61. package/framework/standards/ai-agents/evals-with-cache.md +289 -0
  62. package/framework/standards/ai-agents/guardrails.md +222 -0
  63. package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
  64. package/framework/standards/ai-agents/mcp-server.md +119 -18
  65. package/framework/standards/ai-agents/mcp-tools.md +85 -32
  66. package/framework/standards/ai-agents/media-pipeline.md +352 -0
  67. package/framework/standards/ai-agents/media-video.md +267 -0
  68. package/framework/standards/ai-agents/middleware-patterns.md +39 -5
  69. package/framework/standards/ai-agents/modalities-image-gen.md +354 -105
  70. package/framework/standards/ai-agents/modalities-speech-to-text.md +8 -2
  71. package/framework/standards/ai-agents/modalities-text-to-speech.md +10 -2
  72. package/framework/standards/ai-agents/modalities-vision.md +6 -2
  73. package/framework/standards/ai-agents/multi-agent-patterns.md +61 -5
  74. package/framework/standards/ai-agents/observability-patterns.md +227 -17
  75. package/framework/standards/ai-agents/production.md +38 -9
  76. package/framework/standards/ai-agents/prompt-sources.md +389 -0
  77. package/framework/standards/ai-agents/providers/model-registry.md +174 -39
  78. package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
  79. package/framework/standards/ai-agents/service-tier-flex.md +27 -19
  80. package/framework/standards/ai-agents/setup.md +166 -50
  81. package/framework/standards/ai-agents/structured-output.md +34 -3
  82. package/framework/standards/ai-agents/sweet-spot.md +23 -3
  83. package/framework/standards/ai-agents/testing-ai.md +236 -0
  84. package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
  85. package/framework/standards/ai-agents/workflows.md +27 -7
  86. package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
  87. package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
  88. package/framework/standards/infrastructure/docker/local-compose-isolation.md +3 -1
  89. package/framework/templates/.idea/morph-templates.xml +92 -0
  90. package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
  91. package/framework/templates/IDE-SNIPPETS.md +262 -262
  92. package/framework/templates/REGISTRY.json +13 -0
  93. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
  94. package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -39
  95. package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -68
  96. package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -117
  97. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +1 -1
  98. package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -61
  99. package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -107
  100. package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -58
  101. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +281 -281
  102. package/framework/templates/code/dotnet/database/migration.cs +83 -83
  103. package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
  104. package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
  105. package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
  106. package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -15
  107. package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +1 -1
  108. package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
  109. package/framework/templates/code/typescript/contracts.ts +167 -167
  110. package/framework/templates/docs/clarifications.md +253 -253
  111. package/framework/templates/docs/schema-analysis.md +119 -119
  112. package/framework/templates/docs/ui-components.md +52 -52
  113. package/framework/templates/docs/ui-design-system.md +76 -76
  114. package/framework/templates/docs/ui-flows.md +167 -167
  115. package/framework/templates/docs/ui-mockups.md +98 -98
  116. package/framework/templates/dotnet/ai-kit/Directory.Build.props +25 -0
  117. package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
  118. package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
  119. package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
  120. package/framework/templates/dotnet/ai-kit/README.md +128 -0
  121. package/framework/templates/dotnet/ai-kit/global.json +9 -0
  122. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
  123. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
  124. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
  125. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
  126. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
  127. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
  128. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
  129. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
  130. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
  131. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
  132. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
  133. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
  134. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
  135. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
  136. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
  137. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
  138. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
  139. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
  140. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
  141. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
  142. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
  143. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
  144. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
  145. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
  146. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
  147. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
  148. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
  149. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
  150. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
  151. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
  152. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
  153. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
  154. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
  155. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
  156. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
  157. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
  158. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
  159. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
  160. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
  161. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
  162. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
  163. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
  164. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
  165. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
  166. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
  167. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
  168. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
  169. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
  170. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
  171. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
  172. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
  173. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
  174. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
  175. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
  176. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
  177. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
  178. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
  179. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
  180. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
  181. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
  182. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
  183. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
  184. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
  185. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
  186. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
  187. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
  188. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
  189. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
  190. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
  191. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
  192. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
  193. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
  194. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
  195. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
  196. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
  197. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
  198. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
  199. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
  200. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
  201. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
  202. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
  203. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
  204. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
  205. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
  206. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
  207. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
  208. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
  209. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
  210. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
  211. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
  212. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
  213. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
  214. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
  215. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
  216. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
  217. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
  218. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
  219. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
  220. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
  221. package/framework/templates/feature/decisions.md +122 -122
  222. package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -43
  223. package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
  224. package/framework/templates/frontend/nextjs/env.mjs.hbs +32 -32
  225. package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
  226. package/framework/templates/frontend/nextjs/page.tsx.hbs +22 -22
  227. package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
  228. package/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -54
  229. package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
  230. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  231. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  232. package/framework/templates/infrastructure/github/README.md +56 -56
  233. package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
  234. package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
  235. package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
  236. package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
  237. package/framework/templates/integrations/asaas-client.cs +387 -387
  238. package/framework/templates/integrations/asaas-webhook.cs +351 -351
  239. package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
  240. package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
  241. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
  242. package/framework/templates/project/validate.js +120 -120
  243. package/framework/templates/state.template.json +17 -17
  244. package/framework/templates/ui/design-system.css +226 -226
  245. package/package.json +3 -3
  246. package/src/commands/dashboard/dashboard.js +53 -53
  247. package/src/commands/e2e/e2e.js +15 -2
  248. package/src/commands/index.js +13 -13
  249. package/src/commands/project/checkpoint.js +209 -209
  250. package/src/commands/project/doctor.js +140 -5
  251. package/src/commands/project/update.js +469 -153
  252. package/src/commands/project/worktree.js +8 -1
  253. package/src/commands/state/advance.js +24 -2
  254. package/src/commands/state/approve.js +33 -1
  255. package/src/commands/state/create.js +72 -11
  256. package/src/commands/state/finish.js +333 -21
  257. package/src/commands/state/gate-check.js +190 -6
  258. package/src/commands/state/score.js +36 -1
  259. package/src/commands/validation/verify.js +134 -25
  260. package/src/core/state/phase-state-machine.js +197 -197
  261. package/src/core/state/state-manager.js +9 -1
  262. package/src/core/templates/template-renderer.js +477 -477
  263. package/src/dashboard/app/components/DetailPanel.jsx +11 -11
  264. package/src/dashboard/app/components/FlowGraph.jsx +17 -17
  265. package/src/dashboard/app/components/SearchFilter.jsx +22 -22
  266. package/src/dashboard/app/hooks/useDetailPanel.js +15 -15
  267. package/src/dashboard/app/main.jsx +13 -13
  268. package/src/dashboard/app/pages/AgentMap.jsx +370 -370
  269. package/src/dashboard/app/pages/PhasePipeline.jsx +408 -408
  270. package/src/dashboard/app/pages/RulesMap.jsx +273 -273
  271. package/src/dashboard/app/pages/SkillsLibrary.jsx +366 -366
  272. package/src/dashboard/app/pages/Standards.jsx +332 -332
  273. package/src/dashboard/app/styles/index.css +47 -47
  274. package/src/dashboard/index.html +12 -12
  275. package/src/dashboard/package.json +24 -24
  276. package/src/dashboard/scanner/phases-scanner.js +15 -15
  277. package/src/dashboard/scanner/rubrics-scanner.js +12 -12
  278. package/src/dashboard/scanner/rules-scanner.js +37 -37
  279. package/src/dashboard/scanner/skills-scanner.js +43 -43
  280. package/src/dashboard/scanner/squads-scanner.js +13 -13
  281. package/src/dashboard/vite-plugin-morph-data.js +17 -17
  282. package/src/dashboard/vite.config.js +24 -24
  283. package/src/lib/ai/ai-checks.js +182 -0
  284. package/src/lib/ai/ai-project-scan.js +347 -0
  285. package/src/lib/ai/code-audit.js +181 -0
  286. package/src/lib/ai/comment-stripper.js +184 -0
  287. package/src/lib/ai/pin-drift.js +138 -0
  288. package/src/lib/ai/registry-audit.js +285 -0
  289. package/src/lib/detectors/design-system-detector.js +188 -188
  290. package/src/lib/detectors/index.js +217 -217
  291. package/src/lib/e2e/compose-env.js +50 -4
  292. package/src/lib/evaluator-report.js +269 -15
  293. package/src/lib/generators/design-system-generator.js +508 -508
  294. package/src/lib/generators/settings-generator.js +209 -209
  295. package/src/lib/git/default-branch.js +92 -4
  296. package/src/lib/hooks/hook-executor.js +167 -167
  297. package/src/lib/installers/effects.js +193 -0
  298. package/src/lib/installers/mcp-installer.js +719 -719
  299. package/src/lib/installers/templates-reconcile.js +3 -3
  300. package/src/lib/risk-detector.js +284 -0
  301. package/src/lib/standards/verified-against.js +276 -0
  302. package/src/lib/tasks/eval-node.js +485 -0
  303. package/src/lib/tasks/linux-runner.js +297 -0
  304. package/src/lib/tasks/task-classifier.js +30 -30
  305. package/src/lib/tasks/task-parser.js +209 -209
  306. package/src/lib/tasks/test-nodes.js +486 -0
  307. package/src/lib/tasks/test-runner.js +410 -33
  308. package/src/lib/validators/checkpoint-persistence.js +39 -39
  309. package/src/lib/validators/css/css-validator.js +340 -340
  310. package/src/lib/validators/shared/emit-validator-dispatch.js +14 -14
  311. package/src/lib/validators/shared/issue-counter.js +14 -14
  312. package/src/lib/validators/verify-runner.js +583 -28
  313. package/src/lib/worktree/docker-audit.js +287 -0
  314. package/src/lib/worktree/env-allocator.js +24 -0
  315. package/src/lib/worktree/worktree-audit.js +30 -1
  316. package/src/scripts/setup-infra.js +24 -11
  317. package/src/utils/agent-id-mapper.js +11 -11
  318. package/src/utils/agents-installer.js +18 -8
  319. package/src/utils/claude-md-injector.js +10 -5
  320. package/src/utils/claude-settings-manager.js +300 -300
  321. package/src/utils/file-copier.js +11 -4
  322. package/src/utils/hooks-installer.js +29 -26
  323. package/src/utils/skills-installer.js +36 -29
  324. package/src/utils/version-checker.js +68 -3
  325. 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.
@@ -20,10 +20,14 @@
20
20
  * This is the sanctioned progress path — the agent never has to rewrite the
21
21
  * whole file nor reach for a Node script to record task status.
22
22
  *
23
+ * A gate freezes the APPROVED ARTIFACT, so a protected file that does not yet
24
+ * exist on disk is a CREATION and passes — the criterion is the file's
25
+ * existence, never who signed the gate (see the carve-out in run()).
26
+ *
23
27
  * Fail-open: exits 0 on any error.
24
28
  */
25
29
 
26
- import { readFileSync } from 'fs';
30
+ import { existsSync, readFileSync } from 'fs';
27
31
  import { stateExists, isGateApproved } from '../../shared/state-reader.js';
28
32
  import {
29
33
  isFeaturePath,
@@ -238,6 +242,35 @@ export async function run(payload) {
238
242
  }
239
243
 
240
244
  // ── Gate approved — file is locked ──────────────────────────────────────
245
+ const absPath = resolveTargetPath(filePath, root);
246
+
247
+ // Um gate aprovado congela o ARTEFATO APROVADO. Se o arquivo ainda não
248
+ // existe no disco, não há artefato aprovado a proteger: isto é a CRIAÇÃO
249
+ // inicial, não a edição de uma spec fechada. O caso é real e não é raro —
250
+ // `chore`/`hotfix` nascem com `proposal`+`plan` carimbados `policy:{tipo}`
251
+ // (create.js → work-types.js skippedGates), então o primeiro `Write` de
252
+ // `2-plan/spec.md` já chega aqui com o gate "aprovado" sem que humano
253
+ // nenhum tenha aprovado coisa alguma — e era barrado com uma mensagem
254
+ // mandando revogar o gate de um arquivo inexistente.
255
+ //
256
+ // O critério é a EXISTÊNCIA, nunca o `approvedBy`. Liberar por assinatura
257
+ // (`policy:` passa, `lucas` não) transformaria este carve-out em licença
258
+ // para reescrever qualquer spec aprovada: bastaria apagá-la antes. Por ser
259
+ // sobre o disco, a janela fecha sozinha no instante em que o arquivo
260
+ // existe — os contra-canários de test/hooks/protect-spec-files.test.js
261
+ // pinam exatamente isso.
262
+ //
263
+ // A decisão é explícita e vale para as DUAS metades do hook. Antes, o ramo
264
+ // de campos mutáveis (tasks.json) já deixava a primeira criação passar, mas
265
+ // por acidente — o ENOENT caía no catch fail-open da leitura — enquanto o
266
+ // ramo travado bloqueava. Duas metades respondendo à mesma pergunta em
267
+ // direções opostas; agora respondem aqui, uma vez só. O `result` distinto
268
+ // no log é o que torna essa unificação observável.
269
+ if (!existsSync(absPath)) {
270
+ logHookActivity('protect-spec-files', 'PreToolUse', 'ok:absent');
271
+ return null;
272
+ }
273
+
241
274
  const mutableFields = MUTABLE_SPEC_FIELDS[filename];
242
275
 
243
276
  // Files with mutable progress fields (e.g. tasks.json): allow a full Write
@@ -247,8 +280,9 @@ export async function run(payload) {
247
280
 
248
281
  // Build the proposed document from either a full Write or a targeted Edit,
249
282
  // then semantic-diff it against the current file on disk. Any failure to
250
- // read / parse / apply → fail-open (pass), never a false block.
251
- const absPath = resolveTargetPath(filePath, root);
283
+ // read / parse / apply → fail-open (pass), never a false block. O arquivo
284
+ // EXISTE aqui (a inexistência já foi decidida acima), então este catch
285
+ // volta a significar só o que dizia originalmente: não deu para diffar.
252
286
  let oldDoc, newDoc;
253
287
  try {
254
288
  const original = readFileSync(absPath, 'utf-8');
@@ -312,8 +346,11 @@ export async function run(payload) {
312
346
  // de leitura/reconstrução cai no bloqueio (o conservador aqui é BLOQUEAR —
313
347
  // ao contrário do ramo do tasks.json, onde não conseguir diffar significa
314
348
  // não ter como provar violação; aqui a regra base é "não se edita").
349
+ //
350
+ // O arquivo EXISTE neste ponto — a inexistência foi decidida lá em cima, e
351
+ // é a única coisa que este catch NÃO significa mais. ENOENT tratado como
352
+ // "ilegível" era o defeito F14; "ilegível de verdade" continua bloqueando.
315
353
  const toolName = getToolName(payload);
316
- const absPath = resolveTargetPath(filePath, root);
317
354
  let errataCheck = null;
318
355
  try {
319
356
  const original = readFileSync(absPath, 'utf-8');
@@ -1,11 +1,11 @@
1
- #!/usr/bin/env bash
2
- # morph-spec statusline — installed globally to ~/.claude/statusline.sh
3
- # Claude Code invokes this with JSON via stdin after each response.
4
- # Requires: Python 3 available as `python3` or `python` on PATH.
5
-
6
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
- if command -v python3 &>/dev/null; then
8
- python3 "${SCRIPT_DIR}/statusline.py" 2>/dev/null || true
9
- elif command -v python &>/dev/null; then
10
- python "${SCRIPT_DIR}/statusline.py" 2>/dev/null || true
11
- fi
1
+ #!/usr/bin/env bash
2
+ # morph-spec statusline — installed globally to ~/.claude/statusline.sh
3
+ # Claude Code invokes this with JSON via stdin after each response.
4
+ # Requires: Python 3 available as `python3` or `python` on PATH.
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ if command -v python3 &>/dev/null; then
8
+ python3 "${SCRIPT_DIR}/statusline.py" 2>/dev/null || true
9
+ elif command -v python &>/dev/null; then
10
+ python "${SCRIPT_DIR}/statusline.py" 2>/dev/null || true
11
+ fi