From b6bc9dc2f2d8ccc7bec51558261b3265982d09dd Mon Sep 17 00:00:00 2001 From: Martino Ferrari Date: Wed, 24 Jun 2026 20:02:55 +0200 Subject: [PATCH] docs: control-logic array+scalar locals (Value model, statevars, array nodes) --- TODO.md | 12 ++++++------ docs/TECHNICAL_SPEC.md | 26 +++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/TODO.md b/TODO.md index 6a31ec3..dc5c3db 100644 --- a/TODO.md +++ b/TODO.md @@ -94,14 +94,14 @@ - [x] Live / debug mode in all three node editors — evaluate the graph online and badge each node's value at human speed (~0.5 s). Shared frontend `web/src/lib/flowDebug.ts` (badge/active classes, `useFlowDebug` poller) + CSS `.flow-node-active`/`.flow-node-badge`/`.flow-wire-active`; a green ◉ toggle in each `.flow-palette-toolbar`. Per-editor backends: - [ ] Syntetic signal editor: - [x] Implement live / debug mode where value are evaluated online and visualized at human speed (e.g. 0.5s) — server-side stateless single-shot trace: `POST /api/v1/synthetic/trace` snapshots live source signals (broker `ReadNow`) and runs `evalSampleTrace` with fresh state, returning every node's value; stateful ops (moving_average/rms/lowpass/derivative/integrate/lua) badged `~approx` - - [ ] Logic editor: + - [x] Logic editor: - [x] Implement live / debug mode where value are evaluated online and visualized at human speed (e.g. 0.5s) — editor spins up a second client-side `LogicEngine` in new `dryRun` mode (real writes/config/dialogs suppressed) loaded with the edited graph; per-node values polled into the shared badges; the view-mode singleton is untouched - - add full suppor to local array values: dynamic, dynamic but capped max, fixed size etc: - - array functions should work with new local array - - NOTE: **Phase 1 (panel logic, client-side TS) is DONE** — array statevars (dynamic/capped/fixed), value-polymorphic expression engine with indexing + array functions, `action.array.*` mutation nodes (legacy accumulate/export/clear unified + auto-migrated), panel-XML round-trip, editor declaration form, and widget array modes (plot/table/multi-LED). Box stays unchecked until **Phase 2** (server-side `internal/controllogic` Go port, see below) lands. - - [ ] Control loop: + - [x] add full suppor to local array values: dynamic, dynamic but capped max, fixed size etc: + - [x] array functions should work with new local array + - NOTE: **Phase 1 (panel logic, client-side TS) is DONE** — array statevars (dynamic/capped/fixed), value-polymorphic expression engine with indexing + array functions, `action.array.*` mutation nodes (legacy accumulate/export/clear unified + auto-migrated), panel-XML round-trip, editor declaration form, and widget array modes (plot/table/multi-LED). **Phase 2 (server-side `internal/controllogic` Go port, see below) has now landed**, so this feature is complete across both engines. + - [x] Control loop: - [x] Implement live / debug mode where value are evaluated online and visualized at human speed (e.g. 0.5s) — server pushes per-node events over the WS (`debugSubscribe`/`debugNode`) via a new `DebugObserver` on the engine (lock-free `atomic.Value`, gated by a per-graph watch set) + `internal/server/debughub.go` (drop-on-full fan-out). Two modes share one message shape: **Live** observes the running enabled graph; **Simulate** dry-runs the unsaved edits in a throwaway sandbox (`StartSimulate`, side effects suppressed). Live/Sim sub-toggle in the editor - - add full support to server side array values + - [x] add full support to server side array values — DONE (Phase 2): `Value = float64 | []Value` model (`internal/controllogic/value.go`), `Graph.StateVars` (number/bool/array with dynamic/capped/fixed sizing) persisted in store JSON, value-polymorphic `expr.go` (array literals, negative-wrap indexing, full array-function table), and `action.array.push|set|remove|pop|clear` nodes. Lua block stays scalar-only (array local → NaN); CSV export remains panel-logic-only - [x] Implement git style versioning for: synthetic variable, panels, control logic: - [x] possibility to fork any version - [x] click to view the version diff --git a/docs/TECHNICAL_SPEC.md b/docs/TECHNICAL_SPEC.md index 4b532f8..724161f 100644 --- a/docs/TECHNICAL_SPEC.md +++ b/docs/TECHNICAL_SPEC.md @@ -376,9 +376,9 @@ now produces **index-aligned** CSV: each configured array becomes a column (cust labels supported), rows aligned by element index. Array statevars and all array nodes round-trip through the panel XML (``). -> **Note:** This is Phase 1 (panel logic, client-side TypeScript). The equivalent array -> support in the server-side control-logic engine (`internal/controllogic`) is a separate -> Phase 2 effort and is not yet implemented. +> **Note:** The above is Phase 1 (panel logic, client-side TypeScript). The equivalent array +> support in the server-side control-logic engine (`internal/controllogic`) is Phase 2 and has +> now landed — see the **Array-valued local variables** subsection of §3.9 below. ### 3.9 Control Logic Engine @@ -389,6 +389,26 @@ and writes results back to signals. Graphs are persisted by a store and managed `/api/v1/controllogic`; each mutation calls `Engine.Reload()` to apply changes live. Graphs can be individually enabled/disabled. +**Array-valued local variables (Phase 2).** Engine locals now carry a `Value` — the tagged +union `Value = float64 | []Value` (`internal/controllogic/value.go`), the Go port of the +panel-logic `ArrVal` model, with booleans represented as `1`/`0` at the leaves. A graph may +declare `statevars`: each has a `Name`, a `Type` (`number` | `bool` | `array`), an `Initial` +expression, and — for arrays — a `Sizing` policy and `Capacity`. The three sizing policies +mirror the frontend: **dynamic** (unbounded up to `ARRAY_MAX = 1_000_000`, oldest dropped +FIFO past the cap), **capped** (length kept ≤ `Capacity`, oldest dropped FIFO), and **fixed** +(exactly `Capacity` elements — truncated or zero-padded). Sizing is enforced on write. State +vars are persisted in the graph's store JSON and seeded into locals at compile time. + +The expression evaluator (`internal/controllogic/expr.go`) is value-polymorphic: it supports +array literals `[a, b, c]`, indexing `arr[i]` (negative indices wrap from the end), and a +table of array functions: `len`, `sum`, `mean`, `slice`, `concat`, `reverse`, `sort`, `scale`, +`add`, `sub`, `push`, `set`, `insert`, `remove`, `pop`, `shift`, `indexOf`, `contains`, `fill` +(plus `min`/`max`, which accept either scalars or an array). These are pure — they produce new +values and never mutate a stored local. Five action nodes write back to a declared array +statevar: `action.array.push`, `…set`, `…remove`, `…pop`, and `…clear`. The embedded Lua block +remains **scalar-only**: reading an array local from Lua yields `NaN`. CSV export +(`action.export`) is panel-logic-only and is **not** available in control logic. + The engine also holds a `*confmgr.Store` (injected via `NewEngine`) for five config action nodes: `action.config.apply` resolves an instance + its set and runs `confmgr.Apply` with a broker-backed, audited write closure; `action.config.read` resolves a single parameter value