@photivra/engine 2.18.0 → 2.20.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 (335) hide show
  1. package/CHANGELOG.md +179 -1
  2. package/CITATION.cff +1 -1
  3. package/NODE_SUPPORT.md +7 -5
  4. package/README.md +6 -6
  5. package/SECURITY.md +1 -1
  6. package/THIRD_PARTY.md +14 -10
  7. package/dist/capture/dng-lens-correction-opcodes.d.ts +32 -0
  8. package/dist/capture/dng-lens-correction-opcodes.js +119 -0
  9. package/dist/capture/dng-lens-correction-opcodes.js.map +1 -0
  10. package/dist/capture/focus-control.js +2 -75
  11. package/dist/capture/focus-control.js.map +1 -1
  12. package/dist/capture/native-environment-lean.d.ts +1 -0
  13. package/dist/capture/native-environment-lean.js +2 -6
  14. package/dist/capture/native-environment-lean.js.map +1 -1
  15. package/dist/capture/native-environment-optical-stage.d.ts +1 -0
  16. package/dist/capture/native-environment-optical-stage.js +2 -5
  17. package/dist/capture/native-environment-optical-stage.js.map +1 -1
  18. package/dist/capture/native-environment-raw.js +1 -5
  19. package/dist/capture/native-environment-raw.js.map +1 -1
  20. package/dist/capture/native-raw-dng.d.ts +6 -0
  21. package/dist/capture/native-raw-dng.js +16 -2
  22. package/dist/capture/native-raw-dng.js.map +1 -1
  23. package/dist/capture/release-sequence.js +2 -47
  24. package/dist/capture/release-sequence.js.map +1 -1
  25. package/dist/capture/sensor-raw-producer.js +3 -5
  26. package/dist/capture/sensor-raw-producer.js.map +1 -1
  27. package/dist/color/white-balance.d.ts +2 -0
  28. package/dist/color/white-balance.js +3 -56
  29. package/dist/color/white-balance.js.map +1 -1
  30. package/dist/composition/image-formation-plan.d.ts +1 -0
  31. package/dist/composition/image-formation-plan.js +3 -49
  32. package/dist/composition/image-formation-plan.js.map +1 -1
  33. package/dist/core/evidence-provenance.js +1 -16
  34. package/dist/core/evidence-provenance.js.map +1 -1
  35. package/dist/core/record-validation.d.ts +54 -0
  36. package/dist/core/record-validation.js +176 -0
  37. package/dist/core/record-validation.js.map +1 -1
  38. package/dist/core/scientific-assurance.js +1 -18
  39. package/dist/core/scientific-assurance.js.map +1 -1
  40. package/dist/core/shared-helpers.d.ts +35 -0
  41. package/dist/core/shared-helpers.js +38 -0
  42. package/dist/core/shared-helpers.js.map +1 -0
  43. package/dist/core/spectral-composition.js +1 -36
  44. package/dist/core/spectral-composition.js.map +1 -1
  45. package/dist/core/spectral.js +1 -19
  46. package/dist/core/spectral.js.map +1 -1
  47. package/dist/core/version.d.ts +1 -1
  48. package/dist/core/version.js +1 -1
  49. package/dist/core/version.js.map +1 -1
  50. package/dist/equipment/exposure-capabilities.d.ts +1 -0
  51. package/dist/equipment/exposure-capabilities.js +2 -36
  52. package/dist/equipment/exposure-capabilities.js.map +1 -1
  53. package/dist/equipment/generic-lens-catalogue.d.ts +8 -2
  54. package/dist/equipment/generic-lens-catalogue.js +31 -2
  55. package/dist/equipment/generic-lens-catalogue.js.map +1 -1
  56. package/dist/equipment/generic-tier-assets.js +2 -3
  57. package/dist/equipment/generic-tier-assets.js.map +1 -1
  58. package/dist/equipment/generic-tier-presets.js +2 -3
  59. package/dist/equipment/generic-tier-presets.js.map +1 -1
  60. package/dist/equipment/iso-capabilities.js +2 -49
  61. package/dist/equipment/iso-capabilities.js.map +1 -1
  62. package/dist/equipment/metering-capabilities.js +1 -26
  63. package/dist/equipment/metering-capabilities.js.map +1 -1
  64. package/dist/equipment/release-capabilities.js +1 -53
  65. package/dist/equipment/release-capabilities.js.map +1 -1
  66. package/dist/exposure/auto-iso-slowest-shutter.js +1 -7
  67. package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
  68. package/dist/exposure/exposure-duration-control.js +1 -16
  69. package/dist/exposure/exposure-duration-control.js.map +1 -1
  70. package/dist/exposure/exposure-mode-resolver.js +1 -17
  71. package/dist/exposure/exposure-mode-resolver.js.map +1 -1
  72. package/dist/exposure/filtered-exposure-time.d.ts +93 -0
  73. package/dist/exposure/filtered-exposure-time.js +129 -0
  74. package/dist/exposure/filtered-exposure-time.js.map +1 -0
  75. package/dist/exposure/flash-ttl.d.ts +1 -0
  76. package/dist/exposure/flash-ttl.js +1 -1
  77. package/dist/exposure/flash-ttl.js.map +1 -1
  78. package/dist/exposure/flash.js +1 -49
  79. package/dist/exposure/flash.js.map +1 -1
  80. package/dist/exposure/metering-scene-radiance.js +1 -25
  81. package/dist/exposure/metering-scene-radiance.js.map +1 -1
  82. package/dist/exposure/metering-target.js +1 -30
  83. package/dist/exposure/metering-target.js.map +1 -1
  84. package/dist/exposure/metering-temporal.js +1 -8
  85. package/dist/exposure/metering-temporal.js.map +1 -1
  86. package/dist/exposure/metering.js +1 -72
  87. package/dist/exposure/metering.js.map +1 -1
  88. package/dist/exposure/program-line.js +1 -45
  89. package/dist/exposure/program-line.js.map +1 -1
  90. package/dist/facade/develop-joined-parts.d.ts +29 -0
  91. package/dist/facade/develop-joined-parts.js +33 -0
  92. package/dist/facade/develop-joined-parts.js.map +1 -0
  93. package/dist/facade/display-view-gpu.d.ts +7 -4
  94. package/dist/facade/display-view-gpu.js +4 -4
  95. package/dist/facade/display-view-gpu.js.map +1 -1
  96. package/dist/facade/display-view-lens-signal.d.ts +1 -1
  97. package/dist/facade/display-view-lens-signal.js +5 -3
  98. package/dist/facade/display-view-lens-signal.js.map +1 -1
  99. package/dist/facade/display-view.d.ts +3 -1
  100. package/dist/facade/display-view.js +1 -1
  101. package/dist/facade/display-view.js.map +1 -1
  102. package/dist/facade/fast-methods.d.ts +50 -0
  103. package/dist/facade/fast-methods.js +50 -0
  104. package/dist/facade/fast-methods.js.map +1 -0
  105. package/dist/facade/fast-resolution.d.ts +12 -0
  106. package/dist/facade/fast-resolution.js +18 -0
  107. package/dist/facade/fast-resolution.js.map +1 -0
  108. package/dist/facade/generic-lens-capture.d.ts +6 -3
  109. package/dist/facade/generic-lens-capture.js +6 -3
  110. package/dist/facade/generic-lens-capture.js.map +1 -1
  111. package/dist/facade/simulate-capture.d.ts +88 -16
  112. package/dist/facade/simulate-capture.js +279 -153
  113. package/dist/facade/simulate-capture.js.map +1 -1
  114. package/dist/facade/simulate-display-view.d.ts +3 -2
  115. package/dist/facade/simulate-display-view.js +22 -12
  116. package/dist/facade/simulate-display-view.js.map +1 -1
  117. package/dist/gpu/chart-composite-gpu.js +1 -3
  118. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  119. package/dist/gpu/chart-radiance-gpu.js +1 -5
  120. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  121. package/dist/gpu/display-view-quality-gpu.d.ts +13 -1
  122. package/dist/gpu/display-view-quality-gpu.js +4 -8
  123. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  124. package/dist/gpu/display-view-speed-gpu.js +3 -25
  125. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  126. package/dist/gpu/sensor-stage-gpu.js +1 -5
  127. package/dist/gpu/sensor-stage-gpu.js.map +1 -1
  128. package/dist/gpu/webgpu-runtime.d.ts +2 -0
  129. package/dist/gpu/webgpu-runtime.js +3 -0
  130. package/dist/gpu/webgpu-runtime.js.map +1 -1
  131. package/dist/index.d.ts +11 -1
  132. package/dist/index.js +8 -0
  133. package/dist/index.js.map +1 -1
  134. package/dist/motion/camera-rotation.js +1 -6
  135. package/dist/motion/camera-rotation.js.map +1 -1
  136. package/dist/motion/capture-rotation-inverse-mapping.d.ts +12 -0
  137. package/dist/motion/capture-rotation-inverse-mapping.js +2 -2
  138. package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
  139. package/dist/motion/capture-rotation-temporal-quadrature.d.ts +1 -0
  140. package/dist/motion/capture-rotation-temporal-quadrature.js +1 -1
  141. package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
  142. package/dist/motion/capture-rotation-trajectory.js +2 -17
  143. package/dist/motion/capture-rotation-trajectory.js.map +1 -1
  144. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +1 -0
  145. package/dist/motion/capture-translation-parallax-temporal-quadrature.js +3 -14
  146. package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
  147. package/dist/motion/extended-object-projection.js +5 -40
  148. package/dist/motion/extended-object-projection.js.map +1 -1
  149. package/dist/optics/aperture-diameter.d.ts +47 -0
  150. package/dist/optics/aperture-diameter.js +50 -0
  151. package/dist/optics/aperture-diameter.js.map +1 -0
  152. package/dist/optics/atmospheric-haze.js +1 -7
  153. package/dist/optics/atmospheric-haze.js.map +1 -1
  154. package/dist/optics/brown-conrady-distortion.js +1 -7
  155. package/dist/optics/brown-conrady-distortion.js.map +1 -1
  156. package/dist/optics/complex-pupil-psf.d.ts +1 -0
  157. package/dist/optics/complex-pupil-psf.js +2 -84
  158. package/dist/optics/complex-pupil-psf.js.map +1 -1
  159. package/dist/optics/detail-limit.d.ts +182 -0
  160. package/dist/optics/detail-limit.js +336 -0
  161. package/dist/optics/detail-limit.js.map +1 -0
  162. package/dist/optics/focus-state.js +1 -11
  163. package/dist/optics/focus-state.js.map +1 -1
  164. package/dist/optics/front-of-lens-filter.d.ts +5 -0
  165. package/dist/optics/front-of-lens-filter.js +3 -65
  166. package/dist/optics/front-of-lens-filter.js.map +1 -1
  167. package/dist/optics/generic-lens-psf.d.ts +18 -2
  168. package/dist/optics/generic-lens-psf.js +25 -2
  169. package/dist/optics/generic-lens-psf.js.map +1 -1
  170. package/dist/optics/generic-nd-filter-presets.d.ts +12 -0
  171. package/dist/optics/generic-nd-filter-presets.js +48 -0
  172. package/dist/optics/generic-nd-filter-presets.js.map +1 -0
  173. package/dist/optics/illumination-vignetting.js +1 -6
  174. package/dist/optics/illumination-vignetting.js.map +1 -1
  175. package/dist/optics/lens-psf-profile.d.ts +4 -1
  176. package/dist/optics/lens-psf-profile.js +12 -111
  177. package/dist/optics/lens-psf-profile.js.map +1 -1
  178. package/dist/optics/longitudinal-chromatic-aberration.js +1 -7
  179. package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -1
  180. package/dist/optics/pupil-vignetting.js +1 -7
  181. package/dist/optics/pupil-vignetting.js.map +1 -1
  182. package/dist/optics/radial-distortion.js +1 -6
  183. package/dist/optics/radial-distortion.js.map +1 -1
  184. package/dist/optics/scene-to-sensor-irradiance.d.ts +13 -0
  185. package/dist/optics/scene-to-sensor-irradiance.js +11 -96
  186. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
  187. package/dist/optics/stray-light.d.ts +1 -0
  188. package/dist/optics/stray-light.js +1 -1
  189. package/dist/optics/stray-light.js.map +1 -1
  190. package/dist/optics/zernike-wavefront.js +1 -7
  191. package/dist/optics/zernike-wavefront.js.map +1 -1
  192. package/dist/output/capture-geometry.js +1 -8
  193. package/dist/output/capture-geometry.js.map +1 -1
  194. package/dist/output/crop-to-match-focal-length.d.ts +62 -0
  195. package/dist/output/crop-to-match-focal-length.js +63 -0
  196. package/dist/output/crop-to-match-focal-length.js.map +1 -0
  197. package/dist/output/developed-lens-corrections.d.ts +62 -0
  198. package/dist/output/developed-lens-corrections.js +135 -0
  199. package/dist/output/developed-lens-corrections.js.map +1 -0
  200. package/dist/output/generic-lens-corrections.d.ts +5 -7
  201. package/dist/output/generic-lens-corrections.js +11 -10
  202. package/dist/output/generic-lens-corrections.js.map +1 -1
  203. package/dist/output/geometric-transforms.js +1 -4
  204. package/dist/output/geometric-transforms.js.map +1 -1
  205. package/dist/output/lens-corrections.d.ts +12 -2
  206. package/dist/output/lens-corrections.js +22 -7
  207. package/dist/output/lens-corrections.js.map +1 -1
  208. package/dist/output/native-capture-sdr.d.ts +2 -2
  209. package/dist/output/native-capture-sdr.js +3 -2
  210. package/dist/output/native-capture-sdr.js.map +1 -1
  211. package/dist/output/print-contrast-reference.js +1 -1
  212. package/dist/output/print-contrast-reference.js.map +1 -1
  213. package/dist/output/print-size-blur-noise.d.ts +110 -0
  214. package/dist/output/print-size-blur-noise.js +138 -0
  215. package/dist/output/print-size-blur-noise.js.map +1 -0
  216. package/dist/processing/development-detail.d.ts +29 -0
  217. package/dist/processing/development-detail.js +128 -107
  218. package/dist/processing/development-detail.js.map +1 -1
  219. package/dist/schema/illumination-temporal.js +3 -72
  220. package/dist/schema/illumination-temporal.js.map +1 -1
  221. package/dist/schema/illumination.d.ts +1 -0
  222. package/dist/schema/illumination.js +2 -65
  223. package/dist/schema/illumination.js.map +1 -1
  224. package/dist/schema/scene-radiance-temporal.js +2 -14
  225. package/dist/schema/scene-radiance-temporal.js.map +1 -1
  226. package/dist/schema/scene-radiance.js +2 -60
  227. package/dist/schema/scene-radiance.js.map +1 -1
  228. package/dist/schema/validation.d.ts +2 -0
  229. package/dist/schema/validation.js +2 -17
  230. package/dist/schema/validation.js.map +1 -1
  231. package/dist/sensor/accumulated-charge.js +2 -59
  232. package/dist/sensor/accumulated-charge.js.map +1 -1
  233. package/dist/sensor/architecture.js +1 -16
  234. package/dist/sensor/architecture.js.map +1 -1
  235. package/dist/sensor/camera-saturation-capacity.d.ts +1 -0
  236. package/dist/sensor/camera-saturation-capacity.js +3 -55
  237. package/dist/sensor/camera-saturation-capacity.js.map +1 -1
  238. package/dist/sensor/capture-color-sampling-binding.js +1 -26
  239. package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
  240. package/dist/sensor/capture-mode-timing.js +1 -39
  241. package/dist/sensor/capture-mode-timing.js.map +1 -1
  242. package/dist/sensor/capture-mode.js +1 -23
  243. package/dist/sensor/capture-mode.js.map +1 -1
  244. package/dist/sensor/color-sampling.js +1 -26
  245. package/dist/sensor/color-sampling.js.map +1 -1
  246. package/dist/sensor/constant-rate-temporal-integration.js +2 -46
  247. package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
  248. package/dist/sensor/dark-current.js +2 -45
  249. package/dist/sensor/dark-current.js.map +1 -1
  250. package/dist/sensor/eqe-electron-rate.js +2 -41
  251. package/dist/sensor/eqe-electron-rate.js.map +1 -1
  252. package/dist/sensor/exposure-window.d.ts +7 -0
  253. package/dist/sensor/exposure-window.js +9 -24
  254. package/dist/sensor/exposure-window.js.map +1 -1
  255. package/dist/sensor/iso-gain.js +1 -7
  256. package/dist/sensor/iso-gain.js.map +1 -1
  257. package/dist/sensor/iso-signal-chain.js +1 -43
  258. package/dist/sensor/iso-signal-chain.js.map +1 -1
  259. package/dist/sensor/optical-stack.js +1 -25
  260. package/dist/sensor/optical-stack.js.map +1 -1
  261. package/dist/sensor/photon-energy.js +1 -26
  262. package/dist/sensor/photon-energy.js.map +1 -1
  263. package/dist/sensor/physical-charge-capacity.js +3 -77
  264. package/dist/sensor/physical-charge-capacity.js.map +1 -1
  265. package/dist/sensor/radiometry-readiness.js +2 -23
  266. package/dist/sensor/radiometry-readiness.js.map +1 -1
  267. package/dist/sensor/raw-readout.d.ts +3 -0
  268. package/dist/sensor/raw-readout.js +4 -66
  269. package/dist/sensor/raw-readout.js.map +1 -1
  270. package/dist/sensor/raw-reconstruction.js +2 -64
  271. package/dist/sensor/raw-reconstruction.js.map +1 -1
  272. package/dist/sensor/readout-exposure-linkage.js +1 -9
  273. package/dist/sensor/readout-exposure-linkage.js.map +1 -1
  274. package/dist/sensor/readout-timing.js +4 -79
  275. package/dist/sensor/readout-timing.js.map +1 -1
  276. package/dist/sensor/response-application-compatibility.d.ts +2 -0
  277. package/dist/sensor/response-application-compatibility.js +4 -35
  278. package/dist/sensor/response-application-compatibility.js.map +1 -1
  279. package/dist/sensor/response-operating-range.d.ts +1 -0
  280. package/dist/sensor/response-operating-range.js +3 -79
  281. package/dist/sensor/response-operating-range.js.map +1 -1
  282. package/dist/sensor/responsivity-photocurrent.js +4 -114
  283. package/dist/sensor/responsivity-photocurrent.js.map +1 -1
  284. package/dist/sensor/sampling-aperture.js +1 -25
  285. package/dist/sensor/sampling-aperture.js.map +1 -1
  286. package/dist/sensor/sensor-characteristics.d.ts +137 -0
  287. package/dist/sensor/sensor-characteristics.js +115 -0
  288. package/dist/sensor/sensor-characteristics.js.map +1 -0
  289. package/dist/sensor/spatial-sample-reduction.js +3 -24
  290. package/dist/sensor/spatial-sample-reduction.js.map +1 -1
  291. package/dist/sensor/spatial-sampling-quadrature.js +1 -3
  292. package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
  293. package/dist/sensor/spatio-spectral-reduction.js +1 -18
  294. package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
  295. package/dist/sensor/spectral-coverage.d.ts +10 -1
  296. package/dist/sensor/spectral-coverage.js +1 -1
  297. package/dist/sensor/spectral-coverage.js.map +1 -1
  298. package/dist/sensor/spectral-quadrature.js +3 -41
  299. package/dist/sensor/spectral-quadrature.js.map +1 -1
  300. package/dist/sensor/spectral-response.js +1 -47
  301. package/dist/sensor/spectral-response.js.map +1 -1
  302. package/dist/sensor/temporal-photo-signal.d.ts +3 -0
  303. package/dist/sensor/temporal-photo-signal.js +5 -2
  304. package/dist/sensor/temporal-photo-signal.js.map +1 -1
  305. package/dist/stabilization/camera-shake.js +1 -6
  306. package/dist/stabilization/camera-shake.js.map +1 -1
  307. package/dist/stabilization/system.d.ts +9 -0
  308. package/dist/stabilization/system.js +7 -86
  309. package/dist/stabilization/system.js.map +1 -1
  310. package/docs/AGENT_GUIDE.md +5 -0
  311. package/docs/API_REFERENCE.md +116 -3
  312. package/docs/QUICK_START.md +178 -14
  313. package/docs/USAGE.md +111 -3
  314. package/docs/api/capture-native-raw-dng.md +6 -0
  315. package/docs/api/core-version.md +1 -1
  316. package/docs/api/equipment-generic-lens-catalogue.md +7 -2
  317. package/docs/api/exports.json +203 -3
  318. package/docs/api/exposure-filtered-exposure-time.md +105 -0
  319. package/docs/api/facade-develop-joined-parts.md +32 -0
  320. package/docs/api/facade-display-view-gpu.md +5 -2
  321. package/docs/api/facade-fast-methods.md +91 -0
  322. package/docs/api/facade-simulate-capture.md +72 -16
  323. package/docs/api/facade-simulate-display-view.md +3 -2
  324. package/docs/api/optics-aperture-diameter.md +51 -0
  325. package/docs/api/optics-detail-limit.md +203 -0
  326. package/docs/api/optics-generic-nd-filter-presets.md +34 -0
  327. package/docs/api/optics-lens-psf-profile.md +3 -1
  328. package/docs/api/output-crop-to-match-focal-length.md +67 -0
  329. package/docs/api/output-developed-lens-corrections.md +12 -0
  330. package/docs/api/output-generic-lens-corrections.md +3 -10
  331. package/docs/api/output-lens-corrections.md +11 -1
  332. package/docs/api/output-print-size-blur-noise.md +115 -0
  333. package/docs/api/sensor-sensor-characteristics.md +105 -0
  334. package/llms.txt +5 -0
  335. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"physical-charge-capacity.js","sourceRoot":"","sources":["../../src/sensor/physical-charge-capacity.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Physical charge capacity (full-well capacity): the most electrons a sensor site can physically\n * store, and a check of the expected charge against it.\n *\n * The capacity is the total stored-electron limit given by a specific source, for a specific site,\n * operating state and temperature. The check compares the complete expected charge with it. It does\n * not clip random (noise) realizations and does not model overflow or blooming. Camera saturation\n * capacity and ADC or readout thresholds are separate limits.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport type {\n SensorPhotoAccumulatedChargeComposition as SensorAccumulatedChargeComposition\n} from \"./accumulated-charge.js\";\nimport type {\n SensorSpectralResponseScientificStatus,\n SensorSpectralResponseUncertainty\n} from \"./spectral-response.js\";\nimport { requireInputObject, requireInputKeys, rejectUnknownFields, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS } from \"../core/record-validation.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nexport type SensorPhysicalChargeCapacitySiteApplicability =\n | {\n kind: \"exact-site\";\n site: {\n x: number;\n y: number;\n };\n }\n | {\n kind:\n \"uniform-site-capacity-approximation\";\n limitation: string;\n evidence:\n readonly EvidenceProvenance[];\n };\n\nexport type SensorPhysicalChargeCapacityTemperatureApplicability =\n | {\n kind:\n \"exact-reference-temperature\";\n temperatureC: number;\n }\n | {\n kind: \"not-modeled\";\n limitation: string;\n evidence:\n readonly EvidenceProvenance[];\n };\n\nexport interface SensorPhysicalChargeCapacityProfile {\n schemaVersion: \"0.1.0\";\n profileId: string;\n colorSamplingProfileId: string;\n channelId: string;\n capacityMeaning:\n \"physical-charge-storage-capacity-electrons\";\n capacityElectrons: number;\n scientificStatus:\n SensorSpectralResponseScientificStatus;\n uncertainty:\n SensorSpectralResponseUncertainty;\n evidence:\n readonly EvidenceProvenance[];\n siteApplicability:\n SensorPhysicalChargeCapacitySiteApplicability;\n operatingState: {\n stateId: string;\n evidence:\n readonly EvidenceProvenance[];\n };\n temperatureApplicability:\n SensorPhysicalChargeCapacityTemperatureApplicability;\n}\n\nexport interface AssessSensorPhysicalChargeCapacityInput {\n accumulatedCharge:\n SensorAccumulatedChargeComposition;\n capacityProfile:\n SensorPhysicalChargeCapacityProfile;\n operatingStateId: string;\n operatingTemperatureC: number;\n}\n\nexport interface SensorPhysicalChargeCapacityAssessment {\n capacityProfileId: string;\n completenessProfileId: string;\n colorSamplingProfileId: string;\n channelId: string;\n site: {\n x: number;\n y: number;\n };\n bindingId: string;\n operatingStateId: string;\n operatingTemperatureC: number;\n capacityMeaning:\n \"physical-charge-storage-capacity-electrons\";\n physicalChargeCapacityElectrons:\n number;\n totalExpectedStoredElectronCount:\n number;\n expectedChargeToCapacityRatio:\n number;\n expectedChargeHeadroomElectrons:\n number;\n expectedChargeCapacityStatus:\n | \"below-capacity\"\n | \"at-capacity\"\n | \"above-capacity\";\n expectedChargeExceedsCapacity:\n boolean;\n physicalChargeCapacityAssessmentPerformed:\n true;\n assessmentMeaning:\n \"expected-charge-vs-physical-storage-capacity\";\n actualStochasticSaturationStateKnown:\n false;\n stochasticSaturationProbabilityAssessed:\n false;\n storedChargeAfterPhysicalSaturationCalculated:\n false;\n overflowChargeCalculated: false;\n bloomingModeled: false;\n clampApplied: false;\n cameraSaturationAssessmentAuthorized:\n false;\n adcQuantizationApplied: false;\n rawCodeValueProduced: false;\n capacityUncertaintyPropagated:\n false;\n accumulatedChargeUncertaintyPropagated:\n false;\n componentEvidence: {\n capacity:\n readonly EvidenceProvenance[];\n operatingState:\n readonly EvidenceProvenance[];\n siteApproximation:\n readonly EvidenceProvenance[];\n temperatureApproximation:\n readonly EvidenceProvenance[];\n chargeCompleteness:\n SensorAccumulatedChargeComposition[\"componentEvidence\"][\"completeness\"];\n };\n}\n\nfunction requireRecord(\n value: unknown,\n path: string,\n allowedKeys: readonly string[] | null\n): UnknownRecord {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be an object.\"\n );\n }\n if (allowedKeys !== null) rejectUnknownFields(value, allowedKeys, path);\n return value as UnknownRecord;\n}\n\nfunction requireNonEmptyString(\n value: unknown,\n path: string\n): string {\n if (\n typeof value !== \"string\" ||\n value.trim().length === 0\n ) {\n throw new InvalidConfigurationError(\n path + \" must be a non-empty string.\"\n );\n }\n return value;\n}\n\nfunction requireFinite(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be finite.\"\n );\n }\n return value;\n}\n\nfunction requirePositiveFinite(\n value: unknown,\n path: string\n): number {\n const parsed =\n requireFinite(value, path);\n if (parsed <= 0) {\n throw new InvalidConfigurationError(\n path +\n \" must be greater than zero.\"\n );\n }\n return parsed;\n}\n\nfunction requireNonNegativeFiniteInput(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value < 0\n ) {\n throw new InvalidScientificInputError(\n path +\n \" must be finite and greater than or equal to zero.\"\n );\n }\n return value;\n}\n\nfunction requireSiteIndex(\n value: unknown,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isSafeInteger(value) ||\n value < 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a non-negative safe integer.\"\n );\n }\n return value;\n}\n\nfunction parseUncertainty(\n value: unknown,\n path: string\n): SensorSpectralResponseUncertainty {\n const record =\n requireRecord(value, path, null);\n rejectUnknownVariantFields(record, \"kind\", UNCERTAINTY_VARIANT_FIELDS, path);\n if (record.kind === \"relative\") {\n const fraction =\n requireFinite(\n record.fraction,\n path + \".fraction\"\n );\n if (fraction < 0) {\n throw new InvalidConfigurationError(\n path +\n \".fraction must be nonnegative.\"\n );\n }\n return {\n kind: \"relative\",\n fraction,\n basis: requireNonEmptyString(\n record.basis,\n path + \".basis\"\n )\n };\n }\n if (\n record.kind === \"not-quantified\"\n ) {\n return {\n kind: \"not-quantified\",\n limitation:\n requireNonEmptyString(\n record.limitation,\n path + \".limitation\"\n )\n };\n }\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction parseSiteApplicability(\n value: unknown\n): SensorPhysicalChargeCapacitySiteApplicability {\n const record = requireRecord(\n value,\n \"sensorPhysicalChargeCapacity.siteApplicability\", null\n );\n rejectUnknownVariantFields(record, \"kind\", { \"exact-site\": [\"kind\", \"site\"], \"uniform-site-capacity-approximation\": [\"kind\", \"limitation\", \"evidence\"] }, \"sensorPhysicalChargeCapacity.siteApplicability\");\n if (record.kind === \"exact-site\") {\n const site = requireRecord(\n record.site,\n \"sensorPhysicalChargeCapacity.siteApplicability.site\", [\"x\", \"y\"]\n );\n return {\n kind: \"exact-site\",\n site: {\n x: requireSiteIndex(\n site.x,\n \"sensorPhysicalChargeCapacity.siteApplicability.site.x\"\n ),\n y: requireSiteIndex(\n site.y,\n \"sensorPhysicalChargeCapacity.siteApplicability.site.y\"\n )\n }\n };\n }\n if (\n record.kind ===\n \"uniform-site-capacity-approximation\"\n ) {\n return {\n kind:\n \"uniform-site-capacity-approximation\",\n limitation:\n requireNonEmptyString(\n record.limitation,\n \"sensorPhysicalChargeCapacity.siteApplicability.limitation\"\n ),\n evidence: parseEvidenceList(\n record.evidence,\n \"sensorPhysicalChargeCapacity.siteApplicability.evidence\"\n )\n };\n }\n throw new InvalidConfigurationError(\n \"sensorPhysicalChargeCapacity.siteApplicability.kind is invalid.\"\n );\n}\n\nfunction parseTemperatureApplicability(\n value: unknown\n): SensorPhysicalChargeCapacityTemperatureApplicability {\n const record = requireRecord(\n value,\n \"sensorPhysicalChargeCapacity.temperatureApplicability\", null\n );\n rejectUnknownVariantFields(record, \"kind\", { \"exact-reference-temperature\": [\"kind\", \"temperatureC\"], \"not-modeled\": [\"kind\", \"limitation\", \"evidence\"] }, \"sensorPhysicalChargeCapacity.temperatureApplicability\");\n if (\n record.kind ===\n \"exact-reference-temperature\"\n ) {\n return {\n kind:\n \"exact-reference-temperature\",\n temperatureC:\n requireFinite(\n record.temperatureC,\n \"sensorPhysicalChargeCapacity.temperatureApplicability.temperatureC\"\n )\n };\n }\n if (record.kind === \"not-modeled\") {\n return {\n kind: \"not-modeled\",\n limitation:\n requireNonEmptyString(\n record.limitation,\n \"sensorPhysicalChargeCapacity.temperatureApplicability.limitation\"\n ),\n evidence: parseEvidenceList(\n record.evidence,\n \"sensorPhysicalChargeCapacity.temperatureApplicability.evidence\"\n )\n };\n }\n throw new InvalidConfigurationError(\n \"sensorPhysicalChargeCapacity.temperatureApplicability.kind is invalid.\"\n );\n}\n\n/**\n * Validates untrusted input and returns it as a normalized, typed value. Unknown enum values,\n * missing required fields and inconsistent scientific data are rejected.\n *\n * The capacity is a total stored-electron limit from a specific source, tied to a site, operating\n * state and temperature. Camera saturation capacity and ADC or readout thresholds are separate.\n * @param value - Untrusted data. TypeScript types alone are not validation.\n * @returns The result. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function parseSensorPhysicalChargeCapacityProfile(\n value: unknown\n): SensorPhysicalChargeCapacityProfile {\n const record = requireRecord(\n value,\n \"sensorPhysicalChargeCapacity\", [\"schemaVersion\", \"capacityMeaning\", \"scientificStatus\", \"uncertainty\", \"siteApplicability\", \"temperatureApplicability\", \"operatingState\", \"profileId\", \"colorSamplingProfileId\", \"channelId\", \"capacityElectrons\", \"evidence\"]\n );\n if (\n record.schemaVersion !== \"0.1.0\"\n ) {\n throw new InvalidConfigurationError(\n 'sensorPhysicalChargeCapacity.schemaVersion must be \"0.1.0\".'\n );\n }\n if (\n record.capacityMeaning !==\n \"physical-charge-storage-capacity-electrons\"\n ) {\n throw new InvalidConfigurationError(\n \"sensorPhysicalChargeCapacity.capacityMeaning is invalid.\"\n );\n }\n if (\n record.scientificStatus !==\n \"calibrated\" &&\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n \"sensorPhysicalChargeCapacity.scientificStatus is invalid.\"\n );\n }\n\n const uncertainty =\n parseUncertainty(\n record.uncertainty,\n \"sensorPhysicalChargeCapacity.uncertainty\"\n );\n if (\n record.scientificStatus ===\n \"calibrated\" &&\n uncertainty.kind ===\n \"not-quantified\"\n ) {\n throw new InvalidConfigurationError(\n \"A calibrated physical charge-capacity profile must declare quantified relative uncertainty.\"\n );\n }\n\n const siteApplicability =\n parseSiteApplicability(\n record.siteApplicability\n );\n const temperatureApplicability =\n parseTemperatureApplicability(\n record.temperatureApplicability\n );\n\n if (\n siteApplicability.kind ===\n \"uniform-site-capacity-approximation\" &&\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n \"Uniform site charge capacity must remain an approximation.\"\n );\n }\n if (\n temperatureApplicability.kind ===\n \"not-modeled\" &&\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n \"A capacity with unmodeled temperature dependence must remain an approximation.\"\n );\n }\n\n const state =\n requireRecord(\n record.operatingState,\n \"sensorPhysicalChargeCapacity.operatingState\", [\"stateId\", \"evidence\"]\n );\n\n return {\n schemaVersion: \"0.1.0\",\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"sensorPhysicalChargeCapacity.profileId\"\n ),\n colorSamplingProfileId:\n requireNonEmptyString(\n record.colorSamplingProfileId,\n \"sensorPhysicalChargeCapacity.colorSamplingProfileId\"\n ),\n channelId:\n requireNonEmptyString(\n record.channelId,\n \"sensorPhysicalChargeCapacity.channelId\"\n ),\n capacityMeaning:\n \"physical-charge-storage-capacity-electrons\",\n capacityElectrons:\n requirePositiveFinite(\n record.capacityElectrons,\n \"sensorPhysicalChargeCapacity.capacityElectrons\"\n ),\n scientificStatus:\n record.scientificStatus,\n uncertainty,\n evidence: parseEvidenceList(\n record.evidence,\n \"sensorPhysicalChargeCapacity.evidence\"\n ),\n siteApplicability,\n operatingState: {\n stateId:\n requireNonEmptyString(\n state.stateId,\n \"sensorPhysicalChargeCapacity.operatingState.stateId\"\n ),\n evidence: parseEvidenceList(\n state.evidence,\n \"sensorPhysicalChargeCapacity.operatingState.evidence\"\n )\n },\n temperatureApplicability\n };\n}\n\nfunction sameSite(\n a: { x: number; y: number },\n b: { x: number; y: number }\n): boolean {\n return a.x === b.x && a.y === b.y;\n}\n\nfunction validateCharge(\n charge:\n SensorAccumulatedChargeComposition\n): number {\n requireInputObject(charge, \"charge input\");\n if (\n charge\n .physicalFullWellAssessmentAuthorized !==\n true ||\n charge.saturationAssessed !==\n false ||\n charge.bloomingModeled !== false ||\n charge.accumulatedChargeCompleteness !==\n \"complete-for-physical-storage-capacity-assessment\"\n ) {\n throw new InvalidScientificInputError(\n \"Physical capacity assessment requires an unsaturated complete stored-electron composition.\"\n );\n }\n return requireNonNegativeFiniteInput(\n charge.totalExpectedStoredElectronCount,\n \"accumulatedCharge.totalExpectedStoredElectronCount\"\n );\n}\n\n/**\n * Compares the complete expected stored electrons with the physical capacity that applies, and\n * reports the remaining headroom in expected electrons. Non-linear storage is not simulated.\n *\n * It does not clip random realizations and does not model overflow or blooming.\n * @param input - The input; see `AssessSensorPhysicalChargeCapacityInput` for its fields, units and coordinates.\n * @returns The assessment. Read its structured blockers before acting on an authorization.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function assessSensorPhysicalChargeCapacity(\n input:\n AssessSensorPhysicalChargeCapacityInput\n): CalculationResult<SensorPhysicalChargeCapacityAssessment> {\n requireInputKeys(input, \"assessSensorPhysicalChargeCapacity\", [\"accumulatedCharge\", \"capacityProfile\", \"operatingStateId\", \"operatingTemperatureC\"]);\n const totalExpectedStoredElectronCount =\n validateCharge(\n input.accumulatedCharge\n );\n const profile =\n parseSensorPhysicalChargeCapacityProfile(\n input.capacityProfile\n );\n\n if (\n profile.colorSamplingProfileId !==\n input.accumulatedCharge\n .colorSamplingProfileId ||\n profile.channelId !==\n input.accumulatedCharge.channelId\n ) {\n throw new InvalidScientificInputError(\n \"Physical charge-capacity profile color/channel identity must match the accumulated charge.\"\n );\n }\n if (\n profile.siteApplicability.kind ===\n \"exact-site\" &&\n !sameSite(\n profile.siteApplicability.site,\n input.accumulatedCharge.site\n )\n ) {\n throw new InvalidScientificInputError(\n \"Exact-site physical charge capacity does not apply to the accumulated-charge site.\"\n );\n }\n if (\n typeof input.operatingStateId !==\n \"string\" ||\n input.operatingStateId.trim().length ===\n 0 ||\n input.operatingStateId !==\n profile.operatingState.stateId\n ) {\n throw new InvalidScientificInputError(\n \"operatingStateId must exactly match the physical charge-capacity calibration state.\"\n );\n }\n if (\n typeof input.operatingTemperatureC !==\n \"number\" ||\n !Number.isFinite(\n input.operatingTemperatureC\n )\n ) {\n throw new InvalidScientificInputError(\n \"operatingTemperatureC must be finite.\"\n );\n }\n if (\n profile.temperatureApplicability.kind ===\n \"exact-reference-temperature\" &&\n input.operatingTemperatureC !==\n profile.temperatureApplicability\n .temperatureC\n ) {\n throw new InvalidScientificInputError(\n \"operatingTemperatureC must exactly match the physical charge-capacity reference temperature.\"\n );\n }\n\n const capacity =\n profile.capacityElectrons;\n const ratio =\n totalExpectedStoredElectronCount /\n capacity;\n const headroom =\n capacity -\n totalExpectedStoredElectronCount;\n if (\n !Number.isFinite(ratio) ||\n !Number.isFinite(headroom)\n ) {\n throw new InvalidScientificInputError(\n \"Physical charge-capacity comparison must remain finite.\"\n );\n }\n\n const status =\n totalExpectedStoredElectronCount <\n capacity\n ? \"below-capacity\"\n : totalExpectedStoredElectronCount ===\n capacity\n ? \"at-capacity\"\n : \"above-capacity\";\n\n const result:\n SensorPhysicalChargeCapacityAssessment = {\n capacityProfileId:\n profile.profileId,\n completenessProfileId:\n input.accumulatedCharge\n .completenessProfileId,\n colorSamplingProfileId:\n input.accumulatedCharge\n .colorSamplingProfileId,\n channelId:\n input.accumulatedCharge.channelId,\n site: {\n ...input.accumulatedCharge.site\n },\n bindingId:\n input.accumulatedCharge.bindingId,\n operatingStateId:\n input.operatingStateId,\n operatingTemperatureC:\n input.operatingTemperatureC,\n capacityMeaning:\n \"physical-charge-storage-capacity-electrons\",\n physicalChargeCapacityElectrons:\n capacity,\n totalExpectedStoredElectronCount,\n expectedChargeToCapacityRatio:\n ratio,\n expectedChargeHeadroomElectrons:\n headroom,\n expectedChargeCapacityStatus:\n status,\n expectedChargeExceedsCapacity:\n status === \"above-capacity\",\n physicalChargeCapacityAssessmentPerformed:\n true,\n assessmentMeaning:\n \"expected-charge-vs-physical-storage-capacity\",\n actualStochasticSaturationStateKnown:\n false,\n stochasticSaturationProbabilityAssessed:\n false,\n storedChargeAfterPhysicalSaturationCalculated:\n false,\n overflowChargeCalculated: false,\n bloomingModeled: false,\n clampApplied: false,\n cameraSaturationAssessmentAuthorized:\n false,\n adcQuantizationApplied: false,\n rawCodeValueProduced: false,\n capacityUncertaintyPropagated:\n false,\n accumulatedChargeUncertaintyPropagated:\n false,\n componentEvidence: {\n capacity:\n profile.evidence,\n operatingState:\n profile.operatingState\n .evidence,\n siteApproximation:\n profile.siteApplicability.kind ===\n \"uniform-site-capacity-approximation\"\n ? profile\n .siteApplicability\n .evidence\n : [],\n temperatureApproximation:\n profile.temperatureApplicability.kind ===\n \"not-modeled\"\n ? profile\n .temperatureApplicability\n .evidence\n : [],\n chargeCompleteness:\n input.accumulatedCharge\n .componentEvidence\n .completeness\n }\n };\n\n return approximationResult(\n result,\n \"sensor-physical-charge-capacity-assessment\",\n \"1.0.0\",\n [\n \"The capacity is a source-specific physical charge-storage limit in electrons, not EMVA camera saturation capacity and not an ADC/digital clipping threshold.\",\n \"The comparison uses total expected stored electrons after evidence-backed charge completeness. It does not claim a stochastic realization is certainly below or above capacity.\",\n \"Expected charge below capacity does not rule out stochastic saturation; expected charge above capacity indicates the unsaturated linear expectation exceeds the declared physical storage limit.\",\n \"No clamp is applied and stored charge after physical saturation is not calculated because the nonlinear overflow/recombination behavior is not modeled.\",\n \"Blooming direction, neighbor redistribution and anti-blooming behavior require a separate spatial charge-transfer model and are not inferred from excess expected charge.\",\n \"The operating-state identifier is an exact calibration-state key; Photivra does not infer physical capacity from ISO, gain labels, capture mode names or adjacent specifications.\",\n \"A capacity that is uniform across sites or has unmodeled temperature dependence remains an explicit approximation.\",\n \"Capacity and accumulated-charge uncertainties are preserved upstream but are not propagated into a saturation probability or confidence interval by this version.\",\n \"Camera/analog/digital saturation remains a separate downstream response-chain contract.\"\n ]\n );\n}\n"]}
