@polymorphism-tech/morph-spec 8.37.1 → 8.40.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 (317) hide show
  1. package/CLAUDE.md +37 -13
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +75 -49
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +6 -5
  8. package/framework/MORPH.md +25 -22
  9. package/framework/agents.json +96 -36
  10. package/framework/docs/CLI.md +54 -17
  11. package/framework/evals/rubrics/code-quality.md +5 -0
  12. package/framework/evals/rubrics/condensed.md +6 -2
  13. package/framework/evals/rubrics/contracts.md +20 -0
  14. package/framework/evals/rubrics/test-coverage.md +17 -6
  15. package/framework/hooks/README.md +9 -3
  16. package/framework/hooks/claude-code/core/graph-refresh-kick.js +52 -0
  17. package/framework/hooks/claude-code/core/telemetry-log.js +172 -87
  18. package/framework/hooks/claude-code/core/validate-completion.js +16 -90
  19. package/framework/hooks/claude-code/core/worktree-context.js +10 -0
  20. package/framework/hooks/shared/command-tokens.js +96 -0
  21. package/framework/hooks/shared/git-exclude.js +44 -0
  22. package/framework/hooks/shared/git-paths.js +52 -0
  23. package/framework/hooks/shared/graph-freshness.js +380 -0
  24. package/framework/hooks/shared/graph-refresh.js +416 -0
  25. package/framework/hooks/shared/morph-cli.js +17 -5
  26. package/framework/hooks/shared/redact-secrets.js +55 -0
  27. package/framework/hooks/shared/telemetry-logger.js +25 -2
  28. package/framework/hooks/shared/transcript-usage.js +80 -0
  29. package/framework/mcp/registry.json +33 -2
  30. package/framework/rubrics/backend.json +2 -2
  31. package/framework/rubrics/default.json +2 -2
  32. package/framework/rubrics/frontend.json +2 -2
  33. package/framework/rules/csharp-standards.md +1 -0
  34. package/framework/rules/infrastructure-standards.md +0 -1
  35. package/framework/rules/morph-workflow.md +10 -4
  36. package/framework/rules/nextjs-standards.md +1 -0
  37. package/framework/schemas/config.schema.json +41 -1
  38. package/framework/schemas/feature.schema.json +5 -1
  39. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  40. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  41. package/framework/skills/core/morph-apply/SKILL.md +40 -11
  42. package/framework/skills/core/morph-brainstorming/SKILL.md +16 -7
  43. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  44. package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
  45. package/framework/skills/core/morph-implement/SKILL.md +44 -10
  46. package/framework/skills/core/morph-media/SKILL.md +1 -1
  47. package/framework/skills/core/morph-plan/SKILL.md +73 -15
  48. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  49. package/framework/skills/core/morph-review/SKILL.md +51 -13
  50. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  51. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  52. package/framework/skills/core/morph-uiux/SKILL.md +39 -13
  53. package/framework/standards/STANDARDS.json +189 -14
  54. package/framework/standards/ai-agents/context-providers.md +16 -26
  55. package/framework/standards/ai-agents/durable-workflows-hitl.md +15 -21
  56. package/framework/standards/ai-agents/modalities-image-gen.md +21 -25
  57. package/framework/standards/ai-agents/modalities-speech-to-text.md +4 -15
  58. package/framework/standards/ai-agents/modalities-text-to-speech.md +2 -11
  59. package/framework/standards/ai-agents/modalities-vision.md +1 -18
  60. package/framework/standards/ai-agents/prompt-sources.md +0 -4
  61. package/framework/standards/ai-agents/testing-ai.md +2 -1
  62. package/framework/standards/architecture/code-comments.md +100 -0
  63. package/framework/standards/backend/dotnet/testing.md +22 -0
  64. package/framework/standards/backend/integrations/neon-auth/neon-auth.md +63 -50
  65. package/framework/standards/frontend/admin-app/data-table.md +562 -0
  66. package/framework/standards/frontend/admin-app/feedback.md +236 -0
  67. package/framework/standards/frontend/admin-app/forms.md +232 -0
  68. package/framework/standards/frontend/admin-app/page-structure.md +203 -0
  69. package/framework/standards/frontend/design-system/ai-image-generation.md +5 -5
  70. package/framework/standards/frontend/nextjs/components.md +37 -58
  71. package/framework/standards/frontend/nextjs/data-fetching.md +1 -0
  72. package/framework/standards/frontend/nextjs/forms.md +31 -30
  73. package/framework/standards/frontend/nextjs/state-management.md +2 -1
  74. package/framework/standards/frontend/nextjs/testing.md +18 -0
  75. package/framework/standards/integration/mcp/mcp-tools.md +48 -117
  76. package/framework/templates/code/dotnet/abstractions/result.cs +0 -2
  77. package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +26 -39
  78. package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +28 -68
  79. package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +99 -117
  80. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +2 -44
  81. package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +40 -61
  82. package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +54 -107
  83. package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +53 -58
  84. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +192 -281
  85. package/framework/templates/code/dotnet/database/migration.cs +49 -83
  86. package/framework/templates/code/dotnet/database/vector-entity.cs +2 -46
  87. package/framework/templates/code/dotnet/extensions/result-extensions.cs +0 -2
  88. package/framework/templates/code/dotnet/feature/validator.cs.hbs +11 -15
  89. package/framework/templates/code/dotnet/jobs/agent.cs +3 -51
  90. package/framework/templates/code/dotnet/jobs/job.cs +2 -97
  91. package/framework/templates/code/dotnet/test.cs +2 -87
  92. package/framework/templates/code/typescript/contracts.ts +140 -167
  93. package/framework/templates/context/design-system.md +3 -3
  94. package/framework/templates/docs/proposal.md +11 -0
  95. package/framework/templates/docs/spec.md +15 -0
  96. package/framework/templates/docs/ui-mockups.md +115 -98
  97. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +1 -48
  98. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +3 -79
  99. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +1 -70
  100. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +1 -47
  101. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +2 -99
  102. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +0 -6
  103. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +3 -88
  104. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +1 -41
  105. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +0 -21
  106. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +1 -25
  107. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +2 -63
  108. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +0 -30
  109. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +1 -52
  110. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +3 -78
  111. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +4 -109
  112. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +0 -22
  113. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +1 -36
  114. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +2 -57
  115. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +0 -75
  116. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +2 -59
  117. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +4 -111
  118. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +0 -34
  119. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +1 -57
  120. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +0 -19
  121. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +2 -74
  122. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +2 -33
  123. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +1 -43
  124. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +1 -96
  125. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +0 -13
  126. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +0 -27
  127. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +0 -33
  128. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +0 -31
  129. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +3 -75
  130. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +0 -42
  131. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +0 -39
  132. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +1 -55
  133. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +3 -59
  134. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +0 -46
  135. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +3 -28
  136. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +7 -61
  137. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +2 -37
  138. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +1 -23
  139. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +2 -82
  140. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +1 -68
  141. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +1 -62
  142. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +2 -62
  143. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +1 -25
  144. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +0 -124
  145. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +1 -73
  146. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +1 -66
  147. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +0 -41
  148. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +2 -112
  149. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +2 -43
  150. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +5 -110
  151. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +7 -103
  152. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +1 -42
  153. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +1 -30
  154. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +1 -19
  155. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +0 -48
  156. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +1 -29
  157. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +2 -38
  158. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +1 -14
  159. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +4 -69
  160. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +1 -10
  161. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +1 -57
  162. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +0 -26
  163. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +1 -19
  164. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +0 -32
  165. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +0 -14
  166. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +0 -24
  167. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +0 -32
  168. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +0 -37
  169. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +0 -24
  170. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +0 -78
  171. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +0 -53
  172. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +0 -44
  173. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +0 -44
  174. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +0 -19
  175. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +0 -24
  176. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +6 -48
  177. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +1 -13
  178. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +2 -71
  179. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +5 -100
  180. package/framework/templates/feature/decisions.md +124 -122
  181. package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +39 -43
  182. package/framework/templates/frontend/nextjs/env.mjs.hbs +29 -32
  183. package/framework/templates/frontend/nextjs/page.tsx.hbs +21 -22
  184. package/framework/templates/frontend/nextjs/use-feature.ts.hbs +42 -54
  185. package/framework/templates/integrations/asaas-client.cs +332 -387
  186. package/framework/templates/integrations/asaas-webhook.cs +290 -351
  187. package/framework/templates/integrations/neon-auth-config.cs +9 -105
  188. package/framework/templates/project/validate.js +97 -120
  189. package/package.json +2 -2
  190. package/src/commands/dashboard/dashboard.js +80 -53
  191. package/src/commands/graph/affected.js +4 -3
  192. package/src/commands/graph/build.js +109 -18
  193. package/src/commands/graph/explain.js +8 -5
  194. package/src/commands/graph/status.js +14 -8
  195. package/src/commands/mcp/mcp-setup.js +37 -9
  196. package/src/commands/observability/cost.js +148 -18
  197. package/src/commands/project/doctor.js +85 -15
  198. package/src/commands/project/init.js +6 -3
  199. package/src/commands/project/install-plugin-cmd.js +1 -1
  200. package/src/commands/project/update.js +30 -0
  201. package/src/commands/project/worktree.js +73 -90
  202. package/src/commands/state/advance.js +18 -0
  203. package/src/commands/state/approve.js +15 -0
  204. package/src/commands/state/archive.js +62 -9
  205. package/src/commands/state/finish.js +62 -14
  206. package/src/commands/state/gate-check.js +8 -1
  207. package/src/commands/state/gate-decision.js +8 -4
  208. package/src/commands/state/report-check.js +90 -9
  209. package/src/commands/state/usecase.js +66 -0
  210. package/src/commands/tasks/dag.js +17 -2
  211. package/src/commands/validation/validate-feature.js +6 -1
  212. package/src/commands/validation/verify.js +20 -1
  213. package/src/dashboard/app/App.jsx +80 -16
  214. package/src/dashboard/app/components/ActivityFeed.jsx +172 -0
  215. package/src/dashboard/app/components/CommandPalette.jsx +155 -0
  216. package/src/dashboard/app/components/DetailPanel.jsx +47 -11
  217. package/src/dashboard/app/components/EntityLink.jsx +55 -0
  218. package/src/dashboard/app/components/ErrorBoundary.jsx +54 -0
  219. package/src/dashboard/app/components/FlowGraph.jsx +19 -17
  220. package/src/dashboard/app/components/KnowledgeMarkdown.jsx +53 -0
  221. package/src/dashboard/app/components/Markdown.jsx +47 -0
  222. package/src/dashboard/app/components/PhaseRail.jsx +111 -0
  223. package/src/dashboard/app/components/SearchFilter.jsx +40 -22
  224. package/src/dashboard/app/components/Sidebar.jsx +146 -37
  225. package/src/dashboard/app/hooks/useMorphQuery.js +54 -0
  226. package/src/dashboard/app/hooks/usePref.js +38 -0
  227. package/src/dashboard/app/lib/format.js +69 -0
  228. package/src/dashboard/app/lib/phases.js +56 -0
  229. package/src/dashboard/app/lib/project.js +50 -0
  230. package/src/dashboard/app/pages/Activity.jsx +24 -0
  231. package/src/dashboard/app/pages/AgentMap.jsx +371 -370
  232. package/src/dashboard/app/pages/FeatureDetail.jsx +604 -0
  233. package/src/dashboard/app/pages/Features.jsx +400 -0
  234. package/src/dashboard/app/pages/Guide.jsx +146 -0
  235. package/src/dashboard/app/pages/HookInspector.jsx +357 -322
  236. package/src/dashboard/app/pages/PhasePipeline.jsx +277 -408
  237. package/src/dashboard/app/pages/Portfolio.jsx +156 -0
  238. package/src/dashboard/app/pages/Rubrics.jsx +101 -0
  239. package/src/dashboard/app/pages/RulesMap.jsx +300 -273
  240. package/src/dashboard/app/pages/SkillsLibrary.jsx +483 -366
  241. package/src/dashboard/app/pages/Standards.jsx +407 -332
  242. package/src/dashboard/app/styles/index.css +187 -47
  243. package/src/dashboard/index.html +14 -12
  244. package/src/dashboard/package.json +32 -24
  245. package/src/dashboard/scanner/activity-scanner.js +351 -0
  246. package/src/dashboard/scanner/agents-scanner.js +63 -1
  247. package/src/dashboard/scanner/docs-scanner.js +59 -0
  248. package/src/dashboard/scanner/feature-status.js +10 -0
  249. package/src/dashboard/scanner/features-scanner.js +360 -0
  250. package/src/dashboard/scanner/hooks-scanner.js +8 -1
  251. package/src/dashboard/scanner/index.js +14 -7
  252. package/src/dashboard/scanner/phases-scanner.js +14 -15
  253. package/src/dashboard/scanner/portfolio.js +153 -0
  254. package/src/dashboard/scanner/project-api.js +195 -0
  255. package/src/dashboard/scanner/rules-scanner.js +42 -37
  256. package/src/dashboard/scanner/skills-scanner.js +105 -43
  257. package/src/dashboard/scanner/standards-scanner.js +4 -1
  258. package/src/dashboard/vite-plugin-morph-data.js +134 -17
  259. package/src/lib/ai/comment-stripper.js +101 -4
  260. package/src/lib/detectors/claude-config-detector.js +2 -7
  261. package/src/lib/detectors/index.js +5 -1
  262. package/src/lib/evaluator-report.js +47 -0
  263. package/src/lib/generators/handoff-generator.js +4 -18
  264. package/src/lib/generators/settings-generator.js +208 -209
  265. package/src/lib/git/default-branch.js +52 -0
  266. package/src/lib/git/tree-fingerprint.js +58 -0
  267. package/src/lib/git/tree-state.js +167 -0
  268. package/src/lib/graph/god-nodes.js +12 -3
  269. package/src/lib/graph/graph-health.js +48 -2
  270. package/src/lib/graph/graph-loader.js +99 -25
  271. package/src/lib/graph/graphifyignore.js +145 -28
  272. package/src/lib/graph/sanitize.js +117 -11
  273. package/src/lib/installers/mcp-installer.js +724 -719
  274. package/src/lib/installers/memory-installer.js +1 -2
  275. package/src/lib/projects/registry.js +154 -0
  276. package/src/lib/risk-detector.js +90 -0
  277. package/src/lib/specs/acervo-format.js +70 -0
  278. package/src/lib/specs/acervo-lifecycle.js +264 -0
  279. package/src/lib/specs/adr-index.js +169 -0
  280. package/src/lib/specs/revocations.js +156 -0
  281. package/src/lib/specs/screen-checklist.js +357 -0
  282. package/src/lib/specs/usecase-check.js +20 -16
  283. package/src/lib/specs/usecase-promoter.js +103 -38
  284. package/src/lib/specs/usecase-registry.js +7 -7
  285. package/src/lib/tasks/tasks-json-parser.js +2 -3
  286. package/src/lib/telemetry/metrics.js +386 -0
  287. package/src/lib/telemetry/telemetry-reader.js +161 -51
  288. package/src/lib/telemetry/verify-event.js +79 -0
  289. package/src/lib/validators/code-budget/code-budget-validator.js +200 -0
  290. package/src/lib/validators/code-budget/comment-scanner.js +75 -0
  291. package/src/lib/validators/code-budget/index.js +9 -0
  292. package/src/lib/validators/reuse/reuse-validator.js +4 -2
  293. package/src/lib/validators/reuse/symbol-scanner.js +27 -22
  294. package/src/lib/validators/validation-runner.js +21 -5
  295. package/src/lib/validators/verify-runner.js +11 -0
  296. package/src/lib/worktree/finish-backup.js +739 -0
  297. package/src/lib/worktree/ignored-triage.js +15 -8
  298. package/src/lib/worktree/worktree-audit.js +5 -0
  299. package/src/scripts/install-plugin.js +1 -1
  300. package/src/scripts/setup-infra.js +31 -22
  301. package/src/utils/agents-installer.js +338 -24
  302. package/src/utils/banner.js +1 -1
  303. package/src/utils/hooks-installer.js +75 -15
  304. package/src/commands/index.js +0 -13
  305. package/src/commands/project/checkpoint.js +0 -209
  306. package/src/core/state/phase-state-machine.js +0 -197
  307. package/src/dashboard/app/hooks/useDetailPanel.js +0 -15
  308. package/src/dashboard/app/pages/LiveState.jsx +0 -206
  309. package/src/dashboard/scanner/squads-scanner.js +0 -13
  310. package/src/dashboard/scanner/state-scanner.js +0 -85
  311. package/src/lib/generators/index.js +0 -10
  312. package/src/lib/hooks/hook-executor.js +0 -167
  313. package/src/lib/validators/checkpoint-persistence.js +0 -39
  314. package/src/lib/validators/shared/emit-validator-dispatch.js +0 -14
  315. package/src/lib/validators/shared/index.js +0 -12
  316. package/src/lib/validators/shared/issue-counter.js +0 -14
  317. package/src/lib/validators/shared/result-formatter.js +0 -124
