actionObject
An action is a task in the dispatch Actions queue: something Helix would like an operator to do about a particular stop — rebook a job Spiral could not schedule, check whether a fault could be fixed remotely, look for voluntary work while a resource is still on its previous job.
Actions are Helix-only. They are id-managed, stored in Mongo and streamed to the screen, but are
never sent to Spiral. An action is attached to its stop by the stop’s stable spiralKey rather than a
server-assigned id, so it survives re-optimisation.
For what actions are for and how an operator works them, see the Actions guide. This page is the schema.
The definition
Section titled “The definition”Authored per stop type at stopParams[<type>].helix.actions.<name>, resolved with clone inheritance
and a DEFAULT base — so a definition on the DEFAULT key applies to every stop type. The key is the
action’s name, which becomes type on the raised record.
-
textstring - THE RULE, and the message in one. A value ending in "()" names a function on the client crud module, called as a method on the stop — `this` IS the stop, so the rule reads this.state, this.arv, this.ext directly. Returning a non-empty string raises the action with that text; returning null (or anything that is not a string) does not raise, and cancels an automatic action already showing. A value without "()" is taken as literal text. An undefined function simply never raises.
-
classstring - A name from the domain’s helix.actionClasses catalogue. Its presence is what makes an action AUTOMATIC — the auto-raise engine considers classed definitions only. Omit it for a manual message.
-
actionee"any" | "owner" | "viewer" | "resource"defaultany - Who sees it. resource: the resource fulfilling the stop (Engineer app only). owner: operators owning the stop’s desk. viewer: operators owning OR watching it. any: everyone. Enforced on the dispatch stream filter and narrowed again on screen.
-
rankinteger - Arbitration for automatic actions: only the highest-ranked definition whose rule currently fires is kept in progress on a stop. Rank DOUBLES AS the raised record’s urgency (an unranked definition raises at 50, the middle of the scale) — one number, two jobs.
-
deferinteger - Seconds. When set, the action offers a Defer outcome that hides ALL of this stop’s actions for that long. Note it hides rather than suppresses — see “Suppression” below.
-
statestring - State gate: the action is eligible only while the stop is in this state, and is cancelled automatically when it leaves. Gates on the stop’s RAW Spiral state, not its clientState.
-
statesstring - As `state`, for several states.
-
outcomestring - The decision buttons offered to the operator. Empty or omitted makes the action read-and-acknowledge. The chosen value is recorded to stop.actions.<name>.
-
labelstring - Display name for the queue row; defaults to the action name.
-
iconstring - Icon for the queue row.
"helix": { "actions": { "rebook": { "class": "planning", "actionee": "owner", "rank": 30, "state": "REBK", "label": "Rebook", "text": "This job needs a new appointment — rebook with the customer.", "outcome": ["rebooked", "cancelled"] } }}That definition needs no client code at all: the engine supplies the gate (state) and the
suppression (the recorded outcome), so literal text is enough. Reach for a text function only when
the rule depends on something a state cannot express.
The raised record
Section titled “The raised record”What the engine writes to the action collection and streams to the screen. A domain never authors this
directly; it is listed because it is what the Actions queue, the Engineer inbox and the Contact Centre
all read.
-
idinteger - The action’s id.
-
spiralKeyspiralKey - The stop this action is attached to — a stable logical address, not an outStopId, so it survives re-optimisation.
-
typestring - The action NAME — the key it was raised from in the stop type’s helix.actions.
-
urgencynumber - 0 (least) to 100 (most). Drives queue ranking and the temperature colour.
-
classstring - Copied from the definition; null for a manual message.
-
actionee"any" | "owner" | "viewer" | "resource" - Copied from the definition.
-
rankinteger - Copied from the definition.
-
deferinteger - Copied from the definition.
-
textstring - The resolved message — what the `text` expression returned at raise time.
-
outcomeany - The choices offered. Null or empty means read-and-acknowledge.
-
createdAtinteger - When it was raised (simulated time).
-
stopTypestring - Denormalised at raise time so an actions-only stream can resolve label, icon and class without loading the stop.
-
didinteger - The stop’s desk at raise time. Denormalised — it may go stale when the plan changes.
-
arvinteger - The stop’s planned arrival at raise time, as a sort key. Denormalised on the same terms as `did`.
-
lockUntilinteger - Soft lock. While this is in the future the action is being handled elsewhere and shows greyed on other screens; it releases itself when the time passes. It is never a delete.
-
seqnointeger - Optimistic-lock sequence number.
-
visibility"resource" | "owner" | "viewer" | "all" - DEPRECATED — superseded by `actionee`, and read only as a fallback when `actionee` is absent. Do not author it.
-
extrecord - DEPRECATED — outcomes are recorded to stop.actions.<name>. Still the transport by which a chosen outcome reaches the recorder, so it is not yet removed.
How an action concludes
Section titled “How an action concludes”Choosing an outcome forces it into the record’s ext.outcome, the recorder writes it to
stop.actions.<name> and the audit trail, and then the action record is deleted — the queue entry
is transient; the stop’s record and the audit are the durable trace. An external system concludes an
action the same way: force ext.outcome, then delete. The other endings: defer (posted through the
same door as {defer: seconds}, then deleted and later re-raised), cancellation (rule stops firing,
state gate closes, the stop is deleted, or the definition vanishes in a domain reconfiguration — nothing
recorded), and conclusion by a step — the callout’s answer window records a timeout refusal
outcome when nobody answers in time, exactly as if it had been chosen.
Automatic and manual
Section titled “Automatic and manual”The class field is the whole distinction, and it is worth being precise about because the name suggests
something else:
- Classed ⇒ automatic. The auto-raise engine considers only definitions carrying a
class. It runs on every live stop write-back from the optimiser, keeps one action in progress per stop — the highestrankwhose rule currently fires — and cancels it when the rule stops firing or the state gate closes. (One exception: the built-in callout chase is automatic by its own machinery and defaults CLASS-LESS — its class is pure routing, authored only when a domain wants it skill-matched.) - Class-less ⇒ manual. Raised by a person, not the engine: the two-way
messageIn/messageOutfacilities, and the action raised when a notification exhausts its delivery retries.
A class is also the skill gate: the queues show a classed action only to operators whose
enabledClasses (set per user in the Administration app, picked from helix.actionClasses plus the
built-ins) include it. Unset = every class; a class-less action reaches everyone. Class gates pools,
not individuals — the resource audience ignores it (an engineer’s own inbox is addressed by
identity). The filter is applied at the operator’s next sign-in.
Suppression, and what defer really does
Section titled “Suppression, and what defer really does”An automatic action is re-evaluated on every stop write, so “handled” has to be expressed somewhere or it comes straight back:
- Recording an outcome writes
stop.actions.<name>. For a state-gated action that is enough — the engine will not re-raise it for the rest of that visit, and re-arms only if the stop re-enters the state. - For an ungated action the suppression is yours to author. The
textfunction must consultthis.actions[<name>]and returnnullonce it is satisfied. Nothing else will stop it. deferhides, it does not suppress. It sets a timestamp that makes the screen hide all of that stop’s actions for the period. The engine keeps the action raised throughout.
Related
Section titled “Related”- Actions guide — the role of actions, how operators work them, worked examples
- Events guide — the other mechanism: timed, domain-authored change
- stopParams — where
helix.actionsis authored - helixApp — the
actionClassescatalogue - resourceParams — the standby callout’s synthesised action