1
+ {"version":3,"file":"physical-charge-capacity.js","sourceRoot":"","sources":["../../src/sensor/physical-charge-capacity.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Physical charge capacity (full-well capacity): the most electrons a sensor site can physically\n * store, and a check of the expected charge against it.\n *\n * The capacity is the total stored-electron limit given by a specific source, for a specific site,\n * operating state and temperature. The check compares the complete expected charge with it. It does\n * not clip random (noise) realizations and does not model overflow or blooming. Camera saturation\n * capacity and ADC or readout thresholds are separate limits.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport type {\n SensorPhotoAccumulatedChargeComposition as SensorAccumulatedChargeComposition\n} from \"./accumulated-charge.js\";\nimport type {\n SensorSpectralResponseScientificStatus,\n SensorSpectralResponseUncertainty\n} from \"./spectral-response.js\";\nimport { requireInputObject, requireInputKeys, rejectUnknownVariantFields, requireConfigRecord as requireRecord, requireConfigFinite as requireFinite, requireConfigString as requireNonEmptyString, requireInputNonNegativeFinite as requireNonNegativeFiniteInput, requireConfigNonNegativeSafeInteger as requireSiteIndex, requireConfigFiniteAboveZero as requirePositiveFinite } from \"../core/record-validation.js\";\nimport { sameSite } from \"../core/shared-helpers.js\";\nimport { parseUncertainty } from \"./camera-saturation-capacity.js\";\n\nexport type SensorPhysicalChargeCapacitySiteApplicability =\n | {\n kind: \"exact-site\";\n site: {\n x: number;\n y: number;\n };\n }\n | {\n kind:\n \"uniform-site-capacity-approximation\";\n limitation: string;\n evidence:\n readonly EvidenceProvenance[];\n };\n\nexport type SensorPhysicalChargeCapacityTemperatureApplicability =\n | {\n kind:\n \"exact-reference-temperature\";\n temperatureC: number;\n }\n | {\n kind: \"not-modeled\";\n limitation: string;\n evidence:\n readonly EvidenceProvenance[];\n };\n\nexport interface SensorPhysicalChargeCapacityProfile {\n schemaVersion: \"0.1.0\";\n profileId: string;\n colorSamplingProfileId: string;\n channelId: string;\n capacityMeaning:\n \"physical-charge-storage-capacity-electrons\";\n capacityElectrons: number;\n scientificStatus:\n SensorSpectralResponseScientificStatus;\n uncertainty:\n SensorSpectralResponseUncertainty;\n evidence:\n readonly EvidenceProvenance[];\n siteApplicability:\n SensorPhysicalChargeCapacitySiteApplicability;\n operatingState: {\n stateId: string;\n evidence:\n readonly EvidenceProvenance[];\n };\n temperatureApplicability:\n SensorPhysicalChargeCapacityTemperatureApplicability;\n}\n\nexport interface AssessSensorPhysicalChargeCapacityInput {\n accumulatedCharge:\n SensorAccumulatedChargeComposition;\n capacityProfile:\n SensorPhysicalChargeCapacityProfile;\n operatingStateId: string;\n operatingTemperatureC: number;\n}\n\nexport interface SensorPhysicalChargeCapacityAssessment {\n capacityProfileId: string;\n completenessProfileId: string;\n colorSamplingProfileId: string;\n channelId: string;\n site: {\n x: number;\n y: number;\n };\n bindingId: string;\n operatingStateId: string;\n operatingTemperatureC: number;\n capacityMeaning:\n \"physical-charge-storage-capacity-electrons\";\n physicalChargeCapacityElectrons:\n number;\n totalExpectedStoredElectronCount:\n number;\n expectedChargeToCapacityRatio:\n number;\n expectedChargeHeadroomElectrons:\n number;\n expectedChargeCapacityStatus:\n | \"below-capacity\"\n | \"at-capacity\"\n | \"above-capacity\";\n expectedChargeExceedsCapacity:\n boolean;\n physicalChargeCapacityAssessmentPerformed:\n true;\n assessmentMeaning:\n \"expected-charge-vs-physical-storage-capacity\";\n actualStochasticSaturationStateKnown:\n false;\n stochasticSaturationProbabilityAssessed:\n false;\n storedChargeAfterPhysicalSaturationCalculated:\n false;\n overflowChargeCalculated: false;\n bloomingModeled: false;\n clampApplied: false;\n cameraSaturationAssessmentAuthorized:\n false;\n adcQuantizationApplied: false;\n rawCodeValueProduced: false;\n capacityUncertaintyPropagated:\n false;\n accumulatedChargeUncertaintyPropagated:\n false;\n componentEvidence: {\n capacity:\n readonly EvidenceProvenance[];\n operatingState:\n readonly EvidenceProvenance[];\n siteApproximation:\n readonly EvidenceProvenance[];\n temperatureApproximation:\n readonly EvidenceProvenance[];\n chargeCompleteness:\n SensorAccumulatedChargeComposition[\"componentEvidence\"][\"completeness\"];\n };\n}\n\nfunction parseSiteApplicability(\n value: unknown\n): SensorPhysicalChargeCapacitySiteApplicability {\n const record = requireRecord(\n value,\n \"sensorPhysicalChargeCapacity.siteApplicability\", null\n );\n rejectUnknownVariantFields(record, \"kind\", { \"exact-site\": [\"kind\", \"site\"], \"uniform-site-capacity-approximation\": [\"kind\", \"limitation\", \"evidence\"] }, \"sensorPhysicalChargeCapacity.siteApplicability\");\n if (record.kind === \"exact-site\") {\n const site = requireRecord(\n record.site,\n \"sensorPhysicalChargeCapacity.siteApplicability.site\", [\"x\", \"y\"]\n );\n return {\n kind: \"exact-site\",\n site: {\n x: requireSiteIndex(\n site.x,\n \"sensorPhysicalChargeCapacity.siteApplicability.site.x\"\n ),\n y: requireSiteIndex(\n site.y,\n \"sensorPhysicalChargeCapacity.siteApplicability.site.y\"\n )\n }\n };\n }\n if (\n record.kind ===\n \"uniform-site-capacity-approximation\"\n ) {\n return {\n kind:\n \"uniform-site-capacity-approximation\",\n limitation:\n requireNonEmptyString(\n record.limitation,\n \"sensorPhysicalChargeCapacity.siteApplicability.limitation\"\n ),\n evidence: parseEvidenceList(\n record.evidence,\n \"sensorPhysicalChargeCapacity.siteApplicability.evidence\"\n )\n };\n }\n throw new InvalidConfigurationError(\n \"sensorPhysicalChargeCapacity.siteApplicability.kind is invalid.\"\n );\n}\n\nfunction parseTemperatureApplicability(\n value: unknown\n): SensorPhysicalChargeCapacityTemperatureApplicability {\n const record = requireRecord(\n value,\n \"sensorPhysicalChargeCapacity.temperatureApplicability\", null\n );\n rejectUnknownVariantFields(record, \"kind\", { \"exact-reference-temperature\": [\"kind\", \"temperatureC\"], \"not-modeled\": [\"kind\", \"limitation\", \"evidence\"] }, \"sensorPhysicalChargeCapacity.temperatureApplicability\");\n if (\n record.kind ===\n \"exact-reference-temperature\"\n ) {\n return {\n kind:\n \"exact-reference-temperature\",\n temperatureC:\n requireFinite(\n record.temperatureC,\n \"sensorPhysicalChargeCapacity.temperatureApplicability.temperatureC\"\n )\n };\n }\n if (record.kind === \"not-modeled\") {\n return {\n kind: \"not-modeled\",\n limitation:\n requireNonEmptyString(\n record.limitation,\n \"sensorPhysicalChargeCapacity.temperatureApplicability.limitation\"\n ),\n evidence: parseEvidenceList(\n record.evidence,\n \"sensorPhysicalChargeCapacity.temperatureApplicability.evidence\"\n )\n };\n }\n throw new InvalidConfigurationError(\n \"sensorPhysicalChargeCapacity.temperatureApplicability.kind is invalid.\"\n );\n}\n\n/**\n * Validates untrusted input and returns it as a normalized, typed value. Unknown enum values,\n * missing required fields and inconsistent scientific data are rejected.\n *\n * The capacity is a total stored-electron limit from a specific source, tied to a site, operating\n * state and temperature. Camera saturation capacity and ADC or readout thresholds are separate.\n * @param value - Untrusted data. TypeScript types alone are not validation.\n * @returns The result. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function parseSensorPhysicalChargeCapacityProfile(\n value: unknown\n): SensorPhysicalChargeCapacityProfile {\n const record = requireRecord(\n value,\n \"sensorPhysicalChargeCapacity\", [\"schemaVersion\", \"capacityMeaning\", \"scientificStatus\", \"uncertainty\", \"siteApplicability\", \"temperatureApplicability\", \"operatingState\", \"profileId\", \"colorSamplingProfileId\", \"channelId\", \"capacityElectrons\", \"evidence\"]\n );\n if (\n record.schemaVersion !== \"0.1.0\"\n ) {\n throw new InvalidConfigurationError(\n 'sensorPhysicalChargeCapacity.schemaVersion must be \"0.1.0\".'\n );\n }\n if (\n record.capacityMeaning !==\n \"physical-charge-storage-capacity-electrons\"\n ) {\n throw new InvalidConfigurationError(\n \"sensorPhysicalChargeCapacity.capacityMeaning is invalid.\"\n );\n }\n if (\n record.scientificStatus !==\n \"calibrated\" &&\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n \"sensorPhysicalChargeCapacity.scientificStatus is invalid.\"\n );\n }\n\n const uncertainty =\n parseUncertainty(\n record.uncertainty,\n \"sensorPhysicalChargeCapacity.uncertainty\"\n );\n if (\n record.scientificStatus ===\n \"calibrated\" &&\n uncertainty.kind ===\n \"not-quantified\"\n ) {\n throw new InvalidConfigurationError(\n \"A calibrated physical charge-capacity profile must declare quantified relative uncertainty.\"\n );\n }\n\n const siteApplicability =\n parseSiteApplicability(\n record.siteApplicability\n );\n const temperatureApplicability =\n parseTemperatureApplicability(\n record.temperatureApplicability\n );\n\n if (\n siteApplicability.kind ===\n \"uniform-site-capacity-approximation\" &&\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n \"Uniform site charge capacity must remain an approximation.\"\n );\n }\n if (\n temperatureApplicability.kind ===\n \"not-modeled\" &&\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n \"A capacity with unmodeled temperature dependence must remain an approximation.\"\n );\n }\n\n const state =\n requireRecord(\n record.operatingState,\n \"sensorPhysicalChargeCapacity.operatingState\", [\"stateId\", \"evidence\"]\n );\n\n return {\n schemaVersion: \"0.1.0\",\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"sensorPhysicalChargeCapacity.profileId\"\n ),\n colorSamplingProfileId:\n requireNonEmptyString(\n record.colorSamplingProfileId,\n \"sensorPhysicalChargeCapacity.colorSamplingProfileId\"\n ),\n channelId:\n requireNonEmptyString(\n record.channelId,\n \"sensorPhysicalChargeCapacity.channelId\"\n ),\n capacityMeaning:\n \"physical-charge-storage-capacity-electrons\",\n capacityElectrons:\n requirePositiveFinite(\n record.capacityElectrons,\n \"sensorPhysicalChargeCapacity.capacityElectrons\"\n ),\n scientificStatus:\n record.scientificStatus,\n uncertainty,\n evidence: parseEvidenceList(\n record.evidence,\n \"sensorPhysicalChargeCapacity.evidence\"\n ),\n siteApplicability,\n operatingState: {\n stateId:\n requireNonEmptyString(\n state.stateId,\n \"sensorPhysicalChargeCapacity.operatingState.stateId\"\n ),\n evidence: parseEvidenceList(\n state.evidence,\n \"sensorPhysicalChargeCapacity.operatingState.evidence\"\n )\n },\n temperatureApplicability\n };\n}\n\nfunction validateCharge(\n charge:\n SensorAccumulatedChargeComposition\n): number {\n requireInputObject(charge, \"charge input\");\n if (\n charge\n .physicalFullWellAssessmentAuthorized !==\n true ||\n charge.saturationAssessed !==\n false ||\n charge.bloomingModeled !== false ||\n charge.accumulatedChargeCompleteness !==\n \"complete-for-physical-storage-capacity-assessment\"\n ) {\n throw new InvalidScientificInputError(\n \"Physical capacity assessment requires an unsaturated complete stored-electron composition.\"\n );\n }\n return requireNonNegativeFiniteInput(\n charge.totalExpectedStoredElectronCount,\n \"accumulatedCharge.totalExpectedStoredElectronCount\"\n );\n}\n\n/**\n * Compares the complete expected stored electrons with the physical capacity that applies, and\n * reports the remaining headroom in expected electrons. Non-linear storage is not simulated.\n *\n * It does not clip random realizations and does not model overflow or blooming.\n * @param input - The input; see `AssessSensorPhysicalChargeCapacityInput` for its fields, units and coordinates.\n * @returns The assessment. Read its structured blockers before acting on an authorization.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function assessSensorPhysicalChargeCapacity(\n input:\n AssessSensorPhysicalChargeCapacityInput\n): CalculationResult<SensorPhysicalChargeCapacityAssessment> {\n requireInputKeys(input, \"assessSensorPhysicalChargeCapacity\", [\"accumulatedCharge\", \"capacityProfile\", \"operatingStateId\", \"operatingTemperatureC\"]);\n const totalExpectedStoredElectronCount =\n validateCharge(\n input.accumulatedCharge\n );\n const profile =\n parseSensorPhysicalChargeCapacityProfile(\n input.capacityProfile\n );\n\n if (\n profile.colorSamplingProfileId !==\n input.accumulatedCharge\n .colorSamplingProfileId ||\n profile.channelId !==\n input.accumulatedCharge.channelId\n ) {\n throw new InvalidScientificInputError(\n \"Physical charge-capacity profile color/channel identity must match the accumulated charge.\"\n );\n }\n if (\n profile.siteApplicability.kind ===\n \"exact-site\" &&\n !sameSite(\n profile.siteApplicability.site,\n input.accumulatedCharge.site\n )\n ) {\n throw new InvalidScientificInputError(\n \"Exact-site physical charge capacity does not apply to the accumulated-charge site.\"\n );\n }\n if (\n typeof input.operatingStateId !==\n \"string\" ||\n input.operatingStateId.trim().length ===\n 0 ||\n input.operatingStateId !==\n profile.operatingState.stateId\n ) {\n throw new InvalidScientificInputError(\n \"operatingStateId must exactly match the physical charge-capacity calibration state.\"\n );\n }\n if (\n typeof input.operatingTemperatureC !==\n \"number\" ||\n !Number.isFinite(\n input.operatingTemperatureC\n )\n ) {\n throw new InvalidScientificInputError(\n \"operatingTemperatureC must be finite.\"\n );\n }\n if (\n profile.temperatureApplicability.kind ===\n \"exact-reference-temperature\" &&\n input.operatingTemperatureC !==\n profile.temperatureApplicability\n .temperatureC\n ) {\n throw new InvalidScientificInputError(\n \"operatingTemperatureC must exactly match the physical charge-capacity reference temperature.\"\n );\n }\n\n const capacity =\n profile.capacityElectrons;\n const ratio =\n totalExpectedStoredElectronCount /\n capacity;\n const headroom =\n capacity -\n totalExpectedStoredElectronCount;\n if (\n !Number.isFinite(ratio) ||\n !Number.isFinite(headroom)\n ) {\n throw new InvalidScientificInputError(\n \"Physical charge-capacity comparison must remain finite.\"\n );\n }\n\n const status =\n totalExpectedStoredElectronCount <\n capacity\n ? \"below-capacity\"\n : totalExpectedStoredElectronCount ===\n capacity\n ? \"at-capacity\"\n : \"above-capacity\";\n\n const result:\n SensorPhysicalChargeCapacityAssessment = {\n capacityProfileId:\n profile.profileId,\n completenessProfileId:\n input.accumulatedCharge\n .completenessProfileId,\n colorSamplingProfileId:\n input.accumulatedCharge\n .colorSamplingProfileId,\n channelId:\n input.accumulatedCharge.channelId,\n site: {\n ...input.accumulatedCharge.site\n },\n bindingId:\n input.accumulatedCharge.bindingId,\n operatingStateId:\n input.operatingStateId,\n operatingTemperatureC:\n input.operatingTemperatureC,\n capacityMeaning:\n \"physical-charge-storage-capacity-electrons\",\n physicalChargeCapacityElectrons:\n capacity,\n totalExpectedStoredElectronCount,\n expectedChargeToCapacityRatio:\n ratio,\n expectedChargeHeadroomElectrons:\n headroom,\n expectedChargeCapacityStatus:\n status,\n expectedChargeExceedsCapacity:\n status === \"above-capacity\",\n physicalChargeCapacityAssessmentPerformed:\n true,\n assessmentMeaning:\n \"expected-charge-vs-physical-storage-capacity\",\n actualStochasticSaturationStateKnown:\n false,\n stochasticSaturationProbabilityAssessed:\n false,\n storedChargeAfterPhysicalSaturationCalculated:\n false,\n overflowChargeCalculated: false,\n bloomingModeled: false,\n clampApplied: false,\n cameraSaturationAssessmentAuthorized:\n false,\n adcQuantizationApplied: false,\n rawCodeValueProduced: false,\n capacityUncertaintyPropagated:\n false,\n accumulatedChargeUncertaintyPropagated:\n false,\n componentEvidence: {\n capacity:\n profile.evidence,\n operatingState:\n profile.operatingState\n .evidence,\n siteApproximation:\n profile.siteApplicability.kind ===\n \"uniform-site-capacity-approximation\"\n ? profile\n .siteApplicability\n .evidence\n : [],\n temperatureApproximation:\n profile.temperatureApplicability.kind ===\n \"not-modeled\"\n ? profile\n .temperatureApplicability\n .evidence\n : [],\n chargeCompleteness:\n input.accumulatedCharge\n .componentEvidence\n .completeness\n }\n };\n\n return approximationResult(\n result,\n \"sensor-physical-charge-capacity-assessment\",\n \"1.0.0\",\n [\n \"The capacity is a source-specific physical charge-storage limit in electrons, not EMVA camera saturation capacity and not an ADC/digital clipping threshold.\",\n \"The comparison uses total expected stored electrons after evidence-backed charge completeness. It does not claim a stochastic realization is certainly below or above capacity.\",\n \"Expected charge below capacity does not rule out stochastic saturation; expected charge above capacity indicates the unsaturated linear expectation exceeds the declared physical storage limit.\",\n \"No clamp is applied and stored charge after physical saturation is not calculated because the nonlinear overflow/recombination behavior is not modeled.\",\n \"Blooming direction, neighbor redistribution and anti-blooming behavior require a separate spatial charge-transfer model and are not inferred from excess expected charge.\",\n \"The operating-state identifier is an exact calibration-state key; Photivra does not infer physical capacity from ISO, gain labels, capture mode names or adjacent specifications.\",\n \"A capacity that is uniform across sites or has unmodeled temperature dependence remains an explicit approximation.\",\n \"Capacity and accumulated-charge uncertainties are preserved upstream but are not propagated into a saturation probability or confidence interval by this version.\",\n \"Camera/analog/digital saturation remains a separate downstream response-chain contract.\"\n ]\n );\n}\n"]}
@@ -9,8 +9,9 @@
9
9
  * limits.
