@photivra/engine 0.5.1 → 1.0.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 (753) hide show
  1. package/AGENTS.md +674 -0
  2. package/CHANGELOG.md +218 -0
  3. package/CITATION.cff +1 -1
  4. package/CONTRIBUTING.md +76 -0
  5. package/DCO +33 -0
  6. package/NODE_SUPPORT.md +37 -0
  7. package/NOTICE +2 -0
  8. package/README.md +157 -56
  9. package/SECURITY.md +55 -0
  10. package/THIRD_PARTY.md +63 -0
  11. package/dist/camera/equivalent-focal-length.d.ts +9 -0
  12. package/dist/camera/equivalent-focal-length.d.ts.map +1 -1
  13. package/dist/camera/equivalent-focal-length.js +9 -0
  14. package/dist/camera/equivalent-focal-length.js.map +1 -1
  15. package/dist/camera/field-of-view.d.ts +13 -0
  16. package/dist/camera/field-of-view.d.ts.map +1 -1
  17. package/dist/camera/field-of-view.js +13 -0
  18. package/dist/camera/field-of-view.js.map +1 -1
  19. package/dist/camera/projected-object-size.d.ts +8 -0
  20. package/dist/camera/projected-object-size.d.ts.map +1 -1
  21. package/dist/camera/projected-object-size.js +8 -0
  22. package/dist/camera/projected-object-size.js.map +1 -1
  23. package/dist/capture/capture-export-metadata.d.ts +60 -0
  24. package/dist/capture/capture-export-metadata.d.ts.map +1 -0
  25. package/dist/capture/capture-export-metadata.js +62 -0
  26. package/dist/capture/capture-export-metadata.js.map +1 -0
  27. package/dist/capture/environment-raw-producer.d.ts +55 -0
  28. package/dist/capture/environment-raw-producer.d.ts.map +1 -0
  29. package/dist/capture/environment-raw-producer.js +88 -0
  30. package/dist/capture/environment-raw-producer.js.map +1 -0
  31. package/dist/capture/export-jpeg.d.ts +12 -0
  32. package/dist/capture/export-jpeg.d.ts.map +1 -0
  33. package/dist/capture/export-jpeg.js +126 -0
  34. package/dist/capture/export-jpeg.js.map +1 -0
  35. package/dist/capture/export-tiff.d.ts +45 -0
  36. package/dist/capture/export-tiff.d.ts.map +1 -0
  37. package/dist/capture/export-tiff.js +129 -0
  38. package/dist/capture/export-tiff.js.map +1 -0
  39. package/dist/capture/focus-control.d.ts +210 -0
  40. package/dist/capture/focus-control.d.ts.map +1 -0
  41. package/dist/capture/focus-control.js +664 -0
  42. package/dist/capture/focus-control.js.map +1 -0
  43. package/dist/capture/linear-encoding.d.ts +59 -0
  44. package/dist/capture/linear-encoding.d.ts.map +1 -0
  45. package/dist/capture/linear-encoding.js +98 -0
  46. package/dist/capture/linear-encoding.js.map +1 -0
  47. package/dist/capture/photographic-export.d.ts +135 -0
  48. package/dist/capture/photographic-export.d.ts.map +1 -0
  49. package/dist/capture/photographic-export.js +273 -0
  50. package/dist/capture/photographic-export.js.map +1 -0
  51. package/dist/capture/raw-frame-limits.d.ts +12 -0
  52. package/dist/capture/raw-frame-limits.d.ts.map +1 -0
  53. package/dist/capture/raw-frame-limits.js +13 -0
  54. package/dist/capture/raw-frame-limits.js.map +1 -0
  55. package/dist/capture/raw-frame-reconstruction.d.ts +48 -0
  56. package/dist/capture/raw-frame-reconstruction.d.ts.map +1 -0
  57. package/dist/capture/raw-frame-reconstruction.js +146 -0
  58. package/dist/capture/raw-frame-reconstruction.js.map +1 -0
  59. package/dist/capture/release-sequence.d.ts +120 -0
  60. package/dist/capture/release-sequence.d.ts.map +1 -0
  61. package/dist/capture/release-sequence.js +446 -0
  62. package/dist/capture/release-sequence.js.map +1 -0
  63. package/dist/capture/sensor-raw-frame.d.ts +34 -0
  64. package/dist/capture/sensor-raw-frame.d.ts.map +1 -0
  65. package/dist/capture/sensor-raw-frame.js +106 -0
  66. package/dist/capture/sensor-raw-frame.js.map +1 -0
  67. package/dist/capture/sensor-raw-producer.d.ts +51 -0
  68. package/dist/capture/sensor-raw-producer.d.ts.map +1 -0
  69. package/dist/capture/sensor-raw-producer.js +235 -0
  70. package/dist/capture/sensor-raw-producer.js.map +1 -0
  71. package/dist/capture/simulated-capture.d.ts +125 -0
  72. package/dist/capture/simulated-capture.d.ts.map +1 -0
  73. package/dist/capture/simulated-capture.js +248 -0
  74. package/dist/capture/simulated-capture.js.map +1 -0
  75. package/dist/color/capture-color.d.ts +73 -0
  76. package/dist/color/capture-color.d.ts.map +1 -0
  77. package/dist/color/capture-color.js +145 -0
  78. package/dist/color/capture-color.js.map +1 -0
  79. package/dist/color/sensor-color-development.d.ts +23 -0
  80. package/dist/color/sensor-color-development.d.ts.map +1 -0
  81. package/dist/color/sensor-color-development.js +56 -0
  82. package/dist/color/sensor-color-development.js.map +1 -0
  83. package/dist/color/white-balance.d.ts +175 -0
  84. package/dist/color/white-balance.d.ts.map +1 -0
  85. package/dist/color/white-balance.js +606 -0
  86. package/dist/color/white-balance.js.map +1 -0
  87. package/dist/composition/image-formation-plan.d.ts +481 -0
  88. package/dist/composition/image-formation-plan.d.ts.map +1 -0
  89. package/dist/composition/image-formation-plan.js +2499 -0
  90. package/dist/composition/image-formation-plan.js.map +1 -0
  91. package/dist/composition/plan-consumer.d.ts +53 -0
  92. package/dist/composition/plan-consumer.d.ts.map +1 -0
  93. package/dist/composition/plan-consumer.js +119 -0
  94. package/dist/composition/plan-consumer.js.map +1 -0
  95. package/dist/core/calculation-result.d.ts.map +1 -1
  96. package/dist/core/calculation-result.js +6 -0
  97. package/dist/core/calculation-result.js.map +1 -1
  98. package/dist/core/canonical-json.d.ts +18 -0
  99. package/dist/core/canonical-json.d.ts.map +1 -0
  100. package/dist/core/canonical-json.js +44 -0
  101. package/dist/core/canonical-json.js.map +1 -0
  102. package/dist/core/configuration-error.d.ts +6 -0
  103. package/dist/core/configuration-error.d.ts.map +1 -1
  104. package/dist/core/configuration-error.js +6 -0
  105. package/dist/core/configuration-error.js.map +1 -1
  106. package/dist/core/evidence-provenance.d.ts +6 -0
  107. package/dist/core/evidence-provenance.d.ts.map +1 -1
  108. package/dist/core/evidence-provenance.js +7 -0
  109. package/dist/core/evidence-provenance.js.map +1 -1
  110. package/dist/core/image-formation.d.ts +9 -3
  111. package/dist/core/image-formation.d.ts.map +1 -1
  112. package/dist/core/image-formation.js +29 -5
  113. package/dist/core/image-formation.js.map +1 -1
  114. package/dist/core/owned-data.d.ts +25 -0
  115. package/dist/core/owned-data.d.ts.map +1 -0
  116. package/dist/core/owned-data.js +34 -0
  117. package/dist/core/owned-data.js.map +1 -0
  118. package/dist/core/record-validation.d.ts +17 -0
  119. package/dist/core/record-validation.d.ts.map +1 -0
  120. package/dist/core/record-validation.js +44 -0
  121. package/dist/core/record-validation.js.map +1 -0
  122. package/dist/core/scientific-assurance.d.ts +101 -0
  123. package/dist/core/scientific-assurance.d.ts.map +1 -0
  124. package/dist/core/scientific-assurance.js +301 -0
  125. package/dist/core/scientific-assurance.js.map +1 -0
  126. package/dist/core/spectral-composition.d.ts +106 -0
  127. package/dist/core/spectral-composition.d.ts.map +1 -0
  128. package/dist/core/spectral-composition.js +334 -0
  129. package/dist/core/spectral-composition.js.map +1 -0
  130. package/dist/core/spectral.d.ts +34 -0
  131. package/dist/core/spectral.d.ts.map +1 -0
  132. package/dist/core/spectral.js +57 -0
  133. package/dist/core/spectral.js.map +1 -0
  134. package/dist/core/validation.d.ts +6 -0
  135. package/dist/core/validation.d.ts.map +1 -1
  136. package/dist/core/validation.js +6 -0
  137. package/dist/core/validation.js.map +1 -1
  138. package/dist/core/version.d.ts +14 -0
  139. package/dist/core/version.d.ts.map +1 -0
  140. package/dist/core/version.js +15 -0
  141. package/dist/core/version.js.map +1 -0
  142. package/dist/equipment/exposure-capabilities.d.ts +125 -0
  143. package/dist/equipment/exposure-capabilities.d.ts.map +1 -0
  144. package/dist/equipment/exposure-capabilities.js +391 -0
  145. package/dist/equipment/exposure-capabilities.js.map +1 -0
  146. package/dist/equipment/generic-tier-assets.d.ts +82 -0
  147. package/dist/equipment/generic-tier-assets.d.ts.map +1 -0
  148. package/dist/equipment/generic-tier-assets.js +119 -0
  149. package/dist/equipment/generic-tier-assets.js.map +1 -0
  150. package/dist/equipment/generic-tier-presets.d.ts +57 -0
  151. package/dist/equipment/generic-tier-presets.d.ts.map +1 -0
  152. package/dist/equipment/generic-tier-presets.js +122 -0
  153. package/dist/equipment/generic-tier-presets.js.map +1 -0
  154. package/dist/equipment/iso-capabilities.d.ts +143 -0
  155. package/dist/equipment/iso-capabilities.d.ts.map +1 -0
  156. package/dist/equipment/iso-capabilities.js +578 -0
  157. package/dist/equipment/iso-capabilities.js.map +1 -0
  158. package/dist/equipment/metering-capabilities.d.ts +58 -0
  159. package/dist/equipment/metering-capabilities.d.ts.map +1 -0
  160. package/dist/equipment/metering-capabilities.js +151 -0
  161. package/dist/equipment/metering-capabilities.js.map +1 -0
  162. package/dist/equipment/release-capabilities.d.ts +33 -0
  163. package/dist/equipment/release-capabilities.d.ts.map +1 -0
  164. package/dist/equipment/release-capabilities.js +176 -0
  165. package/dist/equipment/release-capabilities.js.map +1 -0
  166. package/dist/exposure/exposure-duration-control.d.ts +72 -0
  167. package/dist/exposure/exposure-duration-control.d.ts.map +1 -0
  168. package/dist/exposure/exposure-duration-control.js +161 -0
  169. package/dist/exposure/exposure-duration-control.js.map +1 -0
  170. package/dist/exposure/exposure-mode-resolver.d.ts +637 -0
  171. package/dist/exposure/exposure-mode-resolver.d.ts.map +1 -0
  172. package/dist/exposure/exposure-mode-resolver.js +1905 -0
  173. package/dist/exposure/exposure-mode-resolver.js.map +1 -0
  174. package/dist/exposure/exposure.d.ts +8 -0
  175. package/dist/exposure/exposure.d.ts.map +1 -1
  176. package/dist/exposure/exposure.js +8 -0
  177. package/dist/exposure/exposure.js.map +1 -1
  178. package/dist/exposure/flash.d.ts +179 -0
  179. package/dist/exposure/flash.d.ts.map +1 -0
  180. package/dist/exposure/flash.js +644 -0
  181. package/dist/exposure/flash.js.map +1 -0
  182. package/dist/exposure/metering-scene-radiance.d.ts +72 -0
  183. package/dist/exposure/metering-scene-radiance.d.ts.map +1 -0
  184. package/dist/exposure/metering-scene-radiance.js +222 -0
  185. package/dist/exposure/metering-scene-radiance.js.map +1 -0
  186. package/dist/exposure/metering-target.d.ts +67 -0
  187. package/dist/exposure/metering-target.d.ts.map +1 -0
  188. package/dist/exposure/metering-target.js +265 -0
  189. package/dist/exposure/metering-target.js.map +1 -0
  190. package/dist/exposure/metering-temporal.d.ts +76 -0
  191. package/dist/exposure/metering-temporal.d.ts.map +1 -0
  192. package/dist/exposure/metering-temporal.js +210 -0
  193. package/dist/exposure/metering-temporal.js.map +1 -0
  194. package/dist/exposure/metering.d.ts +124 -0
  195. package/dist/exposure/metering.d.ts.map +1 -0
  196. package/dist/exposure/metering.js +422 -0
  197. package/dist/exposure/metering.js.map +1 -0
  198. package/dist/exposure/program-line.d.ts +29 -0
  199. package/dist/exposure/program-line.d.ts.map +1 -0
  200. package/dist/exposure/program-line.js +126 -0
  201. package/dist/exposure/program-line.js.map +1 -0
  202. package/dist/index.d.ts +101 -7
  203. package/dist/index.d.ts.map +1 -1
  204. package/dist/index.js +99 -7
  205. package/dist/index.js.map +1 -1
  206. package/dist/motion/camera-rotation.d.ts +76 -0
  207. package/dist/motion/camera-rotation.d.ts.map +1 -1
  208. package/dist/motion/camera-rotation.js +111 -0
  209. package/dist/motion/camera-rotation.js.map +1 -1
  210. package/dist/motion/capture-rotation-inverse-mapping.d.ts +113 -0
  211. package/dist/motion/capture-rotation-inverse-mapping.d.ts.map +1 -0
  212. package/dist/motion/capture-rotation-inverse-mapping.js +184 -0
  213. package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -0
  214. package/dist/motion/capture-rotation-temporal-quadrature.d.ts +104 -0
  215. package/dist/motion/capture-rotation-temporal-quadrature.d.ts.map +1 -0
  216. package/dist/motion/capture-rotation-temporal-quadrature.js +131 -0
  217. package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -0
  218. package/dist/motion/capture-rotation-trajectory.d.ts +113 -0
  219. package/dist/motion/capture-rotation-trajectory.d.ts.map +1 -0
  220. package/dist/motion/capture-rotation-trajectory.js +168 -0
  221. package/dist/motion/capture-rotation-trajectory.js.map +1 -0
  222. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +119 -0
  223. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts.map +1 -0
  224. package/dist/motion/capture-translation-parallax-temporal-quadrature.js +263 -0
  225. package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -0
  226. package/dist/motion/extended-object-projection.d.ts +175 -0
  227. package/dist/motion/extended-object-projection.d.ts.map +1 -0
  228. package/dist/motion/extended-object-projection.js +402 -0
  229. package/dist/motion/extended-object-projection.js.map +1 -0
  230. package/dist/motion/projected-motion.d.ts +11 -0
  231. package/dist/motion/projected-motion.d.ts.map +1 -1
  232. package/dist/motion/projected-motion.js +11 -0
  233. package/dist/motion/projected-motion.js.map +1 -1
  234. package/dist/optics/aperture.d.ts +9 -0
  235. package/dist/optics/aperture.d.ts.map +1 -1
  236. package/dist/optics/aperture.js +9 -0
  237. package/dist/optics/aperture.js.map +1 -1
  238. package/dist/optics/circle-of-confusion.d.ts +8 -0
  239. package/dist/optics/circle-of-confusion.d.ts.map +1 -1
  240. package/dist/optics/circle-of-confusion.js +8 -0
  241. package/dist/optics/circle-of-confusion.js.map +1 -1
  242. package/dist/optics/complex-pupil-psf.d.ts +128 -0
  243. package/dist/optics/complex-pupil-psf.d.ts.map +1 -0
  244. package/dist/optics/complex-pupil-psf.js +462 -0
  245. package/dist/optics/complex-pupil-psf.js.map +1 -0
  246. package/dist/optics/depth-of-field.d.ts +18 -0
  247. package/dist/optics/depth-of-field.d.ts.map +1 -1
  248. package/dist/optics/depth-of-field.js +29 -4
  249. package/dist/optics/depth-of-field.js.map +1 -1
  250. package/dist/optics/diffraction.d.ts +8 -0
  251. package/dist/optics/diffraction.d.ts.map +1 -1
  252. package/dist/optics/diffraction.js +8 -0
  253. package/dist/optics/diffraction.js.map +1 -1
  254. package/dist/optics/focus-breathing.d.ts +13 -0
  255. package/dist/optics/focus-breathing.d.ts.map +1 -1
  256. package/dist/optics/focus-breathing.js +13 -0
  257. package/dist/optics/focus-breathing.js.map +1 -1
  258. package/dist/optics/focus-state.d.ts +47 -0
  259. package/dist/optics/focus-state.d.ts.map +1 -0
  260. package/dist/optics/focus-state.js +78 -0
  261. package/dist/optics/focus-state.js.map +1 -0
  262. package/dist/optics/front-of-lens-filter.d.ts +114 -0
  263. package/dist/optics/front-of-lens-filter.d.ts.map +1 -0
  264. package/dist/optics/front-of-lens-filter.js +468 -0
  265. package/dist/optics/front-of-lens-filter.js.map +1 -0
  266. package/dist/optics/illumination-vignetting.d.ts +9 -0
  267. package/dist/optics/illumination-vignetting.d.ts.map +1 -1
  268. package/dist/optics/illumination-vignetting.js +9 -0
  269. package/dist/optics/illumination-vignetting.js.map +1 -1
  270. package/dist/optics/lateral-chromatic-aberration.d.ts +11 -0
  271. package/dist/optics/lateral-chromatic-aberration.d.ts.map +1 -1
  272. package/dist/optics/lateral-chromatic-aberration.js +23 -4
  273. package/dist/optics/lateral-chromatic-aberration.js.map +1 -1
  274. package/dist/optics/lens-psf-profile.d.ts +217 -0
  275. package/dist/optics/lens-psf-profile.d.ts.map +1 -0
  276. package/dist/optics/lens-psf-profile.js +823 -0
  277. package/dist/optics/lens-psf-profile.js.map +1 -0
  278. package/dist/optics/polygon-diffraction.d.ts +67 -0
  279. package/dist/optics/polygon-diffraction.d.ts.map +1 -0
  280. package/dist/optics/polygon-diffraction.js +145 -0
  281. package/dist/optics/polygon-diffraction.js.map +1 -0
  282. package/dist/optics/profile-contract.d.ts +42 -0
  283. package/dist/optics/profile-contract.d.ts.map +1 -0
  284. package/dist/optics/profile-contract.js +92 -0
  285. package/dist/optics/profile-contract.js.map +1 -0
  286. package/dist/optics/psf-foundation.d.ts +16 -3
  287. package/dist/optics/psf-foundation.d.ts.map +1 -1
  288. package/dist/optics/psf-foundation.js +28 -15
  289. package/dist/optics/psf-foundation.js.map +1 -1
  290. package/dist/optics/radial-distortion.d.ts +22 -2
  291. package/dist/optics/radial-distortion.d.ts.map +1 -1
  292. package/dist/optics/radial-distortion.js +101 -23
  293. package/dist/optics/radial-distortion.js.map +1 -1
  294. package/dist/optics/scene-to-sensor-irradiance.d.ts +213 -0
  295. package/dist/optics/scene-to-sensor-irradiance.d.ts.map +1 -0
  296. package/dist/optics/scene-to-sensor-irradiance.js +662 -0
  297. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -0
  298. package/dist/optics/scene-to-sensor-quadrature.d.ts +63 -0
  299. package/dist/optics/scene-to-sensor-quadrature.d.ts.map +1 -0
  300. package/dist/optics/scene-to-sensor-quadrature.js +82 -0
  301. package/dist/optics/scene-to-sensor-quadrature.js.map +1 -0
  302. package/dist/optics/sensor-environment-query.d.ts +60 -0
  303. package/dist/optics/sensor-environment-query.d.ts.map +1 -0
  304. package/dist/optics/sensor-environment-query.js +50 -0
  305. package/dist/optics/sensor-environment-query.js.map +1 -0
  306. package/dist/optics/sensor-psf-quadrature.d.ts +70 -0
  307. package/dist/optics/sensor-psf-quadrature.d.ts.map +1 -0
  308. package/dist/optics/sensor-psf-quadrature.js +101 -0
  309. package/dist/optics/sensor-psf-quadrature.js.map +1 -0
  310. package/dist/optics/sensor-psf-support.d.ts +20 -0
  311. package/dist/optics/sensor-psf-support.d.ts.map +1 -0
  312. package/dist/optics/sensor-psf-support.js +13 -0
  313. package/dist/optics/sensor-psf-support.js.map +1 -0
  314. package/dist/optics/stray-light.d.ts +91 -0
  315. package/dist/optics/stray-light.d.ts.map +1 -0
  316. package/dist/optics/stray-light.js +110 -0
  317. package/dist/optics/stray-light.js.map +1 -0
  318. package/dist/optics/thin-lens.d.ts +8 -0
  319. package/dist/optics/thin-lens.d.ts.map +1 -1
  320. package/dist/optics/thin-lens.js +8 -0
  321. package/dist/optics/thin-lens.js.map +1 -1
  322. package/dist/output/capture-corrected-sdr.d.ts +49 -0
  323. package/dist/output/capture-corrected-sdr.d.ts.map +1 -0
  324. package/dist/output/capture-corrected-sdr.js +149 -0
  325. package/dist/output/capture-corrected-sdr.js.map +1 -0
  326. package/dist/output/capture-geometry.d.ts.map +1 -1
  327. package/dist/output/capture-geometry.js +32 -11
  328. package/dist/output/capture-geometry.js.map +1 -1
  329. package/dist/output/capture-sdr.d.ts +49 -0
  330. package/dist/output/capture-sdr.d.ts.map +1 -0
  331. package/dist/output/capture-sdr.js +90 -0
  332. package/dist/output/capture-sdr.js.map +1 -0
  333. package/dist/output/crop.d.ts +6 -0
  334. package/dist/output/crop.d.ts.map +1 -1
  335. package/dist/output/crop.js +6 -0
  336. package/dist/output/crop.js.map +1 -1
  337. package/dist/output/geometric-transforms.d.ts +137 -0
  338. package/dist/output/geometric-transforms.d.ts.map +1 -0
  339. package/dist/output/geometric-transforms.js +225 -0
  340. package/dist/output/geometric-transforms.js.map +1 -0
  341. package/dist/output/lens-corrections.d.ts +121 -0
  342. package/dist/output/lens-corrections.d.ts.map +1 -0
  343. package/dist/output/lens-corrections.js +210 -0
  344. package/dist/output/lens-corrections.js.map +1 -0
  345. package/dist/output/sdr-rendering.d.ts +81 -0
  346. package/dist/output/sdr-rendering.d.ts.map +1 -0
  347. package/dist/output/sdr-rendering.js +106 -0
  348. package/dist/output/sdr-rendering.js.map +1 -0
  349. package/dist/output/subject-framing-crop.d.ts +8 -0
  350. package/dist/output/subject-framing-crop.d.ts.map +1 -1
  351. package/dist/output/subject-framing-crop.js +8 -0
  352. package/dist/output/subject-framing-crop.js.map +1 -1
  353. package/dist/schema/camera.d.ts +6 -0
  354. package/dist/schema/camera.d.ts.map +1 -1
  355. package/dist/schema/illumination-spectral.d.ts +51 -0
  356. package/dist/schema/illumination-spectral.d.ts.map +1 -0
  357. package/dist/schema/illumination-spectral.js +132 -0
  358. package/dist/schema/illumination-spectral.js.map +1 -0
  359. package/dist/schema/illumination-temporal.d.ts +156 -0
  360. package/dist/schema/illumination-temporal.d.ts.map +1 -0
  361. package/dist/schema/illumination-temporal.js +554 -0
  362. package/dist/schema/illumination-temporal.js.map +1 -0
  363. package/dist/schema/illumination.d.ts +138 -0
  364. package/dist/schema/illumination.d.ts.map +1 -0
  365. package/dist/schema/illumination.js +483 -0
  366. package/dist/schema/illumination.js.map +1 -0
  367. package/dist/schema/scene-radiance-temporal.d.ts +107 -0
  368. package/dist/schema/scene-radiance-temporal.d.ts.map +1 -0
  369. package/dist/schema/scene-radiance-temporal.js +259 -0
  370. package/dist/schema/scene-radiance-temporal.js.map +1 -0
  371. package/dist/schema/scene-radiance.d.ts +185 -0
  372. package/dist/schema/scene-radiance.d.ts.map +1 -0
  373. package/dist/schema/scene-radiance.js +535 -0
  374. package/dist/schema/scene-radiance.js.map +1 -0
  375. package/dist/schema/scene.d.ts +7 -0
  376. package/dist/schema/scene.d.ts.map +1 -1
  377. package/dist/schema/validation.d.ts.map +1 -1
  378. package/dist/schema/validation.js +7 -0
  379. package/dist/schema/validation.js.map +1 -1
  380. package/dist/sensor/accumulated-charge.d.ts +199 -0
  381. package/dist/sensor/accumulated-charge.d.ts.map +1 -0
  382. package/dist/sensor/accumulated-charge.js +450 -0
  383. package/dist/sensor/accumulated-charge.js.map +1 -0
  384. package/dist/sensor/architecture.d.ts +48 -13
  385. package/dist/sensor/architecture.d.ts.map +1 -1
  386. package/dist/sensor/architecture.js +58 -16
  387. package/dist/sensor/architecture.js.map +1 -1
  388. package/dist/sensor/camera-saturation-capacity.d.ts +138 -0
  389. package/dist/sensor/camera-saturation-capacity.d.ts.map +1 -0
  390. package/dist/sensor/camera-saturation-capacity.js +356 -0
  391. package/dist/sensor/camera-saturation-capacity.js.map +1 -0
  392. package/dist/sensor/capture-color-sampling-binding.d.ts +212 -0
  393. package/dist/sensor/capture-color-sampling-binding.d.ts.map +1 -0
  394. package/dist/sensor/capture-color-sampling-binding.js +437 -0
  395. package/dist/sensor/capture-color-sampling-binding.js.map +1 -0
  396. package/dist/sensor/capture-mode-timing.d.ts +63 -0
  397. package/dist/sensor/capture-mode-timing.d.ts.map +1 -0
  398. package/dist/sensor/capture-mode-timing.js +270 -0
  399. package/dist/sensor/capture-mode-timing.js.map +1 -0
  400. package/dist/sensor/capture-mode.d.ts +157 -0
  401. package/dist/sensor/capture-mode.d.ts.map +1 -0
  402. package/dist/sensor/capture-mode.js +447 -0
  403. package/dist/sensor/capture-mode.js.map +1 -0
  404. package/dist/sensor/color-sampling.d.ts +133 -0
  405. package/dist/sensor/color-sampling.d.ts.map +1 -0
  406. package/dist/sensor/color-sampling.js +245 -0
  407. package/dist/sensor/color-sampling.js.map +1 -0
  408. package/dist/sensor/constant-rate-temporal-integration.d.ts +126 -0
  409. package/dist/sensor/constant-rate-temporal-integration.d.ts.map +1 -0
  410. package/dist/sensor/constant-rate-temporal-integration.js +382 -0
  411. package/dist/sensor/constant-rate-temporal-integration.js.map +1 -0
  412. package/dist/sensor/dark-current.d.ts +169 -0
  413. package/dist/sensor/dark-current.d.ts.map +1 -0
  414. package/dist/sensor/dark-current.js +427 -0
  415. package/dist/sensor/dark-current.js.map +1 -0
  416. package/dist/sensor/environment-photo-signal.d.ts +123 -0
  417. package/dist/sensor/environment-photo-signal.d.ts.map +1 -0
  418. package/dist/sensor/environment-photo-signal.js +186 -0
  419. package/dist/sensor/environment-photo-signal.js.map +1 -0
  420. package/dist/sensor/eqe-electron-rate.d.ts +107 -0
  421. package/dist/sensor/eqe-electron-rate.d.ts.map +1 -0
  422. package/dist/sensor/eqe-electron-rate.js +561 -0
  423. package/dist/sensor/eqe-electron-rate.js.map +1 -0
  424. package/dist/sensor/eqe-local-exposure.d.ts +65 -0
  425. package/dist/sensor/eqe-local-exposure.d.ts.map +1 -0
  426. package/dist/sensor/eqe-local-exposure.js +84 -0
  427. package/dist/sensor/eqe-local-exposure.js.map +1 -0
  428. package/dist/sensor/eqe-temporal-exposure.d.ts +55 -0
  429. package/dist/sensor/eqe-temporal-exposure.d.ts.map +1 -0
  430. package/dist/sensor/eqe-temporal-exposure.js +62 -0
  431. package/dist/sensor/eqe-temporal-exposure.js.map +1 -0
  432. package/dist/sensor/exposure-window.d.ts +117 -0
  433. package/dist/sensor/exposure-window.d.ts.map +1 -0
  434. package/dist/sensor/exposure-window.js +305 -0
  435. package/dist/sensor/exposure-window.js.map +1 -0
  436. package/dist/sensor/iso-signal-chain.d.ts +148 -0
  437. package/dist/sensor/iso-signal-chain.d.ts.map +1 -0
  438. package/dist/sensor/iso-signal-chain.js +411 -0
  439. package/dist/sensor/iso-signal-chain.js.map +1 -0
  440. package/dist/sensor/local-exposure-binding.d.ts +87 -0
  441. package/dist/sensor/local-exposure-binding.d.ts.map +1 -0
  442. package/dist/sensor/local-exposure-binding.js +214 -0
  443. package/dist/sensor/local-exposure-binding.js.map +1 -0
  444. package/dist/sensor/optical-stack.d.ts +132 -0
  445. package/dist/sensor/optical-stack.d.ts.map +1 -0
  446. package/dist/sensor/optical-stack.js +303 -0
  447. package/dist/sensor/optical-stack.js.map +1 -0
  448. package/dist/sensor/photon-energy.d.ts +97 -0
  449. package/dist/sensor/photon-energy.d.ts.map +1 -0
  450. package/dist/sensor/photon-energy.js +390 -0
  451. package/dist/sensor/photon-energy.js.map +1 -0
  452. package/dist/sensor/physical-charge-capacity.d.ts +130 -0
  453. package/dist/sensor/physical-charge-capacity.d.ts.map +1 -0
  454. package/dist/sensor/physical-charge-capacity.js +345 -0
  455. package/dist/sensor/physical-charge-capacity.js.map +1 -0
  456. package/dist/sensor/pixel-pitch.d.ts +6 -0
  457. package/dist/sensor/pixel-pitch.d.ts.map +1 -1
  458. package/dist/sensor/pixel-pitch.js +6 -0
  459. package/dist/sensor/pixel-pitch.js.map +1 -1
  460. package/dist/sensor/radiometry-readiness.d.ts +10 -0
  461. package/dist/sensor/radiometry-readiness.d.ts.map +1 -1
  462. package/dist/sensor/radiometry-readiness.js +10 -0
  463. package/dist/sensor/radiometry-readiness.js.map +1 -1
  464. package/dist/sensor/raw-readout.d.ts +314 -0
  465. package/dist/sensor/raw-readout.d.ts.map +1 -0
  466. package/dist/sensor/raw-readout.js +914 -0
  467. package/dist/sensor/raw-readout.js.map +1 -0
  468. package/dist/sensor/raw-reconstruction.d.ts +170 -0
  469. package/dist/sensor/raw-reconstruction.d.ts.map +1 -0
  470. package/dist/sensor/raw-reconstruction.js +424 -0
  471. package/dist/sensor/raw-reconstruction.js.map +1 -0
  472. package/dist/sensor/readout-exposure-linkage.d.ts +123 -0
  473. package/dist/sensor/readout-exposure-linkage.d.ts.map +1 -0
  474. package/dist/sensor/readout-exposure-linkage.js +222 -0
  475. package/dist/sensor/readout-exposure-linkage.js.map +1 -0
  476. package/dist/sensor/readout-timing.d.ts +137 -0
  477. package/dist/sensor/readout-timing.d.ts.map +1 -0
  478. package/dist/sensor/readout-timing.js +243 -0
  479. package/dist/sensor/readout-timing.js.map +1 -0
  480. package/dist/sensor/response-application-compatibility.d.ts +136 -0
  481. package/dist/sensor/response-application-compatibility.d.ts.map +1 -0
  482. package/dist/sensor/response-application-compatibility.js +408 -0
  483. package/dist/sensor/response-application-compatibility.js.map +1 -0
  484. package/dist/sensor/response-operating-range.d.ts +173 -0
  485. package/dist/sensor/response-operating-range.d.ts.map +1 -0
  486. package/dist/sensor/response-operating-range.js +672 -0
  487. package/dist/sensor/response-operating-range.js.map +1 -0
  488. package/dist/sensor/responsivity-photocurrent.d.ts +158 -0
  489. package/dist/sensor/responsivity-photocurrent.d.ts.map +1 -0
  490. package/dist/sensor/responsivity-photocurrent.js +644 -0
  491. package/dist/sensor/responsivity-photocurrent.js.map +1 -0
  492. package/dist/sensor/sampling-aperture.d.ts +154 -0
  493. package/dist/sensor/sampling-aperture.d.ts.map +1 -0
  494. package/dist/sensor/sampling-aperture.js +388 -0
  495. package/dist/sensor/sampling-aperture.js.map +1 -0
  496. package/dist/sensor/scene-eqe-temporal-exposure.d.ts +45 -0
  497. package/dist/sensor/scene-eqe-temporal-exposure.d.ts.map +1 -0
  498. package/dist/sensor/scene-eqe-temporal-exposure.js +64 -0
  499. package/dist/sensor/scene-eqe-temporal-exposure.js.map +1 -0
  500. package/dist/sensor/sensor-geometry.d.ts +12 -0
  501. package/dist/sensor/sensor-geometry.d.ts.map +1 -1
  502. package/dist/sensor/sensor-geometry.js +12 -0
  503. package/dist/sensor/sensor-geometry.js.map +1 -1
  504. package/dist/sensor/signal-noise.d.ts +10 -0
  505. package/dist/sensor/signal-noise.d.ts.map +1 -1
  506. package/dist/sensor/signal-noise.js +10 -0
  507. package/dist/sensor/signal-noise.js.map +1 -1
  508. package/dist/sensor/spatial-sample-reduction.d.ts +171 -0
  509. package/dist/sensor/spatial-sample-reduction.d.ts.map +1 -0
  510. package/dist/sensor/spatial-sample-reduction.js +345 -0
  511. package/dist/sensor/spatial-sample-reduction.js.map +1 -0
  512. package/dist/sensor/spatial-sampling-quadrature.d.ts +179 -0
  513. package/dist/sensor/spatial-sampling-quadrature.d.ts.map +1 -0
  514. package/dist/sensor/spatial-sampling-quadrature.js +224 -0
  515. package/dist/sensor/spatial-sampling-quadrature.js.map +1 -0
  516. package/dist/sensor/spatio-spectral-reduction.d.ts +187 -0
  517. package/dist/sensor/spatio-spectral-reduction.d.ts.map +1 -0
  518. package/dist/sensor/spatio-spectral-reduction.js +373 -0
  519. package/dist/sensor/spatio-spectral-reduction.js.map +1 -0
  520. package/dist/sensor/spectral-coverage.d.ts +24 -0
  521. package/dist/sensor/spectral-coverage.d.ts.map +1 -0
  522. package/dist/sensor/spectral-coverage.js +86 -0
  523. package/dist/sensor/spectral-coverage.js.map +1 -0
  524. package/dist/sensor/spectral-quadrature.d.ts +169 -0
  525. package/dist/sensor/spectral-quadrature.d.ts.map +1 -0
  526. package/dist/sensor/spectral-quadrature.js +542 -0
  527. package/dist/sensor/spectral-quadrature.js.map +1 -0
  528. package/dist/sensor/spectral-response.d.ts +192 -0
  529. package/dist/sensor/spectral-response.d.ts.map +1 -0
  530. package/dist/sensor/spectral-response.js +664 -0
  531. package/dist/sensor/spectral-response.js.map +1 -0
  532. package/dist/sensor/temporal-eqe-sum.d.ts +15 -0
  533. package/dist/sensor/temporal-eqe-sum.d.ts.map +1 -0
  534. package/dist/sensor/temporal-eqe-sum.js +30 -0
  535. package/dist/sensor/temporal-eqe-sum.js.map +1 -0
  536. package/dist/sensor/temporal-photo-signal.d.ts +38 -0
  537. package/dist/sensor/temporal-photo-signal.d.ts.map +1 -0
  538. package/dist/sensor/temporal-photo-signal.js +110 -0
  539. package/dist/sensor/temporal-photo-signal.js.map +1 -0
  540. package/dist/sensor/temporal-sample-binding.d.ts +6 -0
  541. package/dist/sensor/temporal-sample-binding.d.ts.map +1 -0
  542. package/dist/sensor/temporal-sample-binding.js +32 -0
  543. package/dist/sensor/temporal-sample-binding.js.map +1 -0
  544. package/dist/simulation/poc-simulation.d.ts.map +1 -1
  545. package/dist/simulation/poc-simulation.js +34 -11
  546. package/dist/simulation/poc-simulation.js.map +1 -1
  547. package/dist/stabilization/camera-shake.d.ts +11 -0
  548. package/dist/stabilization/camera-shake.d.ts.map +1 -1
  549. package/dist/stabilization/camera-shake.js +11 -0
  550. package/dist/stabilization/camera-shake.js.map +1 -1
  551. package/dist/stabilization/system.d.ts +218 -0
  552. package/dist/stabilization/system.d.ts.map +1 -0
  553. package/dist/stabilization/system.js +695 -0
  554. package/dist/stabilization/system.js.map +1 -0
  555. package/docs/API_REFERENCE.md +2017 -0
  556. package/docs/API_STYLE.md +132 -0
  557. package/docs/ARCHITECTURE.md +150 -23
  558. package/docs/AUTOMATION_COORDINATION.md +190 -0
  559. package/docs/CAPTURE_COLOR.md +25 -0
  560. package/docs/CAPTURE_CORRECTED_SDR.md +25 -0
  561. package/docs/CAPTURE_EXPORT_METADATA.md +27 -0
  562. package/docs/CAPTURE_SDR.md +20 -0
  563. package/docs/DEVELOPERS.md +60 -0
  564. package/docs/DIGITAL_OPTICS_FOUNDATION.md +69 -0
  565. package/docs/ENVIRONMENT_RAW_CAPTURE.md +187 -0
  566. package/docs/EXPORT_ACCEPTANCE.md +133 -0
  567. package/docs/GENERIC_TIER_PRESETS.md +269 -0
  568. package/docs/GEOMETRIC_PREPARATION_REUSE.md +141 -0
  569. package/docs/IMAGE_FORMATION.md +105 -9
  570. package/docs/LINEAR_CAPTURE_ENCODING.md +25 -0
  571. package/docs/MOTION_AND_SIGNAL.md +145 -1
  572. package/docs/NUMERICAL_CORRECTNESS.md +191 -0
  573. package/docs/PERFORMANCE_BASELINE.md +56 -0
  574. package/docs/PHOTOGRAPHIC_EXPORT.md +206 -0
  575. package/docs/PHYSICS_FOUNDATION.md +152 -5
  576. package/docs/POC_API.md +2 -0
  577. package/docs/POC_PROJECTION_REUSE.md +124 -0
  578. package/docs/PROCESSED_OUTPUT.md +157 -0
  579. package/docs/PRODUCTION_COMPOSITION.md +373 -0
  580. package/docs/PRODUCTION_ENVIRONMENT_CAPTURE.md +131 -0
  581. package/docs/PROVENANCE.md +4 -0
  582. package/docs/PSF_FOUNDATION.md +110 -88
  583. package/docs/RAW_FRAME_ENVELOPE.md +56 -0
  584. package/docs/RAW_FRAME_RECONSTRUCTION.md +30 -0
  585. package/docs/RELEASE_1_0.md +65 -0
  586. package/docs/RELEASE_AUDIT.md +38 -0
  587. package/docs/SCENE_RADIANCE_AND_ILLUMINATION.md +298 -0
  588. package/docs/SCENE_SENSOR_QUADRATURE.md +98 -0
  589. package/docs/SCENE_SENSOR_TEMPORAL_EXPOSURE.md +86 -0
  590. package/docs/SCIENTIFIC_ASSURANCE.md +280 -0
  591. package/docs/SCIENTIFIC_CONFORMANCE.md +83 -0
  592. package/docs/SDR_RENDERING.md +33 -0
  593. package/docs/SENSOR_ENVIRONMENT_QUERY.md +86 -0
  594. package/docs/SENSOR_EQE_LOCAL_EXPOSURE.md +104 -0
  595. package/docs/SENSOR_EQE_TEMPORAL_EXPOSURE.md +74 -0
  596. package/docs/SENSOR_PSF_QUADRATURE.md +90 -0
  597. package/docs/SENSOR_RAW_FRAME.md +20 -0
  598. package/docs/SENSOR_RAW_PRODUCER.md +77 -0
  599. package/docs/SIGNAL_CONFORMANCE.md +23 -0
  600. package/docs/SIMULATED_CAPTURE.md +65 -0
  601. package/docs/STABILIZATION.md +160 -17
  602. package/docs/TEMPORAL_PHOTO_RAW.md +83 -0
  603. package/docs/TIER_ACCEPTANCE.md +129 -0
  604. package/docs/TIER_PRESET_ACCEPTANCE.md +59 -0
  605. package/docs/USAGE.md +5604 -331
  606. package/docs/V1_COMPOSITION_MAP.md +123 -0
  607. package/docs/V1_HELPER_REUSE_REVIEW.md +60 -0
  608. package/docs/V1_PERFORMANCE_DISPOSITION.md +88 -0
  609. package/docs/api/camera-equivalent-focal-length.md +53 -0
  610. package/docs/api/camera-field-of-view.md +119 -0
  611. package/docs/api/camera-projected-object-size.md +54 -0
  612. package/docs/api/capture-capture-export-metadata.md +107 -0
  613. package/docs/api/capture-environment-raw-producer.md +56 -0
  614. package/docs/api/capture-focus-control.md +419 -0
  615. package/docs/api/capture-linear-encoding.md +99 -0
  616. package/docs/api/capture-photographic-export.md +172 -0
  617. package/docs/api/capture-raw-frame-reconstruction.md +87 -0
  618. package/docs/api/capture-release-sequence.md +252 -0
  619. package/docs/api/capture-sensor-raw-frame.md +66 -0
  620. package/docs/api/capture-sensor-raw-producer.md +98 -0
  621. package/docs/api/capture-simulated-capture.md +179 -0
  622. package/docs/api/color-capture-color.md +122 -0
  623. package/docs/api/color-white-balance.md +386 -0
  624. package/docs/api/composition-image-formation-plan.md +825 -0
  625. package/docs/api/composition-plan-consumer.md +98 -0
  626. package/docs/api/core-calculation-result.md +220 -0
  627. package/docs/api/core-configuration-error.md +19 -0
  628. package/docs/api/core-image-formation.md +204 -0
  629. package/docs/api/core-scientific-assurance.md +214 -0
  630. package/docs/api/core-spectral-composition.md +268 -0
  631. package/docs/api/core-spectral.md +78 -0
  632. package/docs/api/core-validation.md +34 -0
  633. package/docs/api/core-version.md +14 -0
  634. package/docs/api/equipment-exposure-capabilities.md +270 -0
  635. package/docs/api/equipment-generic-tier-assets.md +82 -0
  636. package/docs/api/equipment-generic-tier-presets.md +103 -0
  637. package/docs/api/equipment-iso-capabilities.md +295 -0
  638. package/docs/api/equipment-metering-capabilities.md +126 -0
  639. package/docs/api/equipment-release-capabilities.md +91 -0
  640. package/docs/api/exports.json +5656 -0
  641. package/docs/api/exposure-exposure-duration-control.md +115 -0
  642. package/docs/api/exposure-exposure-mode-resolver.md +966 -0
  643. package/docs/api/exposure-exposure.md +150 -0
  644. package/docs/api/exposure-flash.md +327 -0
  645. package/docs/api/exposure-metering-scene-radiance.md +154 -0
  646. package/docs/api/exposure-metering-target.md +134 -0
  647. package/docs/api/exposure-metering-temporal.md +77 -0
  648. package/docs/api/exposure-metering.md +172 -0
  649. package/docs/api/exposure-program-line.md +64 -0
  650. package/docs/api/motion-camera-rotation.md +215 -0
  651. package/docs/api/motion-capture-rotation-inverse-mapping.md +128 -0
  652. package/docs/api/motion-capture-rotation-temporal-quadrature.md +127 -0
  653. package/docs/api/motion-capture-rotation-trajectory.md +132 -0
  654. package/docs/api/motion-capture-translation-parallax-temporal-quadrature.md +171 -0
  655. package/docs/api/motion-extended-object-projection.md +312 -0
  656. package/docs/api/motion-projected-motion.md +60 -0
  657. package/docs/api/optics-aperture.md +69 -0
  658. package/docs/api/optics-circle-of-confusion.md +46 -0
  659. package/docs/api/optics-complex-pupil-psf.md +193 -0
  660. package/docs/api/optics-depth-of-field.md +92 -0
  661. package/docs/api/optics-diffraction.md +46 -0
  662. package/docs/api/optics-focus-breathing.md +119 -0
  663. package/docs/api/optics-focus-state.md +64 -0
  664. package/docs/api/optics-front-of-lens-filter.md +263 -0
  665. package/docs/api/optics-illumination-vignetting.md +95 -0
  666. package/docs/api/optics-lateral-chromatic-aberration.md +225 -0
  667. package/docs/api/optics-lens-psf-profile.md +380 -0
  668. package/docs/api/optics-polygon-diffraction.md +68 -0
  669. package/docs/api/optics-profile-contract.md +47 -0
  670. package/docs/api/optics-psf-foundation.md +181 -0
  671. package/docs/api/optics-radial-distortion.md +194 -0
  672. package/docs/api/optics-scene-to-sensor-irradiance.md +371 -0
  673. package/docs/api/optics-scene-to-sensor-quadrature.md +78 -0
  674. package/docs/api/optics-sensor-environment-query.md +58 -0
  675. package/docs/api/optics-sensor-psf-quadrature.md +81 -0
  676. package/docs/api/optics-stray-light.md +109 -0
  677. package/docs/api/optics-thin-lens.md +53 -0
  678. package/docs/api/output-capture-corrected-sdr.md +71 -0
  679. package/docs/api/output-capture-geometry.md +500 -0
  680. package/docs/api/output-capture-sdr.md +69 -0
  681. package/docs/api/output-crop.md +47 -0
  682. package/docs/api/output-geometric-transforms.md +199 -0
  683. package/docs/api/output-lens-corrections.md +162 -0
  684. package/docs/api/output-sdr-rendering.md +122 -0
  685. package/docs/api/output-subject-framing-crop.md +59 -0
  686. package/docs/api/schema-camera.md +84 -0
  687. package/docs/api/schema-illumination-spectral.md +77 -0
  688. package/docs/api/schema-illumination-temporal.md +289 -0
  689. package/docs/api/schema-illumination.md +246 -0
  690. package/docs/api/schema-scene-radiance-temporal.md +215 -0
  691. package/docs/api/schema-scene-radiance.md +415 -0
  692. package/docs/api/schema-scene.md +105 -0
  693. package/docs/api/schema-validation.md +25 -0
  694. package/docs/api/sensor-accumulated-charge.md +273 -0
  695. package/docs/api/sensor-architecture.md +155 -0
  696. package/docs/api/sensor-camera-saturation-capacity.md +215 -0
  697. package/docs/api/sensor-capture-color-sampling-binding.md +323 -0
  698. package/docs/api/sensor-capture-mode-timing.md +123 -0
  699. package/docs/api/sensor-capture-mode.md +321 -0
  700. package/docs/api/sensor-color-sampling.md +228 -0
  701. package/docs/api/sensor-constant-rate-temporal-integration.md +152 -0
  702. package/docs/api/sensor-dark-current.md +227 -0
  703. package/docs/api/sensor-environment-photo-signal.md +77 -0
  704. package/docs/api/sensor-eqe-electron-rate.md +166 -0
  705. package/docs/api/sensor-eqe-local-exposure.md +68 -0
  706. package/docs/api/sensor-eqe-temporal-exposure.md +73 -0
  707. package/docs/api/sensor-exposure-window.md +183 -0
  708. package/docs/api/sensor-iso-signal-chain.md +264 -0
  709. package/docs/api/sensor-local-exposure-binding.md +126 -0
  710. package/docs/api/sensor-optical-stack.md +211 -0
  711. package/docs/api/sensor-photon-energy.md +149 -0
  712. package/docs/api/sensor-physical-charge-capacity.md +196 -0
  713. package/docs/api/sensor-pixel-pitch.md +41 -0
  714. package/docs/api/sensor-radiometry-readiness.md +240 -0
  715. package/docs/api/sensor-raw-readout.md +499 -0
  716. package/docs/api/sensor-raw-reconstruction.md +260 -0
  717. package/docs/api/sensor-readout-exposure-linkage.md +172 -0
  718. package/docs/api/sensor-readout-timing.md +209 -0
  719. package/docs/api/sensor-response-application-compatibility.md +256 -0
  720. package/docs/api/sensor-response-operating-range.md +293 -0
  721. package/docs/api/sensor-responsivity-photocurrent.md +245 -0
  722. package/docs/api/sensor-sampling-aperture.md +221 -0
  723. package/docs/api/sensor-scene-eqe-temporal-exposure.md +56 -0
  724. package/docs/api/sensor-sensor-geometry.md +143 -0
  725. package/docs/api/sensor-signal-noise.md +75 -0
  726. package/docs/api/sensor-spatial-sample-reduction.md +186 -0
  727. package/docs/api/sensor-spatial-sampling-quadrature.md +188 -0
  728. package/docs/api/sensor-spatio-spectral-reduction.md +217 -0
  729. package/docs/api/sensor-spectral-coverage.md +33 -0
  730. package/docs/api/sensor-spectral-quadrature.md +183 -0
  731. package/docs/api/sensor-spectral-response.md +291 -0
  732. package/docs/api/sensor-temporal-photo-signal.md +62 -0
  733. package/docs/api/simulation-poc-simulation.md +364 -0
  734. package/docs/api/stabilization-camera-shake.md +71 -0
  735. package/docs/api/stabilization-system.md +442 -0
  736. package/docs/benchmarks/2026-10-01-main-baseline.json +694 -0
  737. package/docs/benchmarks/2026-10-02-geometric-preparation-reuse.json +2190 -0
  738. package/docs/benchmarks/2026-10-02-poc-projection-reuse.json +2423 -0
  739. package/docs/benchmarks/2026-10-02-v1-environment-gc-profile.json +210 -0
  740. package/docs/benchmarks/2026-10-02-v1-environment-ordinary.json +187 -0
  741. package/docs/benchmarks/2026-10-02-v1-geometry-gc-profile.json +756 -0
  742. package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-1.json +711 -0
  743. package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-2.json +711 -0
  744. package/docs/benchmarks/2026-10-02-v1-poc-gc-profile.json +885 -0
  745. package/docs/benchmarks/2026-10-02-v1-poc-ordinary-1.json +868 -0
  746. package/docs/benchmarks/2026-10-02-v1-poc-ordinary-2.json +868 -0
  747. package/docs/examples/production-capture.mjs +34 -0
  748. package/docs/examples/production-request.json +4613 -0
  749. package/docs/examples/quick-start.mjs +12 -0
  750. package/docs/validation/documentation-fragments.json +212 -0
  751. package/docs/validation/release-audit-inventory.json +1306 -0
  752. package/docs/validation/tier-acceptance-report-v1.json +2538 -0
  753. package/package.json +18 -4
