@winkjs/composer 0.0.2 → 0.4.1
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/LICENSE +1 -1
- package/README.md +106 -80
- package/package.json +56 -28
- package/src/composer.js +75 -0
- package/src/core/batch/aoo-encoder.js +148 -0
- package/src/core/batch/index.js +12 -0
- package/src/core/batch/sliding-window.js +91 -0
- package/src/core/codec/index.js +137 -0
- package/src/core/emitter-manager/mqtt/constants.js +102 -0
- package/src/core/emitter-manager/mqtt/emitter.js +780 -0
- package/src/core/emitter-manager/mqtt/index.js +190 -0
- package/src/core/emitter-manager/mqtt/mqtt-store.js +538 -0
- package/src/core/emitter-manager/terminal/assert-columns.js +98 -0
- package/src/core/emitter-manager/terminal/formatters.js +160 -0
- package/src/core/emitter-manager/terminal/index.js +341 -0
- package/src/core/env-vars.js +245 -0
- package/src/core/mqtt-protocol.js +47 -0
- package/src/core/partition-manager/index.js +7 -0
- package/src/core/partition-manager/init.js +44 -0
- package/src/core/partition-manager/introspect.js +15 -0
- package/src/core/partition-manager/publish-to.js +6 -0
- package/src/core/partition-manager/recompute.js +5 -0
- package/src/core/partition-manager/reset.js +5 -0
- package/src/core/partition-manager/update.js +264 -0
- package/src/core/partition-manager/validate-flow.js +157 -0
- package/src/core/semantics/digest.js +128 -0
- package/src/core/semantics/index.js +83 -0
- package/src/core/semantics/loader.js +571 -0
- package/src/core/semantics/schemas/asset-class-schema.js +218 -0
- package/src/core/semantics/schemas/column-schema.js +651 -0
- package/src/core/semantics/schemas/enum-schema.js +153 -0
- package/src/core/semantics/schemas/index.js +51 -0
- package/src/core/semantics/warnings.js +141 -0
- package/src/core/shutdown-manager/index.js +289 -0
- package/src/core/source-manager/csv/index.js +171 -0
- package/src/core/source-manager/csv/start.js +456 -0
- package/src/core/source-manager/mqtt/client.js +406 -0
- package/src/core/source-manager/mqtt/constants.js +147 -0
- package/src/core/source-manager/mqtt/dedup.js +244 -0
- package/src/core/source-manager/mqtt/index.js +260 -0
- package/src/core/source-manager/mqtt/status.js +546 -0
- package/src/core/source-manager/test-harness/comparator.js +226 -0
- package/src/core/source-manager/test-harness/field-generator.js +85 -0
- package/src/core/source-manager/test-harness/fuzz.js +87 -0
- package/src/core/source-manager/test-harness/index.js +115 -0
- package/src/core/source-manager/test-harness/prng.js +57 -0
- package/src/core/source-manager/test-harness/start.js +232 -0
- package/src/core/source-manager/test-harness/validate.js +213 -0
- package/src/core/storage-manager/questdb/assert-columns.js +120 -0
- package/src/core/storage-manager/questdb/ensure-tables.js +187 -0
- package/src/core/storage-manager/questdb/index.js +1251 -0
- package/src/core/storage-manager/questdb/persist-plan.js +488 -0
- package/src/core/storage-manager/questdb/writers.js +142 -0
- package/src/core/test-utils/sealed-record.js +80 -0
- package/src/core/test-utils/soak-signature.js +149 -0
- package/src/core/test-utils/tcp-proxy.js +106 -0
- package/src/core/tunable/helpers.js +254 -0
- package/src/core/tunable/index.js +87 -0
- package/src/core/utils/console-formatter/index.js +207 -0
- package/src/core/utils/create-smart-store-as/index.js +98 -0
- package/src/core/utils/create-smart-store-as/sanitize-field.js +46 -0
- package/src/core/utils/create-smart-store-as/smart-truncate.js +93 -0
- package/src/core/utils/flow/index.js +5 -0
- package/src/core/utils/flow/make-collision-checker.js +23 -0
- package/src/core/utils/flow/to-kebab.js +20 -0
- package/src/core/utils/half-life/index.js +111 -0
- package/src/core/utils/node/disable.js +11 -0
- package/src/core/utils/node/enable.js +11 -0
- package/src/core/utils/node/execute-triggers.js +40 -0
- package/src/core/utils/node/index.js +10 -0
- package/src/core/utils/node/pause.js +11 -0
- package/src/core/utils/node/populate-predicate-inputs.js +14 -0
- package/src/core/utils/node/publish-nan.js +19 -0
- package/src/core/utils/node/reset-predicate-inputs.js +11 -0
- package/src/core/utils/node/unpause.js +11 -0
- package/src/core/utils/node/validate-spec.js +22 -0
- package/src/core/utils/options/resolve-field-keyed.js +115 -0
- package/src/core/utils/quantize/index.js +75 -0
- package/src/core/utils/stats/formulas.js +67 -0
- package/src/core/utils/stats/index.js +3 -0
- package/src/core/utils/validate/composer-validators.js +141 -0
- package/src/core/utils/validate/helpers.js +206 -0
- package/src/core/utils/validate/index.js +12 -0
- package/src/core/utils/validate/type-validators.js +538 -0
- package/src/core/utils/validate/validate.js +107 -0
- package/src/core/utils/validate/validators.js +177 -0
- package/src/core/wiring/assert-handle.js +57 -0
- package/src/core/wiring/assert-module.js +63 -0
- package/src/core/wiring/index.js +5 -0
- package/src/core/wiring/node-type-to-module.js +17 -0
- package/src/core/wiring/wire-emitters.js +256 -0
- package/src/core/wiring/wire-linear-graph.js +25 -0
- package/src/core/wiring/wire-node.js +157 -0
- package/src/core/wiring/wire-semantics.js +173 -0
- package/src/core/wiring/wire-storages.js +344 -0
- package/src/flow/check-output-collisions.js +93 -0
- package/src/flow/consts.js +9 -0
- package/src/flow/deep-clone-spec.js +64 -0
- package/src/flow/driver.js +171 -0
- package/src/flow/expand-single-input-array.js +76 -0
- package/src/flow/expand-template-spec.js +93 -0
- package/src/flow/flow-api-schemas.js +300 -0
- package/src/flow/flow.js +658 -0
- package/src/flow/for-each.js +225 -0
- package/src/flow/get-signature-pattern.js +31 -0
- package/src/flow/get-target-array.js +46 -0
- package/src/flow/inspect.js +67 -0
- package/src/flow/load-node-module.js +81 -0
- package/src/flow/make-node-method.js +112 -0
- package/src/flow/resolve-pick-by-field.js +77 -0
- package/src/flow/resolve-tunables.js +76 -0
- package/src/flow/run.js +392 -0
- package/src/flow/serialize.js +161 -0
- package/src/flow/signatures-schema.js +222 -0
- package/src/flow/spec-builder.js +65 -0
- package/src/flow/validate-triggers.js +250 -0
- package/src/flow/validate.js +261 -0
- package/src/nodes/accumulate/index.js +21 -0
- package/src/nodes/accumulate/init.js +48 -0
- package/src/nodes/accumulate/introspect.js +123 -0
- package/src/nodes/accumulate/publish-to.js +34 -0
- package/src/nodes/accumulate/recompute.js +27 -0
- package/src/nodes/accumulate/reset.js +25 -0
- package/src/nodes/accumulate/update.js +42 -0
- package/src/nodes/appraise/calibrate.js +64 -0
- package/src/nodes/appraise/decision.js +66 -0
- package/src/nodes/appraise/deviation.js +140 -0
- package/src/nodes/appraise/index.js +23 -0
- package/src/nodes/appraise/init.js +165 -0
- package/src/nodes/appraise/integrate.js +45 -0
- package/src/nodes/appraise/introspect.js +352 -0
- package/src/nodes/appraise/publish-to.js +93 -0
- package/src/nodes/appraise/receptor.js +69 -0
- package/src/nodes/appraise/recompute.js +79 -0
- package/src/nodes/appraise/reset.js +53 -0
- package/src/nodes/appraise/update.js +130 -0
- package/src/nodes/archive/csv/index.js +6 -0
- package/src/nodes/archive/csv/init.js +36 -0
- package/src/nodes/archive/csv/load.js +70 -0
- package/src/nodes/archive/csv/reset.js +14 -0
- package/src/nodes/archive/csv/simple-parser.js +216 -0
- package/src/nodes/archive/csv/test.js +173 -0
- package/src/nodes/archive/csv/update.js +63 -0
- package/src/nodes/butterworth-filter/index.js +18 -0
- package/src/nodes/butterworth-filter/init.js +184 -0
- package/src/nodes/butterworth-filter/introspect.js +228 -0
- package/src/nodes/butterworth-filter/publish-to.js +21 -0
- package/src/nodes/butterworth-filter/recompute.js +13 -0
- package/src/nodes/butterworth-filter/reset.js +30 -0
- package/src/nodes/butterworth-filter/update.js +38 -0
- package/src/nodes/categorize/index.js +19 -0
- package/src/nodes/categorize/init.js +58 -0
- package/src/nodes/categorize/introspect.js +177 -0
- package/src/nodes/categorize/publish-to.js +29 -0
- package/src/nodes/categorize/recompute.js +14 -0
- package/src/nodes/categorize/reset.js +16 -0
- package/src/nodes/categorize/update.js +53 -0
- package/src/nodes/controller/index.js +9 -0
- package/src/nodes/controller/init.js +55 -0
- package/src/nodes/controller/introspect.js +91 -0
- package/src/nodes/controller/publish-to.js +8 -0
- package/src/nodes/controller/recompute.js +9 -0
- package/src/nodes/controller/reset.js +17 -0
- package/src/nodes/controller/update.js +63 -0
- package/src/nodes/diff/index.js +19 -0
- package/src/nodes/diff/init.js +37 -0
- package/src/nodes/diff/introspect.js +132 -0
- package/src/nodes/diff/publish-to.js +21 -0
- package/src/nodes/diff/recompute.js +12 -0
- package/src/nodes/diff/reset.js +12 -0
- package/src/nodes/diff/update.js +37 -0
- package/src/nodes/digest-moments/formulas.js +12 -0
- package/src/nodes/digest-moments/index.js +14 -0
- package/src/nodes/digest-moments/init.js +67 -0
- package/src/nodes/digest-moments/introspect.js +154 -0
- package/src/nodes/digest-moments/publish-to.js +34 -0
- package/src/nodes/digest-moments/recompute.js +14 -0
- package/src/nodes/digest-moments/reset.js +14 -0
- package/src/nodes/digest-moments/update.js +120 -0
- package/src/nodes/dwell-time-tracker/index.js +14 -0
- package/src/nodes/dwell-time-tracker/init.js +59 -0
- package/src/nodes/dwell-time-tracker/introspect.js +137 -0
- package/src/nodes/dwell-time-tracker/publish-to.js +22 -0
- package/src/nodes/dwell-time-tracker/recompute.js +8 -0
- package/src/nodes/dwell-time-tracker/reset.js +23 -0
- package/src/nodes/dwell-time-tracker/update.js +103 -0
- package/src/nodes/emit-if/helpers.js +94 -0
- package/src/nodes/emit-if/index.js +16 -0
- package/src/nodes/emit-if/init.js +67 -0
- package/src/nodes/emit-if/introspect.js +102 -0
- package/src/nodes/emit-if/publish-to.js +13 -0
- package/src/nodes/emit-if/recompute.js +12 -0
- package/src/nodes/emit-if/reset.js +27 -0
- package/src/nodes/emit-if/update.js +93 -0
- package/src/nodes/es-correlation/index.js +19 -0
- package/src/nodes/es-correlation/init.js +73 -0
- package/src/nodes/es-correlation/introspect.js +176 -0
- package/src/nodes/es-correlation/publish-to.js +32 -0
- package/src/nodes/es-correlation/recompute.js +56 -0
- package/src/nodes/es-correlation/reset.js +27 -0
- package/src/nodes/es-correlation/update.js +110 -0
- package/src/nodes/es-mean/index.js +20 -0
- package/src/nodes/es-mean/init.js +58 -0
- package/src/nodes/es-mean/introspect.js +129 -0
- package/src/nodes/es-mean/publish-to.js +19 -0
- package/src/nodes/es-mean/recompute.js +16 -0
- package/src/nodes/es-mean/reset.js +24 -0
- package/src/nodes/es-mean/update.js +69 -0
- package/src/nodes/es-pairwise-correlation/index.js +19 -0
- package/src/nodes/es-pairwise-correlation/init.js +98 -0
- package/src/nodes/es-pairwise-correlation/introspect.js +187 -0
- package/src/nodes/es-pairwise-correlation/publish-to.js +31 -0
- package/src/nodes/es-pairwise-correlation/recompute.js +69 -0
- package/src/nodes/es-pairwise-correlation/reset.js +29 -0
- package/src/nodes/es-pairwise-correlation/update.js +89 -0
- package/src/nodes/es-stats/index.js +21 -0
- package/src/nodes/es-stats/init.js +105 -0
- package/src/nodes/es-stats/introspect.js +157 -0
- package/src/nodes/es-stats/publish-to.js +42 -0
- package/src/nodes/es-stats/recompute.js +74 -0
- package/src/nodes/es-stats/reset.js +49 -0
- package/src/nodes/es-stats/update-envelope.js +44 -0
- package/src/nodes/es-stats/update-welford.js +64 -0
- package/src/nodes/es-stats/update.js +59 -0
- package/src/nodes/index.js +83 -0
- package/src/nodes/invert-flag/index.js +20 -0
- package/src/nodes/invert-flag/init.js +36 -0
- package/src/nodes/invert-flag/introspect.js +115 -0
- package/src/nodes/invert-flag/publish-to.js +23 -0
- package/src/nodes/invert-flag/recompute.js +12 -0
- package/src/nodes/invert-flag/reset.js +12 -0
- package/src/nodes/invert-flag/update.js +32 -0
- package/src/nodes/kalman1d/index.js +20 -0
- package/src/nodes/kalman1d/init.js +103 -0
- package/src/nodes/kalman1d/introspect.js +250 -0
- package/src/nodes/kalman1d/publish-to.js +34 -0
- package/src/nodes/kalman1d/recompute.js +23 -0
- package/src/nodes/kalman1d/reset.js +29 -0
- package/src/nodes/kalman1d/update.js +144 -0
- package/src/nodes/kernel/index.js +18 -0
- package/src/nodes/kernel/init.js +66 -0
- package/src/nodes/kernel/introspect.js +163 -0
- package/src/nodes/kernel/presets.js +74 -0
- package/src/nodes/kernel/publish-to.js +25 -0
- package/src/nodes/kernel/recompute.js +14 -0
- package/src/nodes/kernel/reset.js +20 -0
- package/src/nodes/kernel/update.js +69 -0
- package/src/nodes/lag/index.js +21 -0
- package/src/nodes/lag/init.js +87 -0
- package/src/nodes/lag/introspect.js +202 -0
- package/src/nodes/lag/publish-to.js +64 -0
- package/src/nodes/lag/recompute.js +33 -0
- package/src/nodes/lag/reset.js +49 -0
- package/src/nodes/lag/update.js +133 -0
- package/src/nodes/median3/index.js +19 -0
- package/src/nodes/median3/init.js +40 -0
- package/src/nodes/median3/introspect.js +116 -0
- package/src/nodes/median3/publish-to.js +21 -0
- package/src/nodes/median3/recompute.js +12 -0
- package/src/nodes/median3/reset.js +15 -0
- package/src/nodes/median3/update.js +58 -0
- package/src/nodes/moments-digest/copy-from.js +12 -0
- package/src/nodes/moments-digest/flush.js +17 -0
- package/src/nodes/moments-digest/index.js +132 -0
- package/src/nodes/moments-digest/init.js +84 -0
- package/src/nodes/moments-digest/introspect.js +122 -0
- package/src/nodes/moments-digest/prelude.js +28 -0
- package/src/nodes/moments-digest/publish-to.js +31 -0
- package/src/nodes/moments-digest/recompute.js +9 -0
- package/src/nodes/moments-digest/reset.js +20 -0
- package/src/nodes/moments-digest/update.js +182 -0
- package/src/nodes/node-names.js +67 -0
- package/src/nodes/page-hinkley/index.js +20 -0
- package/src/nodes/page-hinkley/init.js +66 -0
- package/src/nodes/page-hinkley/introspect.js +193 -0
- package/src/nodes/page-hinkley/publish-to.js +28 -0
- package/src/nodes/page-hinkley/recompute.js +14 -0
- package/src/nodes/page-hinkley/reset.js +23 -0
- package/src/nodes/page-hinkley/update.js +105 -0
- package/src/nodes/pass-if/index.js +21 -0
- package/src/nodes/pass-if/init.js +37 -0
- package/src/nodes/pass-if/introspect.js +93 -0
- package/src/nodes/pass-if/publish-to.js +15 -0
- package/src/nodes/pass-if/recompute.js +15 -0
- package/src/nodes/pass-if/reset.js +18 -0
- package/src/nodes/pass-if/update.js +37 -0
- package/src/nodes/persist-if/helpers.js +111 -0
- package/src/nodes/persist-if/index.js +9 -0
- package/src/nodes/persist-if/init.js +98 -0
- package/src/nodes/persist-if/introspect.js +106 -0
- package/src/nodes/persist-if/publish-to.js +21 -0
- package/src/nodes/persist-if/recompute.js +20 -0
- package/src/nodes/persist-if/reset.js +35 -0
- package/src/nodes/persist-if/update.js +112 -0
- package/src/nodes/persistence-check/index.js +14 -0
- package/src/nodes/persistence-check/init.js +38 -0
- package/src/nodes/persistence-check/introspect.js +144 -0
- package/src/nodes/persistence-check/publish-to.js +11 -0
- package/src/nodes/persistence-check/recompute.js +7 -0
- package/src/nodes/persistence-check/reset.js +12 -0
- package/src/nodes/persistence-check/update.js +57 -0
- package/src/nodes/process-index/index.js +15 -0
- package/src/nodes/process-index/init.js +48 -0
- package/src/nodes/process-index/introspect.js +182 -0
- package/src/nodes/process-index/publish-to.js +29 -0
- package/src/nodes/process-index/recompute.js +8 -0
- package/src/nodes/process-index/reset.js +8 -0
- package/src/nodes/process-index/update.js +75 -0
- package/src/nodes/ratio/index.js +14 -0
- package/src/nodes/ratio/init.js +37 -0
- package/src/nodes/ratio/introspect.js +155 -0
- package/src/nodes/ratio/publish-to.js +15 -0
- package/src/nodes/ratio/recompute.js +7 -0
- package/src/nodes/ratio/reset.js +7 -0
- package/src/nodes/ratio/update.js +47 -0
- package/src/nodes/sanitize/index.js +82 -0
- package/src/nodes/sanitize/init.js +82 -0
- package/src/nodes/sanitize/introspect.js +194 -0
- package/src/nodes/sanitize/publish-to.js +15 -0
- package/src/nodes/sanitize/recompute.js +8 -0
- package/src/nodes/sanitize/reset.js +14 -0
- package/src/nodes/sanitize/update.js +102 -0
- package/src/nodes/spike-guard/index.js +14 -0
- package/src/nodes/spike-guard/init.js +47 -0
- package/src/nodes/spike-guard/introspect.js +130 -0
- package/src/nodes/spike-guard/publish-to.js +35 -0
- package/src/nodes/spike-guard/recompute.js +14 -0
- package/src/nodes/spike-guard/reset.js +19 -0
- package/src/nodes/spike-guard/update.js +89 -0
- package/src/nodes/sse-emitter/index.js +7 -0
- package/src/nodes/sse-emitter/init.js +105 -0
- package/src/nodes/sse-emitter/introspect.js +134 -0
- package/src/nodes/sse-emitter/publish-to.js +6 -0
- package/src/nodes/sse-emitter/recompute.js +16 -0
- package/src/nodes/sse-emitter/reset.js +19 -0
- package/src/nodes/sse-emitter/update.js +69 -0
- package/src/nodes/sse-emitter/utils/broadcast-heartbeat.js +36 -0
- package/src/nodes/sse-emitter/utils/build-message.js +31 -0
- package/src/nodes/sse-emitter/utils/connection-manager.js +45 -0
- package/src/nodes/sse-emitter/utils/endpoint-initializer.js +20 -0
- package/src/nodes/sse-emitter/utils/health-monitor.js +38 -0
- package/src/nodes/sse-emitter/utils/qos-handler.js +41 -0
- package/src/nodes/state-change-detector/helpers.js +35 -0
- package/src/nodes/state-change-detector/index.js +12 -0
- package/src/nodes/state-change-detector/init.js +56 -0
- package/src/nodes/state-change-detector/introspect.js +146 -0
- package/src/nodes/state-change-detector/publish-to.js +20 -0
- package/src/nodes/state-change-detector/recompute.js +6 -0
- package/src/nodes/state-change-detector/reset.js +20 -0
- package/src/nodes/state-change-detector/update.js +97 -0
- package/src/nodes/sw-stats/index.js +14 -0
- package/src/nodes/sw-stats/init.js +51 -0
- package/src/nodes/sw-stats/introspect.js +131 -0
- package/src/nodes/sw-stats/publish-to.js +45 -0
- package/src/nodes/sw-stats/recompute.js +33 -0
- package/src/nodes/sw-stats/reset.js +15 -0
- package/src/nodes/sw-stats/update.js +39 -0
- package/src/nodes/swing-watch/index.js +17 -0
- package/src/nodes/swing-watch/init.js +144 -0
- package/src/nodes/swing-watch/introspect.js +188 -0
- package/src/nodes/swing-watch/publish-to.js +53 -0
- package/src/nodes/swing-watch/recompute.js +22 -0
- package/src/nodes/swing-watch/reset.js +55 -0
- package/src/nodes/swing-watch/update.js +767 -0
- package/src/nodes/tally/index.js +15 -0
- package/src/nodes/tally/init.js +32 -0
- package/src/nodes/tally/introspect.js +116 -0
- package/src/nodes/tally/publish-to.js +28 -0
- package/src/nodes/tally/recompute.js +10 -0
- package/src/nodes/tally/reset.js +10 -0
- package/src/nodes/tally/update.js +44 -0
- package/src/nodes/threshold/index.js +14 -0
- package/src/nodes/threshold/init.js +121 -0
- package/src/nodes/threshold/introspect.js +192 -0
- package/src/nodes/threshold/publish-to.js +11 -0
- package/src/nodes/threshold/recompute.js +8 -0
- package/src/nodes/threshold/reset.js +14 -0
- package/src/nodes/threshold/update.js +54 -0
- package/src/nodes/transform/helpers.js +39 -0
- package/src/nodes/transform/index.js +15 -0
- package/src/nodes/transform/init.js +35 -0
- package/src/nodes/transform/introspect.js +118 -0
- package/src/nodes/transform/publish-to.js +23 -0
- package/src/nodes/transform/recompute.js +12 -0
- package/src/nodes/transform/reset.js +11 -0
- package/src/nodes/transform/update.js +32 -0
- package/src/nodes/trend/compute-confidence.js +112 -0
- package/src/nodes/trend/index.js +14 -0
- package/src/nodes/trend/init.js +81 -0
- package/src/nodes/trend/introspect.js +151 -0
- package/src/nodes/trend/publish-to.js +22 -0
- package/src/nodes/trend/recompute.js +15 -0
- package/src/nodes/trend/reset.js +26 -0
- package/src/nodes/trend/update.js +93 -0
- package/src/nodes/tw-stats/copy-from.js +16 -0
- package/src/nodes/tw-stats/flush.js +12 -0
- package/src/nodes/tw-stats/index.js +41 -0
- package/src/nodes/tw-stats/init.js +92 -0
- package/src/nodes/tw-stats/introspect.js +171 -0
- package/src/nodes/tw-stats/publish-to.js +108 -0
- package/src/nodes/tw-stats/recompute.js +9 -0
- package/src/nodes/tw-stats/reset.js +16 -0
- package/src/nodes/tw-stats/update.js +113 -0
- package/src/nodes/unbalance/index.js +15 -0
- package/src/nodes/unbalance/init.js +59 -0
- package/src/nodes/unbalance/introspect.js +167 -0
- package/src/nodes/unbalance/publish-to.js +52 -0
- package/src/nodes/unbalance/recompute.js +11 -0
- package/src/nodes/unbalance/reset.js +10 -0
- package/src/nodes/unbalance/update.js +83 -0
- package/src/nodes/vector-distance/index.js +14 -0
- package/src/nodes/vector-distance/init.js +54 -0
- package/src/nodes/vector-distance/introspect.js +149 -0
- package/src/nodes/vector-distance/publish-to.js +35 -0
- package/src/nodes/vector-distance/recompute.js +11 -0
- package/src/nodes/vector-distance/reset.js +20 -0
- package/src/nodes/vector-distance/update.js +139 -0
- package/src/nodes/winnow/index.js +12 -0
- package/src/nodes/winnow/init.js +82 -0
- package/src/nodes/winnow/introspect.js +253 -0
- package/src/nodes/winnow/publish-to.js +51 -0
- package/src/nodes/winnow/recompute.js +14 -0
- package/src/nodes/winnow/reset.js +34 -0
- package/src/nodes/winnow/update.js +203 -0
- package/src/tools/training/features.js +227 -0
- package/src/tools/training/index.js +21 -0
- package/src/tools/training/logistic.js +238 -0
- package/src/tools/training/metrics.js +126 -0
- package/src/tools/training/scale.js +239 -0
- package/src/tools/training/validate.js +103 -0
- package/src/windowing/count-sliding/create.js +16 -0
- package/src/windowing/count-sliding/get-reverse-chronological-index.js +19 -0
- package/src/windowing/count-sliding/index.js +6 -0
- package/src/windowing/count-sliding/is-not-full.js +5 -0
- package/src/windowing/count-sliding/push.js +15 -0
- package/src/windowing/count-sliding/reset.js +11 -0
- package/src/windowing/count-sliding/size.js +5 -0
- package/src/windowing/time-sliding/create.js +25 -0
- package/src/windowing/time-sliding/push.js +42 -0
- package/CODE_OF_CONDUCT.md +0 -46
- package/CONTRIBUTING.md +0 -132
- package/docs/.nojekyll +0 -0
- package/docs/CONTRIBUTING.md +0 -134
- package/docs/README.md +0 -132
- package/docs/_coverpage.md +0 -26
- package/docs/_media/bg.png +0 -0
- package/docs/_media/wink-logo.png +0 -0
- package/docs/_navbar.md +0 -14
- package/docs/_sidebar.md +0 -2
- package/docs/index.html +0 -44
- package/eslint.config.js +0 -283
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
// core/semantics/schemas/column-schema.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Column Schema Definition
|
|
5
|
+
*
|
|
6
|
+
* Defines the validation schema for individual columns within an asset class.
|
|
7
|
+
* Columns represent measurements or computed values with full semantic context.
|
|
8
|
+
*
|
|
9
|
+
* Key design decisions:
|
|
10
|
+
* - Three-tier limit hierarchy: physicalRange → operational → specification
|
|
11
|
+
* - Intuitive naming: criticalLow/High, warningLow/High (not hiHi/loLo)
|
|
12
|
+
* - Meaningful defaults: hysteresis=0, interpretation='informational'
|
|
13
|
+
* - Context-dependent limits via `contexts` array
|
|
14
|
+
*
|
|
15
|
+
* Context Resolution Semantics:
|
|
16
|
+
* - Contexts are evaluated in array order (first match wins)
|
|
17
|
+
* - Each context's `when` clause is tested against current column values
|
|
18
|
+
* - At most one `when: 'default'` context is allowed per column
|
|
19
|
+
* - Default context serves as fallback when no other context matches
|
|
20
|
+
* - Recommended ordering: specific conditions first, default last
|
|
21
|
+
*
|
|
22
|
+
* Example context ordering:
|
|
23
|
+
* contexts: [
|
|
24
|
+
* { when: { column: 'state', equals: 2 }, ... }, // Error state
|
|
25
|
+
* { when: { column: 'state', equals: 1 }, ... }, // Running
|
|
26
|
+
* { when: 'default', ... } // Fallback (Idle, etc.)
|
|
27
|
+
* ]
|
|
28
|
+
*
|
|
29
|
+
* Hysteresis Precedence (intended resolution order for consumers):
|
|
30
|
+
* operational.hysteresis → column.hysteresis → COLUMN_DEFAULTS.hysteresis (0)
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { validators } from '../../utils/validate/index.js';
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// CONSTANTS
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Valid data types for columns.
|
|
41
|
+
* @type {string[]}
|
|
42
|
+
*/
|
|
43
|
+
const COLUMN_TYPES = [ 'float64', 'int64', 'string', 'bool', 'timestamp' ];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* LLM-native interpretation array.
|
|
47
|
+
*
|
|
48
|
+
* Column-level `interpretation` is an array of natural language strings
|
|
49
|
+
* providing guidance to LLM consumers about how to interpret values.
|
|
50
|
+
*
|
|
51
|
+
* Recommended prefixes (convention, not validated):
|
|
52
|
+
* Severity: - How to interpret magnitude
|
|
53
|
+
* Threshold: - Key boundaries and meanings
|
|
54
|
+
* Correlate: - Related tables/metrics
|
|
55
|
+
* Trend: - Temporal pattern significance
|
|
56
|
+
* Pattern: - Multi-signal signatures
|
|
57
|
+
* Action: - Recommended response
|
|
58
|
+
* Context: - Domain background
|
|
59
|
+
*
|
|
60
|
+
* Example:
|
|
61
|
+
* interpretation: [
|
|
62
|
+
* "Severity: higher values indicate more severe glitches",
|
|
63
|
+
* "Threshold: > 30 bar indicates communication dropout",
|
|
64
|
+
* "Correlate: with washCycleStats by timestamp"
|
|
65
|
+
* ]
|
|
66
|
+
*
|
|
67
|
+
* @see ADR-001 (interpretation arrays)
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Default values for optional column properties.
|
|
72
|
+
* @type {Object}
|
|
73
|
+
*/
|
|
74
|
+
const COLUMN_DEFAULTS = {
|
|
75
|
+
unit: '',
|
|
76
|
+
resolution: 1,
|
|
77
|
+
description: '',
|
|
78
|
+
interpretation: [],
|
|
79
|
+
hysteresis: 0
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Allowed properties for 'when' clause (object form).
|
|
84
|
+
* Used for unknown property detection in validWhen.
|
|
85
|
+
* Note: 'when' has union type (string | object), so we can't use
|
|
86
|
+
* schema-based propertyNames directly.
|
|
87
|
+
* @type {Set<string>}
|
|
88
|
+
*/
|
|
89
|
+
const WHEN_ALLOWED_KEYS = new Set( [ 'column', 'equals', 'oneOf' ] );
|
|
90
|
+
|
|
91
|
+
// ============================================================================
|
|
92
|
+
// CUSTOM VALIDATORS
|
|
93
|
+
// ============================================================================
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Validates physical range object.
|
|
97
|
+
*
|
|
98
|
+
* @param {Object} range - Physical range with min/max
|
|
99
|
+
* @returns {boolean} True if valid
|
|
100
|
+
*/
|
|
101
|
+
const validPhysicalRange = function ( range ) {
|
|
102
|
+
if ( typeof range !== 'object' || range === null ) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
if ( typeof range.min !== 'number' || typeof range.max !== 'number' ) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
if ( !Number.isFinite( range.min ) || !Number.isFinite( range.max ) ) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
return range.min < range.max;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Validates operational limits object.
|
|
116
|
+
* Limits must be in ascending order: criticalLow ≤ warningLow ≤ target ≤ warningHigh ≤ criticalHigh
|
|
117
|
+
*
|
|
118
|
+
* @param {Object} ops - Operational limits
|
|
119
|
+
* @returns {boolean} True if valid
|
|
120
|
+
*/
|
|
121
|
+
const validOperational = function ( ops ) {
|
|
122
|
+
if ( typeof ops !== 'object' || ops === null ) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Validate individual fields if present
|
|
127
|
+
const numericFields = [ 'criticalLow', 'warningLow', 'target', 'warningHigh', 'criticalHigh' ];
|
|
128
|
+
for ( let i = 0; i < numericFields.length; i += 1 ) {
|
|
129
|
+
const field = numericFields[ i ];
|
|
130
|
+
if ( ops[ field ] !== undefined ) {
|
|
131
|
+
if ( typeof ops[ field ] !== 'number' || !Number.isFinite( ops[ field ] ) ) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Validate hysteresis if present (must be non-negative finite)
|
|
138
|
+
if ( ops.hysteresis !== undefined ) {
|
|
139
|
+
if ( !Number.isFinite( ops.hysteresis ) || ops.hysteresis < 0 ) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Validate ascending order of defined limits
|
|
145
|
+
const limits = [];
|
|
146
|
+
if ( ops.criticalLow !== undefined ) limits.push( ops.criticalLow );
|
|
147
|
+
if ( ops.warningLow !== undefined ) limits.push( ops.warningLow );
|
|
148
|
+
if ( ops.target !== undefined ) limits.push( ops.target );
|
|
149
|
+
if ( ops.warningHigh !== undefined ) limits.push( ops.warningHigh );
|
|
150
|
+
if ( ops.criticalHigh !== undefined ) limits.push( ops.criticalHigh );
|
|
151
|
+
|
|
152
|
+
for ( let i = 1; i < limits.length; i += 1 ) {
|
|
153
|
+
if ( limits[ i ] < limits[ i - 1 ] ) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return true;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Validates specification limits object.
|
|
163
|
+
*
|
|
164
|
+
* @param {Object} spec - Specification limits with lsl/usl/target
|
|
165
|
+
* @returns {boolean} True if valid
|
|
166
|
+
*/
|
|
167
|
+
const validSpecification = function ( spec ) {
|
|
168
|
+
if ( typeof spec !== 'object' || spec === null ) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Validate individual fields if present
|
|
173
|
+
const fields = [ 'lowerSpecLimit', 'upperSpecLimit', 'target' ];
|
|
174
|
+
for ( let i = 0; i < fields.length; i += 1 ) {
|
|
175
|
+
const field = fields[ i ];
|
|
176
|
+
if ( spec[ field ] !== undefined ) {
|
|
177
|
+
if ( typeof spec[ field ] !== 'number' || !Number.isFinite( spec[ field ] ) ) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// lowerSpecLimit must be less than upperSpecLimit
|
|
184
|
+
if ( spec.lowerSpecLimit !== undefined && spec.upperSpecLimit !== undefined ) {
|
|
185
|
+
if ( spec.lowerSpecLimit >= spec.upperSpecLimit ) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// target must be between lowerSpecLimit and upperSpecLimit
|
|
191
|
+
if ( spec.target !== undefined ) {
|
|
192
|
+
if ( spec.lowerSpecLimit !== undefined && spec.target < spec.lowerSpecLimit ) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
if ( spec.upperSpecLimit !== undefined && spec.target > spec.upperSpecLimit ) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return true;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Checks if a value is a JSON primitive (number, string, boolean, null).
|
|
205
|
+
*
|
|
206
|
+
* @param {*} value - Value to check
|
|
207
|
+
* @returns {boolean} True if primitive
|
|
208
|
+
*/
|
|
209
|
+
const isPrimitive = function ( value ) {
|
|
210
|
+
const type = typeof value;
|
|
211
|
+
return value === null || type === 'number' || type === 'string' || type === 'boolean';
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Validates a 'when' clause in a context entry.
|
|
216
|
+
* Supports:
|
|
217
|
+
* - "default" - fallback when no other context matches
|
|
218
|
+
* - { column, equals } - exact value match (any primitive)
|
|
219
|
+
* - { column, oneOf } - value in set (array of primitives)
|
|
220
|
+
* Extensible for future operators (greaterThan, between, etc.)
|
|
221
|
+
*
|
|
222
|
+
* @param {string|Object} when - When clause
|
|
223
|
+
* @returns {boolean} True if valid
|
|
224
|
+
*/
|
|
225
|
+
const validWhen = function ( when ) {
|
|
226
|
+
// "default" string for fallback
|
|
227
|
+
if ( when === 'default' ) {
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Object form with column and operator
|
|
232
|
+
if ( typeof when !== 'object' || when === null ) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Check for unknown properties
|
|
237
|
+
const keys = Object.keys( when );
|
|
238
|
+
for ( let i = 0; i < keys.length; i += 1 ) {
|
|
239
|
+
if ( !WHEN_ALLOWED_KEYS.has( keys[ i ] ) ) {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Must have column name
|
|
245
|
+
if ( typeof when.column !== 'string' || when.column.length === 0 ) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Check operators (mutually exclusive)
|
|
250
|
+
const hasEquals = when.equals !== undefined;
|
|
251
|
+
const hasOneOf = when.oneOf !== undefined;
|
|
252
|
+
|
|
253
|
+
// Exactly one operator must be present (extensible for future operators)
|
|
254
|
+
const operatorCount = ( hasEquals ? 1 : 0 ) + ( hasOneOf ? 1 : 0 );
|
|
255
|
+
if ( operatorCount !== 1 ) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Validate equals: must be a primitive
|
|
260
|
+
if ( hasEquals && !isPrimitive( when.equals ) ) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Validate oneOf: must be non-empty array of primitives
|
|
265
|
+
if ( hasOneOf ) {
|
|
266
|
+
if ( !Array.isArray( when.oneOf ) || when.oneOf.length === 0 ) {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
for ( let i = 0; i < when.oneOf.length; i += 1 ) {
|
|
270
|
+
if ( !isPrimitive( when.oneOf[ i ] ) ) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return true;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Validates column type.
|
|
281
|
+
*
|
|
282
|
+
* @param {string} type - Column type
|
|
283
|
+
* @returns {boolean} True if valid
|
|
284
|
+
*/
|
|
285
|
+
const validColumnType = function ( type ) {
|
|
286
|
+
return COLUMN_TYPES.includes( type );
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Validates interpretation array.
|
|
291
|
+
* Must be an array of non-empty strings.
|
|
292
|
+
*
|
|
293
|
+
* @param {Array} interps - Interpretation array
|
|
294
|
+
* @returns {boolean} True if valid
|
|
295
|
+
*/
|
|
296
|
+
const validInterpretation = function ( interps ) {
|
|
297
|
+
if ( !Array.isArray( interps ) ) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
for ( let i = 0; i < interps.length; i += 1 ) {
|
|
301
|
+
if ( typeof interps[ i ] !== 'string' || interps[ i ].length === 0 ) {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return true;
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Validates a single context entry.
|
|
310
|
+
* Each context must have:
|
|
311
|
+
* - A valid 'when' clause
|
|
312
|
+
* - At least one of 'operational', 'specification', or 'interpretation'
|
|
313
|
+
*
|
|
314
|
+
* Optional context-specific interpretation allows different "what's bad"
|
|
315
|
+
* semantics per operating mode (e.g., pressure during idle vs operation).
|
|
316
|
+
*
|
|
317
|
+
* @param {Object} ctx - Context entry
|
|
318
|
+
* @returns {boolean} True if valid
|
|
319
|
+
*/
|
|
320
|
+
const validContext = function ( ctx ) {
|
|
321
|
+
if ( typeof ctx !== 'object' || ctx === null ) {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Validate 'when' clause
|
|
326
|
+
if ( !validWhen( ctx.when ) ) {
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Check what's present
|
|
331
|
+
const hasOperational = ctx.operational !== undefined;
|
|
332
|
+
const hasSpecification = ctx.specification !== undefined;
|
|
333
|
+
const hasInterpretation = ctx.interpretation !== undefined;
|
|
334
|
+
|
|
335
|
+
// Must have at least one of operational, specification, or interpretation
|
|
336
|
+
if ( !hasOperational && !hasSpecification && !hasInterpretation ) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Validate operational if present
|
|
341
|
+
if ( hasOperational && !validOperational( ctx.operational ) ) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Validate specification if present
|
|
346
|
+
if ( hasSpecification && !validSpecification( ctx.specification ) ) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Validate interpretation if present
|
|
351
|
+
if ( hasInterpretation && !validInterpretation( ctx.interpretation ) ) {
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return true;
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Validates contexts array.
|
|
360
|
+
* Ensures each context is valid and at most one default context exists.
|
|
361
|
+
*
|
|
362
|
+
* @param {Array} contexts - Array of context entries
|
|
363
|
+
* @returns {boolean} True if valid
|
|
364
|
+
*/
|
|
365
|
+
const validContexts = function ( contexts ) {
|
|
366
|
+
if ( !Array.isArray( contexts ) ) {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
let defaultCount = 0;
|
|
371
|
+
for ( let i = 0; i < contexts.length; i += 1 ) {
|
|
372
|
+
if ( !validContext( contexts[ i ] ) ) {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
// Count default contexts
|
|
376
|
+
if ( contexts[ i ].when === 'default' ) {
|
|
377
|
+
defaultCount += 1;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// At most one default context allowed
|
|
382
|
+
if ( defaultCount > 1 ) {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return true;
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// ============================================================================
|
|
390
|
+
// SCHEMA DEFINITION
|
|
391
|
+
// ============================================================================
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Cross-field validator for mutual exclusivity of contexts vs direct limits.
|
|
395
|
+
* Rule: If contexts exists, operational/specification must NOT exist at column level.
|
|
396
|
+
* If operational/specification exists at column level, contexts must NOT exist.
|
|
397
|
+
*
|
|
398
|
+
* @param {Object} column - Column definition
|
|
399
|
+
* @returns {boolean} True if valid
|
|
400
|
+
*/
|
|
401
|
+
const validLimitsMutualExclusivity = function ( column ) {
|
|
402
|
+
const hasContexts = column.contexts !== undefined && column.contexts.length > 0;
|
|
403
|
+
const hasDirectOperational = column.operational !== undefined;
|
|
404
|
+
const hasDirectSpecification = column.specification !== undefined;
|
|
405
|
+
|
|
406
|
+
// Mutual exclusivity: contexts XOR direct limits
|
|
407
|
+
if ( hasContexts && ( hasDirectOperational || hasDirectSpecification ) ) {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return true;
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// Field names for operational and specification limit checks
|
|
415
|
+
const OPS_LIMIT_FIELDS = [ 'criticalLow', 'warningLow', 'target', 'warningHigh', 'criticalHigh' ];
|
|
416
|
+
const SPEC_LIMIT_FIELDS = [ 'lowerSpecLimit', 'target', 'upperSpecLimit' ];
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Checks if all defined fields in object are within [min, max] range.
|
|
420
|
+
*
|
|
421
|
+
* @param {Object} obj - Object containing limit fields
|
|
422
|
+
* @param {string[]} fields - Field names to check
|
|
423
|
+
* @param {number} min - Minimum allowed value
|
|
424
|
+
* @param {number} max - Maximum allowed value
|
|
425
|
+
* @returns {boolean} True if all defined fields are within range
|
|
426
|
+
*/
|
|
427
|
+
const allFieldsWithinRange = function ( obj, fields, min, max ) {
|
|
428
|
+
for ( let i = 0; i < fields.length; i += 1 ) {
|
|
429
|
+
const val = obj[ fields[ i ] ];
|
|
430
|
+
if ( val !== undefined && ( val < min || val > max ) ) {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return true;
|
|
435
|
+
}; // allFieldsWithinRange()
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Checks if specification limits are within operational critical bounds.
|
|
439
|
+
*
|
|
440
|
+
* @param {Object} ops - Operational limits with criticalLow/criticalHigh
|
|
441
|
+
* @param {Object} spec - Specification with lowerSpecLimit/upperSpecLimit
|
|
442
|
+
* @returns {boolean} True if spec is within ops bounds
|
|
443
|
+
*/
|
|
444
|
+
const specWithinOperational = function ( ops, spec ) {
|
|
445
|
+
// lowerSpecLimit must be >= criticalLow (if both defined)
|
|
446
|
+
if ( spec.lowerSpecLimit !== undefined && ops.criticalLow !== undefined ) {
|
|
447
|
+
if ( spec.lowerSpecLimit < ops.criticalLow ) return false;
|
|
448
|
+
}
|
|
449
|
+
// upperSpecLimit must be <= criticalHigh (if both defined)
|
|
450
|
+
if ( spec.upperSpecLimit !== undefined && ops.criticalHigh !== undefined ) {
|
|
451
|
+
if ( spec.upperSpecLimit > ops.criticalHigh ) return false;
|
|
452
|
+
}
|
|
453
|
+
return true;
|
|
454
|
+
}; // specWithinOperational()
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Validates limits hierarchy: physicalRange ⊇ operational ⊇ specification.
|
|
458
|
+
*
|
|
459
|
+
* Rules:
|
|
460
|
+
* 1. If physicalRange exists, operational limits must be within [min, max]
|
|
461
|
+
* 2. If physicalRange exists, specification limits must be within [min, max]
|
|
462
|
+
* 3. If operational + specification both exist (with or without physicalRange):
|
|
463
|
+
* - specification.lsl >= operational.criticalLow (if both defined)
|
|
464
|
+
* - specification.usl <= operational.criticalHigh (if both defined)
|
|
465
|
+
*
|
|
466
|
+
* @param {Object} column - Column definition
|
|
467
|
+
* @returns {boolean} True if hierarchy is valid
|
|
468
|
+
*/
|
|
469
|
+
const validLimitsHierarchy = function ( column ) {
|
|
470
|
+
const range = column.physicalRange;
|
|
471
|
+
const ops = column.operational;
|
|
472
|
+
const spec = column.specification;
|
|
473
|
+
|
|
474
|
+
// Rule 1: Check operational within physicalRange
|
|
475
|
+
if ( range && ops ) {
|
|
476
|
+
if ( !allFieldsWithinRange( ops, OPS_LIMIT_FIELDS, range.min, range.max ) ) {
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Rule 2: Check specification within physicalRange
|
|
482
|
+
if ( range && spec ) {
|
|
483
|
+
if ( !allFieldsWithinRange( spec, SPEC_LIMIT_FIELDS, range.min, range.max ) ) {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Rule 3: Check specification within operational bounds
|
|
489
|
+
if ( ops && spec ) {
|
|
490
|
+
if ( !specWithinOperational( ops, spec ) ) return false;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return true;
|
|
494
|
+
}; // validLimitsHierarchy()
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Validates context limits hierarchy: physicalRange ⊇ ctx.operational ⊇ ctx.specification.
|
|
498
|
+
*
|
|
499
|
+
* Rules (applied to each context):
|
|
500
|
+
* 1. If column has physicalRange, context operational must be within [min, max]
|
|
501
|
+
* 2. If column has physicalRange, context specification must be within [min, max]
|
|
502
|
+
* 3. If context has both operational + specification:
|
|
503
|
+
* - specification.lsl >= operational.criticalLow (if both defined)
|
|
504
|
+
* - specification.usl <= operational.criticalHigh (if both defined)
|
|
505
|
+
*
|
|
506
|
+
* @param {Object} column - Column definition with contexts array
|
|
507
|
+
* @returns {boolean} True if all context hierarchies are valid
|
|
508
|
+
*/
|
|
509
|
+
const validContextLimitsHierarchy = function ( column ) {
|
|
510
|
+
const range = column.physicalRange;
|
|
511
|
+
const contexts = column.contexts;
|
|
512
|
+
|
|
513
|
+
// No contexts or empty contexts = valid
|
|
514
|
+
if ( !contexts || contexts.length === 0 ) return true;
|
|
515
|
+
|
|
516
|
+
for ( let i = 0; i < contexts.length; i += 1 ) {
|
|
517
|
+
const ctx = contexts[ i ];
|
|
518
|
+
const ops = ctx.operational;
|
|
519
|
+
const spec = ctx.specification;
|
|
520
|
+
|
|
521
|
+
// Rule 1: Check context operational within physicalRange
|
|
522
|
+
if ( range && ops ) {
|
|
523
|
+
if ( !allFieldsWithinRange( ops, OPS_LIMIT_FIELDS, range.min, range.max ) ) {
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Rule 2: Check context specification within physicalRange
|
|
529
|
+
if ( range && spec ) {
|
|
530
|
+
if ( !allFieldsWithinRange( spec, SPEC_LIMIT_FIELDS, range.min, range.max ) ) {
|
|
531
|
+
return false;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Rule 3: Check context specification within context operational
|
|
536
|
+
if ( ops && spec ) {
|
|
537
|
+
if ( !specWithinOperational( ops, spec ) ) return false;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return true;
|
|
542
|
+
}; // validContextLimitsHierarchy()
|
|
543
|
+
|
|
544
|
+
/**
|
|
545
|
+
* Schema for individual column definitions.
|
|
546
|
+
*
|
|
547
|
+
* @type {Object}
|
|
548
|
+
*/
|
|
549
|
+
const columnSchema = {
|
|
550
|
+
_propertyNames: [
|
|
551
|
+
'type', 'unit', 'resolution', 'description', 'interpretation',
|
|
552
|
+
'hysteresis', 'enumRef', 'physicalRange', 'operational',
|
|
553
|
+
'specification', 'contexts'
|
|
554
|
+
],
|
|
555
|
+
type: {
|
|
556
|
+
type: 'string',
|
|
557
|
+
required: true,
|
|
558
|
+
validator: validColumnType,
|
|
559
|
+
error: `Column type must be one of: ${COLUMN_TYPES.join( ', ' )}`
|
|
560
|
+
},
|
|
561
|
+
unit: {
|
|
562
|
+
type: 'string',
|
|
563
|
+
required: false,
|
|
564
|
+
default: COLUMN_DEFAULTS.unit
|
|
565
|
+
},
|
|
566
|
+
resolution: {
|
|
567
|
+
type: 'number',
|
|
568
|
+
required: false,
|
|
569
|
+
default: COLUMN_DEFAULTS.resolution,
|
|
570
|
+
validator: validators.positive,
|
|
571
|
+
error: 'Resolution must be a positive number'
|
|
572
|
+
},
|
|
573
|
+
description: {
|
|
574
|
+
type: 'string',
|
|
575
|
+
required: false,
|
|
576
|
+
default: COLUMN_DEFAULTS.description
|
|
577
|
+
},
|
|
578
|
+
interpretation: {
|
|
579
|
+
type: 'array',
|
|
580
|
+
required: false,
|
|
581
|
+
default: COLUMN_DEFAULTS.interpretation,
|
|
582
|
+
validator: validInterpretation,
|
|
583
|
+
error: 'Interpretation must be an array of non-empty strings'
|
|
584
|
+
},
|
|
585
|
+
hysteresis: {
|
|
586
|
+
type: 'number',
|
|
587
|
+
required: false,
|
|
588
|
+
default: COLUMN_DEFAULTS.hysteresis,
|
|
589
|
+
validator: validators.nonNegativeFinite,
|
|
590
|
+
error: 'Hysteresis must be a non-negative finite number'
|
|
591
|
+
},
|
|
592
|
+
enumRef: {
|
|
593
|
+
type: 'string',
|
|
594
|
+
required: false,
|
|
595
|
+
validator: validators.identifier,
|
|
596
|
+
error: 'Enum reference must be a valid identifier'
|
|
597
|
+
},
|
|
598
|
+
physicalRange: {
|
|
599
|
+
type: 'object',
|
|
600
|
+
required: false,
|
|
601
|
+
validator: validPhysicalRange,
|
|
602
|
+
error: 'Physical range must have min < max (both finite numbers)'
|
|
603
|
+
},
|
|
604
|
+
operational: {
|
|
605
|
+
type: 'object',
|
|
606
|
+
required: false,
|
|
607
|
+
validator: validOperational,
|
|
608
|
+
error: 'Operational limits must be in ascending order: criticalLow ≤ warningLow ≤ target ≤ warningHigh ≤ criticalHigh'
|
|
609
|
+
},
|
|
610
|
+
specification: {
|
|
611
|
+
type: 'object',
|
|
612
|
+
required: false,
|
|
613
|
+
validator: validSpecification,
|
|
614
|
+
error: 'Specification must have lowerSpecLimit < upperSpecLimit and target within bounds (if present)'
|
|
615
|
+
},
|
|
616
|
+
contexts: {
|
|
617
|
+
type: 'array',
|
|
618
|
+
required: false,
|
|
619
|
+
default: [],
|
|
620
|
+
itemSchema: {
|
|
621
|
+
type: 'object',
|
|
622
|
+
propertyNames: [ 'when', 'operational', 'specification', 'interpretation' ],
|
|
623
|
+
validator: validContext
|
|
624
|
+
},
|
|
625
|
+
validator: validContexts,
|
|
626
|
+
error: 'Contexts must be an array of valid context entries'
|
|
627
|
+
}
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
// ============================================================================
|
|
631
|
+
// EXPORTS
|
|
632
|
+
// ============================================================================
|
|
633
|
+
|
|
634
|
+
export {
|
|
635
|
+
columnSchema,
|
|
636
|
+
validPhysicalRange,
|
|
637
|
+
validOperational,
|
|
638
|
+
validSpecification,
|
|
639
|
+
validWhen,
|
|
640
|
+
validContext,
|
|
641
|
+
validContexts,
|
|
642
|
+
validColumnType,
|
|
643
|
+
validInterpretation,
|
|
644
|
+
validLimitsMutualExclusivity,
|
|
645
|
+
validLimitsHierarchy,
|
|
646
|
+
validContextLimitsHierarchy,
|
|
647
|
+
COLUMN_TYPES,
|
|
648
|
+
COLUMN_DEFAULTS
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
export default columnSchema;
|