@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,144 @@
|
|
|
1
|
+
// @fileoverview
|
|
2
|
+
// init.js — pre-allocates all state for the swingWatch node.
|
|
3
|
+
//
|
|
4
|
+
// Every typed array, ring buffer, and accumulator is allocated here and never
|
|
5
|
+
// again during the hot path (update / publishTo). Total memory per instance
|
|
6
|
+
// at W=100 is ~7.9 KB — fits comfortably in L1 cache.
|
|
7
|
+
|
|
8
|
+
import { validateSpec } from '../../core/utils/node/index.js';
|
|
9
|
+
import * as introspect from './introspect.js';
|
|
10
|
+
import { create } from '../../windowing/count-sliding/index.js';
|
|
11
|
+
import { resolveScalar } from '../../core/utils/options/resolve-field-keyed.js';
|
|
12
|
+
import { asTunable } from '../../core/tunable/index.js';
|
|
13
|
+
|
|
14
|
+
const init = function ( spec ) {
|
|
15
|
+
validateSpec( spec, introspect );
|
|
16
|
+
|
|
17
|
+
const state = Object.create( null );
|
|
18
|
+
|
|
19
|
+
// ── Standard flags ───────────────────────────────────────
|
|
20
|
+
state.inputValidationFailed = false;
|
|
21
|
+
state.disable = false;
|
|
22
|
+
state.pause = false;
|
|
23
|
+
|
|
24
|
+
// ── Configuration from spec ──────────────────────────────
|
|
25
|
+
state.x = spec.from.x;
|
|
26
|
+
state.stats = Object.assign( Object.create( null ), spec.stats );
|
|
27
|
+
state.direction = spec.direction ?? introspect.DEFAULT_OPTIONS.direction;
|
|
28
|
+
state.minAbsoluteThreshold = spec.minAbsoluteThreshold ?? introspect.DEFAULT_OPTIONS.minAbsoluteThreshold;
|
|
29
|
+
|
|
30
|
+
// ── Window size (field-keyed support) ─────────────────────
|
|
31
|
+
const windowSizeSpec = resolveScalar( spec.windowSize, state.x );
|
|
32
|
+
const W = windowSizeSpec ?? introspect.DEFAULT_OPTIONS.windowSize;
|
|
33
|
+
state.windowSize = W;
|
|
34
|
+
|
|
35
|
+
// ── Ring buffer (reuse composer's count-sliding module) ──
|
|
36
|
+
state.ring = create( W );
|
|
37
|
+
|
|
38
|
+
// ── Threshold tunable ────────────────────────────────────
|
|
39
|
+
state.thresholdFn = asTunable( spec.threshold );
|
|
40
|
+
state.currentThreshold = 0;
|
|
41
|
+
state.tunableErrorLogged = false;
|
|
42
|
+
|
|
43
|
+
// ── Pre-allocated typed arrays (zero allocation in hot path) ─
|
|
44
|
+
|
|
45
|
+
// Linearized copy of ring buffer (contiguous for sort)
|
|
46
|
+
state.linear = new Float64Array( W );
|
|
47
|
+
|
|
48
|
+
// Sort workspace: indices [0..W-1] sorted by linear[i]
|
|
49
|
+
state.sortedIndices = new Int32Array( W );
|
|
50
|
+
|
|
51
|
+
// Pre-built comparator — avoids per-tick closure allocation at the
|
|
52
|
+
// .sort() call site. Captures state.linear by reference; its contents
|
|
53
|
+
// are overwritten in place each tick but the binding is stable.
|
|
54
|
+
state.compareIndices = ( a, b ) => {
|
|
55
|
+
const d = state.linear[ a ] - state.linear[ b ];
|
|
56
|
+
if ( d !== 0 ) return d;
|
|
57
|
+
return a - b;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Union-find arrays (reused for both min and max sweeps)
|
|
61
|
+
state.ufParent = new Int32Array( W );
|
|
62
|
+
state.ufBirthVal = new Float64Array( W );
|
|
63
|
+
state.ufBirthIdx = new Int32Array( W );
|
|
64
|
+
|
|
65
|
+
// Processed flags for sweep (cleared between min/max sweeps)
|
|
66
|
+
state.processed = new Uint8Array( W );
|
|
67
|
+
|
|
68
|
+
// Accounted-emission flags, one byte per ring slot per direction
|
|
69
|
+
// (exactly-once rule c in update.js Section 3). A set byte means the
|
|
70
|
+
// sample in that slot has already driven — or been recognized as a
|
|
71
|
+
// duplicate of — a completion emission. Cleared per-slot on overwrite.
|
|
72
|
+
state.minEmitFlag = new Uint8Array( W );
|
|
73
|
+
state.maxEmitFlag = new Uint8Array( W );
|
|
74
|
+
|
|
75
|
+
// Pair storage — parallel typed arrays, max pairs = floor(W/2)
|
|
76
|
+
const maxPairs = Math.floor( W / 2 );
|
|
77
|
+
state.maxPairs = maxPairs;
|
|
78
|
+
|
|
79
|
+
// Current tick's min pairs
|
|
80
|
+
state.minBirthValArr = new Float64Array( maxPairs );
|
|
81
|
+
state.minBirthIdxArr = new Int32Array( maxPairs );
|
|
82
|
+
state.minDeathValArr = new Float64Array( maxPairs );
|
|
83
|
+
state.minDeathIdxArr = new Int32Array( maxPairs );
|
|
84
|
+
state.minPersArr = new Float64Array( maxPairs );
|
|
85
|
+
state.minPairCount = 0;
|
|
86
|
+
|
|
87
|
+
// Current tick's max pairs
|
|
88
|
+
state.maxBirthValArr = new Float64Array( maxPairs );
|
|
89
|
+
state.maxBirthIdxArr = new Int32Array( maxPairs );
|
|
90
|
+
state.maxDeathValArr = new Float64Array( maxPairs );
|
|
91
|
+
state.maxDeathIdxArr = new Int32Array( maxPairs );
|
|
92
|
+
state.maxPersArr = new Float64Array( maxPairs );
|
|
93
|
+
state.maxPairCount = 0;
|
|
94
|
+
|
|
95
|
+
// Previous tick's pairs (for diffing — only need indices to compare)
|
|
96
|
+
state.prevMinBirthIdx = new Int32Array( maxPairs );
|
|
97
|
+
state.prevMinDeathIdx = new Int32Array( maxPairs );
|
|
98
|
+
state.prevMinPairCount = 0;
|
|
99
|
+
|
|
100
|
+
state.prevMaxBirthIdx = new Int32Array( maxPairs );
|
|
101
|
+
state.prevMaxDeathIdx = new Int32Array( maxPairs );
|
|
102
|
+
state.prevMaxPairCount = 0;
|
|
103
|
+
|
|
104
|
+
// ── Completion event slots (Mode A) ──────────────────────
|
|
105
|
+
state.dipCompleted = false;
|
|
106
|
+
state.dipValue = NaN;
|
|
107
|
+
state.dipLag = 0;
|
|
108
|
+
state.dipSize = NaN;
|
|
109
|
+
|
|
110
|
+
state.peakCompleted = false;
|
|
111
|
+
state.peakValue = NaN;
|
|
112
|
+
state.peakLag = 0;
|
|
113
|
+
state.peakSize = NaN;
|
|
114
|
+
|
|
115
|
+
// ── Pre-built field-key maps (zero string-concat in diff hot path) ──
|
|
116
|
+
// diffOneSide writes to state[ keys.completed ] etc. using these
|
|
117
|
+
// pre-built strings instead of runtime concatenation. The min/max keys
|
|
118
|
+
// name the sweep side (signal minima/maxima); the values are the
|
|
119
|
+
// published dip/peak stat fields those sides feed.
|
|
120
|
+
state.fieldKeys = Object.create( null );
|
|
121
|
+
state.fieldKeys.min = Object.create( null );
|
|
122
|
+
state.fieldKeys.min.completed = 'dipCompleted';
|
|
123
|
+
state.fieldKeys.min.birthValue = 'dipValue';
|
|
124
|
+
state.fieldKeys.min.birthLag = 'dipLag';
|
|
125
|
+
state.fieldKeys.min.persistence = 'dipSize';
|
|
126
|
+
state.fieldKeys.max = Object.create( null );
|
|
127
|
+
state.fieldKeys.max.completed = 'peakCompleted';
|
|
128
|
+
state.fieldKeys.max.birthValue = 'peakValue';
|
|
129
|
+
state.fieldKeys.max.birthLag = 'peakLag';
|
|
130
|
+
state.fieldKeys.max.persistence = 'peakSize';
|
|
131
|
+
|
|
132
|
+
// ── Diagnostic counters ──────────────────────────────────
|
|
133
|
+
state.received = 0;
|
|
134
|
+
state.emitted = 0;
|
|
135
|
+
state.swingsThisTick = 0;
|
|
136
|
+
state.swingRate = 0;
|
|
137
|
+
|
|
138
|
+
// ── Metadata ─────────────────────────────────────────────
|
|
139
|
+
state.nodeType = introspect.getNodeType();
|
|
140
|
+
|
|
141
|
+
return state;
|
|
142
|
+
}; // init()
|
|
143
|
+
|
|
144
|
+
export default init;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// @fileoverview
|
|
2
|
+
// Introspection metadata for the swingWatch node.
|
|
3
|
+
//
|
|
4
|
+
// swingWatch watches a signal for swings — dips and peaks — over a sliding
|
|
5
|
+
// window and reports the size of each swing when it completes. A swing's
|
|
6
|
+
// size is its topological persistence: how far the value travels between a
|
|
7
|
+
// turning point and the level that closes the round trip. On each tick the
|
|
8
|
+
// node runs a batch persistence sweep (sort by value + union-find, the
|
|
9
|
+
// Huber/Persistence1D algorithm) on the current window and emits completion
|
|
10
|
+
// events for pairs that are new compared to the previous tick.
|
|
11
|
+
//
|
|
12
|
+
// Convention: topological persistence — the global extremum in the window is
|
|
13
|
+
// unpaired (infinite persistence). This matches Persistence1D, not scipy's
|
|
14
|
+
// peak-prominence convention.
|
|
15
|
+
//
|
|
16
|
+
// References:
|
|
17
|
+
// Edelsbrunner, Letscher & Zomorodian (2002). Topological Persistence and
|
|
18
|
+
// Simplification. Discrete & Computational Geometry, 28, 511–533.
|
|
19
|
+
// Huber, S. Persistent Topology for Peak Detection.
|
|
20
|
+
// https://www.sthu.org/blog/13-perstopology-peakdetection/index.html
|
|
21
|
+
|
|
22
|
+
import { validators } from '../../core/utils/validate/index.js';
|
|
23
|
+
|
|
24
|
+
// ── Supported Features ───────────────────────────────────────
|
|
25
|
+
const SUPPORTED_STATS = [
|
|
26
|
+
'dipCompleted',
|
|
27
|
+
'dipValue',
|
|
28
|
+
'dipLag',
|
|
29
|
+
'dipSize',
|
|
30
|
+
'peakCompleted',
|
|
31
|
+
'peakValue',
|
|
32
|
+
'peakLag',
|
|
33
|
+
'peakSize',
|
|
34
|
+
'swingsThisTick',
|
|
35
|
+
'swingRate'
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const STAT_DESCRIPTIONS = {
|
|
39
|
+
dipCompleted: 'True on the tick a significant dip completes (false otherwise)',
|
|
40
|
+
dipValue: 'Signal value at the bottom of the completed dip (undefined when not completing)',
|
|
41
|
+
dipLag: 'Samples back to the bottom of the completed dip within the window (undefined when not completing)',
|
|
42
|
+
dipSize: 'Size (depth) of the completed dip: deathVal - birthVal (undefined when not completing)',
|
|
43
|
+
peakCompleted: 'True on the tick a significant peak completes',
|
|
44
|
+
peakValue: 'Signal value at the top of the completed peak (undefined when not completing)',
|
|
45
|
+
peakLag: 'Samples back to the top of the completed peak within the window (undefined when not completing)',
|
|
46
|
+
peakSize: 'Size (height) of the completed peak: birthVal - deathVal (undefined when not completing)',
|
|
47
|
+
swingsThisTick: 'Number of swings newly accounted this tick; when several finish at once the dip/peak stats detail the largest',
|
|
48
|
+
swingRate: 'Cumulative swings per received sample (emitted / received); can exceed 1.0 with direction "both" when one tick completes both a dip and a peak'
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const SUPPORTED_CONTROL_METHODS = {
|
|
52
|
+
reset: 'Clears ring buffer and all completion history',
|
|
53
|
+
enable: 'Enables node processing',
|
|
54
|
+
disable: 'Disables node processing',
|
|
55
|
+
pause: 'Pauses update but keeps publishTo outputs visible',
|
|
56
|
+
unpause: 'Resumes update after pause'
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const NODE_TYPE = 'Swing Watch';
|
|
60
|
+
|
|
61
|
+
const CAPABILITIES = {
|
|
62
|
+
description: 'Watches a signal for swings — dips and peaks — over a sliding window and reports the size of each completed swing',
|
|
63
|
+
features: [
|
|
64
|
+
'Windowed batch persistence sweep (sort + union-find) per tick',
|
|
65
|
+
'Topological convention — consistent with Persistence1D and Huber',
|
|
66
|
+
'Adaptive threshold via tunable pattern (k × σ from upstream stats)',
|
|
67
|
+
'Configurable minimum absolute threshold floor for quiet signals',
|
|
68
|
+
'Bidirectional detection (dips, peaks, or both)',
|
|
69
|
+
'Output scrubbing on non-completion ticks (undefined) per momentsDigest convention',
|
|
70
|
+
'Zero allocation in hot path — all typed arrays pre-allocated in init',
|
|
71
|
+
'Exactly-once completion events — flag-based emission suppressing window-boundary artifacts (left-edge eviction re-fires, right-edge provisional extrema)'
|
|
72
|
+
]
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// ── Default Options ──────────────────────────────────────────
|
|
76
|
+
export const DEFAULT_OPTIONS = {
|
|
77
|
+
windowSize: 100,
|
|
78
|
+
direction: 'both',
|
|
79
|
+
minAbsoluteThreshold: 0
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** Parameters that support tunable (dynamic) values. */
|
|
83
|
+
export const TUNABLE_PARAMS = [ 'threshold' ];
|
|
84
|
+
|
|
85
|
+
// ── Getter Functions (defensive copies) ──────────────────────
|
|
86
|
+
export const getSupportedStats = () => SUPPORTED_STATS.slice();
|
|
87
|
+
export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
|
|
88
|
+
export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
|
|
89
|
+
export const getNodeType = () => NODE_TYPE;
|
|
90
|
+
export const getCapabilities = () => ( {
|
|
91
|
+
...CAPABILITIES,
|
|
92
|
+
features: CAPABILITIES.features.slice()
|
|
93
|
+
} );
|
|
94
|
+
|
|
95
|
+
// ── DSL Metadata ─────────────────────────────────────────────
|
|
96
|
+
const DSL_METADATA = {
|
|
97
|
+
specSchema: {
|
|
98
|
+
nodeType: {
|
|
99
|
+
type: 'string',
|
|
100
|
+
required: true,
|
|
101
|
+
value: NODE_TYPE
|
|
102
|
+
},
|
|
103
|
+
name: {
|
|
104
|
+
type: 'string',
|
|
105
|
+
required: true,
|
|
106
|
+
validator: validators.identifier,
|
|
107
|
+
error: 'Name must be a valid identifier'
|
|
108
|
+
},
|
|
109
|
+
from: {
|
|
110
|
+
type: 'object',
|
|
111
|
+
required: true,
|
|
112
|
+
properties: {
|
|
113
|
+
x: {
|
|
114
|
+
type: 'string',
|
|
115
|
+
required: true,
|
|
116
|
+
validator: validators.noSpaces,
|
|
117
|
+
error: 'Field name cannot contain spaces'
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
threshold: {
|
|
122
|
+
type: 'numberOrFunctionOrFieldKeyed',
|
|
123
|
+
required: true,
|
|
124
|
+
min: 0,
|
|
125
|
+
error: 'threshold must be a non-negative number, function, or per-field map'
|
|
126
|
+
},
|
|
127
|
+
// Upper bound chosen so the two copy loops and the per-tick sort stay
|
|
128
|
+
// in L1 cache. Algorithm is correct for larger W but performance has
|
|
129
|
+
// not been validated beyond 256. integer+min+max are applied per
|
|
130
|
+
// numeric value — including inside a field-keyed object — by the
|
|
131
|
+
// numberOrFieldKeyed type validator. A custom `validator` would run on
|
|
132
|
+
// the outer value (the object itself), which would reject any
|
|
133
|
+
// field-keyed spec.
|
|
134
|
+
windowSize: {
|
|
135
|
+
type: 'numberOrFieldKeyed',
|
|
136
|
+
required: false,
|
|
137
|
+
default: DEFAULT_OPTIONS.windowSize,
|
|
138
|
+
integer: true,
|
|
139
|
+
min: 4,
|
|
140
|
+
max: 256
|
|
141
|
+
},
|
|
142
|
+
direction: {
|
|
143
|
+
type: 'string',
|
|
144
|
+
required: false,
|
|
145
|
+
default: DEFAULT_OPTIONS.direction,
|
|
146
|
+
validator: validators.oneOf( [ 'both', 'dips', 'peaks' ] ),
|
|
147
|
+
error: 'direction must be "both", "dips", or "peaks"'
|
|
148
|
+
},
|
|
149
|
+
minAbsoluteThreshold: {
|
|
150
|
+
type: 'number',
|
|
151
|
+
required: false,
|
|
152
|
+
default: DEFAULT_OPTIONS.minAbsoluteThreshold,
|
|
153
|
+
min: 0,
|
|
154
|
+
error: 'minAbsoluteThreshold must be a non-negative number'
|
|
155
|
+
},
|
|
156
|
+
stats: {
|
|
157
|
+
type: 'object',
|
|
158
|
+
required: true,
|
|
159
|
+
minProperties: 1,
|
|
160
|
+
propertyNames: SUPPORTED_STATS,
|
|
161
|
+
propertySchema: {
|
|
162
|
+
type: 'object',
|
|
163
|
+
required: true,
|
|
164
|
+
properties: {
|
|
165
|
+
storeAs: {
|
|
166
|
+
type: 'string',
|
|
167
|
+
required: true,
|
|
168
|
+
minLength: 1,
|
|
169
|
+
validator: validators.identifier,
|
|
170
|
+
error: 'storeAs must be a valid identifier'
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
crossFieldValidators: [],
|
|
178
|
+
|
|
179
|
+
buildSpec: ( name, x, stats, options ) => ( {
|
|
180
|
+
nodeType: NODE_TYPE,
|
|
181
|
+
name,
|
|
182
|
+
from: { x },
|
|
183
|
+
stats,
|
|
184
|
+
...( options || {} )
|
|
185
|
+
} )
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export const getDSLMetadata = () => ( { ...DSL_METADATA } );
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// @fileoverview
|
|
2
|
+
// publish-to.js — copy computed completion fields to the output message.
|
|
3
|
+
//
|
|
4
|
+
// Follows the momentsDigest output-scrubbing convention: on non-completion
|
|
5
|
+
// ticks, detail fields (birthValue, birthLag, persistence) are explicitly
|
|
6
|
+
// set to `undefined` — not left as stale values from a previous tick. This
|
|
7
|
+
// prevents downstream nodes from acting on outdated event data.
|
|
8
|
+
//
|
|
9
|
+
// The completion booleans (dipCompleted, peakCompleted) are always published
|
|
10
|
+
// so downstream can branch on them. Diagnostic fields (swingsThisTick,
|
|
11
|
+
// swingRate) are always published when the window is full.
|
|
12
|
+
//
|
|
13
|
+
// Guard order (per ADR-004):
|
|
14
|
+
// 1. disable → skip entirely (node invisible downstream)
|
|
15
|
+
// 2. inputValidationFailed → publishNaN for all stats (fault isolation)
|
|
16
|
+
// 3. isNotFull → skip (warmup, no meaningful output yet)
|
|
17
|
+
|
|
18
|
+
import { isNotFull } from '../../windowing/count-sliding/index.js';
|
|
19
|
+
import { publishNaN } from '../../core/utils/node/index.js';
|
|
20
|
+
|
|
21
|
+
const publishTo = function ( state, msg ) {
|
|
22
|
+
if ( state.disable ) return;
|
|
23
|
+
|
|
24
|
+
if ( state.inputValidationFailed ) {
|
|
25
|
+
publishNaN( state, msg );
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Do not publish during warmup (window not yet full)
|
|
30
|
+
if ( isNotFull( state.ring ) ) return;
|
|
31
|
+
|
|
32
|
+
const s = state.stats;
|
|
33
|
+
|
|
34
|
+
// ── Completion booleans (always published) ────────────────
|
|
35
|
+
if ( s.dipCompleted ) msg[ s.dipCompleted.storeAs ] = state.dipCompleted;
|
|
36
|
+
if ( s.peakCompleted ) msg[ s.peakCompleted.storeAs ] = state.peakCompleted;
|
|
37
|
+
|
|
38
|
+
// ── Dip detail fields (scrubbed to undefined on non-completion ticks) ─
|
|
39
|
+
if ( s.dipValue ) msg[ s.dipValue.storeAs ] = state.dipCompleted ? state.dipValue : undefined;
|
|
40
|
+
if ( s.dipLag ) msg[ s.dipLag.storeAs ] = state.dipCompleted ? state.dipLag : undefined;
|
|
41
|
+
if ( s.dipSize ) msg[ s.dipSize.storeAs ] = state.dipCompleted ? state.dipSize : undefined;
|
|
42
|
+
|
|
43
|
+
// ── Peak detail fields (scrubbed to undefined on non-completion ticks) ─
|
|
44
|
+
if ( s.peakValue ) msg[ s.peakValue.storeAs ] = state.peakCompleted ? state.peakValue : undefined;
|
|
45
|
+
if ( s.peakLag ) msg[ s.peakLag.storeAs ] = state.peakCompleted ? state.peakLag : undefined;
|
|
46
|
+
if ( s.peakSize ) msg[ s.peakSize.storeAs ] = state.peakCompleted ? state.peakSize : undefined;
|
|
47
|
+
|
|
48
|
+
// ── Diagnostics (always published when window is full) ───
|
|
49
|
+
if ( s.swingsThisTick ) msg[ s.swingsThisTick.storeAs ] = state.swingsThisTick;
|
|
50
|
+
if ( s.swingRate ) msg[ s.swingRate.storeAs ] = state.swingRate;
|
|
51
|
+
}; // publishTo()
|
|
52
|
+
|
|
53
|
+
export default publishTo;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// @fileoverview
|
|
2
|
+
// recompute.js — re-establish numerical ground truth per ADR-004.
|
|
3
|
+
//
|
|
4
|
+
// Unlike incremental-accumulator nodes (esMean, swStats) where floating-point
|
|
5
|
+
// drift can compound over millions of updates, swingWatch recomputes the
|
|
6
|
+
// entire persistence diagram from scratch on every tick (the windowed batch
|
|
7
|
+
// sweep sorts and sweeps the full window). There is no accumulated state that
|
|
8
|
+
// can drift.
|
|
9
|
+
//
|
|
10
|
+
// The only action needed is to clear the previous-tick pair storage, which
|
|
11
|
+
// forces the next tick's diff to re-derive every current pair as unmatched.
|
|
12
|
+
// The accounted-emission flags (exactly-once rule c in update.js) survive
|
|
13
|
+
// recompute deliberately: every re-derived pair's birth vertex is still
|
|
14
|
+
// flagged as accounted, so recompute causes no spurious re-emission burst.
|
|
15
|
+
|
|
16
|
+
const recompute = function ( state ) {
|
|
17
|
+
state.prevMinPairCount = 0;
|
|
18
|
+
state.prevMaxPairCount = 0;
|
|
19
|
+
return true;
|
|
20
|
+
}; // recompute()
|
|
21
|
+
|
|
22
|
+
export default recompute;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// @fileoverview
|
|
2
|
+
// reset.js — idempotent reset per ADR-004.
|
|
3
|
+
//
|
|
4
|
+
// Clears the ring buffer, all pair storage (current and previous tick),
|
|
5
|
+
// completion event slots, and diagnostic counters. After reset, the node
|
|
6
|
+
// re-enters the warmup phase (isNotFull returns true) and will not publish
|
|
7
|
+
// until the window fills again.
|
|
8
|
+
//
|
|
9
|
+
// Multiple calls produce the same state as a single call (idempotent).
|
|
10
|
+
|
|
11
|
+
import { reset as resetRing } from '../../windowing/count-sliding/index.js';
|
|
12
|
+
|
|
13
|
+
const reset = function ( state ) {
|
|
14
|
+
// Clear the ring buffer — head, used, and buffer contents all zeroed
|
|
15
|
+
resetRing( state.ring );
|
|
16
|
+
|
|
17
|
+
// Clear current tick's pair counts (typed arrays contents are irrelevant
|
|
18
|
+
// when count is 0 — no need to zero the arrays themselves)
|
|
19
|
+
state.minPairCount = 0;
|
|
20
|
+
state.maxPairCount = 0;
|
|
21
|
+
|
|
22
|
+
// Clear previous tick's pair counts (forces fresh diff on next tick —
|
|
23
|
+
// all pairs in the first full-window tick will appear as "new")
|
|
24
|
+
state.prevMinPairCount = 0;
|
|
25
|
+
state.prevMaxPairCount = 0;
|
|
26
|
+
|
|
27
|
+
// Clear the accounted-emission flags (exactly-once rule c) — after a
|
|
28
|
+
// reset every vertex of the refilled window may emit afresh
|
|
29
|
+
state.minEmitFlag.fill( 0 );
|
|
30
|
+
state.maxEmitFlag.fill( 0 );
|
|
31
|
+
|
|
32
|
+
// Clear completion event slots
|
|
33
|
+
state.dipCompleted = false;
|
|
34
|
+
state.peakCompleted = false;
|
|
35
|
+
state.dipValue = NaN;
|
|
36
|
+
state.peakValue = NaN;
|
|
37
|
+
state.dipLag = 0;
|
|
38
|
+
state.peakLag = 0;
|
|
39
|
+
state.dipSize = NaN;
|
|
40
|
+
state.peakSize = NaN;
|
|
41
|
+
|
|
42
|
+
// Clear diagnostics
|
|
43
|
+
state.received = 0;
|
|
44
|
+
state.emitted = 0;
|
|
45
|
+
state.swingsThisTick = 0;
|
|
46
|
+
state.swingRate = 0;
|
|
47
|
+
|
|
48
|
+
// Clear health and tunable error flags
|
|
49
|
+
state.inputValidationFailed = false;
|
|
50
|
+
state.tunableErrorLogged = false;
|
|
51
|
+
|
|
52
|
+
return true;
|
|
53
|
+
}; // reset()
|
|
54
|
+
|
|
55
|
+
export default reset;
|