@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
@@ -2,10 +2,10 @@
2
2
 
3
3
  > **Scope:** stacks=["dotnet"]
4
4
  > **Layer:** 1 (on-keyword)
5
- > **Keywords:** multi-agent, agent as tool, agent composition, sequential agents, handoff, sub-agent, agent orchestration
5
+ > **Keywords:** multi-agent, agent as tool, agent composition, sequential agents, handoff, sub-agent, agent orchestration, agente auxiliar, nesting
6
6
  > **Read by Claude in:** plan (quando ai-agents-sweet-spot indica multi-agent) + implement
7
7
 
8
- **Verified against:** MAF 1.0 GA. Last-verified: 2026-05-19.
8
+ **Verified against:** Microsoft.Agents.AI 1.20.0 (ai-pin 2026-09-08) + Microsoft.Agents.AI.Workflows 1.20.0 (**fora do pin**; versão apurada no nuget.org em 2026-09-08). **Verificação documental**, sem cláusula `provado por` — o ai-kit não compõe agentes. As assinaturas de `AgentWorkflowBuilder`/`HandoffWorkflowBuilder` e a **ausência** do atributo `[Experimental]` no Handoff foram **medidas por reflexão sobre a assembly 1.20.0** em 2026-09-08. Last-verified: 2026-09-08.
9
9
 
10
10
  ---
11
11
 
@@ -91,12 +91,59 @@ Use `AgentWorkflowBuilder.BuildSequential(agent1, agent2, ...)` quando precisar
91
91
 
92
92
  Um agent de triagem decide qual especialista assume o controle com base no contexto. Útil quando há N especialistas e a decisão de roteamento é complexa demais para uma tool simples.
93
93
 
94
- Para handoff baseado em Workflow: `AgentWorkflowBuilder.CreateHandoffBuilderWith(triageAgent).WithHandoffs(...)`. Ver `ai-agents-workflows` para o padrão completo.
94
+ **Status: graduou.** O Handoff era marcado experimental no 1.0 e foi anunciado como *"graduating to release"* no BUILD 2026 (2026-06-03). **Medido em 2026-09-08:** `Microsoft.Agents.AI.Workflows.HandoffWorkflowBuilder` e `AgentWorkflowBuilder` **não carregam** `[Experimental]` na assembly 1.20.0 — a graduação está no binário, não só no anúncio.
95
+
96
+ Para handoff baseado em Workflow: `AgentWorkflowBuilder.CreateHandoffBuilderWith(triageAgent)`. Ver `ai-agents-workflows` para o padrão completo.
97
+
98
+ **Limites documentados, e o que cada um evita** (assinaturas medidas em `HandoffWorkflowBuilderCore<TBuilder>`):
99
+
100
+ | Limite | Como | O que evita |
101
+ |---|---|---|
102
+ | Teto de turnos | `.WithAutonomousMode(turnLimit: 8)` — aceita também `agentTurnLimits` por agente | Loop infinito de dois agentes se devolvendo a conversa |
103
+ | Condição de término | `.WithTerminationCondition(...)` | O mesmo, por critério de conteúdo em vez de contagem |
104
+ | `Id` estável por agente | Cada `AIAgent` com `Id` fixo (não regenerado a cada boot) | Handoff que aponta para um agente que "sumiu" entre reinícios |
105
+ | Group chat pequeno | ≤ **3** agentes por group chat | Acima disso o gerente gasta mais turnos escolhendo quem fala do que resolvendo |
95
106
 
96
107
  > Para roteamento simples (2-3 caminhos), considere Agent-as-Tool com um agent por caminho antes de ir para Handoff Workflow.
97
108
 
98
109
  ---
99
110
 
111
+ ## Agente auxiliar: em SEQUÊNCIA, nunca dentro de uma tool
112
+
113
+ **Anti-padrão medido em campo.** É tentador embrulhar um agente auxiliar (resumidor, classificador, extrator) numa tool do agente principal: parece composição barata. Não é.
114
+
115
+ ```csharp
116
+ // ERRADO — o auxiliar roda DENTRO da tool do principal.
117
+ AIFunction summarize = AIFunctionFactory.Create(async (string text) =>
118
+ {
119
+ var r = await _summarizerAgent.RunAsync(text); // agente aninhado na tool
120
+ return r.Text;
121
+ });
122
+ ```
123
+
124
+ **Dois problemas concretos:**
125
+
126
+ 1. **`CallId` com tools encadeadas.** O agente auxiliar tem o próprio ciclo de tool calling. Rodando dentro da tool do principal, dois laços de function-calling se sobrepõem no mesmo turno, e a reconciliação de `CallId` entre pedido e resultado passa a depender da ordem em que os dois laços terminam.
127
+ 2. **O loop do principal fica aberto enquanto o auxiliar roda.** O principal está no meio de um turno, com uma chamada pendente, esperando algo que pode levar várias voltas de LLM. Timeout, retry e telemetria do turno principal passam a medir a soma dos dois.
128
+
129
+ **O contrato correto são DUAS chamadas visíveis, em sequência:**
130
+
131
+ ```csharp
132
+ // CERTO — o auxiliar roda FORA, e o resultado entra como dado no turno seguinte.
133
+ AgentResponse summary = await _summarizerAgent.RunAsync(text);
134
+ AgentResponse answer = await _mainAgent.RunAsync(
135
+ $"Resumo do documento:
136
+ {summary.Text}
137
+
138
+ Pergunta: {question}", session);
139
+ ```
140
+
141
+ Cada chamada tem o próprio span, o próprio custo e o próprio timeout — e o orquestrador é o **código**, não o modelo. É o mesmo princípio do compositor determinístico em `ai-agents-context-providers`.
142
+
143
+ **A exceção, com regra:** `agent.AsAIFunction()` é a composição barata **antes** de qualquer orquestração — e serve exatamente quando o LLM principal precisa **decidir** se chama o auxiliar. Nesse caso vale o teto: **aninhamento ≤ 2 níveis** (pai → filho). Um terceiro nível é sinal de que a composição devia ser sequência no código.
144
+
145
+ ---
146
+
100
147
  ## Decision tree
101
148
 