10
10
  */
11
11
  import { parseEvidenceList } from "../core/evidence-provenance.js";
12
- import { rejectUnknownFields, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS } from "../core/record-validation.js";
12
+ import { rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS, requireConfigRecord as requireRecord, requireConfigRecordString as requireString } from "../core/record-validation.js";
13
13
  import { InvalidConfigurationError } from "../core/configuration-error.js";
14
+ import { requirePositiveNumber } from "../schema/validation.js";
14
15
  const REQUIRED_REQUIREMENTS = [
15
16
  "scene-spectral-radiance",
16
17
  "optical-transmission",
@@ -24,28 +25,6 @@ const SCIENTIFIC_STATUSES = new Set([
24
25
  "calibrated",
25
26
  "approximation"
26
27
  ]);
27
- function requireRecord(value, path, allowedKeys) {
28
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
29
- throw new InvalidConfigurationError(`${path} must be an object.`);
30
- }
31
- if (allowedKeys !== null)
32
- rejectUnknownFields(value, allowedKeys, path);
33
- return value;
34
- }
35
- function requireString(record, key, path) {
36
- const value = record[key];
37
- if (typeof value !== "string" || value.trim().length === 0) {
38
- throw new InvalidConfigurationError(`${path}.${key} must be a non-empty string.`);
39
- }
40
- return value;
41
- }
42
- function requirePositiveNumber(record, key, path) {
43
- const value = record[key];
44
- if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
45
- throw new InvalidConfigurationError(`${path}.${key} must be a finite number greater than zero.`);
46
- }
47
- return value;
48
- }
49
28
  function requireFraction(record, key, path, allowZero) {
50
29
  const value = record[key];
51
30
  if (typeof value !== "number" ||
@@ -1 +1 @@
1
- {"version":3,"file":"radiometry-readiness.js","sourceRoot":"","sources":["../../src/sensor/radiometry-readiness.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Radiometry readiness: checks whether the declared prerequisites are enough for a nominal photon\n * estimate and, separately, for a calibrated photon claim.\n *\n * The parser checks structure and provenance. It cannot prove that a cited calibration or evidence\n * claim is true. Passing this check does not switch on composed photon or noise output.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { rejectUnknownFields, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS } from \"../core/record-validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nexport type RadiometryRequirementId =\n | \"scene-spectral-radiance\"\n | \"optical-transmission\"\n | \"pupil-vignetting\"\n | \"photosite-collection-area\"\n | \"exposure-integration\"\n | \"sensor-response\";\n\nexport type RadiometryScientificStatus =\n | \"calibrated\"\n | \"approximation\";\n\nexport type RadiometryUncertaintyDeclaration =\n | {\n kind: \"relative\";\n fraction: number;\n basis: string;\n }\n | {\n kind: \"absolute\";\n plusMinus: number;\n unit: string;\n basis: string;\n }\n | {\n kind: \"not-quantified\";\n limitation: string;\n };\n\nexport interface CalibrationArtifactReference {\n id: string;\n checksumSha256: string;\n}\n\ninterface RadiometryRequirementBase {\n requirement: RadiometryRequirementId;\n scientificStatus: RadiometryScientificStatus;\n modelId: string;\n modelVersion: string;\n evidence: readonly EvidenceProvenance[];\n uncertainty: RadiometryUncertaintyDeclaration;\n}\n\nexport interface SceneSpectralRadianceRequirement\n extends RadiometryRequirementBase {\n requirement: \"scene-spectral-radiance\";\n representation:\n | \"spectral-data\"\n | \"documented-spectral-approximation\";\n dataArtifact: CalibrationArtifactReference;\n}\n\nexport type OpticalTransmissionRequirement =\n | (RadiometryRequirementBase & {\n requirement: \"optical-transmission\";\n representation: \"spectral-data\";\n dataArtifact: CalibrationArtifactReference;\n })\n | (RadiometryRequirementBase & {\n requirement: \"optical-transmission\";\n representation: \"t-stop-approximation\";\n tStop: number;\n });\n\nexport type PupilVignettingRequirement =\n | (RadiometryRequirementBase & {\n requirement: \"pupil-vignetting\";\n representation: \"spatial-data\";\n dataArtifact: CalibrationArtifactReference;\n })\n | (RadiometryRequirementBase & {\n requirement: \"pupil-vignetting\";\n representation: \"documented-approximation\";\n });\n\nexport type PhotositeCollectionAreaRequirement =\n | (RadiometryRequirementBase & {\n requirement: \"photosite-collection-area\";\n areaModel: \"effective-collection-area\";\n effectiveCollectionAreaSquareMicrometers: number;\n })\n | (RadiometryRequirementBase & {\n requirement: \"photosite-collection-area\";\n areaModel: \"geometric-area-times-fill-factor\";\n geometricCellAreaSquareMicrometers: number;\n fillFactor: number;\n });\n\nexport type ExposureIntegrationRequirement =\n | (RadiometryRequirementBase & {\n requirement: \"exposure-integration\";\n integrationModel: \"uniform-boxcar\";\n })\n | (RadiometryRequirementBase & {\n requirement: \"exposure-integration\";\n integrationModel: \"documented-shutter-function\";\n dataArtifact: CalibrationArtifactReference;\n });\n\nexport type SensorResponseRequirement =\n | (RadiometryRequirementBase & {\n requirement: \"sensor-response\";\n responseRepresentation: \"spectral-quantum-efficiency\";\n dataArtifact: CalibrationArtifactReference;\n })\n | (RadiometryRequirementBase & {\n requirement: \"sensor-response\";\n responseRepresentation: \"effective-qe-approximation\";\n effectiveQuantumEfficiency: number;\n });\n\nexport type RadiometryRequirement =\n | SceneSpectralRadianceRequirement\n | OpticalTransmissionRequirement\n | PupilVignettingRequirement\n | PhotositeCollectionAreaRequirement\n | ExposureIntegrationRequirement\n | SensorResponseRequirement;\n\nexport interface RadiometryReadinessProfile {\n schemaVersion: \"0.1.0\";\n components: readonly RadiometryRequirement[];\n}\n\nexport interface RadiometryReadinessAssessment {\n status: \"not-ready\" | \"approximate-only\" | \"calibrated-ready\";\n nominalPhotonEstimateReady: boolean;\n calibratedPhotonClaimReady: boolean;\n missingRequirements: readonly RadiometryRequirementId[];\n approximateRequirements: readonly RadiometryRequirementId[];\n unquantifiedUncertaintyRequirements: readonly RadiometryRequirementId[];\n /**\n * Always false: this assessment never switches on composed photon or noise\n * output by itself. Doing so is a separate, explicit later decision.\n */\n composedPhotonOutputEnabled: false;\n}\n\nconst REQUIRED_REQUIREMENTS: readonly RadiometryRequirementId[] = [\n \"scene-spectral-radiance\",\n \"optical-transmission\",\n \"pupil-vignetting\",\n \"photosite-collection-area\",\n \"exposure-integration\",\n \"sensor-response\"\n];\n\nconst REQUIREMENT_IDS = new Set<RadiometryRequirementId>(\n REQUIRED_REQUIREMENTS\n);\n\nconst SCIENTIFIC_STATUSES = new Set<RadiometryScientificStatus>([\n \"calibrated\",\n \"approximation\"\n]);\n\nfunction requireRecord(\n value: unknown,\n path: string,\n allowedKeys: readonly string[] | null\n): UnknownRecord {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new InvalidConfigurationError(`${path} must be an object.`);\n }\n if (allowedKeys !== null) rejectUnknownFields(value, allowedKeys, path);\n return value as UnknownRecord;\n}\n\nfunction requireString(\n record: UnknownRecord,\n key: string,\n path: string\n): string {\n const value = record[key];\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new InvalidConfigurationError(\n `${path}.${key} must be a non-empty string.`\n );\n }\n return value;\n}\n\nfunction requirePositiveNumber(\n record: UnknownRecord,\n key: string,\n path: string\n): number {\n const value = record[key];\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n throw new InvalidConfigurationError(\n `${path}.${key} must be a finite number greater than zero.`\n );\n }\n return value;\n}\n\nfunction requireFraction(\n record: UnknownRecord,\n key: string,\n path: string,\n allowZero: boolean\n): number {\n const value = record[key];\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n (allowZero ? value < 0 : value <= 0) ||\n value > 1\n ) {\n throw new InvalidConfigurationError(\n `${path}.${key} must be a finite fraction ${allowZero ? \"from 0 through 1\" : \"greater than 0 and at most 1\"}.`\n );\n }\n return value;\n}\n\nfunction parseArtifact(\n value: unknown,\n path: string\n): CalibrationArtifactReference {\n const record = requireRecord(value, path, [\"id\", \"checksumSha256\"]);\n const id = requireString(record, \"id\", path);\n const checksumSha256 = requireString(\n record,\n \"checksumSha256\",\n path\n );\n if (!/^[a-f0-9]{64}$/iu.test(checksumSha256)) {\n throw new InvalidConfigurationError(\n `${path}.checksumSha256 must be a 64-character SHA-256 hex digest.`\n );\n }\n return { id, checksumSha256: checksumSha256.toLowerCase() };\n}\n\nfunction parseUncertainty(\n value: unknown,\n path: string\n): RadiometryUncertaintyDeclaration {\n const record = requireRecord(value, path, null);\n rejectUnknownVariantFields(record, \"kind\", { ...UNCERTAINTY_VARIANT_FIELDS, absolute: [\"kind\", \"plusMinus\", \"unit\", \"basis\"] }, path);\n const kind = requireString(record, \"kind\", path);\n\n if (kind === \"relative\") {\n const fraction = record.fraction;\n if (\n typeof fraction !== \"number\" ||\n !Number.isFinite(fraction) ||\n fraction < 0\n ) {\n throw new InvalidConfigurationError(\n `${path}.fraction must be finite and greater than or equal to zero.`\n );\n }\n return {\n kind,\n fraction,\n basis: requireString(record, \"basis\", path)\n };\n }\n\n if (kind === \"absolute\") {\n const plusMinus = record.plusMinus;\n if (\n typeof plusMinus !== \"number\" ||\n !Number.isFinite(plusMinus) ||\n plusMinus < 0\n ) {\n throw new InvalidConfigurationError(\n `${path}.plusMinus must be finite and greater than or equal to zero.`\n );\n }\n return {\n kind,\n plusMinus,\n unit: requireString(record, \"unit\", path),\n basis: requireString(record, \"basis\", path)\n };\n }\n\n if (kind === \"not-quantified\") {\n return {\n kind,\n limitation: requireString(record, \"limitation\", path)\n };\n }\n\n throw new InvalidConfigurationError(`${path}.kind is invalid.`);\n}\n\nfunction parseBase(\n record: UnknownRecord,\n path: string\n): Omit<RadiometryRequirementBase, \"requirement\"> {\n const scientificStatus = requireString(\n record,\n \"scientificStatus\",\n path\n );\n if (\n !SCIENTIFIC_STATUSES.has(\n scientificStatus as RadiometryScientificStatus\n )\n ) {\n throw new InvalidConfigurationError(\n `${path}.scientificStatus is invalid.`\n );\n }\n\n return {\n scientificStatus:\n scientificStatus as RadiometryScientificStatus,\n modelId: requireString(record, \"modelId\", path),\n modelVersion: requireString(record, \"modelVersion\", path),\n evidence: parseEvidenceList(record.evidence, `${path}.evidence`),\n uncertainty: parseUncertainty(\n record.uncertainty,\n `${path}.uncertainty`\n )\n };\n}\n\nfunction requireApproximationStatus(\n base: Omit<RadiometryRequirementBase, \"requirement\">,\n path: string,\n representation: string\n): void {\n if (base.scientificStatus !== \"approximation\") {\n throw new InvalidConfigurationError(\n `${path} uses inherently approximate representation \"${representation}\" and must declare scientificStatus \"approximation\".`\n );\n }\n}\n\nfunction parseRequirement(\n value: unknown,\n path: string\n): RadiometryRequirement {\n const record = requireRecord(value, path, [\"requirement\", \"scientificStatus\", \"modelId\", \"modelVersion\", \"evidence\", \"uncertainty\", \"representation\", \"dataArtifact\", \"tStop\", \"areaModel\", \"geometricPitchXMicrometers\", \"geometricPitchYMicrometers\", \"effectiveCollectionAreaSquareMicrometers\", \"geometricCellAreaSquareMicrometers\", \"fillFactor\", \"integrationModel\", \"responseRepresentation\", \"effectiveQuantumEfficiency\"]);\n const requirement = requireString(record, \"requirement\", path);\n if (!REQUIREMENT_IDS.has(requirement as RadiometryRequirementId)) {\n throw new InvalidConfigurationError(\n `${path}.requirement is invalid.`\n );\n }\n\n const base = parseBase(record, path);\n\n if (requirement === \"scene-spectral-radiance\") {\n const representation = requireString(\n record,\n \"representation\",\n path\n );\n if (\n representation !== \"spectral-data\" &&\n representation !== \"documented-spectral-approximation\"\n ) {\n throw new InvalidConfigurationError(\n `${path}.representation is invalid.`\n );\n }\n if (representation === \"documented-spectral-approximation\") {\n requireApproximationStatus(base, path, representation);\n }\n return {\n requirement,\n ...base,\n representation,\n dataArtifact: parseArtifact(\n record.dataArtifact,\n `${path}.dataArtifact`\n )\n };\n }\n\n if (requirement === \"optical-transmission\") {\n const representation = requireString(\n record,\n \"representation\",\n path\n );\n if (representation === \"spectral-data\") {\n return {\n requirement,\n ...base,\n representation,\n dataArtifact: parseArtifact(\n record.dataArtifact,\n `${path}.dataArtifact`\n )\n };\n }\n if (representation === \"t-stop-approximation\") {\n requireApproximationStatus(base, path, representation);\n return {\n requirement,\n ...base,\n representation,\n tStop: requirePositiveNumber(record, \"tStop\", path)\n };\n }\n throw new InvalidConfigurationError(\n `${path}.representation is invalid.`\n );\n }\n\n if (requirement === \"pupil-vignetting\") {\n const representation = requireString(\n record,\n \"representation\",\n path\n );\n if (representation === \"spatial-data\") {\n return {\n requirement,\n ...base,\n representation,\n dataArtifact: parseArtifact(\n record.dataArtifact,\n `${path}.dataArtifact`\n )\n };\n }\n if (representation === \"documented-approximation\") {\n requireApproximationStatus(base, path, representation);\n return { requirement, ...base, representation };\n }\n throw new InvalidConfigurationError(\n `${path}.representation is invalid.`\n );\n }\n\n if (requirement === \"photosite-collection-area\") {\n if (\n record.areaModel === undefined &&\n (record.geometricPitchXMicrometers !== undefined ||\n record.geometricPitchYMicrometers !== undefined)\n ) {\n throw new InvalidConfigurationError(\n `${path}.areaModel is required. Geometric sample pitch alone is not a photosite collection-area model.`\n );\n }\n const areaModel = requireString(record, \"areaModel\", path);\n if (areaModel === \"effective-collection-area\") {\n return {\n requirement,\n ...base,\n areaModel,\n effectiveCollectionAreaSquareMicrometers:\n requirePositiveNumber(\n record,\n \"effectiveCollectionAreaSquareMicrometers\",\n path\n )\n };\n }\n if (areaModel === \"geometric-area-times-fill-factor\") {\n return {\n requirement,\n ...base,\n areaModel,\n geometricCellAreaSquareMicrometers:\n requirePositiveNumber(\n record,\n \"geometricCellAreaSquareMicrometers\",\n path\n ),\n fillFactor: requireFraction(\n record,\n \"fillFactor\",\n path,\n false\n )\n };\n }\n throw new InvalidConfigurationError(\n `${path}.areaModel is invalid. Geometric sample pitch alone is not a photosite collection-area model.`\n );\n }\n\n if (requirement === \"exposure-integration\") {\n const integrationModel = requireString(\n record,\n \"integrationModel\",\n path\n );\n if (integrationModel === \"uniform-boxcar\") {\n return { requirement, ...base, integrationModel };\n }\n if (integrationModel === \"documented-shutter-function\") {\n return {\n requirement,\n ...base,\n integrationModel,\n dataArtifact: parseArtifact(\n record.dataArtifact,\n `${path}.dataArtifact`\n )\n };\n }\n throw new InvalidConfigurationError(\n `${path}.integrationModel is invalid.`\n );\n }\n\n const responseRepresentation = requireString(\n record,\n \"responseRepresentation\",\n path\n );\n if (responseRepresentation === \"spectral-quantum-efficiency\") {\n return {\n requirement: \"sensor-response\",\n ...base,\n responseRepresentation,\n dataArtifact: parseArtifact(\n record.dataArtifact,\n `${path}.dataArtifact`\n )\n };\n }\n if (responseRepresentation === \"effective-qe-approximation\") {\n requireApproximationStatus(base, path, responseRepresentation);\n return {\n requirement: \"sensor-response\",\n ...base,\n responseRepresentation,\n effectiveQuantumEfficiency: requireFraction(\n record,\n \"effectiveQuantumEfficiency\",\n path,\n true\n )\n };\n }\n throw new InvalidConfigurationError(\n `${path}.responseRepresentation is invalid.`\n );\n}\n\n/**\n * Parses untrusted metadata about radiometry prerequisites.\n *\n * It checks structure and provenance. It cannot prove that a cited calibration\n * or evidence claim is scientifically true.\n */\nexport function parseRadiometryReadinessProfile(\n value: unknown\n): RadiometryReadinessProfile {\n const profile = requireRecord(value, \"radiometryReadiness\", [\"schemaVersion\", \"components\"]);\n if (profile.schemaVersion !== \"0.1.0\") {\n throw new InvalidConfigurationError(\n 'radiometryReadiness.schemaVersion must be \"0.1.0\".'\n );\n }\n if (!Array.isArray(profile.components)) {\n throw new InvalidConfigurationError(\n \"radiometryReadiness.components must be an array.\"\n );\n }\n\n const components = profile.components.map((component, index) =>\n parseRequirement(\n component,\n `radiometryReadiness.components[${index}]`\n )\n );\n const ids = components.map((component) => component.requirement);\n if (new Set(ids).size !== ids.length) {\n throw new InvalidConfigurationError(\n \"radiometryReadiness.components must not contain duplicate requirement IDs.\"\n );\n }\n\n return {\n schemaVersion: \"0.1.0\",\n components\n };\n}\n\n/**\n * Checks whether the declared prerequisites are enough for a nominal photon\n * estimate and, separately, for a calibrated photon claim.\n *\n * It does not switch on composed photon or noise output.\n */\nexport function assessRadiometryReadiness(\n profile: RadiometryReadinessProfile\n): RadiometryReadinessAssessment {\n const validatedProfile = parseRadiometryReadinessProfile(profile);\n const byId = new Map(\n validatedProfile.components.map((component) => [\n component.requirement,\n component\n ])\n );\n const missingRequirements = REQUIRED_REQUIREMENTS.filter(\n (requirement) => !byId.has(requirement)\n );\n const approximateRequirements = validatedProfile.components\n .filter(\n (component) =>\n component.scientificStatus === \"approximation\"\n )\n .map((component) => component.requirement);\n const unquantifiedUncertaintyRequirements = validatedProfile.components\n .filter(\n (component) =>\n component.uncertainty.kind === \"not-quantified\"\n )\n .map((component) => component.requirement);\n\n const nominalPhotonEstimateReady = missingRequirements.length === 0;\n const calibratedPhotonClaimReady =\n nominalPhotonEstimateReady &&\n approximateRequirements.length === 0 &&\n unquantifiedUncertaintyRequirements.length === 0;\n\n return {\n status: !nominalPhotonEstimateReady\n ? \"not-ready\"\n : calibratedPhotonClaimReady\n ? \"calibrated-ready\"\n : \"approximate-only\",\n nominalPhotonEstimateReady,\n calibratedPhotonClaimReady,\n missingRequirements,\n approximateRequirements,\n unquantifiedUncertaintyRequirements,\n composedPhotonOutputEnabled: false\n };\n}\n"]}
1
+ {"version":3,"file":"radiometry-readiness.js","sourceRoot":"","sources":["../../src/sensor/radiometry-readiness.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Radiometry readiness: checks whether the declared prerequisites are enough for a nominal photon\n * estimate and, separately, for a calibrated photon claim.\n *\n * The parser checks structure and provenance. It cannot prove that a cited calibration or evidence\n * claim is true. Passing this check does not switch on composed photon or noise output.\n * @see docs/MOTION_AND_SIGNAL.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS, requireConfigRecord as requireRecord, requireConfigRecordString as requireString } from \"../core/record-validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requirePositiveNumber } from \"../schema/validation.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nexport type RadiometryRequirementId =\n | \"scene-spectral-radiance\"\n | \"optical-transmission\"\n | \"pupil-vignetting\"\n | \"photosite-collection-area\"\n | \"exposure-integration\"\n | \"sensor-response\";\n\nexport type RadiometryScientificStatus =\n | \"calibrated\"\n | \"approximation\";\n\nexport type RadiometryUncertaintyDeclaration =\n | {\n kind: \"relative\";\n fraction: number;\n basis: string;\n }\n | {\n kind: \"absolute\";\n plusMinus: number;\n unit: string;\n basis: string;\n }\n | {\n kind: \"not-quantified\";\n limitation: string;\n };\n\nexport interface CalibrationArtifactReference {\n id: string;\n checksumSha256: string;\n}\n\ninterface RadiometryRequirementBase {\n requirement: RadiometryRequirementId;\n scientificStatus: RadiometryScientificStatus;\n modelId: string;\n modelVersion: string;\n evidence: readonly EvidenceProvenance[];\n uncertainty: RadiometryUncertaintyDeclaration;\n}\n\nexport interface SceneSpectralRadianceRequirement\n extends RadiometryRequirementBase {\n requirement: \"scene-spectral-radiance\";\n representation:\n | \"spectral-data\"\n | \"documented-spectral-approximation\";\n dataArtifact: CalibrationArtifactReference;\n}\n\nexport type OpticalTransmissionRequirement =\n | (RadiometryRequirementBase & {\n requirement: \"optical-transmission\";\n representation: \"spectral-data\";\n dataArtifact: CalibrationArtifactReference;\n })\n | (RadiometryRequirementBase & {\n requirement: \"optical-transmission\";\n representation: \"t-stop-approximation\";\n tStop: number;\n });\n\nexport type PupilVignettingRequirement =\n | (RadiometryRequirementBase & {\n requirement: \"pupil-vignetting\";\n representation: \"spatial-data\";\n dataArtifact: CalibrationArtifactReference;\n })\n | (RadiometryRequirementBase & {\n requirement: \"pupil-vignetting\";\n representation: \"documented-approximation\";\n });\n\nexport type PhotositeCollectionAreaRequirement =\n | (RadiometryRequirementBase & {\n requirement: \"photosite-collection-area\";\n areaModel: \"effective-collection-area\";\n effectiveCollectionAreaSquareMicrometers: number;\n })\n | (RadiometryRequirementBase & {\n requirement: \"photosite-collection-area\";\n areaModel: \"geometric-area-times-fill-factor\";\n geometricCellAreaSquareMicrometers: number;\n fillFactor: number;\n });\n\nexport type ExposureIntegrationRequirement =\n | (RadiometryRequirementBase & {\n requirement: \"exposure-integration\";\n integrationModel: \"uniform-boxcar\";\n })\n | (RadiometryRequirementBase & {\n requirement: \"exposure-integration\";\n integrationModel: \"documented-shutter-function\";\n dataArtifact: CalibrationArtifactReference;\n });\n\nexport type SensorResponseRequirement =\n | (RadiometryRequirementBase & {\n requirement: \"sensor-response\";\n responseRepresentation: \"spectral-quantum-efficiency\";\n dataArtifact: CalibrationArtifactReference;\n })\n | (RadiometryRequirementBase & {\n requirement: \"sensor-response\";\n responseRepresentation: \"effective-qe-approximation\";\n effectiveQuantumEfficiency: number;\n });\n\nexport type RadiometryRequirement =\n | SceneSpectralRadianceRequirement\n | OpticalTransmissionRequirement\n | PupilVignettingRequirement\n | PhotositeCollectionAreaRequirement\n | ExposureIntegrationRequirement\n | SensorResponseRequirement;\n\nexport interface RadiometryReadinessProfile {\n schemaVersion: \"0.1.0\";\n components: readonly RadiometryRequirement[];\n}\n\nexport interface RadiometryReadinessAssessment {\n status: \"not-ready\" | \"approximate-only\" | \"calibrated-ready\";\n nominalPhotonEstimateReady: boolean;\n calibratedPhotonClaimReady: boolean;\n missingRequirements: readonly RadiometryRequirementId[];\n approximateRequirements: readonly RadiometryRequirementId[];\n unquantifiedUncertaintyRequirements: readonly RadiometryRequirementId[];\n /**\n * Always false: this assessment never switches on composed photon or noise\n * output by itself. Doing so is a separate, explicit later decision.\n */\n composedPhotonOutputEnabled: false;\n}\n\nconst REQUIRED_REQUIREMENTS: readonly RadiometryRequirementId[] = [\n \"scene-spectral-radiance\",\n \"optical-transmission\",\n \"pupil-vignetting\",\n \"photosite-collection-area\",\n \"exposure-integration\",\n \"sensor-response\"\n];\n\nconst REQUIREMENT_IDS = new Set<RadiometryRequirementId>(\n REQUIRED_REQUIREMENTS\n);\n\nconst SCIENTIFIC_STATUSES = new Set<RadiometryScientificStatus>([\n \"calibrated\",\n \"approximation\"\n]);\n\nfunction requireFraction(\n record: UnknownRecord,\n key: string,\n path: string,\n allowZero: boolean\n): number {\n const value = record[key];\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n (allowZero ? value < 0 : value <= 0) ||\n value > 1\n ) {\n throw new InvalidConfigurationError(\n `${path}.${key} must be a finite fraction ${allowZero ? \"from 0 through 1\" : \"greater than 0 and at most 1\"}.`\n );\n }\n return value;\n}\n\nfunction parseArtifact(\n value: unknown,\n path: string\n): CalibrationArtifactReference {\n const record = requireRecord(value, path, [\"id\", \"checksumSha256\"]);\n const id = requireString(record, \"id\", path);\n const checksumSha256 = requireString(\n record,\n \"checksumSha256\",\n path\n );\n if (!/^[a-f0-9]{64}$/iu.test(checksumSha256)) {\n throw new InvalidConfigurationError(\n `${path}.checksumSha256 must be a 64-character SHA-256 hex digest.`\n );\n }\n return { id, checksumSha256: checksumSha256.toLowerCase() };\n}\n\nfunction parseUncertainty(\n value: unknown,\n path: string\n): RadiometryUncertaintyDeclaration {\n const record = requireRecord(value, path, null);\n rejectUnknownVariantFields(record, \"kind\", { ...UNCERTAINTY_VARIANT_FIELDS, absolute: [\"kind\", \"plusMinus\", \"unit\", \"basis\"] }, path);\n const kind = requireString(record, \"kind\", path);\n\n if (kind === \"relative\") {\n const fraction = record.fraction;\n if (\n typeof fraction !== \"number\" ||\n !Number.isFinite(fraction) ||\n fraction < 0\n ) {\n throw new InvalidConfigurationError(\n `${path}.fraction must be finite and greater than or equal to zero.`\n );\n }\n return {\n kind,\n fraction,\n basis: requireString(record, \"basis\", path)\n };\n }\n\n if (kind === \"absolute\") {\n const plusMinus = record.plusMinus;\n if (\n typeof plusMinus !== \"number\" ||\n !Number.isFinite(plusMinus) ||\n plusMinus < 0\n ) {\n throw new InvalidConfigurationError(\n `${path}.plusMinus must be finite and greater than or equal to zero.`\n );\n }\n return {\n kind,\n plusMinus,\n unit: requireString(record, \"unit\", path),\n basis: requireString(record, \"basis\", path)\n };\n }\n\n if (kind === \"not-quantified\") {\n return {\n kind,\n limitation: requireString(record, \"limitation\", path)\n };\n }\n\n throw new InvalidConfigurationError(`${path}.kind is invalid.`);\n}\n\nfunction parseBase(\n record: UnknownRecord,\n path: string\n): Omit<RadiometryRequirementBase, \"requirement\"> {\n const scientificStatus = requireString(\n record,\n \"scientificStatus\",\n path\n );\n if (\n !SCIENTIFIC_STATUSES.has(\n scientificStatus as RadiometryScientificStatus\n )\n ) {\n throw new InvalidConfigurationError(\n `${path}.scientificStatus is invalid.`\n );\n }\n\n return {\n scientificStatus:\n scientificStatus as RadiometryScientificStatus,\n modelId: requireString(record, \"modelId\", path),\n modelVersion: requireString(record, \"modelVersion\", path),\n evidence: parseEvidenceList(record.evidence, `${path}.evidence`),\n uncertainty: parseUncertainty(\n record.uncertainty,\n `${path}.uncertainty`\n )\n };\n}\n\nfunction requireApproximationStatus(\n base: Omit<RadiometryRequirementBase, \"requirement\">,\n path: string,\n representation: string\n): void {\n if (base.scientificStatus !== \"approximation\") {\n throw new InvalidConfigurationError(\n `${path} uses inherently approximate representation \"${representation}\" and must declare scientificStatus \"approximation\".`\n );\n }\n}\n\nfunction parseRequirement(\n value: unknown,\n path: string\n): RadiometryRequirement {\n const record = requireRecord(value, path, [\"requirement\", \"scientificStatus\", \"modelId\", \"modelVersion\", \"evidence\", \"uncertainty\", \"representation\", \"dataArtifact\", \"tStop\", \"areaModel\", \"geometricPitchXMicrometers\", \"geometricPitchYMicrometers\", \"effectiveCollectionAreaSquareMicrometers\", \"geometricCellAreaSquareMicrometers\", \"fillFactor\", \"integrationModel\", \"responseRepresentation\", \"effectiveQuantumEfficiency\"]);\n const requirement = requireString(record, \"requirement\", path);\n if (!REQUIREMENT_IDS.has(requirement as RadiometryRequirementId)) {\n throw new InvalidConfigurationError(\n `${path}.requirement is invalid.`\n );\n }\n\n const base = parseBase(record, path);\n\n if (requirement === \"scene-spectral-radiance\") {\n const representation = requireString(\n record,\n \"representation\",\n path\n );\n if (\n representation !== \"spectral-data\" &&\n representation !== \"documented-spectral-approximation\"\n ) {\n throw new InvalidConfigurationError(\n `${path}.representation is invalid.`\n );\n }\n if (representation === \"documented-spectral-approximation\") {\n requireApproximationStatus(base, path, representation);\n }\n return {\n requirement,\n ...base,\n representation,\n dataArtifact: parseArtifact(\n record.dataArtifact,\n `${path}.dataArtifact`\n )\n };\n }\n\n if (requirement === \"optical-transmission\") {\n const representation = requireString(\n record,\n \"representation\",\n path\n );\n if (representation === \"spectral-data\") {\n return {\n requirement,\n ...base,\n representation,\n dataArtifact: parseArtifact(\n record.dataArtifact,\n `${path}.dataArtifact`\n )\n };\n }\n if (representation === \"t-stop-approximation\") {\n requireApproximationStatus(base, path, representation);\n return {\n requirement,\n ...base,\n representation,\n tStop: requirePositiveNumber(record, \"tStop\", path)\n };\n }\n throw new InvalidConfigurationError(\n `${path}.representation is invalid.`\n );\n }\n\n if (requirement === \"pupil-vignetting\") {\n const representation = requireString(\n record,\n \"representation\",\n path\n );\n if (representation === \"spatial-data\") {\n return {\n requirement,\n ...base,\n representation,\n dataArtifact: parseArtifact(\n record.dataArtifact,\n `${path}.dataArtifact`\n )\n };\n }\n if (representation === \"documented-approximation\") {\n requireApproximationStatus(base, path, representation);\n return { requirement, ...base, representation };\n }\n throw new InvalidConfigurationError(\n `${path}.representation is invalid.`\n );\n }\n\n if (requirement === \"photosite-collection-area\") {\n if (\n record.areaModel === undefined &&\n (record.geometricPitchXMicrometers !== undefined ||\n record.geometricPitchYMicrometers !== undefined)\n ) {\n throw new InvalidConfigurationError(\n `${path}.areaModel is required. Geometric sample pitch alone is not a photosite collection-area model.`\n );\n }\n const areaModel = requireString(record, \"areaModel\", path);\n if (areaModel === \"effective-collection-area\") {\n return {\n requirement,\n ...base,\n areaModel,\n effectiveCollectionAreaSquareMicrometers:\n requirePositiveNumber(\n record,\n \"effectiveCollectionAreaSquareMicrometers\",\n path\n )\n };\n }\n if (areaModel === \"geometric-area-times-fill-factor\") {\n return {\n requirement,\n ...base,\n areaModel,\n geometricCellAreaSquareMicrometers:\n requirePositiveNumber(\n record,\n \"geometricCellAreaSquareMicrometers\",\n path\n ),\n fillFactor: requireFraction(\n record,\n \"fillFactor\",\n path,\n false\n )\n };\n }\n throw new InvalidConfigurationError(\n `${path}.areaModel is invalid. Geometric sample pitch alone is not a photosite collection-area model.`\n );\n }\n\n if (requirement === \"exposure-integration\") {\n const integrationModel = requireString(\n record,\n \"integrationModel\",\n path\n );\n if (integrationModel === \"uniform-boxcar\") {\n return { requirement, ...base, integrationModel };\n }\n if (integrationModel === \"documented-shutter-function\") {\n return {\n requirement,\n ...base,\n integrationModel,\n dataArtifact: parseArtifact(\n record.dataArtifact,\n `${path}.dataArtifact`\n )\n };\n }\n throw new InvalidConfigurationError(\n `${path}.integrationModel is invalid.`\n );\n }\n\n const responseRepresentation = requireString(\n record,\n \"responseRepresentation\",\n path\n );\n if (responseRepresentation === \"spectral-quantum-efficiency\") {\n return {\n requirement: \"sensor-response\",\n ...base,\n responseRepresentation,\n dataArtifact: parseArtifact(\n record.dataArtifact,\n `${path}.dataArtifact`\n )\n };\n }\n if (responseRepresentation === \"effective-qe-approximation\") {\n requireApproximationStatus(base, path, responseRepresentation);\n return {\n requirement: \"sensor-response\",\n ...base,\n responseRepresentation,\n effectiveQuantumEfficiency: requireFraction(\n record,\n \"effectiveQuantumEfficiency\",\n path,\n true\n )\n };\n }\n throw new InvalidConfigurationError(\n `${path}.responseRepresentation is invalid.`\n );\n}\n\n/**\n * Parses untrusted metadata about radiometry prerequisites.\n *\n * It checks structure and provenance. It cannot prove that a cited calibration\n * or evidence claim is scientifically true.\n */\nexport function parseRadiometryReadinessProfile(\n value: unknown\n): RadiometryReadinessProfile {\n const profile = requireRecord(value, \"radiometryReadiness\", [\"schemaVersion\", \"components\"]);\n if (profile.schemaVersion !== \"0.1.0\") {\n throw new InvalidConfigurationError(\n 'radiometryReadiness.schemaVersion must be \"0.1.0\".'\n );\n }\n if (!Array.isArray(profile.components)) {\n throw new InvalidConfigurationError(\n \"radiometryReadiness.components must be an array.\"\n );\n }\n\n const components = profile.components.map((component, index) =>\n parseRequirement(\n component,\n `radiometryReadiness.components[${index}]`\n )\n );\n const ids = components.map((component) => component.requirement);\n if (new Set(ids).size !== ids.length) {\n throw new InvalidConfigurationError(\n \"radiometryReadiness.components must not contain duplicate requirement IDs.\"\n );\n }\n\n return {\n schemaVersion: \"0.1.0\",\n components\n };\n}\n\n/**\n * Checks whether the declared prerequisites are enough for a nominal photon\n * estimate and, separately, for a calibrated photon claim.\n *\n * It does not switch on composed photon or noise output.\n */\nexport function assessRadiometryReadiness(\n profile: RadiometryReadinessProfile\n): RadiometryReadinessAssessment {\n const validatedProfile = parseRadiometryReadinessProfile(profile);\n const byId = new Map(\n validatedProfile.components.map((component) => [\n component.requirement,\n component\n ])\n );\n const missingRequirements = REQUIRED_REQUIREMENTS.filter(\n (requirement) => !byId.has(requirement)\n );\n const approximateRequirements = validatedProfile.components\n .filter(\n (component) =>\n component.scientificStatus === \"approximation\"\n )\n .map((component) => component.requirement);\n const unquantifiedUncertaintyRequirements = validatedProfile.components\n .filter(\n (component) =>\n component.uncertainty.kind === \"not-quantified\"\n )\n .map((component) => component.requirement);\n\n const nominalPhotonEstimateReady = missingRequirements.length === 0;\n const calibratedPhotonClaimReady =\n nominalPhotonEstimateReady &&\n approximateRequirements.length === 0 &&\n unquantifiedUncertaintyRequirements.length === 0;\n\n return {\n status: !nominalPhotonEstimateReady\n ? \"not-ready\"\n : calibratedPhotonClaimReady\n ? \"calibrated-ready\"\n : \"approximate-only\",\n nominalPhotonEstimateReady,\n calibratedPhotonClaimReady,\n missingRequirements,\n approximateRequirements,\n unquantifiedUncertaintyRequirements,\n composedPhotonOutputEnabled: false\n };\n}\n"]}
@@ -299,6 +299,9 @@ export interface SensorRawCodeSample {
299
299
  isoUsedToInferRegime: false;
300
300
  deterministicSeededRealization: true;
301
301
  }
302
+ export declare function requireSafeInteger(value: unknown, path: string): number;
303
+ export declare function parsePositiveFact(value: unknown, path: string): EvidenceBackedFact<number>;
304
+ export declare function parseNonNegativeFact(value: unknown, path: string): EvidenceBackedFact<number>;
302
305
  /**
303
306
  * Validates untrusted input and returns it as a normalized, typed value. Unknown enum values,
304
307
  * missing required fields and inconsistent scientific data are rejected.
@@ -24,50 +24,10 @@ import { parseEvidenceList } from "../core/evidence-provenance.js";
24
24
  import { InvalidScientificInputError } from "../core/validation.js";
25
25
  import { createDeterministicUniformStream, sampleDeterministicStandardNormal, samplePortableStandardNormal } from "./stochastic-seed.js";
26
26
  import { portableExp, portableLog } from "../core/portable-math.js";
27
- import { requireInputKeys, rejectUnknownFields } from "../core/record-validation.js";
27
+ import { requireInputKeys, requireConfigRecord as requireRecord, requireTrimmedConfigString as requireNonEmptyString, requireConfigFinite as requireFinite, parseConfigScientificStatus as parseStatus, parseConfigLimitations as parseLimitations, requireConfigFiniteAboveZero as requirePositiveFinite, requireConfigFiniteAtLeastZero as requireNonNegativeFinite } from "../core/record-validation.js";
28
28
  import { evaluateParsedFixedPatternSite, parseSensorFixedPatternNoiseProfile } from "./fixed-pattern-noise.js";
29
29
  export const SENSOR_CHARGE_SAMPLING_PROFILE_SCHEMA_VERSION = "0.1.0";
30
30
  export const SENSOR_READOUT_CONVERSION_PROFILE_SCHEMA_VERSION = "0.1.0";
31
- function requireRecord(value, path, allowedKeys) {
32
- if (typeof value !== "object" ||
33
- value === null ||
34
- Array.isArray(value)) {
35
- throw new InvalidConfigurationError(path + " must be an object.");
36
- }
37
- if (allowedKeys !== null)
38
- rejectUnknownFields(value, allowedKeys, path);
39
- return value;
40
- }
41
- function requireNonEmptyString(value, path) {
42
- if (typeof value !== "string" ||
43
- value.trim().length === 0) {
44
- throw new InvalidConfigurationError(path + " must be a non-empty string.");
45
- }
46
- return value.trim();
47
- }
48
- function requireFinite(value, path) {
49
- if (typeof value !== "number" ||
50
- !Number.isFinite(value)) {
51
- throw new InvalidConfigurationError(path + " must be finite.");
52
- }
53
- return value;
54
- }
55
- function requireNonNegativeFinite(value, path) {
56
- const parsed = requireFinite(value, path);
57
- if (parsed < 0) {
58
- throw new InvalidConfigurationError(path +
59
- " must be greater than or equal to zero.");
60
- }
61
- return parsed;
62
- }
63
- function requirePositiveFinite(value, path) {
64
- const parsed = requireFinite(value, path);
65
- if (parsed <= 0) {
66
- throw new InvalidConfigurationError(path +
67
- " must be greater than zero.");
68
- }
69
- return parsed;
70
- }
71
31
  function requireUint32(value, path) {
72
32
  if (typeof value !== "number" ||
73
33
  !Number.isSafeInteger(value) ||
@@ -78,36 +38,21 @@ function requireUint32(value, path) {
78
38
  }
79
39
  return value;
80
40
  }
81
- function requireSafeInteger(value, path) {
41
+ export function requireSafeInteger(value, path) {
82
42
  if (typeof value !== "number" ||
83
43
  !Number.isSafeInteger(value)) {
84
44
  throw new InvalidConfigurationError(path + " must be a safe integer.");
85
45
  }
86
46
  return value;
87
47
  }
88
- function parseLimitations(value, path) {
89
- if (!Array.isArray(value)) {
90
- throw new InvalidConfigurationError(path + " must be an array.");
91
- }
92
- const parsed = value.map((entry, index) => requireNonEmptyString(entry, path +
93
- "[" +
94
- index +
95
- "]"));
96
- if (new Set(parsed).size !==
97
- parsed.length) {
98
- throw new InvalidConfigurationError(path +
99
- " must not contain duplicates.");
100
- }
101
- return parsed;
102
- }
103
- function parsePositiveFact(value, path) {
48
+ export function parsePositiveFact(value, path) {
104
49
  const record = requireRecord(value, path, ["value", "evidence"]);
105
50
  return {
106
51
  value: requirePositiveFinite(record.value, path + ".value"),
107
52
  evidence: parseEvidenceList(record.evidence, path + ".evidence")
108
53
  };
109
54
  }
110
- function parseNonNegativeFact(value, path) {
55
+ export function parseNonNegativeFact(value, path) {
111
56
  const record = requireRecord(value, path, ["value", "evidence"]);
112
57
  return {
113
58
  value: requireNonNegativeFinite(record.value, path + ".value"),
@@ -180,13 +125,6 @@ export function parseSensorChargeSamplingProfile(value) {
180
125
  limitations: parseLimitations(record.limitations, "sensorChargeSamplingProfile.limitations")
181
126
  };
182
127
  }
183
- function parseStatus(value, path) {
184
- if (value !== "calibrated" &&
185
- value !== "approximation") {
186
- throw new InvalidConfigurationError(path + " is invalid.");
187
- }
188
- return value;
189
- }
190
128
  function parseReadNoiseComponent(value, path) {
191
129
  const record = requireRecord(value, path, ["componentId", "rmsElectrons", "evidence"]);
192
130
  return {