@@ -1,77 +1,21 @@
1
1
  namespace Morph.AiKit.Media;
2
2
 
3
- /// <summary>
4
- /// O que PRODUZ BYTES. <b><c>internal</c> ao assembly, e e isso que prende a regra dura.</b>
5
- /// </summary>
6
- /// <remarks>
7
- /// <para>
8
- /// <c>ai-agents/media-pipeline.md</c> diz: <i>nunca gere midia dentro de um turno de
9
- /// conversa</i>. Uma frase num standard nao prende nada — o que prende e este modificador.
10
- /// </para>
11
- /// <para>
12
- /// Este tipo e os tres adaptadores de provider sao <c>internal</c>, com
13
- /// <c>InternalsVisibleTo</c> liberando apenas <c>Morph.AiKit.Tests</c>. Um handler de
14
- /// mensagem no projeto consumidor <b>nao consegue nomear</b> o tipo que produz bytes: o
15
- /// codigo nao compila. A unica superficie publica e
16
- /// <see cref="IMediaGenerator.EnqueueAsync"/>, que devolve um <see cref="MediaJobId"/>.
17
- /// </para>
18
- /// <para>
19
- /// Um teste de acessibilidade por reflexao (<c>MediaAccessibilityTests</c>) mantem esta
20
- /// afirmacao verdadeira: tornar o tipo publico derruba a suite. Um canario que ninguem viu
21
- /// morder pode ser o canario errado, entao a mutacao foi rodada.
22
- /// </para>
23
- /// </remarks>
3
+ // internal e o que impede um handler de gerar midia dentro do turno de conversa; MediaAccessibilityTests cobra.
24
4
  internal interface IMediaProvider