102
149
  ```
@@ -126,7 +173,11 @@ Tenho múltiplos agents — qual padrão usar?
126
173
  | Usar multi-agent quando um único agent resolve | Adiciona latência, custo e superfície de erro sem ganho | Single agent com tools. Ver `ai-agents-sweet-spot`. |
127
174
  | Usar Workflow quando Agent-as-Tool basta | Workflow traz edges, builders, streaming — complexidade desnecessária | `agent.AsAIFunction()` primeiro |
128
175
  | Passar histórico de conversa bruto entre agents | Output do LLM é não-determinístico; o outro agent não sabe o que fazer com histórico livre | Structured Output entre agents. Ver `ai-agents-structured-output`. |
129
- | Nesting profundo (agent A chama B chama C chama D) | Dificulta debug, amplifica latência, falhas em cascata | Achate a composição: Agent-as-Tool com o agent folha direto no pai. |
176
+ | Nesting profundo (agent A chama B chama C chama D) | Dificulta debug, amplifica latência, falhas em cascata | Achate a composição: Agent-as-Tool com o agent folha direto no pai; teto de **2** níveis. |
177
+ | **Agente auxiliar aninhado dentro de uma tool** | Dois laços de function-calling no mesmo turno (reconciliação de `CallId`) e o turno do principal aberto enquanto o auxiliar roda | Duas chamadas visíveis, auxiliar **em sequência**, fora da tool |
178
+ | Handoff sem `turnLimit` nem condição de término | Dois agentes devolvem a conversa um ao outro indefinidamente | `.WithAutonomousMode(turnLimit:)` ou `.WithTerminationCondition(...)` |
179
+ | `Id` de agente gerado a cada boot num workflow de handoff | O destino do handoff deixa de existir entre reinícios | `Id` estável, vindo de configuração |
180
+ | Group chat com 5+ agentes | O gerente gasta os turnos escolhendo quem fala | ≤ 3 agentes; acima disso, repense a decomposição |
130
181
  | Agents com responsabilidades sobrepostas | Nenhum dos dois sabe quando agir; o LLM fica confuso | Fronteiras claras de responsabilidade; documente em `decisions.md`. |
131
182
 
132
183
  ---
@@ -139,6 +190,9 @@ Tenho múltiplos agents — qual padrão usar?
139
190
  - [ ] Agents usando alias do Model Registry — nenhum model string hardcoded?
140
191
  - [ ] Structured Output entre agents onde o output de um é input do outro?
141
192
  - [ ] Nesting máximo de 2 níveis (pai → filho) sem cascata profunda?
193
+ - [ ] Nenhum agente auxiliar roda dentro de uma tool de outro agente — auxiliares são chamadas em sequência, no código?
194
+ - [ ] Todo workflow de handoff tem `turnLimit` **ou** condição de término, e os agentes têm `Id` estável?
195
+ - [ ] Group chat (se houver) tem no máximo 3 agentes?
142
196
 
143
197
  ---
144
198
 
@@ -149,7 +203,9 @@ Tenho múltiplos agents — qual padrão usar?
149
203
  - `ai-agents-setup` — pacotes, DI, `AsAIAgent`
150
204
  - `ai-agents-structured-output` — output tipado entre agents
151
205
  - `ai-agents-providers-model-registry` — Model Registry alias pattern
206
+ - `ai-agents-context-providers` — o compositor determinístico: o código decide o modo, o LLM classifica
207
+ - `ai-agents-observability-patterns` — por que "uma chamada, um span" importa para medir latência
152
208
 
153
209
  ---
154
210
 
155
- *MORPH-SPEC by Polymorphism Tech — ai-agents/multi-agent-patterns.md v1.0 (2026-05-19)*
211
+ *MORPH-SPEC by Polymorphism Tech — ai-agents/multi-agent-patterns.md v2.0 (2026-09-08)*
@@ -5,7 +5,7 @@
5
5
  > **Keywords:** observability, telemetry, opentelemetry, logging, tracing, log investigation, troubleshooting, aspire dashboard, span, correlation id
6
6
  > **Read by Claude in:** implement (wiring telemetry into an agent) and troubleshoot (investigating a production issue)
7
7
 
8
- **Verified against:** MAF 1.0 GA. Last-verified: 2026-07-22.
8
+ **Verified against:** Microsoft.Agents.AI 1.20.0 + Microsoft.Extensions.AI 10.9.0 (ai-pin 2026-09-08); `provado por templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs` — o guard de span duplicado, a regra de "um nível, uma instrumentação" e o default `EnableSensitiveData = false` são exatamente o que o kit compila, com os spans contados em `tests/Morph.AiKit.Tests/TelemetryTests.cs`. Nomes de símbolo, de span, de métrica e das duas `ActivitySource` foram **medidos por reflexão e por leitura dos literais das assemblies do pin** em 2026-09-08, e em 2026-09-09 **todos os treze nomes `gen_ai.*` desta página** foram remedidos, um a um, por **teste de exclusividade**: os quatro `SetTag` da seção *Enrichment* e os nove das seções de span, métrica e atributo de agente. **Os treze existem** — depois de uma correção: `gen_ai.response.finish_reason`, no **singular**, não existia, só aparecia como cabeça de `finish_reason`**s**, e sobreviveu a duas varreduras porque as duas usaram `includes` — e **`includes` de um prefixo não prova o literal autônomo**. Os treze estão tabelados, em **duas** tabelas com propósitos diferentes: a de *Enrichment* registra os **4** `SetTag` daquele bloco (mais os **cinco** nomes rejeitados: o `finish_reason` singular, `PromptTokens`, `CompletionTokens`, `prompt_tokens` e `completion_tokens`), e a de distribuição, na seção *Nomes de span, métricas e atributos — medidos*, registra os **13** por assembly. A conferência é reproduzível por `node scripts/api-probe/probe.mjs tags` sobre este arquivo. A **instabilidade da convenção** — o split do semconv **v1.42.0 (2026-06-12)**, que depreciou e moveu todo `gen_ai.*` para `open-telemetry/semantic-conventions-genai`, onde nada GenAI está `Stable`, contra a v1.37 que o `OpenTelemetryChatClient` declara implementar — é **verificação documental**, apurada em 2026-09-08. Last-verified: 2026-09-08.
9
9
 
10
10
  ---
11
11
 
@@ -17,28 +17,45 @@ Um agente MAF em produção não é uma função — é uma cadeia (LLM call →
17
17
 
18
18
  ## Setup — OpenTelemetry
19
19
 
20
+ ### Duas correções medidas contra a versão anterior deste standard
21
+
22
+ | O que este standard dizia | O que o pin diz (medido em 2026-09-08) |
23
+ |---|---|
24
+ | `AgentOpenTelemetryConsts.DefaultSourceName` e `agent.WithOpenTelemetry()` | **Nenhum dos dois existe** em `Microsoft.Agents.AI` 1.20.0. A API é `builder.UseOpenTelemetry(sourceName, configure)` sobre `AIAgentBuilder` / `ChatClientBuilder` |
25
+ | `EnableSensitiveTelemetryData` | O símbolo é **`EnableSensitiveData`**, e existe **nos dois** tipos: `OpenTelemetryAgent.EnableSensitiveData` e `OpenTelemetryChatClient.EnableSensitiveData`. Não são dois nomes diferentes: é o **mesmo nome em dois níveis** |
26
+ | *"não use `Experimental.Microsoft.Extensions.AI.*` — é do 9.x"* | São **duas fontes vivas e necessárias**: `Experimental.Microsoft.Agents.AI` (do agente) e `Experimental.Microsoft.Extensions.AI` (do chat e das tools). Quem só registra a primeira perde os spans `chat` e `execute_tool` |
27
+
28
+ Os dois nomes de `ActivitySource` foram lidos como literais nas assemblies `Microsoft.Agents.AI.dll` 1.20.0 e `Microsoft.Extensions.AI.dll` 10.9.0.
29
+
20
30
  ```csharp
