@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,261 @@
|
|
|
1
|
+
// flow/validate.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Flow validation without execution.
|
|
5
|
+
*
|
|
6
|
+
* Validates specs, checks node references, verifies trigger targets,
|
|
7
|
+
* verifies that adapters' declared semantic requirements are met by the
|
|
8
|
+
* flow runtime, and reports any configuration errors. Provides fail-fast
|
|
9
|
+
* validation at transpile/load time before runtime execution.
|
|
10
|
+
*
|
|
11
|
+
* Registered emitters/storages arrive as module maps
|
|
12
|
+
* `{ id: adapterModule }` (they used to be bare ID arrays).
|
|
13
|
+
* The IDs are used for the cross-flow target check; the modules
|
|
14
|
+
* are also used to read each adapter's `semanticsRequirement`
|
|
15
|
+
* declaration so that "persistIf needs an assetClass" is a derived
|
|
16
|
+
* fact (driven by the storage adapter's declaration), not a hardcoded
|
|
17
|
+
* rule baked into validate.js.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { validateTriggers } from './validate-triggers.js';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validates emitter targets in specs against registered emitters.
|
|
24
|
+
* Ensures all emitIf nodes reference emitters that have been registered.
|
|
25
|
+
*
|
|
26
|
+
* @param {Array} specs - Node specifications
|
|
27
|
+
* @param {Object} registeredEmitters - Map `{ id: adapterModule }` of registered emitters
|
|
28
|
+
* @returns {Array<string>} Array of error messages (empty if valid)
|
|
29
|
+
*/
|
|
30
|
+
const validateEmitterTargets = function ( specs, registeredEmitters ) {
|
|
31
|
+
const errors = [];
|
|
32
|
+
const ids = Object.keys( registeredEmitters );
|
|
33
|
+
|
|
34
|
+
for ( let i = 0; i < specs.length; i += 1 ) {
|
|
35
|
+
const spec = specs[ i ];
|
|
36
|
+
if ( spec.nodeType === 'Emit If' && spec.target ) {
|
|
37
|
+
if ( !( spec.target in registeredEmitters ) ) {
|
|
38
|
+
const registeredList = ids.length > 0 ?
|
|
39
|
+
ids.join( ', ' ) :
|
|
40
|
+
'none';
|
|
41
|
+
errors.push(
|
|
42
|
+
`emitIf '${spec.name}' targets '${spec.target}' but only these emitters are registered: [${registeredList}]`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return errors;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Validates storage targets in specs against registered storages.
|
|
53
|
+
* Ensures all persistIf nodes reference storages that have been registered.
|
|
54
|
+
*
|
|
55
|
+
* @param {Array} specs - Node specifications
|
|
56
|
+
* @param {Object} registeredStorages - Map `{ id: adapterModule }` of registered storages
|
|
57
|
+
* @returns {Array<string>} Array of error messages (empty if valid)
|
|
58
|
+
*/
|
|
59
|
+
const validateStorageTargets = function ( specs, registeredStorages ) {
|
|
60
|
+
const errors = [];
|
|
61
|
+
const ids = Object.keys( registeredStorages );
|
|
62
|
+
|
|
63
|
+
for ( let i = 0; i < specs.length; i += 1 ) {
|
|
64
|
+
const spec = specs[ i ];
|
|
65
|
+
if ( spec.nodeType === 'Persist If' && spec.storageName ) {
|
|
66
|
+
if ( !( spec.storageName in registeredStorages ) ) {
|
|
67
|
+
const registeredList = ids.length > 0 ?
|
|
68
|
+
ids.join( ', ' ) :
|
|
69
|
+
'none';
|
|
70
|
+
errors.push(
|
|
71
|
+
`persistIf '${spec.name}' targets '${spec.storageName}' but only these storages are registered: [${registeredList}]`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return errors;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Walks every registered emitter and storage module; for each adapter
|
|
82
|
+
* that declares `semanticsRequirement.assetClass.required: true`, errors
|
|
83
|
+
* if `assetClass` is null/undefined.
|
|
84
|
+
*
|
|
85
|
+
* Replaces the old hardcoded "persistIf requires .assetClass()" rule.
|
|
86
|
+
* The requirement now lives where it semantically belongs — on the
|
|
87
|
+
* adapter that actually reads the asset class (e.g., QuestDB declares
|
|
88
|
+
* required:true; a future storage that doesn't read semantics declares
|
|
89
|
+
* required:false or no declaration at all).
|
|
90
|
+
*
|
|
91
|
+
* One error per missing-required adapter, naming the adapter and its
|
|
92
|
+
* kind (storage/emitter) so the operator knows what to fix.
|
|
93
|
+
*
|
|
94
|
+
* @param {Object} registeredEmitters - Map `{ id: adapterModule }`
|
|
95
|
+
* @param {Object} registeredStorages - Map `{ id: adapterModule }`
|
|
96
|
+
* @param {Object|null} assetClass - Asset class from runtime, or null
|
|
97
|
+
* @returns {Array<string>} Array of error messages (empty if valid)
|
|
98
|
+
*/
|
|
99
|
+
const validateSemanticsRequirements = function ( registeredEmitters, registeredStorages, assetClass ) {
|
|
100
|
+
if ( assetClass ) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const errors = [];
|
|
105
|
+
|
|
106
|
+
const checkOne = function ( id, module, kind ) {
|
|
107
|
+
const requirement = module && module.semanticsRequirement;
|
|
108
|
+
if ( requirement && requirement.assetClass && requirement.assetClass.required ) {
|
|
109
|
+
errors.push(
|
|
110
|
+
`${kind} '${id}' declares semanticsRequirement.assetClass.required ` +
|
|
111
|
+
'but the flow has no .assetClass() — add .assetClass(assetClassDef) before declaring this adapter'
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const emitterEntries = Object.entries( registeredEmitters );
|
|
117
|
+
for ( let i = 0; i < emitterEntries.length; i += 1 ) {
|
|
118
|
+
const [ id, module ] = emitterEntries[ i ];
|
|
119
|
+
checkOne( id, module, 'emitter' );
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const storageEntries = Object.entries( registeredStorages );
|
|
123
|
+
for ( let i = 0; i < storageEntries.length; i += 1 ) {
|
|
124
|
+
const [ id, module ] = storageEntries[ i ];
|
|
125
|
+
checkOne( id, module, 'storage' );
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return errors;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Validates insightType references in persistIf specs against asset class.
|
|
133
|
+
*
|
|
134
|
+
* Each persistIf insightType must exist in the asset class's insightTypes.
|
|
135
|
+
* The old blanket "persistIf requires .assetClass()" check moved to
|
|
136
|
+
* `validateSemanticsRequirements` (capability-driven). When `assetClass`
|
|
137
|
+
* is null here, that earlier check has already produced its error;
|
|
138
|
+
* this function silently skips the cross-ref to avoid duplicate noise.
|
|
139
|
+
*
|
|
140
|
+
* @param {Array} specs - Node specifications
|
|
141
|
+
* @param {Object|null} assetClass - Asset class from runtime (null if not declared)
|
|
142
|
+
* @returns {Array<string>} Array of error messages (empty if valid)
|
|
143
|
+
*/
|
|
144
|
+
const validateInsightTypeReferences = function ( specs, assetClass ) {
|
|
145
|
+
const errors = [];
|
|
146
|
+
|
|
147
|
+
if ( !assetClass ) {
|
|
148
|
+
// Either the flow doesn't need an asset class (no adapter declared
|
|
149
|
+
// `assetClass.required: true` — see validateSemanticsRequirements),
|
|
150
|
+
// or it does and that earlier check already reported the missing
|
|
151
|
+
// .assetClass(). Either way, no useful cross-ref work to do here.
|
|
152
|
+
return errors;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const persistIfNodes = [];
|
|
156
|
+
for ( let i = 0; i < specs.length; i += 1 ) {
|
|
157
|
+
const spec = specs[ i ];
|
|
158
|
+
if ( spec.nodeType === 'Persist If' && spec.insightType ) {
|
|
159
|
+
persistIfNodes.push( spec );
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if ( persistIfNodes.length === 0 ) {
|
|
164
|
+
return errors;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const validInsightTypes = Object.keys( assetClass.insightTypes || {} );
|
|
168
|
+
for ( let i = 0; i < persistIfNodes.length; i += 1 ) {
|
|
169
|
+
const spec = persistIfNodes[ i ];
|
|
170
|
+
const insightType = spec.insightType;
|
|
171
|
+
|
|
172
|
+
if ( !validInsightTypes.includes( insightType ) ) {
|
|
173
|
+
const validList = validInsightTypes.length > 0 ?
|
|
174
|
+
validInsightTypes.join( ', ' ) :
|
|
175
|
+
'none defined';
|
|
176
|
+
errors.push(
|
|
177
|
+
`persistIf '${spec.name}': insightType '${insightType}' not found in ` +
|
|
178
|
+
`asset class '${assetClass.name}' (valid: ${validList})`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return errors;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Validates the flow without executing.
|
|
188
|
+
*
|
|
189
|
+
* `registeredEmitters` / `registeredStorages` are `{ id: adapterModule }`
|
|
190
|
+
* maps (they used to be bare ID arrays; call sites that pass arrays
|
|
191
|
+
* must be updated). Tests that exercise validateFlow directly pass
|
|
192
|
+
* module maps. The IDs are used for cross-flow target validation; the
|
|
193
|
+
* modules are used for capability-driven `semanticsRequirement`
|
|
194
|
+
* checks.
|
|
195
|
+
*
|
|
196
|
+
* @param {string} flowName - Name of the flow
|
|
197
|
+
* @param {Array} specs - Node specifications
|
|
198
|
+
* @param {Object} nodeModules - Map of module name to node module
|
|
199
|
+
* @param {Object} [registeredEmitters={}] - Map `{ id: module }` of registered emitters
|
|
200
|
+
* @param {Object} [registeredStorages={}] - Map `{ id: module }` of registered storages
|
|
201
|
+
* @param {Object|null} [assetClass=null] - Asset class for capability + insightType validation
|
|
202
|
+
* @returns {{valid: boolean, errors: Array<string>}} Validation result
|
|
203
|
+
*/
|
|
204
|
+
export const validateFlow = function ( flowName, specs, nodeModules, registeredEmitters = {}, registeredStorages = {}, assetClass = null ) {
|
|
205
|
+
const errors = [];
|
|
206
|
+
|
|
207
|
+
// Phase 1: Trigger validation (R1, R2, R3)
|
|
208
|
+
const triggerResult = validateTriggers( specs, nodeModules );
|
|
209
|
+
if ( !triggerResult.valid ) {
|
|
210
|
+
errors.push( ...triggerResult.errors );
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Phase 2: Emitter target validation
|
|
214
|
+
const emitterErrors = validateEmitterTargets( specs, registeredEmitters );
|
|
215
|
+
errors.push( ...emitterErrors );
|
|
216
|
+
|
|
217
|
+
// Phase 3: Storage target validation
|
|
218
|
+
const storageErrors = validateStorageTargets( specs, registeredStorages );
|
|
219
|
+
errors.push( ...storageErrors );
|
|
220
|
+
|
|
221
|
+
// Phase 4: Capability-driven semanticsRequirement check
|
|
222
|
+
// (replaced the hardcoded "persistIf requires .assetClass()" rule)
|
|
223
|
+
const semanticsErrors = validateSemanticsRequirements(
|
|
224
|
+
registeredEmitters,
|
|
225
|
+
registeredStorages,
|
|
226
|
+
assetClass
|
|
227
|
+
);
|
|
228
|
+
errors.push( ...semanticsErrors );
|
|
229
|
+
|
|
230
|
+
// Phase 5: insightType validation against asset class
|
|
231
|
+
const insightTypeErrors = validateInsightTypeReferences( specs, assetClass );
|
|
232
|
+
errors.push( ...insightTypeErrors );
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
valid: errors.length === 0,
|
|
236
|
+
errors
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Validates flow and throws if invalid.
|
|
242
|
+
* Convenience wrapper for fail-fast validation in pipelines.
|
|
243
|
+
*
|
|
244
|
+
* @param {string} flowName - Name of the flow
|
|
245
|
+
* @param {Array} specs - Node specifications
|
|
246
|
+
* @param {Object} nodeModules - Map of module name to node module
|
|
247
|
+
* @param {Object} [registeredEmitters={}] - Map `{ id: module }` of registered emitters
|
|
248
|
+
* @param {Object} [registeredStorages={}] - Map `{ id: module }` of registered storages
|
|
249
|
+
* @param {Object|null} [assetClass=null] - Asset class for capability + insightType validation
|
|
250
|
+
* @throws {Error} If validation fails
|
|
251
|
+
*/
|
|
252
|
+
export const validateFlowOrThrow = function ( flowName, specs, nodeModules, registeredEmitters = {}, registeredStorages = {}, assetClass = null ) {
|
|
253
|
+
const result = validateFlow( flowName, specs, nodeModules, registeredEmitters, registeredStorages, assetClass );
|
|
254
|
+
if ( !result.valid ) {
|
|
255
|
+
const errorList = result.errors.map( ( e ) => ` - ${e}` ).join( '\n' );
|
|
256
|
+
throw new Error(
|
|
257
|
+
`Flow '${flowName}' validation failed:\n${errorList}`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// nodes/accumulate/index.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Accumulate node module exports.
|
|
5
|
+
*
|
|
6
|
+
* Simple running sum accumulator for conditional accumulation.
|
|
7
|
+
* Works with controller disable/enable — no embedded predicate needed.
|
|
8
|
+
*
|
|
9
|
+
* @see ADR-004
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export { default as init } from './init.js';
|
|
13
|
+
export { default as update } from './update.js';
|
|
14
|
+
export { default as reset } from './reset.js';
|
|
15
|
+
export { default as recompute } from './recompute.js';
|
|
16
|
+
export { default as publishTo } from './publish-to.js';
|
|
17
|
+
export { default as disable } from '../../core/utils/node/disable.js';
|
|
18
|
+
export { default as enable } from '../../core/utils/node/enable.js';
|
|
19
|
+
export { default as pause } from '../../core/utils/node/pause.js';
|
|
20
|
+
export { default as unpause } from '../../core/utils/node/unpause.js';
|
|
21
|
+
export * from './introspect.js';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// nodes/accumulate/init.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Initializes the accumulate node state.
|
|
5
|
+
*
|
|
6
|
+
* Creates state object with running sum initialized to zero.
|
|
7
|
+
* No ring buffer needed — simple accumulation with disable/enable support.
|
|
8
|
+
*
|
|
9
|
+
* @see ADR-004
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { validateSpec } from '../../core/utils/node/index.js';
|
|
13
|
+
import * as introspect from './introspect.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Initializes the accumulate node state from a validated spec.
|
|
17
|
+
*
|
|
18
|
+
* @param {Object} spec - Node specification
|
|
19
|
+
* @param {string} spec.name - Unique node identifier
|
|
20
|
+
* @param {Object} spec.from - Input field configuration
|
|
21
|
+
* @param {string} spec.from.x - Input field name for values to accumulate
|
|
22
|
+
* @param {Object} spec.stats - Output statistics configuration
|
|
23
|
+
* @returns {Object} Initialized state object
|
|
24
|
+
*/
|
|
25
|
+
const init = function ( spec ) {
|
|
26
|
+
validateSpec( spec, introspect );
|
|
27
|
+
|
|
28
|
+
const state = Object.create( null );
|
|
29
|
+
|
|
30
|
+
// ── Standard Flags ─────────────────────────────────────────────────────
|
|
31
|
+
state.inputValidationFailed = false;
|
|
32
|
+
state.disable = false;
|
|
33
|
+
state.pause = false;
|
|
34
|
+
|
|
35
|
+
// ── Configuration from Spec ────────────────────────────────────────────
|
|
36
|
+
state.x = spec.from.x;
|
|
37
|
+
state.stats = spec.stats;
|
|
38
|
+
|
|
39
|
+
// ── Accumulated Value ──────────────────────────────────────────────────
|
|
40
|
+
state.sum = 0;
|
|
41
|
+
|
|
42
|
+
// ── Metadata ───────────────────────────────────────────────────────────
|
|
43
|
+
state.nodeType = introspect.getNodeType();
|
|
44
|
+
|
|
45
|
+
return state;
|
|
46
|
+
}; // init()
|
|
47
|
+
|
|
48
|
+
export default init;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// nodes/accumulate/introspect.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Introspection metadata for the accumulate node.
|
|
5
|
+
*
|
|
6
|
+
* Defines supported stats, control methods, capabilities, and DSL schema
|
|
7
|
+
* for a simple running sum accumulator. Works with controller disable/enable
|
|
8
|
+
* for conditional accumulation without embedded predicate.
|
|
9
|
+
*
|
|
10
|
+
* @see ADR-004
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { validators } from '../../core/utils/validate/index.js';
|
|
14
|
+
|
|
15
|
+
// ── Supported Statistics ────────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
const SUPPORTED_STATS = [ 'sum' ];
|
|
18
|
+
|
|
19
|
+
const STAT_DESCRIPTIONS = {
|
|
20
|
+
sum: 'Running sum of input values'
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// ── Control Methods ─────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
const SUPPORTED_CONTROL_METHODS = {
|
|
26
|
+
reset: 'Clears accumulated sum to zero',
|
|
27
|
+
enable: 'Enables node processing',
|
|
28
|
+
disable: 'Disables node processing',
|
|
29
|
+
pause: 'Pauses node processing while keeping state visible',
|
|
30
|
+
unpause: 'Resumes node processing after pause'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// ── Node Identity ───────────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
const NODE_TYPE = 'Accumulate';
|
|
36
|
+
|
|
37
|
+
// ── Capabilities ────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
const CAPABILITIES = {
|
|
40
|
+
description: 'Accumulates numeric values into a running sum',
|
|
41
|
+
features: [
|
|
42
|
+
'Simple running sum (no windowing)',
|
|
43
|
+
'Works with controller disable/enable for conditional accumulation',
|
|
44
|
+
'Expects periodic resets — unbounded sum drifts without them',
|
|
45
|
+
'No ring buffer — no catch-up problem when disabled',
|
|
46
|
+
'Zero allocation in hot path'
|
|
47
|
+
]
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// ── Default Options ─────────────────────────────────────────────────────────
|
|
51
|
+
|
|
52
|
+
const DEFAULT_OPTIONS = {};
|
|
53
|
+
|
|
54
|
+
// ── DSL Metadata ────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
const DSL_METADATA = {
|
|
57
|
+
specSchema: {
|
|
58
|
+
nodeType: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
required: true,
|
|
61
|
+
value: NODE_TYPE
|
|
62
|
+
},
|
|
63
|
+
name: {
|
|
64
|
+
type: 'string',
|
|
65
|
+
required: true,
|
|
66
|
+
validator: validators.identifier,
|
|
67
|
+
error: 'name must be a valid identifier'
|
|
68
|
+
},
|
|
69
|
+
from: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
required: true,
|
|
72
|
+
properties: {
|
|
73
|
+
x: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
required: true,
|
|
76
|
+
validator: validators.noSpaces,
|
|
77
|
+
error: 'from.x must not contain spaces'
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
stats: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
required: true,
|
|
84
|
+
minProperties: 1,
|
|
85
|
+
propertyNames: SUPPORTED_STATS,
|
|
86
|
+
propertySchema: {
|
|
87
|
+
type: 'object',
|
|
88
|
+
required: true,
|
|
89
|
+
properties: {
|
|
90
|
+
storeAs: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
required: true,
|
|
93
|
+
validator: validators.identifier,
|
|
94
|
+
error: 'storeAs must be a valid identifier'
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
crossFieldValidators: [],
|
|
102
|
+
|
|
103
|
+
buildSpec: ( name, x, stats, options ) => ( {
|
|
104
|
+
nodeType: NODE_TYPE,
|
|
105
|
+
name,
|
|
106
|
+
from: { x },
|
|
107
|
+
stats,
|
|
108
|
+
...options
|
|
109
|
+
} )
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// ── Getter Functions (defensive copies) ─────────────────────────────────────
|
|
113
|
+
|
|
114
|
+
export const getSupportedStats = () => SUPPORTED_STATS.slice();
|
|
115
|
+
export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
|
|
116
|
+
export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
|
|
117
|
+
export const getNodeType = () => NODE_TYPE;
|
|
118
|
+
export const getCapabilities = () => ( {
|
|
119
|
+
...CAPABILITIES,
|
|
120
|
+
features: CAPABILITIES.features.slice()
|
|
121
|
+
} );
|
|
122
|
+
export { DEFAULT_OPTIONS };
|
|
123
|
+
export const getDSLMetadata = () => ( { ...DSL_METADATA } );
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// nodes/accumulate/publish-to.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Publishes accumulated sum to output message.
|
|
5
|
+
*
|
|
6
|
+
* Copies state.sum to the configured output field. On validation failure,
|
|
7
|
+
* publishes NaN for fault isolation downstream.
|
|
8
|
+
*
|
|
9
|
+
* @see ADR-004
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { publishNaN } from '../../core/utils/node/index.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Publishes the accumulated sum to the output message.
|
|
16
|
+
*
|
|
17
|
+
* @param {Object} state - Node state
|
|
18
|
+
* @param {Object} msg - Output message to populate
|
|
19
|
+
*/
|
|
20
|
+
const publishTo = function ( state, msg ) {
|
|
21
|
+
// Guard: skip if disabled
|
|
22
|
+
if ( state.disable ) return;
|
|
23
|
+
|
|
24
|
+
// Fault isolation: propagate NaN if input validation failed
|
|
25
|
+
if ( state.inputValidationFailed ) {
|
|
26
|
+
publishNaN( state, msg );
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Publish sum
|
|
31
|
+
msg[ state.stats.sum.storeAs ] = state.sum;
|
|
32
|
+
}; // publishTo()
|
|
33
|
+
|
|
34
|
+
export default publishTo;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// nodes/accumulate/recompute.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Numerical stability handler for accumulate node.
|
|
5
|
+
*
|
|
6
|
+
* Running sum is numerically stable for bounded accumulation windows —
|
|
7
|
+
* controller resets prevent unbounded drift. Without resets, IEEE 754
|
|
8
|
+
* rounding error grows with the number of additions, and precision
|
|
9
|
+
* degrades when magnitudes vary widely. No recomputation is possible
|
|
10
|
+
* here (no ring buffer to re-sum from), so timely controller resets
|
|
11
|
+
* are essential.
|
|
12
|
+
*
|
|
13
|
+
* @see ADR-004
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Handles numerical stability (no-op — no history buffer to recompute from).
|
|
18
|
+
*
|
|
19
|
+
* @returns {boolean} Always returns true
|
|
20
|
+
*/
|
|
21
|
+
const recompute = function () {
|
|
22
|
+
// No-op: controller resets bound the accumulation window.
|
|
23
|
+
// Without resets, sum drifts — but there is no ring buffer to re-sum from.
|
|
24
|
+
return true;
|
|
25
|
+
}; // recompute()
|
|
26
|
+
|
|
27
|
+
export default recompute;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// nodes/accumulate/reset.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Resets the accumulate node state.
|
|
5
|
+
*
|
|
6
|
+
* Clears accumulated sum to zero. Called by controller triggers
|
|
7
|
+
* to start a new accumulation window.
|
|
8
|
+
*
|
|
9
|
+
* @see ADR-004
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Resets the accumulated sum to zero.
|
|
14
|
+
*
|
|
15
|
+
* @param {Object} state - Node state to reset
|
|
16
|
+
* @returns {boolean} Always returns true (success)
|
|
17
|
+
*/
|
|
18
|
+
const reset = function ( state ) {
|
|
19
|
+
// Reset accumulated sum to zero
|
|
20
|
+
state.sum = 0;
|
|
21
|
+
|
|
22
|
+
return true;
|
|
23
|
+
}; // reset()
|
|
24
|
+
|
|
25
|
+
export default reset;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// nodes/accumulate/update.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Hot path for accumulate node message processing.
|
|
5
|
+
*
|
|
6
|
+
* Simple running sum with zero allocation. When disabled, skips update
|
|
7
|
+
* entirely — sum remains unchanged. No ring buffer, so no catch-up problem
|
|
8
|
+
* when re-enabled after disabled period.
|
|
9
|
+
*
|
|
10
|
+
* @see ADR-004
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Processes a message and accumulates the input value.
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} state - Node state from init()
|
|
17
|
+
* @param {Object} msg - Incoming message with field values
|
|
18
|
+
* @returns {Object} Updated state
|
|
19
|
+
*/
|
|
20
|
+
const update = function ( state, msg ) {
|
|
21
|
+
// Guard: skip if disabled or paused
|
|
22
|
+
if ( state.disable || state.pause ) return state;
|
|
23
|
+
|
|
24
|
+
// Extract input value
|
|
25
|
+
const xVal = msg[ state.x ];
|
|
26
|
+
|
|
27
|
+
// Reset health flag
|
|
28
|
+
state.inputValidationFailed = false;
|
|
29
|
+
|
|
30
|
+
// Validate input (catches NaN, Infinity, undefined)
|
|
31
|
+
if ( !Number.isFinite( xVal ) ) {
|
|
32
|
+
state.inputValidationFailed = true;
|
|
33
|
+
return state;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Accumulate
|
|
37
|
+
state.sum += xVal;
|
|
38
|
+
|
|
39
|
+
return state;
|
|
40
|
+
}; // update()
|
|
41
|
+
|
|
42
|
+
export default update;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// nodes/appraise/calibrate.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Burn-in calibration for the L2 decision neuron's Theta parameter.
|
|
5
|
+
*
|
|
6
|
+
* During warmup, the system observes baseline membrane activity and derives
|
|
7
|
+
* Theta such that steady-state conviction sits at c_target (monitor.at / 3).
|
|
8
|
+
* Uses a deterministic sample count — same pattern as esCorrelation and trend
|
|
9
|
+
* warmup (halfLifeToWarmupSamples equivalent).
|
|
10
|
+
*
|
|
11
|
+
* Formula: Theta = V2 * ( 1 - c_target ) / c_target
|
|
12
|
+
* When V2 = 0 at warmup end, Theta defaults to 1.0 (conservative fallback).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Computes the number of warmup messages needed for calibration.
|
|
17
|
+
* Five L2 time constants ensures the membrane has reached steady-state
|
|
18
|
+
* (~99.3% settled).
|
|
19
|
+
*
|
|
20
|
+
* @param {number} l2Tau - L2 time constant tau2
|
|
21
|
+
* @param {number} messageRate - Messages per timestamp unit
|
|
22
|
+
* @returns {number} Warmup sample count (integer >= 1)
|
|
23
|
+
*/
|
|
24
|
+
const computeWarmupSamples = function ( l2Tau, messageRate ) {
|
|
25
|
+
return Math.max( 1, Math.ceil( 5 * l2Tau * messageRate ) );
|
|
26
|
+
}; // computeWarmupSamples()
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Derives the calibration target conviction from the monitor threshold.
|
|
30
|
+
* Steady-state baseline should sit at one-third of the monitor threshold —
|
|
31
|
+
* close enough for sensitivity, far enough to avoid false triggers.
|
|
32
|
+
*
|
|
33
|
+
* @param {number} monitorAt - Monitor threshold value
|
|
34
|
+
* @returns {number} c_target in (0, 1)
|
|
35
|
+
*/
|
|
36
|
+
const deriveCTarget = function ( monitorAt ) {
|
|
37
|
+
return monitorAt / 3;
|
|
38
|
+
}; // deriveCTarget()
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Checks whether calibration is complete and derives Theta if so.
|
|
42
|
+
* Called once per message during the warmup phase. No-op before
|
|
43
|
+
* the warmup boundary, no-op after calibration is complete.
|
|
44
|
+
*
|
|
45
|
+
* @param {Object} state - Node state (mutated: l2Theta, calibrating)
|
|
46
|
+
*/
|
|
47
|
+
const checkCalibration = function ( state ) {
|
|
48
|
+
if ( state.messageCount < state.warmupSamples ) return;
|
|
49
|
+
|
|
50
|
+
// Derive Theta from observed steady-state membrane potential
|
|
51
|
+
const v2 = state.l2Membrane;
|
|
52
|
+
|
|
53
|
+
if ( v2 <= 0 ) {
|
|
54
|
+
// No activity during warmup — use conservative default
|
|
55
|
+
state.l2Theta = 1.0;
|
|
56
|
+
} else {
|
|
57
|
+
// Theta = V2 * ( 1 - c_target ) / c_target
|
|
58
|
+
state.l2Theta = v2 * ( ( 1 - state.cTarget ) / state.cTarget );
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
state.calibrating = false;
|
|
62
|
+
}; // checkCalibration()
|
|
63
|
+
|
|
64
|
+
export { computeWarmupSamples, deriveCTarget, checkCalibration };
|