25
5
  {
26
- /// <summary>Familia do SDK: <c>openai</c>, <c>google</c>.</summary>
27
6
  string Provider { get; }
28
7
 
29
- /// <summary>Se este adaptador atende esse tipo de midia.</summary>
30
8
  bool Supports(MediaKind kind);
31
9
 
32
- /// <summary>
33
- /// Produz os bytes. Bloqueio de moderacao volta como
34
- /// <see cref="MediaErrorCode.PolicyBlocked"/> — terminal, nunca retryable; falha
35
- /// tecnica volta como <see cref="MediaErrorCode.ProviderFailure"/>.
36
- /// </summary>
37
- /// <param name="request">O pedido, ja validado.</param>
38
- /// <param name="binding">
39
- /// O alias resolvido. Viaja como parametro, e nao no construtor, porque um adaptador
40
- /// atende N aliases do mesmo provider e uma instancia por alias multiplicaria clientes
41
- /// sem nenhum ganho.
42
- /// </param>
43
- /// <param name="cancellationToken">—</param>
44
10
  Task<MediaResult<MediaArtifact>> ProduceAsync(
45
11
  MediaRequest request,
46
12
  MediaAliasBinding binding,
47
13
  CancellationToken cancellationToken);
48
14
  }
49
15
 
50
- /// <summary>
51
- /// Constroi os clientes de SDK dos providers de midia. <b>A costura do subsistema</b>: o
52
- /// unico ponto em que o kit toca um provider de verdade.
53
- /// </summary>
54
- /// <remarks>
55
- /// <para>
56
- /// Publica de proposito, e pela mesma razao de <c>IProviderClientFactory</c>: e assim que a
57
- /// suite do kit roda <b>sem rede e sem chave de API</b> — em teste ninguem implementa esta
58
- /// interface, porque os testes usam um <c>IMediaProvider</c> fake e nunca chegam aqui.
59
- /// </para>
60
- /// <para>
61
- /// Devolver <c>null</c> significa "este provider nao e meu": o catalogo entao procura outro
62
- /// adaptador, e se nenhum atender, o job falha com motivo nomeado em vez de silenciosamente
63
- /// nao acontecer.
64
- /// </para>
65
- /// <para>
66
- /// <b>Quem descarta o cliente e o projeto</b>, que o construiu. O kit nao guarda cache
67
- /// propria de cliente — duas caches da mesma coisa e como um cliente vaza de um teste.
68
- /// </para>
69
- /// </remarks>
70
16
  public interface IMediaClientFactory
