@photivra/engine 2.18.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.
- package/CHANGELOG.md +68 -1
- package/CITATION.cff +1 -1
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/dist/capture/focus-control.js +2 -75
- package/dist/capture/focus-control.js.map +1 -1
- package/dist/capture/native-environment-lean.d.ts +1 -0
- package/dist/capture/native-environment-lean.js +1 -1
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-optical-stage.d.ts +1 -0
- package/dist/capture/native-environment-optical-stage.js +2 -5
- package/dist/capture/native-environment-optical-stage.js.map +1 -1
- package/dist/capture/native-environment-raw.js +1 -5
- package/dist/capture/native-environment-raw.js.map +1 -1
- package/dist/capture/release-sequence.js +2 -47
- package/dist/capture/release-sequence.js.map +1 -1
- package/dist/color/white-balance.d.ts +2 -0
- package/dist/color/white-balance.js +3 -56
- package/dist/color/white-balance.js.map +1 -1
- package/dist/composition/image-formation-plan.d.ts +1 -0
- package/dist/composition/image-formation-plan.js +3 -49
- package/dist/composition/image-formation-plan.js.map +1 -1
- package/dist/core/evidence-provenance.js +1 -16
- package/dist/core/evidence-provenance.js.map +1 -1
- package/dist/core/record-validation.d.ts +54 -0
- package/dist/core/record-validation.js +176 -0
- package/dist/core/record-validation.js.map +1 -1
- package/dist/core/scientific-assurance.js +1 -18
- package/dist/core/scientific-assurance.js.map +1 -1
- package/dist/core/shared-helpers.d.ts +33 -0
- package/dist/core/shared-helpers.js +34 -0
- package/dist/core/shared-helpers.js.map +1 -0
- package/dist/core/spectral-composition.js +1 -36
- package/dist/core/spectral-composition.js.map +1 -1
- package/dist/core/spectral.js +1 -19
- package/dist/core/spectral.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/equipment/exposure-capabilities.d.ts +1 -0
- package/dist/equipment/exposure-capabilities.js +2 -36
- package/dist/equipment/exposure-capabilities.js.map +1 -1
- package/dist/equipment/iso-capabilities.js +2 -49
- package/dist/equipment/iso-capabilities.js.map +1 -1
- package/dist/equipment/metering-capabilities.js +1 -26
- package/dist/equipment/metering-capabilities.js.map +1 -1
- package/dist/equipment/release-capabilities.js +1 -53
- package/dist/equipment/release-capabilities.js.map +1 -1
- package/dist/exposure/auto-iso-slowest-shutter.js +1 -7
- package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
- package/dist/exposure/exposure-duration-control.js +1 -16
- package/dist/exposure/exposure-duration-control.js.map +1 -1
- package/dist/exposure/exposure-mode-resolver.js +1 -17
- package/dist/exposure/exposure-mode-resolver.js.map +1 -1
- package/dist/exposure/filtered-exposure-time.d.ts +93 -0
- package/dist/exposure/filtered-exposure-time.js +129 -0
- package/dist/exposure/filtered-exposure-time.js.map +1 -0
- package/dist/exposure/flash-ttl.d.ts +1 -0
- package/dist/exposure/flash-ttl.js +1 -1
- package/dist/exposure/flash-ttl.js.map +1 -1
- package/dist/exposure/flash.js +1 -49
- package/dist/exposure/flash.js.map +1 -1
- package/dist/exposure/metering-scene-radiance.js +1 -25
- package/dist/exposure/metering-scene-radiance.js.map +1 -1
- package/dist/exposure/metering-target.js +1 -30
- package/dist/exposure/metering-target.js.map +1 -1
- package/dist/exposure/metering-temporal.js +1 -8
- package/dist/exposure/metering-temporal.js.map +1 -1
- package/dist/exposure/metering.js +1 -72
- package/dist/exposure/metering.js.map +1 -1
- package/dist/exposure/program-line.js +1 -45
- package/dist/exposure/program-line.js.map +1 -1
- package/dist/facade/develop-joined-parts.d.ts +29 -0
- package/dist/facade/develop-joined-parts.js +33 -0
- package/dist/facade/develop-joined-parts.js.map +1 -0
- package/dist/facade/generic-lens-capture.d.ts +4 -2
- package/dist/facade/generic-lens-capture.js +4 -2
- package/dist/facade/generic-lens-capture.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +37 -5
- package/dist/facade/simulate-capture.js +153 -96
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/gpu/chart-composite-gpu.js +1 -3
- package/dist/gpu/chart-composite-gpu.js.map +1 -1
- package/dist/gpu/chart-radiance-gpu.js +1 -5
- package/dist/gpu/chart-radiance-gpu.js.map +1 -1
- package/dist/gpu/display-view-quality-gpu.d.ts +13 -1
- package/dist/gpu/display-view-quality-gpu.js +4 -8
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.js +3 -25
- package/dist/gpu/display-view-speed-gpu.js.map +1 -1
- package/dist/gpu/sensor-stage-gpu.js +1 -5
- package/dist/gpu/sensor-stage-gpu.js.map +1 -1
- package/dist/gpu/webgpu-runtime.d.ts +2 -0
- package/dist/gpu/webgpu-runtime.js +3 -0
- package/dist/gpu/webgpu-runtime.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/motion/camera-rotation.js +1 -6
- package/dist/motion/camera-rotation.js.map +1 -1
- package/dist/motion/capture-rotation-inverse-mapping.d.ts +12 -0
- package/dist/motion/capture-rotation-inverse-mapping.js +2 -2
- package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts +1 -0
- package/dist/motion/capture-rotation-temporal-quadrature.js +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
- package/dist/motion/capture-rotation-trajectory.js +2 -17
- package/dist/motion/capture-rotation-trajectory.js.map +1 -1
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +1 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js +3 -14
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
- package/dist/motion/extended-object-projection.js +5 -40
- package/dist/motion/extended-object-projection.js.map +1 -1
- package/dist/optics/atmospheric-haze.js +1 -7
- package/dist/optics/atmospheric-haze.js.map +1 -1
- package/dist/optics/brown-conrady-distortion.js +1 -7
- package/dist/optics/brown-conrady-distortion.js.map +1 -1
- package/dist/optics/complex-pupil-psf.d.ts +1 -0
- package/dist/optics/complex-pupil-psf.js +2 -84
- package/dist/optics/complex-pupil-psf.js.map +1 -1
- package/dist/optics/focus-state.js +1 -11
- package/dist/optics/focus-state.js.map +1 -1
- package/dist/optics/front-of-lens-filter.d.ts +5 -0
- package/dist/optics/front-of-lens-filter.js +3 -65
- package/dist/optics/front-of-lens-filter.js.map +1 -1
- package/dist/optics/generic-nd-filter-presets.d.ts +12 -0
- package/dist/optics/generic-nd-filter-presets.js +48 -0
- package/dist/optics/generic-nd-filter-presets.js.map +1 -0
- package/dist/optics/illumination-vignetting.js +1 -6
- package/dist/optics/illumination-vignetting.js.map +1 -1
- package/dist/optics/lens-psf-profile.d.ts +4 -1
- package/dist/optics/lens-psf-profile.js +12 -111
- package/dist/optics/lens-psf-profile.js.map +1 -1
- package/dist/optics/longitudinal-chromatic-aberration.js +1 -7
- package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -1
- package/dist/optics/pupil-vignetting.js +1 -7
- package/dist/optics/pupil-vignetting.js.map +1 -1
- package/dist/optics/radial-distortion.js +1 -6
- package/dist/optics/radial-distortion.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.js +4 -96
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/optics/stray-light.d.ts +1 -0
- package/dist/optics/stray-light.js +1 -1
- package/dist/optics/stray-light.js.map +1 -1
- package/dist/optics/zernike-wavefront.js +1 -7
- package/dist/optics/zernike-wavefront.js.map +1 -1
- package/dist/output/capture-geometry.js +1 -8
- package/dist/output/capture-geometry.js.map +1 -1
- package/dist/output/developed-lens-corrections.d.ts +62 -0
- package/dist/output/developed-lens-corrections.js +135 -0
- package/dist/output/developed-lens-corrections.js.map +1 -0
- package/dist/output/generic-lens-corrections.d.ts +2 -6
- package/dist/output/generic-lens-corrections.js +3 -6
- package/dist/output/generic-lens-corrections.js.map +1 -1
- package/dist/output/geometric-transforms.js +1 -4
- package/dist/output/geometric-transforms.js.map +1 -1
- package/dist/output/native-capture-sdr.d.ts +2 -2
- package/dist/output/native-capture-sdr.js +3 -2
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/processing/development-detail.d.ts +29 -0
- package/dist/processing/development-detail.js +128 -107
- package/dist/processing/development-detail.js.map +1 -1
- package/dist/schema/illumination-temporal.js +3 -72
- package/dist/schema/illumination-temporal.js.map +1 -1
- package/dist/schema/illumination.d.ts +1 -0
- package/dist/schema/illumination.js +2 -65
- package/dist/schema/illumination.js.map +1 -1
- package/dist/schema/scene-radiance-temporal.js +2 -14
- package/dist/schema/scene-radiance-temporal.js.map +1 -1
- package/dist/schema/scene-radiance.js +2 -60
- package/dist/schema/scene-radiance.js.map +1 -1
- package/dist/schema/validation.d.ts +2 -0
- package/dist/schema/validation.js +2 -17
- package/dist/schema/validation.js.map +1 -1
- package/dist/sensor/accumulated-charge.js +2 -59
- package/dist/sensor/accumulated-charge.js.map +1 -1
- package/dist/sensor/architecture.js +1 -16
- package/dist/sensor/architecture.js.map +1 -1
- package/dist/sensor/camera-saturation-capacity.d.ts +1 -0
- package/dist/sensor/camera-saturation-capacity.js +3 -55
- package/dist/sensor/camera-saturation-capacity.js.map +1 -1
- package/dist/sensor/capture-color-sampling-binding.js +1 -26
- package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
- package/dist/sensor/capture-mode-timing.js +1 -39
- package/dist/sensor/capture-mode-timing.js.map +1 -1
- package/dist/sensor/capture-mode.js +1 -23
- package/dist/sensor/capture-mode.js.map +1 -1
- package/dist/sensor/color-sampling.js +1 -26
- package/dist/sensor/color-sampling.js.map +1 -1
- package/dist/sensor/constant-rate-temporal-integration.js +2 -46
- package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
- package/dist/sensor/dark-current.js +2 -45
- package/dist/sensor/dark-current.js.map +1 -1
- package/dist/sensor/eqe-electron-rate.js +2 -35
- package/dist/sensor/eqe-electron-rate.js.map +1 -1
- package/dist/sensor/exposure-window.d.ts +5 -0
- package/dist/sensor/exposure-window.js +7 -22
- package/dist/sensor/exposure-window.js.map +1 -1
- package/dist/sensor/iso-gain.js +1 -7
- package/dist/sensor/iso-gain.js.map +1 -1
- package/dist/sensor/iso-signal-chain.js +1 -43
- package/dist/sensor/iso-signal-chain.js.map +1 -1
- package/dist/sensor/optical-stack.js +1 -25
- package/dist/sensor/optical-stack.js.map +1 -1
- package/dist/sensor/photon-energy.js +1 -26
- package/dist/sensor/photon-energy.js.map +1 -1
- package/dist/sensor/physical-charge-capacity.js +3 -77
- package/dist/sensor/physical-charge-capacity.js.map +1 -1
- package/dist/sensor/radiometry-readiness.js +2 -23
- package/dist/sensor/radiometry-readiness.js.map +1 -1
- package/dist/sensor/raw-readout.d.ts +3 -0
- package/dist/sensor/raw-readout.js +4 -66
- package/dist/sensor/raw-readout.js.map +1 -1
- package/dist/sensor/raw-reconstruction.js +2 -64
- package/dist/sensor/raw-reconstruction.js.map +1 -1
- package/dist/sensor/readout-exposure-linkage.js +1 -9
- package/dist/sensor/readout-exposure-linkage.js.map +1 -1
- package/dist/sensor/readout-timing.js +3 -57
- package/dist/sensor/readout-timing.js.map +1 -1
- package/dist/sensor/response-application-compatibility.d.ts +2 -0
- package/dist/sensor/response-application-compatibility.js +3 -29
- package/dist/sensor/response-application-compatibility.js.map +1 -1
- package/dist/sensor/response-operating-range.d.ts +1 -0
- package/dist/sensor/response-operating-range.js +3 -79
- package/dist/sensor/response-operating-range.js.map +1 -1
- package/dist/sensor/responsivity-photocurrent.js +4 -108
- package/dist/sensor/responsivity-photocurrent.js.map +1 -1
- package/dist/sensor/sampling-aperture.js +1 -25
- package/dist/sensor/sampling-aperture.js.map +1 -1
- package/dist/sensor/spatial-sample-reduction.js +2 -19
- package/dist/sensor/spatial-sample-reduction.js.map +1 -1
- package/dist/sensor/spatial-sampling-quadrature.js +1 -3
- package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
- package/dist/sensor/spatio-spectral-reduction.js +1 -18
- package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
- package/dist/sensor/spectral-coverage.d.ts +10 -1
- package/dist/sensor/spectral-coverage.js +1 -1
- package/dist/sensor/spectral-coverage.js.map +1 -1
- package/dist/sensor/spectral-quadrature.js +2 -35
- package/dist/sensor/spectral-quadrature.js.map +1 -1
- package/dist/sensor/spectral-response.js +1 -47
- package/dist/sensor/spectral-response.js.map +1 -1
- package/dist/stabilization/camera-shake.js +1 -6
- package/dist/stabilization/camera-shake.js.map +1 -1
- package/dist/stabilization/system.js +2 -80
- package/dist/stabilization/system.js.map +1 -1
- package/docs/AGENT_GUIDE.md +1 -0
- package/docs/API_REFERENCE.md +41 -2
- package/docs/QUICK_START.md +90 -8
- package/docs/USAGE.md +47 -2
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +53 -3
- package/docs/api/exposure-filtered-exposure-time.md +105 -0
- package/docs/api/facade-develop-joined-parts.md +32 -0
- package/docs/api/facade-simulate-capture.md +36 -5
- package/docs/api/optics-generic-nd-filter-presets.md +34 -0
- package/docs/api/optics-lens-psf-profile.md +3 -1
- package/docs/api/output-developed-lens-corrections.md +12 -0
- package/docs/api/output-generic-lens-corrections.md +0 -9
- package/llms.txt +1 -0
- package/package.json +1 -1
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* may reuse it. Parsers for one record and for a non-empty list of records.
|
|
5
5
|
* @see docs/API_STYLE.md for equations, coordinate/unit conventions, blockers and support limits.
|
|
6
6
|
*/
|
|
7
|
-
import { rejectUnknownFields } from "./record-validation.js";
|
|
8
7
|
import { InvalidConfigurationError } from "./configuration-error.js";
|
|
8
|
+
import { requireConfigRecord as requireRecord, requireConfigRecordString as requireNonEmptyString } from "./record-validation.js";
|
|
9
9
|
const SOURCE_ORIGINS = new Set([
|
|
10
10
|
"manufacturer",
|
|
11
11
|
"third-party",
|
|
@@ -16,21 +16,6 @@ const REUSE_STATUSES = new Set([
|
|
|
16
16
|
"reusable-data",
|
|
17
17
|
"photivra-owned"
|
|
18
18
|
]);
|
|
19
|
-
function requireRecord(value, path, allowedKeys) {
|
|
20
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
21
|
-
throw new InvalidConfigurationError(`${path} must be an object.`);
|
|
22
|
-
}
|
|
23
|
-
if (allowedKeys !== null)
|
|
24
|
-
rejectUnknownFields(value, allowedKeys, path);
|
|
25
|
-
return value;
|
|
26
|
-
}
|
|
27
|
-
function requireNonEmptyString(record, key, path) {
|
|
28
|
-
const value = record[key];
|
|
29
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
30
|
-
throw new InvalidConfigurationError(`${path}.${key} must be a non-empty string.`);
|
|
31
|
-
}
|
|
32
|
-
return value;
|
|
33
|
-
}
|
|
34
19
|
/**
|
|
35
20
|
* Parses one provenance (evidence) record.
|
|
36
21
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evidence-provenance.js","sourceRoot":"","sources":["../../src/core/evidence-provenance.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC;;;;GAIG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"evidence-provenance.js","sourceRoot":"","sources":["../../src/core/evidence-provenance.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Provenance records: where a scientific fact or data set came from, and whether Photivra\n * may reuse it. Parsers for one record and for a non-empty list of records.\n * @see docs/API_STYLE.md for equations, coordinate/unit conventions, blockers and support limits.\n */\n\nimport { InvalidConfigurationError } from \"./configuration-error.js\";\nimport { requireConfigRecord as requireRecord, requireConfigRecordString as requireNonEmptyString } from \"./record-validation.js\";\n\n\nexport type EvidenceSourceOrigin =\n | \"manufacturer\"\n | \"third-party\"\n | \"photivra\";\n\nexport type EvidenceReuseStatus =\n | \"factual-reference-only\"\n | \"reusable-data\"\n | \"photivra-owned\";\n\n/**\n * Where one scientific fact or numeric data set came from, and what reuse rights apply.\n *\n * Being publicly available does not grant permission to copy. The engine stores the\n * source reference as metadata and never fetches it. A record is a declaration for a\n * human to review. It does not verify a calibration or a licence.\n */\nexport interface EvidenceProvenance {\n /** Who originated the underlying fact/data. */\n sourceOrigin: EvidenceSourceOrigin;\n /**\n * Public/stable source reference or Photivra evidence identifier.\n *\n * The engine does not fetch this reference at runtime.\n */\n sourceReference: string;\n /**\n * How Photivra may use the referenced material.\n *\n * This is independent of who the source is. A manufacturer or third party can\n * publish material that is only a factual reference, or data explicitly licensed\n * for reuse.\n */\n reuseStatus: EvidenceReuseStatus;\n /** Required when reuseStatus is reusable-data. */\n license?: string;\n note?: string;\n}\n\nexport interface EvidenceBackedFact<T> {\n value: T;\n /** One or more independent evidence records supporting this fact. */\n evidence: readonly EvidenceProvenance[];\n}\n\nconst SOURCE_ORIGINS = new Set<EvidenceSourceOrigin>([\n \"manufacturer\",\n \"third-party\",\n \"photivra\"\n]);\n\nconst REUSE_STATUSES = new Set<EvidenceReuseStatus>([\n \"factual-reference-only\",\n \"reusable-data\",\n \"photivra-owned\"\n]);\n\n/**\n * Parses one provenance (evidence) record.\n *\n * Source origin and reuse status are independent of each other. The parser rejects\n * only combinations that contradict themselves.\n */\nexport function parseEvidenceProvenance(\n value: unknown,\n path: string\n): EvidenceProvenance {\n const record = requireRecord(value, path, [\"sourceOrigin\", \"sourceReference\", \"reuseStatus\", \"license\", \"note\"]);\n const sourceOrigin = requireNonEmptyString(record, \"sourceOrigin\", path);\n const sourceReference = requireNonEmptyString(\n record,\n \"sourceReference\",\n path\n );\n const reuseStatus = requireNonEmptyString(record, \"reuseStatus\", path);\n\n if (!SOURCE_ORIGINS.has(sourceOrigin as EvidenceSourceOrigin)) {\n throw new InvalidConfigurationError(`${path}.sourceOrigin is invalid.`);\n }\n if (!REUSE_STATUSES.has(reuseStatus as EvidenceReuseStatus)) {\n throw new InvalidConfigurationError(`${path}.reuseStatus is invalid.`);\n }\n\n const typedOrigin = sourceOrigin as EvidenceSourceOrigin;\n const typedReuseStatus = reuseStatus as EvidenceReuseStatus;\n\n if (\n typedReuseStatus === \"photivra-owned\" &&\n typedOrigin !== \"photivra\"\n ) {\n throw new InvalidConfigurationError(\n `${path}.photivra-owned evidence must have sourceOrigin \"photivra\".`\n );\n }\n\n const license = record.license;\n if (\n license !== undefined &&\n (typeof license !== \"string\" || license.trim().length === 0)\n ) {\n throw new InvalidConfigurationError(\n `${path}.license must be a non-empty string when supplied.`\n );\n }\n if (typedReuseStatus === \"reusable-data\" && license === undefined) {\n throw new InvalidConfigurationError(\n `${path}.license is required for reusable-data provenance.`\n );\n }\n\n const note = record.note;\n if (\n note !== undefined &&\n (typeof note !== \"string\" || note.trim().length === 0)\n ) {\n throw new InvalidConfigurationError(\n `${path}.note must be a non-empty string when supplied.`\n );\n }\n\n return {\n sourceOrigin: typedOrigin,\n sourceReference,\n reuseStatus: typedReuseStatus,\n ...(license === undefined ? {} : { license }),\n ...(note === undefined ? {} : { note })\n };\n}\n\n/**\n * Parses a non-empty evidence array.\n */\nexport function parseEvidenceList(\n value: unknown,\n path: string\n): readonly EvidenceProvenance[] {\n if (!Array.isArray(value) || value.length === 0) {\n throw new InvalidConfigurationError(\n `${path} must be a non-empty array.`\n );\n }\n\n return value.map((entry, index) =>\n parseEvidenceProvenance(entry, `${path}[${index}]`)\n );\n}\n"]}
|
|
@@ -54,3 +54,57 @@ export declare const UNCERTAINTY_VARIANT_FIELDS: Readonly<Record<string, readonl
|
|
|
54
54
|
* discriminator is left to the caller, which reports it with its own message.
|
|
55
55
|
*/
|
|
56
56
|
export declare function rejectUnknownVariantFields(record: Readonly<Record<string, unknown>>, discriminator: string, allowedByVariant: Readonly<Record<string, readonly string[]>>, path: string): void;
|
|
57
|
+
/** A plain object (not null, not an array) whose keys are on `allowedKeys` (null: any keys): `<path> must be an object.` */
|
|
58
|
+
export declare function requireConfigRecord(value: unknown, path: string, allowedKeys: readonly string[] | null): Record<string, unknown>;
|
|
59
|
+
/** `record[key]`, a string that is not blank: `<path>.<key> must be a non-empty string.` */
|
|
60
|
+
export declare function requireConfigRecordString(record: Readonly<Record<string, unknown>>, key: string, path: string): string;
|
|
61
|
+
/** A string that is not blank, returned as given: `<path> must be a non-empty string.` */
|
|
62
|
+
export declare function requireConfigString(value: unknown, path: string): string;
|
|
63
|
+
/** A string that is not blank, returned trimmed: `<path> must be a non-empty string.` */
|
|
64
|
+
export declare function requireTrimmedConfigString(value: unknown, path: string): string;
|
|
65
|
+
/** A finite number: `<path> must be finite.` */
|
|
66
|
+
export declare function requireConfigFinite(value: unknown, path: string): number;
|
|
67
|
+
/** A finite number: `<path> must be a finite number.` */
|
|
68
|
+
export declare function requireConfigFiniteNumber(value: unknown, path: string): number;
|
|
69
|
+
/** A finite number above zero: `<path> must be finite and greater than zero.` */
|
|
70
|
+
export declare function requireConfigPositiveFinite(value: unknown, path: string): number;
|
|
71
|
+
/** A finite number at least zero: `<path> must be finite and greater than or equal to zero.` */
|
|
72
|
+
export declare function requireConfigNonNegativeFinite(value: unknown, path: string): number;
|
|
73
|
+
/** A safe integer above zero: `<path> must be a positive safe integer.` */
|
|
74
|
+
export declare function requireConfigPositiveSafeInteger(value: unknown, path: string): number;
|
|
75
|
+
/** A safe integer at least zero: `<path> must be a non-negative safe integer.` */
|
|
76
|
+
export declare function requireConfigNonNegativeSafeInteger(value: unknown, path: string): number;
|
|
77
|
+
/** `"calibrated"` or `"approximation"`: `<path> is invalid.` */
|
|
78
|
+
export declare function parseConfigScientificStatus(value: unknown, path: string): "calibrated" | "approximation";
|
|
79
|
+
/** `"supported"`, `"unsupported"` or `"unknown"`: `<path> is invalid.` */
|
|
80
|
+
export declare function parseConfigAvailability(value: unknown, path: string): "supported" | "unsupported" | "unknown";
|
|
81
|
+
/** A finite number (scientific input): `<path> must be finite.` */
|
|
82
|
+
export declare function requireInputFinite(value: unknown, path: string): number;
|
|
83
|
+
/** A finite number above zero (scientific input): `<path> must be finite and greater than zero.` */
|
|
84
|
+
export declare function requireInputPositiveFinite(value: unknown, path: string): number;
|
|
85
|
+
/** A finite number at least zero (scientific input): `<path> must be finite and greater than or equal to zero.` */
|
|
86
|
+
export declare function requireInputNonNegativeFinite(value: unknown, path: string): number;
|
|
87
|
+
/** A safe integer at least zero (scientific input): `<path> must be a non-negative safe integer.` */
|
|
88
|
+
export declare function requireInputNonNegativeSafeInteger(value: unknown, path: string): number;
|
|
89
|
+
/** A finite number, name first (scientific input): `<name> must be finite.` */
|
|
90
|
+
export declare function requireNamedFinite(name: string, value: unknown): number;
|
|
91
|
+
/** Throws unless `value` is finite (scientific input): `<name> must be finite.` */
|
|
92
|
+
export declare function assertNamedFinite(name: string, value: number): void;
|
|
93
|
+
/** An array of distinct non-blank strings, each trimmed: `<path> must be an array.`, `<path> must not contain duplicates.` */
|
|
94
|
+
export declare function parseConfigLimitations(value: unknown, path: string): readonly string[];
|
|
95
|
+
/** A finite number above zero: `<path> must be finite.`, then `<path> must be greater than zero.` */
|
|
96
|
+
export declare function requireConfigFiniteAboveZero(value: unknown, path: string): number;
|
|
97
|
+
/** A finite number at least zero: `<path> must be finite.`, then `<path> must be greater than or equal to zero.` */
|
|
98
|
+
export declare function requireConfigFiniteAtLeastZero(value: unknown, path: string): number;
|
|
99
|
+
/** A finite number above zero: `<path> must be a finite number.`, then `<path> must be greater than zero.` */
|
|
100
|
+
export declare function requireConfigNumberAboveZero(value: unknown, path: string): number;
|
|
101
|
+
/** A finite number at least zero: `<path> must be a finite number.`, then `<path> must be greater than or equal to zero.` */
|
|
102
|
+
export declare function requireConfigNumberAtLeastZero(value: unknown, path: string): number;
|
|
103
|
+
/** A number from 0 through 1: `<path> must be a finite number.`, then `<path> must be a finite fraction from 0 through 1.` */
|
|
104
|
+
export declare function requireConfigFraction(value: unknown, path: string): number;
|
|
105
|
+
/** A number from 0 through 1: `<path> must be finite.`, then `<path> must lie from zero through one.` */
|
|
106
|
+
export declare function requireConfigUnitInterval(value: unknown, path: string): number;
|
|
107
|
+
/** A finite number above zero (scientific input): `<path> must be finite.`, then `<path> must be greater than zero.` */
|
|
108
|
+
export declare function requireInputFiniteAboveZero(value: unknown, path: string): number;
|
|
109
|
+
/** A finite number at least zero (scientific input): `<path> must be finite.`, then `<path> must be greater than or equal to zero.` */
|
|
110
|
+
export declare function requireInputFiniteAtLeastZero(value: unknown, path: string): number;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* @see docs/API_STYLE.md for equations, coordinate/unit conventions, blockers and support limits.
|
|
7
7
|
*/
|
|
8
8
|
import { InvalidConfigurationError } from "./configuration-error.js";
|
|
9
|
+
import { InvalidScientificInputError } from "./validation.js";
|
|
9
10
|
/**
|
|
10
11
|
* Checks that a value is a plain record whose keys are all on an allowlist. The caller
|
|
11
12
|
* supplies the domain's schema and error messages.
|
|
@@ -115,4 +116,179 @@ export function rejectUnknownVariantFields(record, discriminator, allowedByVaria
|
|
|
115
116
|
rejectUnknownFields(record, allowedByVariant[variant], path);
|
|
116
117
|
}
|
|
117
118
|
}
|
|
119
|
+
// Field checks shared by the domain parsers, each with the one message every parser used for it (2.19.0: these were private
|
|
120
|
+
// copies in up to 44 modules; one shared copy keeps the bundles smaller and the messages unchanged).
|
|
121
|
+
/** A plain object (not null, not an array) whose keys are on `allowedKeys` (null: any keys): `<path> must be an object.` */
|
|
122
|
+
export function requireConfigRecord(value, path, allowedKeys) {
|
|
123
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
124
|
+
throw new InvalidConfigurationError(path + " must be an object.");
|
|
125
|
+
if (allowedKeys !== null)
|
|
126
|
+
rejectUnknownFields(value, allowedKeys, path);
|
|
127
|
+
return value;
|
|
128
|
+
}
|
|
129
|
+
/** `record[key]`, a string that is not blank: `<path>.<key> must be a non-empty string.` */
|
|
130
|
+
export function requireConfigRecordString(record, key, path) {
|
|
131
|
+
const value = record[key];
|
|
132
|
+
if (typeof value !== "string" || value.trim().length === 0)
|
|
133
|
+
throw new InvalidConfigurationError(path + "." + key + " must be a non-empty string.");
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
/** A string that is not blank, returned as given: `<path> must be a non-empty string.` */
|
|
137
|
+
export function requireConfigString(value, path) {
|
|
138
|
+
if (typeof value !== "string" || value.trim().length === 0)
|
|
139
|
+
throw new InvalidConfigurationError(path + " must be a non-empty string.");
|
|
140
|
+
return value;
|
|
141
|
+
}
|
|
142
|
+
/** A string that is not blank, returned trimmed: `<path> must be a non-empty string.` */
|
|
143
|
+
export function requireTrimmedConfigString(value, path) {
|
|
144
|
+
return requireConfigString(value, path).trim();
|
|
145
|
+
}
|
|
146
|
+
/** A finite number: `<path> must be finite.` */
|
|
147
|
+
export function requireConfigFinite(value, path) {
|
|
148
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
149
|
+
throw new InvalidConfigurationError(path + " must be finite.");
|
|
150
|
+
return value;
|
|
151
|
+
}
|
|
152
|
+
/** A finite number: `<path> must be a finite number.` */
|
|
153
|
+
export function requireConfigFiniteNumber(value, path) {
|
|
154
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
155
|
+
throw new InvalidConfigurationError(path + " must be a finite number.");
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
/** A finite number above zero: `<path> must be finite and greater than zero.` */
|
|
159
|
+
export function requireConfigPositiveFinite(value, path) {
|
|
160
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0)
|
|
161
|
+
throw new InvalidConfigurationError(path + " must be finite and greater than zero.");
|
|
162
|
+
return value;
|
|
163
|
+
}
|
|
164
|
+
/** A finite number at least zero: `<path> must be finite and greater than or equal to zero.` */
|
|
165
|
+
export function requireConfigNonNegativeFinite(value, path) {
|
|
166
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0)
|
|
167
|
+
throw new InvalidConfigurationError(path + " must be finite and greater than or equal to zero.");
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
170
|
+
/** A safe integer above zero: `<path> must be a positive safe integer.` */
|
|
171
|
+
export function requireConfigPositiveSafeInteger(value, path) {
|
|
172
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0)
|
|
173
|
+
throw new InvalidConfigurationError(path + " must be a positive safe integer.");
|
|
174
|
+
return value;
|
|
175
|
+
}
|
|
176
|
+
/** A safe integer at least zero: `<path> must be a non-negative safe integer.` */
|
|
177
|
+
export function requireConfigNonNegativeSafeInteger(value, path) {
|
|
178
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
|
|
179
|
+
throw new InvalidConfigurationError(path + " must be a non-negative safe integer.");
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
182
|
+
/** `"calibrated"` or `"approximation"`: `<path> is invalid.` */
|
|
183
|
+
export function parseConfigScientificStatus(value, path) {
|
|
184
|
+
if (value !== "calibrated" && value !== "approximation")
|
|
185
|
+
throw new InvalidConfigurationError(path + " is invalid.");
|
|
186
|
+
return value;
|
|
187
|
+
}
|
|
188
|
+
/** `"supported"`, `"unsupported"` or `"unknown"`: `<path> is invalid.` */
|
|
189
|
+
export function parseConfigAvailability(value, path) {
|
|
190
|
+
if (value !== "supported" && value !== "unsupported" && value !== "unknown")
|
|
191
|
+
throw new InvalidConfigurationError(path + " is invalid.");
|
|
192
|
+
return value;
|
|
193
|
+
}
|
|
194
|
+
/** A finite number (scientific input): `<path> must be finite.` */
|
|
195
|
+
export function requireInputFinite(value, path) {
|
|
196
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
197
|
+
throw new InvalidScientificInputError(path + " must be finite.");
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
/** A finite number above zero (scientific input): `<path> must be finite and greater than zero.` */
|
|
201
|
+
export function requireInputPositiveFinite(value, path) {
|
|
202
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0)
|
|
203
|
+
throw new InvalidScientificInputError(path + " must be finite and greater than zero.");
|
|
204
|
+
return value;
|
|
205
|
+
}
|
|
206
|
+
/** A finite number at least zero (scientific input): `<path> must be finite and greater than or equal to zero.` */
|
|
207
|
+
export function requireInputNonNegativeFinite(value, path) {
|
|
208
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0)
|
|
209
|
+
throw new InvalidScientificInputError(path + " must be finite and greater than or equal to zero.");
|
|
210
|
+
return value;
|
|
211
|
+
}
|
|
212
|
+
/** A safe integer at least zero (scientific input): `<path> must be a non-negative safe integer.` */
|
|
213
|
+
export function requireInputNonNegativeSafeInteger(value, path) {
|
|
214
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
|
|
215
|
+
throw new InvalidScientificInputError(path + " must be a non-negative safe integer.");
|
|
216
|
+
return value;
|
|
217
|
+
}
|
|
218
|
+
/** A finite number, name first (scientific input): `<name> must be finite.` */
|
|
219
|
+
export function requireNamedFinite(name, value) {
|
|
220
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
221
|
+
throw new InvalidScientificInputError(name + " must be finite.");
|
|
222
|
+
return value;
|
|
223
|
+
}
|
|
224
|
+
/** Throws unless `value` is finite (scientific input): `<name> must be finite.` */
|
|
225
|
+
export function assertNamedFinite(name, value) {
|
|
226
|
+
if (!Number.isFinite(value))
|
|
227
|
+
throw new InvalidScientificInputError(name + " must be finite.");
|
|
228
|
+
}
|
|
229
|
+
/** An array of distinct non-blank strings, each trimmed: `<path> must be an array.`, `<path> must not contain duplicates.` */
|
|
230
|
+
export function parseConfigLimitations(value, path) {
|
|
231
|
+
if (!Array.isArray(value))
|
|
232
|
+
throw new InvalidConfigurationError(path + " must be an array.");
|
|
233
|
+
const parsed = value.map((entry, index) => requireTrimmedConfigString(entry, path + "[" + index + "]"));
|
|
234
|
+
if (new Set(parsed).size !== parsed.length)
|
|
235
|
+
throw new InvalidConfigurationError(path + " must not contain duplicates.");
|
|
236
|
+
return parsed;
|
|
237
|
+
}
|
|
238
|
+
/** A finite number above zero: `<path> must be finite.`, then `<path> must be greater than zero.` */
|
|
239
|
+
export function requireConfigFiniteAboveZero(value, path) {
|
|
240
|
+
const parsed = requireConfigFinite(value, path);
|
|
241
|
+
if (parsed <= 0)
|
|
242
|
+
throw new InvalidConfigurationError(path + " must be greater than zero.");
|
|
243
|
+
return parsed;
|
|
244
|
+
}
|
|
245
|
+
/** A finite number at least zero: `<path> must be finite.`, then `<path> must be greater than or equal to zero.` */
|
|
246
|
+
export function requireConfigFiniteAtLeastZero(value, path) {
|
|
247
|
+
const parsed = requireConfigFinite(value, path);
|
|
248
|
+
if (parsed < 0)
|
|
249
|
+
throw new InvalidConfigurationError(path + " must be greater than or equal to zero.");
|
|
250
|
+
return parsed;
|
|
251
|
+
}
|
|
252
|
+
/** A finite number above zero: `<path> must be a finite number.`, then `<path> must be greater than zero.` */
|
|
253
|
+
export function requireConfigNumberAboveZero(value, path) {
|
|
254
|
+
const parsed = requireConfigFiniteNumber(value, path);
|
|
255
|
+
if (parsed <= 0)
|
|
256
|
+
throw new InvalidConfigurationError(path + " must be greater than zero.");
|
|
257
|
+
return parsed;
|
|
258
|
+
}
|
|
259
|
+
/** A finite number at least zero: `<path> must be a finite number.`, then `<path> must be greater than or equal to zero.` */
|
|
260
|
+
export function requireConfigNumberAtLeastZero(value, path) {
|
|
261
|
+
const parsed = requireConfigFiniteNumber(value, path);
|
|
262
|
+
if (parsed < 0)
|
|
263
|
+
throw new InvalidConfigurationError(path + " must be greater than or equal to zero.");
|
|
264
|
+
return parsed;
|
|
265
|
+
}
|
|
266
|
+
/** A number from 0 through 1: `<path> must be a finite number.`, then `<path> must be a finite fraction from 0 through 1.` */
|
|
267
|
+
export function requireConfigFraction(value, path) {
|
|
268
|
+
const parsed = requireConfigFiniteNumber(value, path);
|
|
269
|
+
if (parsed < 0 || parsed > 1)
|
|
270
|
+
throw new InvalidConfigurationError(path + " must be a finite fraction from 0 through 1.");
|
|
271
|
+
return parsed;
|
|
272
|
+
}
|
|
273
|
+
/** A number from 0 through 1: `<path> must be finite.`, then `<path> must lie from zero through one.` */
|
|
274
|
+
export function requireConfigUnitInterval(value, path) {
|
|
275
|
+
const parsed = requireConfigFinite(value, path);
|
|
276
|
+
if (parsed < 0 || parsed > 1)
|
|
277
|
+
throw new InvalidConfigurationError(path + " must lie from zero through one.");
|
|
278
|
+
return parsed;
|
|
279
|
+
}
|
|
280
|
+
/** A finite number above zero (scientific input): `<path> must be finite.`, then `<path> must be greater than zero.` */
|
|
281
|
+
export function requireInputFiniteAboveZero(value, path) {
|
|
282
|
+
const parsed = requireInputFinite(value, path);
|
|
283
|
+
if (parsed <= 0)
|
|
284
|
+
throw new InvalidScientificInputError(path + " must be greater than zero.");
|
|
285
|
+
return parsed;
|
|
286
|
+
}
|
|
287
|
+
/** A finite number at least zero (scientific input): `<path> must be finite.`, then `<path> must be greater than or equal to zero.` */
|
|
288
|
+
export function requireInputFiniteAtLeastZero(value, path) {
|
|
289
|
+
const parsed = requireInputFinite(value, path);
|
|
290
|
+
if (parsed < 0)
|
|
291
|
+
throw new InvalidScientificInputError(path + " must be greater than or equal to zero.");
|
|
292
|
+
return parsed;
|
|
293
|
+
}
|
|
118
294
|
//# sourceMappingURL=record-validation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record-validation.js","sourceRoot":"","sources":["../../src/core/record-validation.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Shared input checks used by the domain parsers: plain-record and allowed-key checks, the\n * public identifier grammar, and guards for the top-level argument of a public function.\n * Each domain keeps its own schema and error messages.\n * @see docs/API_STYLE.md for equations, coordinate/unit conventions, blockers and support limits.\n */\n\nimport { InvalidConfigurationError } from \"./configuration-error.js\";\n\n/**\n * Checks that a value is a plain record whose keys are all on an allowlist. The caller\n * supplies the domain's schema and error messages.\n *\n * Returns the original record. It does not copy, freeze or strip fields, require missing\n * fields, or check child values. Like the domain parsers, it checks own enumerable string keys.\n * From 2.0.0 an unknown key also names the field: `<message> Unknown field \"<field>\".`\n */\nexport function requireAllowlistedRecord(\n value: unknown, allowedKeys: readonly string[], message: string\n): Record<string, unknown> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new InvalidConfigurationError(message);\n }\n for (const key in value) {\n if (Object.hasOwn(value, key) && !allowedKeys.includes(key)) {\n throw new InvalidConfigurationError(`${message} Unknown field ${JSON.stringify(key)}.`);\n }\n }\n return value as Record<string, unknown>;\n}\n\n/**\n * Shared grammar for public identifiers: 1–128 ASCII characters. The first is a letter or\n * digit. The rest are letters, digits, dot, underscore, colon or hyphen.\n *\n * The identifier is opaque: no trimming, case conversion or path/URL interpretation. Each\n * domain decides what the identifier means and keeps its exact error message.\n */\nexport function requirePublicOpaqueId(value: unknown, message: string): string {\n if (!isPublicOpaqueId(value)) {\n throw new InvalidConfigurationError(message);\n }\n return value;\n}\n\n/** Same grammar for domains that combine ID rejection with other field checks. */\nexport function isPublicOpaqueId(value: unknown): value is string {\n return typeof value === \"string\" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value);\n}\n\n/**\n * Guard for a public function's input object. If it receives null, a primitive or an array,\n * it throws the domain's InvalidConfigurationError, never a raw TypeError from reading a\n * property. It does not check fields.\n */\nexport function requireInputObject(value: unknown, label: string): void {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new InvalidConfigurationError(`${label} must be an object.`);\n }\n}\n\n/** Root-function input guard for a required array argument; see requireInputObject. */\nexport function requireInputArray(value: unknown, label: string): void {\n if (!Array.isArray(value)) {\n throw new InvalidConfigurationError(`${label} must be an array.`);\n }\n}\n\n/**\n * Input object guard for simple scalar calculators that also rejects unknown keys. A misspelled\n * or wrong-unit field (for example focusDistanceMm instead of focusDistanceM) is never silently ignored.\n */\nexport function requireInputKeys(value: unknown, functionName: string, allowedKeys: readonly string[]): void {\n requireInputObject(value, `${functionName} input`);\n // for-in over own keys avoids allocating a key array on hot scalar paths.\n for (const key in value as object) {\n if (Object.hasOwn(value as object, key) && !allowedKeys.includes(key)) {\n throw new InvalidConfigurationError(`${functionName} input has unknown field ${JSON.stringify(key)}.`);\n }\n }\n}\n\n/**\n * Rejects any own enumerable key of a versioned or engine record that is not on its allowlist, with\n * the message `<path> has unknown field \"<field>\".` The caller has already checked that `record` is\n * a plain object. Used at every object level of the `parse*()` record parsers, so a misspelled or\n * stale field in a stored profile fails instead of being silently dropped.\n */\nexport function rejectUnknownFields(record: object, allowedKeys: readonly string[], path: string): void {\n for (const key in record) {\n if (Object.hasOwn(record, key) && !allowedKeys.includes(key)) {\n throw new InvalidConfigurationError(`${path} has unknown field ${JSON.stringify(key)}.`);\n }\n }\n}\n\n/**\n * Checks the fixed-value flags that a parser writes into its own output (for example\n * `sceneRadianceCalculated: false`). They may be passed back in, so a parsed record parses again,\n * but only with exactly the fixed value; any other value is rejected rather than ignored.\n */\nexport function requireFixedFieldsWhenPresent(\n record: Readonly<Record<string, unknown>>, fixed: Readonly<Record<string, boolean | string>>, path: string\n): void {\n for (const key of Object.keys(fixed)) {\n if (record[key] !== undefined && record[key] !== fixed[key]) {\n throw new InvalidConfigurationError(`${path}.${key} must be ${JSON.stringify(fixed[key])} when supplied.`);\n }\n }\n}\n\n/**\n * Fields of the shared relative / not-quantified uncertainty union used by many evidence-backed\n * profiles: `{ kind: \"relative\", fraction, basis }` or `{ kind: \"not-quantified\", limitation }`.\n */\nexport const UNCERTAINTY_VARIANT_FIELDS: Readonly<Record<string, readonly string[]>> = /* @__PURE__ */ Object.freeze({\n relative: /* @__PURE__ */ Object.freeze([\"kind\", \"fraction\", \"basis\"]),\n \"not-quantified\": /* @__PURE__ */ Object.freeze([\"kind\", \"limitation\"])\n});\n\n/**\n * For a record whose allowed fields depend on a discriminator (for example `kind` or\n * `schemaVersion`), rejects fields that the selected variant does not define. An unrecognized\n * discriminator is left to the caller, which reports it with its own message.\n */\nexport function rejectUnknownVariantFields(\n record: Readonly<Record<string, unknown>>, discriminator: string,\n allowedByVariant: Readonly<Record<string, readonly string[]>>, path: string\n): void {\n const variant = record[discriminator];\n if (typeof variant === \"string\" && Object.hasOwn(allowedByVariant, variant)) {\n rejectUnknownFields(record, allowedByVariant[variant]!, path);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"record-validation.js","sourceRoot":"","sources":["../../src/core/record-validation.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Shared input checks used by the domain parsers: plain-record and allowed-key checks, the\n * public identifier grammar, and guards for the top-level argument of a public function.\n * Each domain keeps its own schema and error messages.\n * @see docs/API_STYLE.md for equations, coordinate/unit conventions, blockers and support limits.\n */\n\nimport { InvalidConfigurationError } from \"./configuration-error.js\";\nimport { InvalidScientificInputError } from \"./validation.js\";\n\n/**\n * Checks that a value is a plain record whose keys are all on an allowlist. The caller\n * supplies the domain's schema and error messages.\n *\n * Returns the original record. It does not copy, freeze or strip fields, require missing\n * fields, or check child values. Like the domain parsers, it checks own enumerable string keys.\n * From 2.0.0 an unknown key also names the field: `<message> Unknown field \"<field>\".`\n */\nexport function requireAllowlistedRecord(\n value: unknown, allowedKeys: readonly string[], message: string\n): Record<string, unknown> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new InvalidConfigurationError(message);\n }\n for (const key in value) {\n if (Object.hasOwn(value, key) && !allowedKeys.includes(key)) {\n throw new InvalidConfigurationError(`${message} Unknown field ${JSON.stringify(key)}.`);\n }\n }\n return value as Record<string, unknown>;\n}\n\n/**\n * Shared grammar for public identifiers: 1–128 ASCII characters. The first is a letter or\n * digit. The rest are letters, digits, dot, underscore, colon or hyphen.\n *\n * The identifier is opaque: no trimming, case conversion or path/URL interpretation. Each\n * domain decides what the identifier means and keeps its exact error message.\n */\nexport function requirePublicOpaqueId(value: unknown, message: string): string {\n if (!isPublicOpaqueId(value)) {\n throw new InvalidConfigurationError(message);\n }\n return value;\n}\n\n/** Same grammar for domains that combine ID rejection with other field checks. */\nexport function isPublicOpaqueId(value: unknown): value is string {\n return typeof value === \"string\" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value);\n}\n\n/**\n * Guard for a public function's input object. If it receives null, a primitive or an array,\n * it throws the domain's InvalidConfigurationError, never a raw TypeError from reading a\n * property. It does not check fields.\n */\nexport function requireInputObject(value: unknown, label: string): void {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new InvalidConfigurationError(`${label} must be an object.`);\n }\n}\n\n/** Root-function input guard for a required array argument; see requireInputObject. */\nexport function requireInputArray(value: unknown, label: string): void {\n if (!Array.isArray(value)) {\n throw new InvalidConfigurationError(`${label} must be an array.`);\n }\n}\n\n/**\n * Input object guard for simple scalar calculators that also rejects unknown keys. A misspelled\n * or wrong-unit field (for example focusDistanceMm instead of focusDistanceM) is never silently ignored.\n */\nexport function requireInputKeys(value: unknown, functionName: string, allowedKeys: readonly string[]): void {\n requireInputObject(value, `${functionName} input`);\n // for-in over own keys avoids allocating a key array on hot scalar paths.\n for (const key in value as object) {\n if (Object.hasOwn(value as object, key) && !allowedKeys.includes(key)) {\n throw new InvalidConfigurationError(`${functionName} input has unknown field ${JSON.stringify(key)}.`);\n }\n }\n}\n\n/**\n * Rejects any own enumerable key of a versioned or engine record that is not on its allowlist, with\n * the message `<path> has unknown field \"<field>\".` The caller has already checked that `record` is\n * a plain object. Used at every object level of the `parse*()` record parsers, so a misspelled or\n * stale field in a stored profile fails instead of being silently dropped.\n */\nexport function rejectUnknownFields(record: object, allowedKeys: readonly string[], path: string): void {\n for (const key in record) {\n if (Object.hasOwn(record, key) && !allowedKeys.includes(key)) {\n throw new InvalidConfigurationError(`${path} has unknown field ${JSON.stringify(key)}.`);\n }\n }\n}\n\n/**\n * Checks the fixed-value flags that a parser writes into its own output (for example\n * `sceneRadianceCalculated: false`). They may be passed back in, so a parsed record parses again,\n * but only with exactly the fixed value; any other value is rejected rather than ignored.\n */\nexport function requireFixedFieldsWhenPresent(\n record: Readonly<Record<string, unknown>>, fixed: Readonly<Record<string, boolean | string>>, path: string\n): void {\n for (const key of Object.keys(fixed)) {\n if (record[key] !== undefined && record[key] !== fixed[key]) {\n throw new InvalidConfigurationError(`${path}.${key} must be ${JSON.stringify(fixed[key])} when supplied.`);\n }\n }\n}\n\n/**\n * Fields of the shared relative / not-quantified uncertainty union used by many evidence-backed\n * profiles: `{ kind: \"relative\", fraction, basis }` or `{ kind: \"not-quantified\", limitation }`.\n */\nexport const UNCERTAINTY_VARIANT_FIELDS: Readonly<Record<string, readonly string[]>> = /* @__PURE__ */ Object.freeze({\n relative: /* @__PURE__ */ Object.freeze([\"kind\", \"fraction\", \"basis\"]),\n \"not-quantified\": /* @__PURE__ */ Object.freeze([\"kind\", \"limitation\"])\n});\n\n/**\n * For a record whose allowed fields depend on a discriminator (for example `kind` or\n * `schemaVersion`), rejects fields that the selected variant does not define. An unrecognized\n * discriminator is left to the caller, which reports it with its own message.\n */\nexport function rejectUnknownVariantFields(\n record: Readonly<Record<string, unknown>>, discriminator: string,\n allowedByVariant: Readonly<Record<string, readonly string[]>>, path: string\n): void {\n const variant = record[discriminator];\n if (typeof variant === \"string\" && Object.hasOwn(allowedByVariant, variant)) {\n rejectUnknownFields(record, allowedByVariant[variant]!, path);\n }\n}\n\n// Field checks shared by the domain parsers, each with the one message every parser used for it (2.19.0: these were private\n// copies in up to 44 modules; one shared copy keeps the bundles smaller and the messages unchanged).\n\n/** A plain object (not null, not an array) whose keys are on `allowedKeys` (null: any keys): `<path> must be an object.` */\nexport function requireConfigRecord(value: unknown, path: string, allowedKeys: readonly string[] | null): Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) throw new InvalidConfigurationError(path + \" must be an object.\");\n if (allowedKeys !== null) rejectUnknownFields(value, allowedKeys, path);\n return value as Record<string, unknown>;\n}\n/** `record[key]`, a string that is not blank: `<path>.<key> must be a non-empty string.` */\nexport function requireConfigRecordString(record: Readonly<Record<string, unknown>>, key: string, path: string): string {\n const value = record[key];\n if (typeof value !== \"string\" || value.trim().length === 0) throw new InvalidConfigurationError(path + \".\" + key + \" must be a non-empty string.\");\n return value;\n}\n/** A string that is not blank, returned as given: `<path> must be a non-empty string.` */\nexport function requireConfigString(value: unknown, path: string): string {\n if (typeof value !== \"string\" || value.trim().length === 0) throw new InvalidConfigurationError(path + \" must be a non-empty string.\");\n return value;\n}\n/** A string that is not blank, returned trimmed: `<path> must be a non-empty string.` */\nexport function requireTrimmedConfigString(value: unknown, path: string): string {\n return requireConfigString(value, path).trim();\n}\n/** A finite number: `<path> must be finite.` */\nexport function requireConfigFinite(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw new InvalidConfigurationError(path + \" must be finite.\");\n return value;\n}\n/** A finite number: `<path> must be a finite number.` */\nexport function requireConfigFiniteNumber(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw new InvalidConfigurationError(path + \" must be a finite number.\");\n return value;\n}\n/** A finite number above zero: `<path> must be finite and greater than zero.` */\nexport function requireConfigPositiveFinite(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) throw new InvalidConfigurationError(path + \" must be finite and greater than zero.\");\n return value;\n}\n/** A finite number at least zero: `<path> must be finite and greater than or equal to zero.` */\nexport function requireConfigNonNegativeFinite(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) throw new InvalidConfigurationError(path + \" must be finite and greater than or equal to zero.\");\n return value;\n}\n/** A safe integer above zero: `<path> must be a positive safe integer.` */\nexport function requireConfigPositiveSafeInteger(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0) throw new InvalidConfigurationError(path + \" must be a positive safe integer.\");\n return value;\n}\n/** A safe integer at least zero: `<path> must be a non-negative safe integer.` */\nexport function requireConfigNonNegativeSafeInteger(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) throw new InvalidConfigurationError(path + \" must be a non-negative safe integer.\");\n return value;\n}\n/** `\"calibrated\"` or `\"approximation\"`: `<path> is invalid.` */\nexport function parseConfigScientificStatus(value: unknown, path: string): \"calibrated\" | \"approximation\" {\n if (value !== \"calibrated\" && value !== \"approximation\") throw new InvalidConfigurationError(path + \" is invalid.\");\n return value;\n}\n/** `\"supported\"`, `\"unsupported\"` or `\"unknown\"`: `<path> is invalid.` */\nexport function parseConfigAvailability(value: unknown, path: string): \"supported\" | \"unsupported\" | \"unknown\" {\n if (value !== \"supported\" && value !== \"unsupported\" && value !== \"unknown\") throw new InvalidConfigurationError(path + \" is invalid.\");\n return value;\n}\n/** A finite number (scientific input): `<path> must be finite.` */\nexport function requireInputFinite(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw new InvalidScientificInputError(path + \" must be finite.\");\n return value;\n}\n/** A finite number above zero (scientific input): `<path> must be finite and greater than zero.` */\nexport function requireInputPositiveFinite(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) throw new InvalidScientificInputError(path + \" must be finite and greater than zero.\");\n return value;\n}\n/** A finite number at least zero (scientific input): `<path> must be finite and greater than or equal to zero.` */\nexport function requireInputNonNegativeFinite(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) throw new InvalidScientificInputError(path + \" must be finite and greater than or equal to zero.\");\n return value;\n}\n/** A safe integer at least zero (scientific input): `<path> must be a non-negative safe integer.` */\nexport function requireInputNonNegativeSafeInteger(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) throw new InvalidScientificInputError(path + \" must be a non-negative safe integer.\");\n return value;\n}\n/** A finite number, name first (scientific input): `<name> must be finite.` */\nexport function requireNamedFinite(name: string, value: unknown): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw new InvalidScientificInputError(name + \" must be finite.\");\n return value;\n}\n/** Throws unless `value` is finite (scientific input): `<name> must be finite.` */\nexport function assertNamedFinite(name: string, value: number): void {\n if (!Number.isFinite(value)) throw new InvalidScientificInputError(name + \" must be finite.\");\n}\n/** An array of distinct non-blank strings, each trimmed: `<path> must be an array.`, `<path> must not contain duplicates.` */\nexport function parseConfigLimitations(value: unknown, path: string): readonly string[] {\n if (!Array.isArray(value)) throw new InvalidConfigurationError(path + \" must be an array.\");\n const parsed = value.map((entry, index) => requireTrimmedConfigString(entry, path + \"[\" + index + \"]\"));\n if (new Set(parsed).size !== parsed.length) throw new InvalidConfigurationError(path + \" must not contain duplicates.\");\n return parsed;\n}\n/** A finite number above zero: `<path> must be finite.`, then `<path> must be greater than zero.` */\nexport function requireConfigFiniteAboveZero(value: unknown, path: string): number {\n const parsed = requireConfigFinite(value, path);\n if (parsed <= 0) throw new InvalidConfigurationError(path + \" must be greater than zero.\");\n return parsed;\n}\n/** A finite number at least zero: `<path> must be finite.`, then `<path> must be greater than or equal to zero.` */\nexport function requireConfigFiniteAtLeastZero(value: unknown, path: string): number {\n const parsed = requireConfigFinite(value, path);\n if (parsed < 0) throw new InvalidConfigurationError(path + \" must be greater than or equal to zero.\");\n return parsed;\n}\n/** A finite number above zero: `<path> must be a finite number.`, then `<path> must be greater than zero.` */\nexport function requireConfigNumberAboveZero(value: unknown, path: string): number {\n const parsed = requireConfigFiniteNumber(value, path);\n if (parsed <= 0) throw new InvalidConfigurationError(path + \" must be greater than zero.\");\n return parsed;\n}\n/** A finite number at least zero: `<path> must be a finite number.`, then `<path> must be greater than or equal to zero.` */\nexport function requireConfigNumberAtLeastZero(value: unknown, path: string): number {\n const parsed = requireConfigFiniteNumber(value, path);\n if (parsed < 0) throw new InvalidConfigurationError(path + \" must be greater than or equal to zero.\");\n return parsed;\n}\n/** A number from 0 through 1: `<path> must be a finite number.`, then `<path> must be a finite fraction from 0 through 1.` */\nexport function requireConfigFraction(value: unknown, path: string): number {\n const parsed = requireConfigFiniteNumber(value, path);\n if (parsed < 0 || parsed > 1) throw new InvalidConfigurationError(path + \" must be a finite fraction from 0 through 1.\");\n return parsed;\n}\n/** A number from 0 through 1: `<path> must be finite.`, then `<path> must lie from zero through one.` */\nexport function requireConfigUnitInterval(value: unknown, path: string): number {\n const parsed = requireConfigFinite(value, path);\n if (parsed < 0 || parsed > 1) throw new InvalidConfigurationError(path + \" must lie from zero through one.\");\n return parsed;\n}\n/** A finite number above zero (scientific input): `<path> must be finite.`, then `<path> must be greater than zero.` */\nexport function requireInputFiniteAboveZero(value: unknown, path: string): number {\n const parsed = requireInputFinite(value, path);\n if (parsed <= 0) throw new InvalidScientificInputError(path + \" must be greater than zero.\");\n return parsed;\n}\n/** A finite number at least zero (scientific input): `<path> must be finite.`, then `<path> must be greater than or equal to zero.` */\nexport function requireInputFiniteAtLeastZero(value: unknown, path: string): number {\n const parsed = requireInputFinite(value, path);\n if (parsed < 0) throw new InvalidScientificInputError(path + \" must be greater than or equal to zero.\");\n return parsed;\n}\n"]}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { validateCalculationQuality } from "./calculation-result.js";
|
|
11
11
|
import { InvalidScientificInputError } from "./validation.js";
|
|
12
12
|
import { parseEvidenceProvenance } from "./evidence-provenance.js";
|
|
13
|
-
import { requireInputKeys } from "./record-validation.js";
|
|
13
|
+
import { requireInputKeys, requireTrimmedConfigString as requireNonEmptyString, requireInputNonNegativeFinite as requireNonNegativeFinite } from "./record-validation.js";
|
|
14
14
|
import { InvalidConfigurationError } from "./configuration-error.js";
|
|
15
15
|
export const SCIENTIFIC_ASSURANCE_CONTRACT_VERSION = "0.1.0";
|
|
16
16
|
const SCIENTIFIC_STATUSES = new Set([
|
|
@@ -29,23 +29,6 @@ const SOURCE_KINDS = new Set([
|
|
|
29
29
|
"model",
|
|
30
30
|
"fixture"
|
|
31
31
|
]);
|
|
32
|
-
function requireNonEmptyString(value, path) {
|
|
33
|
-
if (typeof value !== "string" ||
|
|
34
|
-
value.trim().length === 0) {
|
|
35
|
-
throw new InvalidConfigurationError(path +
|
|
36
|
-
" must be a non-empty string.");
|
|
37
|
-
}
|
|
38
|
-
return value.trim();
|
|
39
|
-
}
|
|
40
|
-
function requireNonNegativeFinite(value, path) {
|
|
41
|
-
if (typeof value !== "number" ||
|
|
42
|
-
!Number.isFinite(value) ||
|
|
43
|
-
value < 0) {
|
|
44
|
-
throw new InvalidScientificInputError(path +
|
|
45
|
-
" must be finite and greater than or equal to zero.");
|
|
46
|
-
}
|
|
47
|
-
return value;
|
|
48
|
-
}
|
|
49
32
|
function validateSourceIdentity(value, path) {
|
|
50
33
|
if (!SOURCE_KINDS.has(value.kind)) {
|
|
51
34
|
throw new InvalidConfigurationError(path + ".kind is invalid.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scientific-assurance.js","sourceRoot":"","sources":["../../src/core/scientific-assurance.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Combines the scientific status, evidence and uncertainty of several pipeline stages into one\n * record, without inventing a single numeric uncertainty.\n *\n * The combined status can be no better than the weakest required input. Each component's\n * evidence and uncertainty is kept exactly as given, after validation.\n * @see docs/API_STYLE.md for equations, coordinate/unit conventions, blockers and support limits.\n */\n\nimport {\n validateCalculationQuality,\n type CalculationQuality\n} from \"./calculation-result.js\";\nimport { InvalidScientificInputError } from \"./validation.js\";\nimport {\n parseEvidenceProvenance,\n type EvidenceProvenance\n} from \"./evidence-provenance.js\";\nimport { requireInputKeys } from \"./record-validation.js\";\nimport { InvalidConfigurationError } from \"./configuration-error.js\";\n\nexport const SCIENTIFIC_ASSURANCE_CONTRACT_VERSION =\n \"0.1.0\" as const;\n\nexport type ScientificAssuranceStatus =\n | \"calibrated\"\n | \"approximation\"\n | \"unknown\";\n\nexport type ScientificAssuranceBasisKind =\n | \"evidence-backed-fact\"\n | \"photivra-model-assumption\"\n | \"not-applicable\";\n\nexport type ScientificAssuranceSourceKind =\n | \"profile\"\n | \"result\"\n | \"model\"\n | \"fixture\";\n\nexport interface ScientificAssuranceSourceIdentity {\n kind: ScientificAssuranceSourceKind;\n id: string;\n version?: string;\n}\n\nexport type ScientificAssuranceComponentUncertainty =\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: \"calculation-quality\";\n quality: CalculationQuality;\n }\n | {\n kind: \"not-quantified\";\n limitation: string;\n }\n | {\n kind: \"unknown\";\n limitation: string;\n }\n | {\n kind: \"not-applicable\";\n reason: string;\n };\n\nexport interface ScientificAssuranceComponent {\n componentId: string;\n role: string;\n required: boolean;\n sourceIdentity:\n ScientificAssuranceSourceIdentity;\n basisKind:\n ScientificAssuranceBasisKind;\n scientificStatus:\n ScientificAssuranceStatus;\n evidenceRequirement:\n | \"required\"\n | \"not-required\";\n evidence:\n readonly EvidenceProvenance[];\n uncertainty:\n ScientificAssuranceComponentUncertainty;\n limitations:\n readonly string[];\n}\n\nexport type ComposedScientificUncertaintyStatus =\n | {\n kind: \"unknown\";\n componentIds:\n readonly string[];\n limitation: string;\n }\n | {\n kind: \"not-quantified\";\n componentIds:\n readonly string[];\n limitation: string;\n }\n | {\n kind: \"not-propagated\";\n componentIds:\n readonly string[];\n limitation: string;\n }\n | {\n kind: \"not-applicable\";\n componentIds:\n readonly string[];\n limitation: string;\n };\n\n/**\n * Combined status and kept evidence for one declared scientific result across stages.\n *\n * - A required input that is incomplete or approximate limits the combined status.\n * - Deterministic processing cannot turn an approximation into a calibration.\n * - Uncertainty components stay separate unless an explicit mathematical propagation\n * model justifies combining them.\n * - A count of successful stages is not an accuracy bound.\n */\nexport interface ComposedScientificAssurance {\n version:\n typeof SCIENTIFIC_ASSURANCE_CONTRACT_VERSION;\n scientificStatus:\n ScientificAssuranceStatus;\n weakestRequiredComponentIds:\n readonly string[];\n evidenceStatus:\n | \"complete\"\n | \"missing-required-evidence\";\n missingRequiredEvidenceComponentIds:\n readonly string[];\n uncertainty:\n ComposedScientificUncertaintyStatus;\n components:\n readonly ScientificAssuranceComponent[];\n componentEvidencePreserved: true;\n componentUncertaintyPreserved: true;\n aggregateNumericUncertaintyFabricated:\n false;\n downstreamStatusPromotedAboveInputs:\n false;\n}\n\nexport interface ComposeScientificAssuranceInput {\n components:\n readonly ScientificAssuranceComponent[];\n}\n\nconst SCIENTIFIC_STATUSES =\n new Set<ScientificAssuranceStatus>([\n \"calibrated\",\n \"approximation\",\n \"unknown\"\n ]);\n\nconst BASIS_KINDS =\n new Set<ScientificAssuranceBasisKind>([\n \"evidence-backed-fact\",\n \"photivra-model-assumption\",\n \"not-applicable\"\n ]);\n\nconst SOURCE_KINDS =\n new Set<ScientificAssuranceSourceKind>([\n \"profile\",\n \"result\",\n \"model\",\n \"fixture\"\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 +\n \" must be a non-empty string.\"\n );\n }\n return value.trim();\n}\n\nfunction requireNonNegativeFinite(\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 validateSourceIdentity(\n value:\n ScientificAssuranceSourceIdentity,\n path: string\n): ScientificAssuranceSourceIdentity {\n if (\n !SOURCE_KINDS.has(\n value.kind as\n ScientificAssuranceSourceKind\n )\n ) {\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n }\n\n return {\n kind: value.kind,\n id:\n requireNonEmptyString(\n value.id,\n path + \".id\"\n ),\n ...(value.version === undefined\n ? {}\n : {\n version:\n requireNonEmptyString(\n value.version,\n path + \".version\"\n )\n })\n };\n}\n\nfunction validateUncertainty(\n value:\n ScientificAssuranceComponentUncertainty,\n path: string\n): ScientificAssuranceComponentUncertainty {\n if (value.kind === \"relative\") {\n const fraction =\n requireNonNegativeFinite(\n value.fraction,\n path + \".fraction\"\n );\n if (fraction > 1) {\n throw new InvalidScientificInputError(\n path +\n \".fraction must be less than or equal to one.\"\n );\n }\n return {\n kind: \"relative\",\n fraction,\n basis:\n requireNonEmptyString(\n value.basis,\n path + \".basis\"\n )\n };\n }\n\n if (value.kind === \"absolute\") {\n return {\n kind: \"absolute\",\n plusMinus:\n requireNonNegativeFinite(\n value.plusMinus,\n path + \".plusMinus\"\n ),\n unit:\n requireNonEmptyString(\n value.unit,\n path + \".unit\"\n ),\n ...(value.basis === undefined\n ? {}\n : {\n basis:\n requireNonEmptyString(\n value.basis,\n path + \".basis\"\n )\n })\n };\n }\n\n if (\n value.kind ===\n \"calculation-quality\"\n ) {\n validateCalculationQuality(\n value.quality\n );\n if (\n value.quality\n .uncertainty ===\n undefined ||\n value.quality\n .uncertainty.length ===\n 0\n ) {\n throw new InvalidScientificInputError(\n path +\n \".quality must include quantified uncertainty components; use another semantic uncertainty state otherwise.\"\n );\n }\n return {\n kind:\n \"calculation-quality\",\n quality: value.quality\n };\n }\n\n if (\n value.kind ===\n \"not-quantified\"\n ) {\n return {\n kind: \"not-quantified\",\n limitation:\n requireNonEmptyString(\n value.limitation,\n path + \".limitation\"\n )\n };\n }\n\n if (value.kind === \"unknown\") {\n return {\n kind: \"unknown\",\n limitation:\n requireNonEmptyString(\n value.limitation,\n path + \".limitation\"\n )\n };\n }\n\n if (\n value.kind ===\n \"not-applicable\"\n ) {\n return {\n kind: \"not-applicable\",\n reason:\n requireNonEmptyString(\n value.reason,\n path + \".reason\"\n )\n };\n }\n\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction validateLimitations(\n value: readonly string[],\n path: string\n): readonly string[] {\n if (!Array.isArray(value)) {\n throw new InvalidConfigurationError(\n path + \" must be an array.\"\n );\n }\n\n const parsed =\n value.map((entry, index) =>\n requireNonEmptyString(\n entry,\n path +\n \"[\" +\n index +\n \"]\"\n )\n );\n\n if (\n new Set(parsed).size !==\n parsed.length\n ) {\n throw new InvalidScientificInputError(\n path +\n \" must not contain duplicates.\"\n );\n }\n\n return parsed;\n}\n\nfunction validateComponent(\n value:\n ScientificAssuranceComponent,\n index: number\n): ScientificAssuranceComponent {\n const path =\n \"components[\" +\n index +\n \"]\";\n\n if (\n typeof value.required !==\n \"boolean\"\n ) {\n throw new InvalidConfigurationError(\n path +\n \".required must be boolean.\"\n );\n }\n\n if (\n !BASIS_KINDS.has(\n value.basisKind as\n ScientificAssuranceBasisKind\n )\n ) {\n throw new InvalidConfigurationError(\n path +\n \".basisKind is invalid.\"\n );\n }\n\n if (\n !SCIENTIFIC_STATUSES.has(\n value.scientificStatus as\n ScientificAssuranceStatus\n )\n ) {\n throw new InvalidConfigurationError(\n path +\n \".scientificStatus is invalid.\"\n );\n }\n\n if (\n value.basisKind ===\n \"evidence-backed-fact\" &&\n value.evidenceRequirement !==\n \"required\"\n ) {\n throw new InvalidScientificInputError(\n path +\n '.basisKind \"evidence-backed-fact\" requires evidenceRequirement \"required\".'\n );\n }\n\n if (\n value.evidenceRequirement !==\n \"required\" &&\n value.evidenceRequirement !==\n \"not-required\"\n ) {\n throw new InvalidConfigurationError(\n path +\n \".evidenceRequirement is invalid.\"\n );\n }\n\n if (!Array.isArray(value.evidence)) {\n throw new InvalidConfigurationError(\n path +\n \".evidence must be an array.\"\n );\n }\n\n const evidence =\n value.evidence.map(\n (entry, evidenceIndex) =>\n parseEvidenceProvenance(\n entry,\n path +\n \".evidence[\" +\n evidenceIndex +\n \"]\"\n )\n );\n\n return {\n componentId:\n requireNonEmptyString(\n value.componentId,\n path + \".componentId\"\n ),\n role:\n requireNonEmptyString(\n value.role,\n path + \".role\"\n ),\n required: value.required,\n sourceIdentity:\n validateSourceIdentity(\n value.sourceIdentity,\n path +\n \".sourceIdentity\"\n ),\n basisKind:\n value.basisKind,\n scientificStatus:\n value.scientificStatus,\n evidenceRequirement:\n value.evidenceRequirement,\n evidence,\n uncertainty:\n validateUncertainty(\n value.uncertainty,\n path + \".uncertainty\"\n ),\n limitations:\n validateLimitations(\n value.limitations,\n path + \".limitations\"\n )\n };\n}\n\nfunction statusRank(\n value:\n ScientificAssuranceStatus\n): number {\n if (value === \"unknown\") {\n return 0;\n }\n if (\n value === \"approximation\"\n ) {\n return 1;\n }\n return 2;\n}\n\nfunction composedUncertainty(\n required:\n readonly ScientificAssuranceComponent[]\n): ComposedScientificUncertaintyStatus {\n const unknown =\n required.filter(\n (component) =>\n component.uncertainty.kind ===\n \"unknown\"\n );\n\n if (unknown.length > 0) {\n return {\n kind: \"unknown\",\n componentIds:\n unknown.map(\n (component) =>\n component.componentId\n ),\n limitation:\n \"At least one required component has unknown uncertainty; no aggregate numeric uncertainty is claimed.\"\n };\n }\n\n const unquantified =\n required.filter(\n (component) =>\n component.uncertainty.kind ===\n \"not-quantified\"\n );\n\n if (\n unquantified.length > 0\n ) {\n return {\n kind: \"not-quantified\",\n componentIds:\n unquantified.map(\n (component) =>\n component.componentId\n ),\n limitation:\n \"At least one required component has unquantified uncertainty; absence of a numeric bound is not zero uncertainty.\"\n };\n }\n\n const quantified =\n required.filter(\n (component) =>\n component.uncertainty.kind ===\n \"relative\" ||\n component.uncertainty.kind ===\n \"absolute\" ||\n component.uncertainty.kind ===\n \"calculation-quality\"\n );\n\n if (quantified.length > 0) {\n return {\n kind: \"not-propagated\",\n componentIds:\n quantified.map(\n (component) =>\n component.componentId\n ),\n limitation:\n \"Quantified component uncertainties are preserved but are not numerically combined without an explicit propagation model and correlation assumptions.\"\n };\n }\n\n return {\n kind: \"not-applicable\",\n componentIds:\n required.map(\n (component) =>\n component.componentId\n ),\n limitation:\n \"No required component declares a quantitative uncertainty applicable to this composition.\"\n };\n}\n\n/**\n * Combines the scientific status, evidence and uncertainty of several inputs into one\n * record, without inventing a single numeric uncertainty.\n *\n * The combined status can be no better than the weakest required input. Each component's\n * evidence and uncertainty is kept exactly as given, after validation.\n */\nexport function composeScientificAssurance(\n input:\n ComposeScientificAssuranceInput\n): ComposedScientificAssurance {\n requireInputKeys(input, \"composeScientificAssurance\", [\"components\"]);\n if (\n !Array.isArray(\n input.components\n ) ||\n input.components.length === 0\n ) {\n throw new InvalidConfigurationError(\n \"components must be a non-empty array.\"\n );\n }\n\n const components =\n input.components.map(\n validateComponent\n );\n\n const ids =\n components.map(\n (component) =>\n component.componentId\n );\n\n if (\n new Set(ids).size !==\n ids.length\n ) {\n throw new InvalidScientificInputError(\n \"components must not contain duplicate componentId values.\"\n );\n }\n\n const required =\n components.filter(\n (component) =>\n component.required\n );\n\n if (required.length === 0) {\n throw new InvalidScientificInputError(\n \"At least one scientific-assurance component must be required.\"\n );\n }\n\n let weakestRank =\n Number.POSITIVE_INFINITY;\n\n for (const component of required) {\n weakestRank =\n Math.min(\n weakestRank,\n statusRank(\n component.scientificStatus\n )\n );\n }\n\n const weakest =\n required.filter(\n (component) =>\n statusRank(\n component.scientificStatus\n ) === weakestRank\n );\n\n const statusFromInputs =\n weakestRank === 0\n ? \"unknown\"\n : weakestRank === 1\n ? \"approximation\"\n : \"calibrated\";\n\n const missingRequiredEvidence =\n required.filter(\n (component) =>\n component\n .evidenceRequirement ===\n \"required\" &&\n component.evidence.length === 0\n );\n\n const scientificStatus:\n ScientificAssuranceStatus =\n missingRequiredEvidence.length >\n 0\n ? \"unknown\"\n : statusFromInputs;\n\n const weakestRequiredComponentIds =\n missingRequiredEvidence.length >\n 0\n ? missingRequiredEvidence.map(\n (component) =>\n component.componentId\n )\n : weakest.map(\n (component) =>\n component.componentId\n );\n\n return {\n version:\n SCIENTIFIC_ASSURANCE_CONTRACT_VERSION,\n scientificStatus,\n weakestRequiredComponentIds,\n evidenceStatus:\n missingRequiredEvidence\n .length === 0\n ? \"complete\"\n : \"missing-required-evidence\",\n missingRequiredEvidenceComponentIds:\n missingRequiredEvidence.map(\n (component) =>\n component.componentId\n ),\n uncertainty:\n composedUncertainty(\n required\n ),\n components,\n componentEvidencePreserved:\n true,\n componentUncertaintyPreserved:\n true,\n aggregateNumericUncertaintyFabricated:\n false,\n downstreamStatusPromotedAboveInputs:\n false\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"scientific-assurance.js","sourceRoot":"","sources":["../../src/core/scientific-assurance.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Combines the scientific status, evidence and uncertainty of several pipeline stages into one\n * record, without inventing a single numeric uncertainty.\n *\n * The combined status can be no better than the weakest required input. Each component's\n * evidence and uncertainty is kept exactly as given, after validation.\n * @see docs/API_STYLE.md for equations, coordinate/unit conventions, blockers and support limits.\n */\n\nimport {\n validateCalculationQuality,\n type CalculationQuality\n} from \"./calculation-result.js\";\nimport { InvalidScientificInputError } from \"./validation.js\";\nimport {\n parseEvidenceProvenance,\n type EvidenceProvenance\n} from \"./evidence-provenance.js\";\nimport { requireInputKeys, requireTrimmedConfigString as requireNonEmptyString, requireInputNonNegativeFinite as requireNonNegativeFinite } from \"./record-validation.js\";\nimport { InvalidConfigurationError } from \"./configuration-error.js\";\n\nexport const SCIENTIFIC_ASSURANCE_CONTRACT_VERSION =\n \"0.1.0\" as const;\n\nexport type ScientificAssuranceStatus =\n | \"calibrated\"\n | \"approximation\"\n | \"unknown\";\n\nexport type ScientificAssuranceBasisKind =\n | \"evidence-backed-fact\"\n | \"photivra-model-assumption\"\n | \"not-applicable\";\n\nexport type ScientificAssuranceSourceKind =\n | \"profile\"\n | \"result\"\n | \"model\"\n | \"fixture\";\n\nexport interface ScientificAssuranceSourceIdentity {\n kind: ScientificAssuranceSourceKind;\n id: string;\n version?: string;\n}\n\nexport type ScientificAssuranceComponentUncertainty =\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: \"calculation-quality\";\n quality: CalculationQuality;\n }\n | {\n kind: \"not-quantified\";\n limitation: string;\n }\n | {\n kind: \"unknown\";\n limitation: string;\n }\n | {\n kind: \"not-applicable\";\n reason: string;\n };\n\nexport interface ScientificAssuranceComponent {\n componentId: string;\n role: string;\n required: boolean;\n sourceIdentity:\n ScientificAssuranceSourceIdentity;\n basisKind:\n ScientificAssuranceBasisKind;\n scientificStatus:\n ScientificAssuranceStatus;\n evidenceRequirement:\n | \"required\"\n | \"not-required\";\n evidence:\n readonly EvidenceProvenance[];\n uncertainty:\n ScientificAssuranceComponentUncertainty;\n limitations:\n readonly string[];\n}\n\nexport type ComposedScientificUncertaintyStatus =\n | {\n kind: \"unknown\";\n componentIds:\n readonly string[];\n limitation: string;\n }\n | {\n kind: \"not-quantified\";\n componentIds:\n readonly string[];\n limitation: string;\n }\n | {\n kind: \"not-propagated\";\n componentIds:\n readonly string[];\n limitation: string;\n }\n | {\n kind: \"not-applicable\";\n componentIds:\n readonly string[];\n limitation: string;\n };\n\n/**\n * Combined status and kept evidence for one declared scientific result across stages.\n *\n * - A required input that is incomplete or approximate limits the combined status.\n * - Deterministic processing cannot turn an approximation into a calibration.\n * - Uncertainty components stay separate unless an explicit mathematical propagation\n * model justifies combining them.\n * - A count of successful stages is not an accuracy bound.\n */\nexport interface ComposedScientificAssurance {\n version:\n typeof SCIENTIFIC_ASSURANCE_CONTRACT_VERSION;\n scientificStatus:\n ScientificAssuranceStatus;\n weakestRequiredComponentIds:\n readonly string[];\n evidenceStatus:\n | \"complete\"\n | \"missing-required-evidence\";\n missingRequiredEvidenceComponentIds:\n readonly string[];\n uncertainty:\n ComposedScientificUncertaintyStatus;\n components:\n readonly ScientificAssuranceComponent[];\n componentEvidencePreserved: true;\n componentUncertaintyPreserved: true;\n aggregateNumericUncertaintyFabricated:\n false;\n downstreamStatusPromotedAboveInputs:\n false;\n}\n\nexport interface ComposeScientificAssuranceInput {\n components:\n readonly ScientificAssuranceComponent[];\n}\n\nconst SCIENTIFIC_STATUSES =\n new Set<ScientificAssuranceStatus>([\n \"calibrated\",\n \"approximation\",\n \"unknown\"\n ]);\n\nconst BASIS_KINDS =\n new Set<ScientificAssuranceBasisKind>([\n \"evidence-backed-fact\",\n \"photivra-model-assumption\",\n \"not-applicable\"\n ]);\n\nconst SOURCE_KINDS =\n new Set<ScientificAssuranceSourceKind>([\n \"profile\",\n \"result\",\n \"model\",\n \"fixture\"\n ]);\n\nfunction validateSourceIdentity(\n value:\n ScientificAssuranceSourceIdentity,\n path: string\n): ScientificAssuranceSourceIdentity {\n if (\n !SOURCE_KINDS.has(\n value.kind as\n ScientificAssuranceSourceKind\n )\n ) {\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n }\n\n return {\n kind: value.kind,\n id:\n requireNonEmptyString(\n value.id,\n path + \".id\"\n ),\n ...(value.version === undefined\n ? {}\n : {\n version:\n requireNonEmptyString(\n value.version,\n path + \".version\"\n )\n })\n };\n}\n\nfunction validateUncertainty(\n value:\n ScientificAssuranceComponentUncertainty,\n path: string\n): ScientificAssuranceComponentUncertainty {\n if (value.kind === \"relative\") {\n const fraction =\n requireNonNegativeFinite(\n value.fraction,\n path + \".fraction\"\n );\n if (fraction > 1) {\n throw new InvalidScientificInputError(\n path +\n \".fraction must be less than or equal to one.\"\n );\n }\n return {\n kind: \"relative\",\n fraction,\n basis:\n requireNonEmptyString(\n value.basis,\n path + \".basis\"\n )\n };\n }\n\n if (value.kind === \"absolute\") {\n return {\n kind: \"absolute\",\n plusMinus:\n requireNonNegativeFinite(\n value.plusMinus,\n path + \".plusMinus\"\n ),\n unit:\n requireNonEmptyString(\n value.unit,\n path + \".unit\"\n ),\n ...(value.basis === undefined\n ? {}\n : {\n basis:\n requireNonEmptyString(\n value.basis,\n path + \".basis\"\n )\n })\n };\n }\n\n if (\n value.kind ===\n \"calculation-quality\"\n ) {\n validateCalculationQuality(\n value.quality\n );\n if (\n value.quality\n .uncertainty ===\n undefined ||\n value.quality\n .uncertainty.length ===\n 0\n ) {\n throw new InvalidScientificInputError(\n path +\n \".quality must include quantified uncertainty components; use another semantic uncertainty state otherwise.\"\n );\n }\n return {\n kind:\n \"calculation-quality\",\n quality: value.quality\n };\n }\n\n if (\n value.kind ===\n \"not-quantified\"\n ) {\n return {\n kind: \"not-quantified\",\n limitation:\n requireNonEmptyString(\n value.limitation,\n path + \".limitation\"\n )\n };\n }\n\n if (value.kind === \"unknown\") {\n return {\n kind: \"unknown\",\n limitation:\n requireNonEmptyString(\n value.limitation,\n path + \".limitation\"\n )\n };\n }\n\n if (\n value.kind ===\n \"not-applicable\"\n ) {\n return {\n kind: \"not-applicable\",\n reason:\n requireNonEmptyString(\n value.reason,\n path + \".reason\"\n )\n };\n }\n\n throw new InvalidConfigurationError(\n path + \".kind is invalid.\"\n );\n}\n\nfunction validateLimitations(\n value: readonly string[],\n path: string\n): readonly string[] {\n if (!Array.isArray(value)) {\n throw new InvalidConfigurationError(\n path + \" must be an array.\"\n );\n }\n\n const parsed =\n value.map((entry, index) =>\n requireNonEmptyString(\n entry,\n path +\n \"[\" +\n index +\n \"]\"\n )\n );\n\n if (\n new Set(parsed).size !==\n parsed.length\n ) {\n throw new InvalidScientificInputError(\n path +\n \" must not contain duplicates.\"\n );\n }\n\n return parsed;\n}\n\nfunction validateComponent(\n value:\n ScientificAssuranceComponent,\n index: number\n): ScientificAssuranceComponent {\n const path =\n \"components[\" +\n index +\n \"]\";\n\n if (\n typeof value.required !==\n \"boolean\"\n ) {\n throw new InvalidConfigurationError(\n path +\n \".required must be boolean.\"\n );\n }\n\n if (\n !BASIS_KINDS.has(\n value.basisKind as\n ScientificAssuranceBasisKind\n )\n ) {\n throw new InvalidConfigurationError(\n path +\n \".basisKind is invalid.\"\n );\n }\n\n if (\n !SCIENTIFIC_STATUSES.has(\n value.scientificStatus as\n ScientificAssuranceStatus\n )\n ) {\n throw new InvalidConfigurationError(\n path +\n \".scientificStatus is invalid.\"\n );\n }\n\n if (\n value.basisKind ===\n \"evidence-backed-fact\" &&\n value.evidenceRequirement !==\n \"required\"\n ) {\n throw new InvalidScientificInputError(\n path +\n '.basisKind \"evidence-backed-fact\" requires evidenceRequirement \"required\".'\n );\n }\n\n if (\n value.evidenceRequirement !==\n \"required\" &&\n value.evidenceRequirement !==\n \"not-required\"\n ) {\n throw new InvalidConfigurationError(\n path +\n \".evidenceRequirement is invalid.\"\n );\n }\n\n if (!Array.isArray(value.evidence)) {\n throw new InvalidConfigurationError(\n path +\n \".evidence must be an array.\"\n );\n }\n\n const evidence =\n value.evidence.map(\n (entry, evidenceIndex) =>\n parseEvidenceProvenance(\n entry,\n path +\n \".evidence[\" +\n evidenceIndex +\n \"]\"\n )\n );\n\n return {\n componentId:\n requireNonEmptyString(\n value.componentId,\n path + \".componentId\"\n ),\n role:\n requireNonEmptyString(\n value.role,\n path + \".role\"\n ),\n required: value.required,\n sourceIdentity:\n validateSourceIdentity(\n value.sourceIdentity,\n path +\n \".sourceIdentity\"\n ),\n basisKind:\n value.basisKind,\n scientificStatus:\n value.scientificStatus,\n evidenceRequirement:\n value.evidenceRequirement,\n evidence,\n uncertainty:\n validateUncertainty(\n value.uncertainty,\n path + \".uncertainty\"\n ),\n limitations:\n validateLimitations(\n value.limitations,\n path + \".limitations\"\n )\n };\n}\n\nfunction statusRank(\n value:\n ScientificAssuranceStatus\n): number {\n if (value === \"unknown\") {\n return 0;\n }\n if (\n value === \"approximation\"\n ) {\n return 1;\n }\n return 2;\n}\n\nfunction composedUncertainty(\n required:\n readonly ScientificAssuranceComponent[]\n): ComposedScientificUncertaintyStatus {\n const unknown =\n required.filter(\n (component) =>\n component.uncertainty.kind ===\n \"unknown\"\n );\n\n if (unknown.length > 0) {\n return {\n kind: \"unknown\",\n componentIds:\n unknown.map(\n (component) =>\n component.componentId\n ),\n limitation:\n \"At least one required component has unknown uncertainty; no aggregate numeric uncertainty is claimed.\"\n };\n }\n\n const unquantified =\n required.filter(\n (component) =>\n component.uncertainty.kind ===\n \"not-quantified\"\n );\n\n if (\n unquantified.length > 0\n ) {\n return {\n kind: \"not-quantified\",\n componentIds:\n unquantified.map(\n (component) =>\n component.componentId\n ),\n limitation:\n \"At least one required component has unquantified uncertainty; absence of a numeric bound is not zero uncertainty.\"\n };\n }\n\n const quantified =\n required.filter(\n (component) =>\n component.uncertainty.kind ===\n \"relative\" ||\n component.uncertainty.kind ===\n \"absolute\" ||\n component.uncertainty.kind ===\n \"calculation-quality\"\n );\n\n if (quantified.length > 0) {\n return {\n kind: \"not-propagated\",\n componentIds:\n quantified.map(\n (component) =>\n component.componentId\n ),\n limitation:\n \"Quantified component uncertainties are preserved but are not numerically combined without an explicit propagation model and correlation assumptions.\"\n };\n }\n\n return {\n kind: \"not-applicable\",\n componentIds:\n required.map(\n (component) =>\n component.componentId\n ),\n limitation:\n \"No required component declares a quantitative uncertainty applicable to this composition.\"\n };\n}\n\n/**\n * Combines the scientific status, evidence and uncertainty of several inputs into one\n * record, without inventing a single numeric uncertainty.\n *\n * The combined status can be no better than the weakest required input. Each component's\n * evidence and uncertainty is kept exactly as given, after validation.\n */\nexport function composeScientificAssurance(\n input:\n ComposeScientificAssuranceInput\n): ComposedScientificAssurance {\n requireInputKeys(input, \"composeScientificAssurance\", [\"components\"]);\n if (\n !Array.isArray(\n input.components\n ) ||\n input.components.length === 0\n ) {\n throw new InvalidConfigurationError(\n \"components must be a non-empty array.\"\n );\n }\n\n const components =\n input.components.map(\n validateComponent\n );\n\n const ids =\n components.map(\n (component) =>\n component.componentId\n );\n\n if (\n new Set(ids).size !==\n ids.length\n ) {\n throw new InvalidScientificInputError(\n \"components must not contain duplicate componentId values.\"\n );\n }\n\n const required =\n components.filter(\n (component) =>\n component.required\n );\n\n if (required.length === 0) {\n throw new InvalidScientificInputError(\n \"At least one scientific-assurance component must be required.\"\n );\n }\n\n let weakestRank =\n Number.POSITIVE_INFINITY;\n\n for (const component of required) {\n weakestRank =\n Math.min(\n weakestRank,\n statusRank(\n component.scientificStatus\n )\n );\n }\n\n const weakest =\n required.filter(\n (component) =>\n statusRank(\n component.scientificStatus\n ) === weakestRank\n );\n\n const statusFromInputs =\n weakestRank === 0\n ? \"unknown\"\n : weakestRank === 1\n ? \"approximation\"\n : \"calibrated\";\n\n const missingRequiredEvidence =\n required.filter(\n (component) =>\n component\n .evidenceRequirement ===\n \"required\" &&\n component.evidence.length === 0\n );\n\n const scientificStatus:\n ScientificAssuranceStatus =\n missingRequiredEvidence.length >\n 0\n ? \"unknown\"\n : statusFromInputs;\n\n const weakestRequiredComponentIds =\n missingRequiredEvidence.length >\n 0\n ? missingRequiredEvidence.map(\n (component) =>\n component.componentId\n )\n : weakest.map(\n (component) =>\n component.componentId\n );\n\n return {\n version:\n SCIENTIFIC_ASSURANCE_CONTRACT_VERSION,\n scientificStatus,\n weakestRequiredComponentIds,\n evidenceStatus:\n missingRequiredEvidence\n .length === 0\n ? \"complete\"\n : \"missing-required-evidence\",\n missingRequiredEvidenceComponentIds:\n missingRequiredEvidence.map(\n (component) =>\n component.componentId\n ),\n uncertainty:\n composedUncertainty(\n required\n ),\n components,\n componentEvidencePreserved:\n true,\n componentUncertaintyPreserved:\n true,\n aggregateNumericUncertaintyFabricated:\n false,\n downstreamStatusPromotedAboveInputs:\n false\n };\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small helpers shared by several modules (2.19.0: these were private copies in each; one shared copy keeps the bundles
|
|
3
|
+
* smaller). Behaviour is unchanged.
|
|
4
|
+
*/
|
|
5
|
+
/** Freezes a value and every object it holds, depth first; already frozen objects are left as they are. */
|
|
6
|
+
export declare function deepFreeze<T>(value: T): T;
|
|
7
|
+
/** A deep copy of JSON data. */
|
|
8
|
+
export declare function cloneJson<T>(value: T): T;
|
|
9
|
+
/** A running sum with Kahan compensation. */
|
|
10
|
+
export interface CompensatedSum {
|
|
11
|
+
sum: number;
|
|
12
|
+
correction: number;
|
|
13
|
+
}
|
|
14
|
+
/** Adds `value` to a Kahan-compensated sum (Kahan 1965). */
|
|
15
|
+
export declare function addCompensated(state: CompensatedSum, value: number): void;
|
|
16
|
+
/** Whether two points (or sites) have the same x and y. */
|
|
17
|
+
export declare function sameSite(a: {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
}, b: {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
}): boolean;
|
|
24
|
+
/** The whole raster as a rectangle at the origin. */
|
|
25
|
+
export declare function fullRect(raster: {
|
|
26
|
+
pixelWidth: number;
|
|
27
|
+
pixelHeight: number;
|
|
28
|
+
}): {
|
|
29
|
+
x: number;
|
|
30
|
+
y: number;
|
|
31
|
+
width: number;
|
|
32
|
+
height: number;
|
|
33
|
+
};
|