@hraness/slopcamera 3.2.4

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 (441) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +60 -0
  3. package/PRIVACY.md +46 -0
  4. package/README.md +311 -0
  5. package/SECURITY.md +21 -0
  6. package/apps/desktop/README.md +966 -0
  7. package/apps/desktop/analysis/protocol.ts +223 -0
  8. package/apps/desktop/application/capability-binding.ts +594 -0
  9. package/apps/desktop/application/context.ts +97 -0
  10. package/apps/desktop/application/creative-iteration.ts +1385 -0
  11. package/apps/desktop/application/default-registry.ts +146 -0
  12. package/apps/desktop/application/directing-contract.ts +218 -0
  13. package/apps/desktop/application/directing-plan.ts +178 -0
  14. package/apps/desktop/application/errors.ts +18 -0
  15. package/apps/desktop/application/gateway-port.ts +867 -0
  16. package/apps/desktop/application/html-overlay-browser-runtime.ts +687 -0
  17. package/apps/desktop/application/html-overlay-integrity.ts +337 -0
  18. package/apps/desktop/application/html-overlay-renderer.ts +45 -0
  19. package/apps/desktop/application/index.ts +13 -0
  20. package/apps/desktop/application/operation-completion-checkpoint.ts +333 -0
  21. package/apps/desktop/application/operation-effects.ts +94 -0
  22. package/apps/desktop/application/operation.ts +224 -0
  23. package/apps/desktop/application/operations/analysis/faces.ts +244 -0
  24. package/apps/desktop/application/operations/analysis/music.ts +248 -0
  25. package/apps/desktop/application/operations/analysis/project-auto-zooms.ts +302 -0
  26. package/apps/desktop/application/operations/analysis/project-inactivity.ts +381 -0
  27. package/apps/desktop/application/operations/analysis/scenes.ts +272 -0
  28. package/apps/desktop/application/operations/analysis/shared.ts +202 -0
  29. package/apps/desktop/application/operations/derive/edit-batch.ts +967 -0
  30. package/apps/desktop/application/operations/derive/follow-faces.ts +454 -0
  31. package/apps/desktop/application/operations/edit/bind-candidate-revision.ts +91 -0
  32. package/apps/desktop/application/operations/edit/create-candidate-revision.ts +377 -0
  33. package/apps/desktop/application/operations/edit/create-revision.ts +255 -0
  34. package/apps/desktop/application/operations/edit/freeze-revision.ts +182 -0
  35. package/apps/desktop/application/operations/gateway/image.ts +41 -0
  36. package/apps/desktop/application/operations/gateway/index.ts +17 -0
  37. package/apps/desktop/application/operations/gateway/shared.ts +122 -0
  38. package/apps/desktop/application/operations/gateway/speech.ts +41 -0
  39. package/apps/desktop/application/operations/gateway/transcription.ts +42 -0
  40. package/apps/desktop/application/operations/gateway/video.ts +41 -0
  41. package/apps/desktop/application/operations/index.ts +31 -0
  42. package/apps/desktop/application/operations/iteration/create-candidate.ts +240 -0
  43. package/apps/desktop/application/operations/iteration/create-matrix.ts +117 -0
  44. package/apps/desktop/application/operations/iteration/select.ts +155 -0
  45. package/apps/desktop/application/operations/iteration/shared.ts +250 -0
  46. package/apps/desktop/application/operations/media/audio-effects.ts +376 -0
  47. package/apps/desktop/application/operations/media/binding.ts +79 -0
  48. package/apps/desktop/application/operations/media/capabilities.ts +112 -0
  49. package/apps/desktop/application/operations/media/color-grade.ts +343 -0
  50. package/apps/desktop/application/operations/media/html-overlay.ts +802 -0
  51. package/apps/desktop/application/operations/media/index.ts +8 -0
  52. package/apps/desktop/application/operations/media/ingest.ts +303 -0
  53. package/apps/desktop/application/operations/media/overlay.ts +729 -0
  54. package/apps/desktop/application/operations/media/shared.ts +845 -0
  55. package/apps/desktop/application/operations/media/transform-platform.ts +120 -0
  56. package/apps/desktop/application/operations/project/commit-edits.ts +2054 -0
  57. package/apps/desktop/application/operations/project/promote-selection.ts +495 -0
  58. package/apps/desktop/application/operations/project/snapshot.ts +95 -0
  59. package/apps/desktop/application/operations/recording/index.ts +5 -0
  60. package/apps/desktop/application/operations/recording/pause.ts +34 -0
  61. package/apps/desktop/application/operations/recording/resume.ts +34 -0
  62. package/apps/desktop/application/operations/recording/shared.ts +199 -0
  63. package/apps/desktop/application/operations/recording/start.ts +169 -0
  64. package/apps/desktop/application/operations/recording/stop.ts +34 -0
  65. package/apps/desktop/application/operations/render/bind-candidate-output.ts +324 -0
  66. package/apps/desktop/application/operations/render/materialize-selection.ts +322 -0
  67. package/apps/desktop/application/operations/render/project-caption-plan.ts +287 -0
  68. package/apps/desktop/application/operations/render/project-plan.ts +939 -0
  69. package/apps/desktop/application/operations/render/project-spatial-receipt.ts +70 -0
  70. package/apps/desktop/application/operations/render/project.ts +1922 -0
  71. package/apps/desktop/application/operations/shared.ts +67 -0
  72. package/apps/desktop/application/operations/slopcamera-portable.ts +1188 -0
  73. package/apps/desktop/application/operations/slopcamera-visuals.ts +784 -0
  74. package/apps/desktop/application/operations/spatial-project.ts +209 -0
  75. package/apps/desktop/application/operations/spatial-render.ts +415 -0
  76. package/apps/desktop/application/operations/spatial-scene.ts +97 -0
  77. package/apps/desktop/application/operations/studio.ts +143 -0
  78. package/apps/desktop/application/output-publication-lease.ts +163 -0
  79. package/apps/desktop/application/project-publication-lease.ts +233 -0
  80. package/apps/desktop/application/project-store.ts +196 -0
  81. package/apps/desktop/application/receipts.ts +533 -0
  82. package/apps/desktop/application/registry.ts +182 -0
  83. package/apps/desktop/application/spatial-assets.ts +675 -0
  84. package/apps/desktop/application/spatial-compositor-cadence.ts +23 -0
  85. package/apps/desktop/application/spatial-project-authority.ts +35 -0
  86. package/apps/desktop/application/spatial-project-lease.ts +126 -0
  87. package/apps/desktop/application/spatial-project-render-preparation.ts +225 -0
  88. package/apps/desktop/application/spatial-project-store.ts +286 -0
  89. package/apps/desktop/application/spatial-render-projection.ts +201 -0
  90. package/apps/desktop/application/spatial-render.ts +677 -0
  91. package/apps/desktop/application/spatial-spz.ts +44 -0
  92. package/apps/desktop/application/spatial-world-import.ts +135 -0
  93. package/apps/desktop/application/spatial-world-provenance.ts +46 -0
  94. package/apps/desktop/application/studio-port.ts +58 -0
  95. package/apps/desktop/application/verified-receipt-reconciliation.ts +1574 -0
  96. package/apps/desktop/capture/protocol.ts +689 -0
  97. package/apps/desktop/cli/analyzer.ts +406 -0
  98. package/apps/desktop/cli/args.ts +3181 -0
  99. package/apps/desktop/cli/asset-ingest.ts +747 -0
  100. package/apps/desktop/cli/atomic-render-effects.ts +210 -0
  101. package/apps/desktop/cli/atomic-render-platform.ts +205 -0
  102. package/apps/desktop/cli/atomic-render.ts +50 -0
  103. package/apps/desktop/cli/audio-analysis.ts +252 -0
  104. package/apps/desktop/cli/bounded-map.ts +39 -0
  105. package/apps/desktop/cli/bundle-service.ts +256 -0
  106. package/apps/desktop/cli/capabilities.ts +212 -0
  107. package/apps/desktop/cli/capture-bundle.ts +1117 -0
  108. package/apps/desktop/cli/command-host-resources.ts +251 -0
  109. package/apps/desktop/cli/commands.ts +6836 -0
  110. package/apps/desktop/cli/directing-blob.ts +291 -0
  111. package/apps/desktop/cli/directing-media.ts +517 -0
  112. package/apps/desktop/cli/directing-quote.ts +89 -0
  113. package/apps/desktop/cli/directing-service.ts +288 -0
  114. package/apps/desktop/cli/emoji-assets.ts +538 -0
  115. package/apps/desktop/cli/errors.ts +29 -0
  116. package/apps/desktop/cli/face-analysis-service.ts +940 -0
  117. package/apps/desktop/cli/filter-script.ts +76 -0
  118. package/apps/desktop/cli/gateway-application-port.ts +1142 -0
  119. package/apps/desktop/cli/gateway-credential.ts +81 -0
  120. package/apps/desktop/cli/gateway-media-artifacts.ts +723 -0
  121. package/apps/desktop/cli/gateway-media-catalog.ts +922 -0
  122. package/apps/desktop/cli/gateway-media-service.ts +3106 -0
  123. package/apps/desktop/cli/gateway-media-signature.ts +122 -0
  124. package/apps/desktop/cli/gateway-provider-options.ts +562 -0
  125. package/apps/desktop/cli/gateway-scene-provider.ts +391 -0
  126. package/apps/desktop/cli/help.ts +501 -0
  127. package/apps/desktop/cli/html-overlay-gpu.ts +97 -0
  128. package/apps/desktop/cli/html-overlay-renderer.ts +2478 -0
  129. package/apps/desktop/cli/io.ts +290 -0
  130. package/apps/desktop/cli/main.ts +123 -0
  131. package/apps/desktop/cli/media-effects-service.ts +885 -0
  132. package/apps/desktop/cli/media-ingest-model.ts +364 -0
  133. package/apps/desktop/cli/media-ingest-platform.ts +227 -0
  134. package/apps/desktop/cli/media-ingest-program.ts +200 -0
  135. package/apps/desktop/cli/media-ingest.ts +30 -0
  136. package/apps/desktop/cli/music-analysis-service.ts +434 -0
  137. package/apps/desktop/cli/mutation-lock.ts +530 -0
  138. package/apps/desktop/cli/native-assets.d.ts +12 -0
  139. package/apps/desktop/cli/native-media-runtime.macos.ts +7 -0
  140. package/apps/desktop/cli/overlay-playback.ts +177 -0
  141. package/apps/desktop/cli/paths.ts +265 -0
  142. package/apps/desktop/cli/portable-surface.ts +242 -0
  143. package/apps/desktop/cli/project-camera-receipt.ts +112 -0
  144. package/apps/desktop/cli/project-face-camera.ts +394 -0
  145. package/apps/desktop/cli/project-inactivity-service.ts +552 -0
  146. package/apps/desktop/cli/project-media-integrity.ts +121 -0
  147. package/apps/desktop/cli/project-renderer.ts +1526 -0
  148. package/apps/desktop/cli/project-service.ts +519 -0
  149. package/apps/desktop/cli/project-state-transaction.ts +520 -0
  150. package/apps/desktop/cli/query-limits.ts +1 -0
  151. package/apps/desktop/cli/recording-controller.ts +1567 -0
  152. package/apps/desktop/cli/recording-daemon.ts +931 -0
  153. package/apps/desktop/cli/recording-ref.ts +56 -0
  154. package/apps/desktop/cli/renamed-environment.ts +6 -0
  155. package/apps/desktop/cli/renderer.ts +1439 -0
  156. package/apps/desktop/cli/run-cli-test-helper.ts +60 -0
  157. package/apps/desktop/cli/scene-analysis-service.ts +879 -0
  158. package/apps/desktop/cli/spatial-compositor-verifier.ts +213 -0
  159. package/apps/desktop/cli/spatial-project-service.ts +90 -0
  160. package/apps/desktop/cli/spatial-scene-service.ts +105 -0
  161. package/apps/desktop/cli/spatial-world-service.ts +39 -0
  162. package/apps/desktop/cli/speech-analysis-service.ts +682 -0
  163. package/apps/desktop/cli/studio-assemble.ts +58 -0
  164. package/apps/desktop/cli/studio-command.ts +60 -0
  165. package/apps/desktop/cli/studio-custody.ts +60 -0
  166. package/apps/desktop/cli/studio-encode.ts +216 -0
  167. package/apps/desktop/cli/studio-exr.ts +52 -0
  168. package/apps/desktop/cli/studio-files.ts +179 -0
  169. package/apps/desktop/cli/studio-output-validation.ts +162 -0
  170. package/apps/desktop/cli/studio-process.ts +145 -0
  171. package/apps/desktop/cli/studio-runtime.ts +77 -0
  172. package/apps/desktop/cli/studio-scaffold.ts +70 -0
  173. package/apps/desktop/cli/studio-service.ts +301 -0
  174. package/apps/desktop/cli/studio-spatial-asset.ts +248 -0
  175. package/apps/desktop/cli/studio-template-names.ts +3 -0
  176. package/apps/desktop/cli/studio-workflow.ts +19 -0
  177. package/apps/desktop/cli/time.ts +25 -0
  178. package/apps/desktop/cli/workflow-code.ts +584 -0
  179. package/apps/desktop/cli/workflow-runs.ts +576 -0
  180. package/apps/desktop/code/advanced.ts +139 -0
  181. package/apps/desktop/code/application-node-planner.ts +1288 -0
  182. package/apps/desktop/code/compiler.ts +329 -0
  183. package/apps/desktop/code/contracts.ts +13 -0
  184. package/apps/desktop/code/creative-recipes.ts +94 -0
  185. package/apps/desktop/code/define-workflow.ts +115 -0
  186. package/apps/desktop/code/editing.ts +284 -0
  187. package/apps/desktop/code/file-candidate-provenance.ts +420 -0
  188. package/apps/desktop/code/file-candidate.ts +69 -0
  189. package/apps/desktop/code/graph-builder.ts +10 -0
  190. package/apps/desktop/code/host-resource-policy.ts +55 -0
  191. package/apps/desktop/code/plan-contracts.ts +159 -0
  192. package/apps/desktop/code/planning.ts +361 -0
  193. package/apps/desktop/code/public.ts +134 -0
  194. package/apps/desktop/code/reference-projection.ts +62 -0
  195. package/apps/desktop/code/run-contracts.ts +466 -0
  196. package/apps/desktop/code/run-store.ts +2478 -0
  197. package/apps/desktop/code/runtime-identity.ts +328 -0
  198. package/apps/desktop/code/scheduler.ts +3067 -0
  199. package/apps/desktop/code/semantic-builder.ts +1436 -0
  200. package/apps/desktop/code/source-bundle.ts +1641 -0
  201. package/apps/desktop/code/source-typecheck.ts +211 -0
  202. package/apps/desktop/code/testing.ts +79 -0
  203. package/apps/desktop/code/worker-client.ts +1675 -0
  204. package/apps/desktop/code/worker-effects.ts +141 -0
  205. package/apps/desktop/code/worker-entry.ts +435 -0
  206. package/apps/desktop/code/worker-lease-guardian.ts +179 -0
  207. package/apps/desktop/code/worker-process-identity.ts +484 -0
  208. package/apps/desktop/code/worker-protocol.ts +211 -0
  209. package/apps/desktop/code/workflow-effects.ts +132 -0
  210. package/apps/desktop/contracts/analysis.ts +949 -0
  211. package/apps/desktop/contracts/edit.ts +576 -0
  212. package/apps/desktop/contracts/index.ts +9 -0
  213. package/apps/desktop/contracts/media-effects.ts +139 -0
  214. package/apps/desktop/contracts/project-render.ts +644 -0
  215. package/apps/desktop/contracts/project.ts +740 -0
  216. package/apps/desktop/contracts/recording.ts +1434 -0
  217. package/apps/desktop/contracts/render.ts +334 -0
  218. package/apps/desktop/contracts/runtime.ts +155 -0
  219. package/apps/desktop/contracts/spatial-compositor.ts +58 -0
  220. package/apps/desktop/contracts/spatial-project.ts +159 -0
  221. package/apps/desktop/contracts/spatial-world.ts +48 -0
  222. package/apps/desktop/contracts/video-effects.ts +120 -0
  223. package/apps/desktop/core/alignment-apply.ts +400 -0
  224. package/apps/desktop/core/audio-alignment.ts +466 -0
  225. package/apps/desktop/core/auto-zoom.ts +209 -0
  226. package/apps/desktop/core/canonical-json.ts +14 -0
  227. package/apps/desktop/core/emoji.ts +210 -0
  228. package/apps/desktop/core/events.ts +409 -0
  229. package/apps/desktop/core/face-framing.ts +533 -0
  230. package/apps/desktop/core/face-tracks.ts +326 -0
  231. package/apps/desktop/core/inactivity.ts +137 -0
  232. package/apps/desktop/core/index.ts +30 -0
  233. package/apps/desktop/core/intervals.ts +123 -0
  234. package/apps/desktop/core/montage.ts +236 -0
  235. package/apps/desktop/core/music-analysis.ts +518 -0
  236. package/apps/desktop/core/plan.ts +244 -0
  237. package/apps/desktop/core/project-auto-zoom.ts +75 -0
  238. package/apps/desktop/core/project-camera-spatial.ts +676 -0
  239. package/apps/desktop/core/project-camera.ts +403 -0
  240. package/apps/desktop/core/project-captions.ts +888 -0
  241. package/apps/desktop/core/project-inactivity.ts +125 -0
  242. package/apps/desktop/core/project-metadata.ts +927 -0
  243. package/apps/desktop/core/project-plan.ts +375 -0
  244. package/apps/desktop/core/project-render-plan.ts +303 -0
  245. package/apps/desktop/core/project-time.ts +469 -0
  246. package/apps/desktop/core/render-plan.ts +442 -0
  247. package/apps/desktop/core/scene-cache.ts +174 -0
  248. package/apps/desktop/core/scene-sampling.ts +448 -0
  249. package/apps/desktop/core/spatial-compositor.ts +22 -0
  250. package/apps/desktop/core/spatial-durability.ts +99 -0
  251. package/apps/desktop/core/spatial-project.ts +169 -0
  252. package/apps/desktop/core/spatial-shot-clock.ts +32 -0
  253. package/apps/desktop/core/speech-analysis.ts +333 -0
  254. package/apps/desktop/core/storage.ts +970 -0
  255. package/apps/desktop/core/time-map.ts +91 -0
  256. package/apps/desktop/core/time.ts +61 -0
  257. package/apps/desktop/core/video-effects.ts +660 -0
  258. package/apps/desktop/dist/cli/NebulaSans-Bold-26se8aek.otf +0 -0
  259. package/apps/desktop/dist/cli/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
  260. package/apps/desktop/dist/cli/NebulaSans-Book-5ax05zvn.woff2 +0 -0
  261. package/apps/desktop/dist/cli/NebulaSans-Book-8cenzchw.otf +0 -0
  262. package/apps/desktop/dist/cli/main.js +5086 -0
  263. package/apps/desktop/html-overlay/catalog.ts +171 -0
  264. package/apps/desktop/html-overlay/contracts.ts +372 -0
  265. package/apps/desktop/html-overlay/execution-profile.ts +77 -0
  266. package/apps/desktop/html-overlay/index.ts +98 -0
  267. package/apps/desktop/html-overlay/libraries.ts +263 -0
  268. package/apps/desktop/html-overlay/random.ts +49 -0
  269. package/apps/desktop/html-overlay/runtime.ts +813 -0
  270. package/apps/desktop/html-overlay/scaffolds.ts +792 -0
  271. package/apps/desktop/html-overlay/spark-runtime.ts +88 -0
  272. package/apps/desktop/html-overlay/spatial-splat-runtime.ts +60 -0
  273. package/apps/desktop/html-overlay/spatial.ts +720 -0
  274. package/apps/desktop/studio/assets/README.md +39 -0
  275. package/apps/desktop/studio/assets/contracts.ts +129 -0
  276. package/apps/desktop/studio/assets/network.ts +64 -0
  277. package/apps/desktop/studio/assets/poly-haven.ts +148 -0
  278. package/apps/desktop/studio/drivers/blender_driver.py +466 -0
  279. package/apps/desktop/studio/drivers/cadquery_driver.py +176 -0
  280. package/apps/desktop/studio/education/driver.py +308 -0
  281. package/apps/desktop/studio/education/lesson.py +180 -0
  282. package/apps/desktop/studio/education/toolkit.py +249 -0
  283. package/apps/desktop/workflows/chaptered-demo.ts +48 -0
  284. package/apps/desktop/workflows/creative-iteration.ts +107 -0
  285. package/apps/desktop/workflows/creative-selection.ts +92 -0
  286. package/apps/desktop/workflows/fragments.ts +486 -0
  287. package/apps/desktop/workflows/index.ts +93 -0
  288. package/apps/desktop/workflows/polished-screen-demo.ts +128 -0
  289. package/apps/desktop/workflows/scene-direction.ts +12 -0
  290. package/apps/desktop/workflows/social-variants.ts +75 -0
  291. package/apps/desktop/workflows/talking-head-cleanup.ts +53 -0
  292. package/dist/NebulaSans-Bold-26se8aek.otf +0 -0
  293. package/dist/NebulaSans-Bold-bcz7y08t.woff2 +0 -0
  294. package/dist/NebulaSans-Book-5ax05zvn.woff2 +0 -0
  295. package/dist/NebulaSans-Book-8cenzchw.otf +0 -0
  296. package/dist/cli.js +479 -0
  297. package/dist/code/advanced.js +270 -0
  298. package/dist/code/index.js +2240 -0
  299. package/dist/generate.js +24 -0
  300. package/dist/host-resources.js +26 -0
  301. package/dist/index-42zsesc1.js +2257 -0
  302. package/dist/index-7308egqr.js +48 -0
  303. package/dist/index-8txs6fkn.js +712 -0
  304. package/dist/index-mcy8z0br.js +192 -0
  305. package/dist/index-p63wavx0.js +2029 -0
  306. package/dist/index-r7gdhmsp.js +424 -0
  307. package/dist/index-sh6xbav6.js +1219 -0
  308. package/dist/index-z1w83f81.js +4 -0
  309. package/dist/index-z7239b4h.js +2363 -0
  310. package/dist/index-zfeg9hmw.js +2013 -0
  311. package/dist/index.js +241 -0
  312. package/dist/operations.js +29 -0
  313. package/dist/skill-install-dh0ntqba.js +10 -0
  314. package/dist/vectorize/worker.js +142 -0
  315. package/dist/workflow.js +16 -0
  316. package/docs/README.md +38 -0
  317. package/docs/studio.md +215 -0
  318. package/examples/studio/blender/README.md +26 -0
  319. package/examples/studio/blender/character.py +152 -0
  320. package/examples/studio/blender/cloth.py +101 -0
  321. package/examples/studio/blender/color_chart.py +29 -0
  322. package/examples/studio/blender/fluid.py +78 -0
  323. package/examples/studio/blender/import_model.py +74 -0
  324. package/examples/studio/blender/product.py +53 -0
  325. package/examples/studio/blender/shaded_street.py +481 -0
  326. package/examples/studio/blender/studio_scene.py +147 -0
  327. package/examples/studio/cadquery/README.md +13 -0
  328. package/examples/studio/cadquery/bracket.py +36 -0
  329. package/examples/studio/cadquery/import_step.py +12 -0
  330. package/examples/studio/education/README.md +46 -0
  331. package/examples/studio/education/lesson.json +99 -0
  332. package/examples/studio/education/scene.py +7 -0
  333. package/examples/studio/hybrid-scene.ts +96 -0
  334. package/examples/studio/native-workflow.ts +14 -0
  335. package/examples/studio/vgpu/README.md +64 -0
  336. package/examples/studio/vgpu/heat-field.mjs +290 -0
  337. package/package.json +304 -0
  338. package/packages/scene/src/index.ts +1 -0
  339. package/packages/scene/src/scene.ts +215 -0
  340. package/schema/diagram.schema.json +334 -0
  341. package/skills/slopcamera/SKILL.md +45 -0
  342. package/skills/slopcamera/agents/openai.yaml +4 -0
  343. package/skills/slopcamera/references/customization.md +77 -0
  344. package/skills/slopcamera/references/diagrams.md +153 -0
  345. package/skills/slopcamera/references/directed-scenes.md +42 -0
  346. package/skills/slopcamera/references/directing-video.md +18 -0
  347. package/skills/slopcamera/references/educational-video.md +26 -0
  348. package/skills/slopcamera/references/gateway-media.md +134 -0
  349. package/skills/slopcamera/references/install.md +62 -0
  350. package/skills/slopcamera/references/native-studio.md +31 -0
  351. package/skills/slopcamera/references/reference-led-3d.md +140 -0
  352. package/skills/slopcamera/references/rubber-stamp-examples/poster-example-1.jpg +0 -0
  353. package/skills/slopcamera/references/rubber-stamp-examples/poster-example-2.jpg +0 -0
  354. package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-1.png +0 -0
  355. package/skills/slopcamera/references/rubber-stamp-examples/stamp-style-2.png +0 -0
  356. package/skills/slopcamera/references/rubber-stamp-field-notes.md +144 -0
  357. package/skills/slopcamera/references/vectorization.md +29 -0
  358. package/skills/slopcamera/references/video-projects.md +187 -0
  359. package/skills/slopcamera/references/visual-communication.md +120 -0
  360. package/skills/slopcamera/references/workflows-sdk.md +45 -0
  361. package/skills/slopcamera/scripts/compose-rubber-stamp-field-note.ts +229 -0
  362. package/src/artifacts.ts +106 -0
  363. package/src/assets/fonts/nebula-sans/LICENSE.txt +96 -0
  364. package/src/assets/fonts/nebula-sans/NebulaSans-Bold.otf +0 -0
  365. package/src/assets/fonts/nebula-sans/NebulaSans-Bold.woff2 +0 -0
  366. package/src/assets/fonts/nebula-sans/NebulaSans-Book.otf +0 -0
  367. package/src/assets/fonts/nebula-sans/NebulaSans-Book.woff2 +0 -0
  368. package/src/assets/fonts/nebula-sans/PROVENANCE.md +21 -0
  369. package/src/assets.d.ts +9 -0
  370. package/src/cli.ts +601 -0
  371. package/src/cloud-errors.ts +26 -0
  372. package/src/code/advanced.ts +10 -0
  373. package/src/code/boundary.ts +21 -0
  374. package/src/code/canonical-json.ts +129 -0
  375. package/src/code/compiler.ts +953 -0
  376. package/src/code/contracts.ts +576 -0
  377. package/src/code/define-workflow.ts +334 -0
  378. package/src/code/errors.ts +41 -0
  379. package/src/code/graph-builder.ts +945 -0
  380. package/src/code/index.ts +121 -0
  381. package/src/code/json-snapshot.ts +899 -0
  382. package/src/code/json-utf8.ts +88 -0
  383. package/src/code/portable-builder.ts +136 -0
  384. package/src/code/projection.ts +378 -0
  385. package/src/code/public-operations.ts +450 -0
  386. package/src/code/runtime.ts +580 -0
  387. package/src/code/sha256.ts +36 -0
  388. package/src/config.ts +180 -0
  389. package/src/desktop.ts +253 -0
  390. package/src/fs.ts +10 -0
  391. package/src/generate.ts +704 -0
  392. package/src/host-resource-posix.ts +161 -0
  393. package/src/host-resources.ts +1749 -0
  394. package/src/icons.ts +58 -0
  395. package/src/index.ts +200 -0
  396. package/src/label-layout.ts +130 -0
  397. package/src/layout.ts +413 -0
  398. package/src/lint.ts +127 -0
  399. package/src/mcp/boundary.ts +354 -0
  400. package/src/mcp/index.ts +33 -0
  401. package/src/mcp/server.ts +272 -0
  402. package/src/mcp/tools.ts +963 -0
  403. package/src/mcp/types.ts +71 -0
  404. package/src/operations.ts +775 -0
  405. package/src/parse.ts +861 -0
  406. package/src/process-environment.ts +17 -0
  407. package/src/render.ts +437 -0
  408. package/src/skill-install.ts +49 -0
  409. package/src/spatial-scene/authoring.ts +27 -0
  410. package/src/spatial-scene/camera-track.ts +83 -0
  411. package/src/spatial-scene/contracts.ts +277 -0
  412. package/src/spatial-scene/evaluate.ts +145 -0
  413. package/src/spatial-scene/gltf.ts +558 -0
  414. package/src/spatial-scene/identity.ts +260 -0
  415. package/src/spatial-scene/index.ts +10 -0
  416. package/src/spatial-scene/inspect.ts +68 -0
  417. package/src/spatial-scene/math.ts +280 -0
  418. package/src/spatial-scene/patch.ts +131 -0
  419. package/src/spatial-scene/time.ts +53 -0
  420. package/src/studio/contracts.ts +129 -0
  421. package/src/studio/index.ts +2 -0
  422. package/src/studio/plan.ts +156 -0
  423. package/src/studio/shared.ts +41 -0
  424. package/src/theme.ts +68 -0
  425. package/src/tldr.ts +474 -0
  426. package/src/types.ts +212 -0
  427. package/src/vectorize/archive.ts +101 -0
  428. package/src/vectorize/command.ts +797 -0
  429. package/src/vectorize/index.ts +27 -0
  430. package/src/vectorize/limits.ts +61 -0
  431. package/src/vectorize/metrics.ts +351 -0
  432. package/src/vectorize/pixels.ts +323 -0
  433. package/src/vectorize/supervisor.ts +339 -0
  434. package/src/vectorize/svg.ts +188 -0
  435. package/src/vectorize/tool.ts +542 -0
  436. package/src/vectorize/types.ts +113 -0
  437. package/src/vectorize/vectorize.ts +634 -0
  438. package/src/vectorize/worker-protocol.ts +40 -0
  439. package/src/vectorize/worker.ts +209 -0
  440. package/src/version.ts +1 -0
  441. package/src/workflow.ts +409 -0