71
17
  {
72
- /// <summary>O <c>ImageClient</c> do alias, ou nulo quando o provider nao e a OpenAI.</summary>
73
18
  OpenAI.Images.ImageClient? CreateOpenAiImageClient(MediaAliasBinding binding);
74
19
 
75
- /// <summary>O cliente do Google GenAI, ou nulo quando o provider nao e o Google.</summary>
76
20
  Google.GenAI.Client? CreateGoogleClient(MediaAliasBinding binding);
77
21
  }
@@ -1,24 +1,5 @@
1
1
  namespace Morph.AiKit.Media;
2
2
 
3
- /// <summary>
4
- /// O que um provider produz: bytes, mais o que so o provider sabe sobre a geracao.
5
- /// </summary>
6
- /// <remarks>
7
- /// <b>Este tipo nunca sai pela superficie publica do subsistema.</b> Ele existe entre o
8
- /// <c>IMediaProvider</c> (internal) e o worker (internal); o que chega ao projeto e um
9
- /// <see cref="MediaJob"/> com caminho e hash. Se um handler consegue segurar um
10
- /// <see cref="MediaArtifact"/>, a regra dura de ai-agents/media-pipeline.md foi furada.
11
- /// </remarks>
12
- /// <param name="Kind">Imagem ou video.</param>
13
- /// <param name="MediaType">MIME dos bytes devolvidos pelo provider.</param>
14
- /// <param name="Bytes">O conteudo. Baixado JA, nunca uma URL guardada para depois.</param>
15
- /// <param name="RevisedPrompt">O prompt que o provider reescreveu, quando ele devolve um.</param>
16
- /// <param name="ResponseId">O id do lado do provider, para abrir chamado.</param>
17
- /// <param name="C2paPreserved">
18
- /// Se os metadados de proveniencia do provider sobreviveram ao caminho ate aqui. Falso
19
- /// quando o adaptador re-encodou os bytes — e um re-encode destrutivo apaga a credencial
20
- /// C2PA, que e a unica prova tecnica de origem que a imagem carregava.
21
- /// </param>
22
3
  internal sealed record MediaArtifact(
23
4
  MediaKind Kind,
24
5
  string MediaType,
@@ -1,44 +1,8 @@
1
1
  namespace Morph.AiKit.Media;
2
2
 
3
- /// <summary>
4
- /// A marcação "gerado/editado por IA" que acompanha a publicação.
5
- /// </summary>
6
- /// <remarks>
7
- /// <para>
8
- /// <b>Este tipo existe porque a afirmação estava só na prosa.</b> Antes dele,
9
- /// <see cref="MediaJobState.Published"/> dizia "publicado, com a marcacao aplicada" e
10
- /// <see cref="MediaPurpose.Marketing"/> dizia "marcacao visivel obrigatoria" — e um
11
- /// <c>grep</c> por label, watermark ou disclosure no kit inteiro voltava <b>vazio</b>. Três
12
- /// das quatro afirmações que a rubrica <c>media-claims</c> cobra de terceiros estavam presas
13
- /// por tipo ou por estado; a quarta, que é a obrigação legal, estava presa por nada.
14
- /// </para>
15
- /// <para>
16
- /// <b>O construtor é PRIVADO, e isso não é estilo.</b> A primeira versão deste tipo era um
17
- /// record POSICIONAL — e um record posicional gera um construtor <b>público</b>. A validação
18
- /// morava só em <see cref="Create"/>, então <c>new MediaDisclosure("", "", at)</c> compilava,
19
- /// era aceito, e publicava com rótulo vazio. Medido de um consumidor externo:
20
- /// <c>IsSuccess=True State=Published</c>, <c>Text='' Surface=''</c>. A prosa dizia "recusado na
21
- /// construção" em quatro superfícies; a construção não recusava nada. Uma marcação vazia é
22
- /// exatamente o campo preenchido "para passar" que este tipo existe para impedir, e agora é o
23
- /// <b>compilador</b> que fecha a porta — não a documentação. Mesma forma de
24
- /// <see cref="MediaReview"/>, três arquivos ao lado.
25
- /// </para>
26
- /// <para>
27
- /// <b>O que este tipo prova, exatamente:</b> que um job <b>não alcança</b>
28
- /// <see cref="MediaJobState.Published"/> sem uma marcação registrada e não-vazia, quando a
29
- /// finalidade a exige. É o mesmo mecanismo de <see cref="MediaJob.Approve"/> — uma transição
30
- /// que o código não tem, em vez de uma frase que alguém tem de lembrar.
31
- /// </para>
32
- /// <para>
33
- /// <b>O que ele NÃO prova, e é honesto dizer:</b> que o rótulo chegou aos olhos de alguém. A
34
- /// renderização é do aplicativo consumidor, e nenhum tipo em C# alcança um pixel. O que o kit
35
- /// garante é que a decisão foi tomada, com texto e superfície nomeados, e ficou gravada com o
36
- /// artefato — de modo que "esquecemos de marcar" deixa de ser um caminho silencioso e passa a
37
- /// ser uma recusa na publicação.
38
- /// </para>
39
- /// </remarks>
40
3
  public sealed record MediaDisclosure
41
4
  {
5
+ // Privado de proposito: um record posicional geraria construtor publico que pula a validacao de Create.
42
6
  private MediaDisclosure(string text, string surface, DateTimeOffset appliedAt)
43
7
  {
44
8
  Text = text;
@@ -46,25 +10,12 @@ public sealed record MediaDisclosure
46
10
  AppliedAt = appliedAt;
47
11
  }
48
12
 
49
- /// <summary>
50
- /// O texto visível, por extenso. Em branco é recusado — e a recusa é presa pelo construtor
51
- /// privado, não por convenção de chamada.
52
- /// </summary>
53
13
  public string Text { get; }
54
14
 
55
- /// <summary>
56
- /// ONDE o rótulo aparece — legenda, sobreposição, texto alternativo, ficha do produto. Sem
57
- /// isto, "marcado" não diz se alguém consegue ver.
58
- /// </summary>
59
15
  public string Surface { get; }
60
16
 
61
- /// <summary>Quando a marcação foi decidida.</summary>
62
17
  public DateTimeOffset AppliedAt { get; }
63
18
 
64
- /// <summary>
65
- /// A ÚNICA forma de obter uma marcação. Recusa texto ou superfície em branco.
66
- /// </summary>
67
- /// <exception cref="ArgumentException">Texto ou superfície vazios.</exception>
68
19
  public static MediaDisclosure Create(string text, string surface, DateTimeOffset appliedAt)
69
20
  {
70
21
  ArgumentException.ThrowIfNullOrWhiteSpace(text);
@@ -74,34 +25,11 @@ public sealed record MediaDisclosure
74
25
  }
75
26
  }
76
27
 
77
- /// <summary>Política de marcação por finalidade. Escrita uma vez, aqui.</summary>
78
28
  public static class MediaPurposeExtensions
79
29
  {
80
- /// <summary>
81
- /// Se a finalidade exige marcação visível para publicar.
82
- /// </summary>
83
- /// <remarks>
84
- /// <para>
85
- /// <b>Catálogo e marketing exigem; rascunho não publica.</b> A regra do art. 50 do AI Act
86
- /// mira conteúdo que <i>possa parecer autêntico</i> sobre produto, pessoa ou lugar — e é
87
- /// exatamente o que catálogo e peça de campanha são. A leitura conservadora é do standard
88
- /// <c>ai-agents/media-pipeline.md</c>, seção Marcação, com a ressalva de fonte que ele
89
- /// carrega: este predicado é uma decisão de desenho, não parecer jurídico.
90
- /// </para>
91
- /// <para>
92
- /// Não confunda com <see cref="IsPublishable"/>: um rascunho não chega a publicar, então
93
- /// a pergunta "precisa de marcação" nem se coloca para ele.
94
- /// </para>
95
- /// </remarks>
30
+ // AI Act art. 50, na leitura conservadora de ai-agents/media-pipeline.md (decisao de desenho, nao parecer juridico).
96
31
  public static bool RequiresDisclosure(this MediaPurpose purpose)
97
32
  => purpose is MediaPurpose.CatalogPhoto or MediaPurpose.Marketing;
98
33
 
99
- /// <summary>
100
- /// Se a finalidade pode chegar a <see cref="MediaJobState.Published"/>.
101
- /// </summary>
102
- /// <remarks>
103
- /// <see cref="MediaPurpose.Draft"/> se declara "nunca publicável" desde o primeiro dia — e
104
- /// até este tipo existir, isso era só um comentário XML. Agora é uma recusa.
105
- /// </remarks>
106
34
  public static bool IsPublishable(this MediaPurpose purpose) => purpose != MediaPurpose.Draft;
107
35
  }
@@ -2,17 +2,6 @@ using Morph.AiKit.Media.Providers;
2
2
 
3
3
  namespace Morph.AiKit.Media;
4
4
 
5
- /// <summary>
6
- /// A implementacao de <see cref="IMediaGenerator"/>. <b><c>internal</c></b>: o projeto
7
- /// enxerga a interface, nunca o tipo.
8
- /// </summary>
9
- /// <remarks>
10
- /// A ORDEM do <see cref="EnqueueAsync"/> e o contrato, e ela e economia, nao estilo:
11
- /// validar, resolver alias, derivar a chave de PEDIDO, <b>consultar a chave antes de
12
- /// qualquer coisa paga</b>, so entao estimar custo e reservar teto, e por ultimo gravar o
13
- /// job. Um retry que chega aqui reencontra o job e nao paga de novo; um estouro de teto
14
- /// recusa antes de o dinheiro sair.
15
- /// </remarks>
16
5
  internal sealed class MediaGenerator : IMediaGenerator
17
6
  {
18
7
  private readonly IMediaAliasResolver _aliases;
@@ -36,7 +25,6 @@ internal sealed class MediaGenerator : IMediaGenerator
36
25
  _clock = clock;
37
26
  }
38
27
 
39
- /// <inheritdoc />
40
28
  public async Task<MediaResult<MediaJobId>> EnqueueAsync(
41
29
  MediaRequest request,
42
30
  CancellationToken cancellationToken = default)
@@ -64,8 +52,7 @@ internal sealed class MediaGenerator : IMediaGenerator
64
52
 
65
53
  var key = MediaIdempotencyKey.From(request, binding.Value.Provider, binding.Value.Model);
66
54
 
67
- // ANTES de qualquer coisa paga. Um pedido identico a outro ja atendido reusa o job
68
- // existente; so um job em Failed vale outra tentativa.
55
+ // ANTES de qualquer coisa paga; so um job em Failed vale outra tentativa.
69
56
  var existing = await _jobs.FindByIdempotencyKeyAsync(key, cancellationToken).ConfigureAwait(false);
70
57
  if (existing is not null && existing.State != MediaJobState.Failed)
71
58
  {
@@ -99,7 +86,6 @@ internal sealed class MediaGenerator : IMediaGenerator
99
86
  return MediaResult<MediaJobId>.Ok(job.Id);
100
87
  }
101
88
 
102
- /// <inheritdoc />
103
89
  public async Task<MediaResult<MediaJob>> GetAsync(MediaJobId id, CancellationToken cancellationToken = default)
104
90
  {
105
91
  var job = await _jobs.FindAsync(id, cancellationToken).ConfigureAwait(false);
@@ -110,16 +96,7 @@ internal sealed class MediaGenerator : IMediaGenerator
110
96
  }
111
97
  }
