@photivra/engine 2.17.0 → 2.19.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 (288) hide show
  1. package/CHANGELOG.md +116 -1
  2. package/CITATION.cff +1 -1
  3. package/README.md +6 -6
  4. package/SECURITY.md +1 -1
  5. package/dist/camera/sensor-equivalence.d.ts +156 -0
  6. package/dist/camera/sensor-equivalence.js +208 -0
  7. package/dist/camera/sensor-equivalence.js.map +1 -0
  8. package/dist/capture/focus-control.js +2 -75
  9. package/dist/capture/focus-control.js.map +1 -1
  10. package/dist/capture/native-environment-lean.d.ts +1 -0
  11. package/dist/capture/native-environment-lean.js +1 -1
  12. package/dist/capture/native-environment-lean.js.map +1 -1
  13. package/dist/capture/native-environment-optical-stage.d.ts +1 -0
  14. package/dist/capture/native-environment-optical-stage.js +2 -5
  15. package/dist/capture/native-environment-optical-stage.js.map +1 -1
  16. package/dist/capture/native-environment-raw.js +1 -5
  17. package/dist/capture/native-environment-raw.js.map +1 -1
  18. package/dist/capture/native-environment-tabulated.d.ts +5 -0
  19. package/dist/capture/native-environment-tabulated.js +1 -1
  20. package/dist/capture/native-environment-tabulated.js.map +1 -1
  21. package/dist/capture/release-sequence.js +2 -47
  22. package/dist/capture/release-sequence.js.map +1 -1
  23. package/dist/color/white-balance.d.ts +2 -0
  24. package/dist/color/white-balance.js +3 -56
  25. package/dist/color/white-balance.js.map +1 -1
  26. package/dist/composition/image-formation-plan.d.ts +1 -0
  27. package/dist/composition/image-formation-plan.js +3 -49
  28. package/dist/composition/image-formation-plan.js.map +1 -1
  29. package/dist/core/evidence-provenance.js +1 -16
  30. package/dist/core/evidence-provenance.js.map +1 -1
  31. package/dist/core/record-validation.d.ts +54 -0
  32. package/dist/core/record-validation.js +176 -0
  33. package/dist/core/record-validation.js.map +1 -1
  34. package/dist/core/scientific-assurance.js +1 -18
  35. package/dist/core/scientific-assurance.js.map +1 -1
  36. package/dist/core/shared-helpers.d.ts +33 -0
  37. package/dist/core/shared-helpers.js +34 -0
  38. package/dist/core/shared-helpers.js.map +1 -0
  39. package/dist/core/spectral-composition.js +1 -36
  40. package/dist/core/spectral-composition.js.map +1 -1
  41. package/dist/core/spectral.js +1 -19
  42. package/dist/core/spectral.js.map +1 -1
  43. package/dist/core/version.d.ts +1 -1
  44. package/dist/core/version.js +1 -1
  45. package/dist/core/version.js.map +1 -1
  46. package/dist/equipment/exposure-capabilities.d.ts +1 -0
  47. package/dist/equipment/exposure-capabilities.js +2 -36
  48. package/dist/equipment/exposure-capabilities.js.map +1 -1
  49. package/dist/equipment/ideal-lens.d.ts +25 -0
  50. package/dist/equipment/ideal-lens.js +21 -0
  51. package/dist/equipment/ideal-lens.js.map +1 -0
  52. package/dist/equipment/iso-capabilities.js +2 -49
  53. package/dist/equipment/iso-capabilities.js.map +1 -1
  54. package/dist/equipment/metering-capabilities.js +1 -26
  55. package/dist/equipment/metering-capabilities.js.map +1 -1
  56. package/dist/equipment/release-capabilities.js +1 -53
  57. package/dist/equipment/release-capabilities.js.map +1 -1
  58. package/dist/exposure/auto-iso-slowest-shutter.js +1 -7
  59. package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
  60. package/dist/exposure/exposure-duration-control.js +1 -16
  61. package/dist/exposure/exposure-duration-control.js.map +1 -1
  62. package/dist/exposure/exposure-mode-resolver.js +1 -17
  63. package/dist/exposure/exposure-mode-resolver.js.map +1 -1
  64. package/dist/exposure/filtered-exposure-time.d.ts +93 -0
  65. package/dist/exposure/filtered-exposure-time.js +129 -0
  66. package/dist/exposure/filtered-exposure-time.js.map +1 -0
  67. package/dist/exposure/flash-ttl.d.ts +1 -0
  68. package/dist/exposure/flash-ttl.js +1 -1
  69. package/dist/exposure/flash-ttl.js.map +1 -1
  70. package/dist/exposure/flash.js +1 -49
  71. package/dist/exposure/flash.js.map +1 -1
  72. package/dist/exposure/metering-scene-radiance.js +1 -25
  73. package/dist/exposure/metering-scene-radiance.js.map +1 -1
  74. package/dist/exposure/metering-target.js +1 -30
  75. package/dist/exposure/metering-target.js.map +1 -1
  76. package/dist/exposure/metering-temporal.js +1 -8
  77. package/dist/exposure/metering-temporal.js.map +1 -1
  78. package/dist/exposure/metering.js +1 -72
  79. package/dist/exposure/metering.js.map +1 -1
  80. package/dist/exposure/program-line.js +1 -45
  81. package/dist/exposure/program-line.js.map +1 -1
  82. package/dist/facade/catalogue-lens-signal.d.ts +94 -0
  83. package/dist/facade/catalogue-lens-signal.js +362 -0
  84. package/dist/facade/catalogue-lens-signal.js.map +1 -0
  85. package/dist/facade/defocus-image-space-provider.js +5 -2
  86. package/dist/facade/defocus-image-space-provider.js.map +1 -1
  87. package/dist/facade/develop-joined-parts.d.ts +29 -0
  88. package/dist/facade/develop-joined-parts.js +33 -0
  89. package/dist/facade/develop-joined-parts.js.map +1 -0
  90. package/dist/facade/display-view-lens-signal.d.ts +32 -1
  91. package/dist/facade/display-view-lens-signal.js +85 -10
  92. package/dist/facade/display-view-lens-signal.js.map +1 -1
  93. package/dist/facade/expected-signal-setup.d.ts +8 -0
  94. package/dist/facade/expected-signal-setup.js +7 -0
  95. package/dist/facade/expected-signal-setup.js.map +1 -1
  96. package/dist/facade/expected-signal.d.ts +5 -0
  97. package/dist/facade/expected-signal.js +5 -1
  98. package/dist/facade/expected-signal.js.map +1 -1
  99. package/dist/facade/generic-lens-capture.d.ts +5 -2
  100. package/dist/facade/generic-lens-capture.js +5 -2
  101. package/dist/facade/generic-lens-capture.js.map +1 -1
  102. package/dist/facade/simulate-capture.d.ts +67 -8
  103. package/dist/facade/simulate-capture.js +262 -126
  104. package/dist/facade/simulate-capture.js.map +1 -1
  105. package/dist/facade/simulate-display-view.js +1 -1
  106. package/dist/facade/simulate-display-view.js.map +1 -1
  107. package/dist/gpu/chart-composite-gpu.js +1 -3
  108. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  109. package/dist/gpu/chart-radiance-gpu.js +1 -5
  110. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  111. package/dist/gpu/display-view-quality-gpu.d.ts +13 -1
  112. package/dist/gpu/display-view-quality-gpu.js +4 -8
  113. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  114. package/dist/gpu/display-view-speed-gpu.js +3 -25
  115. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  116. package/dist/gpu/sensor-stage-gpu.js +1 -5
  117. package/dist/gpu/sensor-stage-gpu.js.map +1 -1
  118. package/dist/gpu/webgpu-runtime.d.ts +2 -0
  119. package/dist/gpu/webgpu-runtime.js +3 -0
  120. package/dist/gpu/webgpu-runtime.js.map +1 -1
  121. package/dist/index.d.ts +6 -1
  122. package/dist/index.js +5 -0
  123. package/dist/index.js.map +1 -1
  124. package/dist/motion/camera-rotation.js +1 -6
  125. package/dist/motion/camera-rotation.js.map +1 -1
  126. package/dist/motion/capture-rotation-inverse-mapping.d.ts +12 -0
  127. package/dist/motion/capture-rotation-inverse-mapping.js +2 -2
  128. package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
  129. package/dist/motion/capture-rotation-temporal-quadrature.d.ts +1 -0
  130. package/dist/motion/capture-rotation-temporal-quadrature.js +1 -1
  131. package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
  132. package/dist/motion/capture-rotation-trajectory.js +2 -17
  133. package/dist/motion/capture-rotation-trajectory.js.map +1 -1
  134. package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +1 -0
  135. package/dist/motion/capture-translation-parallax-temporal-quadrature.js +3 -14
  136. package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
  137. package/dist/motion/extended-object-projection.js +5 -40
  138. package/dist/motion/extended-object-projection.js.map +1 -1
  139. package/dist/optics/atmospheric-haze.js +1 -7
  140. package/dist/optics/atmospheric-haze.js.map +1 -1
  141. package/dist/optics/brown-conrady-distortion.js +1 -7
  142. package/dist/optics/brown-conrady-distortion.js.map +1 -1
  143. package/dist/optics/complex-pupil-psf.d.ts +1 -0
  144. package/dist/optics/complex-pupil-psf.js +2 -84
  145. package/dist/optics/complex-pupil-psf.js.map +1 -1
  146. package/dist/optics/focus-state.js +1 -11
  147. package/dist/optics/focus-state.js.map +1 -1
  148. package/dist/optics/front-of-lens-filter.d.ts +5 -0
  149. package/dist/optics/front-of-lens-filter.js +3 -65
  150. package/dist/optics/front-of-lens-filter.js.map +1 -1
  151. package/dist/optics/generic-nd-filter-presets.d.ts +12 -0
  152. package/dist/optics/generic-nd-filter-presets.js +48 -0
  153. package/dist/optics/generic-nd-filter-presets.js.map +1 -0
  154. package/dist/optics/illumination-vignetting.js +1 -6
  155. package/dist/optics/illumination-vignetting.js.map +1 -1
  156. package/dist/optics/lens-psf-profile.d.ts +4 -1
  157. package/dist/optics/lens-psf-profile.js +12 -111
  158. package/dist/optics/lens-psf-profile.js.map +1 -1
  159. package/dist/optics/longitudinal-chromatic-aberration.js +1 -7
  160. package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -1
  161. package/dist/optics/pupil-vignetting.js +1 -7
  162. package/dist/optics/pupil-vignetting.js.map +1 -1
  163. package/dist/optics/radial-distortion.js +1 -6
  164. package/dist/optics/radial-distortion.js.map +1 -1
  165. package/dist/optics/scene-to-sensor-irradiance.js +4 -96
  166. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
  167. package/dist/optics/stray-light.d.ts +1 -0
  168. package/dist/optics/stray-light.js +1 -1
  169. package/dist/optics/stray-light.js.map +1 -1
  170. package/dist/optics/zernike-wavefront.js +1 -7
  171. package/dist/optics/zernike-wavefront.js.map +1 -1
  172. package/dist/output/capture-geometry.js +1 -8
  173. package/dist/output/capture-geometry.js.map +1 -1
  174. package/dist/output/developed-lens-corrections.d.ts +62 -0
  175. package/dist/output/developed-lens-corrections.js +135 -0
  176. package/dist/output/developed-lens-corrections.js.map +1 -0
  177. package/dist/output/generic-lens-corrections.d.ts +2 -6
  178. package/dist/output/generic-lens-corrections.js +3 -6
  179. package/dist/output/generic-lens-corrections.js.map +1 -1
  180. package/dist/output/geometric-transforms.js +1 -4
  181. package/dist/output/geometric-transforms.js.map +1 -1
  182. package/dist/output/native-capture-sdr.d.ts +2 -2
  183. package/dist/output/native-capture-sdr.js +3 -2
  184. package/dist/output/native-capture-sdr.js.map +1 -1
  185. package/dist/processing/development-detail.d.ts +29 -0
  186. package/dist/processing/development-detail.js +128 -107
  187. package/dist/processing/development-detail.js.map +1 -1
  188. package/dist/schema/illumination-temporal.js +3 -72
  189. package/dist/schema/illumination-temporal.js.map +1 -1
  190. package/dist/schema/illumination.d.ts +1 -0
  191. package/dist/schema/illumination.js +2 -65
  192. package/dist/schema/illumination.js.map +1 -1
  193. package/dist/schema/scene-radiance-temporal.js +2 -14
  194. package/dist/schema/scene-radiance-temporal.js.map +1 -1
  195. package/dist/schema/scene-radiance.js +2 -60
  196. package/dist/schema/scene-radiance.js.map +1 -1
  197. package/dist/schema/validation.d.ts +2 -0
  198. package/dist/schema/validation.js +2 -17
  199. package/dist/schema/validation.js.map +1 -1
  200. package/dist/sensor/accumulated-charge.js +2 -59
  201. package/dist/sensor/accumulated-charge.js.map +1 -1
  202. package/dist/sensor/architecture.js +1 -16
  203. package/dist/sensor/architecture.js.map +1 -1
  204. package/dist/sensor/camera-saturation-capacity.d.ts +1 -0
  205. package/dist/sensor/camera-saturation-capacity.js +3 -55
  206. package/dist/sensor/camera-saturation-capacity.js.map +1 -1
  207. package/dist/sensor/capture-color-sampling-binding.js +1 -26
  208. package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
  209. package/dist/sensor/capture-mode-timing.js +1 -39
  210. package/dist/sensor/capture-mode-timing.js.map +1 -1
  211. package/dist/sensor/capture-mode.js +1 -23
  212. package/dist/sensor/capture-mode.js.map +1 -1
  213. package/dist/sensor/color-sampling.js +1 -26
  214. package/dist/sensor/color-sampling.js.map +1 -1
  215. package/dist/sensor/constant-rate-temporal-integration.js +2 -46
  216. package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
  217. package/dist/sensor/dark-current.js +2 -45
  218. package/dist/sensor/dark-current.js.map +1 -1
  219. package/dist/sensor/eqe-electron-rate.js +2 -35
  220. package/dist/sensor/eqe-electron-rate.js.map +1 -1
  221. package/dist/sensor/exposure-window.d.ts +5 -0
  222. package/dist/sensor/exposure-window.js +7 -22
  223. package/dist/sensor/exposure-window.js.map +1 -1
  224. package/dist/sensor/iso-gain.js +1 -7
  225. package/dist/sensor/iso-gain.js.map +1 -1
  226. package/dist/sensor/iso-signal-chain.js +1 -43
  227. package/dist/sensor/iso-signal-chain.js.map +1 -1
  228. package/dist/sensor/optical-stack.js +1 -25
  229. package/dist/sensor/optical-stack.js.map +1 -1
  230. package/dist/sensor/photon-energy.js +1 -26
  231. package/dist/sensor/photon-energy.js.map +1 -1
  232. package/dist/sensor/physical-charge-capacity.js +3 -77
  233. package/dist/sensor/physical-charge-capacity.js.map +1 -1
  234. package/dist/sensor/radiometry-readiness.js +2 -23
  235. package/dist/sensor/radiometry-readiness.js.map +1 -1
  236. package/dist/sensor/raw-readout.d.ts +3 -0
  237. package/dist/sensor/raw-readout.js +4 -66
  238. package/dist/sensor/raw-readout.js.map +1 -1
  239. package/dist/sensor/raw-reconstruction.js +2 -64
  240. package/dist/sensor/raw-reconstruction.js.map +1 -1
  241. package/dist/sensor/readout-exposure-linkage.js +1 -9
  242. package/dist/sensor/readout-exposure-linkage.js.map +1 -1
  243. package/dist/sensor/readout-timing.js +3 -57
  244. package/dist/sensor/readout-timing.js.map +1 -1
  245. package/dist/sensor/response-application-compatibility.d.ts +2 -0
  246. package/dist/sensor/response-application-compatibility.js +3 -29
  247. package/dist/sensor/response-application-compatibility.js.map +1 -1
  248. package/dist/sensor/response-operating-range.d.ts +1 -0
  249. package/dist/sensor/response-operating-range.js +3 -79
  250. package/dist/sensor/response-operating-range.js.map +1 -1
  251. package/dist/sensor/responsivity-photocurrent.js +4 -108
  252. package/dist/sensor/responsivity-photocurrent.js.map +1 -1
  253. package/dist/sensor/sampling-aperture.js +1 -25
  254. package/dist/sensor/sampling-aperture.js.map +1 -1
  255. package/dist/sensor/spatial-sample-reduction.js +2 -19
  256. package/dist/sensor/spatial-sample-reduction.js.map +1 -1
  257. package/dist/sensor/spatial-sampling-quadrature.js +1 -3
  258. package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
  259. package/dist/sensor/spatio-spectral-reduction.js +1 -18
  260. package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
  261. package/dist/sensor/spectral-coverage.d.ts +10 -1
  262. package/dist/sensor/spectral-coverage.js +1 -1
  263. package/dist/sensor/spectral-coverage.js.map +1 -1
  264. package/dist/sensor/spectral-quadrature.js +2 -35
  265. package/dist/sensor/spectral-quadrature.js.map +1 -1
  266. package/dist/sensor/spectral-response.js +1 -47
  267. package/dist/sensor/spectral-response.js.map +1 -1
  268. package/dist/stabilization/camera-shake.js +1 -6
  269. package/dist/stabilization/camera-shake.js.map +1 -1
  270. package/dist/stabilization/system.js +2 -80
  271. package/dist/stabilization/system.js.map +1 -1
  272. package/docs/AGENT_GUIDE.md +4 -0
  273. package/docs/API_REFERENCE.md +69 -2
  274. package/docs/QUICK_START.md +136 -6
  275. package/docs/USAGE.md +89 -3
  276. package/docs/api/camera-sensor-equivalence.md +209 -0
  277. package/docs/api/core-version.md +1 -1
  278. package/docs/api/equipment-ideal-lens.md +26 -0
  279. package/docs/api/exports.json +118 -3
  280. package/docs/api/exposure-filtered-exposure-time.md +105 -0
  281. package/docs/api/facade-develop-joined-parts.md +32 -0
  282. package/docs/api/facade-simulate-capture.md +62 -8
  283. package/docs/api/optics-generic-nd-filter-presets.md +34 -0
  284. package/docs/api/optics-lens-psf-profile.md +3 -1
  285. package/docs/api/output-developed-lens-corrections.md +12 -0
  286. package/docs/api/output-generic-lens-corrections.md +0 -9
  287. package/llms.txt +3 -0
  288. package/package.json +1 -1
@@ -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 {