@polymorphism-tech/morph-spec 8.33.0 → 8.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/CLAUDE.md +22 -2
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +43 -5
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +5 -4
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +2 -2
  8. package/framework/MORPH.md +20 -22
  9. package/framework/agents.json +198 -44
  10. package/framework/ai-pin.json +22 -0
  11. package/framework/commands/morph-media.md +45 -0
  12. package/framework/docs/CLI.md +238 -10
  13. package/framework/evals/proof-rubrics/README.md +76 -0
  14. package/framework/evals/proof-rubrics/eval-de-modelo.md +64 -0
  15. package/framework/evals/proof-rubrics/fiacao.md +54 -0
  16. package/framework/evals/proof-rubrics/guard-cego.md +52 -0
  17. package/framework/evals/proof-rubrics/media-claims.md +109 -0
  18. package/framework/evals/proof-rubrics/mutation-proof.md +77 -0
  19. package/framework/evals/proof-rubrics/observabilidade-genai.md +119 -0
  20. package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +48 -0
  21. package/framework/evals/rubrics/architecture.md +30 -0
  22. package/framework/evals/rubrics/code-quality.md +26 -0
  23. package/framework/evals/rubrics/test-coverage.md +20 -0
  24. package/framework/hooks/README.md +11 -1
  25. package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +5 -8
  26. package/framework/hooks/claude-code/core/block-raw-worktree-add.js +79 -0
  27. package/framework/hooks/claude-code/core/chain.js +27 -7
  28. package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
  29. package/framework/hooks/claude-code/core/worktree-context.js +83 -14
  30. package/framework/hooks/claude-code/core/worktree-create.js +206 -0
  31. package/framework/hooks/claude-code/core/worktree-env-inject.js +87 -0
  32. package/framework/hooks/claude-code/core/worktree-remove.js +81 -0
  33. package/framework/hooks/shared/command-tokens.js +23 -0
  34. package/framework/hooks/shared/e2e-check.js +0 -0
  35. package/framework/hooks/shared/git-paths.js +25 -0
  36. package/framework/hooks/shared/hook-response.js +17 -0
  37. package/framework/hooks/shared/morph-cli.js +134 -0
  38. package/framework/rules/ai-agents-standards.md +14 -2
  39. package/framework/rules/infrastructure-standards.md +3 -1
  40. package/framework/schemas/ai-pin.schema.json +97 -0
  41. package/framework/schemas/config.schema.json +107 -0
  42. package/framework/schemas/feature.schema.json +23 -4
  43. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  44. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  45. package/framework/skills/core/morph-apply/SKILL.md +28 -7
  46. package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
  47. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  48. package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
  49. package/framework/skills/core/morph-implement/SKILL.md +20 -2
  50. package/framework/skills/core/morph-media/SKILL.md +215 -0
  51. package/framework/skills/core/morph-plan/SKILL.md +38 -4
  52. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  53. package/framework/skills/core/morph-review/SKILL.md +166 -9
  54. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  55. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  56. package/framework/skills/core/morph-uiux/SKILL.md +1 -1
  57. package/framework/standards/PROVENANCE.json +81 -3
  58. package/framework/standards/STANDARDS.json +1504 -830
  59. package/framework/standards/ai-agents/agent-archetypes.md +160 -0
  60. package/framework/standards/ai-agents/agent-session.md +256 -160
  61. package/framework/standards/ai-agents/agent-spec.md +196 -0
  62. package/framework/standards/ai-agents/batching.md +217 -193
  63. package/framework/standards/ai-agents/context-providers.md +261 -188
  64. package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
  65. package/framework/standards/ai-agents/cost-and-budget.md +256 -0
  66. package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
  67. package/framework/standards/ai-agents/evals-with-cache.md +289 -0
  68. package/framework/standards/ai-agents/guardrails.md +222 -0
  69. package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
  70. package/framework/standards/ai-agents/mcp-server.md +351 -250
  71. package/framework/standards/ai-agents/mcp-tools.md +250 -197
  72. package/framework/standards/ai-agents/media-pipeline.md +352 -0
  73. package/framework/standards/ai-agents/media-video.md +267 -0
  74. package/framework/standards/ai-agents/middleware-patterns.md +241 -207
  75. package/framework/standards/ai-agents/modalities-image-gen.md +422 -173
  76. package/framework/standards/ai-agents/modalities-speech-to-text.md +177 -171
  77. package/framework/standards/ai-agents/modalities-text-to-speech.md +189 -181
  78. package/framework/standards/ai-agents/modalities-vision.md +205 -201
  79. package/framework/standards/ai-agents/multi-agent-patterns.md +211 -155
  80. package/framework/standards/ai-agents/observability-patterns.md +227 -17
  81. package/framework/standards/ai-agents/production.md +260 -231
  82. package/framework/standards/ai-agents/prompt-sources.md +389 -0
  83. package/framework/standards/ai-agents/providers/model-registry.md +293 -158
  84. package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
  85. package/framework/standards/ai-agents/service-tier-flex.md +143 -135
  86. package/framework/standards/ai-agents/setup.md +166 -50
  87. package/framework/standards/ai-agents/structured-output.md +280 -249
  88. package/framework/standards/ai-agents/sweet-spot.md +129 -109
  89. package/framework/standards/ai-agents/testing-ai.md +236 -0
  90. package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
  91. package/framework/standards/ai-agents/workflows.md +27 -7
  92. package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
  93. package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
  94. package/framework/standards/infrastructure/docker/local-compose-isolation.md +90 -0
  95. package/framework/templates/REGISTRY.json +14 -1
  96. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
  97. package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
  98. package/framework/templates/dotnet/ai-kit/Directory.Build.props +25 -0
  99. package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
  100. package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
  101. package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
  102. package/framework/templates/dotnet/ai-kit/README.md +128 -0
  103. package/framework/templates/dotnet/ai-kit/global.json +9 -0
  104. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
  105. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
  106. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
  107. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
  108. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
  109. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
  110. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
  111. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
  112. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
  113. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
  114. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
  115. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
  116. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
  117. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
  118. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
  119. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
  120. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
  121. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
  122. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
  123. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
  124. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
  125. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
  126. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
  127. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
  128. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
  129. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
  130. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
  131. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
  132. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
  133. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
  134. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
  135. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
  136. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
  137. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
  138. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
  139. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
  140. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
  141. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
  142. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
  143. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
  144. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
  145. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
  146. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
  147. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
  148. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
  149. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
  150. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
  151. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
  152. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
  153. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
  154. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
  155. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
  156. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
  157. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
  158. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
  159. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
  160. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
  161. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
  162. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
  163. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
  164. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
  165. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
  166. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
  167. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
  168. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
  169. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
  170. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
  171. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
  172. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
  173. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
  174. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
  175. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
  176. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
  177. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
  178. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
  179. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
  180. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
  181. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
  182. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
  183. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
  184. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
  185. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
  186. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
  187. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
  188. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
  189. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
  190. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
  191. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
  192. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
  193. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
  194. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
  195. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
  196. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
  197. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
  198. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
  199. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
  200. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
  201. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
  202. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
  203. package/framework/templates/infrastructure/docker/docker-compose.template.yml +24 -14
  204. package/package.json +3 -3
  205. package/src/commands/e2e/e2e.js +91 -40
  206. package/src/commands/project/doctor.js +143 -6
  207. package/src/commands/project/env.js +95 -0
  208. package/src/commands/project/update.js +469 -153
  209. package/src/commands/project/worktree.js +274 -53
  210. package/src/commands/state/advance.js +24 -2
  211. package/src/commands/state/approve.js +33 -1
  212. package/src/commands/state/create.js +72 -11
  213. package/src/commands/state/delete.js +8 -0
  214. package/src/commands/state/finish.js +360 -53
  215. package/src/commands/state/gate-check.js +190 -6
  216. package/src/commands/state/score.js +36 -1
  217. package/src/commands/validation/verify.js +134 -25
  218. package/src/core/state/state-manager.js +9 -1
  219. package/src/dashboard/app/pages/HookInspector.jsx +430 -418
  220. package/src/dashboard/scanner/hooks-scanner.js +5 -1
  221. package/src/lib/ai/ai-checks.js +182 -0
  222. package/src/lib/ai/ai-project-scan.js +347 -0
  223. package/src/lib/ai/code-audit.js +181 -0
  224. package/src/lib/ai/comment-stripper.js +184 -0
  225. package/src/lib/ai/pin-drift.js +138 -0
  226. package/src/lib/ai/registry-audit.js +285 -0
  227. package/src/lib/e2e/compose-env.js +55 -14
  228. package/src/lib/e2e/stack-teardown.js +115 -0
  229. package/src/lib/evaluator-report.js +269 -15
  230. package/src/lib/generators/architecture-scanner.js +2 -1
  231. package/src/lib/git/default-branch.js +92 -4
  232. package/src/lib/graph/graphifyignore.js +2 -1
  233. package/src/lib/installers/effects.js +193 -0
  234. package/src/lib/installers/templates-reconcile.js +3 -3
  235. package/src/lib/risk-detector.js +284 -0
  236. package/src/lib/standards/verified-against.js +276 -0
  237. package/src/lib/tasks/eval-node.js +485 -0
  238. package/src/lib/tasks/linux-runner.js +297 -0
  239. package/src/lib/tasks/test-nodes.js +486 -0
  240. package/src/lib/tasks/test-runner.js +431 -37
  241. package/src/lib/validators/verify-runner.js +590 -28
  242. package/src/lib/worktree/dirs.js +32 -0
  243. package/src/lib/worktree/docker-audit.js +287 -0
  244. package/src/lib/worktree/env-allocator.js +69 -11
  245. package/src/lib/worktree/worktree-audit.js +70 -3
  246. package/src/scripts/setup-infra.js +24 -11
  247. package/src/utils/agents-installer.js +18 -8
  248. package/src/utils/claude-md-injector.js +10 -5
  249. package/src/utils/file-copier.js +28 -16
  250. package/src/utils/hooks-installer.js +75 -29
  251. package/src/utils/skills-installer.js +194 -187
  252. package/src/utils/version-checker.js +68 -3
  253. package/framework/standards/ai-agents/prompts-in-db.md +0 -214