112
98
 
113
- /// <summary>
114
- /// Executa um job: chama o provider, guarda os bytes, move o estado. <b><c>internal</c></b>
115
- /// — e este e o unico tipo do subsistema que segura um <see cref="IMediaProvider"/>.
116
- /// </summary>
117
- /// <remarks>
118
- /// A ordem tambem e o contrato: <c>Generating</c> antes da chamada (para que um worker
119
- /// morto no meio deixe rastro), os bytes GRAVADOS antes de <c>Generated</c> (um job em
120
- /// <c>Generated</c> sem bytes no storage mente sobre o proprio estado), e o bloqueio de
121
- /// moderacao indo para <c>RejectedByPolicy</c> e nao para <c>Failed</c>.
122
- /// </remarks>
99
+ // Generating antes da chamada (worker morto deixa rastro) e bytes gravados antes de Generated.
123
100
  internal sealed class MediaWorker : IMediaJobRunner
124
101
  {
125
102
  private readonly IMediaAliasResolver _aliases;
@@ -148,7 +125,6 @@ internal sealed class MediaWorker : IMediaJobRunner
148
125
  _clock = clock;
149
126
  }
150
127
 
151
- /// <inheritdoc />
152
128
  public async Task<MediaResult<MediaJob>> RunAsync(MediaJobId id, CancellationToken cancellationToken = default)
