Actions

The action editor: identity and location, the script block, what a script may read and write, every validation message, the Run verb and its journal, Enable and Disable, Copy and Delete, and the run limits.

View as Markdown

An action is a JavaScript statement block that reads the address space and writes memory variables and tags. Actions are the write path of Logic: they run on demand (Run), on a trigger, or from a dashboard Button wired to them. Select an action under the Actions section of the Logic column (or create one with New… > New action) to open its editor; reading needs View logic, editing Configure logic, running Operate logic.

The header shows the action mark, the name, the line "A script you run on demand, or that a trigger runs for you, writing variables and tags." and a Disabled pill while the action is off. The form column holds IDENTITY and SCRIPT; the rail holds LAST RUN.

Identity

Field What it is Values / default Effect
Name The display name and the label a run is journaled under. Free text; a new action is ActionN; a blank name saves as Action. Autosaves per keystroke. Actions are referenced by identity, so renaming rewrites nothing and breaks nothing.
Location line Where the action is filed, in words: Actions / Startup / Walk setpoint. Read only. An action has no address; the line is a place, never something to type into an expression. Change it with Move to in the tree.
Description (optional) Free text. Empty by default. None.

Script

The SCRIPT card is the script editor with the hint "JavaScript statements (let, if, for, functions). Write memory variables by assignment (Variables.Setpoint = 21.5;) and tags with Connector.Driver.Device.Tag.Write(value). Reads are not quality-gated: check .State() and guard gaps with ?? before arithmetic." The script autosaves per keystroke and is validated every half second; the message appears under the hint. Validation never executes the script.

A script is ordinary strict-mode JavaScript (locals, if, loops, functions, Math, Date, JSON) over the same address space and the same read surface as expressions, with two differences. Reads are not quality-gated: a gap reads as null, so check .State() and guard arithmetic with ??; handling a bad reading is what actions are for. And a script may read expression variables (their published value); only an expression may not reference them.

What an action may write

Exactly two constructs mutate the plant, and both go through the journaled write funnel:

Write Form Target
Memory assignment Variables.Setpoint = 21.5; or Variables.Forno.Setpoint = 21.5; A memory variable, folder levels included. The value is coerced to the variable's output type and marked for retention when the variable is retentive.
Tag write Connector.Simulated.Pump.Cmd.Write(true); A live tag. The value is an engineering value: it travels backwards through the tag's conversion pipeline to the raw value the device takes.

A write is write-through: what applied before a failure stays applied, and the journal shows each write as old to new under the source Action. A failed write throws, aborting that run with the reason in its outcome:

  • "Write to 'X' rejected: the value is not finite." (NaN or infinity)
  • "'Tag' is not materialized in the connector." (a disabled device, or a tag the embedded server does not carry)
  • "'value' could not be converted for 'Tag'."
  • "'X' is write-protected by '<holder>'." (a recipe run or an interlock holds the source)
  • "Write to 'Tag' failed. Is the server running?"
  • "Variable 'X' was not found." and "'Variables.X' is an expression variable: it is computed, never written."

What validation refuses

Message Cause
A script is required. The editor is empty.
Script error: … The text does not parse.
Addresses must be static: 'Root' is accessed with a computed segment. Variables[name] or any non-literal segment.
Incomplete address '…'. A reference too short to name a point.
'X' was not found. A read, or an assignment target, that resolves to nothing.
Assign to the variable itself: Variables.Name = value. The left side of = names a member, or goes deeper than a variable's address can.
'X' is an expression variable: it is computed, never written. Assigning to an expression variable.
'Connector' points are read-only. Write tags with Connector.Driver.Device.Tag.Write(value). Assigning to any root other than Variables (Process has its own message).
Process points are read-only in Actions; run commands and staging writes are not supported by scripts. Assigning to, or calling Write on, a Process point.
Process run commands cannot be called from Actions; command points expose read-only readiness values. Calling Process.<Model>.<Unit>.Commands.Start() or any other command point; a Commands point only reads whether the command could execute now.
The ++ and -- operators are not supported on points. Use Variables.Name = Variables.Name.ValueToReal() + 1. Variables.N++.
Write(value) is the tag write: Connector.Driver.Device.Tag.Write(value). Write called on something that is not a tag address.

JavaScript locals (let x = 1; x = x + 1;) are untouched by these rules.

Run

Run is the leading verb of the bar over an open action; it is drawn only for a role with Operate logic and greyed with "Runtime stopped" while the station is read-only (the engineering lock does not grey it: running is operating, not configuring). When the role also holds Configure logic, the draft in the editor is saved first and the run executes the saved definition; without it, the run executes the durable definition (the fields are read-only, so the two never differ).

Every run executes on the single logic queue with a fresh script engine, so no state leaks between runs and a run never interleaves a sweep, another action or an operator write. A run is aborted past 500 ms ("The script was aborted: it ran past the 500 ms time limit (infinite loop?)."), 100,000 statements or 4 MB of memory, each with a message naming the limit. A disabled action fails without running ("The action is disabled."); a stopped runtime answers "The logic runtime is not running." The feed reports "Run OK in 12 ms." or "Run failed: <reason>". Only the failure reaches the Events console, under the action's name together with what invoked it: Manual for the verb, the trigger's name for a scheduled run. It is journaled as a warning the first time, summarized while it keeps failing with the same cause, and noted once more when it recovers, and that recovery line is the one entry a successful run ever writes there. A run that simply succeeds, and every value it writes, is written only to the detailed capture: a script writing on every sweep produces values by the thousand, and a console filled with them is a console nobody can read the station's news in.

The LAST RUN rail shows when the action last ran (or "Never run."), "Duration: N ms", the last error in a caution note, and the reminder "Runs execute on the single logic queue. Only a failed run reaches the Events console; a run that succeeds, and every value it writes, is kept for the detailed capture. Triggers invoke actions on schedule." The rail belongs to the live action: an autosave never blanks it; a restart of the runtime does.

Commands

Command What it does Greyed when Not drawn when
Run Saves the draft (with Configure logic) and queues one run. Runtime stopped. Role lacks Operate logic.
Enable / Disable Flips Enabled; a disabled action refuses Run and idles every trigger bound to it. Station locked or read-only. Role lacks Configure logic.
Copy Duplicates the action to the Actions root under a free name and opens the copy, which has no run recorded and no trigger bound to it. Station locked or read-only. Role lacks Configure logic.
Delete action Asks "Delete 'X'? This removes the action. This cannot be undone." A trigger bound to it is left unbound, not deleted. Station locked or read-only. Role lacks Configure logic.

The Actions root panel lists every action with its state in the Value column: "Enabled · last run <when>", with "· error" when the last run failed, or "Disabled".

What actions do not do

They do not dispatch Process run commands, stage a procedure or add a run comment (those points are read-only readiness and staging values); they do not acknowledge alarms; they do not run in parallel; they keep no state between runs and share no functions; and they are not fired by value changes or conditions, only by Run, a trigger's interval or a dashboard button.