@@ -0,0 +1,2499 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * Module boundary and integration notes.
4
+ * Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
5
+ * missing required fields and incompatible scientific data fail at this boundary. The planner owns
6
+ * scientific stage ordering, immutable capture identity and reproducibility. Well-formed unsupported
7
+ * combinations produce structured blockers; malformed declarations throw. The bounded environment
8
+ * route executes supplied radiance through native RAW and optional output, while sample-only and
9
+ * attached-RAW routes retain missing upstream blockers. FNV fingerprints are reproducibility keys, not
10
+ * cryptographic integrity proofs.
11
+ * Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
12
+ * missing required fields and incompatible scientific data fail at this boundary. The planner owns
13
+ * scientific stage ordering, immutable capture identity and reproducibility. Well-formed unsupported
14
+ * combinations produce structured blockers; malformed declarations throw. The bounded environment
15
+ * route executes supplied radiance through native RAW and optional output, while sample-only and
16
+ * attached-RAW routes retain missing upstream blockers. FNV fingerprints are reproducibility keys, not
17
+ * cryptographic integrity proofs.
18
+ * @see docs/PRODUCTION_ENVIRONMENT_CAPTURE.md for equations, coordinate/unit conventions, blockers and
19
+ * support limits.
20
+ */
21
+ import { simulateEnvironmentSensorRawFrame } from "../capture/environment-raw-producer.js";
22
+ import { parseSimulatedCapture } from "../capture/simulated-capture.js";
23
+ import { calculateProcessedSensorRaw, validateProcessedSensorRawEnvelope } from "../capture/photographic-export.js";
24
+ import { stringifyCanonicalJson } from "../core/canonical-json.js";
25
+ import { RELEASE_SEQUENCE_VERSION } from "../capture/release-sequence.js";
26
+ import { parseResolvedWhiteBalanceState } from "../color/white-balance.js";
27
+ import { InvalidConfigurationError } from "../core/configuration-error.js";
28
+ import { getImageFormationContract, IMAGE_FORMATION_CONTRACT_VERSION } from "../core/image-formation.js";
29
+ import { ENGINE_API_VERSION } from "../core/version.js";
30
+ import { SCIENTIFIC_ASSURANCE_CONTRACT_VERSION, composeScientificAssurance } from "../core/scientific-assurance.js";
31
+ import { InvalidScientificInputError } from "../core/validation.js";
32
+ import { calculateCaptureRotationTemporalQuadrature } from "../motion/capture-rotation-temporal-quadrature.js";
33
+ import { calculateCaptureExposureWindows } from "../sensor/exposure-window.js";
34
+ import { calculateSensorReadoutTiming } from "../sensor/readout-timing.js";
35
+ import { GENERIC_EQUIPMENT_EXPOSURE_CAPABILITY_SCHEMA_VERSION } from "../equipment/exposure-capabilities.js";
36
+ import { parseFrontOfLensFilterProfile, resolveFrontOfLensFilterTransmission } from "../optics/front-of-lens-filter.js";
37
+ import { parseFocusPlane } from "../optics/focus-state.js";
38
+ import { calculateSceneRadianceToSensorIrradiance, parseSceneToSensorIrradianceProfile } from "../optics/scene-to-sensor-irradiance.js";
39
+ import { parseSceneRadianceEvaluationRequest, parseSceneRadianceEvaluationResult } from "../schema/scene-radiance.js";
40
+ export const PRODUCTION_IMAGE_FORMATION_PLAN_VERSION = "0.7.0";
41
+ export const PREPARED_IMAGE_FORMATION_CONTEXT_VERSION = "0.1.0";
42
+ export const PRODUCTION_CAPTURE_SNAPSHOT_VERSION = "0.3.0";
43
+ export const RENDERER_CAPABILITY_SCHEMA_VERSION = "0.1.0";
44
+ export const IMAGE_FORMATION_FIDELITY_PROFILE_SCHEMA_VERSION = "0.1.0";
45
+ const PROCESSED_OUTPUT_STAGES = new Set([
46
+ "reconstruction", "physical-orientation-transform", "output-crop-resample", "display-processing"
47
+ ]);
48
+ const COMPOSER_SUPPORTED_STAGES = new Set([
49
+ "scene-ray-projection",
50
+ "scene-radiance-evaluation",
51
+ "lens-field-pupil-evaluation",
52
+ "temporal-exposure-readout"
53
+ ]);
54
+ const COMPOSER_SUPPORTED_EFFECTS = new Set([
55
+ "illumination-vignetting",
56
+ "spatial-camera-rotation",
57
+ "rolling-readout"
58
+ ]);
59
+ function requireRecord(value, path) {
60
+ if (typeof value !== "object" ||
61
+ value === null ||
62
+ Array.isArray(value)) {
63
+ throw new InvalidConfigurationError(path + " must be an object.");
64
+ }
65
+ return value;
66
+ }
67
+ function requireNonEmptyString(value, path) {
68
+ if (typeof value !== "string" ||
69
+ value.trim().length === 0) {
70
+ throw new InvalidConfigurationError(path + " must be a non-empty string.");
71
+ }
72
+ return value.trim();
73
+ }
74
+ function requireFinite(value, path) {
75
+ if (typeof value !== "number" ||
76
+ !Number.isFinite(value)) {
77
+ throw new InvalidConfigurationError(path + " must be finite.");
78
+ }
79
+ return value;
80
+ }
81
+ function requirePositiveFinite(value, path) {
82
+ const parsed = requireFinite(value, path);
83
+ if (parsed <= 0) {
84
+ throw new InvalidConfigurationError(path +
85
+ " must be greater than zero.");
86
+ }
87
+ return parsed;
88
+ }
89
+ function requireUint32(value, path) {
90
+ if (typeof value !== "number" ||
91
+ !Number.isSafeInteger(value) ||
92
+ value < 0 ||
93
+ value > 0xffff_ffff) {
94
+ throw new InvalidConfigurationError(path +
95
+ " must be an unsigned 32-bit integer.");
96
+ }
97
+ return value;
98
+ }
99
+ function contractStageIds() {
100
+ return new Set(getImageFormationContract()
101
+ .stages.map((stage) => stage.id));
102
+ }
103
+ function contractEffectIds() {
104
+ return new Set(getImageFormationContract()
105
+ .effectPlacements.map((effect) => effect.id));
106
+ }
107
+ function parseUniqueStageIds(value, path) {
108
+ if (!Array.isArray(value)) {
109
+ throw new InvalidConfigurationError(path + " must be an array.");
110
+ }
111
+ const valid = contractStageIds();
112
+ const seen = new Set();
113
+ value.forEach((entry, index) => {
114
+ if (typeof entry !== "string" ||
115
+ !valid.has(entry)) {
116
+ throw new InvalidConfigurationError(path +
117
+ "[" +
118
+ index +
119
+ "] is not a declared image-formation stage.");
120
+ }
121
+ const typed = entry;
122
+ if (seen.has(typed)) {
123
+ throw new InvalidConfigurationError(path +
124
+ " must not contain duplicate stage IDs.");
125
+ }
126
+ seen.add(typed);
127
+ });
128
+ return getImageFormationContract()
129
+ .stages
130
+ .map((stage) => stage.id)
131
+ .filter((stageId) => seen.has(stageId));
132
+ }
133
+ function parseUniqueEffectIds(value, path) {
134
+ if (!Array.isArray(value)) {
135
+ throw new InvalidConfigurationError(path + " must be an array.");
136
+ }
137
+ const valid = contractEffectIds();
138
+ const seen = new Set();
139
+ value.forEach((entry, index) => {
140
+ if (typeof entry !== "string" ||
141
+ !valid.has(entry)) {
142
+ throw new InvalidConfigurationError(path +
143
+ "[" +
144
+ index +
145
+ "] is not a declared image-formation effect.");
146
+ }
147
+ const typed = entry;
148
+ if (seen.has(typed)) {
149
+ throw new InvalidConfigurationError(path +
150
+ " must not contain duplicate effect IDs.");
151
+ }
152
+ seen.add(typed);
153
+ });
154
+ return getImageFormationContract()
155
+ .effectPlacements
156
+ .map((effect) => effect.id)
157
+ .filter((effectId) => seen.has(effectId));
158
+ }
159
+ /**
160
+ * Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
161
+ * missing required fields and incompatible scientific data fail at this boundary.
162
+ *
163
+ * The planner owns scientific stage ordering, immutable capture identity and reproducibility.
164
+ * Well-formed unsupported combinations produce structured blockers; malformed declarations throw. The
165
+ * bounded environment route executes supplied radiance through native RAW and optional output, while
166
+ * sample-only and attached-RAW routes retain missing upstream blockers. FNV fingerprints are
167
+ * reproducibility keys, not cryptographic integrity proofs.
168
+ * @param value - unknown. Treated as untrusted data; static typing alone is not validation.
169
+ * @returns RendererCapabilityDeclaration. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
170
+ *
171
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
172
+ */
173
+ export function parseRendererCapabilityDeclaration(value) {
174
+ const record = requireRecord(value, "rendererCapability");
175
+ if (record.schemaVersion !==
176
+ RENDERER_CAPABILITY_SCHEMA_VERSION) {
177
+ throw new InvalidConfigurationError('rendererCapability.schemaVersion must be "' +
178
+ RENDERER_CAPABILITY_SCHEMA_VERSION +
179
+ '".');
180
+ }
181
+ const consumerKind = record.consumerKind;
182
+ if (consumerKind !==
183
+ "interactive-optimized" &&
184
+ consumerKind !== "reference") {
185
+ throw new InvalidConfigurationError("rendererCapability.consumerKind is invalid.");
186
+ }
187
+ const spectralCapability = record.spectralCapability;
188
+ if (spectralCapability !==
189
+ "wavelength-resolved" &&
190
+ spectralCapability !==
191
+ "wavelength-independent-approximation") {
192
+ throw new InvalidConfigurationError("rendererCapability.spectralCapability is invalid.");
193
+ }
194
+ const temporal = requireRecord(record.temporalSampling, "rendererCapability.temporalSampling");
195
+ let temporalSampling;
196
+ if (temporal.kind === "none") {
197
+ temporalSampling = {
198
+ kind: "none"
199
+ };
200
+ }
201
+ else if (temporal.kind === "bounded") {
202
+ const maximumSamples = temporal.maximumSamples;
203
+ if (typeof maximumSamples !==
204
+ "number" ||
205
+ !Number.isSafeInteger(maximumSamples) ||
206
+ maximumSamples <= 0) {
207
+ throw new InvalidConfigurationError("rendererCapability.temporalSampling.maximumSamples must be a positive safe integer.");
208
+ }
209
+ temporalSampling = {
210
+ kind: "bounded",
211
+ maximumSamples
212
+ };
213
+ }
214
+ else {
215
+ throw new InvalidConfigurationError("rendererCapability.temporalSampling.kind is invalid.");
216
+ }
217
+ const depthCapability = record.depthCapability;
218
+ if (depthCapability !== "none" &&
219
+ depthCapability !== "per-layer") {
220
+ throw new InvalidConfigurationError("rendererCapability.depthCapability is invalid.");
221
+ }
222
+ const alphaRepresentation = record.alphaRepresentation;
223
+ if (alphaRepresentation !==
224
+ "premultiplied" &&
225
+ alphaRepresentation !==
226
+ "straight") {
227
+ throw new InvalidConfigurationError("rendererCapability.alphaRepresentation is invalid.");
228
+ }
229
+ for (const [key, raw] of [
230
+ [
231
+ "inverseFieldMapping",
232
+ record.inverseFieldMapping
233
+ ],
234
+ [
235
+ "preservesDepthOrderAcrossWarps",
236
+ record
237
+ .preservesDepthOrderAcrossWarps
238
+ ],
239
+ [
240
+ "sensorDomainProcessing",
241
+ record.sensorDomainProcessing
242
+ ]
243
+ ]) {
244
+ if (typeof raw !== "boolean") {
245
+ throw new InvalidConfigurationError("rendererCapability." +
246
+ key +
247
+ " must be boolean.");
248
+ }
249
+ }
250
+ return {
251
+ schemaVersion: RENDERER_CAPABILITY_SCHEMA_VERSION,
252
+ rendererId: requireNonEmptyString(record.rendererId, "rendererCapability.rendererId"),
253
+ rendererVersion: requireNonEmptyString(record.rendererVersion, "rendererCapability.rendererVersion"),
254
+ consumerKind,
255
+ supportedStages: parseUniqueStageIds(record.supportedStages, "rendererCapability.supportedStages"),
256
+ supportedEffects: parseUniqueEffectIds(record.supportedEffects, "rendererCapability.supportedEffects"),
257
+ spectralCapability,
258
+ temporalSampling,
259
+ depthCapability,
260
+ inverseFieldMapping: record
261
+ .inverseFieldMapping,
262
+ alphaRepresentation,
263
+ preservesDepthOrderAcrossWarps: record
264
+ .preservesDepthOrderAcrossWarps,
265
+ sensorDomainProcessing: record
266
+ .sensorDomainProcessing
267
+ };
268
+ }
269
+ /**
270
+ * Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
271
+ * missing required fields and incompatible scientific data fail at this boundary.
272
+ *
273
+ * The planner owns scientific stage ordering, immutable capture identity and reproducibility.
274
+ * Well-formed unsupported combinations produce structured blockers; malformed declarations throw. The
275
+ * bounded environment route executes supplied radiance through native RAW and optional output, while
276
+ * sample-only and attached-RAW routes retain missing upstream blockers. FNV fingerprints are
277
+ * reproducibility keys, not cryptographic integrity proofs.
278
+ * @param value - unknown. Treated as untrusted data; static typing alone is not validation.
279
+ * @returns ImageFormationFidelityProfile. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
280
+ *
281
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
282
+ */
283
+ export function parseImageFormationFidelityProfile(value) {
284
+ const record = requireRecord(value, "imageFormationFidelityProfile");
285
+ if (record.schemaVersion !==
286
+ IMAGE_FORMATION_FIDELITY_PROFILE_SCHEMA_VERSION) {
287
+ throw new InvalidConfigurationError('imageFormationFidelityProfile.schemaVersion must be "' +
288
+ IMAGE_FORMATION_FIDELITY_PROFILE_SCHEMA_VERSION +
289
+ '".');
290
+ }
291
+ if (!Array.isArray(record.requiredEffects)) {
292
+ throw new InvalidConfigurationError("imageFormationFidelityProfile.requiredEffects must be an array.");
293
+ }
294
+ const validEffects = contractEffectIds();
295
+ const seenEffects = new Set();
296
+ const requestedEffects = record.requiredEffects.map((entry, index) => {
297
+ const path = "imageFormationFidelityProfile.requiredEffects[" +
298
+ index +
299
+ "]";
300
+ const effect = requireRecord(entry, path);
301
+ const effectId = effect.effectId;
302
+ if (typeof effectId !==
303
+ "string" ||
304
+ !validEffects.has(effectId)) {
305
+ throw new InvalidConfigurationError(path +
306
+ ".effectId is not a declared image-formation effect.");
307
+ }
308
+ const typed = effectId;
309
+ if (seenEffects.has(typed)) {
310
+ throw new InvalidConfigurationError("imageFormationFidelityProfile.requiredEffects must not contain duplicate effect IDs.");
311
+ }
312
+ seenEffects.add(typed);
313
+ return {
314
+ effectId: typed,
315
+ modelId: requireNonEmptyString(effect.modelId, path + ".modelId"),
316
+ modelVersion: requireNonEmptyString(effect.modelVersion, path +
317
+ ".modelVersion")
318
+ };
319
+ });
320
+ const effectOrder = new Map(getImageFormationContract()
321
+ .effectPlacements.map((effect, index) => [
322
+ effect.id,
323
+ index
324
+ ]));
325
+ const requiredEffects = [
326
+ ...requestedEffects
327
+ ].sort((left, right) => (effectOrder.get(left.effectId) ?? 0) -
328
+ (effectOrder.get(right.effectId) ?? 0));
329
+ const requirements = requireRecord(record.rendererRequirements, "imageFormationFidelityProfile.rendererRequirements");
330
+ const spectral = requirements.spectral;
331
+ if (spectral !==
332
+ "wavelength-resolved" &&
333
+ spectral !==
334
+ "wavelength-independent-approximation") {
335
+ throw new InvalidConfigurationError("imageFormationFidelityProfile.rendererRequirements.spectral is invalid.");
336
+ }
337
+ if (typeof requirements
338
+ .sensorDomainProcessing !==
339
+ "boolean") {
340
+ throw new InvalidConfigurationError("imageFormationFidelityProfile.rendererRequirements.sensorDomainProcessing must be boolean.");
341
+ }
342
+ const depth = requirements.depth;
343
+ if (depth !== "none" &&
344
+ depth !== "per-layer") {
345
+ throw new InvalidConfigurationError("imageFormationFidelityProfile.rendererRequirements.depth is invalid.");
346
+ }
347
+ return {
348
+ schemaVersion: IMAGE_FORMATION_FIDELITY_PROFILE_SCHEMA_VERSION,
349
+ profileId: requireNonEmptyString(record.profileId, "imageFormationFidelityProfile.profileId"),
350
+ profileVersion: requireNonEmptyString(record.profileVersion, "imageFormationFidelityProfile.profileVersion"),
351
+ requiredStages: parseUniqueStageIds(record.requiredStages, "imageFormationFidelityProfile.requiredStages"),
352
+ requiredEffects,
353
+ rendererRequirements: {
354
+ spectral,
355
+ sensorDomainProcessing: requirements
356
+ .sensorDomainProcessing,
357
+ depth
358
+ }
359
+ };
360
+ }
361
+ function validateEquipmentCapabilities(value) {
362
+ if (value.schemaVersion !==
363
+ GENERIC_EQUIPMENT_EXPOSURE_CAPABILITY_SCHEMA_VERSION ||
364
+ value.scientificStatus !==
365
+ "approximation") {
366
+ throw new InvalidConfigurationError("equipmentCapabilities do not satisfy the resolved generic equipment capability contract.");
367
+ }
368
+ requireNonEmptyString(value.bodyProfile.profileId, "equipmentCapabilities.bodyProfile.profileId");
369
+ requireNonEmptyString(value.bodyProfile.profileVersion, "equipmentCapabilities.bodyProfile.profileVersion");
370
+ requireNonEmptyString(value.lensProfile.profileId, "equipmentCapabilities.lensProfile.profileId");
371
+ requireNonEmptyString(value.lensProfile.profileVersion, "equipmentCapabilities.lensProfile.profileVersion");
372
+ requirePositiveFinite(value.selectedFocalLengthMm, "equipmentCapabilities.selectedFocalLengthMm");
373
+ requirePositiveFinite(value.aperture
374
+ .widestAvailableFNumber, "equipmentCapabilities.aperture.widestAvailableFNumber");
375
+ requirePositiveFinite(value.aperture
376
+ .narrowestAvailableFNumber, "equipmentCapabilities.aperture.narrowestAvailableFNumber");
377
+ requirePositiveFinite(value.shutter.minimumSeconds, "equipmentCapabilities.shutter.minimumSeconds");
378
+ requirePositiveFinite(value.shutter.maximumSeconds, "equipmentCapabilities.shutter.maximumSeconds");
379
+ requirePositiveFinite(value.iso.minimum, "equipmentCapabilities.iso.minimum");
380
+ requirePositiveFinite(value.iso.maximum, "equipmentCapabilities.iso.maximum");
381
+ }
382
+ function settingEquals(left, right) {
383
+ const scale = Math.max(1, Math.abs(left), Math.abs(right));
384
+ return (Math.abs(left - right) <=
385
+ Number.EPSILON *
386
+ 32 *
387
+ scale);
388
+ }
389
+ function validateSetting(value, minimum, maximum, grid, path) {
390
+ if (value < minimum ||
391
+ value > maximum) {
392
+ throw new InvalidScientificInputError(path +
393
+ " lies outside the prepared equipment capability range.");
394
+ }
395
+ if (grid.kind ===
396
+ "discrete-values" &&
397
+ !grid.values.some((candidate) => settingEquals(candidate, value))) {
398
+ throw new InvalidScientificInputError(path +
399
+ " is not present in the prepared discrete equipment setting grid.");
400
+ }
401
+ }
402
+ function cloneJson(value) {
403
+ return JSON.parse(JSON.stringify(value));
404
+ }
405
+ function deepFreeze(value) {
406
+ if (typeof value !== "object" ||
407
+ value === null ||
408
+ Object.isFrozen(value)) {
409
+ return value;
410
+ }
411
+ Object.freeze(value);
412
+ for (const child of Object.values(value)) {
413
+ deepFreeze(child);
414
+ }
415
+ return value;
416
+ }
417
+ function canonicalStringify(value) {
418
+ return stringifyCanonicalJson(value, {
419
+ undefinedObjectProperties: "omit",
420
+ nonFiniteNumberMessage: "Canonical plan serialization does not permit non-finite numbers.",
421
+ unsupportedValueMessage: "Canonical plan serialization encountered an unsupported value type."
422
+ });
423
+ }
424
+ function fingerprintText(text) {
425
+ let hash = 0x811c9dc5;
426
+ const bytes = new TextEncoder().encode(text);
427
+ for (const byte of bytes) {
428
+ hash ^= byte;
429
+ hash =
430
+ Math.imul(hash, 0x01000193) >>> 0;
431
+ }
432
+ return hash
433
+ .toString(16)
434
+ .padStart(8, "0");
435
+ }
436
+ function fingerprintValue(value) {
437
+ return fingerprintText(canonicalStringify(value));
438
+ }
439
+ /**
440
+ * Return deterministic canonical JSON of a validated production plan. Sorted object keys preserve
441
+ * array order; the representation contains data and excludes executable provider callbacks.
442
+ *
443
+ * The planner owns scientific stage ordering, immutable capture identity and reproducibility.
444
+ * Well-formed unsupported combinations produce structured blockers; malformed declarations throw. The
445
+ * bounded environment route executes supplied radiance through native RAW and optional output, while
446
+ * sample-only and attached-RAW routes retain missing upstream blockers. FNV fingerprints are
447
+ * reproducibility keys, not cryptographic integrity proofs.
448
+ * @param plan - ProductionImageFormationPlan. See the linked contract for coordinate, unit and profile binding semantics.
449
+ * @returns string. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
450
+ *
451
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
452
+ */
453
+ export function serializeProductionImageFormationPlan(plan) {
454
+ return canonicalStringify(plan);
455
+ }
456
+ /**
457
+ * Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
458
+ * missing required fields and incompatible scientific data fail at this boundary.
459
+ *
460
+ * The planner owns scientific stage ordering, immutable capture identity and reproducibility.
461
+ * Well-formed unsupported combinations produce structured blockers; malformed declarations throw. The
462
+ * bounded environment route executes supplied radiance through native RAW and optional output, while
463
+ * sample-only and attached-RAW routes retain missing upstream blockers. FNV fingerprints are
464
+ * reproducibility keys, not cryptographic integrity proofs.
465
+ * @param value - unknown. Treated as untrusted data; static typing alone is not validation.
466
+ * @returns PreparedImageFormationContext. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
467
+ *
468
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
469
+ */
470
+ export function parsePreparedImageFormationContext(value) {
471
+ const record = requireRecord(value, "preparedImageFormationContext");
472
+ if (record.version !==
473
+ PREPARED_IMAGE_FORMATION_CONTEXT_VERSION) {
474
+ throw new InvalidConfigurationError('preparedImageFormationContext.version must be "' +
475
+ PREPARED_IMAGE_FORMATION_CONTEXT_VERSION +
476
+ '".');
477
+ }
478
+ const parsed = prepareImageFormationContext({
479
+ contextId: record.contextId,
480
+ sceneId: record.sceneId,
481
+ sceneRadianceProviderProfileId: record
482
+ .sceneRadianceProviderProfileId,
483
+ outputGeometryProfileId: record
484
+ .outputGeometryProfileId,
485
+ equipmentCapabilities: record
486
+ .equipmentCapabilities,
487
+ ...(record
488
+ .opticalBridgeProfile ===
489
+ undefined
490
+ ? {}
491
+ : {
492
+ opticalBridgeProfile: record
493
+ .opticalBridgeProfile
494
+ }),
495
+ renderer: record.renderer,
496
+ fidelity: record.fidelity
497
+ });
498
+ if (typeof record.fingerprint !==
499
+ "object" ||
500
+ record.fingerprint === null) {
501
+ throw new InvalidConfigurationError("preparedImageFormationContext.fingerprint must be present.");
502
+ }
503
+ const supplied = requireRecord(record.fingerprint, "preparedImageFormationContext.fingerprint");
504
+ if (supplied.algorithm !==
505
+ "fnv1a-32-non-cryptographic" ||
506
+ supplied.value !==
507
+ parsed.fingerprint.value) {
508
+ throw new InvalidConfigurationError("preparedImageFormationContext fingerprint does not match its parsed content.");
509
+ }
510
+ return parsed;
511
+ }
512
+ /**
513
+ * Parse, own and freeze relatively static equipment, scene, renderer and fidelity declarations for
514
+ * reuse by later immutable captures. This prepares semantic state and does not render a frame.
515
+ *
516
+ * The planner owns scientific stage ordering, immutable capture identity and reproducibility.
517
+ * Well-formed unsupported combinations produce structured blockers; malformed declarations throw. The
518
+ * bounded environment route executes supplied radiance through native RAW and optional output, while
519
+ * sample-only and attached-RAW routes retain missing upstream blockers. FNV fingerprints are
520
+ * reproducibility keys, not cryptographic integrity proofs.
521
+ * @param input - PrepareImageFormationContextInput. See the linked contract for coordinate, unit and profile binding semantics.
522
+ * @returns PreparedImageFormationContext. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
523
+ *
524
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
525
+ */
526
+ export function prepareImageFormationContext(input) {
527
+ validateEquipmentCapabilities(input.equipmentCapabilities);
528
+ const renderer = parseRendererCapabilityDeclaration(input.renderer);
529
+ const fidelity = parseImageFormationFidelityProfile(input.fidelity);
530
+ const opticalBridgeProfile = input.opticalBridgeProfile ===
531
+ undefined
532
+ ? undefined
533
+ : parseSceneToSensorIrradianceProfile(input
534
+ .opticalBridgeProfile);
535
+ if (opticalBridgeProfile !==
536
+ undefined &&
537
+ opticalBridgeProfile
538
+ .lensProfileId !==
539
+ input
540
+ .equipmentCapabilities
541
+ .lensProfile.profileId) {
542
+ throw new InvalidConfigurationError("opticalBridgeProfile.lensProfileId must match equipmentCapabilities.lensProfile.profileId.");
543
+ }
544
+ const core = {
545
+ version: PREPARED_IMAGE_FORMATION_CONTEXT_VERSION,
546
+ contextId: requireNonEmptyString(input.contextId, "contextId"),
547
+ sceneId: requireNonEmptyString(input.sceneId, "sceneId"),
548
+ sceneRadianceProviderProfileId: requireNonEmptyString(input
549
+ .sceneRadianceProviderProfileId, "sceneRadianceProviderProfileId"),
550
+ outputGeometryProfileId: requireNonEmptyString(input.outputGeometryProfileId, "outputGeometryProfileId"),
551
+ equipmentCapabilities: cloneJson(input
552
+ .equipmentCapabilities),
553
+ ...(opticalBridgeProfile ===
554
+ undefined
555
+ ? {}
556
+ : {
557
+ opticalBridgeProfile: cloneJson(opticalBridgeProfile)
558
+ }),
559
+ renderer,
560
+ fidelity
561
+ };
562
+ const prepared = {
563
+ ...core,
564
+ fingerprint: {
565
+ algorithm: "fnv1a-32-non-cryptographic",
566
+ value: fingerprintValue(core)
567
+ }
568
+ };
569
+ return deepFreeze(cloneJson(prepared));
570
+ }
571
+ function validatePhysicalSceneSample(sample, sceneTimeSecondsFromExposureStart) {
572
+ const request = parseSceneRadianceEvaluationRequest(sample.sceneRadianceRequest);
573
+ const result = parseSceneRadianceEvaluationResult(sample.sceneRadianceResult);
574
+ if (request
575
+ .timeSecondsFromExposureStart !==
576
+ sceneTimeSecondsFromExposureStart) {
577
+ throw new InvalidConfigurationError("physicalSceneSample.sceneRadianceRequest.timeSecondsFromExposureStart must equal the capture snapshot scene time.");
578
+ }
579
+ const imagePoint = requireRecord(sample.imagePointMm, "physicalSceneSample.imagePointMm");
580
+ return cloneJson({
581
+ sceneRadianceRequest: request,
582
+ sceneRadianceResult: result,
583
+ focus: sample.focus,
584
+ imagePointMm: {
585
+ x: requireFinite(imagePoint.x, "physicalSceneSample.imagePointMm.x"),
586
+ y: requireFinite(imagePoint.y, "physicalSceneSample.imagePointMm.y")
587
+ },
588
+ fieldThroughput: sample.fieldThroughput,
589
+ ...(sample.frontOfLensFilters ===
590
+ undefined
591
+ ? {}
592
+ : {
593
+ frontOfLensFilters: sample.frontOfLensFilters.map((profile) => parseFrontOfLensFilterProfile(profile))
594
+ })
595
+ });
596
+ }
597
+ const CAPTURE_ORIENTATIONS = new Set([
598
+ "landscape",
599
+ "portrait-clockwise",
600
+ "landscape-inverted",
601
+ "portrait-counter-clockwise"
602
+ ]);
603
+ function validateTemporalCaptureInput(input, shutterSeconds) {
604
+ const exposureWindows = calculateCaptureExposureWindows(input.exposureWindowInput).value;
605
+ if (!settingEquals(exposureWindows
606
+ .nominalExposureDurationSeconds
607
+ .value, shutterSeconds)) {
608
+ throw new InvalidConfigurationError("temporalCapture.exposureWindowInput.nominalExposureDurationSeconds must match exposure.shutterSeconds.");
609
+ }
610
+ requirePositiveFinite(input.imagingArea.widthMm, "temporalCapture.imagingArea.widthMm");
611
+ requirePositiveFinite(input.imagingArea.heightMm, "temporalCapture.imagingArea.heightMm");
612
+ if (!CAPTURE_ORIENTATIONS.has(input.orientation)) {
613
+ throw new InvalidConfigurationError("temporalCapture.orientation is invalid.");
614
+ }
615
+ if (input.readout !== undefined) {
616
+ calculateSensorReadoutTiming({
617
+ nativeRaster: input.exposureWindowInput
618
+ .nativeRaster,
619
+ ...(input.exposureWindowInput
620
+ .activeCaptureRect ===
621
+ undefined
622
+ ? {}
623
+ : {
624
+ activeCaptureRect: input
625
+ .exposureWindowInput
626
+ .activeCaptureRect
627
+ }),
628
+ shutterMechanism: input.exposureWindowInput
629
+ .shutterMechanism,
630
+ readout: input.readout,
631
+ ...(input.exposureWindowInput
632
+ .samplePointsNative ===
633
+ undefined
634
+ ? {}
635
+ : {
636
+ samplePointsNative: input
637
+ .exposureWindowInput
638
+ .samplePointsNative
639
+ })
640
+ });
641
+ }
642
+ if (input.rotation !== undefined) {
643
+ const sampleCount = input.rotation
644
+ .temporalSampleCount;
645
+ if (!Number.isSafeInteger(sampleCount) ||
646
+ sampleCount <= 0) {
647
+ throw new InvalidConfigurationError("temporalCapture.rotation.temporalSampleCount must be a positive safe integer.");
648
+ }
649
+ for (const [axis, value] of [
650
+ [
651
+ "pitch",
652
+ input.rotation
653
+ .angularVelocityRadPerSec
654
+ .pitch
655
+ ],
656
+ [
657
+ "yaw",
658
+ input.rotation
659
+ .angularVelocityRadPerSec
660
+ .yaw
661
+ ],
662
+ [
663
+ "roll",
664
+ input.rotation
665
+ .angularVelocityRadPerSec
666
+ .roll
667
+ ]
668
+ ]) {
669
+ requireFinite(value, "temporalCapture.rotation.angularVelocityRadPerSec." +
670
+ axis);
671
+ }
672
+ if (input.rotation
673
+ .focusDistanceM !==
674
+ undefined) {
675
+ requirePositiveFinite(input.rotation
676
+ .focusDistanceM, "temporalCapture.rotation.focusDistanceM");
677
+ }
678
+ if (!Array.isArray(input.exposureWindowInput
679
+ .samplePointsNative) ||
680
+ input.exposureWindowInput
681
+ .samplePointsNative
682
+ .length === 0) {
683
+ throw new InvalidConfigurationError("temporalCapture.rotation requires non-empty exposureWindowInput.samplePointsNative.");
684
+ }
685
+ }
686
+ return cloneJson(input);
687
+ }
688
+ const RELEASE_TIMING_CONSTRAINTS = new Set([
689
+ "requested-cadence",
690
+ "body-maximum-cadence",
691
+ "exposure-duration",
692
+ "minimum-inter-frame-gap"
693
+ ]);
694
+ function validateReleaseAutomationState(value, path) {
695
+ if (value !== "manual" &&
696
+ value !== "locked" &&
697
+ value !== "continuous") {
698
+ throw new InvalidConfigurationError(path + " is invalid.");
699
+ }
700
+ return value;
701
+ }
702
+ function validateProductionReleaseFrameBinding(binding, releaseFrameId, exposure, stochasticSeedUint32) {
703
+ if (binding.releaseSequenceVersion !==
704
+ RELEASE_SEQUENCE_VERSION) {
705
+ throw new InvalidConfigurationError('releaseFrameBinding.releaseSequenceVersion must be "' +
706
+ RELEASE_SEQUENCE_VERSION +
707
+ '".');
708
+ }
709
+ const frameIndex = binding.frameIndex;
710
+ if (!Number.isSafeInteger(frameIndex) ||
711
+ frameIndex < 0) {
712
+ throw new InvalidConfigurationError("releaseFrameBinding.frameIndex must be a non-negative safe integer.");
713
+ }
714
+ const start = requireFinite(binding.exposureStartTimeSeconds, "releaseFrameBinding.exposureStartTimeSeconds");
715
+ const end = requireFinite(binding.exposureEndTimeSeconds, "releaseFrameBinding.exposureEndTimeSeconds");
716
+ if (end <= start) {
717
+ throw new InvalidConfigurationError("releaseFrameBinding exposure end must be after exposure start.");
718
+ }
719
+ if (!settingEquals(end - start, exposure.shutterSeconds)) {
720
+ throw new InvalidConfigurationError("releaseFrameBinding exposure duration must match exposure.shutterSeconds.");
721
+ }
722
+ const sceneTime = requireFinite(binding.sceneTimeSecondsFromSequenceStart, "releaseFrameBinding.sceneTimeSecondsFromSequenceStart");
723
+ if (sceneTime < 0) {
724
+ throw new InvalidConfigurationError("releaseFrameBinding.sceneTimeSecondsFromSequenceStart must be greater than or equal to zero.");
725
+ }
726
+ let interval = null;
727
+ if (binding.startIntervalFromPreviousSeconds !==
728
+ null) {
729
+ interval =
730
+ requirePositiveFinite(binding.startIntervalFromPreviousSeconds, "releaseFrameBinding.startIntervalFromPreviousSeconds");
731
+ }
732
+ if (frameIndex === 0 &&
733
+ interval !== null) {
734
+ throw new InvalidConfigurationError("The first release frame must not declare a previous-frame interval.");
735
+ }
736
+ if (frameIndex > 0 &&
737
+ interval === null) {
738
+ throw new InvalidConfigurationError("A non-first release frame must declare its previous-frame interval.");
739
+ }
740
+ if (!Array.isArray(binding.timingConstraints)) {
741
+ throw new InvalidConfigurationError("releaseFrameBinding.timingConstraints must be an array.");
742
+ }
743
+ const timingConstraints = binding.timingConstraints.map((constraint, index) => {
744
+ if (!RELEASE_TIMING_CONSTRAINTS.has(constraint)) {
745
+ throw new InvalidConfigurationError("releaseFrameBinding.timingConstraints[" +
746
+ index +
747
+ "] is invalid.");
748
+ }
749
+ return constraint;
750
+ });
751
+ if (new Set(timingConstraints).size !==
752
+ timingConstraints.length) {
753
+ throw new InvalidConfigurationError("releaseFrameBinding.timingConstraints must not contain duplicates.");
754
+ }
755
+ const automationRecord = requireRecord(binding.automation, "releaseFrameBinding.automation");
756
+ const automation = {
757
+ ae: validateReleaseAutomationState(automationRecord.ae, "releaseFrameBinding.automation.ae"),
758
+ af: validateReleaseAutomationState(automationRecord.af, "releaseFrameBinding.automation.af"),
759
+ awb: validateReleaseAutomationState(automationRecord.awb, "releaseFrameBinding.automation.awb")
760
+ };
761
+ const whiteBalanceStateId = binding.whiteBalanceStateId ===
762
+ undefined
763
+ ? undefined
764
+ : requireNonEmptyString(binding.whiteBalanceStateId, "releaseFrameBinding.whiteBalanceStateId");
765
+ const exposureRecord = requireRecord(binding.exposure, "releaseFrameBinding.exposure");
766
+ const parsedExposure = {
767
+ aperture: requirePositiveFinite(exposureRecord.aperture, "releaseFrameBinding.exposure.aperture"),
768
+ shutterSeconds: requirePositiveFinite(exposureRecord.shutterSeconds, "releaseFrameBinding.exposure.shutterSeconds"),
769
+ iso: requirePositiveFinite(exposureRecord.iso, "releaseFrameBinding.exposure.iso")
770
+ };
771
+ const parsedSeed = requireUint32(binding.stochasticSeedUint32, "releaseFrameBinding.stochasticSeedUint32");
772
+ if (!settingEquals(parsedExposure.aperture, exposure.aperture) ||
773
+ !settingEquals(parsedExposure.shutterSeconds, exposure.shutterSeconds) ||
774
+ !settingEquals(parsedExposure.iso, exposure.iso)) {
775
+ throw new InvalidConfigurationError("releaseFrameBinding.exposure must match the committed capture exposure.");
776
+ }
777
+ if (parsedSeed !==
778
+ stochasticSeedUint32) {
779
+ throw new InvalidConfigurationError("releaseFrameBinding.stochasticSeedUint32 must match the committed capture seed.");
780
+ }
781
+ const parsed = {
782
+ releaseSequenceVersion: RELEASE_SEQUENCE_VERSION,
783
+ sequenceId: requireNonEmptyString(binding.sequenceId, "releaseFrameBinding.sequenceId"),
784
+ releaseFrameId: requireNonEmptyString(binding.releaseFrameId, "releaseFrameBinding.releaseFrameId"),
785
+ frameIndex,
786
+ exposure: parsedExposure,
787
+ stochasticSeedUint32: parsedSeed,
788
+ exposureStartTimeSeconds: start,
789
+ exposureEndTimeSeconds: end,
790
+ sceneTimeSecondsFromSequenceStart: sceneTime,
791
+ startIntervalFromPreviousSeconds: interval,
792
+ timingConstraints,
793
+ focus: parseFocusPlane(binding.focus),
794
+ automation,
795
+ ...(whiteBalanceStateId ===
796
+ undefined
797
+ ? {}
798
+ : {
799
+ whiteBalanceStateId
800
+ })
801
+ };
802
+ if (parsed.releaseFrameId !==
803
+ releaseFrameId) {
804
+ throw new InvalidConfigurationError("releaseFrameBinding.releaseFrameId must match releaseFrameId.");
805
+ }
806
+ return parsed;
807
+ }
808
+ function releaseFocusMatchesOpticalFocus(releaseFocus, opticalFocus) {
809
+ if (releaseFocus.kind ===
810
+ "infinity") {
811
+ return (opticalFocus.kind ===
812
+ "infinity-focus" ||
813
+ (opticalFocus.kind ===
814
+ "supplied-working-f-number" &&
815
+ opticalFocus.focus.kind ===
816
+ "infinity"));
817
+ }
818
+ if (opticalFocus.kind ===
819
+ "ideal-symmetric-thin-lens") {
820
+ return settingEquals(opticalFocus.objectDistanceM, releaseFocus.distanceM);
821
+ }
822
+ if (opticalFocus.kind ===
823
+ "supplied-working-f-number" &&
824
+ opticalFocus.focus.kind ===
825
+ "finite") {
826
+ return settingEquals(opticalFocus.focus.objectDistanceM, releaseFocus.distanceM);
827
+ }
828
+ return false;
829
+ }
830
+ function validateCommittedWhiteBalanceState(state, binding) {
831
+ const parsed = state === undefined
832
+ ? undefined
833
+ : parseResolvedWhiteBalanceState(state);
834
+ if (binding === undefined) {
835
+ return parsed;
836
+ }
837
+ if (binding.whiteBalanceStateId ===
838
+ undefined) {
839
+ if (parsed !== undefined) {
840
+ throw new InvalidConfigurationError("A release frame without whiteBalanceStateId must not receive a committed whiteBalanceState.");
841
+ }
842
+ return undefined;
843
+ }
844
+ if (parsed === undefined) {
845
+ throw new InvalidConfigurationError("A release frame with whiteBalanceStateId requires the committed resolved white-balance state.");
846
+ }
847
+ if (parsed.stateId !==
848
+ binding.whiteBalanceStateId) {
849
+ throw new InvalidConfigurationError("whiteBalanceState.stateId must match releaseFrameBinding.whiteBalanceStateId.");
850
+ }
851
+ if (binding.automation.awb ===
852
+ "locked" &&
853
+ !parsed.locked) {
854
+ throw new InvalidConfigurationError("A release frame with locked AWB requires a locked committed white-balance state.");
855
+ }
856
+ return parsed;
857
+ }
858
+ /**
859
+ * Commit resolved capture settings, scene time/identity, stochastic seed and optional
860
+ * temporal/focus/WB state by value. Later application mutations cannot alter this scientific event.
861
+ *
862
+ * The planner owns scientific stage ordering, immutable capture identity and reproducibility.
863
+ * Well-formed unsupported combinations produce structured blockers; malformed declarations throw. The
864
+ * bounded environment route executes supplied radiance through native RAW and optional output, while
865
+ * sample-only and attached-RAW routes retain missing upstream blockers. FNV fingerprints are
866
+ * reproducibility keys, not cryptographic integrity proofs.
867
+ * @param input - CreateProductionCaptureSnapshotInput. See the linked contract for coordinate, unit and profile binding semantics.
868
+ * @returns ProductionCaptureSnapshot. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
869
+ *
870
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
871
+ */
872
+ export function createProductionCaptureSnapshot(input) {
873
+ const sceneTime = requireFinite(input
874
+ .sceneTimeSecondsFromExposureStart, "sceneTimeSecondsFromExposureStart");
875
+ if (sceneTime < 0) {
876
+ throw new InvalidConfigurationError("sceneTimeSecondsFromExposureStart must be greater than or equal to zero.");
877
+ }
878
+ const releaseFrameId = requireNonEmptyString(input.releaseFrameId, "releaseFrameId");
879
+ const exposure = {
880
+ aperture: requirePositiveFinite(input.exposure.aperture, "exposure.aperture"),
881
+ shutterSeconds: requirePositiveFinite(input.exposure
882
+ .shutterSeconds, "exposure.shutterSeconds"),
883
+ iso: requirePositiveFinite(input.exposure.iso, "exposure.iso")
884
+ };
885
+ const releaseFrameBinding = input.releaseFrameBinding ===
886
+ undefined
887
+ ? undefined
888
+ : validateProductionReleaseFrameBinding(input.releaseFrameBinding, releaseFrameId, exposure, requireUint32(input.stochasticSeedUint32, "stochasticSeedUint32"));
889
+ const whiteBalanceState = validateCommittedWhiteBalanceState(input.whiteBalanceState, releaseFrameBinding);
890
+ const physicalSceneSample = input.physicalSceneSample ===
891
+ undefined
892
+ ? undefined
893
+ : validatePhysicalSceneSample(input.physicalSceneSample, sceneTime);
894
+ if (releaseFrameBinding !==
895
+ undefined &&
896
+ physicalSceneSample !==
897
+ undefined &&
898
+ !releaseFocusMatchesOpticalFocus(releaseFrameBinding.focus, physicalSceneSample.focus)) {
899
+ throw new InvalidConfigurationError("physicalSceneSample.focus must match the committed release-frame focus.");
900
+ }
901
+ const core = {
902
+ version: PRODUCTION_CAPTURE_SNAPSHOT_VERSION,
903
+ captureId: requireNonEmptyString(input.captureId, "captureId"),
904
+ releaseFrameId,
905
+ sceneStateId: requireNonEmptyString(input.sceneStateId, "sceneStateId"),
906
+ sceneTimeSecondsFromExposureStart: sceneTime,
907
+ outputStateId: requireNonEmptyString(input.outputStateId, "outputStateId"),
908
+ exposure,
909
+ stochasticSeedUint32: requireUint32(input.stochasticSeedUint32, "stochasticSeedUint32"),
910
+ ...(releaseFrameBinding ===
911
+ undefined
912
+ ? {}
913
+ : {
914
+ releaseFrameBinding
915
+ }),
916
+ ...(whiteBalanceState ===
917
+ undefined
918
+ ? {}
919
+ : {
920
+ whiteBalanceState
921
+ }),
922
+ ...(input.temporalCapture ===
923
+ undefined
924
+ ? {}
925
+ : {
926
+ temporalCapture: validateTemporalCaptureInput(input.temporalCapture, exposure.shutterSeconds)
927
+ }),
928
+ ...(physicalSceneSample ===
929
+ undefined
930
+ ? {}
931
+ : {
932
+ physicalSceneSample
933
+ })
934
+ };
935
+ const snapshot = {
936
+ ...core,
937
+ fingerprint: {
938
+ algorithm: "fnv1a-32-non-cryptographic",
939
+ value: fingerprintValue(core)
940
+ }
941
+ };
942
+ return deepFreeze(cloneJson(snapshot));
943
+ }
944
+ /**
945
+ * Creates one immutable production snapshot directly from a committed #105
946
+ * release frame. The release frame owns exposure/focus/automation/seed
947
+ * identity; callers provide only the scene/output-local state that is not
948
+ * owned by the release sequence.
949
+ */
950
+ export function createProductionCaptureSnapshotFromReleaseFrame(input) {
951
+ const frame = input.releaseFrame;
952
+ const releaseFrameBinding = {
953
+ releaseSequenceVersion: RELEASE_SEQUENCE_VERSION,
954
+ sequenceId: requireNonEmptyString(frame.sequenceId, "releaseFrame.sequenceId"),
955
+ releaseFrameId: requireNonEmptyString(frame.releaseFrameId, "releaseFrame.releaseFrameId"),
956
+ frameIndex: frame.frameIndex,
957
+ exposure: {
958
+ ...frame.exposure
959
+ },
960
+ stochasticSeedUint32: frame.stochasticSeedUint32,
961
+ exposureStartTimeSeconds: frame.exposureStartTimeSeconds,
962
+ exposureEndTimeSeconds: frame.exposureEndTimeSeconds,
963
+ sceneTimeSecondsFromSequenceStart: frame.sceneTimeSecondsFromSequenceStart,
964
+ startIntervalFromPreviousSeconds: frame.startIntervalFromPreviousSeconds,
965
+ timingConstraints: [
966
+ ...frame.timingConstraints
967
+ ],
968
+ focus: parseFocusPlane(frame.focus),
969
+ automation: {
970
+ ...frame.automation
971
+ },
972
+ ...(frame.whiteBalanceStateId ===
973
+ undefined
974
+ ? {}
975
+ : {
976
+ whiteBalanceStateId: frame.whiteBalanceStateId
977
+ })
978
+ };
979
+ return createProductionCaptureSnapshot({
980
+ captureId: input.captureId,
981
+ releaseFrameId: frame.releaseFrameId,
982
+ sceneStateId: input.sceneStateId,
983
+ sceneTimeSecondsFromExposureStart: input
984
+ .sceneTimeSecondsFromExposureStart,
985
+ outputStateId: input.outputStateId,
986
+ exposure: {
987
+ ...frame.exposure
988
+ },
989
+ stochasticSeedUint32: frame.stochasticSeedUint32,
990
+ releaseFrameBinding,
991
+ ...(input.whiteBalanceState ===
992
+ undefined
993
+ ? {}
994
+ : {
995
+ whiteBalanceState: input.whiteBalanceState
996
+ }),
997
+ ...(input.physicalSceneSample ===
998
+ undefined
999
+ ? {}
1000
+ : {
1001
+ physicalSceneSample: input.physicalSceneSample
1002
+ }),
1003
+ ...(input.temporalCapture ===
1004
+ undefined
1005
+ ? {}
1006
+ : {
1007
+ temporalCapture: input.temporalCapture
1008
+ })
1009
+ });
1010
+ }
1011
+ /**
1012
+ * Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
1013
+ * missing required fields and incompatible scientific data fail at this boundary.
1014
+ *
1015
+ * The planner owns scientific stage ordering, immutable capture identity and reproducibility.
1016
+ * Well-formed unsupported combinations produce structured blockers; malformed declarations throw. The
1017
+ * bounded environment route executes supplied radiance through native RAW and optional output, while
1018
+ * sample-only and attached-RAW routes retain missing upstream blockers. FNV fingerprints are
1019
+ * reproducibility keys, not cryptographic integrity proofs.
1020
+ * @param value - unknown. Treated as untrusted data; static typing alone is not validation.
1021
+ * @returns ProductionCaptureSnapshot. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
1022
+ *
1023
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
1024
+ */
1025
+ export function parseProductionCaptureSnapshot(value) {
1026
+ const record = requireRecord(value, "productionCaptureSnapshot");
1027
+ if (record.version !==
1028
+ PRODUCTION_CAPTURE_SNAPSHOT_VERSION) {
1029
+ throw new InvalidConfigurationError('productionCaptureSnapshot.version must be "' +
1030
+ PRODUCTION_CAPTURE_SNAPSHOT_VERSION +
1031
+ '".');
1032
+ }
1033
+ const parsed = createProductionCaptureSnapshot({
1034
+ captureId: record.captureId,
1035
+ releaseFrameId: record.releaseFrameId,
1036
+ sceneStateId: record.sceneStateId,
1037
+ sceneTimeSecondsFromExposureStart: record
1038
+ .sceneTimeSecondsFromExposureStart,
1039
+ outputStateId: record.outputStateId,
1040
+ exposure: record.exposure,
1041
+ stochasticSeedUint32: record
1042
+ .stochasticSeedUint32,
1043
+ ...(record
1044
+ .releaseFrameBinding ===
1045
+ undefined
1046
+ ? {}
1047
+ : {
1048
+ releaseFrameBinding: record
1049
+ .releaseFrameBinding
1050
+ }),
1051
+ ...(record
1052
+ .whiteBalanceState ===
1053
+ undefined
1054
+ ? {}
1055
+ : {
1056
+ whiteBalanceState: record
1057
+ .whiteBalanceState
1058
+ }),
1059
+ ...(record
1060
+ .physicalSceneSample ===
1061
+ undefined
1062
+ ? {}
1063
+ : {
1064
+ physicalSceneSample: record
1065
+ .physicalSceneSample
1066
+ }),
1067
+ ...(record.temporalCapture ===
1068
+ undefined
1069
+ ? {}
1070
+ : {
1071
+ temporalCapture: record
1072
+ .temporalCapture
1073
+ })
1074
+ });
1075
+ const supplied = requireRecord(record.fingerprint, "productionCaptureSnapshot.fingerprint");
1076
+ if (supplied.algorithm !==
1077
+ "fnv1a-32-non-cryptographic" ||
1078
+ supplied.value !==
1079
+ parsed.fingerprint.value) {
1080
+ throw new InvalidConfigurationError("productionCaptureSnapshot fingerprint does not match its parsed content.");
1081
+ }
1082
+ return parsed;
1083
+ }
1084
+ /**
1085
+ * Expand the requested graph through hard upstream dependencies in the engine
1086
+ * contract. Shared/coupled effects remain distinct from serialization order.
1087
+ * Dependency presence is not execution: deriveStagePlan still assesses declared
1088
+ * inputs, renderer capabilities and scientific support for every expanded stage.
1089
+ */
1090
+ function expandRequiredStages(fidelity) {
1091
+ const contract = getImageFormationContract();
1092
+ const byId = new Map(contract.stages.map((stage) => [
1093
+ stage.id,
1094
+ stage
1095
+ ]));
1096
+ const effects = new Map(contract.effectPlacements.map((effect) => [
1097
+ effect.id,
1098
+ effect
1099
+ ]));
1100
+ const required = new Set();
1101
+ const addStage = (stageId) => {
1102
+ if (required.has(stageId)) {
1103
+ return;
1104
+ }
1105
+ required.add(stageId);
1106
+ const stage = byId.get(stageId);
1107
+ if (stage === undefined) {
1108
+ throw new InvalidConfigurationError("Image-formation contract is missing stage " +
1109
+ stageId +
1110
+ ".");
1111
+ }
1112
+ for (const upstream of stage.requiredUpstreamStages) {
1113
+ addStage(upstream);
1114
+ }
1115
+ };
1116
+ for (const stageId of fidelity.requiredStages) {
1117
+ addStage(stageId);
1118
+ }
1119
+ for (const requiredEffect of fidelity.requiredEffects) {
1120
+ const placement = effects.get(requiredEffect.effectId);
1121
+ if (placement === undefined) {
1122
+ throw new InvalidConfigurationError("Image-formation contract is missing effect " +
1123
+ requiredEffect.effectId +
1124
+ ".");
1125
+ }
1126
+ addStage(placement.primaryStage);
1127
+ for (const coupled of placement.coupledStages) {
1128
+ addStage(coupled);
1129
+ }
1130
+ }
1131
+ return required;
1132
+ }
1133
+ function validateSnapshotAgainstContext(prepared, snapshot) {
1134
+ if (prepared.outputGeometryProfileId !==
1135
+ snapshot.outputStateId) {
1136
+ throw new InvalidScientificInputError("captureSnapshot.outputStateId must match the prepared outputGeometryProfileId in plan schema " +
1137
+ PRODUCTION_IMAGE_FORMATION_PLAN_VERSION +
1138
+ ".");
1139
+ }
1140
+ validateSetting(snapshot.exposure.aperture, prepared
1141
+ .equipmentCapabilities
1142
+ .aperture
1143
+ .widestAvailableFNumber, prepared
1144
+ .equipmentCapabilities
1145
+ .aperture
1146
+ .narrowestAvailableFNumber, prepared
1147
+ .equipmentCapabilities
1148
+ .aperture.settingGrid, "captureSnapshot.exposure.aperture");
1149
+ validateSetting(snapshot.exposure
1150
+ .shutterSeconds, prepared
1151
+ .equipmentCapabilities
1152
+ .shutter.minimumSeconds, prepared
1153
+ .equipmentCapabilities
1154
+ .shutter.maximumSeconds, prepared
1155
+ .equipmentCapabilities
1156
+ .shutter.settingGrid, "captureSnapshot.exposure.shutterSeconds");
1157
+ validateSetting(snapshot.exposure.iso, prepared
1158
+ .equipmentCapabilities
1159
+ .iso.minimum, prepared
1160
+ .equipmentCapabilities
1161
+ .iso.maximum, prepared
1162
+ .equipmentCapabilities
1163
+ .iso.settingGrid, "captureSnapshot.exposure.iso");
1164
+ const sample = snapshot
1165
+ .physicalSceneSample;
1166
+ if (sample !== undefined) {
1167
+ if (sample.sceneRadianceRequest
1168
+ .sceneId !==
1169
+ prepared.sceneId ||
1170
+ sample.sceneRadianceResult
1171
+ .sceneId !==
1172
+ prepared.sceneId) {
1173
+ throw new InvalidScientificInputError("Physical scene sample sceneId must match the prepared sceneId.");
1174
+ }
1175
+ if (sample.sceneRadianceRequest
1176
+ .providerProfileId !==
1177
+ prepared
1178
+ .sceneRadianceProviderProfileId ||
1179
+ sample.sceneRadianceResult
1180
+ .providerProfileId !==
1181
+ prepared
1182
+ .sceneRadianceProviderProfileId) {
1183
+ throw new InvalidScientificInputError("Physical scene sample providerProfileId must match the prepared scene-radiance provider.");
1184
+ }
1185
+ }
1186
+ }
1187
+ function addBlocker(blockers, blocker) {
1188
+ if (!blockers.some((existing) => canonicalStringify(existing) ===
1189
+ canonicalStringify(blocker))) {
1190
+ blockers.push(blocker);
1191
+ }
1192
+ }
1193
+ function evaluateRendererRequirements(prepared, requiredStages, blockers) {
1194
+ const renderer = prepared.renderer;
1195
+ const fidelity = prepared.fidelity;
1196
+ if (fidelity.rendererRequirements
1197
+ .spectral ===
1198
+ "wavelength-resolved" &&
1199
+ renderer.spectralCapability !==
1200
+ "wavelength-resolved") {
1201
+ addBlocker(blockers, {
1202
+ code: "renderer-spectral-capability-insufficient",
1203
+ message: "Requested fidelity requires wavelength-resolved renderer support."
1204
+ });
1205
+ }
1206
+ if (fidelity.rendererRequirements
1207
+ .sensorDomainProcessing &&
1208
+ !renderer
1209
+ .sensorDomainProcessing) {
1210
+ addBlocker(blockers, {
1211
+ code: "renderer-sensor-domain-processing-unavailable",
1212
+ message: "Requested fidelity requires renderer sensor-domain processing support."
1213
+ });
1214
+ }
1215
+ if (fidelity.rendererRequirements
1216
+ .depth === "per-layer" &&
1217
+ renderer.depthCapability !==
1218
+ "per-layer") {
1219
+ addBlocker(blockers, {
1220
+ code: "renderer-depth-capability-insufficient",
1221
+ message: "Requested fidelity requires per-layer depth capability."
1222
+ });
1223
+ }
1224
+ if (!renderer.inverseFieldMapping &&
1225
+ [...requiredStages].some((stageId) => stageId ===
1226
+ "lens-field-pupil-evaluation" ||
1227
+ stageId ===
1228
+ "field-wavelength-psf")) {
1229
+ addBlocker(blockers, {
1230
+ code: "renderer-inverse-field-mapping-required",
1231
+ message: "The requested lens/field plan requires inverse field mapping semantics."
1232
+ });
1233
+ }
1234
+ if (renderer.alphaRepresentation !==
1235
+ "premultiplied") {
1236
+ addBlocker(blockers, {
1237
+ code: "renderer-premultiplied-alpha-required",
1238
+ message: "The image-formation renderer contract requires premultiplied alpha."
1239
+ });
1240
+ }
1241
+ if (!renderer
1242
+ .preservesDepthOrderAcrossWarps) {
1243
+ addBlocker(blockers, {
1244
+ code: "renderer-depth-order-preservation-required",
1245
+ message: "The image-formation renderer contract requires depth-order preservation across warps."
1246
+ });
1247
+ }
1248
+ }
1249
+ function requestedEffectMap(fidelity) {
1250
+ return new Map(fidelity.requiredEffects.map((effect) => [
1251
+ effect.effectId,
1252
+ effect
1253
+ ]));
1254
+ }
1255
+ function hasActiveUndeclaredFieldThroughput(prepared, snapshot) {
1256
+ const sample = snapshot.physicalSceneSample;
1257
+ if (sample === undefined ||
1258
+ sample.fieldThroughput.kind ===
1259
+ "unity") {
1260
+ return false;
1261
+ }
1262
+ return !prepared.fidelity
1263
+ .requiredEffects.some((effect) => effect.effectId ===
1264
+ "illumination-vignetting");
1265
+ }
1266
+ function angularVelocityIsZero(velocity) {
1267
+ return (velocity.pitch === 0 &&
1268
+ velocity.yaw === 0 &&
1269
+ velocity.roll === 0);
1270
+ }
1271
+ function computeTemporalResult(prepared, snapshot, requiredStages, blockers) {
1272
+ if (!requiredStages.has("temporal-exposure-readout")) {
1273
+ return undefined;
1274
+ }
1275
+ const temporal = snapshot.temporalCapture;
1276
+ if (temporal === undefined) {
1277
+ addBlocker(blockers, {
1278
+ code: "missing-temporal-capture-input",
1279
+ stageId: "temporal-exposure-readout",
1280
+ message: "Temporal exposure/readout planning requires immutable temporal capture input."
1281
+ });
1282
+ return undefined;
1283
+ }
1284
+ const requestedEffects = requestedEffectMap(prepared.fidelity);
1285
+ if (requestedEffects.has("spatial-camera-rotation") &&
1286
+ temporal.rotation === undefined) {
1287
+ addBlocker(blockers, {
1288
+ code: "missing-camera-rotation-model",
1289
+ stageId: "temporal-exposure-readout",
1290
+ effectId: "spatial-camera-rotation",
1291
+ message: "Requested spatial camera rotation requires an explicit capture rotation model."
1292
+ });
1293
+ }
1294
+ if (requestedEffects.has("rolling-readout") &&
1295
+ temporal.readout === undefined) {
1296
+ addBlocker(blockers, {
1297
+ code: "missing-sensor-readout-timing",
1298
+ stageId: "temporal-exposure-readout",
1299
+ effectId: "rolling-readout",
1300
+ message: "Requested rolling-readout semantics require an explicit sensor readout declaration."
1301
+ });
1302
+ }
1303
+ const rotationRequested = requestedEffects.has("spatial-camera-rotation");
1304
+ if (rotationRequested &&
1305
+ temporal.rotation !== undefined) {
1306
+ const rendererTemporal = prepared.renderer
1307
+ .temporalSampling;
1308
+ if (rendererTemporal.kind ===
1309
+ "none" ||
1310
+ rendererTemporal
1311
+ .maximumSamples <
1312
+ temporal.rotation
1313
+ .temporalSampleCount) {
1314
+ addBlocker(blockers, {
1315
+ code: "renderer-temporal-sampling-insufficient",
1316
+ stageId: "temporal-exposure-readout",
1317
+ effectId: "spatial-camera-rotation",
1318
+ message: "Renderer temporal-sampling capability is insufficient for the committed rotation quadrature sample count."
1319
+ });
1320
+ }
1321
+ }
1322
+ try {
1323
+ const exposureWindows = calculateCaptureExposureWindows(temporal
1324
+ .exposureWindowInput).value;
1325
+ const sensorReadoutTiming = temporal.readout === undefined
1326
+ ? undefined
1327
+ : calculateSensorReadoutTiming({
1328
+ nativeRaster: temporal
1329
+ .exposureWindowInput
1330
+ .nativeRaster,
1331
+ ...(temporal
1332
+ .exposureWindowInput
1333
+ .activeCaptureRect ===
1334
+ undefined
1335
+ ? {}
1336
+ : {
1337
+ activeCaptureRect: temporal
1338
+ .exposureWindowInput
1339
+ .activeCaptureRect
1340
+ }),
1341
+ shutterMechanism: temporal
1342
+ .exposureWindowInput
1343
+ .shutterMechanism,
1344
+ readout: temporal.readout,
1345
+ ...(temporal
1346
+ .exposureWindowInput
1347
+ .samplePointsNative ===
1348
+ undefined
1349
+ ? {}
1350
+ : {
1351
+ samplePointsNative: temporal
1352
+ .exposureWindowInput
1353
+ .samplePointsNative
1354
+ })
1355
+ }).value;
1356
+ const rotationQuadrature = !rotationRequested ||
1357
+ temporal.rotation === undefined
1358
+ ? undefined
1359
+ : calculateCaptureRotationTemporalQuadrature({
1360
+ ...temporal
1361
+ .exposureWindowInput,
1362
+ imagingArea: temporal.imagingArea,
1363
+ focalLengthMm: prepared
1364
+ .equipmentCapabilities
1365
+ .selectedFocalLengthMm,
1366
+ ...(temporal.rotation
1367
+ .focusDistanceM ===
1368
+ undefined
1369
+ ? {}
1370
+ : {
1371
+ focusDistanceM: temporal.rotation
1372
+ .focusDistanceM
1373
+ }),
1374
+ angularVelocityRadPerSec: temporal.rotation
1375
+ .angularVelocityRadPerSec,
1376
+ orientation: temporal.orientation,
1377
+ temporalSampleCount: temporal.rotation
1378
+ .temporalSampleCount,
1379
+ samplePointsNative: temporal
1380
+ .exposureWindowInput
1381
+ .samplePointsNative
1382
+ }).value;
1383
+ return {
1384
+ exposureWindows,
1385
+ ...(sensorReadoutTiming ===
1386
+ undefined
1387
+ ? {}
1388
+ : {
1389
+ sensorReadoutTiming
1390
+ }),
1391
+ ...(rotationQuadrature ===
1392
+ undefined
1393
+ ? {}
1394
+ : {
1395
+ rotationQuadrature
1396
+ }),
1397
+ exposureTimeReference: "first-opening-boundary-phase",
1398
+ readoutExposureSynchronization: "not-assumed",
1399
+ sensorReadoutTimingRemainsSeparate: true,
1400
+ temporalRadianceIntegrated: false
1401
+ };
1402
+ }
1403
+ catch (error) {
1404
+ if (error instanceof
1405
+ InvalidConfigurationError ||
1406
+ error instanceof
1407
+ InvalidScientificInputError) {
1408
+ addBlocker(blockers, {
1409
+ code: "temporal-evaluation-blocked",
1410
+ stageId: "temporal-exposure-readout",
1411
+ message: error.message
1412
+ });
1413
+ return undefined;
1414
+ }
1415
+ throw error;
1416
+ }
1417
+ }
1418
+ function deriveEffectPlan(prepared, snapshot, temporalResult, blockers) {
1419
+ const contract = getImageFormationContract();
1420
+ const requested = requestedEffectMap(prepared.fidelity);
1421
+ const rendererEffects = new Set(prepared.renderer
1422
+ .supportedEffects);
1423
+ return contract
1424
+ .effectPlacements.map((placement) => {
1425
+ const request = requested.get(placement.id);
1426
+ if (request === undefined) {
1427
+ return {
1428
+ effectId: placement.id,
1429
+ primaryStage: placement.primaryStage,
1430
+ coupledStages: [
1431
+ ...placement
1432
+ .coupledStages
1433
+ ],
1434
+ state: "omitted-by-fidelity",
1435
+ scientificStatus: "not-applicable",
1436
+ requiredByFidelity: false,
1437
+ blockerCodes: []
1438
+ };
1439
+ }
1440
+ if (!COMPOSER_SUPPORTED_EFFECTS.has(placement.id)) {
1441
+ const blocker = {
1442
+ code: "engine-effect-not-composed",
1443
+ effectId: placement.id,
1444
+ message: "Production plan schema " +
1445
+ PRODUCTION_IMAGE_FORMATION_PLAN_VERSION +
1446
+ " does not yet compose required effect " +
1447
+ placement.id +
1448
+ "."
1449
+ };
1450
+ addBlocker(blockers, blocker);
1451
+ return {
1452
+ effectId: placement.id,
1453
+ primaryStage: placement.primaryStage,
1454
+ coupledStages: [
1455
+ ...placement
1456
+ .coupledStages
1457
+ ],
1458
+ state: "unsupported",
1459
+ scientificStatus: "not-applicable",
1460
+ requiredByFidelity: true,
1461
+ modelId: request.modelId,
1462
+ modelVersion: request.modelVersion,
1463
+ blockerCodes: [
1464
+ blocker.code
1465
+ ]
1466
+ };
1467
+ }
1468
+ if (!rendererEffects.has(placement.id)) {
1469
+ const blocker = {
1470
+ code: "renderer-effect-unsupported",
1471
+ effectId: placement.id,
1472
+ message: "Renderer does not declare support for required effect " +
1473
+ placement.id +
1474
+ "."
1475
+ };
1476
+ addBlocker(blockers, blocker);
1477
+ return {
1478
+ effectId: placement.id,
1479
+ primaryStage: placement.primaryStage,
1480
+ coupledStages: [
1481
+ ...placement
1482
+ .coupledStages
1483
+ ],
1484
+ state: "blocked",
1485
+ scientificStatus: "not-applicable",
1486
+ requiredByFidelity: true,
1487
+ modelId: request.modelId,
1488
+ modelVersion: request.modelVersion,
1489
+ blockerCodes: [
1490
+ blocker.code
1491
+ ]
1492
+ };
1493
+ }
1494
+ if (placement.id ===
1495
+ "illumination-vignetting") {
1496
+ const field = snapshot
1497
+ .physicalSceneSample
1498
+ ?.fieldThroughput;
1499
+ if (field === undefined) {
1500
+ const blocker = {
1501
+ code: "missing-physical-scene-sample",
1502
+ effectId: placement.id,
1503
+ message: "Illumination-vignetting planning requires a physical scene sample with explicit field throughput."
1504
+ };
1505
+ addBlocker(blockers, blocker);
1506
+ return {
1507
+ effectId: placement.id,
1508
+ primaryStage: placement.primaryStage,
1509
+ coupledStages: [],
1510
+ state: "blocked",
1511
+ scientificStatus: "not-applicable",
1512
+ requiredByFidelity: true,
1513
+ modelId: request.modelId,
1514
+ modelVersion: request.modelVersion,
1515
+ blockerCodes: [
1516
+ blocker.code
1517
+ ]
1518
+ };
1519
+ }
1520
+ const modeledZero = field.kind ===
1521
+ "unity" ||
1522
+ field.result
1523
+ .linearThroughputFactor ===
1524
+ 1;
1525
+ return {
1526
+ effectId: placement.id,
1527
+ primaryStage: placement.primaryStage,
1528
+ coupledStages: [],
1529
+ state: modeledZero
1530
+ ? "modeled-zero"
1531
+ : "active",
1532
+ scientificStatus: "approximation",
1533
+ requiredByFidelity: true,
1534
+ modelId: request.modelId,
1535
+ modelVersion: request.modelVersion,
1536
+ blockerCodes: []
1537
+ };
1538
+ }
1539
+ if (placement.id ===
1540
+ "spatial-camera-rotation") {
1541
+ const rotation = snapshot.temporalCapture
1542
+ ?.rotation;
1543
+ if (rotation === undefined) {
1544
+ const blocker = {
1545
+ code: "missing-camera-rotation-model",
1546
+ effectId: placement.id,
1547
+ stageId: "temporal-exposure-readout",
1548
+ message: "Spatial camera rotation requires committed rotation input."
1549
+ };
1550
+ addBlocker(blockers, blocker);
1551
+ return {
1552
+ effectId: placement.id,
1553
+ primaryStage: placement.primaryStage,
1554
+ coupledStages: [
1555
+ ...placement
1556
+ .coupledStages
1557
+ ],
1558
+ state: "blocked",
1559
+ scientificStatus: "not-applicable",
1560
+ requiredByFidelity: true,
1561
+ modelId: request.modelId,
1562
+ modelVersion: request.modelVersion,
1563
+ blockerCodes: [
1564
+ blocker.code
1565
+ ]
1566
+ };
1567
+ }
1568
+ const blocked = temporalResult
1569
+ ?.rotationQuadrature ===
1570
+ undefined &&
1571
+ !angularVelocityIsZero(rotation
1572
+ .angularVelocityRadPerSec);
1573
+ return {
1574
+ effectId: placement.id,
1575
+ primaryStage: placement.primaryStage,
1576
+ coupledStages: [
1577
+ ...placement
1578
+ .coupledStages
1579
+ ],
1580
+ state: blocked
1581
+ ? "blocked"
1582
+ : angularVelocityIsZero(rotation
1583
+ .angularVelocityRadPerSec)
1584
+ ? "modeled-zero"
1585
+ : "active",
1586
+ scientificStatus: blocked
1587
+ ? "not-applicable"
1588
+ : "approximation",
1589
+ requiredByFidelity: true,
1590
+ modelId: request.modelId,
1591
+ modelVersion: request.modelVersion,
1592
+ blockerCodes: blocked
1593
+ ? blockers
1594
+ .filter((blocker) => blocker.effectId ===
1595
+ placement.id ||
1596
+ blocker.stageId ===
1597
+ placement
1598
+ .primaryStage)
1599
+ .map((blocker) => blocker.code)
1600
+ : []
1601
+ };
1602
+ }
1603
+ if (placement.id ===
1604
+ "rolling-readout") {
1605
+ const timing = temporalResult
1606
+ ?.sensorReadoutTiming;
1607
+ if (timing === undefined) {
1608
+ const blocker = {
1609
+ code: "missing-sensor-readout-timing",
1610
+ effectId: placement.id,
1611
+ stageId: "temporal-exposure-readout",
1612
+ message: "Rolling-readout effect requires resolved sensor readout timing."
1613
+ };
1614
+ addBlocker(blockers, blocker);
1615
+ return {
1616
+ effectId: placement.id,
1617
+ primaryStage: placement.primaryStage,
1618
+ coupledStages: [
1619
+ ...placement
1620
+ .coupledStages
1621
+ ],
1622
+ state: "blocked",
1623
+ scientificStatus: "not-applicable",
1624
+ requiredByFidelity: true,
1625
+ modelId: request.modelId,
1626
+ modelVersion: request.modelVersion,
1627
+ blockerCodes: [
1628
+ blocker.code
1629
+ ]
1630
+ };
1631
+ }
1632
+ const modeledZero = timing.readoutMode ===
1633
+ "global" ||
1634
+ timing
1635
+ .maximumSpatialSamplingSkewSeconds ===
1636
+ 0;
1637
+ return {
1638
+ effectId: placement.id,
1639
+ primaryStage: placement.primaryStage,
1640
+ coupledStages: [
1641
+ ...placement
1642
+ .coupledStages
1643
+ ],
1644
+ state: modeledZero
1645
+ ? "modeled-zero"
1646
+ : "active",
1647
+ scientificStatus: "approximation",
1648
+ requiredByFidelity: true,
1649
+ modelId: request.modelId,
1650
+ modelVersion: request.modelVersion,
1651
+ blockerCodes: []
1652
+ };
1653
+ }
1654
+ throw new InvalidConfigurationError("Unexpected composed effect " +
1655
+ placement.id +
1656
+ ".");
1657
+ });
1658
+ }
1659
+ function computePhysicalResult(prepared, snapshot, requiredStages, blockers) {
1660
+ if (!requiredStages.has("lens-field-pupil-evaluation")) {
1661
+ return undefined;
1662
+ }
1663
+ if (prepared.opticalBridgeProfile ===
1664
+ undefined) {
1665
+ addBlocker(blockers, {
1666
+ code: "missing-optical-bridge-profile",
1667
+ stageId: "lens-field-pupil-evaluation",
1668
+ message: "Physical lens-throughput planning requires a prepared #110 optical bridge profile."
1669
+ });
1670
+ return undefined;
1671
+ }
1672
+ const sample = snapshot
1673
+ .physicalSceneSample;
1674
+ if (sample === undefined) {
1675
+ addBlocker(blockers, {
1676
+ code: "missing-physical-scene-sample",
1677
+ stageId: "lens-field-pupil-evaluation",
1678
+ message: "Physical lens-throughput planning requires one immutable scene-radiance/field sample."
1679
+ });
1680
+ return undefined;
1681
+ }
1682
+ if (hasActiveUndeclaredFieldThroughput(prepared, snapshot)) {
1683
+ addBlocker(blockers, {
1684
+ code: "undeclared-field-throughput-effect",
1685
+ stageId: "lens-field-pupil-evaluation",
1686
+ effectId: "illumination-vignetting",
1687
+ message: "A non-unity field-throughput input was supplied without requesting illumination-vignetting in the fidelity profile."
1688
+ });
1689
+ return undefined;
1690
+ }
1691
+ try {
1692
+ return calculateSceneRadianceToSensorIrradiance({
1693
+ sceneRadianceRequest: sample
1694
+ .sceneRadianceRequest,
1695
+ sceneRadianceResult: sample
1696
+ .sceneRadianceResult,
1697
+ profile: prepared
1698
+ .opticalBridgeProfile,
1699
+ focalLengthMm: prepared
1700
+ .equipmentCapabilities
1701
+ .selectedFocalLengthMm,
1702
+ nominalFNumber: snapshot.exposure
1703
+ .aperture,
1704
+ focus: sample.focus,
1705
+ imagePointMm: sample.imagePointMm,
1706
+ fieldThroughput: sample.fieldThroughput,
1707
+ ...(sample.frontOfLensFilters ===
1708
+ undefined
1709
+ ? {}
1710
+ : {
1711
+ frontOfLensFilters: sample.frontOfLensFilters
1712
+ })
1713
+ }).value;
1714
+ }
1715
+ catch (error) {
1716
+ if (error instanceof
1717
+ InvalidConfigurationError ||
1718
+ error instanceof
1719
+ InvalidScientificInputError) {
1720
+ addBlocker(blockers, {
1721
+ code: "physical-radiometry-evaluation-blocked",
1722
+ stageId: "lens-field-pupil-evaluation",
1723
+ message: error.message
1724
+ });
1725
+ return undefined;
1726
+ }
1727
+ throw error;
1728
+ }
1729
+ }
1730
+ function deriveStagePlan(prepared, snapshot, requiredStages, physicalResult, temporalResult, blockers, processedResult, environmentResult, environmentRequested = false) {
1731
+ const contract = getImageFormationContract();
1732
+ const rendererStages = new Set(prepared.renderer
1733
+ .supportedStages);
1734
+ return contract.stages.map((stage) => {
1735
+ if (!requiredStages.has(stage.id)) {
1736
+ return {
1737
+ stageId: stage.id,
1738
+ contractStatus: stage.status,
1739
+ state: "omitted-by-fidelity",
1740
+ scientificStatus: "not-applicable",
1741
+ requiredByFidelity: false,
1742
+ requiredUpstreamStages: [
1743
+ ...stage
1744
+ .requiredUpstreamStages
1745
+ ],
1746
+ coupledStages: [
1747
+ ...stage.coupledStages
1748
+ ],
1749
+ blockerCodes: []
1750
+ };
1751
+ }
1752
+ const stageBlockers = [];
1753
+ if (environmentRequested && environmentResult === undefined) {
1754
+ return { stageId: stage.id, contractStatus: stage.status, state: "blocked",
1755
+ scientificStatus: "not-applicable", requiredByFidelity: true,
1756
+ requiredUpstreamStages: [...stage.requiredUpstreamStages], coupledStages: [...stage.coupledStages],
1757
+ blockerCodes: ["environment-capture-evaluation-blocked"] };
1758
+ }
1759
+ if (environmentResult !== undefined && !PROCESSED_OUTPUT_STAGES.has(stage.id)) {
1760
+ const supported = rendererStages.has(stage.id);
1761
+ const psfOmitted = stage.id === "field-wavelength-psf" &&
1762
+ environmentResult.value.sites.every(site => !site.value.psfRedistributionApplied);
1763
+ if (!supported)
1764
+ addBlocker(blockers, { code: "renderer-stage-unsupported", stageId: stage.id,
1765
+ message: "Renderer does not declare the executed environment stage " + stage.id + "." });
1766
+ return { stageId: stage.id, contractStatus: stage.status,
1767
+ state: !supported ? "blocked" : psfOmitted ? "modeled-zero" : "active",
1768
+ scientificStatus: supported ? "approximation" : "not-applicable",
1769
+ requiredByFidelity: true, requiredUpstreamStages: [...stage.requiredUpstreamStages],
1770
+ coupledStages: [...stage.coupledStages], modelId: "environment-native-raw-producer", modelVersion: "0.1.0",
1771
+ resultIdentity: environmentResult.value.raw.value.frame.frameId,
1772
+ blockerCodes: supported ? [] : ["renderer-stage-unsupported"] };
1773
+ }
1774
+ if (processedResult !== undefined && PROCESSED_OUTPUT_STAGES.has(stage.id)) {
1775
+ const supported = rendererStages.has(stage.id);
1776
+ if (!supported)
1777
+ addBlocker(blockers, { code: "renderer-stage-unsupported", stageId: stage.id,
1778
+ message: "Renderer does not declare support for processed output stage " + stage.id + "." });
1779
+ return { stageId: stage.id, contractStatus: stage.status, state: supported ? "active" : "blocked",
1780
+ scientificStatus: supported ? "approximation" : "not-applicable", requiredByFidelity: true,
1781
+ requiredUpstreamStages: [...stage.requiredUpstreamStages], coupledStages: [...stage.coupledStages],
1782
+ modelId: "processed-sensor-raw-sdr", modelVersion: "0.1.0",
1783
+ resultIdentity: processedResult.value.source.value.rawFrame.frameId,
1784
+ blockerCodes: supported ? [] : ["renderer-stage-unsupported"] };
1785
+ }
1786
+ if (!COMPOSER_SUPPORTED_STAGES.has(stage.id)) {
1787
+ const blocker = {
1788
+ code: "engine-stage-not-composed",
1789
+ stageId: stage.id,
1790
+ message: "Production plan schema " +
1791
+ PRODUCTION_IMAGE_FORMATION_PLAN_VERSION +
1792
+ " does not yet compose required stage " +
1793
+ stage.id +
1794
+ "."
1795
+ };
1796
+ addBlocker(blockers, blocker);
1797
+ stageBlockers.push(blocker.code);
1798
+ return {
1799
+ stageId: stage.id,
1800
+ contractStatus: stage.status,
1801
+ state: "unsupported",
1802
+ scientificStatus: "not-applicable",
1803
+ requiredByFidelity: true,
1804
+ requiredUpstreamStages: [
1805
+ ...stage
1806
+ .requiredUpstreamStages
1807
+ ],
1808
+ coupledStages: [
1809
+ ...stage.coupledStages
1810
+ ],
1811
+ blockerCodes: stageBlockers
1812
+ };
1813
+ }
1814
+ if (!rendererStages.has(stage.id)) {
1815
+ const blocker = {
1816
+ code: "renderer-stage-unsupported",
1817
+ stageId: stage.id,
1818
+ message: "Renderer does not declare support for required stage " +
1819
+ stage.id +
1820
+ "."
1821
+ };
1822
+ addBlocker(blockers, blocker);
1823
+ stageBlockers.push(blocker.code);
1824
+ }
1825
+ if (stage.id ===
1826
+ "lens-field-pupil-evaluation" &&
1827
+ physicalResult ===
1828
+ undefined) {
1829
+ const relevant = blockers
1830
+ .filter((blocker) => blocker.stageId ===
1831
+ stage.id)
1832
+ .map((blocker) => blocker.code);
1833
+ stageBlockers.push(...relevant);
1834
+ }
1835
+ if (stageBlockers.length > 0) {
1836
+ return {
1837
+ stageId: stage.id,
1838
+ contractStatus: stage.status,
1839
+ state: "blocked",
1840
+ scientificStatus: "not-applicable",
1841
+ requiredByFidelity: true,
1842
+ requiredUpstreamStages: [
1843
+ ...stage
1844
+ .requiredUpstreamStages
1845
+ ],
1846
+ coupledStages: [
1847
+ ...stage.coupledStages
1848
+ ],
1849
+ blockerCodes: [
1850
+ ...new Set(stageBlockers)
1851
+ ]
1852
+ };
1853
+ }
1854
+ if (stage.id ===
1855
+ "scene-ray-projection") {
1856
+ const target = snapshot
1857
+ .physicalSceneSample
1858
+ ?.sceneRadianceRequest
1859
+ .target;
1860
+ const modeledZero = target?.kind ===
1861
+ "environment-direction";
1862
+ return {
1863
+ stageId: stage.id,
1864
+ contractStatus: stage.status,
1865
+ state: modeledZero
1866
+ ? "modeled-zero"
1867
+ : "active",
1868
+ scientificStatus: "approximation",
1869
+ requiredByFidelity: true,
1870
+ requiredUpstreamStages: [],
1871
+ coupledStages: [
1872
+ ...stage.coupledStages
1873
+ ],
1874
+ modelId: "capture-bound-scene-ray-target",
1875
+ modelVersion: "1.0.0",
1876
+ resultIdentity: target?.kind ??
1877
+ "unresolved-target",
1878
+ blockerCodes: []
1879
+ };
1880
+ }
1881
+ if (stage.id ===
1882
+ "scene-radiance-evaluation") {
1883
+ const sample = snapshot
1884
+ .physicalSceneSample;
1885
+ if (sample === undefined) {
1886
+ const blocker = {
1887
+ code: "missing-physical-scene-sample",
1888
+ stageId: stage.id,
1889
+ message: "Scene-radiance stage requires one immutable #85 request/result sample."
1890
+ };
1891
+ addBlocker(blockers, blocker);
1892
+ return {
1893
+ stageId: stage.id,
1894
+ contractStatus: stage.status,
1895
+ state: "blocked",
1896
+ scientificStatus: "not-applicable",
1897
+ requiredByFidelity: true,
1898
+ requiredUpstreamStages: [
1899
+ ...stage
1900
+ .requiredUpstreamStages
1901
+ ],
1902
+ coupledStages: [
1903
+ ...stage
1904
+ .coupledStages
1905
+ ],
1906
+ blockerCodes: [
1907
+ blocker.code
1908
+ ]
1909
+ };
1910
+ }
1911
+ return {
1912
+ stageId: stage.id,
1913
+ contractStatus: stage.status,
1914
+ state: "active",
1915
+ scientificStatus: "approximation",
1916
+ requiredByFidelity: true,
1917
+ requiredUpstreamStages: [
1918
+ ...stage
1919
+ .requiredUpstreamStages
1920
+ ],
1921
+ coupledStages: [
1922
+ ...stage.coupledStages
1923
+ ],
1924
+ modelId: "scene-radiance-provider-result",
1925
+ modelVersion: sample
1926
+ .sceneRadianceResult
1927
+ .schemaVersion,
1928
+ resultIdentity: sample
1929
+ .sceneRadianceResult
1930
+ .sampleId,
1931
+ blockerCodes: []
1932
+ };
1933
+ }
1934
+ if (stage.id ===
1935
+ "lens-field-pupil-evaluation") {
1936
+ const result = physicalResult;
1937
+ return {
1938
+ stageId: stage.id,
1939
+ contractStatus: stage.status,
1940
+ state: "active",
1941
+ scientificStatus: result.scientificStatus,
1942
+ requiredByFidelity: true,
1943
+ requiredUpstreamStages: [
1944
+ ...stage
1945
+ .requiredUpstreamStages
1946
+ ],
1947
+ coupledStages: [
1948
+ ...stage.coupledStages
1949
+ ],
1950
+ modelId: "scene-radiance-to-sensor-irradiance",
1951
+ modelVersion: "1.0.0",
1952
+ resultIdentity: result.sampleId,
1953
+ blockerCodes: []
1954
+ };
1955
+ }
1956
+ if (stage.id ===
1957
+ "temporal-exposure-readout") {
1958
+ if (temporalResult === undefined) {
1959
+ const relevant = blockers
1960
+ .filter((blocker) => blocker.stageId ===
1961
+ stage.id)
1962
+ .map((blocker) => blocker.code);
1963
+ return {
1964
+ stageId: stage.id,
1965
+ contractStatus: stage.status,
1966
+ state: "blocked",
1967
+ scientificStatus: "not-applicable",
1968
+ requiredByFidelity: true,
1969
+ requiredUpstreamStages: [
1970
+ ...stage
1971
+ .requiredUpstreamStages
1972
+ ],
1973
+ coupledStages: [
1974
+ ...stage.coupledStages
1975
+ ],
1976
+ modelId: "capture-temporal-schedule",
1977
+ modelVersion: "1.0.0",
1978
+ blockerCodes: [
1979
+ ...new Set(relevant)
1980
+ ]
1981
+ };
1982
+ }
1983
+ return {
1984
+ stageId: stage.id,
1985
+ contractStatus: stage.status,
1986
+ state: "active",
1987
+ scientificStatus: "approximation",
1988
+ requiredByFidelity: true,
1989
+ requiredUpstreamStages: [
1990
+ ...stage
1991
+ .requiredUpstreamStages
1992
+ ],
1993
+ coupledStages: [
1994
+ ...stage.coupledStages
1995
+ ],
1996
+ modelId: "capture-temporal-schedule",
1997
+ modelVersion: "1.0.0",
1998
+ resultIdentity: snapshot
1999
+ .fingerprint.value,
2000
+ blockerCodes: []
2001
+ };
2002
+ }
2003
+ throw new InvalidConfigurationError("Unexpected composed stage.");
2004
+ });
2005
+ }
2006
+ function toAssuranceUncertainty(uncertainty) {
2007
+ if (uncertainty.kind ===
2008
+ "relative") {
2009
+ return {
2010
+ kind: "relative",
2011
+ fraction: uncertainty.fraction,
2012
+ basis: uncertainty.basis
2013
+ };
2014
+ }
2015
+ return {
2016
+ kind: "not-quantified",
2017
+ limitation: uncertainty.limitation
2018
+ };
2019
+ }
2020
+ function physicalAssuranceComponents(prepared, snapshot, physicalResult) {
2021
+ const sample = snapshot.physicalSceneSample;
2022
+ const optical = prepared.opticalBridgeProfile;
2023
+ if (sample === undefined ||
2024
+ optical === undefined) {
2025
+ throw new InvalidConfigurationError("Physical scientific assurance requires the committed physical sample and optical profile.");
2026
+ }
2027
+ const components = [
2028
+ {
2029
+ componentId: "scene-radiance",
2030
+ role: "outgoing scene spectral radiance",
2031
+ required: true,
2032
+ sourceIdentity: {
2033
+ kind: "result",
2034
+ id: sample
2035
+ .sceneRadianceResult
2036
+ .sampleId,
2037
+ version: sample
2038
+ .sceneRadianceResult
2039
+ .schemaVersion
2040
+ },
2041
+ basisKind: "evidence-backed-fact",
2042
+ scientificStatus: sample
2043
+ .sceneRadianceResult
2044
+ .scientificStatus,
2045
+ evidenceRequirement: "required",
2046
+ evidence: sample
2047
+ .sceneRadianceResult
2048
+ .evidence,
2049
+ uncertainty: toAssuranceUncertainty(sample
2050
+ .sceneRadianceResult
2051
+ .uncertainty),
2052
+ limitations: [
2053
+ ...sample
2054
+ .sceneRadianceResult
2055
+ .limitations
2056
+ ]
2057
+ },
2058
+ {
2059
+ componentId: "optical-throughput-profile",
2060
+ role: "lens throughput and working-aperture profile",
2061
+ required: true,
2062
+ sourceIdentity: {
2063
+ kind: "profile",
2064
+ id: optical.profileId,
2065
+ version: optical.profileVersion
2066
+ },
2067
+ basisKind: "evidence-backed-fact",
2068
+ scientificStatus: optical
2069
+ .scientificStatus,
2070
+ evidenceRequirement: "required",
2071
+ evidence: [
2072
+ ...physicalResult
2073
+ .componentEvidence
2074
+ .opticalProfile,
2075
+ ...physicalResult
2076
+ .componentEvidence
2077
+ .transmission,
2078
+ ...physicalResult
2079
+ .componentEvidence
2080
+ .workingFNumber
2081
+ ],
2082
+ uncertainty: toAssuranceUncertainty(optical
2083
+ .transmission
2084
+ .uncertainty),
2085
+ limitations: [
2086
+ ...optical.limitations
2087
+ ]
2088
+ },
2089
+ {
2090
+ componentId: "primary-optics-bridge-model",
2091
+ role: "scene-radiance to pre-sensor-stack irradiance composition model",
2092
+ required: true,
2093
+ sourceIdentity: {
2094
+ kind: "model",
2095
+ id: "scene-radiance-to-sensor-irradiance",
2096
+ version: "1.1.0"
2097
+ },
2098
+ basisKind: "photivra-model-assumption",
2099
+ scientificStatus: "approximation",
2100
+ evidenceRequirement: "not-required",
2101
+ evidence: [],
2102
+ uncertainty: {
2103
+ kind: "not-quantified",
2104
+ limitation: "The paraxial primary-optics bridge is an explicit approximation with no defensible aggregate model-error bound yet."
2105
+ },
2106
+ limitations: [
2107
+ "Paraxial circular-pupil acceptance is not a full ray-traced pupil solution.",
2108
+ "PSF redistribution, sensor optical-stack response and polarization remain outside this bridge."
2109
+ ]
2110
+ }
2111
+ ];
2112
+ for (let index = 0; index <
2113
+ (sample.frontOfLensFilters
2114
+ ?.length ?? 0); index += 1) {
2115
+ const profile = sample
2116
+ .frontOfLensFilters[index];
2117
+ const resolved = resolveFrontOfLensFilterTransmission({
2118
+ profile,
2119
+ wavelengthNanometers: physicalResult
2120
+ .wavelengthNanometers,
2121
+ wavelengthBasis: physicalResult
2122
+ .wavelengthBasis
2123
+ });
2124
+ components.push({
2125
+ componentId: "front-filter:" +
2126
+ index,
2127
+ role: "front-of-lens transmission filter",
2128
+ required: true,
2129
+ sourceIdentity: {
2130
+ kind: "profile",
2131
+ id: resolved.filterId,
2132
+ version: resolved.profileVersion
2133
+ },
2134
+ basisKind: "evidence-backed-fact",
2135
+ scientificStatus: resolved
2136
+ .scientificStatus,
2137
+ evidenceRequirement: "required",
2138
+ evidence: resolved.evidence,
2139
+ uncertainty: toAssuranceUncertainty(resolved.uncertainty),
2140
+ limitations: [
2141
+ ...resolved.limitations
2142
+ ]
2143
+ });
2144
+ }
2145
+ if (sample.fieldThroughput.kind !==
2146
+ "unity") {
2147
+ components.push({
2148
+ componentId: "field-throughput-model",
2149
+ role: "field-dependent illumination throughput",
2150
+ required: true,
2151
+ sourceIdentity: {
2152
+ kind: "model",
2153
+ id: "generic-illumination-vignetting",
2154
+ version: "1.0.0"
2155
+ },
2156
+ basisKind: "photivra-model-assumption",
2157
+ scientificStatus: "approximation",
2158
+ evidenceRequirement: "not-required",
2159
+ evidence: [],
2160
+ uncertainty: {
2161
+ kind: "not-quantified",
2162
+ limitation: "The capture snapshot retains the evaluated vignetting value but not the source CalculationResult quality envelope; no numeric uncertainty is inferred."
2163
+ },
2164
+ limitations: [
2165
+ "Field-throughput model status remains separate from lens transmission and front-filter transmission.",
2166
+ "Future capture contracts must explicitly preserve source quality if calibrated field-throughput uncertainty is required downstream."
2167
+ ]
2168
+ });
2169
+ }
2170
+ return components;
2171
+ }
2172
+ function temporalAssuranceComponent(snapshot) {
2173
+ return {
2174
+ componentId: "temporal-capture-schedule",
2175
+ role: "capture exposure/readout temporal composition",
2176
+ required: true,
2177
+ sourceIdentity: {
2178
+ kind: "model",
2179
+ id: "capture-temporal-schedule",
2180
+ version: "1.0.0"
2181
+ },
2182
+ basisKind: "photivra-model-assumption",
2183
+ scientificStatus: "approximation",
2184
+ evidenceRequirement: "not-required",
2185
+ evidence: [],
2186
+ uncertainty: {
2187
+ kind: "not-quantified",
2188
+ limitation: "Temporal schedule composition preserves declared timing facts but does not claim a generic aggregate timing/model uncertainty."
2189
+ },
2190
+ limitations: [
2191
+ "Readout/exposure synchronization is not assumed unless explicitly modeled.",
2192
+ "Renderer execution timing does not redefine the committed capture schedule.",
2193
+ "Capture identity " +
2194
+ snapshot.captureId +
2195
+ " owns the committed temporal state."
2196
+ ]
2197
+ };
2198
+ }
2199
+ /**
2200
+ * Compose evidence/status from actual child stages without averaging uncertainty
2201
+ * or upgrading declared approximation to calibration. Requested blockers and
2202
+ * executed lineage are part of assurance; a complete graph alone cannot establish
2203
+ * physical accuracy or validate an external provider's numerical transport.
2204
+ */
2205
+ function composeProductionScientificAssurance(prepared, snapshot, physicalResult, temporalResult, processedResult, environmentResult) {
2206
+ const components = [];
2207
+ if (physicalResult !== undefined) {
2208
+ components.push(...physicalAssuranceComponents(prepared, snapshot, physicalResult));
2209
+ }
2210
+ if (temporalResult !== undefined) {
2211
+ components.push(temporalAssuranceComponent(snapshot));
2212
+ }
2213
+ if (environmentResult !== undefined) {
2214
+ components.push({ componentId: "environment-native-raw-producer", role: "bounded executed environment-to-ADC capture", required: true,
2215
+ sourceIdentity: { kind: "model", id: "environment-native-raw-producer", version: "0.1.0" },
2216
+ basisKind: "photivra-model-assumption", scientificStatus: "approximation", evidenceRequirement: "required",
2217
+ evidence: environmentResult.value.sceneBinding.evidence,
2218
+ uncertainty: { kind: "not-quantified", limitation: "Child source, optical, response and readout uncertainty is not propagated into a combined capture uncertainty." },
2219
+ limitations: ["Provider code executes, but transport, visibility and calibrated source truth remain unverified.",
2220
+ "Destination-local PSF and explicitly bounded native sampling do not establish global energy conservation or high-resolution performance."] });
2221
+ }
2222
+ if (processedResult !== undefined) {
2223
+ components.push({ componentId: "processed-sensor-raw-sdr", role: "committed post-capture SDR development", required: true,
2224
+ sourceIdentity: { kind: "model", id: "processed-sensor-raw-sdr", version: "0.1.0" }, basisKind: "photivra-model-assumption",
2225
+ scientificStatus: "approximation", evidenceRequirement: "required", evidence: processedResult.value.colorProfile.evidence,
2226
+ uncertainty: { kind: "not-quantified", limitation: "Reconstruction, color interpretation and optional correction uncertainty are not propagated into a combined output uncertainty." },
2227
+ limitations: [...processedResult.value.colorProfile.limitations,
2228
+ environmentResult === undefined ? "Attached RAW origin is declared; downstream execution does not verify missing upstream production stages." :
2229
+ "RAW origin is executed by this bounded plan; provider transport and calibrated accuracy remain unverified.",
2230
+ "SDR rendering is a deterministic rendering choice; platform viewing adaptation is external."] });
2231
+ }
2232
+ if (components.length === 0) {
2233
+ return undefined;
2234
+ }
2235
+ return composeScientificAssurance({
2236
+ components
2237
+ });
2238
+ }
2239
+ /** Check immutable event ownership before source code or downstream pixel work. */
2240
+ function validateProductionRawCapture(capture, snapshot, label = "Processed RAW") {
2241
+ if (capture.captureId !== snapshot.captureId || capture.sceneStateId !== snapshot.sceneStateId ||
2242
+ capture.sceneTimeSeconds !== snapshot.sceneTimeSecondsFromExposureStart || capture.noise.seedUint32 !== snapshot.stochasticSeedUint32 ||
2243
+ capture.exposure.aperture !== snapshot.exposure.aperture || capture.exposure.shutterSeconds !== snapshot.exposure.shutterSeconds || capture.exposure.iso !== snapshot.exposure.iso ||
2244
+ (capture.whiteBalanceIntent?.stateId !== snapshot.whiteBalanceState?.stateId) ||
2245
+ (capture.whiteBalanceIntent !== null && ["red", "green", "blue"].some((channel) => capture.whiteBalanceIntent.channelGains[channel] !== snapshot.whiteBalanceState?.channelGains[channel]))) {
2246
+ throw new InvalidConfigurationError(label + " capture identity, scene clock, seed, exposure or WB differs from the immutable production snapshot.");
2247
+ }
2248
+ const releaseFocus = snapshot.releaseFrameBinding?.focus;
2249
+ if (releaseFocus !== undefined && (releaseFocus.kind !== capture.focus.kind ||
2250
+ (releaseFocus.kind === "finite" && capture.focus.kind === "finite" && releaseFocus.distanceM !== capture.focus.distanceM))) {
2251
+ throw new InvalidConfigurationError(label + " focus differs from the committed release frame.");
2252
+ }
2253
+ if (snapshot.physicalSceneSample !== undefined && !releaseFocusMatchesOpticalFocus(capture.focus, snapshot.physicalSceneSample.focus)) {
2254
+ throw new InvalidConfigurationError(label + " focus differs from the committed optical sample.");
2255
+ }
2256
+ }
2257
+ /** Execute the committed post-capture boundary without blessing absent upstream stages. */
2258
+ function computeProcessedOutput(input, prepared, snapshot, required, blockers) {
2259
+ if (input === undefined)
2260
+ return undefined;
2261
+ try {
2262
+ const declaration = requireRecord(input, "processedOutput");
2263
+ if (Object.keys(declaration).some(key => key !== "outputStateId" && key !== "processing"))
2264
+ throw new InvalidConfigurationError("Unknown processed output declaration fields.");
2265
+ if (!required.has("display-processing") || !prepared.renderer.sensorDomainProcessing)
2266
+ throw new InvalidConfigurationError("Processed RAW requires requested display processing and renderer sensor-domain support.");
2267
+ if (input.outputStateId !== snapshot.outputStateId)
2268
+ throw new InvalidConfigurationError("Processed RAW output state differs from the immutable production snapshot.");
2269
+ const result = calculateProcessedSensorRaw(input.processing), capture = result.value.source.value.rawFrame.capture;
2270
+ validateProductionRawCapture(capture, snapshot);
2271
+ return result;
2272
+ }
2273
+ catch (error) {
2274
+ if (!(error instanceof InvalidConfigurationError || error instanceof InvalidScientificInputError))
2275
+ throw error;
2276
+ addBlocker(blockers, { code: "processed-output-evaluation-blocked", stageId: "display-processing", message: error.message });
2277
+ return undefined;
2278
+ }
2279
+ }
2280
+ /**
2281
+ * Commit the execution envelope before invoking supplied provider code. A failed
2282
+ * preflight returns a structured blocker and never invokes that code. The existing
2283
+ * environment producer owns all node budgets, response validity and seeded RAW.
2284
+ */
2285
+ /**
2286
+ * Validate shared capture/context, renderer and supported-envelope commitments
2287
+ * before any trusted provider callback runs. Snapshot owned scientific and output
2288
+ * policy data first, then delegate to the one existing environment RAW producer.
2289
+ * Callback failure propagates; a successful call proves invocation and data binding,
2290
+ * not physical transport, visibility, calibration or a fallback renderer.
2291
+ */
2292
+ function computeEnvironmentCapture(input, externalOutput, prepared, snapshot, required, blockers) {
2293
+ if (input === undefined)
2294
+ return undefined;
2295
+ try {
2296
+ const declaration = requireRecord(input, "environmentCapture");
2297
+ if (Object.keys(declaration).some(key => key !== "capture" && key !== "processing")) {
2298
+ throw new InvalidConfigurationError("Unknown environment capture declaration fields.");
2299
+ }
2300
+ if (externalOutput !== undefined || snapshot.physicalSceneSample !== undefined) {
2301
+ throw new InvalidConfigurationError("Executed environment capture cannot mix declared scene samples or external RAW output sources.");
2302
+ }
2303
+ const { evaluateRadiance, ...data } = input.capture;
2304
+ const owned = structuredClone(data);
2305
+ const capture = parseSimulatedCapture(owned.frame.capture);
2306
+ validateProductionRawCapture(capture, snapshot, "Production RAW");
2307
+ if (!required.has("adc-quantization") || !prepared.renderer.sensorDomainProcessing ||
2308
+ prepared.renderer.spectralCapability !== "wavelength-resolved" ||
2309
+ [...required].some(stage => !prepared.renderer.supportedStages.includes(stage))) {
2310
+ throw new InvalidConfigurationError("Executed environment capture requires the complete requested ADC graph and renderer stage/spectral/sensor support.");
2311
+ }
2312
+ if (blockers.length !== 0)
2313
+ throw new InvalidConfigurationError("Environment execution is blocked by production renderer or temporal preflight.");
2314
+ if (input.processing !== undefined) {
2315
+ validateProcessedSensorRawEnvelope({ rawFrame: { capture }, region: input.processing.reconstruction.region }, input.processing.correction !== undefined);
2316
+ }
2317
+ const temporal = snapshot.temporalCapture;
2318
+ if (temporal === undefined)
2319
+ throw new InvalidConfigurationError("Environment execution requires committed temporal capture input.");
2320
+ const { nativeRaster, samplePointsNative: _, activeCaptureRect, ...schedule } = temporal.exposureWindowInput;
2321
+ void _;
2322
+ if (canonicalStringify(schedule) !== canonicalStringify(owned.exposureWindow) ||
2323
+ canonicalStringify(nativeRaster) !== canonicalStringify(capture.geometry.nativeRaster) ||
2324
+ canonicalStringify(temporal.imagingArea) !== canonicalStringify(capture.geometry.imagingArea) ||
2325
+ temporal.orientation !== capture.geometry.orientation ||
2326
+ (activeCaptureRect !== undefined && canonicalStringify(activeCaptureRect) !== canonicalStringify({ x: 0, y: 0,
2327
+ width: capture.geometry.nativeRaster.pixelWidth, height: capture.geometry.nativeRaster.pixelHeight })) ||
2328
+ capture.exposure.focalLengthMm !== prepared.equipmentCapabilities.selectedFocalLengthMm ||
2329
+ owned.sceneBinding.providerSceneId !== prepared.sceneId) {
2330
+ throw new InvalidConfigurationError("Environment geometry, scene, focal length and shutter schedule differ from the committed production context.");
2331
+ }
2332
+ const rendererTemporal = prepared.renderer.temporalSampling;
2333
+ for (const site of owned.sites) {
2334
+ const e = site.environment;
2335
+ if (e.sceneBindings.providerProfile.profileId !== prepared.sceneRadianceProviderProfileId ||
2336
+ canonicalStringify(e.optics.profile) !== canonicalStringify(prepared.opticalBridgeProfile) ||
2337
+ rendererTemporal.kind !== "bounded" || e.temporalSampleCount > rendererTemporal.maximumSamples ||
2338
+ (temporal.rotation === undefined && !angularVelocityIsZero(e.motion.angularVelocityRadPerSec)) ||
2339
+ (temporal.rotation !== undefined && (canonicalStringify(e.motion.angularVelocityRadPerSec) !== canonicalStringify(temporal.rotation.angularVelocityRadPerSec) ||
2340
+ e.temporalSampleCount !== temporal.rotation.temporalSampleCount ||
2341
+ (capture.focus.kind === "finite" ? capture.focus.distanceM : undefined) !== temporal.rotation.focusDistanceM))) {
2342
+ throw new InvalidConfigurationError("Environment provider, optics, motion or temporal sampling differs from the committed production context.");
2343
+ }
2344
+ }
2345
+ const requestFingerprint = fingerprintValue(owned);
2346
+ return { result: simulateEnvironmentSensorRawFrame({ ...owned, evaluateRadiance }), requestFingerprint };
2347
+ }
2348
+ catch (error) {
2349
+ if (!(error instanceof InvalidConfigurationError || error instanceof InvalidScientificInputError))
2350
+ throw error;
2351
+ addBlocker(blockers, { code: "environment-capture-evaluation-blocked", stageId: "adc-quantization", message: error.message });
2352
+ return undefined;
2353
+ }
2354
+ }
2355
+ /**
2356
+ * Expand requested stages through the authoritative graph, validate shared commitments and capability
2357
+ * limits, then execute only supported declared input routes. Return explicit
2358
+ * active/zero/omitted/blocked dispositions and child evidence rather than silently skipping a
2359
+ * requested effect.
2360
+ *
2361
+ * The planner owns scientific stage ordering, immutable capture identity and reproducibility.
2362
+ * Well-formed unsupported combinations produce structured blockers; malformed declarations throw. The
2363
+ * bounded environment route executes supplied radiance through native RAW and optional output, while
2364
+ * sample-only and attached-RAW routes retain missing upstream blockers. FNV fingerprints are
2365
+ * reproducibility keys, not cryptographic integrity proofs.
2366
+ * @param input - CreateProductionImageFormationPlanInput. See the linked contract for coordinate, unit and profile binding semantics.
2367
+ * @returns ProductionImageFormationPlan. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
2368
+ *
2369
+ * @see docs/API_REFERENCE.md for the root export and exact type graph.
2370
+ */
2371
+ export function createProductionImageFormationPlan(input) {
2372
+ const prepared = parsePreparedImageFormationContext(input.preparedContext);
2373
+ const snapshot = parseProductionCaptureSnapshot(input.captureSnapshot);
2374
+ validateSnapshotAgainstContext(prepared, snapshot);
2375
+ const requiredStages = expandRequiredStages(prepared.fidelity);
2376
+ const blockers = [];
2377
+ evaluateRendererRequirements(prepared, requiredStages, blockers);
2378
+ const physicalResult = input.environmentCapture !== undefined ? undefined :
2379
+ computePhysicalResult(prepared, snapshot, requiredStages, blockers);
2380
+ const temporalResult = computeTemporalResult(prepared, snapshot, requiredStages, blockers);
2381
+ const effectPlan = deriveEffectPlan(prepared, snapshot, temporalResult, blockers);
2382
+ // Snapshot post-capture policy before a provider can mutate caller-owned state.
2383
+ const environmentProcessing = input.environmentCapture?.processing === undefined ? undefined :
2384
+ structuredClone(input.environmentCapture.processing);
2385
+ const environmentExecution = computeEnvironmentCapture(input.environmentCapture, input.processedOutput, prepared, snapshot, requiredStages, blockers);
2386
+ const environmentCaptureResult = environmentExecution?.result;
2387
+ const executedOutput = environmentCaptureResult === undefined || environmentProcessing === undefined ? undefined : {
2388
+ outputStateId: snapshot.outputStateId,
2389
+ processing: { ...environmentProcessing, reconstruction: { ...environmentProcessing.reconstruction,
2390
+ rawFrame: environmentCaptureResult.value.raw.value.frame } }
2391
+ };
2392
+ const processedOutputResult = computeProcessedOutput(input.environmentCapture === undefined ? input.processedOutput : executedOutput, prepared, snapshot, requiredStages, blockers);
2393
+ const scientificAssurance = composeProductionScientificAssurance(prepared, snapshot, physicalResult, temporalResult, processedOutputResult, environmentCaptureResult);
2394
+ const stagePlan = deriveStagePlan(prepared, snapshot, requiredStages, physicalResult, temporalResult, blockers, processedOutputResult, environmentCaptureResult, input.environmentCapture !== undefined);
2395
+ const core = {
2396
+ version: PRODUCTION_IMAGE_FORMATION_PLAN_VERSION,
2397
+ status: blockers.length === 0
2398
+ ? "ready"
2399
+ : "blocked",
2400
+ versions: {
2401
+ engineApi: ENGINE_API_VERSION,
2402
+ imageFormationContract: IMAGE_FORMATION_CONTRACT_VERSION,
2403
+ plan: PRODUCTION_IMAGE_FORMATION_PLAN_VERSION,
2404
+ preparedContext: PREPARED_IMAGE_FORMATION_CONTEXT_VERSION,
2405
+ captureSnapshot: PRODUCTION_CAPTURE_SNAPSHOT_VERSION,
2406
+ rendererCapability: RENDERER_CAPABILITY_SCHEMA_VERSION,
2407
+ fidelityProfile: IMAGE_FORMATION_FIDELITY_PROFILE_SCHEMA_VERSION,
2408
+ scientificAssurance: SCIENTIFIC_ASSURANCE_CONTRACT_VERSION
2409
+ },
2410
+ contextIdentity: {
2411
+ contextId: prepared.contextId,
2412
+ preparedContextFingerprint: prepared
2413
+ .fingerprint.value
2414
+ },
2415
+ captureIdentity: {
2416
+ captureId: snapshot.captureId,
2417
+ releaseFrameId: snapshot.releaseFrameId,
2418
+ sceneStateId: snapshot.sceneStateId,
2419
+ ...(snapshot
2420
+ .releaseFrameBinding ===
2421
+ undefined
2422
+ ? {}
2423
+ : {
2424
+ releaseSequenceId: snapshot
2425
+ .releaseFrameBinding
2426
+ .sequenceId,
2427
+ releaseFrameIndex: snapshot
2428
+ .releaseFrameBinding
2429
+ .frameIndex
2430
+ }),
2431
+ ...(snapshot
2432
+ .whiteBalanceState ===
2433
+ undefined
2434
+ ? {}
2435
+ : {
2436
+ whiteBalanceStateId: snapshot
2437
+ .whiteBalanceState
2438
+ .stateId
2439
+ }),
2440
+ captureSnapshotFingerprint: snapshot
2441
+ .fingerprint.value
2442
+ },
2443
+ rendererIdentity: {
2444
+ rendererId: prepared.renderer
2445
+ .rendererId,
2446
+ rendererVersion: prepared.renderer
2447
+ .rendererVersion,
2448
+ consumerKind: prepared.renderer
2449
+ .consumerKind
2450
+ },
2451
+ fidelityIdentity: {
2452
+ profileId: prepared.fidelity
2453
+ .profileId,
2454
+ profileVersion: prepared.fidelity
2455
+ .profileVersion
2456
+ },
2457
+ stagePlan,
2458
+ ...(environmentExecution === undefined ? {} : { environmentCaptureResult: environmentExecution.result,
2459
+ environmentCaptureRequestFingerprint: environmentExecution.requestFingerprint }),
2460
+ ...(processedOutputResult === undefined ? {} : { processedOutputResult }),
2461
+ effectPlan,
2462
+ blockers,
2463
+ ...(physicalResult ===
2464
+ undefined
2465
+ ? {}
2466
+ : {
2467
+ physicalSceneToSensorResult: physicalResult
2468
+ }),
2469
+ ...(temporalResult ===
2470
+ undefined
2471
+ ? {}
2472
+ : {
2473
+ temporalCaptureResult: temporalResult
2474
+ }),
2475
+ ...(scientificAssurance ===
2476
+ undefined
2477
+ ? {}
2478
+ : {
2479
+ scientificAssurance
2480
+ }),
2481
+ stochastic: {
2482
+ captureSeedUint32: snapshot
2483
+ .stochasticSeedUint32,
2484
+ backendRandomnessMayRedefineScientificResult: false
2485
+ },
2486
+ immutableCaptureSnapshot: true,
2487
+ legacyPocModified: false
2488
+ };
2489
+ const plan = {
2490
+ ...core,
2491
+ fingerprint: {
2492
+ algorithm: "fnv1a-32-non-cryptographic",
2493
+ value: fingerprintValue(core),
2494
+ purpose: "deterministic-reproducibility-key-not-integrity-security"
2495
+ }
2496
+ };
2497
+ return deepFreeze(cloneJson(plan));
2498
+ }
2499
+ //# sourceMappingURL=image-formation-plan.js.map