@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,250 @@
1
+ /**
2
+ * @fileoverview Introspection metadata for kalman1d node.
3
+ *
4
+ * Defines supported stats, control methods, capabilities, DSL schema,
5
+ * and default options. All getters return defensive copies.
6
+ *
7
+ * The kalman1d node is a 1-D Kalman filter for model-based state estimation
8
+ * with statistical outlier detection via an innovation gate (chi-squared test).
9
+ *
10
+ * **Compositional value — the innovation signal:**
11
+ * The node's primary differentiator is publishing the innovation (prediction
12
+ * error) as a first-class stat. This enables powerful downstream compositions:
13
+ *
14
+ * - **innovation → appraise**: Detect "temperature is SURPRISING given the
15
+ * current draw" rather than "temperature is high" — the Kalman model
16
+ * accounts for expected variation from control inputs, leaving only the
17
+ * unexplained component as anomaly evidence.
18
+ *
19
+ * - **innovation → esStats → threshold**: Monitor mean(|innovation|) over
20
+ * time to detect model mismatch and trigger recalibration.
21
+ *
22
+ * - **innovationGate → predict**: Classify the PATTERN of normalized
23
+ * surprises across multiple signals for fault diagnosis.
24
+ *
25
+ * - **ghost + innovation**: In shadow partitions, innovation grows as
26
+ * simulated degradation diverges — enabling data-driven prognosis.
27
+ *
28
+ * **Control input generalization:**
29
+ * "Control" is not limited to actuator commands — it is any measurable causal
30
+ * influence: fuel rate → tank level, occupancy → CO2, current → temperature.
31
+ * This makes Kalman applicable wherever an approximate physical model exists.
32
+ */
33
+
34
+ import { validators } from '../../core/utils/validate/index.js';
35
+
36
+ // ── Supported Features ──────────────────────────────────────────────────────
37
+
38
+ const SUPPORTED_STATS = [ 'filtered', 'variance', 'innovation', 'innovationGate' ];
39
+
40
+ const STAT_DESCRIPTIONS = {
41
+ filtered: 'Optimal state estimate (Kalman-filtered value)',
42
+ variance: 'Estimation error covariance — quantifies uncertainty in the estimate',
43
+ innovation: 'Prediction error (signed): z - H·xHat. The anomaly signal — ' +
44
+ 'feeds appraise for surprise detection, esStats for model monitoring',
45
+ innovationGate: 'Normalized innovation squared (chi-squared(1) statistic). ' +
46
+ 'Unitless anomaly score — directly thresholdable with known false-alarm rates'
47
+ };
48
+
49
+ const SUPPORTED_CONTROL_METHODS = {
50
+ reset: 'Clears accumulated state; next measurement auto-initializes',
51
+ enable: 'Enables node processing',
52
+ disable: 'Disables node processing',
53
+ pause: 'Pauses node processing while keeping state visible',
54
+ unpause: 'Resumes node processing after pause'
55
+ };
56
+
57
+ const NODE_TYPE = 'Kalman 1d';
58
+
59
+ const CAPABILITIES = {
60
+ description: 'Model-based state estimation with statistical outlier detection via innovation gating',
61
+ features: [
62
+ 'Optimal state estimation for linear systems with Gaussian noise',
63
+ 'Control-aware prediction using any causal influence as input',
64
+ 'Innovation signal as first-class output for downstream anomaly detection',
65
+ 'Statistical outlier detection via Mahalanobis distance (chi-squared gate)',
66
+ 'Dual-mode operation: exclude outliers OR track sudden changes (follow mode)',
67
+ 'Gap-tolerant prediction with bounded uncertainty growth',
68
+ 'Auto-initialization from first measurement',
69
+ 'Variance floor prevents filter lock on long-running streams'
70
+ ]
71
+ };
72
+
73
+ // ── Getter Functions (defensive copies) ─────────────────────────────────────
74
+
75
+ export const getSupportedStats = () => SUPPORTED_STATS.slice();
76
+ export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
77
+ export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
78
+ export const getNodeType = () => NODE_TYPE;
79
+ export const getCapabilities = () => ( {
80
+ ...CAPABILITIES,
81
+ features: CAPABILITIES.features.slice()
82
+ } );
83
+
84
+ // ── Default Options ─────────────────────────────────────────────────────────
85
+
86
+ export const DEFAULT_OPTIONS = {
87
+ sensorVariance: 1,
88
+ processVariance: 0.01,
89
+ chi2Threshold: 6.63,
90
+ followMode: false,
91
+ stateTransition: 1,
92
+ measurement: 1,
93
+ controlModel: 0,
94
+ varianceLimit: 100
95
+ };
96
+
97
+ // ── DSL Metadata ────────────────────────────────────────────────────────────
98
+
99
+ const DSL_METADATA = {
100
+ specSchema: {
101
+ nodeType: {
102
+ type: 'string',
103
+ required: true,
104
+ value: NODE_TYPE
105
+ },
106
+ name: {
107
+ type: 'string',
108
+ required: true,
109
+ validator: validators.identifier,
110
+ error: 'name must be a valid identifier'
111
+ },
112
+ from: {
113
+ type: 'object',
114
+ required: true,
115
+ properties: {
116
+ x: {
117
+ type: 'string',
118
+ required: true,
119
+ validator: validators.noSpaces,
120
+ error: 'from.x must not contain spaces'
121
+ }
122
+ }
123
+ },
124
+
125
+ // ── Control input field (optional) ──────────────────────────
126
+ // Any measurable causal influence: heater power, fuel rate,
127
+ // motor current, occupancy. Not just actuator commands.
128
+ control: {
129
+ type: 'string',
130
+ required: false,
131
+ validator: validators.noSpaces,
132
+ error: 'control field name must not contain spaces'
133
+ },
134
+
135
+ // ── Noise covariances ───────────────────────────────────────
136
+ // R: measurement noise variance, in measurement² units. The
137
+ // expected variance of the sensor noise on each measurement.
138
+ // Per-sensor via field-keyed objects.
139
+ sensorVariance: {
140
+ type: 'numberOrFieldKeyed',
141
+ required: false,
142
+ default: DEFAULT_OPTIONS.sensorVariance,
143
+ validator: validators.positive,
144
+ error: 'sensorVariance must be positive'
145
+ },
146
+ // Q: process noise variance, in state² units. The expected
147
+ // variance of the unmodeled change in state from one step to
148
+ // the next. Used directly in the predict step (PPred = F·P·F + Q).
149
+ // Larger Q → filter trusts new measurements more (responsive).
150
+ // Smaller Q → filter trusts its model more (smoother).
151
+ processVariance: {
152
+ type: 'numberOrFieldKeyed',
153
+ required: false,
154
+ default: DEFAULT_OPTIONS.processVariance,
155
+ validator: validators.positive,
156
+ error: 'processVariance must be positive'
157
+ },
158
+
159
+ // ── Outlier detection ───────────────────────────────────────
160
+ // Chi-squared(1) threshold for innovation gate.
161
+ // 3.84 = 95%, 6.63 = 99%, 10.84 = 99.9%
162
+ chi2Threshold: {
163
+ type: 'numberOrFieldKeyed',
164
+ required: false,
165
+ default: DEFAULT_OPTIONS.chi2Threshold,
166
+ validator: validators.positive,
167
+ error: 'chi2Threshold must be positive'
168
+ },
169
+ // Follow mode tracks jumps; exclude mode rejects outliers.
170
+ followMode: {
171
+ type: 'boolean',
172
+ required: false,
173
+ default: DEFAULT_OPTIONS.followMode
174
+ },
175
+
176
+ // ── State-space model coefficients ──────────────────────────
177
+ // F: state transition (how state evolves between measurements).
178
+ // Default 1 = random walk / constant-state model.
179
+ stateTransition: {
180
+ type: 'number',
181
+ required: false,
182
+ default: DEFAULT_OPTIONS.stateTransition
183
+ },
184
+ // H: measurement model (how state appears in measurements).
185
+ // Default 1 = direct observation. H=0 is never valid — makes
186
+ // the state unobservable and causes division by zero in update.
187
+ measurement: {
188
+ type: 'number',
189
+ required: false,
190
+ default: DEFAULT_OPTIONS.measurement,
191
+ validator: validators.nonZero,
192
+ error: 'measurement (H) must be nonzero'
193
+ },
194
+ // G: control coefficient. Can be zero (no control), positive
195
+ // (e.g., heater adding heat), or negative (e.g., fuel consumption
196
+ // depleting tank level). Per-sensor via field-keyed objects.
197
+ controlModel: {
198
+ type: 'numberOrFieldKeyed',
199
+ required: false,
200
+ default: DEFAULT_OPTIONS.controlModel
201
+ },
202
+
203
+ // ── Numerical safeguards ────────────────────────────────────
204
+ // Pmax = varianceLimit * R. Bounds uncertainty growth during
205
+ // prediction-only periods (missing data, gaps).
206
+ varianceLimit: {
207
+ type: 'number',
208
+ required: false,
209
+ default: DEFAULT_OPTIONS.varianceLimit,
210
+ validator: validators.positive,
211
+ error: 'varianceLimit must be positive'
212
+ },
213
+
214
+ // ── Output configuration ────────────────────────────────────
215
+ stats: {
216
+ type: 'object',
217
+ required: true,
218
+ propertyNames: SUPPORTED_STATS,
219
+ propertySchema: {
220
+ type: 'object',
221
+ required: true,
222
+ properties: {
223
+ storeAs: {
224
+ type: 'string',
225
+ required: true,
226
+ validator: validators.identifier,
227
+ error: 'storeAs must be a valid identifier'
228
+ }
229
+ }
230
+ }
231
+ }
232
+ },
233
+
234
+ // No cross-field constraints needed:
235
+ // - controlModel != 0 without `control` is valid (control defaults to 0)
236
+ // - All parameter combinations are mathematically valid
237
+ crossFieldValidators: [],
238
+
239
+ // Pattern: nameXOutputsOptions
240
+ // DSL: .kalman1d( name, field, { filtered: 'est' }, { control: 'power' } )
241
+ buildSpec: ( name, x, stats, options ) => ( {
242
+ nodeType: NODE_TYPE,
243
+ name,
244
+ from: { x },
245
+ stats,
246
+ ...options
247
+ } )
248
+ };
249
+
250
+ export const getDSLMetadata = () => ( { ...DSL_METADATA } );
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @fileoverview Publish function for kalman1d node.
3
+ *
4
+ * Copies computed state values to the output message, or propagates NaN
5
+ * if the last input was invalid. Skipped entirely when disabled.
6
+ *
7
+ * All four stats (filtered, variance, innovation, innovationGate) are
8
+ * published on every tick — including after outlier exclusion. This is
9
+ * intentional: innovation reflects what reality looked like (measurement-
10
+ * space), while filtered/variance reflect the predict-only state. Downstream
11
+ * nodes (appraise, esStats, predict) need the innovation from excluded
12
+ * measurements to detect model mismatch and build anomaly conviction.
13
+ */
14
+
15
+ import { publishNaN } from '../../core/utils/node/index.js';
16
+
17
+ const publishTo = function ( state, msg ) {
18
+ if ( state.disable ) return;
19
+
20
+ // Propagate NaN if unhealthy (fault isolation)
21
+ if ( state.inputValidationFailed ) {
22
+ publishNaN( state, msg );
23
+ return;
24
+ }
25
+
26
+ // Publish only the stats the user requested
27
+ const stats = state.stats;
28
+ if ( stats.filtered ) msg[ stats.filtered.storeAs ] = state.xHat;
29
+ if ( stats.variance ) msg[ stats.variance.storeAs ] = state.P;
30
+ if ( stats.innovation ) msg[ stats.innovation.storeAs ] = state.innovation;
31
+ if ( stats.innovationGate ) msg[ stats.innovationGate.storeAs ] = state.innovationGate;
32
+ }; // publishTo()
33
+
34
+ export default publishTo;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @fileoverview Recompute for kalman1d node.
3
+ *
4
+ * Clamps the estimation error covariance P to [Pmin, Pmax]. The update()
5
+ * function already clamps after prediction, but recompute provides a periodic
6
+ * safety net for very long-running pipelines where floating-point drift could
7
+ * push P outside its valid bounds.
8
+ *
9
+ * Unlike butterworth-filter (which is a no-op), Kalman's recompute is active
10
+ * because the covariance evolves recursively and is susceptible to long-term
11
+ * drift in edge cases (e.g., extended prediction-only periods with near-zero
12
+ * process noise).
13
+ */
14
+
15
+ const recompute = function ( state ) {
16
+ // Clamp covariance to valid range
17
+ if ( state.P > state.Pmax ) state.P = state.Pmax;
18
+ if ( state.P < state.Pmin ) state.P = state.Pmin;
19
+
20
+ return true;
21
+ }; // recompute()
22
+
23
+ export default recompute;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @fileoverview Reset for kalman1d node.
3
+ *
4
+ * Clears all accumulated state to pre-first-measurement condition. The next
5
+ * valid measurement will auto-initialize the filter (xHat = z/H, P = R/H²).
6
+ *
7
+ * Idempotent: multiple reset() calls produce the same state as a single call.
8
+ * Model parameters (R, Q, F, G, H, thresholds) are preserved — only the
9
+ * estimation state is cleared.
10
+ */
11
+
12
+ const reset = function ( state ) {
13
+ // ── Estimation state ────────────────────────────────────────────────
14
+ state.xHat = 0;
15
+ state.P = 0;
16
+ state.isInitialized = false;
17
+
18
+ // ── Innovation outputs ──────────────────────────────────────────────
19
+ state.innovation = 0;
20
+ state.innovationGate = 0;
21
+
22
+ // ── Diagnostics ─────────────────────────────────────────────────────
23
+ state.updateCount = 0;
24
+ state.outlierCount = 0;
25
+
26
+ return true;
27
+ }; // reset()
28
+
29
+ export default reset;
@@ -0,0 +1,144 @@
1
+ /**
2
+ * @fileoverview Core Kalman filter algorithm for kalman1d node (hot path).
3
+ *
4
+ * Implements the standard 1-D Kalman filter: predict → innovate → gate →
5
+ * update/exclude/follow. Zero allocations — all scalar arithmetic.
6
+ *
7
+ * **Why innovation is stored BEFORE the gate branch:**
8
+ *
9
+ * Innovation (prediction error) is a measurement-space signal about reality,
10
+ * not a filter-state signal about the filter's decision. When the filter
11
+ * excludes an outlier, the innovation that triggered the exclusion is itself
12
+ * valuable diagnostic information for downstream nodes:
13
+ *
14
+ * 1. **innovation → appraise**: "Temperature is SURPRISING given the heater
15
+ * power" — the Kalman model accounts for expected heating; only the
16
+ * UNEXPLAINED component triggers appraise conviction. Excluded outlier
17
+ * innovation tells appraise about a real event the filter chose to ignore.
18
+ *
19
+ * 2. **innovation → esStats → threshold**: Sustained mean(|innovation|)
20
+ * detects model mismatch. If we suppressed innovation on excluded
21
+ * measurements, esStats would underestimate the mismatch.
22
+ *
23
+ * 3. **innovation → predict (fault classification)**: Classify the PATTERN
24
+ * of surprises across multiple Kalman-filtered signals. Missing the
25
+ * outlier innovation breaks the pattern.
26
+ *
27
+ * 4. **ghost + innovation**: In shadow partitions running degradation
28
+ * scenarios, innovation grows as the perturbation diverges from the
29
+ * real model — enabling data-driven prognosis without a physics model.
30
+ *
31
+ * 5. **Signed innovation + control direction**: "Positive innovation with
32
+ * negative control input = external heat source" — directional
33
+ * diagnostics require the raw signed innovation even on excluded ticks.
34
+ *
35
+ * References:
36
+ * - Bar-Shalom, Li, Kirubarajan, "Estimation with Applications to Tracking
37
+ * and Navigation" (Wiley, 2001), Ch. 5: 1-D Kalman filter, innovation gate.
38
+ * - Mahalanobis distance ≡ |innovation|/√S; innovationGate = D² ~ χ²(1).
39
+ */
40
+
41
+ const DENORMAL_THRESHOLD = 1e-30;
42
+
43
+ const update = function ( state, msg ) {
44
+ // ── Guard ───────────────────────────────────────────────────────────
45
+ if ( state.disable || state.pause ) return state;
46
+
47
+ const z = msg[ state.x ];
48
+
49
+ // Reset health flag on each update
50
+ state.inputValidationFailed = false;
51
+
52
+ // ── Fault handling: NaN, Infinity, undefined ────────────────────────
53
+ // Missing data → prediction-only: covariance grows (via the predict
54
+ // step on the next valid measurement), innovation is NaN downstream.
55
+ if ( !Number.isFinite( z ) ) {
56
+ state.inputValidationFailed = true;
57
+ return state;
58
+ }
59
+
60
+ // ── Control input (optional, defaults to 0) ─────────────────────────
61
+ // When absent or invalid, no control influence this tick.
62
+ // "Control" = any measurable causal influence, not just actuators:
63
+ // fuel rate → tank level, occupancy → CO₂, current → temperature.
64
+ const u = state.controlField ? ( msg[ state.controlField ] ?? 0 ) : 0;
65
+ const uSafe = Number.isFinite( u ) ? u : 0;
66
+
67
+ // ── Auto-initialize from first measurement ──────────────────────────
68
+ // No prior estimate needed: x₀ = z/H, P₀ = R/H².
69
+ // Innovation is 0 (no prediction to compare against).
70
+ if ( !state.isInitialized ) {
71
+ state.xHat = z / state.H;
72
+ state.P = state.R / ( state.H * state.H );
73
+ state.innovation = 0;
74
+ state.innovationGate = 0;
75
+ state.isInitialized = true;
76
+ state.updateCount += 1;
77
+ return state;
78
+ }
79
+
80
+ // ── PREDICT ─────────────────────────────────────────────────────────
81
+ // State prediction: x̂(k|k-1) = F·x̂(k-1) + G·u(k)
82
+ // Covariance prediction: P(k|k-1) = F·P(k-1)·F + Q
83
+ const xPred = ( state.F * state.xHat ) + ( state.G * uSafe );
84
+ let PPred = ( state.F * state.P * state.F ) + state.Q;
85
+
86
+ // Clamp covariance to valid range
87
+ if ( PPred > state.Pmax ) PPred = state.Pmax;
88
+ if ( PPred < state.Pmin ) PPred = state.Pmin;
89
+
90
+ // ── INNOVATE (always computed, always stored) ───────────────────────
91
+ // Innovation: ν = z - H·x̂(k|k-1)
92
+ // Innovation covariance: S = H·P(k|k-1)·H + R
93
+ // Innovation gate: ν²/S ~ χ²(1) when model is correct
94
+ const innovation = z - ( state.H * xPred );
95
+ const S = ( state.H * PPred * state.H ) + state.R;
96
+ const innovationGate = ( innovation * innovation ) / S;
97
+
98
+ // Store BEFORE branching — downstream always sees what reality
99
+ // looked like, regardless of the filter's gate decision.
100
+ state.innovation = innovation;
101
+ state.innovationGate = innovationGate;
102
+
103
+ // ── OUTLIER GATE ────────────────────────────────────────────────────
104
+ // Mahalanobis distance² > χ²(1) threshold → statistically unlikely
105
+ if ( innovationGate > state.chi2Threshold ) {
106
+ state.outlierCount += 1;
107
+
108
+ if ( state.followMode ) {
109
+ // Follow mode: reset estimate to track the jump.
110
+ // Use case: systems with legitimate step changes (valve
111
+ // positions, load changes, operating mode switches).
112
+ state.xHat = z / state.H;
113
+ state.P = state.R / ( state.H * state.H );
114
+ } else {
115
+ // Exclude mode: reject measurement, advance with prediction.
116
+ // Time marches on — xHat and P reflect the predict-only state.
117
+ // Innovation IS published (stored above) so downstream sees
118
+ // the anomalous measurement even though the filter ignored it.
119
+ // Use case: continuous processes where outliers are sensor
120
+ // glitches (temperature, pressure, tank level).
121
+ state.xHat = xPred;
122
+ state.P = PPred;
123
+ state.updateCount += 1;
124
+ return state;
125
+ }
126
+ } else {
127
+ // ── NORMAL KALMAN UPDATE ────────────────────────────────────
128
+ // Kalman gain: K = P(k|k-1)·H / S
129
+ // State update: x̂(k) = x̂(k|k-1) + K·ν
130
+ // Covariance update: P(k) = (1 - K·H)·P(k|k-1)
131
+ const K = ( PPred * state.H ) / S;
132
+ state.xHat = xPred + ( K * innovation );
133
+ state.P = ( 1 - ( K * state.H ) ) * PPred;
134
+ }
135
+
136
+ // ── Denormal flushing ───────────────────────────────────────────────
137
+ // Prevents 100x slowdown on x86/ARM when P approaches zero.
138
+ if ( Math.abs( state.P ) < DENORMAL_THRESHOLD ) state.P = 0;
139
+
140
+ state.updateCount += 1;
141
+ return state;
142
+ }; // update()
143
+
144
+ export default update;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @fileoverview Public API for kernel node.
3
+ *
4
+ * Re-exports all lifecycle functions and shared control signals.
5
+ */
6
+
7
+ export { default as init } from './init.js';
8
+ export { default as update } from './update.js';
9
+ export { default as reset } from './reset.js';
10
+ export { default as recompute } from './recompute.js';
11
+ export { default as publishTo } from './publish-to.js';
12
+ // Direct imports for common control functions
13
+ export { default as disable } from '../../core/utils/node/disable.js';
14
+ export { default as enable } from '../../core/utils/node/enable.js';
15
+ export { default as pause } from '../../core/utils/node/pause.js';
16
+ export { default as unpause } from '../../core/utils/node/unpause.js';
17
+ // Re-export everything from introspection.js
18
+ export * from './introspect.js';
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @fileoverview Initialization for kernel node.
3
+ *
4
+ * Validates the spec, resolves the kernel (from preset name or custom array),
5
+ * reverses it for efficient sequential memory access during convolution,
6
+ * allocates a doubled ring buffer (2 × kernelLength) that enables a
7
+ * branch-free contiguous read window during convolution (see update.js for
8
+ * the "duplicated head" pattern), and returns the fully initialized state.
9
+ */
10
+
11
+ import { validateSpec } from '../../core/utils/node/index.js';
12
+ import * as introspect from './introspect.js';
13
+ import PRESETS from './presets.js';
14
+ import { resolveScalar, resolveArray } from '../../core/utils/options/resolve-field-keyed.js';
15
+
16
+ const init = function ( spec ) {
17
+ // 1. Validate
18
+ validateSpec( spec, introspect );
19
+
20
+ // 2. Initialize state
21
+ const state = Object.create( null );
22
+ // Standard input parameter health flag during update: false means healthy
23
+ state.inputValidationFailed = false;
24
+ // Ensure node is enabled by default
25
+ state.disable = false;
26
+ state.pause = false;
27
+
28
+ // Store field name and output configuration
29
+ state.x = spec.from.x;
30
+ state.stats = spec.stats;
31
+
32
+ // Get kernel from preset or custom kernel
33
+ // Supports both direct and field-keyed specification
34
+ const presetSpec = resolveScalar( spec.preset, state.x );
35
+ const kernelSpec = resolveArray( spec.kernel, state.x );
36
+
37
+ // Reverse kernel for efficient sequential memory access during convolution
38
+ state.kernel = presetSpec ?
39
+ PRESETS[ presetSpec ].slice().reverse() :
40
+ kernelSpec.slice().reverse();
41
+ // For debugging/introspection
42
+ state.presetName = presetSpec || 'userDefined';
43
+
44
+ // Pre-compute kernel length for hot path
45
+ state.kernelLength = state.kernel.length;
46
+
47
+ // Doubled ring buffer: size is the logical window length, buffer holds
48
+ // 2 × size doubles so every push writes to both halves (see update.js).
49
+ // Preserves the { size, buffer, head, used } shape expected by
50
+ // publishTo (via isNotFull) and reset (via ring.reset).
51
+ state.ring = Object.create( null );
52
+ state.ring.size = state.kernelLength;
53
+ state.ring.buffer = new Float64Array( state.kernelLength * 2 );
54
+ state.ring.head = 0;
55
+ state.ring.used = 0;
56
+
57
+ // Result storage
58
+ state.result = 0;
59
+
60
+ // Node type for debugging
61
+ state.nodeType = introspect.getNodeType();
62
+
63
+ return state;
64
+ }; // init()
65
+
66
+ export default init;