@@ -0,0 +1,352 @@
1
+ # Media Pipeline — job, revisão humana, proveniência e marcação
2
+
3
+ > **Scope:** stacks=["dotnet"]
4
+ > **Layer:** 1 (load when relevant)
5
+ > **Keywords:** media pipeline, media job, geração de mídia, revisão humana, C2PA, SynthID, AI Act, idempotência de mídia, teto de custo, marcação de IA
6
+ > **Read by Claude in:** plan e implement (sempre que a feature gerar imagem ou vídeo)
7
+
8
+ **Verified against:** Microsoft.Extensions.AI 10.9.0 + OpenAI 2.13.0 + Google.GenAI 1.21.0 (ai-pin 2026-09-08); provado por `templates/dotnet/ai-kit/src/Morph.AiKit/Media/` — a máquina de estados (`MediaJob`), a revisão humana (`MediaReview`), a marcação exigida na publicação (`MediaDisclosure` + `MediaJob.Publish`), as duas chaves (`MediaIdempotencyKey` × `MediaHash`), o storage por conteúdo (`MediaStore`) e a acessibilidade `internal` de `IMediaProvider` compilam e são exercitados por teste. Preço, data de desligamento, C2PA/SynthID e o texto legal do AI Act são **verificação documental** contra as páginas de §Como re-verificar este standard. Last-verified: 2026-09-08.
9
+
10
+ ---
11
+
12
+ **Fronteira, primeiro.** `ai-agents/durable-workflows-hitl.md` cobre HITL e checkpoint **dentro de
13
+ um Workflow MAF** — `RequestPort`, `RequestInfoEvent`, `ICheckpointStore`. Este standard é a outra
14
+ coisa: um **pipeline de domínio**, cujo mecanismo de job é `BackgroundService`/Channels ou
15
+ Hangfire/Quartz com storage persistido. O wiring de job (enqueue, retry, `IDbContextFactory`,
16
+ dashboard) já é standard e **não se repete aqui**:
17
+ `backend/integrations/hangfire/hangfire-jobs.md`. Use `RequestPort` só quando o passo humano é, de
18
+ fato, um nó de um grafo de agente — o que quase nunca é o caso de aprovar uma foto de catálogo.
19
+
20
+ O que este standard acrescenta ao mecanismo de job é o que o job **não sabe**: quais estados
21
+ existem, quem pode aprovar, o que é persistido, o que é marcado e quanto pode custar.
22
+
23
+ Imagem: `ai-agents/modalities-image-gen.md`. Vídeo: `ai-agents/media-video.md`.
24
+
25
+ ---
26
+
27
+ ## A regra dura
28
+
29
+ > **Nunca gere mídia dentro de um turno de conversa.** Nem em WhatsApp, nem em chat, nem em webhook
30
+ > síncrono. O turno **enfileira e confirma**; a mídia volta depois, revisada.
31
+
32
+ Três números sustentam a regra, e nenhum deles é opinião:
33
+
34
+ | Fato | Consequência dentro do turno |
35
+ |---|---|
36
+ | Imagem: latência documentada de **até 2 minutos** para prompt complexo | O turno estoura antes da resposta |
37
+ | Vídeo: **11 s a 6 min**, assíncrono por desenho em todo provedor | Não existe caminho síncrono para tentar |
38
+ | Custo **por chamada**, sem teto natural | Um usuário curioso vira uma fatura |
39
+ | **Zero revisão possível** dentro do turno | Claim visual errado sai direto para o cliente |
40
+
41
+ O quarto é o que não tem contorno técnico. Latência se resolve com paciência e custo com orçamento;
42
+ "ninguém olhou antes de publicar" não se resolve com nada.
43
+
44
+ > **De onde vêm os dois números de latência.** "Até 2 minutos" é a frase do guia de geração de imagem
45
+ > da OpenAI (`https://developers.openai.com/api/docs/guides/image-generation`); "11 s a 6 min" é a
46
+ > faixa da documentação do Veo (`https://ai.google.dev/gemini-api/docs/veo`). Ambas consultadas em
47
+ > **2026-09-07**, e ambas na lista de §Como re-verificar este standard. **Nenhum dos dois foi medido
48
+ > por esta casa** — gerar mídia para cronometrar custaria dinheiro, e um número medido uma vez numa
49
+ > região não vale como SLA.
50
+
51
+ ### Como a regra é presa
52
+
53
+ **Prosa não prende regra.** O que prende é a forma da API:
54
+
55
+ - O tipo que **produz bytes** (`IMediaProvider` e as implementações de provedor) é `internal` ao
56
+ assembly do kit, com `InternalsVisibleTo` liberando apenas os testes. Um handler de mensagem no
57
+ projeto consumidor **não consegue nomear** esse tipo — o código não compila.
58
+ - A única superfície pública é `IMediaGenerator.EnqueueAsync`, que devolve um **id de job** e nunca
59
+ bytes. `GetAsync` devolve o job, com o estado dele.
60
+ - O worker que chama o provedor também é `internal`. Ele é montado por uma **raiz de composição**
61
+ (`MorphMedia.Create(options)`, no exemplar), que devolve as duas interfaces públicas —
62
+ `IMediaGenerator` e `IMediaJobRunner` — e nenhuma forma de alcançar o provider. O projeto registra
63
+ o resultado no seu contêiner numa linha; a montagem **não** é uma extensão de `IServiceCollection`,
64
+ porque isso obrigaria o kit a referenciar o pacote de DI, e o exemplar deste repositório escreve o
65
+ porquê no próprio arquivo. A propriedade que importa é a mesma nos dois desenhos: **não existe
66
+ caminho público até o tipo que produz bytes.**
67
+
68
+ É a diferença entre "o standard diz para não fazer" e "o compilador recusa". O exemplar está em
69
+ `templates/dotnet/ai-kit/src/Morph.AiKit/Media/`, e a acessibilidade é asserida por reflexão num
70
+ teste — porque uma regra que ninguém viu falhar pode ser a regra errada.
71
+
72
+ ### O que o tipo prende, e o que ele não prende
73
+
74
+ Ser exato aqui vale mais que ser tranquilizador, porque é o exato que sobrevive a uma revisão.
75
+
76
+ **Prende:** um handler não consegue **obter bytes** (a superfície pública devolve id de job) nem
77
+ **nomear** o tipo que os produz (`internal` — o código não compila). Nenhuma quantidade de pressa
78
+ contorna isso, e a acessibilidade é asserida por reflexão num teste.
79
+
80
+ **Não prende:** `IMediaJobRunner.RunAsync` é **público** — precisa ser, porque é o
81
+ `BackgroundService`/Hangfire do projeto que o dispara. Um handler pode escrever
82
+ `await runner.RunAsync(id)` e, com isso, **aguardar a chamada paga dentro do turno**. Ele não vê os
83
+ bytes, mas paga a latência: os mesmos até 2 min em imagem, 11 s a 6 min em vídeo.
84
+
85
+ Ou seja: o tipo fecha **"gere estes bytes agora"** e deixa aberto **"rode este job agora"**. Fechar
86
+ o segundo também exigiria esconder o gatilho de quem precisa dele, e o remédio seria pior. A leitura
87
+ no seu projeto é literal: **um `await` num runner dentro de um handler de mensagem é o defeito**,
88
+ mesmo compilando — e é isso que a revisão de código procura, porque o compilador não vai procurar
89
+ por ela.
90
+
91
+ ---
92
+
93
+ ## A máquina de estados
94
+
95
+ ```
96
+ Pending ──▶ Generating ──▶ Generated ──┬──▶ Approved ──▶ Published
97
+ │ │ ├──▶ Rejected
98
+ └────────────┴──▶ Failed └──▶ RejectedByPolicy
99
+ ```
100
+
101
+ | Estado | Significa | Retryable? |
102
+ |---|---|---|
103
+ | `Pending` | Pedido aceito, nada gasto ainda | — |
104
+ | `Generating` | Chamada paga em voo (ou tarefa remota em polling) | — |
105
+ | `Generated` | Bytes existem no **seu** storage | — |
106
+ | `Approved` | Humano aprovou. **Única** porta para `Published` | — |
107
+ | `Rejected` | Humano recusou | não |
108
+ | `RejectedByPolicy` | **Bloqueio de moderação do provedor** | **não** |
109
+ | `Published` | Publicado, com a marcação **registrada junto** — ver a terceira porta abaixo | — |
110
+ | `Failed` | Erro técnico (429, 5xx, timeout, download quebrado) | **sim** |
111
+
112
+ **`RejectedByPolicy` não é `Failed`, e a distinção é dinheiro.** Um bloqueio de moderação é uma
113
+ resposta definitiva: retentá-lo gasta para receber o mesmo "não" — e nos provedores que cobram o
114
+ bloqueio, gasta duas vezes. Modelar bloqueio como erro técnico é como um retry loop vira uma fatura.
115
+
116
+ **`Approve(reviewer)` é a única transição para `Approved`**, e `Publish()` devolve falha a partir de
117
+ qualquer estado que não seja `Approved`. É assim que "há revisão humana" deixa de ser uma frase no
118
+ README e vira um caminho que o código não tem.
119
+
120
+ **A publicação tem três portas, e não uma.** No exemplar, a assinatura é
121
+ `Publish(MediaDisclosure? disclosure, DateTimeOffset publishedAt)`, e ela recusa:
122
+
123
+ 1. **estado** diferente de `Approved` — inclusive `Generated`, que é o atalho que alguém sempre quer;
124
+ 2. **finalidade não publicável** — `Draft` se declarava "nunca publicável" num comentário que nada
125
+ cobrava;
126
+ 3. **marcação ausente** quando a finalidade a exige (`RequiresDisclosure()`: catálogo e marketing).
127
+
128
+ A ordem importa e é testada: um job não aprovado reclama da revisão humana, **não** da marcação —
129
+ mandar consertar o rótulo de algo que ninguém revisou manda consertar a coisa errada.
130
+
131
+ ---
132
+
133
+ ## As duas chaves de idempotência
134
+
135
+ Duas chaves distintas, e confundi-las é o defeito caro:
136
+
137
+ | Chave | Fórmula | O que dedupe |
138
+ |---|---|---|
139
+ | **De pedido** | `sha256(provider + model + prompt normalizado + sha256 de cada referência + opções)` | A **chamada paga** |
140
+ | **De conteúdo** | `sha256(bytes)` | O **storage** |
141
+
142
+ A chave **de pedido** é consultada **antes** de chamar o provedor: se já existe job com a mesma
143
+ chave e resultado, reuse o artefato em vez de pagar de novo. É o que faz um retry — de fila, de
144
+ worker reiniciado, de webhook duplicado — custar zero.
145
+
146
+ A chave **de conteúdo** é o endereço do arquivo: `PutAsync` do mesmo conteúdo devolve o caminho já
147
+ existente sem regravar. Dois pedidos diferentes podem produzir bytes idênticos; um pedido só sempre
148
+ produz o mesmo pedido.
149
+
150
+ Trocar a foto de referência muda a chave de pedido mesmo com prompt idêntico — por isso o sha256 de
151
+ **cada** referência entra na fórmula, e não a contagem delas.
152
+
153
+ ---
154
+
155
+ ## Storage
156
+
157
+ - **Bytes no blob próprio**, sempre. URL de provedor expira: o Veo apaga o arquivo em 2 dias, e todo
158
+ agregador devolve URL temporária.
159
+ - O banco guarda **caminho relativo + sha256**, nunca URL absoluta de provedor e nunca o caminho
160
+ absoluto do disco de hoje.
161
+ - O download acontece **no mesmo passo** que detectou a conclusão, antes de marcar `Generated`. Um
162
+ job em `Generated` sem bytes no seu storage está mentindo sobre o próprio estado.
163
+
164
+ ---
165
+
166
+ ## Proveniência persistida
167
+
168
+ Um registro por job, gravado no momento da geração:
169
+
170
+ | Campo | Por quê |
171
+ |---|---|
172
+ | `provider`, `modelId` | Sem eles, nenhuma auditoria de "que modelo gerou isto" é possível |
173
+ | `promptFinal` | O texto que foi enviado, não o template |
174
+ | `revisedPrompt` | O que o provedor reescreveu — frequentemente diferente do enviado |
175
+ | `refsHash` | sha256 das referências, o mesmo que entra na chave de pedido |
176
+ | `options` | Tamanho, qualidade, formato, background |
177
+ | `responseId` | O id do lado do provedor, para abrir chamado |
178
+ | `estimatedCostUsd` | Gravado **antes** da chamada — ver §Teto de custo |
179
+ | `createdAt` | — |
180
+ | `c2paPreserved` | Se os metadados sobreviveram ao seu pipeline |
181
+
182
+ **Metadados C2PA são preservados: nada de re-encode destrutivo.** Um resize ou uma recompressão
183
+ "para economizar CDN" apaga a credencial de conteúdo que o provedor embutiu, e você fica sem a única
184
+ prova técnica de origem que tinha.
185
+
186
+ ---
187
+
188
+ ## Marcação, C2PA e SynthID
189
+
190
+ As imagens das duas famílias já vêm com credencial embutida — **C2PA Content Credentials + SynthID**
191
+ na OpenAI, **SynthID** em toda imagem Gemini — e a OpenAI expõe um endpoint
192
+ `content_provenance_check` que verifica ambos.
193
+
194
+ **E isso não basta**, por três razões escritas na própria documentação:
195
+
196
+ 1. **C2PA cai com screenshot e com re-encode.** Qualquer trânsito por uma ferramenta que reprocessa
197
+ o arquivo apaga a credencial. SynthID sobrevive melhor, mas não é infalível.
198
+ 2. **`not_detected` não significa "feito por humano".** A ausência de marca é ausência de
199
+ informação, nunca prova de origem.
200
+ 3. **A credencial é invisível para quem olha a imagem.** Um cliente no WhatsApp não roda verificador
201
+ de proveniência.
202
+
203
+ Por isso **a marcação visível é obrigação separada**, aplicada no ponto de publicação e não no de
204
+ geração.
205
+
206
+ ### Como esta obrigação é presa — e até onde ela chega
207
+
208
+ Uma obrigação legal escrita só em prosa é a mesma coisa que nenhuma obrigação: alguém esquece, o
209
+ teste fica verde, e o silêncio vira aprovação. No exemplar ela é **um parâmetro obrigatório da
210
+ transição**, não um lembrete:
211
+
212
+ ```csharp
213
+ public sealed record MediaDisclosure(string Text, string Surface, DateTimeOffset AppliedAt);
214
+
215
+ // Texto E superfície são exigidos na construção: "marcado" sem dizer ONDE não responde
216
+ // se alguém consegue ver, e texto em branco é o campo preenchido "para passar".
217
+ public static bool RequiresDisclosure(this MediaPurpose purpose)
218
+ => purpose is MediaPurpose.CatalogPhoto or MediaPurpose.Marketing;
219
+ ```
220
+
221
+ `MediaJob.Publish(null, at)` sobre um job de catálogo **aprovado** devolve falha nomeando a
222
+ marcação. A mutação foi rodada: removida a terceira porta, os dois casos de
223
+ `MediaDisclosureTests.PublishFailsWithoutADisclosureWhenThePurposeDemandsOne` morrem
224
+ (`CatalogPhoto` e `Marketing`), a suíte cai de 220/0 para 220/2, e a mensagem de falha diz por quê.
225
+
226
+ **O limite, dito em voz alta.** Isto prova que a **decisão foi tomada e gravada**, com texto e
227
+ superfície nomeados — não que o rótulo chegou aos olhos de alguém. Nenhum tipo em C# alcança um
228
+ pixel: a renderização é do aplicativo consumidor. O que o mecanismo elimina é o caminho silencioso
229
+ "esquecemos de marcar", que passa a ser uma recusa na publicação.
230
+
231
+ ### EU AI Act art. 50
232
+
233
+ O Regulamento (UE) 2024/1689 exige, no art. 50, transparência sobre conteúdo sintético: imagem
234
+ gerada que **possa parecer autêntica** sobre produto, pessoa ou lugar exige aviso claro no primeiro
235
+ contato.
236
+
237
+ **Ressalva de fonte, declarada em vez de escondida.** O art. 113 do regulamento diz *"It shall apply
238
+ from 2 August 2026"*, e o Capítulo IV — onde vive o art. 50 — **não tem data própria** naquele
239
+ artigo; daí a leitura de que ele segue a data geral de **2026-08-02**. Essa derivação é **leitura do
240
+ artigo, não citação de um considerando explícito**, e foi feita sobre
241
+ `https://artificialintelligenceact.eu/article/113/`, uma fonte secundária que reproduz o texto.
242
+ **Antes de o seu projeto assumir consequência jurídica** — prazo, multa, obrigação de rótulo —
243
+ confira o mesmo artigo no EUR-Lex e registre a leitura com a data. Este standard afirma o
244
+ mecanismo (marcar é obrigação de desenho); ele **não** é parecer jurídico, e escrever um número de
245
+ multa aqui como se fosse fato verificado seria exatamente o defeito que ele combate.
246
+
247
+ Regra de desenho, independente do prazo: **produto real sobre cena gerada é declarado como tal**, e
248
+ nenhuma geração cria claim visual de material, medida ou cor que o produto não tem. Isso é
249
+ codificado — uma lista de atributos bloqueados no validador do prompt — e não confiado ao texto do
250
+ prompt.
251
+
252
+ ---
253
+
254
+ ## Revisão humana
255
+
256
+ - `Approved` **exige humano** antes de `Published` para qualquer mídia de catálogo ou peça pública.
257
+ - O revisor é identificado e carimbado com data no `MediaReview` — "aprovado" sem quem e sem quando
258
+ não é revisão, é campo booleano.
259
+ - **Juiz LLM é pré-filtro, nunca substituto.** Ele derruba as candidatas obviamente ruins e economiza
260
+ o tempo do humano; ele não assume a responsabilidade de um claim visual.
261
+ - O gate humano natural é a **escolha entre N candidatas** geradas em qualidade baixa. A escada de
262
+ custo e a revisão são o mesmo passo, não dois.
263
+
264
+ ---
265
+
266
+ ## Teto de custo
267
+
268
+ - **Orçamento por tenant/dia em unidades**, não em reais: imagens × qualidade para imagem, segundos
269
+ de saída para vídeo. Unidade é o que o provedor cobra; moeda é derivada.
270
+ - **`estimatedCostUsd` é gravado antes da chamada**, com a tarifa da tabela de preço do standard da
271
+ modalidade (`modalities-image-gen.md` §Custo por chamada, `media-video.md` §Custo por segundo).
272
+ Estimar depois é contabilidade; estimar antes é controle.
273
+ - Estouro de teto é recusa **no enqueue**, com erro nomeado — nunca uma chamada que já saiu e um
274
+ alerta que chega depois.
275
+
276
+ ---
277
+
278
+ ## Telemetria
279
+
280
+ Quatro séries, por modelo, e cada uma responde a uma pergunta que alguém vai fazer:
281
+
282
+ | Série | Pergunta |
283
+ |---|---|
284
+ | Latência | "Por que o cliente ainda não recebeu?" |
285
+ | Custo | "Quanto gastamos com isto no mês?" |
286
+ | Taxa de rejeição por política | "Nosso prompt está pedindo o que o provedor não faz?" |
287
+ | Taxa de aprovação humana | "O modelo que escolhemos serve para este trabalho?" |
288
+
289
+ A última é a que ninguém instrumenta e a que mais decide: um modelo com 30 % de aprovação humana é
290
+ mais caro que um modelo com o dobro da tarifa e 90 %.
291
+
292
+ ---
293
+
294
+ ## Testes
295
+
296
+ - **Nenhum teste chama API paga.** Provider fake implementando a mesma abstração interna, store em
297
+ memória. Isso não é preferência: é a única forma de a suíte rodar em CI sem chave e sem fatura.
298
+ - O que se testa é o **mecanismo**: que `Publish` falha fora de `Approved`; que `RejectedByPolicy`
299
+ não oferece retry; que a chave de pedido é estável para o mesmo pedido e muda quando qualquer campo
300
+ participante muda; que gravar o mesmo conteúdo duas vezes grava uma.
301
+ - **Teste de acessibilidade por reflexão** para a regra dura: o tipo que produz bytes não é público.
302
+ Torná-lo público tem de derrubar esse teste — e vale rodar a mutação uma vez para ver.
303
+
304
+ ---
305
+
306
+ ## Checklist (verifiable by morph-eval)
307
+
308
+ - [ ] Nenhum handler síncrono consegue nomear o tipo que produz bytes
309
+ - [ ] Nenhum `await runner.RunAsync(...)` dentro de handler de turno — **o tipo não fecha esta
310
+ porta** (o runner é público de propósito); quem a fecha é a revisão de código
311
+ - [ ] A superfície pública devolve id de job, nunca bytes
312
+ - [ ] Os oito estados existem, e `Publish` falha fora de `Approved`
313
+ - [ ] `Publish` recusa sem marcação quando a finalidade a exige — e o teste dessa recusa existe
314
+ - [ ] Bloqueio de moderação é `rejected_by_policy`, sem retry
315
+ - [ ] Chave de **pedido** consultada antes da chamada paga; chave de **conteúdo** endereça o storage
316
+ - [ ] Bytes no blob próprio; banco com caminho relativo + sha256
317
+ - [ ] Proveniência com os nove campos, C2PA preservado sem re-encode
318
+ - [ ] Marcação visível aplicada no ponto de publicação, com texto **e** superfície nomeados
319
+ - [ ] `Approve` carimba revisor e data
320
+ - [ ] `estimatedCostUsd` gravado antes da chamada; teto por tenant/dia recusa no enqueue
321
+ - [ ] Telemetria com as quatro séries, incluindo taxa de aprovação humana
322
+ - [ ] Nenhum teste toca API paga
323
+
324
+ ---
325
+
326
+ ## Como re-verificar este standard
327
+
328
+ | Página | O que conferir |
329
+ |---|---|
330
+ | `https://developers.openai.com/api/docs/guides/content-provenance` | Se `content_provenance_check` mudou, e a afirmação de que C2PA cai com re-encode |
331
+ | `https://ai.google.dev/gemini-api/docs/image-generation` | Se SynthID continua em toda imagem Gemini |
332
+ | `https://eur-lex.europa.eu/eli/reg/2024/1689/oj` | O art. 50 e o art. 113 no texto oficial — é a fonte primária que a §EU AI Act ainda não tem |
333
+ | `https://ai.google.dev/gemini-api/docs/veo` | A retenção de 2 dias citada em §Storage |
334
+ | `modalities-image-gen.md` e `media-video.md` | As tabelas de preço que este standard referencia sem copiar |
335
+
336
+ Ao terminar, atualize `Last-verified` **e** o `ai-pin` citado no header.
337
+
338
+ ---
339
+
340
+ ## References
341
+
342
+ - `ai-agents/modalities-image-gen.md` — a chamada de imagem, os aliases e o custo
343
+ - `ai-agents/media-video.md` — a chamada de vídeo, o polling e o custo por segundo
344
+ - `backend/integrations/hangfire/hangfire-jobs.md` — o mecanismo de job: enqueue, retry,
345
+ `IDbContextFactory`, dashboard. Este standard **cita** e não reescreve
346
+ - `ai-agents/durable-workflows-hitl.md` — HITL dentro de um Workflow MAF; a outra coisa
347
+ - `ai-agents/production.md` — custo por chamada, teste sem rede, observabilidade
348
+ - `ai-agents/batching.md` — o desconto de lote que o catálogo usa
349
+
350
+ ---
351
+
352
+ *MORPH-SPEC by Polymorphism Tech — ai-agents/media-pipeline.md v1.0*
@@ -0,0 +1,267 @@
1
+ # Media — Video Generation (runtime, a partir de .NET)
2
+
3
+ > **Scope:** stacks=["dotnet"]
4
+ > **Layer:** 2 (on-keyword)
5
+ > **Keywords:** video generation, veo, seedance, kling, runway, image to video, text to video, media video
6
+ > **Read by Claude in:** implement (quando o projeto precisa gerar vídeo em runtime)
7
+
8
+ **Verified against:** Google.GenAI 1.21.0 + OpenAI 2.13.0 (ai-pin 2026-09-08); provado por `templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs` — `Models.GenerateVideosAsync(model, GenerateVideosSource, GenerateVideosConfig, ct)`, o polling por `Operations.GetAsync` + `operation.Done` e o sinal de bloqueio `RaiMediaFilteredCount` COMPILAM ali. Preço, duração, retenção e data de desligamento são **verificação documental** contra as páginas listadas em §Como re-verificar este standard. Last-verified: 2026-09-08.
9
+
10
+ ---
11
+
12
+ **A fronteira, primeiro.** Este standard é sobre **gerar vídeo em runtime a partir de .NET**: o
13
+ backend cria uma tarefa paga, faz polling, baixa bytes e guarda. Footage de landing page
14
+ scroll-driven, produzido por MCP em **tempo de autoria**, é
15
+ `frontend/design-system/ai-video-generation.md` — loop × direcional, `endImage`, o contorno de
16
+ moderação E005 e a escada de custo daquele fluxo. Os dois se citam e não se sobrepõem: lá o
17
+ operador é um designer numa sessão; aqui é um worker no seu servidor.
18
+
19
+ O pipeline (job, revisão, publicação, marcação) é `ai-agents/media-pipeline.md`. Imagem é
20
+ `ai-agents/modalities-image-gen.md`.
21
+
22
+ ---
23
+
24
+ ## Quando usar
25
+
26
+ | Caso | Nota |
27
+ |---|---|
28
+ | **Vídeo curto de produto** (reels, stories, até 8 s com áudio) | O caso que paga a conta |
29
+ | **Animar render de cliente** | `img2vid` sobre a arte real, nunca recriação por IA |
30
+ | **Variação de cena** sobre um herói aprovado | Depois da aprovação da imagem, nunca antes |
31
+
32
+ **Nunca dentro de um turno de conversa.** A geração de vídeo leva de **11 s a 6 min** medidos na
33
+ documentação do Veo, é assíncrona **por desenho em todos os provedores** — nenhum deles devolve o
34
+ arquivo na resposta do POST — e custa por segundo de saída. Não existe forma de fazer isso caber num
35
+ turno de WhatsApp; a tentativa é `ai-agents/media-pipeline.md` §A regra dura.
36
+
37
+ ---
38
+
39
+ ## O caminho com SDK
40
+
41
+ `Google.GenAI` 1.21.0, `net8.0` + `netstandard2.0`. É o **único** caminho com SDK .NET oficial
42
+ depois do desligamento listado em §Deprecações.
43
+
44
+ ```csharp
45
+ using Google.GenAI.Types;
46
+
47
+ // 1. Cria a operacao. Ela volta NAO-concluida: o video ainda nao existe.
48
+ // O prompt vai DENTRO de GenerateVideosSource — nao e um parametro solto.
49
+ var operation = await client.Models.GenerateVideosAsync(
50
+ "veo-3.1-fast-generate-preview",
51
+ new GenerateVideosSource { Prompt = prompt },
52
+ new GenerateVideosConfig { DurationSeconds = 8, AspectRatio = "16:9" },
53
+ ct);
54
+
55
+ // 2. Polling. ~10 s entre voltas e o intervalo que a doc do Veo usa; back-off e
56
+ // TETO DE TENTATIVAS — um laco sem saida e indistinguivel de um worker travado.
57
+ // `Done` e bool? : `!operation.Done` NAO compila; compare com true.
58
+ for (var poll = 0; operation.Done != true && poll < 60; poll++)
59
+ {
60
+ await Task.Delay(TimeSpan.FromSeconds(10), ct);
61
+ operation = await client.Operations.GetAsync(operation, new GetOperationConfig(), ct);
62
+ }
63
+
64
+ // 3. Bloqueio de moderacao NAO e erro tecnico, e o sinal e este:
65
+ if (operation.Response?.RaiMediaFilteredCount is > 0) { /* rejected_by_policy, sem retry */ }
66
+
67
+ // 4. BAIXE OS BYTES AGORA (operation.Response.GeneratedVideos[..].Video.VideoBytes).
68
+ // Ver a secao "O arquivo expira".
69
+ ```
70
+
71
+ > **Assinaturas medidas contra `Google.GenAI` 1.21.0 por reflexão, não lidas em blog.** Três
72
+ > detalhes derrubam o build de quem copia de uma página de terceiro: o prompt viaja em
73
+ > `GenerateVideosSource`, `Operations.GetAsync` pede um `GetOperationConfig` (não só o token), e
74
+ > `operation.Done` é `bool?` — `while (!operation.Done)` não compila. O exemplar que compila está
75
+ > em `templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs`.
76
+
77
+ Três exigências de desenho que caem deste formato, e não são opcionais:
78
+
79
+ 1. **O `operation` é estado persistido**, não variável local. Se o worker reiniciar no meio, o id da
80
+ operação tem de estar no banco — senão você paga de novo por um vídeo que já está pronto.
81
+ 2. **O polling mora num job**, nunca numa request HTTP. Um `while` de 6 minutos dentro de um
82
+ controller é um thread pool derretido.
83
+ 3. **Timeout e teto de tentativas explícitos.** `Done` que nunca vira `true` é um caso real, e um
84
+ loop sem saída é indistinguível de um worker travado.
85
+
86
+ ---
87
+
88
+ ## O caminho sem SDK
89
+
90
+ Seedance 2.0 (BytePlus ModelArk ou fal.ai), Kling 3.0 e Runway **não têm SDK .NET**. Sem exceção,
91
+ sem "biblioteca da comunidade": `HttpClient` **tipado** via `IHttpClientFactory`, DTOs próprios,
92
+ `System.Text.Json` com source generation, e Polly para 429/5xx/timeout.
93
+
94
+ O contrato é o mesmo nos três, e é o que torna o adaptador escrevível:
95
+
96
+ ```
97
+ POST criar tarefa → { id } (202 / 200, NUNCA o arquivo)
98
+ ↓ persistir o id ANTES de qualquer outra coisa
99
+ GET status(id) → queued | running | succeeded | failed
100
+ ↓ polling com back-off, OU webhook (fal.ai, Runway)
101
+ GET resultado → URL temporaria → baixar → blob proprio
102
+ ```
103
+
104
+ **Persistir o id antes de qualquer outra coisa** é a linha que separa "retry custa zero" de "retry
105
+ custa outra geração". O resto do desenho — chave de idempotência, estados, storage — está em
106
+ `ai-agents/media-pipeline.md`.
107
+
108
+ Webhook, onde existe, é preferível a polling: menos chamada, menos latência de detecção. Mas o
109
+ polling continua sendo o caminho de recuperação quando o webhook se perde — implemente os dois, e
110
+ faça o handler de webhook idempotente.
111
+
112
+ ---
113
+
114
+ ## Sora: não planejar
115
+
116
+ `sora-2`, `sora-2-pro` e o `VideoClient` do `openai-dotnet` (`CreateVideo`, `GetVideo`,
117
+ `DownloadVideo`, `CreateVideoRemix`) **saem de circulação sem substituto** — a data está em
118
+ §Deprecações. "Sem substituto" é literal: a OpenAI não anunciou modelo de vídeo sucessor.
119
+
120
+ Consequência prática: **não escreva adaptador para Sora**, não pine alias de Sora, e se encontrar um
121
+ num projeto existente, a migração é para o caminho com SDK do Google ou para um dos HTTP crus. Um
122
+ adaptador escrito hoje para Sora nasce morto.
123
+
124
+ ---
125
+
126
+ ## Custo por segundo
127
+
128
+ > **Toda a aritmética de dinheiro deste standard mora nesta seção, e em lugar nenhum mais.**
129
+
130
+ Preço de **lista pública**, em USD por segundo de saída, sem desconto de contrato. Consultadas em
131
+ **2026-09-07**: `https://ai.google.dev/gemini-api/docs/veo` com
132
+ `https://ai.google.dev/gemini-api/docs/pricing`, `https://docs.byteplus.com/en/docs/ModelArk/1520757`,
133
+ `https://fal.ai/models/bytedance/seedance-2.0/image-to-video`, `https://kling.ai/dev/pricing` e
134
+ `https://docs.dev.runwayml.com/guides/pricing/`.
135
+
136
+ | Modelo | Preço | Nota |
137
+ |---|---|---|
138
+ | Veo 3.1 **Lite** | $0,05 / s | Sem 4K |
139
+ | Veo 3.1 **Fast** — 720p | $0,10 / s | O default recomendado; áudio incluso |
140
+ | Veo 3.1 Standard — 720p/1080p | $0,40 / s | 4K: $0,60 / s |
141
+ | Seedance 2.0 (BytePlus oficial) | $0,04 – $0,78 / s | Varia por modelo e resolução; pacote pré-pago mínimo de $30,10 |
142
+ | Seedance 2.0 (fal.ai) | $0,3024 / s std 720p; $0,2419 / s fast | Mesmo modelo, agregador diferente, preço diferente |
143
+ | Kling 3.0 std | ≈ $0,42 por 5 s | Sem SDK |
144
+ | Runway gen4.5 | $0,12 / s | Créditos a $0,01; 12 cr/s |
145
+
146
+ Três leituras que decidem projeto:
147
+
148
+ 1. **A faixa do Seedance é de 20× entre o piso oficial e o teto**, e o mesmo modelo custa preços
149
+ diferentes conforme o agregador. Por isso **nenhum alias default é pinado** para Seedance, Kling
150
+ ou Runway neste standard: escolher um seria escolher fornecedor por conveniência de escrita, e não
151
+ por evidência. Meça o seu caso antes de pinar.
152
+ 2. **Vídeo é caro por segundo e mínimo de 4 s.** Um rascunho de 4 s em Lite custa uma fração de um
153
+ final de 8 s em Standard — a escada de custo é a mesma disciplina de imagem, com números maiores.
154
+ 3. **Bloqueio de moderação no Veo não cobra.** Isso muda o desenho de retry: um bloqueio é
155
+ `rejected_by_policy` e não deve ser retentado; um erro técnico é `failed` e deve.
156
+
157
+ ---
158
+
159
+ ## Duração, resolução e referências
160
+
161
+ Medido contra `https://ai.google.dev/gemini-api/docs/veo` (Veo 3.1) e a doc do BytePlus ModelArk
162
+ (Seedance 2.0), ambas consultadas na data declarada em §Custo por segundo.
163
+
164
+ | Parâmetro | Veo 3.1 | Seedance 2.0 |
165
+ |---|---|---|
166
+ | Duração | 4, 6 ou 8 s | 4 a 15 s |
167
+ | **8 s é obrigatório** para | 1080p, 4K e uso de imagens de referência | — |
168
+ | Aspect ratio | 16:9 ou 9:16 | 480p / 720p / 1080p |
169
+ | Frame rate | 24 fps | — |
170
+ | Áudio | nativo, incluso no preço | nativo |
171
+ | Imagem inicial | sim (primeiro frame) | JPEG/PNG/WebP até 30 MB |
172
+ | Interpolação | primeiro + último frame | imagem final opcional |
173
+ | Referências | **até 3 imagens** (exige 8 s) | referências de vídeo e áudio |
174
+ | Extensão | +7 s, até 20 vezes (720p) | — |
175
+
176
+ "8 s obrigatório para referências" é a pegadinha cara: pedir 4 s **com** imagem de referência é uma
177
+ requisição inválida, e descobrir isso em produção custa uma rodada de suporte.
178
+
179
+ ---
180
+
181
+ ## O arquivo expira
182
+
183
+ O Veo retém o arquivo gerado por **2 dias**. Depois disso a URL devolve 404 e o vídeo pelo qual você
184
+ pagou não existe mais em lugar nenhum.
185
+
186
+ **Baixar e gravar no blob próprio é obrigação, não otimização.** O download entra no mesmo passo do
187
+ worker que detectou `Done`, antes de qualquer outra coisa; o banco guarda caminho relativo + sha256,
188
+ nunca a URL do provedor. O mesmo vale para todo agregador: URL de resultado é sempre temporária.
189
+
190
+ Um job que marcou `generated` sem ter baixado os bytes está mentindo sobre o próprio estado. Ver
191
+ `ai-agents/media-pipeline.md` §Storage.
192
+
193
+ ---
194
+
195
+ ## Moderação e pessoas
196
+
197
+ - **Bloqueio não cobra** (Veo). Trate-o como `rejected_by_policy`: estado terminal, **sem retry**.
198
+ Retentar um bloqueio é gastar dinheiro para receber o mesmo "não" — e nos provedores que cobram o
199
+ bloqueio, é gastar duas vezes.
200
+ - **`personGeneration` é restrito por região.** O mesmo prompt aprovado num mercado é recusado em
201
+ outro; a política tem de ser por tenant, não global.
202
+ - **Rostos disparam moderação com frequência.** O motivo e o contorno operacional (enquadrar do
203
+ pescoço para baixo, mãos, produto; reservar rosto para imagem estática) estão escritos em
204
+ `frontend/design-system/ai-video-generation.md` §Section 3 — este standard cita e não repete.
205
+ - **Nunca gere rosto de cliente real.** Além do risco jurídico, é o caso que a marcação obrigatória
206
+ do `media-pipeline.md` foi feita para cobrir.
207
+
208
+ ---
209
+
210
+ ## Deprecações
211
+
212
+ > **Toda data de desligamento deste standard mora nesta seção, e em lugar nenhum mais.**
213
+
214
+ Fonte, consultada em **2026-09-07**: `https://developers.openai.com/api/docs/deprecations`.
215
+
216
+ | Alias / superfície | Situação | Data |
217
+ |---|---|---|
218
+ | `sora-2`, `sora-2-pro` e a Videos API | **desligam, sem substituto** (anunciado 2026-03-24) | 2026-09-24 |
219
+ | `VideoClient` do `openai-dotnet` | morre junto com a API acima | 2026-09-24 |
220
+
221
+ **Próximo desligamento conhecido: 2026-09-24.** Se esta data já passou quando você está lendo, este
222
+ standard não está apenas velho — ele está **errado** em pelo menos uma afirmação, e a §Como
223
+ re-verificar diz qual página conferir. É falsificável em segundos, sem pesquisa.
224
+
225
+ ---
226
+
227
+ ## Checklist (verifiable by morph-eval)
228
+
229
+ - [ ] Nenhum código novo aponta para um alias de §Deprecações
230
+ - [ ] O id da operação/tarefa é **persistido antes** do primeiro polling
231
+ - [ ] O polling roda num job, com back-off e teto de tentativas — nunca numa request HTTP
232
+ - [ ] Os bytes são baixados assim que a tarefa conclui, e gravados em blob próprio
233
+ - [ ] O banco guarda caminho relativo + sha256, nunca a URL do provedor
234
+ - [ ] Bloqueio de moderação é estado terminal `rejected_by_policy`, sem retry
235
+ - [ ] Duração pedida respeita o mínimo do provedor (8 s no Veo quando há referência)
236
+ - [ ] Custo estimado gravado antes da chamada, com a tarifa de §Custo por segundo
237
+ - [ ] Nenhuma geração dentro de um turno de conversa
238
+ - [ ] Nenhum teste toca API paga — provider fake, sempre
239
+
240
+ ---
241
+
242
+ ## Como re-verificar este standard
243
+
244
+ | Página | O que conferir |
245
+ |---|---|
246
+ | `https://developers.openai.com/api/docs/deprecations` | A tabela de §Deprecações e a linha "próximo desligamento conhecido" |
247
+ | `https://ai.google.dev/gemini-api/docs/veo` | Duração, resolução, limite de referências, retenção de 2 dias, `personGeneration` |
248
+ | `https://ai.google.dev/gemini-api/docs/pricing` | As três linhas Veo de §Custo por segundo |
249
+ | `https://docs.byteplus.com/en/docs/ModelArk/1520757` e `https://fal.ai/models/bytedance/seedance-2.0/image-to-video` | A faixa de preço do Seedance nos dois canais |
250
+ | `https://www.nuget.org/packages/Google.GenAI` | Se `GenerateVideosAsync`/`Operations.GetAsync` mudaram de forma |
251
+
252
+ Ao terminar, atualize `Last-verified` **e** o `ai-pin` citado no header.
253
+
254
+ ---
255
+
256
+ ## References
257
+
258
+ - `ai-agents/media-pipeline.md` — o job, os estados, a idempotência, a marcação
259
+ - `ai-agents/modalities-image-gen.md` — imagem em runtime, e a escada de custo irmã desta
260
+ - `frontend/design-system/ai-video-generation.md` — footage direcional para scroll scrub via MCP:
261
+ loop × direcional, `endImage`, moderação E005. Consumidor diferente, tempo diferente
262
+ - `ai-agents/providers/model-registry.md` — o alias por provedor, com `api: videos`
263
+ - `backend/integrations/hangfire/hangfire-jobs.md` — o mecanismo de job que o polling usa
264
+
265
+ ---
266
+
267
+ *MORPH-SPEC by Polymorphism Tech — ai-agents/media-video.md v1.0*