@winkjs/composer 0.0.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +42 -103
  3. package/package.json +53 -29
  4. package/src/composer.js +75 -0
  5. package/src/core/batch/aoo-encoder.js +148 -0
  6. package/src/core/batch/index.js +12 -0
  7. package/src/core/batch/sliding-window.js +91 -0
  8. package/src/core/codec/index.js +137 -0
  9. package/src/core/emitter-manager/mqtt/constants.js +102 -0
  10. package/src/core/emitter-manager/mqtt/emitter.js +780 -0
  11. package/src/core/emitter-manager/mqtt/index.js +190 -0
  12. package/src/core/emitter-manager/mqtt/mqtt-store.js +538 -0
  13. package/src/core/emitter-manager/terminal/assert-columns.js +98 -0
  14. package/src/core/emitter-manager/terminal/formatters.js +160 -0
  15. package/src/core/emitter-manager/terminal/index.js +341 -0
  16. package/src/core/env-vars.js +245 -0
  17. package/src/core/mqtt-protocol.js +47 -0
  18. package/src/core/partition-manager/index.js +7 -0
  19. package/src/core/partition-manager/init.js +44 -0
  20. package/src/core/partition-manager/introspect.js +15 -0
  21. package/src/core/partition-manager/publish-to.js +6 -0
  22. package/src/core/partition-manager/recompute.js +5 -0
  23. package/src/core/partition-manager/reset.js +5 -0
  24. package/src/core/partition-manager/update.js +264 -0
  25. package/src/core/partition-manager/validate-flow.js +157 -0
  26. package/src/core/semantics/digest.js +128 -0
  27. package/src/core/semantics/index.js +83 -0
  28. package/src/core/semantics/loader.js +571 -0
  29. package/src/core/semantics/schemas/asset-class-schema.js +218 -0
  30. package/src/core/semantics/schemas/column-schema.js +651 -0
  31. package/src/core/semantics/schemas/enum-schema.js +153 -0
  32. package/src/core/semantics/schemas/index.js +51 -0
  33. package/src/core/semantics/warnings.js +141 -0
  34. package/src/core/shutdown-manager/index.js +289 -0
  35. package/src/core/source-manager/csv/index.js +171 -0
  36. package/src/core/source-manager/csv/start.js +456 -0
  37. package/src/core/source-manager/mqtt/client.js +406 -0
  38. package/src/core/source-manager/mqtt/constants.js +147 -0
  39. package/src/core/source-manager/mqtt/dedup.js +244 -0
  40. package/src/core/source-manager/mqtt/index.js +260 -0
  41. package/src/core/source-manager/mqtt/status.js +546 -0
  42. package/src/core/source-manager/test-harness/comparator.js +226 -0
  43. package/src/core/source-manager/test-harness/field-generator.js +85 -0
  44. package/src/core/source-manager/test-harness/fuzz.js +87 -0
  45. package/src/core/source-manager/test-harness/index.js +115 -0
  46. package/src/core/source-manager/test-harness/prng.js +57 -0
  47. package/src/core/source-manager/test-harness/start.js +232 -0
  48. package/src/core/source-manager/test-harness/validate.js +213 -0
  49. package/src/core/storage-manager/questdb/assert-columns.js +120 -0
  50. package/src/core/storage-manager/questdb/ensure-tables.js +187 -0
  51. package/src/core/storage-manager/questdb/index.js +1251 -0
  52. package/src/core/storage-manager/questdb/persist-plan.js +488 -0
  53. package/src/core/storage-manager/questdb/writers.js +142 -0
  54. package/src/core/test-utils/sealed-record.js +80 -0
  55. package/src/core/test-utils/soak-signature.js +149 -0
  56. package/src/core/test-utils/tcp-proxy.js +106 -0
  57. package/src/core/tunable/helpers.js +254 -0
  58. package/src/core/tunable/index.js +87 -0
  59. package/src/core/utils/console-formatter/index.js +207 -0
  60. package/src/core/utils/create-smart-store-as/index.js +98 -0
  61. package/src/core/utils/create-smart-store-as/sanitize-field.js +46 -0
  62. package/src/core/utils/create-smart-store-as/smart-truncate.js +93 -0
  63. package/src/core/utils/flow/index.js +5 -0
  64. package/src/core/utils/flow/make-collision-checker.js +23 -0
  65. package/src/core/utils/flow/to-kebab.js +20 -0
  66. package/src/core/utils/half-life/index.js +111 -0
  67. package/src/core/utils/node/disable.js +11 -0
  68. package/src/core/utils/node/enable.js +11 -0
  69. package/src/core/utils/node/execute-triggers.js +40 -0
  70. package/src/core/utils/node/index.js +10 -0
  71. package/src/core/utils/node/pause.js +11 -0
  72. package/src/core/utils/node/populate-predicate-inputs.js +14 -0
  73. package/src/core/utils/node/publish-nan.js +19 -0
  74. package/src/core/utils/node/reset-predicate-inputs.js +11 -0
  75. package/src/core/utils/node/unpause.js +11 -0
  76. package/src/core/utils/node/validate-spec.js +22 -0
  77. package/src/core/utils/options/resolve-field-keyed.js +115 -0
  78. package/src/core/utils/quantize/index.js +75 -0
  79. package/src/core/utils/stats/formulas.js +67 -0
  80. package/src/core/utils/stats/index.js +3 -0
  81. package/src/core/utils/validate/composer-validators.js +141 -0
  82. package/src/core/utils/validate/helpers.js +206 -0
  83. package/src/core/utils/validate/index.js +12 -0
  84. package/src/core/utils/validate/type-validators.js +538 -0
  85. package/src/core/utils/validate/validate.js +107 -0
  86. package/src/core/utils/validate/validators.js +177 -0
  87. package/src/core/wiring/assert-handle.js +57 -0
  88. package/src/core/wiring/assert-module.js +63 -0
  89. package/src/core/wiring/index.js +5 -0
  90. package/src/core/wiring/node-type-to-module.js +17 -0
  91. package/src/core/wiring/wire-emitters.js +256 -0
  92. package/src/core/wiring/wire-linear-graph.js +25 -0
  93. package/src/core/wiring/wire-node.js +157 -0
  94. package/src/core/wiring/wire-semantics.js +173 -0
  95. package/src/core/wiring/wire-storages.js +344 -0
  96. package/src/flow/check-output-collisions.js +93 -0
  97. package/src/flow/consts.js +9 -0
  98. package/src/flow/deep-clone-spec.js +64 -0
  99. package/src/flow/driver.js +171 -0
  100. package/src/flow/expand-single-input-array.js +76 -0
  101. package/src/flow/expand-template-spec.js +93 -0
  102. package/src/flow/flow-api-schemas.js +300 -0
  103. package/src/flow/flow.js +658 -0
  104. package/src/flow/for-each.js +225 -0
  105. package/src/flow/get-signature-pattern.js +31 -0
  106. package/src/flow/get-target-array.js +46 -0
  107. package/src/flow/inspect.js +67 -0
  108. package/src/flow/load-node-module.js +81 -0
  109. package/src/flow/make-node-method.js +112 -0
  110. package/src/flow/resolve-pick-by-field.js +77 -0
  111. package/src/flow/resolve-tunables.js +76 -0
  112. package/src/flow/run.js +392 -0
  113. package/src/flow/serialize.js +161 -0
  114. package/src/flow/signatures-schema.js +222 -0
  115. package/src/flow/spec-builder.js +65 -0
  116. package/src/flow/validate-triggers.js +250 -0
  117. package/src/flow/validate.js +261 -0
  118. package/src/nodes/accumulate/index.js +21 -0
  119. package/src/nodes/accumulate/init.js +48 -0
  120. package/src/nodes/accumulate/introspect.js +123 -0
  121. package/src/nodes/accumulate/publish-to.js +34 -0
  122. package/src/nodes/accumulate/recompute.js +27 -0
  123. package/src/nodes/accumulate/reset.js +25 -0
  124. package/src/nodes/accumulate/update.js +42 -0
  125. package/src/nodes/appraise/calibrate.js +64 -0
  126. package/src/nodes/appraise/decision.js +66 -0
  127. package/src/nodes/appraise/deviation.js +140 -0
  128. package/src/nodes/appraise/index.js +23 -0
  129. package/src/nodes/appraise/init.js +165 -0
  130. package/src/nodes/appraise/integrate.js +45 -0
  131. package/src/nodes/appraise/introspect.js +352 -0
  132. package/src/nodes/appraise/publish-to.js +93 -0
  133. package/src/nodes/appraise/receptor.js +69 -0
  134. package/src/nodes/appraise/recompute.js +79 -0
  135. package/src/nodes/appraise/reset.js +53 -0
  136. package/src/nodes/appraise/update.js +130 -0
  137. package/src/nodes/archive/csv/index.js +6 -0
  138. package/src/nodes/archive/csv/init.js +36 -0
  139. package/src/nodes/archive/csv/load.js +70 -0
  140. package/src/nodes/archive/csv/reset.js +14 -0
  141. package/src/nodes/archive/csv/simple-parser.js +216 -0
  142. package/src/nodes/archive/csv/test.js +173 -0
  143. package/src/nodes/archive/csv/update.js +63 -0
  144. package/src/nodes/butterworth-filter/index.js +18 -0
  145. package/src/nodes/butterworth-filter/init.js +184 -0
  146. package/src/nodes/butterworth-filter/introspect.js +228 -0
  147. package/src/nodes/butterworth-filter/publish-to.js +21 -0
  148. package/src/nodes/butterworth-filter/recompute.js +13 -0
  149. package/src/nodes/butterworth-filter/reset.js +30 -0
  150. package/src/nodes/butterworth-filter/update.js +38 -0
  151. package/src/nodes/categorize/index.js +19 -0
  152. package/src/nodes/categorize/init.js +58 -0
  153. package/src/nodes/categorize/introspect.js +177 -0
  154. package/src/nodes/categorize/publish-to.js +29 -0
  155. package/src/nodes/categorize/recompute.js +14 -0
  156. package/src/nodes/categorize/reset.js +16 -0
  157. package/src/nodes/categorize/update.js +53 -0
  158. package/src/nodes/controller/index.js +9 -0
  159. package/src/nodes/controller/init.js +55 -0
  160. package/src/nodes/controller/introspect.js +91 -0
  161. package/src/nodes/controller/publish-to.js +8 -0
  162. package/src/nodes/controller/recompute.js +9 -0
  163. package/src/nodes/controller/reset.js +17 -0
  164. package/src/nodes/controller/update.js +63 -0
  165. package/src/nodes/diff/index.js +19 -0
  166. package/src/nodes/diff/init.js +37 -0
  167. package/src/nodes/diff/introspect.js +132 -0
  168. package/src/nodes/diff/publish-to.js +21 -0
  169. package/src/nodes/diff/recompute.js +12 -0
  170. package/src/nodes/diff/reset.js +12 -0
  171. package/src/nodes/diff/update.js +37 -0
  172. package/src/nodes/digest-moments/formulas.js +12 -0
  173. package/src/nodes/digest-moments/index.js +14 -0
  174. package/src/nodes/digest-moments/init.js +67 -0
  175. package/src/nodes/digest-moments/introspect.js +154 -0
  176. package/src/nodes/digest-moments/publish-to.js +34 -0
  177. package/src/nodes/digest-moments/recompute.js +14 -0
  178. package/src/nodes/digest-moments/reset.js +14 -0
  179. package/src/nodes/digest-moments/update.js +120 -0
  180. package/src/nodes/dwell-time-tracker/index.js +14 -0
  181. package/src/nodes/dwell-time-tracker/init.js +59 -0
  182. package/src/nodes/dwell-time-tracker/introspect.js +137 -0
  183. package/src/nodes/dwell-time-tracker/publish-to.js +22 -0
  184. package/src/nodes/dwell-time-tracker/recompute.js +8 -0
  185. package/src/nodes/dwell-time-tracker/reset.js +23 -0
  186. package/src/nodes/dwell-time-tracker/update.js +103 -0
  187. package/src/nodes/emit-if/helpers.js +94 -0
  188. package/src/nodes/emit-if/index.js +16 -0
  189. package/src/nodes/emit-if/init.js +67 -0
  190. package/src/nodes/emit-if/introspect.js +102 -0
  191. package/src/nodes/emit-if/publish-to.js +13 -0
  192. package/src/nodes/emit-if/recompute.js +12 -0
  193. package/src/nodes/emit-if/reset.js +27 -0
  194. package/src/nodes/emit-if/update.js +93 -0
  195. package/src/nodes/es-correlation/index.js +19 -0
  196. package/src/nodes/es-correlation/init.js +73 -0
  197. package/src/nodes/es-correlation/introspect.js +176 -0
  198. package/src/nodes/es-correlation/publish-to.js +32 -0
  199. package/src/nodes/es-correlation/recompute.js +56 -0
  200. package/src/nodes/es-correlation/reset.js +27 -0
  201. package/src/nodes/es-correlation/update.js +110 -0
  202. package/src/nodes/es-mean/index.js +20 -0
  203. package/src/nodes/es-mean/init.js +58 -0
  204. package/src/nodes/es-mean/introspect.js +129 -0
  205. package/src/nodes/es-mean/publish-to.js +19 -0
  206. package/src/nodes/es-mean/recompute.js +16 -0
  207. package/src/nodes/es-mean/reset.js +24 -0
  208. package/src/nodes/es-mean/update.js +69 -0
  209. package/src/nodes/es-pairwise-correlation/index.js +19 -0
  210. package/src/nodes/es-pairwise-correlation/init.js +98 -0
  211. package/src/nodes/es-pairwise-correlation/introspect.js +187 -0
  212. package/src/nodes/es-pairwise-correlation/publish-to.js +31 -0
  213. package/src/nodes/es-pairwise-correlation/recompute.js +69 -0
  214. package/src/nodes/es-pairwise-correlation/reset.js +29 -0
  215. package/src/nodes/es-pairwise-correlation/update.js +89 -0
  216. package/src/nodes/es-stats/index.js +21 -0
  217. package/src/nodes/es-stats/init.js +105 -0
  218. package/src/nodes/es-stats/introspect.js +157 -0
  219. package/src/nodes/es-stats/publish-to.js +42 -0
  220. package/src/nodes/es-stats/recompute.js +74 -0
  221. package/src/nodes/es-stats/reset.js +49 -0
  222. package/src/nodes/es-stats/update-envelope.js +44 -0
  223. package/src/nodes/es-stats/update-welford.js +64 -0
  224. package/src/nodes/es-stats/update.js +59 -0
  225. package/src/nodes/index.js +83 -0
  226. package/src/nodes/invert-flag/index.js +20 -0
  227. package/src/nodes/invert-flag/init.js +36 -0
  228. package/src/nodes/invert-flag/introspect.js +115 -0
  229. package/src/nodes/invert-flag/publish-to.js +23 -0
  230. package/src/nodes/invert-flag/recompute.js +12 -0
  231. package/src/nodes/invert-flag/reset.js +12 -0
  232. package/src/nodes/invert-flag/update.js +32 -0
  233. package/src/nodes/kalman1d/index.js +20 -0
  234. package/src/nodes/kalman1d/init.js +103 -0
  235. package/src/nodes/kalman1d/introspect.js +250 -0
  236. package/src/nodes/kalman1d/publish-to.js +34 -0
  237. package/src/nodes/kalman1d/recompute.js +23 -0
  238. package/src/nodes/kalman1d/reset.js +29 -0
  239. package/src/nodes/kalman1d/update.js +144 -0
  240. package/src/nodes/kernel/index.js +18 -0
  241. package/src/nodes/kernel/init.js +66 -0
  242. package/src/nodes/kernel/introspect.js +163 -0
  243. package/src/nodes/kernel/presets.js +74 -0
  244. package/src/nodes/kernel/publish-to.js +25 -0
  245. package/src/nodes/kernel/recompute.js +14 -0
  246. package/src/nodes/kernel/reset.js +20 -0
  247. package/src/nodes/kernel/update.js +69 -0
  248. package/src/nodes/lag/index.js +21 -0
  249. package/src/nodes/lag/init.js +87 -0
  250. package/src/nodes/lag/introspect.js +202 -0
  251. package/src/nodes/lag/publish-to.js +64 -0
  252. package/src/nodes/lag/recompute.js +33 -0
  253. package/src/nodes/lag/reset.js +49 -0
  254. package/src/nodes/lag/update.js +133 -0
  255. package/src/nodes/median3/index.js +19 -0
  256. package/src/nodes/median3/init.js +40 -0
  257. package/src/nodes/median3/introspect.js +116 -0
  258. package/src/nodes/median3/publish-to.js +21 -0
  259. package/src/nodes/median3/recompute.js +12 -0
  260. package/src/nodes/median3/reset.js +15 -0
  261. package/src/nodes/median3/update.js +58 -0
  262. package/src/nodes/moments-digest/copy-from.js +12 -0
  263. package/src/nodes/moments-digest/flush.js +17 -0
  264. package/src/nodes/moments-digest/index.js +132 -0
  265. package/src/nodes/moments-digest/init.js +84 -0
  266. package/src/nodes/moments-digest/introspect.js +122 -0
  267. package/src/nodes/moments-digest/prelude.js +28 -0
  268. package/src/nodes/moments-digest/publish-to.js +31 -0
  269. package/src/nodes/moments-digest/recompute.js +9 -0
  270. package/src/nodes/moments-digest/reset.js +20 -0
  271. package/src/nodes/moments-digest/update.js +182 -0
  272. package/src/nodes/node-names.js +67 -0
  273. package/src/nodes/page-hinkley/index.js +20 -0
  274. package/src/nodes/page-hinkley/init.js +66 -0
  275. package/src/nodes/page-hinkley/introspect.js +193 -0
  276. package/src/nodes/page-hinkley/publish-to.js +28 -0
  277. package/src/nodes/page-hinkley/recompute.js +14 -0
  278. package/src/nodes/page-hinkley/reset.js +23 -0
  279. package/src/nodes/page-hinkley/update.js +105 -0
  280. package/src/nodes/pass-if/index.js +21 -0
  281. package/src/nodes/pass-if/init.js +37 -0
  282. package/src/nodes/pass-if/introspect.js +93 -0
  283. package/src/nodes/pass-if/publish-to.js +15 -0
  284. package/src/nodes/pass-if/recompute.js +15 -0
  285. package/src/nodes/pass-if/reset.js +18 -0
  286. package/src/nodes/pass-if/update.js +37 -0
  287. package/src/nodes/persist-if/helpers.js +111 -0
  288. package/src/nodes/persist-if/index.js +9 -0
  289. package/src/nodes/persist-if/init.js +98 -0
  290. package/src/nodes/persist-if/introspect.js +106 -0
  291. package/src/nodes/persist-if/publish-to.js +21 -0
  292. package/src/nodes/persist-if/recompute.js +20 -0
  293. package/src/nodes/persist-if/reset.js +35 -0
  294. package/src/nodes/persist-if/update.js +112 -0
  295. package/src/nodes/persistence-check/index.js +14 -0
  296. package/src/nodes/persistence-check/init.js +38 -0
  297. package/src/nodes/persistence-check/introspect.js +144 -0
  298. package/src/nodes/persistence-check/publish-to.js +11 -0
  299. package/src/nodes/persistence-check/recompute.js +7 -0
  300. package/src/nodes/persistence-check/reset.js +12 -0
  301. package/src/nodes/persistence-check/update.js +57 -0
  302. package/src/nodes/process-index/index.js +15 -0
  303. package/src/nodes/process-index/init.js +48 -0
  304. package/src/nodes/process-index/introspect.js +182 -0
  305. package/src/nodes/process-index/publish-to.js +29 -0
  306. package/src/nodes/process-index/recompute.js +8 -0
  307. package/src/nodes/process-index/reset.js +8 -0
  308. package/src/nodes/process-index/update.js +75 -0
  309. package/src/nodes/ratio/index.js +14 -0
  310. package/src/nodes/ratio/init.js +37 -0
  311. package/src/nodes/ratio/introspect.js +155 -0
  312. package/src/nodes/ratio/publish-to.js +15 -0
  313. package/src/nodes/ratio/recompute.js +7 -0
  314. package/src/nodes/ratio/reset.js +7 -0
  315. package/src/nodes/ratio/update.js +47 -0
  316. package/src/nodes/sanitize/index.js +82 -0
  317. package/src/nodes/sanitize/init.js +82 -0
  318. package/src/nodes/sanitize/introspect.js +194 -0
  319. package/src/nodes/sanitize/publish-to.js +15 -0
  320. package/src/nodes/sanitize/recompute.js +8 -0
  321. package/src/nodes/sanitize/reset.js +14 -0
  322. package/src/nodes/sanitize/update.js +102 -0
  323. package/src/nodes/spike-guard/index.js +14 -0
  324. package/src/nodes/spike-guard/init.js +47 -0
  325. package/src/nodes/spike-guard/introspect.js +130 -0
  326. package/src/nodes/spike-guard/publish-to.js +35 -0
  327. package/src/nodes/spike-guard/recompute.js +14 -0
  328. package/src/nodes/spike-guard/reset.js +19 -0
  329. package/src/nodes/spike-guard/update.js +89 -0
  330. package/src/nodes/sse-emitter/index.js +7 -0
  331. package/src/nodes/sse-emitter/init.js +105 -0
  332. package/src/nodes/sse-emitter/introspect.js +134 -0
  333. package/src/nodes/sse-emitter/publish-to.js +6 -0
  334. package/src/nodes/sse-emitter/recompute.js +16 -0
  335. package/src/nodes/sse-emitter/reset.js +19 -0
  336. package/src/nodes/sse-emitter/update.js +69 -0
  337. package/src/nodes/sse-emitter/utils/broadcast-heartbeat.js +36 -0
  338. package/src/nodes/sse-emitter/utils/build-message.js +31 -0
  339. package/src/nodes/sse-emitter/utils/connection-manager.js +45 -0
  340. package/src/nodes/sse-emitter/utils/endpoint-initializer.js +20 -0
  341. package/src/nodes/sse-emitter/utils/health-monitor.js +38 -0
  342. package/src/nodes/sse-emitter/utils/qos-handler.js +41 -0
  343. package/src/nodes/state-change-detector/helpers.js +35 -0
  344. package/src/nodes/state-change-detector/index.js +12 -0
  345. package/src/nodes/state-change-detector/init.js +56 -0
  346. package/src/nodes/state-change-detector/introspect.js +146 -0
  347. package/src/nodes/state-change-detector/publish-to.js +20 -0
  348. package/src/nodes/state-change-detector/recompute.js +6 -0
  349. package/src/nodes/state-change-detector/reset.js +20 -0
  350. package/src/nodes/state-change-detector/update.js +97 -0
  351. package/src/nodes/sw-stats/index.js +14 -0
  352. package/src/nodes/sw-stats/init.js +51 -0
  353. package/src/nodes/sw-stats/introspect.js +131 -0
  354. package/src/nodes/sw-stats/publish-to.js +45 -0
  355. package/src/nodes/sw-stats/recompute.js +33 -0
  356. package/src/nodes/sw-stats/reset.js +15 -0
  357. package/src/nodes/sw-stats/update.js +39 -0
  358. package/src/nodes/swing-watch/index.js +17 -0
  359. package/src/nodes/swing-watch/init.js +144 -0
  360. package/src/nodes/swing-watch/introspect.js +188 -0
  361. package/src/nodes/swing-watch/publish-to.js +53 -0
  362. package/src/nodes/swing-watch/recompute.js +22 -0
  363. package/src/nodes/swing-watch/reset.js +55 -0
  364. package/src/nodes/swing-watch/update.js +767 -0
  365. package/src/nodes/tally/index.js +15 -0
  366. package/src/nodes/tally/init.js +32 -0
  367. package/src/nodes/tally/introspect.js +116 -0
  368. package/src/nodes/tally/publish-to.js +28 -0
  369. package/src/nodes/tally/recompute.js +10 -0
  370. package/src/nodes/tally/reset.js +10 -0
  371. package/src/nodes/tally/update.js +44 -0
  372. package/src/nodes/threshold/index.js +14 -0
  373. package/src/nodes/threshold/init.js +121 -0
  374. package/src/nodes/threshold/introspect.js +192 -0
  375. package/src/nodes/threshold/publish-to.js +11 -0
  376. package/src/nodes/threshold/recompute.js +8 -0
  377. package/src/nodes/threshold/reset.js +14 -0
  378. package/src/nodes/threshold/update.js +54 -0
  379. package/src/nodes/transform/helpers.js +39 -0
  380. package/src/nodes/transform/index.js +15 -0
  381. package/src/nodes/transform/init.js +35 -0
  382. package/src/nodes/transform/introspect.js +118 -0
  383. package/src/nodes/transform/publish-to.js +23 -0
  384. package/src/nodes/transform/recompute.js +12 -0
  385. package/src/nodes/transform/reset.js +11 -0
  386. package/src/nodes/transform/update.js +32 -0
  387. package/src/nodes/trend/compute-confidence.js +112 -0
  388. package/src/nodes/trend/index.js +14 -0
  389. package/src/nodes/trend/init.js +81 -0
  390. package/src/nodes/trend/introspect.js +151 -0
  391. package/src/nodes/trend/publish-to.js +22 -0
  392. package/src/nodes/trend/recompute.js +15 -0
  393. package/src/nodes/trend/reset.js +26 -0
  394. package/src/nodes/trend/update.js +93 -0
  395. package/src/nodes/tw-stats/copy-from.js +16 -0
  396. package/src/nodes/tw-stats/flush.js +12 -0
  397. package/src/nodes/tw-stats/index.js +41 -0
  398. package/src/nodes/tw-stats/init.js +92 -0
  399. package/src/nodes/tw-stats/introspect.js +171 -0
  400. package/src/nodes/tw-stats/publish-to.js +108 -0
  401. package/src/nodes/tw-stats/recompute.js +9 -0
  402. package/src/nodes/tw-stats/reset.js +16 -0
  403. package/src/nodes/tw-stats/update.js +113 -0
  404. package/src/nodes/unbalance/index.js +15 -0
  405. package/src/nodes/unbalance/init.js +59 -0
  406. package/src/nodes/unbalance/introspect.js +167 -0
  407. package/src/nodes/unbalance/publish-to.js +52 -0
  408. package/src/nodes/unbalance/recompute.js +11 -0
  409. package/src/nodes/unbalance/reset.js +10 -0
  410. package/src/nodes/unbalance/update.js +83 -0
  411. package/src/nodes/vector-distance/index.js +14 -0
  412. package/src/nodes/vector-distance/init.js +54 -0
  413. package/src/nodes/vector-distance/introspect.js +149 -0
  414. package/src/nodes/vector-distance/publish-to.js +35 -0
  415. package/src/nodes/vector-distance/recompute.js +11 -0
  416. package/src/nodes/vector-distance/reset.js +20 -0
  417. package/src/nodes/vector-distance/update.js +139 -0
  418. package/src/nodes/winnow/index.js +12 -0
  419. package/src/nodes/winnow/init.js +82 -0
  420. package/src/nodes/winnow/introspect.js +253 -0
  421. package/src/nodes/winnow/publish-to.js +51 -0
  422. package/src/nodes/winnow/recompute.js +14 -0
  423. package/src/nodes/winnow/reset.js +34 -0
  424. package/src/nodes/winnow/update.js +203 -0
  425. package/src/tools/training/features.js +227 -0
  426. package/src/tools/training/index.js +21 -0
  427. package/src/tools/training/logistic.js +238 -0
  428. package/src/tools/training/metrics.js +126 -0
  429. package/src/tools/training/scale.js +239 -0
  430. package/src/tools/training/validate.js +103 -0
  431. package/src/windowing/count-sliding/create.js +16 -0
  432. package/src/windowing/count-sliding/get-reverse-chronological-index.js +19 -0
  433. package/src/windowing/count-sliding/index.js +6 -0
  434. package/src/windowing/count-sliding/is-not-full.js +5 -0
  435. package/src/windowing/count-sliding/push.js +15 -0
  436. package/src/windowing/count-sliding/reset.js +11 -0
  437. package/src/windowing/count-sliding/size.js +5 -0
  438. package/src/windowing/time-sliding/create.js +25 -0
  439. package/src/windowing/time-sliding/push.js +42 -0
  440. package/CODE_OF_CONDUCT.md +0 -46
  441. package/CONTRIBUTING.md +0 -132
  442. package/docs/.nojekyll +0 -0
  443. package/docs/CONTRIBUTING.md +0 -134
  444. package/docs/README.md +0 -132
  445. package/docs/_coverpage.md +0 -26
  446. package/docs/_media/bg.png +0 -0
  447. package/docs/_media/wink-logo.png +0 -0
  448. package/docs/_navbar.md +0 -14
  449. package/docs/_sidebar.md +0 -2
  450. package/docs/index.html +0 -44
  451. package/eslint.config.js +0 -283
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @fileoverview Numerical stability handler for the es-pairwise-correlation node.
3
+ * Floors negative variances (floating-point guard), recomputes all pairwise
4
+ * correlations from current accumulated state, clamps results, and re-derives
5
+ * Fisher Z transforms when enabled.
6
+ */
7
+ // nodes/es-pairwise-correlation/recompute.js
8
+
9
+ const recompute = function ( state ) {
10
+ // Recompute correlations from current statistics
11
+ // This ensures numerical consistency and fixes any accumulated errors
12
+
13
+ const {
14
+ n, variances, covariances, correlations,
15
+ minVariance, fisherZCap, pairCount
16
+ } = state;
17
+
18
+ // Step 1: Ensure variances are non-negative (fix numerical errors)
19
+ for ( let i = 0; i < n; i += 1 ) {
20
+ if ( variances[ i ] < 0 ) {
21
+ variances[ i ] = 0;
22
+ }
23
+ }
24
+
25
+ // Step 2: Recompute all correlations using direct nested loops
26
+ let idx = 0;
27
+ for ( let i = 0; i < n; i += 1 ) {
28
+ // Pre-compute variance for variable i with protection
29
+ const varX = Math.max( variances[ i ], minVariance );
30
+ const stdX = Math.sqrt( varX );
31
+
32
+ for ( let j = i + 1; j < n; j += 1 ) {
33
+ // Pre-compute variance for variable j with protection
34
+ const varY = Math.max( variances[ j ], minVariance );
35
+ const stdY = Math.sqrt( varY );
36
+
37
+ // Compute correlation from covariance
38
+ const cov = covariances[ idx ];
39
+ correlations[ idx ] = cov / ( stdX * stdY );
40
+
41
+ // Ensure valid range [-1, 1] with Fisher Z cap if applicable
42
+ if ( correlations[ idx ] >= fisherZCap ) {
43
+ correlations[ idx ] = fisherZCap;
44
+ } else if ( correlations[ idx ] <= -fisherZCap ) {
45
+ correlations[ idx ] = -fisherZCap;
46
+ } else if ( Number.isNaN( correlations[ idx ] ) ) {
47
+ // Handle edge case where both variances were zero
48
+ correlations[ idx ] = 0;
49
+ }
50
+
51
+ idx += 1;
52
+ }
53
+ }
54
+
55
+ // Step 3: Recompute Fisher Z transformation if present
56
+ if ( state.fisherZT ) {
57
+ for ( let i = 0; i < pairCount; i += 1 ) {
58
+ const r = correlations[ i ];
59
+ // Fisher Z: 0.5 * ln((1+r)/(1-r))
60
+ // Note: r is already clamped to [-fisherZCap, fisherZCap]
61
+ // so we're guaranteed (1+r)/(1-r) > 0
62
+ state.fisherZT[ i ] = 0.5 * Math.log( ( 1 + r ) / ( 1 - r ) );
63
+ }
64
+ }
65
+
66
+ return true;
67
+ }; // recompute()
68
+
69
+ export default recompute;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @fileoverview Resets all statistical accumulators (means, variances,
3
+ * covariances, correlations) and output values (fisherZT) to their initial
4
+ * state, allowing the node to restart computation from scratch.
5
+ */
6
+ // nodes/es-pairwise-correlation/reset.js
7
+
8
+ const reset = function ( state ) {
9
+ // Reset all statistics to zero
10
+ state.means.fill( 0 );
11
+ state.variances.fill( 0 );
12
+ state.covariances.fill( 0 );
13
+ state.correlations.fill( 0 );
14
+
15
+ if ( state.fisherZT ) {
16
+ state.fisherZT.fill( 0 );
17
+ }
18
+
19
+ // Reset sample counter
20
+ state.sampleCount = 0;
21
+
22
+ // Clear workspace arrays
23
+ state.values.fill( 0 );
24
+ state.deltas.fill( 0 );
25
+
26
+ return true;
27
+ }; // reset()
28
+
29
+ export default reset;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @fileoverview Hot-path exponentially weighted pairwise correlation computation.
3
+ * Uses a Welford-style incremental algorithm with exponential decay on means,
4
+ * variance, and covariance for all n*(n-1)/2 variable pairs. Zero allocations;
5
+ * all reads/writes via the pre-allocated state object.
6
+ */
7
+ // nodes/es-pairwise-correlation/update.js
8
+
9
+ const update = function ( state, msg ) {
10
+ if ( state.disable || state.pause ) return state;
11
+ const {
12
+ x, n, alpha, minVariance,
13
+ values, deltas, means, variances, covariances,
14
+ correlations, fisherZCap, pairCount
15
+ } = state;
16
+
17
+ state.inputValidationFailed = false;
18
+ // Extract and validate & Handle faults gracefully: ensure their isolation
19
+ for ( let i = 0; i < n; i += 1 ) {
20
+ const val = msg[ x[ i ] ];
21
+ if ( val === undefined || val === null ) {
22
+ // Signals publishing NaN for all demanded `stats` in publishTo.
23
+ state.inputValidationFailed = true;
24
+ return state;
25
+ }
26
+ values[ i ] = val;
27
+ if ( !Number.isFinite( values[ i ] ) ) {
28
+ // Signals publishing NaN for all demanded `stats` in publishTo.
29
+ state.inputValidationFailed = true;
30
+ return state;
31
+ }
32
+ }
33
+
34
+ // Initialize on first sample: set means and count, no variance/covariance yet.
35
+ if ( state.sampleCount === 0 ) {
36
+ for ( let i = 0; i < n; i += 1 ) {
37
+ means[ i ] = values[ i ];
38
+ }
39
+ state.sampleCount = 1;
40
+ return state;
41
+ }
42
+
43
+ // Increment sample count for subsequent observations.
44
+ state.sampleCount += 1;
45
+
46
+ // Update deltas, means, variances
47
+ for ( let i = 0; i < n; i += 1 ) {
48
+ deltas[ i ] = values[ i ] - means[ i ];
49
+ means[ i ] += alpha * deltas[ i ];
50
+ variances[ i ] += alpha * ( ( deltas[ i ] * ( values[ i ] - means[ i ] ) ) - variances[ i ] );
51
+ }
52
+
53
+ // Update covariances and correlations
54
+ let idx = 0;
55
+ for ( let i = 0; i < n; i += 1 ) {
56
+ for ( let j = i + 1; j < n; j += 1 ) {
57
+ // Update covariance
58
+ covariances[ idx ] += alpha * ( ( deltas[ i ] * ( values[ j ] - means[ j ] ) ) - covariances[ idx ] );
59
+
60
+ // Compute correlation if ready
61
+ if ( state.sampleCount >= state.minSamples ) {
62
+ const varX = Math.max( variances[ i ], minVariance );
63
+ const varY = Math.max( variances[ j ], minVariance );
64
+ correlations[ idx ] = covariances[ idx ] / Math.sqrt( varX * varY );
65
+
66
+ // Clamp
67
+ if ( correlations[ idx ] >= fisherZCap ) {
68
+ correlations[ idx ] = fisherZCap;
69
+ } else if ( correlations[ idx ] <= -fisherZCap ) {
70
+ correlations[ idx ] = -fisherZCap;
71
+ }
72
+ }
73
+
74
+ idx += 1;
75
+ }
76
+ }
77
+
78
+ // Fisher Z transform if needed
79
+ if ( state.fisherZT && state.sampleCount >= state.minSamples ) {
80
+ for ( let i = 0; i < pairCount; i += 1 ) {
81
+ const r = correlations[ i ];
82
+ state.fisherZT[ i ] = 0.5 * Math.log( ( 1 + r ) / ( 1 - r ) );
83
+ }
84
+ }
85
+
86
+ return state;
87
+ }; // update()
88
+
89
+ export default update;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @fileoverview Barrel module for the esStats node.
3
+ *
4
+ * Re-exports the standard node lifecycle methods (init, update, reset,
5
+ * recompute, publishTo), shared control signals (disable, enable, pause,
6
+ * unpause), and all introspection metadata.
7
+ */
8
+ // nodes/es-stats/index.js
9
+
10
+ export { default as init } from './init.js';
11
+ export { default as update } from './update.js';
12
+ export { default as reset } from './reset.js';
13
+ export { default as recompute } from './recompute.js';
14
+ export { default as publishTo } from './publish-to.js';
15
+ // Direct imports for common control functions
16
+ export { default as disable } from '../../core/utils/node/disable.js';
17
+ export { default as enable } from '../../core/utils/node/enable.js';
18
+ export { default as pause } from '../../core/utils/node/pause.js';
19
+ export { default as unpause } from '../../core/utils/node/unpause.js';
20
+ // Re-export everything from introspection.js
21
+ export * from './introspect.js';
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @fileoverview Initializes esStats node state from a validated spec.
3
+ *
4
+ * Derives the exponential smoothing factor (alpha) from halfLife, pre-allocates
5
+ * all statistical accumulators on a prototype-free state object, and determines
6
+ * which computation paths (Welford for mean/variance, envelope for floor/ceiling)
7
+ * are required by the requested stats. All allocation happens here; the hot path
8
+ * is zero-allocation.
9
+ */
10
+ // nodes/es-stats/init.js
11
+
12
+ import { validateSpec } from '../../core/utils/node/index.js';
13
+ import * as introspect from './introspect.js';
14
+ import { halfLifeToAlpha } from '../../core/utils/half-life/index.js';
15
+ import { resolveScalar } from '../../core/utils/options/resolve-field-keyed.js';
16
+
17
+ /**
18
+ * Initialize ES Stats node with comprehensive streaming statistics.
19
+ *
20
+ * @param {Object} spec - Node specification
21
+ * @returns {Object} Initial state for statistics computation
22
+ */
23
+ const init = function ( spec ) {
24
+ // Validate against schema
25
+ validateSpec( spec, introspect );
26
+
27
+ // Create state after validation passes
28
+ const state = Object.create( null );
29
+ // Standard input parameter health flag during update: false means healthy
30
+ state.inputValidationFailed = false;
31
+ // Ensure node is enabled by default
32
+ state.disable = false;
33
+ state.pause = false;
34
+
35
+ // Input field
36
+ state.x = spec.from.x;
37
+
38
+ // Config copy for output field mapping
39
+ const stats = spec.stats;
40
+ state.stats = stats;
41
+
42
+ // Half-life configuration with defaults
43
+ // Supports both direct: { halfLife: 20 } and field-keyed: { halfLife: { temp: 5, pressure: 20 } }
44
+ const defaults = introspect.DEFAULT_OPTIONS;
45
+ const halfLifeSpec = resolveScalar( spec.halfLife, state.x );
46
+ state.halfLife = halfLifeSpec ?? defaults.halfLife;
47
+
48
+ // Convert half-life to alpha for hot-path efficiency
49
+ state.alpha = halfLifeToAlpha( state.halfLife );
50
+ state.decay = 1 - state.alpha; // Pre-compute for efficiency
51
+
52
+ // Biased/unbiased estimator choice
53
+ state.biased = spec.biased ?? defaults.biased;
54
+
55
+ // Constants
56
+ state.EPS = 1e-12;
57
+ state.snrDbCap = 60;
58
+ state.cvLarge = 1e6;
59
+
60
+ // Core statistics (Welford's algorithm)
61
+ state.mean = 0;
62
+ state.m2 = 0; // Sum of squared deviations
63
+ state.variance = 0;
64
+ state.stdev = 0;
65
+
66
+ // Envelope statistics (leaky min/max)
67
+ state.floor = 0;
68
+ state.ceiling = 0;
69
+ state.envelope = 0;
70
+ state.mid = 0;
71
+
72
+ // Signal quality metrics
73
+ state.snrDB = 0;
74
+ state.cv = 0;
75
+
76
+ // Current value scores
77
+ state.zScore = 0;
78
+ state.envScore = 0;
79
+
80
+ // Warmup normalization for unbiased mode
81
+ state.weightSum = 0; // Sum of exponentially smoothed weights: 1 - (1 - alpha)^t
82
+
83
+ // Sample counter
84
+ state.sampleCount = 0;
85
+
86
+ // Determine computation paths needed
87
+ state.needsWelford = stats.mean !== undefined ||
88
+ stats.variance !== undefined ||
89
+ stats.stdev !== undefined ||
90
+ stats.snrDB !== undefined ||
91
+ stats.cv !== undefined ||
92
+ stats.zScore !== undefined;
93
+
94
+ state.needsEnvelope = stats.floor !== undefined ||
95
+ stats.ceiling !== undefined ||
96
+ stats.envelope !== undefined ||
97
+ stats.mid !== undefined ||
98
+ stats.envScore !== undefined;
99
+
100
+ state.nodeType = introspect.getNodeType();
101
+
102
+ return state;
103
+ }; // init()
104
+
105
+ export default init;
@@ -0,0 +1,157 @@
1
+ /**
2
+ * @fileoverview Single source of truth for esStats node metadata.
3
+ *
4
+ * Exports supported stats (11 metrics across Welford, envelope, and
5
+ * signal-quality categories), human-readable stat descriptions, control
6
+ * methods, node capabilities, default options, and the DSL spec schema
7
+ * with validators. All getter functions return defensive copies.
8
+ */
9
+ // nodes/es-stats/introspect.js
10
+
11
+ import { validators, composerValidators } from '../../core/utils/validate/index.js';
12
+
13
+ /** Single source of truth for what this plugin can do */
14
+ const SUPPORTED_STATS = [
15
+ // Core Statistics (Welford's algorithm)
16
+ 'mean',
17
+ 'variance',
18
+ 'stdev',
19
+
20
+ // Envelope Statistics (Leaky min/max)
21
+ 'floor',
22
+ 'ceiling',
23
+ 'envelope',
24
+ 'mid',
25
+
26
+ // Signal Quality Metrics
27
+ 'snrDB',
28
+ 'cv',
29
+
30
+ // Current Value Scores (computed per sample)
31
+ 'zScore',
32
+ 'envScore'
33
+ ];
34
+
35
+ /** Human-readable descriptions (for introspection) */
36
+ const STAT_DESCRIPTIONS = {
37
+ mean: 'Exponentially smoothed mean',
38
+ variance: 'Exponentially smoothed variance (Welford\'s algorithm)',
39
+ stdev: 'Square root of variance',
40
+ floor: 'Recent minimum with exponential decay (envelope follower)',
41
+ ceiling: 'Recent maximum with exponential decay (envelope follower)',
42
+ envelope: 'Signal envelope width (ceiling - floor)',
43
+ mid: 'Envelope midpoint ((floor + ceiling) / 2)',
44
+ snrDB: 'Signal-to-noise ratio in dB (20*log10(|mean|/stdev))',
45
+ cv: 'Coefficient of variation (stdev/|mean|)',
46
+ zScore: 'Normalized deviation of current value ((x - mean)/stdev)',
47
+ envScore: 'Envelope-normalized score ((x - mid)/(envelope/2))'
48
+ };
49
+
50
+ /** Control methods available for triggers */
51
+ const SUPPORTED_CONTROL_METHODS = {
52
+ reset: 'Clears accumulated state and restarts computation',
53
+ enable: 'Enables node processing',
54
+ disable: 'Disables node processing',
55
+ pause: 'Pauses node processing while keeping state visible',
56
+ unpause: 'Resumes node processing after pause'
57
+ };
58
+
59
+ /** The type of this node */
60
+ const NODE_TYPE = 'ES Stats';
61
+
62
+ /** Node capabilities for documentation */
63
+ const CAPABILITIES = {
64
+ description: 'Comprehensive exponentially weighted statistics for streaming signals',
65
+ features: [
66
+ 'Numerically stable Welford\'s algorithm for mean/variance',
67
+ 'Leaky envelope tracking (floor/ceiling) with fast attack/slow release',
68
+ 'Signal quality metrics (SNR, CV)',
69
+ 'Real-time anomaly scores (z-score, envelope score)',
70
+ 'No allocations in hot path',
71
+ 'Single half-life for consistent weighting'
72
+ ]
73
+ };
74
+
75
+ // Export functions for accessing metadata
76
+ export const getSupportedStats = () => SUPPORTED_STATS.slice();
77
+ export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
78
+ export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
79
+ export const getNodeType = () => NODE_TYPE;
80
+ export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
81
+
82
+ export const DEFAULT_OPTIONS = {
83
+ halfLife: 10,
84
+ biased: false
85
+ };
86
+
87
+ // DSL Metadata for transpilation
88
+ const DSL_METADATA = {
89
+ // Full spec schema for validation
90
+ specSchema: {
91
+ nodeType: {
92
+ type: 'string',
93
+ required: true,
94
+ value: NODE_TYPE
95
+ },
96
+ name: {
97
+ type: 'string',
98
+ required: true,
99
+ validator: validators.identifier,
100
+ error: 'Name must be a valid identifier'
101
+ },
102
+ from: {
103
+ type: 'object',
104
+ required: true,
105
+ properties: {
106
+ x: {
107
+ type: 'string',
108
+ required: true,
109
+ validator: validators.noSpaces,
110
+ error: 'Field name cannot contain spaces'
111
+ }
112
+ }
113
+ },
114
+ halfLife: {
115
+ type: 'numberOrFieldKeyed',
116
+ required: false,
117
+ default: DEFAULT_OPTIONS.halfLife,
118
+ validator: composerValidators.halfLife,
119
+ error: 'halfLife must be > 0 and < 999999'
120
+ },
121
+ biased: {
122
+ type: 'boolean',
123
+ required: false,
124
+ default: DEFAULT_OPTIONS.biased
125
+ },
126
+ stats: {
127
+ type: 'object',
128
+ required: true,
129
+ minProperties: 1,
130
+ propertyNames: SUPPORTED_STATS,
131
+ propertySchema: {
132
+ type: 'object',
133
+ properties: {
134
+ storeAs: {
135
+ type: 'string',
136
+ required: true,
137
+ validator: validators.identifier,
138
+ error: 'storeAs must be a valid identifier'
139
+ }
140
+ }
141
+ }
142
+ }
143
+ },
144
+
145
+ // Build spec from DSL parameters
146
+ // Pattern: NAME_X_OUTPUTS_OPTIONS -> (name, x, stats, options)
147
+ buildSpec: ( name, x, stats, options ) => ( {
148
+ nodeType: NODE_TYPE,
149
+ name,
150
+ from: { x },
151
+ stats,
152
+ ...options
153
+ } ),
154
+
155
+ };
156
+
157
+ export const getDSLMetadata = () => ( { ...DSL_METADATA } );
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @fileoverview Copies requested esStats statistics onto the message for
3
+ * downstream consumption.
4
+ *
5
+ * Propagates NaN for all configured stats when input validation has failed.
6
+ * Gates output until the warmup period (3 samples) is complete to ensure
7
+ * statistical meaningfulness. Iterates only over stats declared in the spec;
8
+ * zero allocations on the hot path.
9
+ */
10
+ // nodes/es-stats/publish-to.js
11
+
12
+ import { publishNaN } from '../../core/utils/node/index.js';
13
+
14
+ /**
15
+ * Publish computed statistics to message.
16
+ * Only publishes stats that were requested and after warmup.
17
+ *
18
+ * @param {Object} state - Node state with computed statistics
19
+ * @param {Object} msg - Message to annotate with outputs
20
+ */
21
+ const publishTo = function ( state, msg ) {
22
+ if ( state.disable ) return;
23
+ // Propagate NaN if unhealthy
24
+ if ( state.inputValidationFailed ) {
25
+ publishNaN( state, msg );
26
+ return;
27
+ }
28
+ // Only publish after at least 3 samples for statistical meaning
29
+ if ( state.sampleCount < 3 ) {
30
+ return;
31
+ }
32
+
33
+ // Iterate only over configured stats
34
+ const stats = state.stats;
35
+ for ( const statName in stats ) {
36
+ if ( Object.prototype.hasOwnProperty.call( stats, statName ) ) {
37
+ msg[ stats[ statName ].storeAs ] = state[ statName ];
38
+ }
39
+ }
40
+ }; // publishTo()
41
+
42
+ export default publishTo;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @fileoverview Numerical stability handler for the esStats node.
3
+ *
4
+ * Floors negative m2 and variance to zero, corrects inverted floor/ceiling
5
+ * order, and recomputes variance from m2 using the appropriate normalization
6
+ * (biased or unbiased). On catastrophic NaN/Infinity in critical state fields,
7
+ * triggers a full reset. Since exponentially weighted statistics have inherently
8
+ * bounded state (each update is a weighted blend, not unbounded accumulation),
9
+ * consistency corrections suffice — no sample buffer is available for full
10
+ * recomputation.
11
+ */
12
+ // nodes/es-stats/recompute.js
13
+
14
+ import reset from './reset.js';
15
+
16
+ /**
17
+ * Recompute statistics from current state to ensure numerical consistency.
18
+ * Handles numerical drift in long-running streams.
19
+ *
20
+ * @param {Object} state - Node state
21
+ * @returns {boolean} Always true (successful recomputation)
22
+ */
23
+ const recompute = function ( state ) {
24
+ // Ensure m2 is non-negative (second moment)
25
+ if ( state.m2 < 0 ) {
26
+ state.m2 = 0;
27
+ }
28
+
29
+ // Ensure variance is non-negative
30
+ if ( state.variance < 0 ) {
31
+ state.variance = 0;
32
+ state.stdev = 0;
33
+ }
34
+
35
+ const stats = state.stats;
36
+ // Recompute variance from m2 to ensure consistency
37
+ if ( state.sampleCount >= 2 && stats.variance !== undefined ) {
38
+ if ( state.biased ) {
39
+ state.variance = state.m2;
40
+ } else {
41
+ const w = state.weightSum;
42
+ state.variance = ( w > 1e-12 ) ? ( state.m2 / w ) : state.m2;
43
+ }
44
+ state.stdev = Math.sqrt( state.variance );
45
+ }
46
+
47
+ // Ensure envelope consistency
48
+ if ( stats.envelope !== undefined ) {
49
+ // Floor should not exceed ceiling
50
+ if ( state.floor > state.ceiling ) {
51
+ const temp = state.floor;
52
+ state.floor = state.ceiling;
53
+ state.ceiling = temp;
54
+ }
55
+
56
+ // Recompute derived envelope metrics
57
+ state.envelope = state.ceiling - state.floor;
58
+ state.mid = ( state.floor + state.ceiling ) * 0.5;
59
+ }
60
+
61
+ // Check for NaN and reset if found
62
+ if ( !Number.isFinite( state.mean ) ||
63
+ !Number.isFinite( state.variance ) ||
64
+ !Number.isFinite( state.floor ) ||
65
+ !Number.isFinite( state.ceiling ) ) {
66
+ // Catastrophic numerical failure - reset
67
+ reset( state );
68
+ return true;
69
+ }
70
+
71
+ return true;
72
+ }; // recompute()
73
+
74
+ export default recompute;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @fileoverview Resets all esStats accumulated state to its pre-observation
3
+ * condition.
4
+ *
5
+ * Clears mean, m2, variance, stdev, envelope metrics, signal-quality scores,
6
+ * weightSum, and sampleCount. Configuration (alpha, decay, halfLife, biased,
7
+ * stats, computation-path flags) is preserved so the next observation seeds
8
+ * the estimate afresh. Returns true per ADR-004 control-signal contract.
9
+ */
10
+ // nodes/es-stats/reset.js
11
+
12
+ /**
13
+ * Reset all statistical accumulators to initial state.
14
+ * Called by control signals to restart statistics tracking.
15
+ *
16
+ * @param {Object} state - Node state to reset
17
+ * @returns {boolean} Always true (ADR-004)
18
+ */
19
+ const reset = function ( state ) {
20
+ // Reset core statistics
21
+ state.mean = 0;
22
+ state.m2 = 0;
23
+ state.variance = 0;
24
+ state.stdev = 0;
25
+
26
+ // Reset envelope statistics
27
+ state.floor = 0;
28
+ state.ceiling = 0;
29
+ state.envelope = 0;
30
+ state.mid = 0;
31
+
32
+ // Reset signal quality
33
+ state.snrDB = 0;
34
+ state.cv = 0;
35
+
36
+ // Reset current value scores
37
+ state.zScore = 0;
38
+ state.envScore = 0;
39
+
40
+ // Reset weight accumulator
41
+ state.weightSum = 0;
42
+
43
+ // Reset sample counter
44
+ state.sampleCount = 0;
45
+
46
+ return true;
47
+ }; // reset()
48
+
49
+ export default reset;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @fileoverview Leaky envelope follower with fast-attack / slow-release
3
+ * semantics for the esStats node.
4
+ *
5
+ * New extremes are adopted immediately (fast attack); non-extreme values
6
+ * relax floor/ceiling toward the current value at rate alpha (slow release).
7
+ * Computes envelope width (ceiling - floor), midpoint, and envScore
8
+ * (normalized distance from midpoint, unclamped to preserve severity).
9
+ *
10
+ * Zero allocations; all reads/writes via the pre-allocated state object.
11
+ */
12
+ // nodes/es-stats/update-envelope.js
13
+
14
+ const updateEnvelope = function ( state, xVal ) {
15
+ // Envelope Score: Normalized distance from range midpoint
16
+ // Score = (value - mid) / halfRange; 0=center, ±1=bounds, >1=outside
17
+ // Computed BEFORE update to detect range breakouts
18
+ // Unclamped to preserve severity (e.g., score=3 means 3x beyond normal)
19
+ if ( state.stats.envScore ) {
20
+ const halfEnv = state.envelope * 0.5;
21
+ state.envScore = ( halfEnv > state.EPS ) ?
22
+ ( ( xVal - state.mid ) / halfEnv ) : 0;
23
+ // optional clamp:
24
+ // state.envScore = Math.max( -1, Math.min( 1, state.envScore ) );
25
+ }
26
+
27
+ // NOW update envelope with fast-attack/slow-release
28
+ if ( xVal < state.floor ) {
29
+ state.floor = xVal;
30
+ } else {
31
+ state.floor += ( state.alpha * ( xVal - state.floor ) );
32
+ }
33
+
34
+ if ( xVal > state.ceiling ) {
35
+ state.ceiling = xVal;
36
+ } else {
37
+ state.ceiling -= ( state.alpha * ( state.ceiling - xVal ) );
38
+ }
39
+
40
+ state.envelope = state.ceiling - state.floor;
41
+ state.mid = ( state.floor + state.ceiling ) * 0.5;
42
+ }; // updateEnvelope()
43
+
44
+ export default updateEnvelope;