@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,37 @@
1
+ // nodes/pass-if/update.js
2
+
3
+ /**
4
+ * @fileoverview Update function for passIf node
5
+ *
6
+ * Hot path — evaluates user-supplied predicate with message and
7
+ * counter. Returns null to stop downstream flow when predicate
8
+ * is false. Predicate errors are caught and tracked per-episode.
9
+ */
10
+
11
+ const update = function ( state, msg ) {
12
+ if ( state.disable || state.pause ) return state;
13
+
14
+ // Increment counter for this message
15
+ state.counter += 1;
16
+
17
+ let shouldPass;
18
+ try {
19
+ // Evaluate predicate with message and current counter
20
+ shouldPass = state.predicate( msg, state.counter );
21
+ // Recovery: clear log-suppression flag on success
22
+ if ( state.predicateErrorLogged ) state.predicateErrorLogged = false;
23
+ } catch ( error ) {
24
+ // Assume it to be a case of predicate evaluating to false
25
+ shouldPass = false;
26
+ // Log first error per episode; suppress subsequent until recovery
27
+ if ( !state.predicateErrorLogged ) {
28
+ state.predicateErrorLogged = true;
29
+ console.error( `WinkComposer/passIf: predicate threw exception: ${error.message}` );
30
+ }
31
+ }
32
+
33
+ // Return null to stop flow, state to continue
34
+ return shouldPass ? state : null;
35
+ }; // update()
36
+
37
+ export default update;
@@ -0,0 +1,111 @@
1
+ // nodes/persist-if/helpers.js
2
+
3
+ /**
4
+ * @fileoverview Helper functions for persistIf node
5
+ *
6
+ * The shared write-failure recording used by update.js, and the static
7
+ * fallback error for adapters that break the return contract. Mirrors
8
+ * emit-if/helpers.js — the two output gates share one failure model.
9
+ */
10
+
11
+ /**
12
+ * Static fallback error the framework substitutes when an adapter breaks
13
+ * the return contract — no result object at all, or `{ ok: false }` with
14
+ * no `error` (ADR-018 error vocabulary). A module-level singleton, so the
15
+ * hot path allocates nothing. Mirrors emit-if.
16
+ */
17
+ const MALFORMED_RESULT_ERROR = {
18
+ code: 'MALFORMED_RESULT',
19
+ message: 'storage returned a malformed write result (expected { ok, error? })'
20
+ };
21
+
22
+ /**
23
+ * Throws when an annotate return is not a plain object — arrays pass a
24
+ * bare typeof check but are just as wrong. A flow-authoring bug surfaces
25
+ * in the node's own error episode (the predicate/annotate try in
26
+ * update.js), never downstream where it would masquerade as an adapter
27
+ * failure. Mirrors emit-if.
28
+ *
29
+ * @param {*} record - The annotate return value
30
+ * @throws {Error} Naming the offending type
31
+ */
32
+ const assertAnnotateReturn = function ( record ) {
33
+ const got = record === null ? 'null' :
34
+ ( Array.isArray( record ) ? 'array' : typeof record );
35
+ if ( got === 'object' ) {
36
+ return;
37
+ }
38
+ throw new Error( `annotate must return an object, got ${got}` );
39
+ }; // assertAnnotateReturn()
40
+
41
+ /**
42
+ * Warns, once per gate, about invented keys in an annotate record.
43
+ *
44
+ * An invented key is one the annotate function added that is neither a
45
+ * declared column nor a field of the message. Such a key is almost always
46
+ * a typo, and today it fails silently: the persist plan writes only
47
+ * declared columns, so the value never reaches storage. Keys that also
48
+ * exist in the message are skipped on purpose — a `...msg` spread carries
49
+ * many working fields, and naming those would bury the real finding.
50
+ *
51
+ * Runs once per gate. The `checked` flag lives on the wiring-stamped sweep
52
+ * object that every partition shares, and it flips before the comparison,
53
+ * so the check cannot repeat. The Object.keys call and the warning string
54
+ * allocate — once, on this single firing, inside the per-event allocation
55
+ * the function-form annotate already makes. Later firings never reach this
56
+ * function (update.js short-circuits on the flag), so the steady-state hot
57
+ * path stays allocation-free per ADR-004.
58
+ *
59
+ * @param {Object} state - Node state (name, insightType, annotateSweep)
60
+ * @param {Object} record - The record the annotate function returned
61
+ * @param {Object} msg - The message that produced it
62
+ */
63
+ const sweepAnnotateKeys = function ( state, record, msg ) {
64
+ const sweep = state.annotateSweep;
65
+ sweep.checked = true;
66
+
67
+ const recordKeys = Object.keys( record );
68
+ const invented = [];
69
+ for ( let i = 0; i < recordKeys.length; i += 1 ) {
70
+ const key = recordKeys[ i ];
71
+ if ( !sweep.declaredColumns.has( key ) && !( key in msg ) ) {
72
+ invented.push( key );
73
+ }
74
+ }
75
+
76
+ if ( invented.length > 0 ) {
77
+ console.warn(
78
+ `WinkComposer/persistIf: annotate for node '${state.name}' ` +
79
+ `(insightType '${state.insightType}') returned keys that are not declared columns: ` +
80
+ `${invented.join( ', ' )}. These values are never stored, because the persist plan ` +
81
+ 'writes only declared columns. Check the key names against the asset class. ' +
82
+ 'Reported once per gate.'
83
+ );
84
+ }
85
+ }; // sweepAnnotateKeys()
86
+
87
+ /**
88
+ * Records a failed write into the node's failure episode: updates the
89
+ * last* fields, and on the first failure of an episode captures the first*
90
+ * fields and logs one console.error (repeats stay quiet until a successful
91
+ * write closes the episode — see update.js). The first* fields keep the
92
+ * episode-opening error (the cause; later failures in a cascade are
93
+ * symptoms).
94
+ *
95
+ * @param {Object} state - Node state
96
+ * @param {Object} error - The `{ code, message }` from the storage's
97
+ * `{ ok: false }` return (ADR-018 sink return contract)
98
+ */
99
+ const recordPersistFailure = function ( state, error ) {
100
+ state.persistErrors += 1;
101
+ state.lastPersistError = error.message;
102
+ state.lastPersistErrorCode = error.code;
103
+ if ( !state.writeErrorLogged ) {
104
+ state.writeErrorLogged = true;
105
+ state.firstPersistError = error.message;
106
+ state.firstPersistErrorCode = error.code;
107
+ console.error( state.writeErrorLogPrefix + error.code + '): ' + error.message );
108
+ }
109
+ }; // recordPersistFailure()
110
+
111
+ export { assertAnnotateReturn, sweepAnnotateKeys, recordPersistFailure, MALFORMED_RESULT_ERROR };
@@ -0,0 +1,9 @@
1
+ // nodes/persist-if/index.js
2
+
3
+ export { default as init } from './init.js';
4
+ export { default as update } from './update.js';
5
+ export { default as reset } from './reset.js';
6
+ export { default as recompute } from './recompute.js';
7
+ export { default as publishTo } from './publish-to.js';
8
+ // Re-export everything from introspection
9
+ export * from './introspect.js';
@@ -0,0 +1,98 @@
1
+ // nodes/persist-if/init.js
2
+
3
+ /**
4
+ * @fileoverview Initialization for persistIf node
5
+ *
6
+ * Validates specification and creates initial state with pre-allocated
7
+ * structures for zero-allocation hot path.
8
+ */
9
+
10
+ import { validateWithSchema } from '../../core/utils/validate/index.js';
11
+ import { getDSLMetadata, getNodeType } from './introspect.js';
12
+
13
+ /**
14
+ * Initialize persistIf node state.
15
+ *
16
+ * @param {Object} spec - Node specification
17
+ * @param {string} spec.nodeType - Must be 'Persist If'
18
+ * @param {string} spec.name - Node identifier
19
+ * @param {Function} spec.predicate - Function to evaluate for persistence
20
+ * @param {string} spec.insightType - Insight type (maps to storage table)
21
+ * @param {string} spec.storageName - Name of registered storage adapter
22
+ * @param {Function} [spec.annotate] - Shapes the stored record: write annotate( msg )
23
+ * instead of msg. Mirrors emitIf's annotate; the persist plan still writes only
24
+ * the insight type's declared columns, so the hook cannot widen the schema.
25
+ * @param {Object} [spec.annotateSweep] - Stamped by wiring, not by flow authors:
26
+ * the declared-column set plus a shared once-flag for the first-firing
27
+ * unknown-key warning (see helpers.js sweepAnnotateKeys)
28
+ * @returns {Object} Initialized state
29
+ */
30
+ const init = function ( spec ) {
31
+ // Validate specification
32
+ const metadata = getDSLMetadata();
33
+ const validation = validateWithSchema(
34
+ {
35
+ ...metadata.specSchema,
36
+ _crossFieldValidators: metadata.crossFieldValidators
37
+ },
38
+ spec,
39
+ 'spec'
40
+ );
41
+ validation.throwIfInvalid( getNodeType() );
42
+
43
+ // Create state after validation passes
44
+ const state = Object.create( null );
45
+
46
+ // Core configuration
47
+ state.nodeType = getNodeType();
48
+ state.name = spec.name;
49
+ state.predicate = spec.predicate;
50
+ state.insightType = spec.insightType;
51
+ state.storageName = spec.storageName;
52
+ state.annotate = spec.annotate || null;
53
+ // Annotate key-sweep support, stamped by wiring (wire-storages) when a
54
+ // function-form annotate can be checked against declared columns. The
55
+ // object is shared by every partition of this gate on purpose: its
56
+ // `checked` flag makes the unknown-key warning fire once per gate, not
57
+ // once per partition. Unit tests and flows without an asset class have
58
+ // no stamp; null disables the check.
59
+ state.annotateSweep = spec.annotateSweep || null;
60
+
61
+ // Storage reference (injected by partition manager at runtime)
62
+ state.storage = null;
63
+
64
+ // State transition tracking (semantic — controls error tracking)
65
+ state.inErrorState = false;
66
+ // Log suppression: one log per error episode; reset on recovery.
67
+ state.predicateErrorLogged = false;
68
+
69
+ // Statistics for observability
70
+ state.persistCount = 0;
71
+ state.passCount = 0;
72
+ state.lastPersistTime = null;
73
+
74
+ // Error tracking
75
+ state.persistErrors = 0;
76
+ state.lastPersistError = null;
77
+ // Per ADR-018 the storage write returns { ok: false, error: { code, message } }
78
+ // on failure. We surface both fields: lastPersistError is the human message
79
+ // (predicate exceptions also write here as a string), lastPersistErrorCode
80
+ // is the structured code (null when the error came from a predicate exception
81
+ // since predicate failures are not classified by the contract).
82
+ state.lastPersistErrorCode = null;
83
+ // Write-failure episode: one console.error per episode; a successful
84
+ // write closes it. The first* fields keep the episode-opening error —
85
+ // in a cascade the LAST error is the symptom and the FIRST is the
86
+ // cause. They survive recovery for post-mortem reads and are
87
+ // overwritten only when the next episode opens.
88
+ state.writeErrorLogged = false;
89
+ state.firstPersistError = null;
90
+ state.firstPersistErrorCode = null;
91
+ // Static log prefix pre-built here per ADR-004 (no string building in
92
+ // update beyond the two runtime fields, and only once per episode).
93
+ state.writeErrorLogPrefix = `WinkComposer/persistIf: storage write failed (node=${state.name}, insightType=${state.insightType}, code=`;
94
+
95
+ return state;
96
+ }; // init()
97
+
98
+ export default init;
@@ -0,0 +1,106 @@
1
+ // nodes/persist-if/introspect.js
2
+
3
+ /**
4
+ * @fileoverview Introspection metadata for persistIf node
5
+ *
6
+ * Single source of truth for DSL metadata, validation schema,
7
+ * and node capabilities. Used by flow transpiler and documentation.
8
+ */
9
+
10
+ import { validators } from '../../core/utils/validate/index.js';
11
+
12
+ /** Single source of truth for what this plugin can do */
13
+ const SUPPORTED_STATS = []; // Pass-through node, no stats to publish
14
+
15
+ /** Human-readable descriptions (for introspection) */
16
+ const STAT_DESCRIPTIONS = {}; // No stats, no descriptions
17
+
18
+ /** Control methods available for triggers (none - side-effect only node) */
19
+ const SUPPORTED_CONTROL_METHODS = {};
20
+
21
+ /** The type of this node */
22
+ const NODE_TYPE = 'Persist If';
23
+
24
+ /** Node capabilities for documentation (kept accurate to shipping code) */
25
+ const CAPABILITIES = {
26
+ description: 'Conditionally persists messages to storage without disrupting pipeline flow',
27
+ features: [
28
+ 'Pure pass-through behavior - messages continue unchanged',
29
+ 'Conditional persistence based on predicate function',
30
+ 'Optional annotate hook shapes the stored record (mirrors emitIf); the persist plan still writes only the insight type\'s declared columns',
31
+ 'On the first firing, annotate record keys are checked once per gate: a key that is neither a declared column nor a message field is named in a warning, because its value would otherwise vanish silently',
32
+ 'Columns and types come from the declared semantics (asset class), never inferred from data',
33
+ 'Writes through the storage handle\'s write and reads its classified { ok, error } result',
34
+ 'Write failures open a loud error episode (one console.error per episode); the pipeline never stops',
35
+ 'Per-partition persistence tracking'
36
+ ]
37
+ };
38
+
39
+ // Export functions for accessing metadata
40
+ export const getSupportedStats = () => SUPPORTED_STATS.slice();
41
+ export const getStatDescriptions = () => ( { ...STAT_DESCRIPTIONS } );
42
+ export const getSupportedControlMethods = () => ( { ...SUPPORTED_CONTROL_METHODS } );
43
+ export const getNodeType = () => NODE_TYPE;
44
+ export const getCapabilities = () => ( { ...CAPABILITIES, features: CAPABILITIES.features.slice() } );
45
+
46
+ /** Spec default values */
47
+ export const DEFAULT_OPTIONS = {};
48
+
49
+ // DSL Metadata for transpilation
50
+ const DSL_METADATA = {
51
+ // Validation schema
52
+ specSchema: {
53
+ nodeType: {
54
+ type: 'string',
55
+ required: true,
56
+ value: NODE_TYPE
57
+ },
58
+ name: {
59
+ type: 'string',
60
+ required: true,
61
+ validator: validators.identifier,
62
+ error: 'Name must be a valid JavaScript identifier'
63
+ },
64
+ predicate: {
65
+ type: 'function',
66
+ required: true,
67
+ arity: 1,
68
+ error: 'Predicate must be a function with exactly one parameter (msg)'
69
+ },
70
+ insightType: {
71
+ type: 'string',
72
+ required: true,
73
+ error: 'Insight type must be specified (maps to storage table)'
74
+ },
75
+ storageName: {
76
+ type: 'string',
77
+ required: true,
78
+ error: 'Storage name must reference a registered storage adapter'
79
+ },
80
+ annotate: {
81
+ type: 'function',
82
+ required: false,
83
+ arity: 1,
84
+ error: 'Annotate must be a function with exactly one parameter (msg)'
85
+ },
86
+ stats: {
87
+ type: 'object',
88
+ required: false,
89
+ propertyNames: [], // No stats for pass-through node
90
+ error: 'PersistIf is a pass-through node and does not support stats'
91
+ }
92
+ },
93
+
94
+ // Cross-field validators
95
+ crossFieldValidators: [],
96
+
97
+ // Build spec from DSL
98
+ buildSpec: ( name, predicate, options ) => ( {
99
+ nodeType: NODE_TYPE,
100
+ name,
101
+ predicate,
102
+ ...options
103
+ } )
104
+ };
105
+
106
+ export const getDSLMetadata = () => ( { ...DSL_METADATA } );
@@ -0,0 +1,21 @@
1
+ // nodes/persist-if/publish-to.js
2
+
3
+ /**
4
+ * @fileoverview PublishTo function for persistIf node
5
+ *
6
+ * Pass-through node - message continues unchanged.
7
+ * No fields are added to the outgoing message.
8
+ */
9
+
10
+ /**
11
+ * Publish computed results to message.
12
+ *
13
+ * @param {Object} _state - Node state (unused)
14
+ * @param {Object} _msg - Outgoing message (unchanged)
15
+ */
16
+ const publishTo = function ( _state, _msg ) {
17
+ // Pure pass-through node - message continues unchanged
18
+ // No fields are added to the message
19
+ }; // publishTo()
20
+
21
+ export default publishTo;
@@ -0,0 +1,20 @@
1
+ // nodes/persist-if/recompute.js
2
+
3
+ /**
4
+ * @fileoverview Recompute function for persistIf node
5
+ *
6
+ * No numerical computation to stabilize.
7
+ */
8
+
9
+ /**
10
+ * Recompute for numerical stability.
11
+ *
12
+ * @param {Object} _state - Node state (unused)
13
+ * @returns {boolean} Always true (no recomputation needed)
14
+ */
15
+ const recompute = function ( _state ) {
16
+ // No numerical computation to stabilize
17
+ return true;
18
+ }; // recompute()
19
+
20
+ export default recompute;
@@ -0,0 +1,35 @@
1
+ // nodes/persist-if/reset.js
2
+
3
+ /**
4
+ * @fileoverview Reset function for persistIf node
5
+ *
6
+ * Resets statistics and state tracking.
7
+ */
8
+
9
+ /**
10
+ * Reset node state.
11
+ *
12
+ * @param {Object} state - Node state
13
+ * @returns {boolean} Always true (ADR-004; parity with emitIf)
14
+ */
15
+ const reset = function ( state ) {
16
+ // Reset statistics
17
+ state.persistCount = 0;
18
+ state.passCount = 0;
19
+ state.lastPersistTime = null;
20
+ state.persistErrors = 0;
21
+ state.lastPersistError = null;
22
+ state.lastPersistErrorCode = null;
23
+ state.firstPersistError = null;
24
+ state.firstPersistErrorCode = null;
25
+
26
+ // Reset state tracking
27
+ state.inErrorState = false;
28
+ // Clear error suppression so next error episode is logged
29
+ state.predicateErrorLogged = false;
30
+ state.writeErrorLogged = false;
31
+
32
+ return true;
33
+ }; // reset()
34
+
35
+ export default reset;
@@ -0,0 +1,112 @@
1
+ // nodes/persist-if/update.js
2
+
3
+ /**
4
+ * @fileoverview Update function for persistIf node
5
+ *
6
+ * Hot path - zero allocation after first message (annotate, when configured,
7
+ * allocates only on the ticks that actually persist - the same per-event
8
+ * asymmetry as emitIf's annotate).
9
+ * Evaluates predicate, optionally shapes the record via annotate, and writes
10
+ * it to the storage buffer if the predicate passed.
11
+ */
12
+
13
+ import { assertAnnotateReturn, sweepAnnotateKeys, recordPersistFailure, MALFORMED_RESULT_ERROR } from './helpers.js';
14
+
15
+ /**
16
+ * Process incoming message.
17
+ *
18
+ * @param {Object} state - Node state
19
+ * @param {Object} msg - Incoming message
20
+ * @returns {Object} Updated state (always returns state for pass-through)
21
+ */
22
+ const update = function ( state, msg ) {
23
+ // Always increment pass count for observability
24
+ state.passCount += 1;
25
+
26
+ // Early exit if storage not available
27
+ if ( !state.storage ) {
28
+ return state;
29
+ }
30
+
31
+ // Evaluate predicate, then shape the record when persisting. Annotate
32
+ // mirrors emitIf: both run inside one try, so predicate and annotate
33
+ // share the same error episode (tracking, log suppression, recovery).
34
+ let shouldPersist = false;
35
+ let record = msg;
36
+ try {
37
+ shouldPersist = state.predicate( msg );
38
+ if ( shouldPersist && state.annotate ) {
39
+ record = state.annotate( msg );
40
+ // A flow-authoring bug (non-object return) throws here, into
41
+ // this node's error episode — never into storage.write where
42
+ // it would masquerade as a storage failure (SEND_FAILED).
43
+ assertAnnotateReturn( record );
44
+ // First firing only: warn about invented record keys — typos
45
+ // that would otherwise vanish silently (the persist plan writes
46
+ // only declared columns). Every later firing takes this
47
+ // two-read short-circuit; nothing allocates here.
48
+ if ( state.annotateSweep && !state.annotateSweep.checked ) {
49
+ sweepAnnotateKeys( state, record, msg );
50
+ }
51
+ }
52
+
53
+ // Clear error state on successful evaluation
54
+ if ( state.inErrorState ) {
55
+ state.inErrorState = false;
56
+ }
57
+ // Recovery: clear log-suppression flag on success
58
+ if ( state.predicateErrorLogged ) state.predicateErrorLogged = false;
59
+ } catch ( error ) {
60
+ // Handle predicate/annotate errors (semantic — tracks error state)
61
+ if ( !state.inErrorState ) {
62
+ state.inErrorState = true;
63
+ }
64
+ // Log first error per episode; suppress subsequent until recovery
65
+ if ( !state.predicateErrorLogged ) {
66
+ state.predicateErrorLogged = true;
67
+ console.error( `WinkComposer/persistIf: predicate threw exception: ${error.message}` );
68
+ }
69
+ state.persistErrors += 1;
70
+ state.lastPersistError = error.message;
71
+ // Predicate exceptions are persist-if-internal, not part of the
72
+ // ADR-018 adapter err.code vocabulary. Clear the code so the two
73
+ // fields stay in sync (a stale code from a prior storage error
74
+ // would mislead readers).
75
+ state.lastPersistErrorCode = null;
76
+ return state;
77
+ }
78
+
79
+ // Write to storage if predicate returned true
80
+ if ( shouldPersist ) {
81
+ // Build record for storage (zero-alloc: storage.write handles it).
82
+ // storage.write() is synchronous per ADR-013; the actual I/O happens
83
+ // asynchronously via the storage adapter's background flush.
84
+ // Per the ADR-018 sink return contract, the storage answers
85
+ // { ok: true } on success or
86
+ // { ok: false, error: { code, message } } on failure.
87
+ const result = state.storage.write(
88
+ state.insightType,
89
+ record,
90
+ state.partitionId
91
+ );
92
+
93
+ if ( result && result.ok ) {
94
+ state.persistCount += 1;
95
+ // Wall-clock marker of the last successful write (post-mortem
96
+ // reads only, like the first* error fields).
97
+ state.lastPersistTime = Date.now();
98
+ // Recovery: a successful write closes the failure episode.
99
+ if ( state.writeErrorLogged ) state.writeErrorLogged = false;
100
+ } else {
101
+ // A malformed result (no object at all, or ok:false with no
102
+ // error) counts as a failure with the static fallback error,
103
+ // so a non-conforming adapter can neither fail silently
104
+ // nor throw out of the hot path.
105
+ recordPersistFailure( state, ( result && result.error ) || MALFORMED_RESULT_ERROR );
106
+ }
107
+ }
108
+
109
+ return state;
110
+ }; // update()
111
+
112
+ export default update;
@@ -0,0 +1,14 @@
1
+ // nodes/persistence-check/index.js
2
+
3
+ export { default as init } from './init.js';
4
+ export { default as update } from './update.js';
5
+ export { default as reset } from './reset.js';
6
+ export { default as recompute } from './recompute.js';
7
+ export { default as publishTo } from './publish-to.js';
8
+ // Direct imports for common control functions
9
+ export { default as disable } from '../../core/utils/node/disable.js';
10
+ export { default as enable } from '../../core/utils/node/enable.js';
11
+ export { default as pause } from '../../core/utils/node/pause.js';
12
+ export { default as unpause } from '../../core/utils/node/unpause.js';
13
+ // Re-export everything from introspection.js
14
+ export * from './introspect.js';
@@ -0,0 +1,38 @@
1
+ // nodes/persistence-check/init.js
2
+
3
+ import { validateSpec } from '../../core/utils/node/index.js';
4
+ import * as introspect from './introspect.js';
5
+
6
+ const init = function ( spec ) {
7
+ validateSpec( spec, introspect );
8
+
9
+ // Create state after validation passes
10
+ const state = Object.create( null );
11
+ // Ensure node is enabled by default
12
+ state.disable = false;
13
+ state.pause = false;
14
+
15
+ // Extract validated predicate
16
+ state.predicate = spec.predicate;
17
+ state.requires = spec.requires;
18
+ state.stats = spec.stats;
19
+
20
+ // Apply defaults manually (validation doesn't enforce them)
21
+ state.minVotes = spec.minVotes || introspect.DEFAULT_OPTIONS.minVotes;
22
+ state.outOfTotal = spec.outOfTotal || introspect.DEFAULT_OPTIONS.outOfTotal;
23
+
24
+ // State variables
25
+ state.persistenceConfirmed = false;
26
+ state.voteCount = 0;
27
+ state.unvoteCount = 0;
28
+
29
+ state.nodeType = introspect.getNodeType();
30
+ state.inControlPhase = false;
31
+
32
+ // Log suppression: one log per error episode; reset on recovery.
33
+ state.predicateErrorLogged = false;
34
+
35
+ return state;
36
+ }; // init()
37
+
38
+ export default init;