153
129
  {
154
130
  var job = await _jobs.FindAsync(id, cancellationToken).ConfigureAwait(false);
@@ -186,8 +162,6 @@ internal sealed class MediaWorker : IMediaJobRunner
186
162
 
187
163
  if (!produced.IsSuccess)
188
164
  {
189
- // A distincao que vale dinheiro: bloqueio de politica e terminal, falha tecnica
190
- // e retryable. Colapsar as duas em "erro" e como um laco de retry vira fatura.
191
165
  var transition = produced.Error!.Code == MediaErrorCode.PolicyBlocked
192
166
  ? job.RejectByPolicy(produced.Error.Message)
193
167
  : job.Fail(produced.Error.Message);
@@ -232,13 +206,8 @@ internal sealed class MediaWorker : IMediaJobRunner
232
206
  }
233
207
  }
234
208
 
235
- /// <summary>
236
- /// Monta os adaptadores de provider. <b><c>internal</c></b>, e e por isso que nao existe
237
- /// caminho publico ate um <see cref="IMediaProvider"/>.
238
- /// </summary>
239
209
  internal static class MediaProviderCatalog
240
210
  {
241
- /// <summary>Os tres adaptadores que o kit traz.</summary>
242
211
  public static IReadOnlyList<IMediaProvider> Build(IMediaClientFactory clients)
243
212
  {
244
213
  ArgumentNullException.ThrowIfNull(clients);
@@ -3,53 +3,13 @@ using System.Text;
3
3
 
4
4
  namespace Morph.AiKit.Media;
5
5
 
6
- /// <summary>
7
- /// A chave de idempotencia do <b>PEDIDO</b> — a que dedupe a CHAMADA PAGA.
8
- /// </summary>
9
- /// <remarks>
10
- /// <para>
11
- /// <b>Ela nao e o <see cref="MediaHash"/>, e a diferenca e o defeito caro deste
12
- /// subsistema.</b> Esta chave e o sha256 do PEDIDO (provider + modelo + prompt normalizado
13
- /// + sha256 de cada referencia + opcoes) e responde "ja pagamos por isto?". O
14
- /// <see cref="MediaHash"/> e o sha256 dos BYTES e responde "ja guardamos isto?". Duas
15
- /// perguntas diferentes: dois pedidos distintos podem produzir bytes identicos, e o mesmo
16
- /// pedido sempre produz o mesmo pedido.
17
- /// </para>
18
- /// <para>
19
- /// Ela e consultada <b>antes</b> de chamar o provider. E o que faz um retry — de fila, de
20
- /// worker reiniciado, de webhook duplicado — custar zero.
21
- /// </para>
22
- /// <para>
23
- /// <b>O prompt e normalizado, nao minusculado.</b> Espacos em branco colapsam e as pontas
24
- /// sao aparadas, porque um espaco a mais nao muda o pedido; a caixa e preservada, porque
25
- /// num prompt ela muda (nomes de marca, texto literal entre aspas que vai aparecer na
26
- /// imagem).
27
- /// </para>
28
- /// </remarks>
29
- /// <param name="Value">sha256 em hex minusculo.</param>
30
6
  public readonly record struct MediaIdempotencyKey(string Value)
31
7
  {
32
- /// <summary>Separador de CAMPO na forma canonica: UNIT SEPARATOR (U+001F).</summary>
33
- /// <remarks>
34
- /// Um caractere de controle, e nao <c>|</c> ou <c>:</c>, porque o separador nao pode
35
- /// aparecer dentro de um campo. Um prompt que contivesse o separador emendaria dois
36
- /// campos numa chave so, e duas requisicoes diferentes passariam a compartilhar a
37
- /// chave — o que faz uma reusar o artefato PAGO da outra. Pior que pagar duas vezes.
38
- /// Escrito como <c>(char)0x1F</c> e nao como o caractere cru: um byte de controle
39
- /// invisivel no fonte e uma armadilha para o proximo editor.
40
- /// </remarks>
8
+ // Caractere de controle: um separador que aparecesse no prompt emendaria campos e duas requisicoes dividiriam a chave.
41
9
  private const char FieldSeparator = (char)0x1F;
42
10
 
43
- /// <summary>Separador de ITEM dentro de um campo: RECORD SEPARATOR (U+001E).</summary>
44
11
  private const char ItemSeparator = (char)0x1E;
45
12
 
46
- /// <summary>
47
- /// Deriva a chave do pedido resolvido.
48
- /// </summary>
49
- /// <param name="request">O pedido.</param>
50
- /// <param name="provider">A familia do SDK que vai atender (<c>openai</c>, <c>google</c>).</param>
51
- /// <param name="model">O modelo resolvido pelo alias — nunca o alias, que pode ser repontado.</param>
52
- /// <exception cref="ArgumentNullException">Pedido nulo.</exception>
53
13
  public static MediaIdempotencyKey From(MediaRequest request, string provider, string model)
54
14
  {
55
15
  ArgumentNullException.ThrowIfNull(request);
@@ -70,7 +30,6 @@ public readonly record struct MediaIdempotencyKey(string Value)
70
30
  Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(canonical))));
71
31
  }
72
32
 
73
- /// <summary>Apara as pontas e colapsa espacos em branco. NAO minuscula.</summary>
74
33
  public static string NormalizePrompt(string prompt)
75
34
  {
76
35
  ArgumentNullException.ThrowIfNull(prompt);
@@ -98,6 +57,5 @@ public readonly record struct MediaIdempotencyKey(string Value)
98
57
  return builder.ToString();
99
58
  }
100
59
 
101
- /// <summary>A chave, para log.</summary>
102
60
  public override string ToString() => Value;
103
61
  }
@@ -1,34 +1,5 @@
1
1
  namespace Morph.AiKit.Media;
2
2
 