@@ -0,0 +1,1385 @@
1
+ import { z } from "zod";
2
+
3
+ import {
4
+ IsoTimestampSchema,
5
+ ProjectEditPlanV1Schema,
6
+ ProjectRenderOutputPathSchema,
7
+ RepositoryRelativePathSchema,
8
+ Sha256Schema,
9
+ VideoProjectIdSchema,
10
+ VideoProjectV1Schema,
11
+ type ProjectEditPlanV1,
12
+ type VideoProjectV1,
13
+ } from "../contracts";
14
+ import {
15
+ canonicalJson,
16
+ canonicalJsonSha256,
17
+ hashProjectEditPlan,
18
+ hashProjectStructure,
19
+ } from "../core";
20
+ import {
21
+ OrderedProjectEditV3Schema,
22
+ ProjectEditBatchV3Schema,
23
+ } from "./operations/derive/edit-batch";
24
+ import {
25
+ ProjectCommitManualZoomBindingV3Schema,
26
+ ProjectCommitMetadataBindingV2Schema,
27
+ } from "./operations/project/commit-edits";
28
+ import {
29
+ hashProjectGeneration,
30
+ projectEditBasis,
31
+ projectGenerationSha256FromHashes,
32
+ ProjectEditBasisSchema,
33
+ ProjectGenerationHashesSchema,
34
+ } from "./project-store";
35
+ import {
36
+ ProjectEditRevisionArtifactSchema,
37
+ ProjectRenderOutputReferenceSchema,
38
+ ProjectRenderReceiptReferenceSchema,
39
+ } from "./receipts";
40
+
41
+ const MAXIMUM_CREATIVE_DOCUMENT_BYTES = 256 * 1024 * 1024;
42
+ const CREATIVE_CANDIDATE_ID_PREFIX = "candidate_";
43
+
44
+ export const CreativeVariantKeySchema = z.string()
45
+ .min(1)
46
+ .max(64)
47
+ .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/u);
48
+
49
+ export const CreativeRenderNameSchema = z.string()
50
+ .min(1)
51
+ .max(64)
52
+ .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/u);
53
+
54
+ export const CreativeCandidateIdSchema = z.string()
55
+ .regex(/^candidate_[a-f0-9]{32}$/u);
56
+
57
+ export const CreativeCandidateNamespaceSchema = RepositoryRelativePathSchema
58
+ .refine(
59
+ value => /^iterations\/[a-f0-9]{64}\/candidates\/candidate_[a-f0-9]{32}$/u
60
+ .test(value),
61
+ "Creative candidate namespaces must be deterministic iteration paths.",
62
+ );
63
+
64
+ export const CreativeImmutableArtifactSchema = z.strictObject({
65
+ bytes: z.number().int().safe().positive().max(MAXIMUM_CREATIVE_DOCUMENT_BYTES),
66
+ path: RepositoryRelativePathSchema,
67
+ sha256: Sha256Schema,
68
+ });
69
+
70
+ const CreativeBaseV1BodySchema = z.strictObject({
71
+ currentPlan: ProjectEditPlanV1Schema,
72
+ editBasis: ProjectEditBasisSchema,
73
+ generation: ProjectGenerationHashesSchema,
74
+ kind: z.union([
75
+ z.literal("slopcamera.creative-base"),
76
+ z.literal("studio.creative-base"),
77
+ ]),
78
+ project: VideoProjectV1Schema,
79
+ projectId: VideoProjectIdSchema,
80
+ schemaVersion: z.literal(1),
81
+ });
82
+
83
+ function creativeBaseDomainHash(
84
+ body: z.infer<typeof CreativeBaseV1BodySchema>,
85
+ ): string {
86
+ return canonicalJsonSha256({
87
+ domain: "studio.creative-base/v1",
88
+ ...body,
89
+ });
90
+ }
91
+
92
+ function validateCreativeBase(
93
+ base: z.infer<typeof CreativeBaseV1BodySchema> & {
94
+ readonly baseSha256: string;
95
+ },
96
+ context: z.RefinementCtx,
97
+ ): void {
98
+ const generation = hashProjectGeneration(base.project, base.currentPlan);
99
+ const basis = projectEditBasis(base.project, base.currentPlan);
100
+ if (
101
+ base.projectId !== base.project.projectId
102
+ || base.projectId !== base.editBasis.projectId
103
+ || base.currentPlan.projectId !== base.projectId
104
+ ) {
105
+ context.addIssue({
106
+ code: "custom",
107
+ message: "Creative base project identities disagree.",
108
+ path: ["projectId"],
109
+ });
110
+ }
111
+ if (
112
+ base.currentPlan.projectStructureSha256
113
+ !== hashProjectStructure(base.project)
114
+ ) {
115
+ context.addIssue({
116
+ code: "custom",
117
+ message: "Creative base plan is not bound to its exact frozen project.",
118
+ path: ["currentPlan", "projectStructureSha256"],
119
+ });
120
+ }
121
+ if (canonicalJson(generation) !== canonicalJson(base.generation)) {
122
+ context.addIssue({
123
+ code: "custom",
124
+ message: "Creative base generation does not match its frozen documents.",
125
+ path: ["generation"],
126
+ });
127
+ }
128
+ if (canonicalJson(basis) !== canonicalJson(base.editBasis)) {
129
+ context.addIssue({
130
+ code: "custom",
131
+ message: "Creative base edit basis does not match its frozen documents.",
132
+ path: ["editBasis"],
133
+ });
134
+ }
135
+ if (
136
+ base.generation.currentPlanSha256 !== base.editBasis.currentPlanSha256
137
+ || base.generation.generationSha256 !== projectGenerationSha256FromHashes(
138
+ base.generation,
139
+ )
140
+ ) {
141
+ context.addIssue({
142
+ code: "custom",
143
+ message: "Creative base exact generation and append-tolerant basis disagree.",
144
+ path: ["generation"],
145
+ });
146
+ }
147
+ const body = CreativeBaseV1BodySchema.parse({
148
+ currentPlan: base.currentPlan,
149
+ editBasis: base.editBasis,
150
+ generation: base.generation,
151
+ kind: base.kind,
152
+ project: base.project,
153
+ projectId: base.projectId,
154
+ schemaVersion: base.schemaVersion,
155
+ });
156
+ if (creativeBaseDomainHash(body) !== base.baseSha256) {
157
+ context.addIssue({
158
+ code: "custom",
159
+ message: "Creative base hash does not match its exact frozen documents.",
160
+ path: ["baseSha256"],
161
+ });
162
+ }
163
+ }
164
+
165
+ export const CreativeBaseV1Schema = CreativeBaseV1BodySchema.extend({
166
+ baseSha256: Sha256Schema,
167
+ }).strict().superRefine(validateCreativeBase);
168
+
169
+ export type CreativeBaseV1 = z.infer<typeof CreativeBaseV1Schema>;
170
+
171
+ export function createCreativeBaseV1(input: {
172
+ readonly currentPlan: ProjectEditPlanV1;
173
+ readonly project: VideoProjectV1;
174
+ }): CreativeBaseV1 {
175
+ const project = VideoProjectV1Schema.parse(input.project);
176
+ const currentPlan = ProjectEditPlanV1Schema.parse(input.currentPlan);
177
+ const body = CreativeBaseV1BodySchema.parse({
178
+ currentPlan,
179
+ editBasis: projectEditBasis(project, currentPlan),
180
+ generation: hashProjectGeneration(project, currentPlan),
181
+ kind: "slopcamera.creative-base",
182
+ project,
183
+ projectId: project.projectId,
184
+ schemaVersion: 1,
185
+ });
186
+ return CreativeBaseV1Schema.parse({
187
+ ...body,
188
+ baseSha256: creativeBaseDomainHash(body),
189
+ });
190
+ }
191
+
192
+ export const CreativeBaseIdentityV1Schema = z.strictObject({
193
+ baseSha256: Sha256Schema,
194
+ editBasis: ProjectEditBasisSchema,
195
+ generation: ProjectGenerationHashesSchema,
196
+ projectId: VideoProjectIdSchema,
197
+ schemaVersion: z.literal(1),
198
+ }).superRefine((base, context) => {
199
+ if (
200
+ base.projectId !== base.editBasis.projectId
201
+ || base.generation.currentPlanSha256 !== base.editBasis.currentPlanSha256
202
+ || base.generation.generationSha256
203
+ !== projectGenerationSha256FromHashes(base.generation)
204
+ ) {
205
+ context.addIssue({
206
+ code: "custom",
207
+ message: "Creative base identity does not describe one project generation.",
208
+ });
209
+ }
210
+ });
211
+
212
+ export type CreativeBaseIdentityV1 = z.infer<
213
+ typeof CreativeBaseIdentityV1Schema
214
+ >;
215
+
216
+ export function creativeBaseIdentityV1(
217
+ baseInput: CreativeBaseV1,
218
+ ): CreativeBaseIdentityV1 {
219
+ const base = CreativeBaseV1Schema.parse(baseInput);
220
+ return CreativeBaseIdentityV1Schema.parse({
221
+ baseSha256: base.baseSha256,
222
+ editBasis: base.editBasis,
223
+ generation: base.generation,
224
+ projectId: base.projectId,
225
+ schemaVersion: 1,
226
+ });
227
+ }
228
+
229
+ export function creativeCandidateId(input: {
230
+ readonly baseSha256: string;
231
+ readonly variantKey: string;
232
+ }): string {
233
+ const baseSha256 = Sha256Schema.parse(input.baseSha256);
234
+ const variantKey = CreativeVariantKeySchema.parse(input.variantKey);
235
+ return CreativeCandidateIdSchema.parse(
236
+ `${CREATIVE_CANDIDATE_ID_PREFIX}${canonicalJsonSha256({
237
+ baseSha256,
238
+ domain: "studio.creative-candidate-id/v1",
239
+ variantKey,
240
+ }).slice(0, 32)}`,
241
+ );
242
+ }
243
+
244
+ export function creativeCandidateNamespace(input: {
245
+ readonly baseSha256: string;
246
+ readonly candidateId: string;
247
+ }): string {
248
+ const baseSha256 = Sha256Schema.parse(input.baseSha256);
249
+ const candidateId = CreativeCandidateIdSchema.parse(input.candidateId);
250
+ return CreativeCandidateNamespaceSchema.parse(
251
+ `iterations/${baseSha256}/candidates/${candidateId}`,
252
+ );
253
+ }
254
+
255
+ export const CreativeCandidateIdentityV1Schema = z.strictObject({
256
+ candidateId: CreativeCandidateIdSchema,
257
+ namespace: CreativeCandidateNamespaceSchema,
258
+ variantKey: CreativeVariantKeySchema,
259
+ }).superRefine((candidate, context) => {
260
+ const parts = candidate.namespace.split("/");
261
+ const baseSha256 = parts[1];
262
+ if (
263
+ baseSha256 === undefined
264
+ || creativeCandidateId({
265
+ baseSha256,
266
+ variantKey: candidate.variantKey,
267
+ }) !== candidate.candidateId
268
+ || parts.at(-1) !== candidate.candidateId
269
+ ) {
270
+ context.addIssue({
271
+ code: "custom",
272
+ message: "Creative candidate identity is not stable within its namespace.",
273
+ });
274
+ }
275
+ });
276
+
277
+ export type CreativeCandidateIdentityV1 = z.infer<
278
+ typeof CreativeCandidateIdentityV1Schema
279
+ >;
280
+
281
+ export function createCreativeCandidateIdentityV1(input: {
282
+ readonly base: CreativeBaseV1 | CreativeBaseIdentityV1;
283
+ readonly variantKey: string;
284
+ }): CreativeCandidateIdentityV1 {
285
+ const base = "currentPlan" in input.base
286
+ ? creativeBaseIdentityV1(input.base)
287
+ : CreativeBaseIdentityV1Schema.parse(input.base);
288
+ const candidateId = creativeCandidateId({
289
+ baseSha256: base.baseSha256,
290
+ variantKey: input.variantKey,
291
+ });
292
+ return CreativeCandidateIdentityV1Schema.parse({
293
+ candidateId,
294
+ namespace: creativeCandidateNamespace({
295
+ baseSha256: base.baseSha256,
296
+ candidateId,
297
+ }),
298
+ variantKey: input.variantKey,
299
+ });
300
+ }
301
+
302
+ export const CandidateRevisionHostBindingsV1Schema = z.strictObject({
303
+ manualZoomBindings: z.array(
304
+ ProjectCommitManualZoomBindingV3Schema,
305
+ ).max(10_000),
306
+ metadataBinding: ProjectCommitMetadataBindingV2Schema.nullable(),
307
+ }).superRefine((bindings, context) => {
308
+ const zoomIds = bindings.manualZoomBindings.map(binding => binding.zoomId);
309
+ if (new Set(zoomIds).size !== zoomIds.length) {
310
+ context.addIssue({
311
+ code: "custom",
312
+ message: "Candidate revision manual zoom bindings must have unique zoom IDs.",
313
+ path: ["manualZoomBindings"],
314
+ });
315
+ }
316
+ for (let index = 1; index < zoomIds.length; index += 1) {
317
+ if (zoomIds[index - 1]!.localeCompare(zoomIds[index]!) >= 0) {
318
+ context.addIssue({
319
+ code: "custom",
320
+ message: "Candidate revision manual zoom bindings must be sorted by zoom ID.",
321
+ path: ["manualZoomBindings", index, "zoomId"],
322
+ });
323
+ break;
324
+ }
325
+ }
326
+ });
327
+
328
+ export type CandidateRevisionHostBindingsV1 = z.infer<
329
+ typeof CandidateRevisionHostBindingsV1Schema
330
+ >;
331
+
332
+ /**
333
+ * Creative comparison includes the frozen baseline. It therefore uses the
334
+ * complete V3 edit language while admitting the one canonical empty batch.
335
+ */
336
+ export const CandidateProjectEditBatchV3Schema = z.strictObject({
337
+ kind: z.union([
338
+ z.literal("slopcamera.project-edit-batch"),
339
+ z.literal("studio.project-edit-batch"),
340
+ ]),
341
+ ordered: z.array(OrderedProjectEditV3Schema).max(10_000),
342
+ schemaVersion: z.literal(3),
343
+ sha256: Sha256Schema,
344
+ }).superRefine((batch, context) => {
345
+ if (
346
+ canonicalJsonSha256({
347
+ kind: batch.kind,
348
+ ordered: batch.ordered,
349
+ schemaVersion: batch.schemaVersion,
350
+ }) !== batch.sha256
351
+ ) {
352
+ context.addIssue({
353
+ code: "custom",
354
+ message: "Candidate V3 edit batch hash does not match its ordered edits.",
355
+ path: ["sha256"],
356
+ });
357
+ }
358
+ if (batch.ordered.length > 0 && !ProjectEditBatchV3Schema.safeParse(batch).success) {
359
+ context.addIssue({
360
+ code: "custom",
361
+ message: "Candidate edits must satisfy the complete V3 batch contract.",
362
+ });
363
+ }
364
+ });
365
+
366
+ export type CandidateProjectEditBatchV3 = z.infer<
367
+ typeof CandidateProjectEditBatchV3Schema
368
+ >;
369
+
370
+ export function createEmptyCandidateProjectEditBatchV3(): CandidateProjectEditBatchV3 {
371
+ const body = {
372
+ kind: "slopcamera.project-edit-batch" as const,
373
+ ordered: [],
374
+ schemaVersion: 3 as const,
375
+ };
376
+ return CandidateProjectEditBatchV3Schema.parse({
377
+ ...body,
378
+ sha256: canonicalJsonSha256(body),
379
+ });
380
+ }
381
+
382
+ export function canonicalCandidateRevisionHostBindingsV1(input: {
383
+ readonly manualZoomBindings?: readonly z.infer<
384
+ typeof ProjectCommitManualZoomBindingV3Schema
385
+ >[];
386
+ readonly metadataBinding?: z.infer<
387
+ typeof ProjectCommitMetadataBindingV2Schema
388
+ > | null;
389
+ }): CandidateRevisionHostBindingsV1 {
390
+ return CandidateRevisionHostBindingsV1Schema.parse({
391
+ manualZoomBindings: [...(input.manualZoomBindings ?? [])]
392
+ .sort((left, right) => left.zoomId.localeCompare(right.zoomId)),
393
+ metadataBinding: input.metadataBinding ?? null,
394
+ });
395
+ }
396
+
397
+ export function candidateRevisionDerivationSha256(input: {
398
+ readonly baseSha256: string;
399
+ readonly batch: CandidateProjectEditBatchV3;
400
+ readonly bindings: CandidateRevisionHostBindingsV1;
401
+ readonly candidate: CreativeCandidateIdentityV1;
402
+ readonly projectEditPlanSha256: string;
403
+ readonly revisionSha256: string;
404
+ readonly updatedAt: string;
405
+ }): string {
406
+ return canonicalJsonSha256({
407
+ baseSha256: Sha256Schema.parse(input.baseSha256),
408
+ batch: CandidateProjectEditBatchV3Schema.parse(input.batch),
409
+ bindings: CandidateRevisionHostBindingsV1Schema.parse(input.bindings),
410
+ candidate: CreativeCandidateIdentityV1Schema.parse(input.candidate),
411
+ domain: "studio.creative-candidate-revision-derivation/v1",
412
+ projectEditPlanSha256: Sha256Schema.parse(input.projectEditPlanSha256),
413
+ revisionSha256: Sha256Schema.parse(input.revisionSha256),
414
+ updatedAt: IsoTimestampSchema.parse(input.updatedAt),
415
+ });
416
+ }
417
+
418
+ export const CreativeCandidateRevisionReferenceV1Schema = z.strictObject({
419
+ artifact: ProjectEditRevisionArtifactSchema,
420
+ base: CreativeBaseIdentityV1Schema,
421
+ batchSha256: Sha256Schema,
422
+ bindingsSha256: Sha256Schema,
423
+ candidate: CreativeCandidateIdentityV1Schema,
424
+ derivationSha256: Sha256Schema,
425
+ kind: z.union([
426
+ z.literal("slopcamera.creative-candidate-revision-reference"),
427
+ z.literal("studio.creative-candidate-revision-reference"),
428
+ ]),
429
+ planId: ProjectEditPlanV1Schema.shape.planId,
430
+ projectEditPlanSha256: Sha256Schema,
431
+ projectId: VideoProjectIdSchema,
432
+ projectSha256: Sha256Schema,
433
+ projectStructureSha256: Sha256Schema,
434
+ revisionSha256: Sha256Schema,
435
+ schemaVersion: z.literal(1),
436
+ updatedAt: IsoTimestampSchema,
437
+ }).superRefine((revision, context) => {
438
+ if (
439
+ revision.artifact.path
440
+ !== `edits/revisions/${revision.artifact.sha256}.json`
441
+ || revision.base.projectId !== revision.projectId
442
+ || revision.base.generation.projectSha256 !== revision.projectSha256
443
+ || !revision.candidate.namespace.startsWith(
444
+ `iterations/${revision.base.baseSha256}/`,
445
+ )
446
+ ) {
447
+ context.addIssue({
448
+ code: "custom",
449
+ message: "Candidate revision reference identities or artifact path disagree.",
450
+ });
451
+ }
452
+ });
453
+
454
+ export type CreativeCandidateRevisionReferenceV1 = z.infer<
455
+ typeof CreativeCandidateRevisionReferenceV1Schema
456
+ >;
457
+
458
+ export const CreativeCandidateRenderV1Schema = z.strictObject({
459
+ name: CreativeRenderNameSchema,
460
+ output: ProjectRenderOutputReferenceSchema,
461
+ receipt: ProjectRenderReceiptReferenceSchema,
462
+ }).superRefine((render, context) => {
463
+ if (
464
+ render.output.projectId !== render.receipt.projectId
465
+ || render.output.revisionSha256 !== render.receipt.revisionSha256
466
+ || render.output.sha256 !== render.receipt.outputSha256
467
+ ) {
468
+ context.addIssue({
469
+ code: "custom",
470
+ message: "Creative candidate render output and verified receipt disagree.",
471
+ });
472
+ }
473
+ });
474
+
475
+ export type CreativeCandidateRenderV1 = z.infer<
476
+ typeof CreativeCandidateRenderV1Schema
477
+ >;
478
+
479
+ function validateCanonicalRenders(
480
+ renders: readonly CreativeCandidateRenderV1[],
481
+ context: z.RefinementCtx,
482
+ path: readonly (number | string)[],
483
+ ): void {
484
+ for (let index = 1; index < renders.length; index += 1) {
485
+ if (renders[index - 1]!.name.localeCompare(renders[index]!.name) >= 0) {
486
+ context.addIssue({
487
+ code: "custom",
488
+ message: "Creative candidate render names must be unique and sorted.",
489
+ path: [...path, index, "name"],
490
+ });
491
+ break;
492
+ }
493
+ }
494
+ }
495
+
496
+ const CreativeCandidateV1BodySchema = z.strictObject({
497
+ base: CreativeBaseV1Schema,
498
+ batch: CandidateProjectEditBatchV3Schema,
499
+ bindings: CandidateRevisionHostBindingsV1Schema,
500
+ candidate: CreativeCandidateIdentityV1Schema,
501
+ kind: z.union([
502
+ z.literal("slopcamera.creative-candidate"),
503
+ z.literal("studio.creative-candidate"),
504
+ ]),
505
+ renders: z.array(CreativeCandidateRenderV1Schema).max(16),
506
+ revision: CreativeCandidateRevisionReferenceV1Schema,
507
+ schemaVersion: z.literal(1),
508
+ updatedAt: IsoTimestampSchema,
509
+ });
510
+
511
+ function creativeCandidateDomainHash(
512
+ body: z.infer<typeof CreativeCandidateV1BodySchema>,
513
+ ): string {
514
+ return canonicalJsonSha256({
515
+ domain: "studio.creative-candidate/v1",
516
+ ...body,
517
+ });
518
+ }
519
+
520
+ export const CreativeCandidateV1Schema = CreativeCandidateV1BodySchema.extend({
521
+ candidateSha256: Sha256Schema,
522
+ }).strict().superRefine((candidate, context) => {
523
+ validateCanonicalRenders(candidate.renders, context, ["renders"]);
524
+ const base = creativeBaseIdentityV1(candidate.base);
525
+ if (
526
+ canonicalJson(base) !== canonicalJson(candidate.revision.base)
527
+ || canonicalJson(candidate.candidate)
528
+ !== canonicalJson(candidate.revision.candidate)
529
+ || candidate.batch.sha256 !== candidate.revision.batchSha256
530
+ || canonicalJsonSha256(candidate.bindings)
531
+ !== candidate.revision.bindingsSha256
532
+ || candidate.updatedAt !== candidate.revision.updatedAt
533
+ ) {
534
+ context.addIssue({
535
+ code: "custom",
536
+ message: "Creative candidate derivation does not match its revision reference.",
537
+ });
538
+ }
539
+ const expectedDerivation = candidateRevisionDerivationSha256({
540
+ baseSha256: candidate.base.baseSha256,
541
+ batch: candidate.batch,
542
+ bindings: candidate.bindings,
543
+ candidate: candidate.candidate,
544
+ projectEditPlanSha256: candidate.revision.projectEditPlanSha256,
545
+ revisionSha256: candidate.revision.revisionSha256,
546
+ updatedAt: candidate.updatedAt,
547
+ });
548
+ if (expectedDerivation !== candidate.revision.derivationSha256) {
549
+ context.addIssue({
550
+ code: "custom",
551
+ message: "Creative candidate revision derivation hash is invalid.",
552
+ path: ["revision", "derivationSha256"],
553
+ });
554
+ }
555
+ if (candidate.renders.some(render => (
556
+ render.output.projectId !== candidate.base.projectId
557
+ || render.output.revisionSha256 !== candidate.revision.revisionSha256
558
+ ))) {
559
+ context.addIssue({
560
+ code: "custom",
561
+ message: "Creative candidate renders must belong to its one revision.",
562
+ path: ["renders"],
563
+ });
564
+ }
565
+ const body = CreativeCandidateV1BodySchema.parse({
566
+ base: candidate.base,
567
+ batch: candidate.batch,
568
+ bindings: candidate.bindings,
569
+ candidate: candidate.candidate,
570
+ kind: candidate.kind,
571
+ renders: candidate.renders,
572
+ revision: candidate.revision,
573
+ schemaVersion: candidate.schemaVersion,
574
+ updatedAt: candidate.updatedAt,
575
+ });
576
+ if (creativeCandidateDomainHash(body) !== candidate.candidateSha256) {
577
+ context.addIssue({
578
+ code: "custom",
579
+ message: "Creative candidate hash does not match its complete derivation.",
580
+ path: ["candidateSha256"],
581
+ });
582
+ }
583
+ });
584
+
585
+ export type CreativeCandidateV1 = z.infer<typeof CreativeCandidateV1Schema>;
586
+
587
+ export function createCreativeCandidateV1(input: {
588
+ readonly base: CreativeBaseV1;
589
+ readonly batch: CandidateProjectEditBatchV3;
590
+ readonly bindings: CandidateRevisionHostBindingsV1;
591
+ readonly candidate: CreativeCandidateIdentityV1;
592
+ readonly renders: readonly CreativeCandidateRenderV1[];
593
+ readonly revision: CreativeCandidateRevisionReferenceV1;
594
+ readonly updatedAt: string;
595
+ }): CreativeCandidateV1 {
596
+ const body = CreativeCandidateV1BodySchema.parse({
597
+ ...input,
598
+ kind: "slopcamera.creative-candidate",
599
+ renders: [...input.renders]
600
+ .sort((left, right) => left.name.localeCompare(right.name)),
601
+ schemaVersion: 1,
602
+ });
603
+ return CreativeCandidateV1Schema.parse({
604
+ ...body,
605
+ candidateSha256: creativeCandidateDomainHash(body),
606
+ });
607
+ }
608
+
609
+ export function creativeCandidatePath(input: {
610
+ readonly baseSha256: string;
611
+ readonly candidateId: string;
612
+ readonly candidateSha256: string;
613
+ }): string {
614
+ return RepositoryRelativePathSchema.parse(
615
+ `${creativeCandidateNamespace(input)}/${Sha256Schema.parse(
616
+ input.candidateSha256,
617
+ )}.json`,
618
+ );
619
+ }
620
+
621
+ export const CreativeCandidateReferenceV1Schema = z.strictObject({
622
+ artifact: CreativeImmutableArtifactSchema,
623
+ base: CreativeBaseIdentityV1Schema,
624
+ candidate: CreativeCandidateIdentityV1Schema,
625
+ candidateSha256: Sha256Schema,
626
+ kind: z.union([
627
+ z.literal("slopcamera.creative-candidate-reference"),
628
+ z.literal("studio.creative-candidate-reference"),
629
+ ]),
630
+ renderSetSha256: Sha256Schema,
631
+ revisionSha256: Sha256Schema,
632
+ schemaVersion: z.literal(1),
633
+ }).superRefine((reference, context) => {
634
+ const expectedPath = creativeCandidatePath({
635
+ baseSha256: reference.base.baseSha256,
636
+ candidateId: reference.candidate.candidateId,
637
+ candidateSha256: reference.candidateSha256,
638
+ });
639
+ if (
640
+ reference.artifact.path !== expectedPath
641
+ || !reference.candidate.namespace.startsWith(
642
+ `iterations/${reference.base.baseSha256}/`,
643
+ )
644
+ ) {
645
+ context.addIssue({
646
+ code: "custom",
647
+ message: "Creative candidate reference path or namespace is invalid.",
648
+ });
649
+ }
650
+ });
651
+
652
+ export type CreativeCandidateReferenceV1 = z.infer<
653
+ typeof CreativeCandidateReferenceV1Schema
654
+ >;
655
+
656
+ export function creativeCandidateRenderSetSha256(
657
+ rendersInput: readonly CreativeCandidateRenderV1[],
658
+ ): string {
659
+ const renders = [...rendersInput]
660
+ .map(render => CreativeCandidateRenderV1Schema.parse(render))
661
+ .sort((left, right) => left.name.localeCompare(right.name));
662
+ return creativeCandidateRenderSummarySetSha256(
663
+ renders.map(render => ({
664
+ name: render.name,
665
+ outputSha256: render.output.sha256,
666
+ receiptSha256: render.receipt.receiptSha256,
667
+ })),
668
+ );
669
+ }
670
+
671
+ export function creativeCandidateRenderSummarySetSha256(
672
+ rendersInput: readonly {
673
+ readonly name: string;
674
+ readonly outputSha256: string;
675
+ readonly receiptSha256: string;
676
+ }[],
677
+ ): string {
678
+ const renders = [...rendersInput].map(render => ({
679
+ name: CreativeRenderNameSchema.parse(render.name),
680
+ outputSha256: Sha256Schema.parse(render.outputSha256),
681
+ receiptSha256: Sha256Schema.parse(render.receiptSha256),
682
+ }))
683
+ .sort((left, right) => left.name.localeCompare(right.name));
684
+ return canonicalJsonSha256({
685
+ domain: "studio.creative-candidate-render-set/v1",
686
+ renders,
687
+ });
688
+ }
689
+
690
+ export function creativeCandidateReferenceV1(input: {
691
+ readonly artifact: z.infer<typeof CreativeImmutableArtifactSchema>;
692
+ readonly candidate: CreativeCandidateV1;
693
+ }): CreativeCandidateReferenceV1 {
694
+ const candidate = CreativeCandidateV1Schema.parse(input.candidate);
695
+ return CreativeCandidateReferenceV1Schema.parse({
696
+ artifact: input.artifact,
697
+ base: creativeBaseIdentityV1(candidate.base),
698
+ candidate: candidate.candidate,
699
+ candidateSha256: candidate.candidateSha256,
700
+ kind: "slopcamera.creative-candidate-reference",
701
+ renderSetSha256: creativeCandidateRenderSetSha256(candidate.renders),
702
+ revisionSha256: candidate.revision.revisionSha256,
703
+ schemaVersion: 1,
704
+ });
705
+ }
706
+
707
+ function compareCandidateReferences(
708
+ left: CreativeCandidateReferenceV1,
709
+ right: CreativeCandidateReferenceV1,
710
+ ): number {
711
+ return left.candidate.candidateId.localeCompare(right.candidate.candidateId);
712
+ }
713
+
714
+ export function variantCandidateSetSha256(
715
+ candidatesInput: readonly CreativeCandidateReferenceV1[],
716
+ ): string {
717
+ const candidates = [...candidatesInput]
718
+ .map(candidate => CreativeCandidateReferenceV1Schema.parse(candidate))
719
+ .sort(compareCandidateReferences);
720
+ return canonicalJsonSha256({
721
+ candidates,
722
+ domain: "studio.variant-candidate-set/v1",
723
+ });
724
+ }
725
+
726
+ const VariantMatrixV1BodySchema = z.strictObject({
727
+ base: CreativeBaseIdentityV1Schema,
728
+ candidateSetSha256: Sha256Schema,
729
+ candidates: z.array(CreativeCandidateReferenceV1Schema).min(1).max(16),
730
+ kind: z.union([
731
+ z.literal("slopcamera.variant-matrix"),
732
+ z.literal("studio.variant-matrix"),
733
+ ]),
734
+ schemaVersion: z.literal(1),
735
+ });
736
+
737
+ function variantMatrixDomainHash(
738
+ body: z.infer<typeof VariantMatrixV1BodySchema>,
739
+ ): string {
740
+ return canonicalJsonSha256({
741
+ domain: "studio.variant-matrix/v1",
742
+ ...body,
743
+ });
744
+ }
745
+
746
+ export const VariantMatrixV1Schema = VariantMatrixV1BodySchema.extend({
747
+ matrixSha256: Sha256Schema,
748
+ }).strict().superRefine((matrix, context) => {
749
+ for (let index = 0; index < matrix.candidates.length; index += 1) {
750
+ const candidate = matrix.candidates[index]!;
751
+ if (canonicalJson(candidate.base) !== canonicalJson(matrix.base)) {
752
+ context.addIssue({
753
+ code: "custom",
754
+ message: "Variant matrix candidates must share the matrix base.",
755
+ path: ["candidates", index, "base"],
756
+ });
757
+ }
758
+ const previous = matrix.candidates[index - 1];
759
+ if (
760
+ previous !== undefined
761
+ && compareCandidateReferences(previous, candidate) >= 0
762
+ ) {
763
+ context.addIssue({
764
+ code: "custom",
765
+ message: "Variant matrix candidate IDs must be unique and sorted.",
766
+ path: ["candidates", index, "candidate", "candidateId"],
767
+ });
768
+ }
769
+ }
770
+ if (variantCandidateSetSha256(matrix.candidates) !== matrix.candidateSetSha256) {
771
+ context.addIssue({
772
+ code: "custom",
773
+ message: "Variant matrix candidate-set hash is invalid.",
774
+ path: ["candidateSetSha256"],
775
+ });
776
+ }
777
+ const body = VariantMatrixV1BodySchema.parse({
778
+ base: matrix.base,
779
+ candidateSetSha256: matrix.candidateSetSha256,
780
+ candidates: matrix.candidates,
781
+ kind: matrix.kind,
782
+ schemaVersion: matrix.schemaVersion,
783
+ });
784
+ if (variantMatrixDomainHash(body) !== matrix.matrixSha256) {
785
+ context.addIssue({
786
+ code: "custom",
787
+ message: "Variant matrix hash does not match its closed candidate set.",
788
+ path: ["matrixSha256"],
789
+ });
790
+ }
791
+ });
792
+
793
+ export type VariantMatrixV1 = z.infer<typeof VariantMatrixV1Schema>;
794
+
795
+ export function createVariantMatrixV1(input: {
796
+ readonly base: CreativeBaseIdentityV1;
797
+ readonly candidates: readonly CreativeCandidateReferenceV1[];
798
+ }): VariantMatrixV1 {
799
+ const candidates = [...input.candidates]
800
+ .map(candidate => CreativeCandidateReferenceV1Schema.parse(candidate))
801
+ .sort(compareCandidateReferences);
802
+ const body = VariantMatrixV1BodySchema.parse({
803
+ base: input.base,
804
+ candidateSetSha256: variantCandidateSetSha256(candidates),
805
+ candidates,
806
+ kind: "slopcamera.variant-matrix",
807
+ schemaVersion: 1,
808
+ });
809
+ return VariantMatrixV1Schema.parse({
810
+ ...body,
811
+ matrixSha256: variantMatrixDomainHash(body),
812
+ });
813
+ }
814
+
815
+ export function variantMatrixPath(input: {
816
+ readonly baseSha256: string;
817
+ readonly matrixSha256: string;
818
+ }): string {
819
+ return RepositoryRelativePathSchema.parse(
820
+ `iterations/${Sha256Schema.parse(input.baseSha256)}/matrices/${
821
+ Sha256Schema.parse(input.matrixSha256)
822
+ }.json`,
823
+ );
824
+ }
825
+
826
+ export const VariantMatrixReferenceV1Schema = z.strictObject({
827
+ artifact: CreativeImmutableArtifactSchema,
828
+ base: CreativeBaseIdentityV1Schema,
829
+ candidateCount: z.number().int().safe().min(1).max(16),
830
+ candidateSetSha256: Sha256Schema,
831
+ kind: z.union([
832
+ z.literal("slopcamera.variant-matrix-reference"),
833
+ z.literal("studio.variant-matrix-reference"),
834
+ ]),
835
+ matrixSha256: Sha256Schema,
836
+ schemaVersion: z.literal(1),
837
+ }).superRefine((reference, context) => {
838
+ if (reference.artifact.path !== variantMatrixPath({
839
+ baseSha256: reference.base.baseSha256,
840
+ matrixSha256: reference.matrixSha256,
841
+ })) {
842
+ context.addIssue({
843
+ code: "custom",
844
+ message: "Variant matrix reference path is not content-addressed.",
845
+ path: ["artifact", "path"],
846
+ });
847
+ }
848
+ });
849
+
850
+ export type VariantMatrixReferenceV1 = z.infer<
851
+ typeof VariantMatrixReferenceV1Schema
852
+ >;
853
+
854
+ export function variantMatrixReferenceV1(input: {
855
+ readonly artifact: z.infer<typeof CreativeImmutableArtifactSchema>;
856
+ readonly matrix: VariantMatrixV1;
857
+ }): VariantMatrixReferenceV1 {
858
+ const matrix = VariantMatrixV1Schema.parse(input.matrix);
859
+ return VariantMatrixReferenceV1Schema.parse({
860
+ artifact: input.artifact,
861
+ base: matrix.base,
862
+ candidateCount: matrix.candidates.length,
863
+ candidateSetSha256: matrix.candidateSetSha256,
864
+ kind: "slopcamera.variant-matrix-reference",
865
+ matrixSha256: matrix.matrixSha256,
866
+ schemaVersion: 1,
867
+ });
868
+ }
869
+
870
+ export const VariantSelectionEvidenceScoreV1Schema = z.strictObject({
871
+ criterion: z.string().min(1).max(128),
872
+ score: z.number().finite().min(-1_000_000).max(1_000_000),
873
+ });
874
+
875
+ export const VariantSelectionEvidenceV1Schema = z.strictObject({
876
+ rationale: z.string().min(1).max(8_192),
877
+ scores: z.array(VariantSelectionEvidenceScoreV1Schema).max(64).optional(),
878
+ }).superRefine((evidence, context) => {
879
+ const scores = evidence.scores ?? [];
880
+ for (let index = 1; index < scores.length; index += 1) {
881
+ if (scores[index - 1]!.criterion.localeCompare(scores[index]!.criterion) >= 0) {
882
+ context.addIssue({
883
+ code: "custom",
884
+ message: "Selection evidence criteria must be unique and sorted.",
885
+ path: ["scores", index, "criterion"],
886
+ });
887
+ break;
888
+ }
889
+ }
890
+ });
891
+
892
+ export const VariantSelectionResultV1Schema = z.strictObject({
893
+ candidateSha256: Sha256Schema,
894
+ renders: z.array(z.strictObject({
895
+ name: CreativeRenderNameSchema,
896
+ outputSha256: Sha256Schema,
897
+ receiptSha256: Sha256Schema,
898
+ })).max(16),
899
+ revisionSha256: Sha256Schema,
900
+ }).superRefine((result, context) => {
901
+ for (let index = 1; index < result.renders.length; index += 1) {
902
+ if (
903
+ result.renders[index - 1]!.name.localeCompare(
904
+ result.renders[index]!.name,
905
+ ) >= 0
906
+ ) {
907
+ context.addIssue({
908
+ code: "custom",
909
+ message: "Selection result render names must be unique and sorted.",
910
+ path: ["renders", index, "name"],
911
+ });
912
+ break;
913
+ }
914
+ }
915
+ });
916
+
917
+ const VariantSelectionV1BodySchema = z.strictObject({
918
+ base: CreativeBaseIdentityV1Schema,
919
+ chosen: CreativeCandidateReferenceV1Schema,
920
+ evidence: VariantSelectionEvidenceV1Schema.optional(),
921
+ kind: z.union([
922
+ z.literal("slopcamera.variant-selection"),
923
+ z.literal("studio.variant-selection"),
924
+ ]),
925
+ matrix: VariantMatrixReferenceV1Schema,
926
+ result: VariantSelectionResultV1Schema,
927
+ schemaVersion: z.literal(1),
928
+ });
929
+
930
+ function variantSelectionDomainHash(
931
+ body: z.infer<typeof VariantSelectionV1BodySchema>,
932
+ ): string {
933
+ return canonicalJsonSha256({
934
+ domain: "studio.variant-selection/v1",
935
+ ...body,
936
+ });
937
+ }
938
+
939
+ export const VariantSelectionV1Schema = VariantSelectionV1BodySchema.extend({
940
+ selectionSha256: Sha256Schema,
941
+ }).strict().superRefine((selection, context) => {
942
+ if (
943
+ canonicalJson(selection.base) !== canonicalJson(selection.matrix.base)
944
+ || canonicalJson(selection.base) !== canonicalJson(selection.chosen.base)
945
+ || selection.result.candidateSha256 !== selection.chosen.candidateSha256
946
+ || selection.result.revisionSha256 !== selection.chosen.revisionSha256
947
+ || creativeCandidateRenderSummarySetSha256(selection.result.renders)
948
+ !== selection.chosen.renderSetSha256
949
+ ) {
950
+ context.addIssue({
951
+ code: "custom",
952
+ message: "Variant selection base, chosen candidate, and result disagree.",
953
+ });
954
+ }
955
+ const body = VariantSelectionV1BodySchema.parse({
956
+ base: selection.base,
957
+ chosen: selection.chosen,
958
+ ...(selection.evidence === undefined
959
+ ? {}
960
+ : { evidence: selection.evidence }),
961
+ kind: selection.kind,
962
+ matrix: selection.matrix,
963
+ result: selection.result,
964
+ schemaVersion: selection.schemaVersion,
965
+ });
966
+ if (variantSelectionDomainHash(body) !== selection.selectionSha256) {
967
+ context.addIssue({
968
+ code: "custom",
969
+ message: "Variant selection hash does not match its exact decision.",
970
+ path: ["selectionSha256"],
971
+ });
972
+ }
973
+ });
974
+
975
+ export type VariantSelectionV1 = z.infer<typeof VariantSelectionV1Schema>;
976
+
977
+ export function createVariantSelectionV1(input: {
978
+ readonly candidate: CreativeCandidateV1;
979
+ readonly chosen: CreativeCandidateReferenceV1;
980
+ readonly evidence?: z.infer<typeof VariantSelectionEvidenceV1Schema>;
981
+ readonly matrix: VariantMatrixReferenceV1;
982
+ }): VariantSelectionV1 {
983
+ const candidate = CreativeCandidateV1Schema.parse(input.candidate);
984
+ const renders = candidate.renders.map(render => ({
985
+ name: render.name,
986
+ outputSha256: render.output.sha256,
987
+ receiptSha256: render.receipt.receiptSha256,
988
+ }));
989
+ const evidence = input.evidence === undefined
990
+ ? undefined
991
+ : VariantSelectionEvidenceV1Schema.parse({
992
+ ...input.evidence,
993
+ ...(input.evidence.scores === undefined
994
+ ? {}
995
+ : {
996
+ scores: [...input.evidence.scores].sort((left, right) => (
997
+ left.criterion.localeCompare(right.criterion)
998
+ )),
999
+ }),
1000
+ });
1001
+ const body = VariantSelectionV1BodySchema.parse({
1002
+ base: input.matrix.base,
1003
+ chosen: input.chosen,
1004
+ ...(evidence === undefined ? {} : { evidence }),
1005
+ kind: "slopcamera.variant-selection",
1006
+ matrix: input.matrix,
1007
+ result: {
1008
+ candidateSha256: candidate.candidateSha256,
1009
+ renders,
1010
+ revisionSha256: candidate.revision.revisionSha256,
1011
+ },
1012
+ schemaVersion: 1,
1013
+ });
1014
+ return VariantSelectionV1Schema.parse({
1015
+ ...body,
1016
+ selectionSha256: variantSelectionDomainHash(body),
1017
+ });
1018
+ }
1019
+
1020
+ export function variantSelectionPath(input: {
1021
+ readonly baseSha256: string;
1022
+ readonly selectionSha256: string;
1023
+ }): string {
1024
+ return RepositoryRelativePathSchema.parse(
1025
+ `iterations/${Sha256Schema.parse(input.baseSha256)}/selections/${
1026
+ Sha256Schema.parse(input.selectionSha256)
1027
+ }.json`,
1028
+ );
1029
+ }
1030
+
1031
+ export const VariantSelectionReferenceV1Schema = z.strictObject({
1032
+ artifact: CreativeImmutableArtifactSchema,
1033
+ base: CreativeBaseIdentityV1Schema,
1034
+ chosenCandidateId: CreativeCandidateIdSchema,
1035
+ chosenCandidateSha256: Sha256Schema,
1036
+ kind: z.union([
1037
+ z.literal("slopcamera.variant-selection-reference"),
1038
+ z.literal("studio.variant-selection-reference"),
1039
+ ]),
1040
+ matrixSha256: Sha256Schema,
1041
+ revisionSha256: Sha256Schema,
1042
+ schemaVersion: z.literal(1),
1043
+ selectionSha256: Sha256Schema,
1044
+ }).superRefine((reference, context) => {
1045
+ if (reference.artifact.path !== variantSelectionPath({
1046
+ baseSha256: reference.base.baseSha256,
1047
+ selectionSha256: reference.selectionSha256,
1048
+ })) {
1049
+ context.addIssue({
1050
+ code: "custom",
1051
+ message: "Variant selection reference path is not content-addressed.",
1052
+ path: ["artifact", "path"],
1053
+ });
1054
+ }
1055
+ });
1056
+
1057
+ export type VariantSelectionReferenceV1 = z.infer<
1058
+ typeof VariantSelectionReferenceV1Schema
1059
+ >;
1060
+
1061
+ export function variantSelectionReferenceV1(input: {
1062
+ readonly artifact: z.infer<typeof CreativeImmutableArtifactSchema>;
1063
+ readonly selection: VariantSelectionV1;
1064
+ }): VariantSelectionReferenceV1 {
1065
+ const selection = VariantSelectionV1Schema.parse(input.selection);
1066
+ return VariantSelectionReferenceV1Schema.parse({
1067
+ artifact: input.artifact,
1068
+ base: selection.base,
1069
+ chosenCandidateId: selection.chosen.candidate.candidateId,
1070
+ chosenCandidateSha256: selection.chosen.candidateSha256,
1071
+ kind: "slopcamera.variant-selection-reference",
1072
+ matrixSha256: selection.matrix.matrixSha256,
1073
+ revisionSha256: selection.result.revisionSha256,
1074
+ schemaVersion: 1,
1075
+ selectionSha256: selection.selectionSha256,
1076
+ });
1077
+ }
1078
+
1079
+ const EditorialPromotionReceiptV1BodySchema = z.strictObject({
1080
+ base: CreativeBaseIdentityV1Schema,
1081
+ candidate: CreativeCandidateReferenceV1Schema,
1082
+ kind: z.union([
1083
+ z.literal("slopcamera.editorial-promotion-receipt"),
1084
+ z.literal("studio.editorial-promotion-receipt"),
1085
+ ]),
1086
+ promotedBasis: ProjectEditBasisSchema,
1087
+ promotedPlanId: ProjectEditPlanV1Schema.shape.planId,
1088
+ promotedPlanSha256: Sha256Schema,
1089
+ schemaVersion: z.literal(1),
1090
+ selection: VariantSelectionReferenceV1Schema,
1091
+ transactionId: z.string().regex(/^transaction_[a-f0-9]{32}$/u),
1092
+ });
1093
+
1094
+ function editorialPromotionDomainHash(
1095
+ body: z.infer<typeof EditorialPromotionReceiptV1BodySchema>,
1096
+ ): string {
1097
+ return canonicalJsonSha256({
1098
+ domain: "studio.editorial-promotion-receipt/v1",
1099
+ ...body,
1100
+ });
1101
+ }
1102
+
1103
+ export const EditorialPromotionReceiptV1Schema =
1104
+ EditorialPromotionReceiptV1BodySchema.extend({
1105
+ promotionSha256: Sha256Schema,
1106
+ }).strict().superRefine((receipt, context) => {
1107
+ if (
1108
+ canonicalJson(receipt.base) !== canonicalJson(receipt.selection.base)
1109
+ || canonicalJson(receipt.base) !== canonicalJson(receipt.candidate.base)
1110
+ || receipt.selection.chosenCandidateSha256
1111
+ !== receipt.candidate.candidateSha256
1112
+ || receipt.promotedBasis.currentPlanSha256
1113
+ !== receipt.promotedPlanSha256
1114
+ ) {
1115
+ context.addIssue({
1116
+ code: "custom",
1117
+ message: "Editorial promotion receipt identities disagree.",
1118
+ });
1119
+ }
1120
+ const body = EditorialPromotionReceiptV1BodySchema.parse({
1121
+ base: receipt.base,
1122
+ candidate: receipt.candidate,
1123
+ kind: receipt.kind,
1124
+ promotedBasis: receipt.promotedBasis,
1125
+ promotedPlanId: receipt.promotedPlanId,
1126
+ promotedPlanSha256: receipt.promotedPlanSha256,
1127
+ schemaVersion: receipt.schemaVersion,
1128
+ selection: receipt.selection,
1129
+ transactionId: receipt.transactionId,
1130
+ });
1131
+ if (editorialPromotionDomainHash(body) !== receipt.promotionSha256) {
1132
+ context.addIssue({
1133
+ code: "custom",
1134
+ message: "Editorial promotion receipt hash is invalid.",
1135
+ path: ["promotionSha256"],
1136
+ });
1137
+ }
1138
+ });
1139
+
1140
+ export type EditorialPromotionReceiptV1 = z.infer<
1141
+ typeof EditorialPromotionReceiptV1Schema
1142
+ >;
1143
+
1144
+ export function editorialPromotionTransactionId(selectionSha256: string): string {
1145
+ return `transaction_${canonicalJsonSha256({
1146
+ domain: "studio.editorial-promotion-transaction/v1",
1147
+ selectionSha256: Sha256Schema.parse(selectionSha256),
1148
+ }).slice(0, 32)}`;
1149
+ }
1150
+
1151
+ export function createEditorialPromotionReceiptV1(input: {
1152
+ readonly base: CreativeBaseIdentityV1;
1153
+ readonly candidate: CreativeCandidateReferenceV1;
1154
+ readonly promotedPlan: ProjectEditPlanV1;
1155
+ readonly selection: VariantSelectionReferenceV1;
1156
+ readonly frozenProject: VideoProjectV1;
1157
+ }): EditorialPromotionReceiptV1 {
1158
+ const promotedPlan = ProjectEditPlanV1Schema.parse(input.promotedPlan);
1159
+ const frozenProject = VideoProjectV1Schema.parse(input.frozenProject);
1160
+ const body = EditorialPromotionReceiptV1BodySchema.parse({
1161
+ base: input.base,
1162
+ candidate: input.candidate,
1163
+ kind: "slopcamera.editorial-promotion-receipt",
1164
+ promotedBasis: projectEditBasis(frozenProject, promotedPlan),
1165
+ promotedPlanId: promotedPlan.planId,
1166
+ promotedPlanSha256: hashProjectEditPlan(promotedPlan),
1167
+ schemaVersion: 1,
1168
+ selection: input.selection,
1169
+ transactionId: editorialPromotionTransactionId(
1170
+ input.selection.selectionSha256,
1171
+ ),
1172
+ });
1173
+ return EditorialPromotionReceiptV1Schema.parse({
1174
+ ...body,
1175
+ promotionSha256: editorialPromotionDomainHash(body),
1176
+ });
1177
+ }
1178
+
1179
+ export function editorialPromotionReceiptPath(input: {
1180
+ readonly baseSha256: string;
1181
+ }): string {
1182
+ return RepositoryRelativePathSchema.parse(
1183
+ `iterations/${Sha256Schema.parse(input.baseSha256)}/promotions/editorial.json`,
1184
+ );
1185
+ }
1186
+
1187
+ export const EditorialPromotionReceiptReferenceV1Schema = z.strictObject({
1188
+ artifact: CreativeImmutableArtifactSchema,
1189
+ kind: z.union([
1190
+ z.literal("slopcamera.editorial-promotion-receipt-reference"),
1191
+ z.literal("studio.editorial-promotion-receipt-reference"),
1192
+ ]),
1193
+ projectId: VideoProjectIdSchema,
1194
+ promotedPlanSha256: Sha256Schema,
1195
+ promotionSha256: Sha256Schema,
1196
+ schemaVersion: z.literal(1),
1197
+ selectionSha256: Sha256Schema,
1198
+ }).superRefine((reference, context) => {
1199
+ const segments = reference.artifact.path.split("/");
1200
+ if (
1201
+ segments[0] !== "iterations"
1202
+ || segments[2] !== "promotions"
1203
+ || segments[3] !== "editorial.json"
1204
+ ) {
1205
+ context.addIssue({
1206
+ code: "custom",
1207
+ message: "Editorial promotion receipt reference path is invalid.",
1208
+ path: ["artifact", "path"],
1209
+ });
1210
+ }
1211
+ });
1212
+
1213
+ export type EditorialPromotionReceiptReferenceV1 = z.infer<
1214
+ typeof EditorialPromotionReceiptReferenceV1Schema
1215
+ >;
1216
+
1217
+ export function editorialPromotionReceiptReferenceV1(input: {
1218
+ readonly artifact: z.infer<typeof CreativeImmutableArtifactSchema>;
1219
+ readonly receipt: EditorialPromotionReceiptV1;
1220
+ }): EditorialPromotionReceiptReferenceV1 {
1221
+ const receipt = EditorialPromotionReceiptV1Schema.parse(input.receipt);
1222
+ return EditorialPromotionReceiptReferenceV1Schema.parse({
1223
+ artifact: input.artifact,
1224
+ kind: "slopcamera.editorial-promotion-receipt-reference",
1225
+ projectId: receipt.base.projectId,
1226
+ promotedPlanSha256: receipt.promotedPlanSha256,
1227
+ promotionSha256: receipt.promotionSha256,
1228
+ schemaVersion: 1,
1229
+ selectionSha256: receipt.selection.selectionSha256,
1230
+ });
1231
+ }
1232
+
1233
+ const DeliveryMaterializationReceiptV1BodySchema = z.strictObject({
1234
+ candidate: CreativeCandidateReferenceV1Schema,
1235
+ destination: ProjectRenderOutputReferenceSchema,
1236
+ kind: z.union([
1237
+ z.literal("slopcamera.delivery-materialization-receipt"),
1238
+ z.literal("studio.delivery-materialization-receipt"),
1239
+ ]),
1240
+ renderName: CreativeRenderNameSchema,
1241
+ schemaVersion: z.literal(1),
1242
+ selection: VariantSelectionReferenceV1Schema,
1243
+ source: ProjectRenderOutputReferenceSchema,
1244
+ });
1245
+
1246
+ function deliveryMaterializationDomainHash(
1247
+ body: z.infer<typeof DeliveryMaterializationReceiptV1BodySchema>,
1248
+ ): string {
1249
+ return canonicalJsonSha256({
1250
+ domain: "studio.delivery-materialization-receipt/v1",
1251
+ ...body,
1252
+ });
1253
+ }
1254
+
1255
+ export const DeliveryMaterializationReceiptV1Schema =
1256
+ DeliveryMaterializationReceiptV1BodySchema.extend({
1257
+ materializationSha256: Sha256Schema,
1258
+ }).strict().superRefine((receipt, context) => {
1259
+ if (
1260
+ receipt.source.path === receipt.destination.path
1261
+ || receipt.source.bytes !== receipt.destination.bytes
1262
+ || receipt.source.sha256 !== receipt.destination.sha256
1263
+ || receipt.source.projectId !== receipt.destination.projectId
1264
+ || receipt.source.revisionSha256 !== receipt.destination.revisionSha256
1265
+ || receipt.source.planArtifactSha256
1266
+ !== receipt.destination.planArtifactSha256
1267
+ || canonicalJson(receipt.candidate.base)
1268
+ !== canonicalJson(receipt.selection.base)
1269
+ || receipt.candidate.candidate.candidateId
1270
+ !== receipt.selection.chosenCandidateId
1271
+ || receipt.candidate.candidateSha256
1272
+ !== receipt.selection.chosenCandidateSha256
1273
+ || receipt.candidate.revisionSha256
1274
+ !== receipt.selection.revisionSha256
1275
+ || receipt.source.projectId !== receipt.selection.base.projectId
1276
+ || receipt.source.revisionSha256 !== receipt.selection.revisionSha256
1277
+ ) {
1278
+ context.addIssue({
1279
+ code: "custom",
1280
+ message: "Delivery materialization does not preserve the selected render provenance and bytes.",
1281
+ });
1282
+ }
1283
+ const body = DeliveryMaterializationReceiptV1BodySchema.parse({
1284
+ candidate: receipt.candidate,
1285
+ destination: receipt.destination,
1286
+ kind: receipt.kind,
1287
+ renderName: receipt.renderName,
1288
+ schemaVersion: receipt.schemaVersion,
1289
+ selection: receipt.selection,
1290
+ source: receipt.source,
1291
+ });
1292
+ if (
1293
+ deliveryMaterializationDomainHash(body)
1294
+ !== receipt.materializationSha256
1295
+ ) {
1296
+ context.addIssue({
1297
+ code: "custom",
1298
+ message: "Delivery materialization receipt hash is invalid.",
1299
+ path: ["materializationSha256"],
1300
+ });
1301
+ }
1302
+ });
1303
+
1304
+ export type DeliveryMaterializationReceiptV1 = z.infer<
1305
+ typeof DeliveryMaterializationReceiptV1Schema
1306
+ >;
1307
+
1308
+ export function createDeliveryMaterializationReceiptV1(input: {
1309
+ readonly candidate: CreativeCandidateReferenceV1;
1310
+ readonly destinationPath: string;
1311
+ readonly renderName: string;
1312
+ readonly selection: VariantSelectionReferenceV1;
1313
+ readonly source: z.infer<typeof ProjectRenderOutputReferenceSchema>;
1314
+ }): DeliveryMaterializationReceiptV1 {
1315
+ const source = ProjectRenderOutputReferenceSchema.parse(input.source);
1316
+ const body = DeliveryMaterializationReceiptV1BodySchema.parse({
1317
+ candidate: input.candidate,
1318
+ destination: {
1319
+ ...source,
1320
+ path: ProjectRenderOutputPathSchema.parse(input.destinationPath),
1321
+ },
1322
+ kind: "slopcamera.delivery-materialization-receipt",
1323
+ renderName: input.renderName,
1324
+ schemaVersion: 1,
1325
+ selection: input.selection,
1326
+ source,
1327
+ });
1328
+ return DeliveryMaterializationReceiptV1Schema.parse({
1329
+ ...body,
1330
+ materializationSha256: deliveryMaterializationDomainHash(body),
1331
+ });
1332
+ }
1333
+
1334
+ export function deliveryMaterializationReceiptPath(
1335
+ materializationSha256Input: string,
1336
+ ): string {
1337
+ const materializationSha256 = Sha256Schema.parse(
1338
+ materializationSha256Input,
1339
+ );
1340
+ return RepositoryRelativePathSchema.parse(
1341
+ `renders/materializations/${materializationSha256}.json`,
1342
+ );
1343
+ }
1344
+
1345
+ export const DeliveryMaterializationReceiptReferenceV1Schema = z.strictObject({
1346
+ artifact: CreativeImmutableArtifactSchema,
1347
+ destination: ProjectRenderOutputReferenceSchema,
1348
+ kind: z.union([
1349
+ z.literal("slopcamera.delivery-materialization-receipt-reference"),
1350
+ z.literal("studio.delivery-materialization-receipt-reference"),
1351
+ ]),
1352
+ materializationSha256: Sha256Schema,
1353
+ schemaVersion: z.literal(1),
1354
+ selectionSha256: Sha256Schema,
1355
+ }).superRefine((reference, context) => {
1356
+ if (
1357
+ reference.artifact.path
1358
+ !== deliveryMaterializationReceiptPath(reference.materializationSha256)
1359
+ ) {
1360
+ context.addIssue({
1361
+ code: "custom",
1362
+ message: "Delivery materialization receipt path is not content-addressed.",
1363
+ path: ["artifact", "path"],
1364
+ });
1365
+ }
1366
+ });
1367
+
1368
+ export type DeliveryMaterializationReceiptReferenceV1 = z.infer<
1369
+ typeof DeliveryMaterializationReceiptReferenceV1Schema
1370
+ >;
1371
+
1372
+ export function deliveryMaterializationReceiptReferenceV1(input: {
1373
+ readonly artifact: z.infer<typeof CreativeImmutableArtifactSchema>;
1374
+ readonly receipt: DeliveryMaterializationReceiptV1;
1375
+ }): DeliveryMaterializationReceiptReferenceV1 {
1376
+ const receipt = DeliveryMaterializationReceiptV1Schema.parse(input.receipt);
1377
+ return DeliveryMaterializationReceiptReferenceV1Schema.parse({
1378
+ artifact: input.artifact,
1379
+ destination: receipt.destination,
1380
+ kind: "slopcamera.delivery-materialization-receipt-reference",
1381
+ materializationSha256: receipt.materializationSha256,
1382
+ schemaVersion: 1,
1383
+ selectionSha256: receipt.selection.selectionSha256,
1384
+ });
1385
+ }