docs: control-logic array+scalar locals (Value model, statevars, array nodes)

This commit is contained in:
Martino Ferrari
2026-06-24 20:02:55 +02:00
parent 3133e50e09
commit b6bc9dc2f2
2 changed files with 29 additions and 9 deletions
+23 -3
View File
@@ -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 (`<statevar type="array" elem=… sizing=… capacity=…>`).
> **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