3
- /// <summary>
4
- /// Um pedido de midia com estado. <b>E o unico objeto de dominio que a superficie publica
5
- /// devolve</b> — nunca bytes.
6
- /// </summary>
7
- /// <remarks>
8
- /// <para>
9
- /// As transicoes sao metodos que devolvem <see cref="MediaResult{T}"/> e um job NOVO: o
10
- /// registro e imutavel, e uma transicao invalida e informacao devolvida, nunca excecao.
11
- /// </para>
12
- /// <para>
13
- /// <b>Duas invariantes carregam o standard inteiro:</b>
14
- /// </para>
15
- /// <list type="number">
16
- /// <item>
17
- /// <see cref="Approve"/> e a UNICA porta para <see cref="MediaJobState.Approved"/>, e
18
- /// ela exige um revisor com nome e carimbo de tempo. E assim que "ha revisao humana"
19
- /// deixa de ser uma frase no README e vira um caminho que o codigo nao tem.
20
- /// </item>
21
- /// <item>
22
- /// <see cref="Publish"/> falha a partir de qualquer estado que nao seja
23
- /// <c>Approved</c>. Nao ha atalho, nem flag, nem sobrecarga "force".
24
- /// </item>
25
- /// </list>
26
- /// <para>
27
- /// E ha uma terceira, que vale dinheiro: <see cref="RejectByPolicy"/> produz um estado
28
- /// terminal com <see cref="IsRetryable"/> falso. Bloqueio de moderacao nao e erro tecnico —
29
- /// retenta-lo gasta para receber o mesmo "nao".
30
- /// </para>
31
- /// </remarks>
32
3
  public sealed record MediaJob
33
4
  {
34
5
  private MediaJob(MediaJobId id, MediaRequest request, MediaIdempotencyKey key, DateTimeOffset createdAt)
@@ -40,70 +11,44 @@ public sealed record MediaJob
40
11
  State = MediaJobState.Pending;
41
12
  }
42
13
 
43
- /// <summary>A identidade. O unico valor que sai pela superficie publica.</summary>
44
14
  public MediaJobId Id { get; private init; }
45
15
 
46
- /// <summary>O pedido, congelado.</summary>
47
16
  public MediaRequest Request { get; private init; }
48
17
 
49
- /// <summary>A chave que dedupe a chamada paga.</summary>
50
18
  public MediaIdempotencyKey IdempotencyKey { get; private init; }
51
19
 
52
- /// <summary>Onde o job esta.</summary>
53
20
  public MediaJobState State { get; private init; }
54
21
 
55
- /// <summary>Quando o pedido foi aceito.</summary>
56
22
  public DateTimeOffset CreatedAt { get; private init; }
57
23
 
58
- /// <summary>sha256 dos bytes, a partir de <see cref="MediaJobState.Generated"/>.</summary>
59
24
  public MediaHash? Hash { get; private init; }
60
25
 
61
- /// <summary>Caminho RELATIVO no blob do projeto. Nunca URL de provider.</summary>
62
26
  public string? RelativePath { get; private init; }
63
27
 
64
- /// <summary>A proveniencia, gravada na geracao.</summary>
65
28
  public MediaProvenance? Provenance { get; private init; }
66
29
 
67
- /// <summary>Quem decidiu, quando, e o que escreveu. Nulo enquanto ninguem revisou.</summary>
68
30
  public MediaReview? Review { get; private init; }
69
31
 
70
- /// <summary>Por que falhou ou foi bloqueado. Nulo nos estados saudaveis.</summary>
71
32
  public string? FailureReason { get; private init; }
72
33
 
73
- /// <summary>Quando foi publicado.</summary>
74
34
  public DateTimeOffset? PublishedAt { get; private init; }
75
35
 
76
- /// <summary>
77
- /// A marcação "gerado por IA" registrada na publicação, ou nulo quando a finalidade não
78
- /// a exige. Ver <see cref="MediaDisclosure"/> e <see cref="Publish"/>.
79
- /// </summary>
80
36
  public MediaDisclosure? Disclosure { get; private init; }
81
37
 
82
- /// <summary>
83
- /// Se vale tentar de novo. <b>So <see cref="MediaJobState.Failed"/> e retryable.</b>
84
- /// <see cref="MediaJobState.RejectedByPolicy"/> nao e, e essa e a diferenca que impede
85
- /// um laco de retry de virar uma fatura.
86
- /// </summary>
38
+ // RejectedByPolicy nao e retryable: retentar um bloqueio de moderacao paga pelo mesmo "nao".
87
39
  public bool IsRetryable => State == MediaJobState.Failed;
88
40
 
89
- /// <summary>Nasce em <see cref="MediaJobState.Pending"/>. Nada foi gasto ainda.</summary>
90
- /// <exception cref="ArgumentNullException">Pedido nulo.</exception>
91
41
  public static MediaJob Create(MediaRequest request, MediaIdempotencyKey key, DateTimeOffset createdAt)
92
42
  {
93
43
  ArgumentNullException.ThrowIfNull(request);
94
44
  return new MediaJob(MediaJobId.New(), request, key, createdAt);
95
45
  }
96
46
 
97
- /// <summary>Pending para Generating: a chamada paga esta em voo.</summary>
98
47
  public MediaResult<MediaJob> StartGenerating()
99
48
  => State == MediaJobState.Pending || State == MediaJobState.Failed
100
49
  ? MediaResult<MediaJob>.Ok(this with { State = MediaJobState.Generating, FailureReason = null })
101
50
  : Invalid(nameof(StartGenerating), MediaJobState.Generating);
102
51
 
103
- /// <summary>
104
- /// Generating para Generated. Exige hash, caminho e proveniencia <b>juntos</b>: um job
105
- /// em <c>Generated</c> sem bytes no seu storage esta mentindo sobre o proprio estado.
106
- /// </summary>
107
52
  public MediaResult<MediaJob> MarkGenerated(MediaHash hash, string relativePath, MediaProvenance provenance)
108
53
  {
109
54
  ArgumentException.ThrowIfNullOrWhiteSpace(relativePath);
@@ -120,7 +65,6 @@ public sealed record MediaJob
120
65
  : Invalid(nameof(MarkGenerated), MediaJobState.Generated);
121
66
  }
122
67
 
123
- /// <summary>Falha tecnica. Retryable.</summary>
124
68
  public MediaResult<MediaJob> Fail(string reason)
125
69
  {
126
70
  ArgumentException.ThrowIfNullOrWhiteSpace(reason);
@@ -130,9 +74,6 @@ public sealed record MediaJob
130
74
  : Invalid(nameof(Fail), MediaJobState.Failed);
131
75
  }
132
76
 
133
- /// <summary>
134
- /// Bloqueio de moderacao. Terminal e NAO retryable — ver <see cref="IsRetryable"/>.
135
- /// </summary>
136
77
  public MediaResult<MediaJob> RejectByPolicy(string reason)