21
31
  using OpenTelemetry;
22
32
  using OpenTelemetry.Trace;
23
33
  using OpenTelemetry.Metrics;
24
34
  using Microsoft.Agents.AI;
35
+ using Microsoft.Extensions.AI;
25
36
 
26
- // Habilitar em agents individuais
27
- agent.WithOpenTelemetry();
37
+ const string AgentSource = "Experimental.Microsoft.Agents.AI"; // span invoke_agent
38
+ const string ChatSource = "Experimental.Microsoft.Extensions.AI"; // spans chat e execute_tool
39
+
40
+ // Instrumentar o AGENTE (span externo). EnableSensitiveData default = false.
41
+ AIAgent instrumented = agent.AsBuilder()
42
+ .UseOpenTelemetry(sourceName: AgentSource, configure: o => o.EnableSensitiveData = false)
43
+ .Build();
28
44
 
29
45
  // Program.cs — setup completo
30
46
  builder.Services.AddOpenTelemetry()
31
47
  .WithTracing(tracing =>
32
48
  {
33
- tracing.AddSource(AgentOpenTelemetryConsts.DefaultSourceName); // MAF 1.0 GA source
34
- tracing.AddSource(builder.Environment.ApplicationName); // seus spans customizados (ver Enrichment)
49
+ tracing.AddSource(AgentSource); // sem isto: nenhum invoke_agent
50
+ tracing.AddSource(ChatSource); // sem isto: nenhum chat / execute_tool
51
+ tracing.AddSource(builder.Environment.ApplicationName); // seus spans customizados (ver Enrichment)
35
52
  tracing.AddAspNetCoreInstrumentation();
36
53
  tracing.AddHttpClientInstrumentation();
37
54
  tracing.AddOtlpExporter();
38
55
  })
