@polymorphism-tech/morph-spec 8.33.0 → 8.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +22 -2
- package/README.md +2 -2
- package/bin/morph-spec.js +43 -5
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +5 -4
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +2 -2
- package/framework/MORPH.md +20 -22
- package/framework/agents.json +198 -44
- package/framework/ai-pin.json +22 -0
- package/framework/commands/morph-media.md +45 -0
- package/framework/docs/CLI.md +238 -10
- package/framework/evals/proof-rubrics/README.md +76 -0
- package/framework/evals/proof-rubrics/eval-de-modelo.md +64 -0
- package/framework/evals/proof-rubrics/fiacao.md +54 -0
- package/framework/evals/proof-rubrics/guard-cego.md +52 -0
- package/framework/evals/proof-rubrics/media-claims.md +109 -0
- package/framework/evals/proof-rubrics/mutation-proof.md +77 -0
- package/framework/evals/proof-rubrics/observabilidade-genai.md +119 -0
- package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +48 -0
- package/framework/evals/rubrics/architecture.md +30 -0
- package/framework/evals/rubrics/code-quality.md +26 -0
- package/framework/evals/rubrics/test-coverage.md +20 -0
- package/framework/hooks/README.md +11 -1
- package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +5 -8
- package/framework/hooks/claude-code/core/block-raw-worktree-add.js +79 -0
- package/framework/hooks/claude-code/core/chain.js +27 -7
- package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
- package/framework/hooks/claude-code/core/worktree-context.js +83 -14
- package/framework/hooks/claude-code/core/worktree-create.js +206 -0
- package/framework/hooks/claude-code/core/worktree-env-inject.js +87 -0
- package/framework/hooks/claude-code/core/worktree-remove.js +81 -0
- package/framework/hooks/shared/command-tokens.js +23 -0
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/git-paths.js +25 -0
- package/framework/hooks/shared/hook-response.js +17 -0
- package/framework/hooks/shared/morph-cli.js +134 -0
- package/framework/rules/ai-agents-standards.md +14 -2
- package/framework/rules/infrastructure-standards.md +3 -1
- package/framework/schemas/ai-pin.schema.json +97 -0
- package/framework/schemas/config.schema.json +107 -0
- package/framework/schemas/feature.schema.json +23 -4
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +28 -7
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
- package/framework/skills/core/morph-implement/SKILL.md +20 -2
- package/framework/skills/core/morph-media/SKILL.md +215 -0
- package/framework/skills/core/morph-plan/SKILL.md +38 -4
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +166 -9
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/PROVENANCE.json +81 -3
- package/framework/standards/STANDARDS.json +1504 -830
- package/framework/standards/ai-agents/agent-archetypes.md +160 -0
- package/framework/standards/ai-agents/agent-session.md +256 -160
- package/framework/standards/ai-agents/agent-spec.md +196 -0
- package/framework/standards/ai-agents/batching.md +217 -193
- package/framework/standards/ai-agents/context-providers.md +261 -188
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
- package/framework/standards/ai-agents/cost-and-budget.md +256 -0
- package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
- package/framework/standards/ai-agents/evals-with-cache.md +289 -0
- package/framework/standards/ai-agents/guardrails.md +222 -0
- package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
- package/framework/standards/ai-agents/mcp-server.md +351 -250
- package/framework/standards/ai-agents/mcp-tools.md +250 -197
- package/framework/standards/ai-agents/media-pipeline.md +352 -0
- package/framework/standards/ai-agents/media-video.md +267 -0
- package/framework/standards/ai-agents/middleware-patterns.md +241 -207
- package/framework/standards/ai-agents/modalities-image-gen.md +422 -173
- package/framework/standards/ai-agents/modalities-speech-to-text.md +177 -171
- package/framework/standards/ai-agents/modalities-text-to-speech.md +189 -181
- package/framework/standards/ai-agents/modalities-vision.md +205 -201
- package/framework/standards/ai-agents/multi-agent-patterns.md +211 -155
- package/framework/standards/ai-agents/observability-patterns.md +227 -17
- package/framework/standards/ai-agents/production.md +260 -231
- package/framework/standards/ai-agents/prompt-sources.md +389 -0
- package/framework/standards/ai-agents/providers/model-registry.md +293 -158
- package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
- package/framework/standards/ai-agents/service-tier-flex.md +143 -135
- package/framework/standards/ai-agents/setup.md +166 -50
- package/framework/standards/ai-agents/structured-output.md +280 -249
- package/framework/standards/ai-agents/sweet-spot.md +129 -109
- package/framework/standards/ai-agents/testing-ai.md +236 -0
- package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
- package/framework/standards/ai-agents/workflows.md +27 -7
- package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
- package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
- package/framework/standards/infrastructure/docker/local-compose-isolation.md +90 -0
- package/framework/templates/REGISTRY.json +14 -1
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
- package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
- package/framework/templates/dotnet/ai-kit/Directory.Build.props +25 -0
- package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
- package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
- package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
- package/framework/templates/dotnet/ai-kit/README.md +128 -0
- package/framework/templates/dotnet/ai-kit/global.json +9 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
- package/framework/templates/infrastructure/docker/docker-compose.template.yml +24 -14
- package/package.json +3 -3
- package/src/commands/e2e/e2e.js +91 -40
- package/src/commands/project/doctor.js +143 -6
- package/src/commands/project/env.js +95 -0
- package/src/commands/project/update.js +469 -153
- package/src/commands/project/worktree.js +274 -53
- package/src/commands/state/advance.js +24 -2
- package/src/commands/state/approve.js +33 -1
- package/src/commands/state/create.js +72 -11
- package/src/commands/state/delete.js +8 -0
- package/src/commands/state/finish.js +360 -53
- package/src/commands/state/gate-check.js +190 -6
- package/src/commands/state/score.js +36 -1
- package/src/commands/validation/verify.js +134 -25
- package/src/core/state/state-manager.js +9 -1
- package/src/dashboard/app/pages/HookInspector.jsx +430 -418
- package/src/dashboard/scanner/hooks-scanner.js +5 -1
- package/src/lib/ai/ai-checks.js +182 -0
- package/src/lib/ai/ai-project-scan.js +347 -0
- package/src/lib/ai/code-audit.js +181 -0
- package/src/lib/ai/comment-stripper.js +184 -0
- package/src/lib/ai/pin-drift.js +138 -0
- package/src/lib/ai/registry-audit.js +285 -0
- package/src/lib/e2e/compose-env.js +55 -14
- package/src/lib/e2e/stack-teardown.js +115 -0
- package/src/lib/evaluator-report.js +269 -15
- package/src/lib/generators/architecture-scanner.js +2 -1
- package/src/lib/git/default-branch.js +92 -4
- package/src/lib/graph/graphifyignore.js +2 -1
- package/src/lib/installers/effects.js +193 -0
- package/src/lib/installers/templates-reconcile.js +3 -3
- package/src/lib/risk-detector.js +284 -0
- package/src/lib/standards/verified-against.js +276 -0
- package/src/lib/tasks/eval-node.js +485 -0
- package/src/lib/tasks/linux-runner.js +297 -0
- package/src/lib/tasks/test-nodes.js +486 -0
- package/src/lib/tasks/test-runner.js +431 -37
- package/src/lib/validators/verify-runner.js +590 -28
- package/src/lib/worktree/dirs.js +32 -0
- package/src/lib/worktree/docker-audit.js +287 -0
- package/src/lib/worktree/env-allocator.js +69 -11
- package/src/lib/worktree/worktree-audit.js +70 -3
- package/src/scripts/setup-infra.js +24 -11
- package/src/utils/agents-installer.js +18 -8
- package/src/utils/claude-md-injector.js +10 -5
- package/src/utils/file-copier.js +28 -16
- package/src/utils/hooks-installer.js +75 -29
- package/src/utils/skills-installer.js +194 -187
- package/src/utils/version-checker.js +68 -3
- package/framework/standards/ai-agents/prompts-in-db.md +0 -214
|
@@ -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:**
|
|
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
|
-
|
|
27
|
-
|
|
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(
|
|
34
|
-
tracing.AddSource(
|
|
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(
|
|
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
|
-
> **
|
|
56
|
-
|
|
57
|
-
|
|
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.
|
|
85
|
-
activity?.SetTag("gen_ai.usage.
|
|
86
|
-
activity?.SetTag("gen_ai.response.
|
|
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
|
-
|
|
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 `
|
|
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
|
-
- [ ]
|
|
138
|
-
- [ ] `
|
|
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
|
|
366
|
+
*MORPH-SPEC by Polymorphism Tech — ai-agents/observability-patterns.md v2.0 (2026-09-08)*
|