137
78
  {
138
79
  ArgumentException.ThrowIfNullOrWhiteSpace(reason);
@@ -146,10 +87,6 @@ public sealed record MediaJob
146
87
  : Invalid(nameof(RejectByPolicy), MediaJobState.RejectedByPolicy);
147
88
  }
148
89
 
149
- /// <summary>
150
- /// A UNICA porta para <see cref="MediaJobState.Approved"/>, e ela exige um humano
151
- /// nomeado com carimbo de tempo.
152
- /// </summary>
153
90
  public MediaResult<MediaJob> Approve(MediaReview review)
154
91
  {
155
92
  ArgumentNullException.ThrowIfNull(review);
@@ -167,7 +104,6 @@ public sealed record MediaJob
167
104
  : Invalid(nameof(Approve), MediaJobState.Approved);
168
105
  }
169
106
 
170
- /// <summary>Recusa humana. Terminal.</summary>
171
107
  public MediaResult<MediaJob> Reject(MediaReview review)
172
108
  {
173
109
  ArgumentNullException.ThrowIfNull(review);
@@ -184,37 +120,6 @@ public sealed record MediaJob
184
120
  : Invalid(nameof(Reject), MediaJobState.Rejected);
185
121
  }
186
122
 
187
- /// <summary>
188
- /// Publica. <b>Tres portas, e cada uma fecha um caminho que existia so na prosa:</b>
189
- /// </summary>
190
- /// <remarks>
191
- /// <list type="number">
192
- /// <item>
193
- /// Falha a partir de qualquer estado que nao seja <see cref="MediaJobState.Approved"/>
194
- /// — inclusive de <c>Generated</c>, que e o atalho que alguem sempre quer. E o que
195
- /// torna a REVISAO HUMANA um caminho que o codigo nao tem.
196
- /// </item>
197
- /// <item>
198
- /// Falha quando a finalidade nao e publicavel. <see cref="MediaPurpose.Draft"/> se
199
- /// declarava "nunca publicavel" num comentario XML que nada cobrava.
200
- /// </item>
201
- /// <item>
202
- /// Falha quando a finalidade exige MARCACAO e ela nao foi passada. Era a unica das
203
- /// quatro afirmacoes da rubrica <c>media-claims</c> presa por prosa — e e a que
204
- /// carrega a obrigacao legal (AI Act art. 50).
205
- /// </item>
206
- /// </list>
207
- /// <para>
208
- /// O que isto prova e o que nao prova esta escrito em <see cref="MediaDisclosure"/>: o
209
- /// kit garante que a DECISAO foi tomada e gravada, nao que o rotulo chegou aos olhos de
210
- /// alguem — a renderizacao e do aplicativo consumidor.
211
- /// </para>
212
- /// </remarks>
213
- /// <param name="disclosure">
214
- /// A marcacao. Pode ser nula somente quando <see cref="MediaPurpose.RequiresDisclosure"/>
215
- /// e falso para a finalidade do pedido.
216
- /// </param>
217
- /// <param name="publishedAt">Quando.</param>
218
123
  public MediaResult<MediaJob> Publish(MediaDisclosure? disclosure, DateTimeOffset publishedAt)
219
124
  {
220
125
  if (State != MediaJobState.Approved)
@@ -1,21 +1,8 @@
1
1
  namespace Morph.AiKit.Media;
2
2
 
3
- /// <summary>
4
- /// A identidade de um job de midia. <b>O unico valor que a superficie publica devolve</b> —
5
- /// nunca bytes.
6
- /// </summary>
7
- /// <remarks>
8
- /// <c>Guid.CreateVersion7()</c> e nao <c>Guid.NewGuid()</c>: v7 e ordenavel por tempo, o
9
- /// que mantem o indice do banco do projeto sequencial em vez de espalhar escrita por toda
10
- /// a arvore. E a regra da casa, escrita aqui porque este e o unico lugar do subsistema que
11
- /// gera identidade.
12
- /// </remarks>
13
- /// <param name="Value">O GUID v7.</param>
14
3
  public readonly record struct MediaJobId(Guid Value)
15
4
  {
16
- /// <summary>Uma identidade nova, ordenavel por tempo.</summary>
17
5
  public static MediaJobId New() => new(Guid.CreateVersion7());
18
6
 
19
- /// <summary>Forma compacta, para log e URL.</summary>
20
7
  public override string ToString() => Value.ToString("N");
21
8
  }
@@ -1,47 +1,20 @@
1
1
  namespace Morph.AiKit.Media;
2
2
 
3
- /// <summary>
4
- /// Os oito estados de um job de midia.
5
- /// </summary>
6
- /// <remarks>
7
- /// <para>
8
- /// A distincao que vale dinheiro esta entre <see cref="Failed"/> e
9
- /// <see cref="RejectedByPolicy"/>. Um bloqueio de moderacao e uma resposta DEFINITIVA:
10
- /// retenta-lo gasta para receber o mesmo "nao" — e no provider que cobra o bloqueio, gasta
11
- /// duas vezes. Modelar bloqueio como erro tecnico e como um laco de retry vira uma fatura.
12
- /// </para>
13
- /// <para>
14
- /// A distincao que vale credibilidade esta entre <see cref="Generated"/> e
15
- /// <see cref="Approved"/>: <c>Approved</c> so existe por uma transicao que carimba um
16
- /// revisor humano, e <c>Published</c> so existe a partir de <c>Approved</c>.
17
- /// </para>
18
- /// </remarks>
19
3
  public enum MediaJobState
20
4
  {
21
- /// <summary>Pedido aceito. Nada foi gasto ainda.</summary>
22
5
  Pending = 0,
23
6
 
24
- /// <summary>Chamada paga em voo, ou tarefa remota em polling.</summary>
25
7
  Generating = 1,
26
8
 
27
- /// <summary>Os bytes existem NO SEU storage. Nao basta a tarefa remota ter concluido.</summary>
28
9
  Generated = 2,
29
10
 
30
- /// <summary>Um humano aprovou, com nome e carimbo de tempo. Unica porta para <see cref="Published"/>.</summary>
31
11
  Approved = 3,
32
12
 
33
- /// <summary>Um humano recusou. Terminal.</summary>
34
13
  Rejected = 4,
35
14
 
36
- /// <summary>Bloqueio de moderacao do provider. Terminal e <b>nao</b> retryable.</summary>
37
15
  RejectedByPolicy = 5,
38
16
 
39
- /// <summary>
40
- /// Publicado. So se alcanca por <see cref="MediaJob.Publish"/>, que exige finalidade
41
- /// publicavel e — quando a finalidade a pede — uma <see cref="MediaDisclosure"/> registrada.
42
- /// </summary>
43
17
  Published = 6,
44
18
 
45
- /// <summary>Erro tecnico (429, 5xx, timeout, download quebrado). Retryable.</summary>
46
19
  Failed = 7,
47
20
  }