39
56
  .WithMetrics(metrics =>
40
57
  {
41
- metrics.AddMeter(AgentOpenTelemetryConsts.DefaultSourceName);
58
+ metrics.AddMeter(ChatSource); // as métricas gen_ai.client.* saem daqui
42
59
  metrics.AddAspNetCoreInstrumentation();
43
60
  metrics.AddHttpClientInstrumentation();
44
61
  metrics.AddRuntimeInstrumentation();
@@ -52,9 +69,99 @@ builder.Logging.AddOpenTelemetry(logging =>
52
69
  });
53
70
  ```
54
71
 
55
- > **Source name:** sempre `AgentOpenTelemetryConsts.DefaultSourceName` de `Microsoft.Agents.AI`.
56
- > **NÃO usar** o source string `"Experimental.[pacote-antigo].*"` — pertence à família `Microsoft.Extensions.AI` 9.x, incompatível com MAF 1.0 GA.
57
- > **Produção:** desabilite dados sensíveis — `EnableSensitiveTelemetryData = false` no agent — para não vazar prompt/response completos no backend de export.
72
+ > **Produção:** `EnableSensitiveData = false` (é o default nos dois níveis) para não vazar prompt/response completos no backend de export.
73
+
74
+ ### A regra de duplicação — um NÍVEL, uma instrumentação
75
+
76
+ A mudança de **1.6.1** (2026-05-14) foi o `OpenTelemetryAgent` passar a **auto-encapsular** o chat client com um `OpenTelemetryChatClient` no pipeline que o `ChatClientAgent` monta sozinho. Daí saiu a regra folclórica *"instrumente o agente **ou** o chat client, nunca os dois"* — que é **imprecisa**, e a diferença muda o que se escreve.
77
+
78
+ **O que foi medido no pin** (`Morph.AiKit.Tests/TelemetryTests.cs`, contra `Microsoft.Agents.AI` 1.20.0):
79
+
80
+ - Uma invocação instrumentada produz **`invoke_agent` (raiz) + `chat` (filho)**. Instrumentar os **dois níveis** é o caminho normal, e **não** duplica nada — o teste `AnInstrumentedAgentEmitsOneInvokeAgentSpanAndOneChatSpan` pina isso.
81
+ - O que duplica é **duas camadas no MESMO nível**: dois `OpenTelemetryChatClient` dão dois `chat`; dois `OpenTelemetryAgent` dão dois `invoke_agent` (`ForcingInstrumentChatClientProducesTheDuplicateChatSpan`).
82
+ - O guard do MAF **só alcança o pipeline que o `ChatClientAgent` monta sozinho**. Quem monta o próprio pipeline (`ChatClientAgentOptions.UseProvidedChatClientAsIs = true`, necessário para posicionar middleware de custo ou ajustar tool calling) **perde** esse slot: medido, agente instrumentado + pipeline próprio sem instrumentação de chat = **zero** spans de chat.
83
+
84
+ **A regra correta, então, é em duas linhas:**
85
+
86
+ 1. **Instrumente cada nível no máximo uma vez.** O predicado é respondível, não um palpite: `inner.GetService(typeof(OpenTelemetryChatClient))` / `typeof(OpenTelemetryAgent)` atravessa a cadeia de delegates.
87
+ 2. **Com pipeline próprio, a instrumentação de chat é obrigatória** — não é um extra opcional, é a única coisa que produz o span `chat`.
88
+
89
+ ```csharp
90
+ // O guard, na forma que o ai-kit compila: nulo = instrumenta só o que ainda não está.
91
+ builder.Use(inner => inner.GetService(typeof(OpenTelemetryChatClient)) is null
92
+ ? new OpenTelemetryChatClient(inner, logger: null, sourceName: ChatSource) { EnableSensitiveData = false }
93
+ : inner);
94
+ ```
95
+
96
+ **Onde o span de chat fica no pipeline:** **abaixo** do `FunctionInvokingChatClient`. É assim que o span `chat` fecha antes das tools e o `invoke_agent` fica sendo a raiz. Ver a ordem completa do pipeline em `ai-agents-middleware-patterns`.
97
+
98
+ ### Nomes de span, métricas e atributos — medidos
99
+
100
+ | O que | Nome | Onde foi medido |
101
+ |---|---|---|
102
+ | Span do agente | `invoke_agent` | literal em `Microsoft.Agents.AI.dll` 1.20.0 |
103
+ | Span do modelo | operação + modelo (`gen_ai.operation.name` + `gen_ai.request.model`) | `Microsoft.Extensions.AI.dll` 10.9.0 |
104
+ | Span de tool | `execute_tool` | `Microsoft.Extensions.AI.dll` 10.9.0 |
105
+ | Métrica de duração | `gen_ai.client.operation.duration` | idem |
106
+ | Métrica de tokens | `gen_ai.client.token.usage` | idem |
107
+ | Métricas extras | `gen_ai.client.operation.exception`, `gen_ai.client.operation.time_per_output_chunk` | idem |
108
+ | Atributos do agente | `gen_ai.agent.id`, `gen_ai.agent.name`, `gen_ai.agent.description`, `gen_ai.provider.name` | `Microsoft.Agents.AI.dll` 1.20.0 |
109
+
110
+ A coluna "onde foi medido" nomeia **uma** assembly onde o literal ocorre, e **não** afirma
111
+ exclusividade. A distribuição completa, medida por exclusividade sobre **todas** as assemblies
112
+ restauradas do pin (`probe.mjs tags`, 2026-09-09) — repare que ela **não se limita às duas** que esta
113
+ página nomeia:
114
+
115
+ | Nome | Assemblies onde o literal ocorre |
116
+ |---|---|
117
+ | `invoke_agent` | `Microsoft.Agents.AI` **e** `Microsoft.Extensions.AI` |
118
+ | `execute_tool` | `Microsoft.Extensions.AI` **e** `ModelContextProtocol.Core` |
119
+ | `gen_ai.agent.id`, `gen_ai.agent.name`, `gen_ai.agent.description` | **só** `Microsoft.Agents.AI` |
120
+ | `gen_ai.provider.name` | `Microsoft.Agents.AI` **e** `Microsoft.Extensions.AI` |
121
+ | `gen_ai.operation.name` | `Microsoft.Agents.AI`, `Microsoft.Extensions.AI`, `ModelContextProtocol.Core` **e** `OpenAI` |
122
+ | `gen_ai.request.model`, `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`, `gen_ai.response.finish_reasons`, `gen_ai.client.operation.duration`, `gen_ai.client.token.usage` | `Microsoft.Extensions.AI` **e** `OpenAI` |
123
+ | `gen_ai.client.operation.exception`, `gen_ai.client.operation.time_per_output_chunk` | **só** `Microsoft.Extensions.AI` |
124
+
125
+ **Por que isto importa para quem instrumenta:** o mesmo nome emitido por camadas diferentes é o que
126
+ produz span duplicado — e é a razão de este standard começar pelo guard de "um nível, uma
127
+ instrumentação". `OpenAI` e `ModelContextProtocol.Core` estão sob o **mesmo pin** e carregam parte
128
+ destes nomes; se você registrar a fonte deles junto com a do agente sem o guard, o atributo chega
129
+ duas vezes com procedências diferentes.
130
+
131
+ > **Duas afirmações que NÃO se confirmaram, e por isso não estão acima.** `agent_framework.function.invocation.duration` e a variável de ambiente `OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental` **não aparecem** em nenhuma das quatro assemblies do pin (`Microsoft.Agents.AI`, `.Abstractions`, `Microsoft.Extensions.AI`, `.Abstractions`), varridas por literal em 2026-09-08. A duração de invocação de função pode existir noutro pacote, e a variável é do SDK do OpenTelemetry, não destes pacotes — em nenhum dos dois casos este standard as prescreve sem fonte.
132
+
133
+ ### Estabilidade da convenção GenAI — a ressalva que muda como ler a tabela acima
134
+
135
+ Os nomes acima são **medidos nas assemblies do pin**, e continuam corretos. O que não é estável é a
136
+ **convenção** que eles implementam, e um standard que manda instrumentar sem dizer isso está mandando
137
+ pintar alvo num muro que se move.
138
+
139
+ Os fatos, apurados em 2026-09-08:
140
+
141
+ - As **GenAI semantic conventions saíram do repositório principal** do OpenTelemetry. A versão
142
+ **1.42.0 do semconv (2026-06-12)** depreciou e moveu todo o namespace `gen_ai.*`; a **1.43.0
143
+ (2026-07-03)** não traz nenhum.
144
+ - O conteúdo passou a viver em `open-telemetry/semantic-conventions-genai`, e ali **nenhum** span,
145
+ evento, métrica ou atributo GenAI está marcado `Stable` — todos estão em `Development`. Os únicos
146
+ estáveis no conjunto são `error.type`, `server.address` e `server.port`, que são **atributos
147
+ comuns**, não GenAI.
148
+ - Enquanto isso, o `OpenTelemetryChatClient` do `Microsoft.Extensions.AI` declara implementar a
149
+ **v1.37** — ou seja, a versão implementada está **atrás** do split.
150
+
151
+ **O que isso implica na prática, e é o que se leva daqui:**
152
+
153
+ | Implicação | O que fazer |
154
+ |---|---|
155
+ | Nome de atributo `gen_ai.*` pode mudar entre versões do pacote | Não construa alerta cujo único identificador seja um nome `gen_ai.*` sem um plano de renomeação |
156
+ | A versão implementada pelo pacote **não** é a última da convenção | Ao subir o pin, confira a tabela de nomes acima em vez de assumir continuidade |
157
+ | Painel montado sobre o namespace instável envelhece com o pacote | Vale a pena manter uma camada própria de nomes (`morph.*`) para o que o time consulta todo dia |
158
+
159
+ Isto **não** é motivo para não instrumentar. É motivo para instrumentar sabendo que os nomes são de
160
+ uma convenção em desenvolvimento, e para não tratar uma renomeação futura como incidente.
161
+
162
+ ### Limitação conhecida, em aberto
163
+
164
+ Issue **3637** do `microsoft/agent-framework`: o `UseOpenTelemetry()` do .NET **não emite `ActivityEvent`s** conforme a spec de eventos GenAI — o conteúdo de mensagem viaja como atributo, não como evento. Estado em 2026-09-08: **aberta**. Consequência prática: um backend que monta a conversa a partir de *events* GenAI mostra spans sem mensagens. Não é bug do seu wiring.
58
165
 
59
166
  ### Aspire Dashboard (dev/local)
60
167
 
@@ -81,12 +188,54 @@ Sem um `correlation_id` propagado manualmente através de chamadas assíncronas/
81
188
 
82
189
  ```csharp
83
190
  activity?.SetTag("gen_ai.request.model", modelAlias); // alias do Model Registry, nunca o nome hardcoded
84
- activity?.SetTag("gen_ai.usage.prompt_tokens", usage.PromptTokens);
85
- activity?.SetTag("gen_ai.usage.completion_tokens", usage.CompletionTokens);
86
- activity?.SetTag("gen_ai.response.finish_reason", finishReason);
191
+ activity?.SetTag("gen_ai.usage.input_tokens", usage.InputTokenCount);
192
+ activity?.SetTag("gen_ai.usage.output_tokens", usage.OutputTokenCount);
193
+ activity?.SetTag("gen_ai.response.finish_reasons", finishReasons); // PLURAL — o singular não existe no pin
87
194
  ```
88
195
 
89
- Nomeação `gen_ai.*` segue a convenção semântica OpenTelemetry para GenAI — mantém compatibilidade se o backend de observability tiver dashboards prontos para essa convenção.
196
+ > **Correção de 2026-09-09 (duas passadas), medida por reflexão e por literal nas assemblies do
197
+ > pin. As QUATRO linhas acima foram conferidas, uma a uma** — a primeira passada corrigiu duas e
198
+ > deixou uma errada no mesmo bloco, que é a razão de este callout listar todas em vez de só as que
199
+ > mudaram.
200
+ >
201
+ > | Tag / símbolo | Veredito | Como |
202
+ > |---|---|---|
203
+ > | `gen_ai.request.model` | **existe** | 2 ocorrências autônomas; **distribuição por assembly na tabela da seção _Nomes de span, métricas e atributos — medidos_** — não é exclusivo de uma |
204
+ > | `gen_ai.usage.input_tokens` | **existe** | 2 autônomas; distribuição na tabela citada acima |
205
+ > | `gen_ai.usage.output_tokens` | **existe** | 2 autônomas; distribuição na tabela citada acima |
206
+ > | `gen_ai.response.finish_reasons` (a linha acima, no **plural**) | **existe** | 2 autônomas; distribuição na tabela citada acima |
207
+ > | `gen_ai.response.finish_reason` (o **singular**, que estava aqui) | **NÃO existe** | as **mesmas** 2 ocorrências do plural, **nenhuma autônoma**: o singular é a cabeça de `finish_reason`**s** |
208
+ > | `usage.PromptTokens` / `CompletionTokens` | **NÃO existem** | 0 ocorrências autônomas em assembly restaurada nenhuma |
209
+ > | `gen_ai.usage.prompt_tokens` / `completion_tokens` | **NÃO existem** | 0 ocorrências autônomas em assembly restaurada nenhuma |
210
+ >
211
+ > O que existe no lugar dos dois últimos é `InputTokenCount` / `OutputTokenCount`, propriedades de
212
+ > `UsageDetails` — que vive na assembly **`Microsoft.Extensions.AI.Abstractions` 10.9.0** (que viaja dentro do pacote `Microsoft.Extensions.AI`, e não é id de pacote do pin), e não na assembly
213
+ > que carrega os literais. E **"a assembly que carrega os literais" não é uma só** — a distribuição
214
+ > completa, por nome, está na tabela da seção *Nomes de span, métricas e atributos — medidos*, e **esta linha não a
215
+ > repete**: uma segunda tabela dos mesmos nomes foi escrita aqui na rodada 5 e **contradizia** a
216
+ > primeira (dizia "só em `Microsoft.Extensions.AI`" para seis literais que também vivem em `OpenAI`),
217
+ > justamente por invocá-la como autoridade sem relê-la. Duas cópias do mesmo fato divergem; a
218
+ > segunda foi removida.
219
+ >
220
+ > Faz sentido: quem **emite** o span de chamada de modelo é `OpenTelemetryChatClient`
221
+ > (`Microsoft.Extensions.AI` 10.9.0); quem descreve o **agente** é a camada de agente. Os nomes
222
+ > velhos eram da convenção **anterior** à renomeação do semconv. Código copiado daqui não compilava,
223
+ > e a tag emitida não casaria com nenhum painel montado sobre a convenção atual.
224
+ >
225
+ > **O método importa tanto quanto o resultado:** `finish_reason` sobreviveu a duas varreduras porque
226
+ > as duas usaram `includes(literal)`, e **`includes` de um prefixo não prova o literal autônomo** —
227
+ > o singular casa dentro do plural. A conferência acima é por **exclusividade**: cada ocorrência é
228
+ > aceita só se o caractere anterior e o seguinte não forem `[A-Za-z0-9_.-]`. Literais de string .NET
229
+ > vivem no heap `#US` em **UTF-16**; a varredura cobre `#US` (UTF-16) e `#Strings` (ASCII).
230
+
231
+ Nomeação `gen_ai.*` segue a convenção semântica OpenTelemetry para GenAI — mantém compatibilidade se o backend de observability tiver dashboards prontos para essa convenção. Sobre a **instabilidade** dessa convenção, ver a ressalva na seção de Setup.
232
+
233
+ > **Tokens ficam aqui; dinheiro não.** A **tarifa** por alias (com data de verificação), o **cálculo**
234
+ > do custo (e as três armadilhas de fórmula: raciocínio cobrado como saída, entrada cacheada como
235
+ > subconjunto da entrada, taxa fixa de operação hospedada), o estado de um custo
236
+ > (`Computed`/`Waived`/`UsageMissing`, e por que `cost_usd` nunca é nulo) e o **teto de orçamento**
237
+ > têm **tratamento canônico** em **`ai-agents-cost-and-budget`**. Não duplicado aqui. A delegação é
238
+ > de mão dupla: aquele standard aponta de volta para esta seção quando o assunto é atributo de span.
90
239
 
91
240
  ### Logging estruturado com `ILogger` — sempre com scope
92
241
 
@@ -105,11 +254,57 @@ using (_logger.BeginScope(new Dictionary<string, object>
105
254
  ```
106
255
 
107
256
  - **Sempre** parâmetros nomeados no template (`{ToolName}`, não string interpolada) — permite querying estruturado no backend em vez de grep de texto livre.
108
- - **Nunca** logar o conteúdo completo do prompt/response em `Information` — isso é PII/dado sensível do cliente por padrão. Logar em `Debug` apenas, e só se `EnableSensitiveTelemetryData` estiver habilitado explicitamente para o ambiente.
257
+ - **Nunca** logar o conteúdo completo do prompt/response em `Information` — isso é PII/dado sensível do cliente por padrão. Logar em `Debug` apenas, e só se `EnableSensitiveData` estiver habilitado explicitamente para o ambiente.
109
258
  - **Nível de log por tipo de evento:** `Information` para início/fim de tool call e decisões do agent; `Warning` para retry/fallback de provider; `Error` apenas para falhas que geram resposta degradada ao usuário (não para toda exceção capturada e tratada).
110
259
 
111
260
  ---
112
261
 
262
+ ## Rastreabilidade do que foi ao provedor
263
+
264
+ A pergunta que a instrumentação existe para responder depois de um incidente é uma só: **dá para
265
+ reconstruir o que foi enviado ao provedor, e o que ele respondeu, neste turno?**
266
+
267
+ **A regra: prompt cru no harness; hash em produção.**
268
+
269
+ | Ambiente | O que se registra | Por quê |
270
+ |---|---|---|
271
+ | Dev e harness | O texto enviado, com **opt-in explícito** e sem dado pessoal | É onde se depura; o custo de vazamento é controlado |
272
+ | Produção | O **hash** do texto enviado (e, quando o prompt é composto de blocos, um hash por bloco) | Um prompt cru persistido em produção é um vazamento esperando indexação. O hash responde "foi o mesmo texto?" sem guardar o texto |
273
+
274
+ Isso é a mesma chave que `EnableSensitiveData = false` fora de dev já protege — e o hash é o que
275
+ sobra de útil depois de desligá-la.
276
+
277
+ ### A invariante que torna o hash confiável
278
+
279
+ Um hash só prova alguma coisa se o texto de que ele é hash **é** o texto que foi enviado. Isso deixa
280
+ de valer no instante em que existe um cache entre a montagem e o envio: a partir dali, telemetria e
281
+ requisição podem divergir, e a divergência é silenciosa.
282
+
283
+ Por isso a exigência é do lado de quem monta o prompt, não de quem o registra: **o texto enviado é
284
+ derivado dos blocos, sem cache**. É uma invariante deliberadamente cara, e a razão está escrita no
285
+ código de campo que a implementa — *"para a telemetria não poder mentir"*. O tratamento canônico
286
+ está em `ai-agents-conversational-agent-with-phases`, seção do compositor de turno.
287
+
288
+ **Duas asserções que fecham o ciclo**, e ambas são de teste, não de wiring:
289
+
290
+ - A lista de tools **ofertadas** saiu da lista real do turno, e não de uma constante paralela.
291
+ - **Turno cancelado não grava** — um registro de algo que não aconteceu é pior que a ausência dele.
292
+
293
+ A metade de harness deste assunto (o que o fake captura, e como assertar sobre isso) é de
294
+ `ai-agents-testing-ai`. O veredito ternário e o escape registrado, que são o que torna um guard
295
+ auditável pela mesma via, são de `ai-agents-guardrails`.
296
+
297
+ > **O que o Gate 3 procura.** Os nomes concretos — `ActivitySource`, spans, métricas e atributos
298
+ > requeridos — estão medidos na tabela **"Nomes de span, métricas e atributos — medidos"** acima, e
299
+ > **não** são repetidos aqui: uma segunda lista dos mesmos nomes é a segunda verdade nascendo. A
300
+ > régua de avaliação correspondente vive em
301
+ > `.morph/framework/evals/proof-rubrics/observabilidade-genai.md`, e ela pergunta a **propriedade**
302
+ > desta seção (dá para reconstruir o turno?), não a tecnologia — porque uma régua binária "tem span?"
303
+ > daria a mesma nota a quem tem só a mensagem da exceção e a quem tem hash por bloco de prompt com
304
+ > teste de fidelidade.
305
+
306
+ ---
307
+
113
308
  ## Investigação e análise — quando algo dá errado
114
309
 
115
310
  Workflow para diagnosticar um incidente relatado ("o agente X respondeu errado/lento/nada às HH:MM"):
@@ -134,12 +329,20 @@ Workflow para diagnosticar um incidente relatado ("o agente X respondeu errado/l
134
329
 
135
330
  ## Checklist (verifiable by morph-eval)
136
331
 
137
- - [ ] OpenTelemetry configurado com `AgentOpenTelemetryConsts.DefaultSourceName` (traces + metrics + logging)
138
- - [ ] `EnableSensitiveTelemetryData = false` fora de dev/staging
332
+ - [ ] `AddSource` das **duas** fontes: `Experimental.Microsoft.Agents.AI` e `Experimental.Microsoft.Extensions.AI`
333
+ - [ ] Nenhuma referência a `AgentOpenTelemetryConsts` ou `agent.WithOpenTelemetry()` (não existem no pin)
334
+ - [ ] `EnableSensitiveData = false` fora de dev/staging (é o default — confirme que ninguém ligou)
335
+ - [ ] Cada nível instrumentado **no máximo uma vez**; com `UseProvidedChatClientAsIs = true`, a instrumentação de chat está explicitamente presente
336
+ - [ ] Um teste conta os spans de uma invocação: exatamente um `invoke_agent` e um `chat`
139
337
  - [ ] Todo tool call relevante tem `correlation_id` propagado manualmente através de boundaries assíncronos (filas, background jobs)
140
338
  - [ ] Logging via `ILogger` com `BeginScope` estruturado, nunca string interpolada em templates de log
141
339
  - [ ] Nenhum log em `Information`/produção contém prompt/response completo
142
340
  - [ ] Alertas configurados para os thresholds da tabela "What to Monitor" relevantes ao projeto
341
+ - [ ] Nenhum alerta depende de um nome `gen_ai.*` como identificador único sem plano de renomeação (a convenção está em `Development`, não `Stable`)
342
+ - [ ] Em produção, o que foi ao provedor é reconstituível por **hash**; prompt cru só em dev/harness, com opt-in
343
+ - [ ] O texto enviado é derivado dos blocos **sem cache** — sem isso o hash não prova nada
344
+ - [ ] Há asserção de que a lista de tools ofertadas saiu da lista real do turno
345
+ - [ ] Turno cancelado **não** grava telemetria
143
346
 
144
347
  ---
145
348
 
@@ -147,10 +350,17 @@ Workflow para diagnosticar um incidente relatado ("o agente X respondeu errado/l
147
350
 
148
351
  - `ai-agents-production` — panorama de produção; esta seção era resumida lá, tratamento canônico agora aqui
149
352
  - `ai-agents-middleware-patterns` — middleware de telemetria no nível `IChatClient` (`TelemetryMiddleware`)
353
+ - `ai-agents-cost-and-budget` — tarifa, cálculo de custo e teto de orçamento (delegação recíproca: tokens ficam aqui, dinheiro fica lá)
354
+ - `ai-agents-conversational-agent-with-phases` — o compositor de turno e a invariante "derivado sem cache" que torna o hash confiável
355
+ - `ai-agents-testing-ai` — a metade de harness da rastreabilidade (captura do fake, prompt cru com opt-in)
356
+ - `ai-agents-guardrails` — veredito ternário e escape registrado, auditáveis pela mesma telemetria
357
+ - `.morph/framework/evals/proof-rubrics/observabilidade-genai.md` — a régua do Gate 3 para a propriedade desta seção
150
358
  - `infrastructure-docker-coolify-deploy` — Serilog/JSON console log para o pipeline de agregação em produção
359
+ - Reference implementation (compila e conta spans contra o pin): `templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs` + `tests/Morph.AiKit.Tests/TelemetryTests.cs`
151
360
  - [OpenTelemetry Semantic Conventions for GenAI](https://opentelemetry.io/docs/specs/semconv/gen-ai/)
152
361
  - [Agent Observability](https://learn.microsoft.com/agent-framework/user-guide/observability/)
362
+ - Issue aberta `microsoft/agent-framework#3637` — `ActivityEvent`s da spec GenAI não emitidos (estado em 2026-09-08: **aberta**)
153
363
 
154
364
  ---
155
365
 
156
- *MORPH-SPEC by Polymorphism Tech — ai-agents/observability-patterns.md v1.0 (2026-07-22)*
366
+ *MORPH-SPEC by Polymorphism Tech — ai-agents/observability-patterns.md v2.0 (2026-09-08)*
@@ -5,7 +5,7 @@
5
5
  > **Keywords:** middleware, observability, telemetry, mcp, a2a, caching, anti-hallucination, production agent
6
6
  > **Read by Claude in:** implement (when wiring middleware/telemetry/MCP into an agent)
7
7
 
8
- **Verified against:** MAF 1.0 GA. Last-verified: 2026-05-19.
8
+ **Verified against:** Microsoft.Agents.AI 1.20.0 (ai-pin 2026-09-08) + Microsoft.Agents.AI.Hosting `1.20.0-preview.260831.1` e Microsoft.Agents.AI.A2A `1.20.0-preview.260831.1` (**fora do pin**; versões apuradas no nuget.org em 2026-09-08). **Verificação documental**, sem cláusula `provado por` — este standard é panorama, e cada tema tem dono canônico noutro standard. Os nomes de isolamento multi-tenant foram **medidos por reflexão sobre `Microsoft.Agents.AI.Hosting`** em 2026-09-08. Last-verified: 2026-09-08.
9
9
 
10
10
  ---
11
11
 
@@ -33,12 +33,15 @@ e os patterns de telemetria, resilência (retry + rate-limit) e anti-hallucinati
33
33
 
34
34
  Exponha agents como serviços web interoperáveis via protocolo A2A padronizado.
35
35
 
36
- **Package (GA):**
36
+ **Package — PRERELEASE, e fora do `ai-pin.json`:**
37
37
 
38
38
  ```xml
39
- <PackageReference Include="Microsoft.Agents.AI.A2A" Version="1.0.*" />
39
+ <!-- Apurado no nuget.org em 2026-09-08: não há versão estável de Microsoft.Agents.AI.A2A. -->
40
+ <PackageReference Include="Microsoft.Agents.AI.A2A" Version="1.20.0-preview.260831.1" />
40
41
  ```
41
42
 
43
+ > **Correção de 2026-09-08:** a versão anterior deste standard rotulava o A2A como **GA** com faixa `1.0.*`. Nenhuma das duas coisas se sustenta: o pacote nunca teve versão estável, e faixa flutuante num SDK de cadência semanal é o defeito que `ai-agents-setup` §1 proíbe.
44
+
42
45
  ### Expor um agent via A2A
43
46
 
44
47
  ```csharp
@@ -181,7 +184,30 @@ public async Task<WeatherResponse> GetWeatherAsync(
181
184
 
182
185
  Setup, enrichment (span attributes, correlation IDs, structured logging) e o workflow de investigação/análise de logs em produção têm **tratamento canônico** em **`ai-agents-observability-patterns`**. Não duplicado aqui.
183
186
 
184
- > Em produção: source name sempre `AgentOpenTelemetryConsts.DefaultSourceName`; `EnableSensitiveTelemetryData = false` fora de dev/staging. Ver `ai-agents-observability-patterns` para o setup completo, o que preencher em cada span/log, e o workflow de investigação quando um incidente for reportado.
187
+ > Em produção: `AddSource` das **duas** fontes — `Experimental.Microsoft.Agents.AI` e `Experimental.Microsoft.Extensions.AI` — e `EnableSensitiveData = false` fora de dev/staging. (Correção de 2026-09-08: `AgentOpenTelemetryConsts` e `EnableSensitiveTelemetryData` **não existem** no pin; medido.) Ver `ai-agents-observability-patterns` para o setup completo, o que preencher em cada span/log, e o workflow de investigação quando um incidente for reportado.
188
+
189
+ ---
190
+
191
+ ## Isolamento multi-tenant — renomeado em 1.18
192
+
193
+ Um agente registrado como singleton atende todos os tenants. O que separa um do outro não é o agente: é a **chave de isolamento** que decide de qual balde vem a sessão.
194
+
195
+ Na **1.18** (2026-08-18) essa superfície foi renomeada. Nomes atuais, medidos por reflexão sobre `Microsoft.Agents.AI.Hosting` (pacote `1.20.0-preview.260831.1`) em 2026-09-08:
196
+
197
+ | Tipo | Papel |
198
+ |---|---|
199
+ | `Microsoft.Agents.AI.Hosting.AgentIsolationKeyProvider` | Produz a chave de isolamento do request corrente |
200
+ | `Microsoft.Agents.AI.Hosting.IsolationKeyScopedAgentSessionStore` | O `AgentSessionStore` que aplica a chave; tem `IsolationKeyScopedAgentSessionStoreOptions` |
201
+ | `UseClaimsBasedAgentIsolation()` (ASP.NET Core) | Deriva a chave das claims do usuário autenticado |
202
+
203
+ **Duas advertências que valem mais que os nomes:**
204
+
205
+ 1. **O pacote é prerelease.** `Microsoft.Agents.AI.Hosting` não tem versão estável (apurado 2026-09-08). Isolamento multi-tenant por esse caminho é adoção de preview — registre em `decisions.md`.
206
+ 2. **A chave vem da credencial, nunca do payload.** Uma chave derivada de algo que o cliente envia é uma chave que o cliente escolhe. `UseClaimsBasedAgentIsolation()` existe exatamente para não deixar essa decisão passar pelo corpo do request.
207
+
208
+ ### Invocação concorrente de tools é opt-in desde 1.18
209
+
210
+ `FunctionInvokingChatClient.AllowConcurrentInvocation` (exposto como `ChatClientAgentOptions.AllowConcurrentInvocation`) tem default **`false`**: numa volta com várias chamadas de tool, elas rodam **em sequência**. Ligar a concorrência é decisão explícita — e só é segura se **todas** as tools daquele agente forem thread-safe. Um `DbContext` do EF Core **não** é: duas tools concorrentes sobre o mesmo `DbContext` scoped produzem `InvalidOperationException` intermitente sob carga, que é o pior formato possível de bug.
185
211
 
186
212
  ---
187
213
 
@@ -194,18 +220,21 @@ Setup, enrichment (span attributes, correlation IDs, structured logging) e o wor
194
220
  - [ ] Rate limiting middleware em agents expostos publicamente
195
221
  - [ ] Endpoints A2A protegidos com autenticação
196
222
  - [ ] Structured output usado para respostas — evita parsing de texto livre
197
- - [ ] OpenTelemetry com `AgentOpenTelemetryConsts.DefaultSourceName` configurado
223
+ - [ ] OpenTelemetry com `AddSource` das duas fontes `Experimental.Microsoft.*` configurado
224
+ - [ ] Multi-tenant: a chave de isolamento vem da credencial (claims), nunca do payload do request
198
225
 
199
226
  ---
200
227
 
201
228
  ## Production Checklist (verifiable by morph-eval)
202
229
 
203
- - [ ] `Microsoft.Agents.AI` 1.0.* no `.csproj`; nenhum pacote `Experimental.*` ou SK
230
+ - [ ] `Microsoft.Agents.AI` **1.20.0** (versão exata, do `ai-pin.json`) no `.csproj`; nenhum pacote SK de orquestração
231
+ - [ ] Nenhum `PackageReference` de SDK de IA com faixa flutuante; pacote fora do pin com versão exata + data de apuração
232
+ - [ ] `AllowConcurrentInvocation` continua `false`, ou todas as tools do agente são comprovadamente thread-safe
204
233
  - [ ] Middleware registrado via `.AsBuilder().Use(...)` antes de `Build()`
205
234
  - [ ] `ResilientToolMiddleware` (ou equivalente) em agents que chamam APIs externas
206
235
  - [ ] Semantic cache configurado se o agent recebe queries repetitivas
207
- - [ ] OpenTelemetry source = `AgentOpenTelemetryConsts.DefaultSourceName`
208
- - [ ] Dados sensíveis de telemetry desabilitados em produção (`EnableSensitiveTelemetryData = false`)
236
+ - [ ] OpenTelemetry source = `Experimental.Microsoft.Agents.AI` **e** `Experimental.Microsoft.Extensions.AI`
237
+ - [ ] Dados sensíveis de telemetry desabilitados em produção (`EnableSensitiveData = false`)
209
238
  - [ ] A2A endpoints com `MapA2A` protegidos por auth se expostos na internet
210
239
  - [ ] MCP client `await using` para dispose correto do transporte
211
240
 
@@ -228,4 +257,4 @@ Setup, enrichment (span attributes, correlation IDs, structured logging) e o wor
228
257
 
229
258
  ---
230
259
 
231
- *MORPH-SPEC by Polymorphism Tech — ai-agents/production.md v2.1 (2026-05-19)*
260
+ *MORPH-SPEC by Polymorphism Tech — ai-agents/production.md v3.0 (2026-09-08)*