compiler

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

Documentation

Overview

Package compiler turns a BPMN model into an immutable, integer-indexed CompiledProcess (ADR-0004). Element ids become array indices, topology lives in shared contiguous arrays, and per-type data lives in detail tables, so the runtime hot path is pointer arithmetic with no strings, maps, or locks (invariant I5).

This is the minimal target structure plus a programmatic Builder. The XML parse/resolve/validate front end (compiler.md stages 1–5) is a later milestone; the linearized result here is the shape the engine consumes.

Index

Constants

View Source
const (
	RuleReachability           = "reachability"
	RuleGatewayNoOutgoing      = "gateway.no-outgoing"
	RuleGatewayNoIncoming      = "gateway.no-incoming"
	RuleGatewayMultipleDefault = "gateway.multiple-default"
	RuleGatewayMissingDefault  = "gateway.missing-default"
	RuleBoundaryIncomingFlow   = "boundary.incoming-flow"
	RuleBoundaryInvalidHost    = "boundary.invalid-host"
	RuleFlowCrossScope         = "flow.cross-scope"
	// RuleErrorUnhandled marks an error end event with no statically matching enclosing
	// error boundary or error event subprocess in the same process (ADR-0089). A warning,
	// not an error: the catch may live at a call-activity caller one process cannot see,
	// and the runtime incident is the real terminal for a truly uncaught error.
	RuleErrorUnhandled = "error.unhandled"
	// RuleCancelEndOutsideTransaction marks a cancel end event whose enclosing scope is not a
	// transaction — an error, since BPMN allows a cancel end only within a <transaction> (ADR-0108).
	RuleCancelEndOutsideTransaction = "cancel.end-outside-transaction"
	// RuleCancelBoundaryInvalidHost marks a cancel boundary attached to something other than a
	// transaction — an error, since a cancel boundary may attach only to a <transaction> (ADR-0108).
	RuleCancelBoundaryInvalidHost = "cancel.boundary-invalid-host"
	// RuleTransactionNoCancelBoundary marks a transaction that has a cancel end event but no
	// cancel boundary (ADR-0108). A warning: the cancellation tears the transaction down with
	// no recovery route, usually a modeling mistake, but not structurally invalid.
	RuleTransactionNoCancelBoundary = "transaction.no-cancel-boundary"
	// RuleEventGatewayTarget marks an event-based gateway whose outgoing flow leads to a
	// non-catch element — an error, since a deferred choice can only race catch events
	// (message/timer/signal intermediate catch); a task or gateway cannot participate (ADR-0110).
	RuleEventGatewayTarget = "event-gateway.invalid-target"
	// RuleTimerStartSchedule marks a timer start event whose constant FEEL schedule cannot be
	// resolved to a valid duration/date/cycle at deploy (ADR-0111). It is an error: a start
	// schedule that will not resolve arms nothing, so the process would silently never trigger.
	// A start-event FEEL schedule is compiler-constant (references no variables, ADR-0056), so it
	// evaluates the same way at deploy as at arm and can be checked without an instance.
	RuleTimerStartSchedule = "timer.start-schedule"
)

Rule identifiers are stable machine slugs for the check that produced a Problem, so a UI can group, filter, or link to documentation by rule without parsing the human-readable Message (which is deliberately not a stable API). They are grouped by the three validation families of ROADMAP Milestone 1: reachability, gateway coverage, and scope consistency.

View Source
const (
	// RuleParse marks a document that will not decode at all, or a model with no
	// executable process — a model-level failure with no single owning element.
	RuleParse = "parse"
	// RuleCompile marks a per-process failure in an earlier compile stage (an
	// unknown flow reference, a bad FEEL expression) — the pool named nothing the
	// graph checks could inspect, so its error is surfaced as one Problem instead.
	RuleCompile = "compile"
)

Rule slugs for whole-model dry-run findings that ValidateModel raises outside the per-node graph checks — a fault that stops the compile before a linearized graph exists, so it cannot be anchored the way the graph rules above are.

View Source
const ClioQueryJobType = "io.atlas.clio.query"

ClioQueryJobType is the reserved job type a clio "query" connector task carries. The in-process clio worker subscribes to it to read projected state (get_state) or run a stored query (run_query) on the configured clio instance and write the result back into the task's result variable (ADR-0036).

View Source
const ClioQueryJobTypeIndex int32 = 8

ClioQueryJobTypeIndex is the interned index ClioQueryJobType is guaranteed to occupy: NewBuilder reserves it ninth, so it is always 8.

View Source
const ClioReadJobType = "io.atlas.clio.read"

ClioReadJobType is the reserved job type a clio "read" connector task carries. The in-process clio worker subscribes to it to read a subject's events (read_events) from the configured clio instance and write them back into the task's result variable as a JSON array (ADR-0036).

View Source
const ClioReadJobTypeIndex int32 = 9

ClioReadJobTypeIndex is the interned index ClioReadJobType is guaranteed to occupy: NewBuilder reserves it tenth, so it is always 9.

View Source
const ClioWriteJobType = "io.atlas.clio.write"

ClioWriteJobType is the reserved job type a clio "write-events" connector task carries. The in-process clio connector worker subscribes to it to append the event to the configured clio instance (ADR-0036), the same way the DMN worker subscribes to DMNJobType.

View Source
const ClioWriteJobTypeIndex int32 = 7

ClioWriteJobTypeIndex is the interned index ClioWriteJobType is guaranteed to occupy in every compiled process: NewBuilder reserves it eighth, so it is always 7. This lets a single in-process clio worker subscribe by one global index across every deployed process, the same way the DMN worker uses DMNJobTypeIndex — which is what wires the clio connector into the server run loop (ADR-0036).

View Source
const CsvImportJobType = "io.atlas.csv-import"

CsvImportJobType is the reserved job type a CSV-import service task carries. An in-process worker parses an uploaded CSV (a `csvText` variable) against a column layout (a `columnConfig` variable, typically set by a preceding script task) into a `rows` collection — so a process ingests and validates a batch of records entirely on the engine, the upload arriving through a user-task form rather than a side-channel endpoint (ADR-0087).

View Source
const CsvImportJobTypeIndex int32 = 11

CsvImportJobTypeIndex is the interned index CsvImportJobType is guaranteed to occupy: NewBuilder reserves it twelfth, so it is always 11. A single in-process CSV worker subscribes by this global index across every deployed process, the same way the mail worker uses MailJobTypeIndex.

View Source
const DMNJobType = "io.atlas.dmn"

DMNJobType is the reserved job type business rule tasks carry. The in-process DMN worker subscribes to it to pick up decisions for evaluation, the same way an external worker subscribes to a service task's job type.

View Source
const DMNJobTypeIndex int32 = 0

DMNJobTypeIndex is the interned index DMNJobType is guaranteed to occupy in every compiled process: NewBuilder reserves it first, so it is always 0. Job type indices are otherwise per-process (interned in build order), which makes a global int32-keyed job runner ambiguous across processes — index 3 could be a service task's type in one process and something else in another. Pinning the DMN type to a single global index lets one in-process DMN worker serve every deployed process without colliding with any service-task type (which always interns to >= 1). See ADR-0014.

View Source
const JsJobType = "io.atlas.script.javascript"

JsJobType is the reserved job type a JavaScript script task carries; the in-process Node worker subscribes to it (ADR-0047), like the PowerShell worker.

View Source
const JsJobTypeIndex int32 = 6

JsJobTypeIndex is the interned index JsJobType is guaranteed to occupy: NewBuilder reserves it seventh, so it is always 6, giving the in-process Node worker one global index across every deployed process.

View Source
const MailJobType = "io.atlas.mail.send"

MailJobType is the reserved job type an outbound mail connector task carries. The in-process mail connector worker subscribes to it to send the model-authored message through a server-registered mail provider off the hot path (ADR-0079), the same way the clio worker subscribes to ClioWriteJobType.

View Source
const MailJobTypeIndex int32 = 10

MailJobTypeIndex is the interned index MailJobType is guaranteed to occupy in every compiled process: NewBuilder reserves it eleventh (after the ten job types above), so it is always 10. This lets a single in-process mail worker subscribe by one global index across every deployed process, the same way the REST worker uses RestJobTypeIndex (ADR-0067/0078).

View Source
const NumBpmnTypes = numBpmnTypes

NumBpmnTypes is the size a behavior dispatch table indexed by BpmnType needs.

View Source
const PwshJobType = "io.atlas.script.powershell"

PwshJobType is the reserved job type a PowerShell script task carries. The in-process PowerShell script worker subscribes to it to run the script off the hot path and write its result back, the same way the DMN worker subscribes to DMNJobType (ADR-0047). Each polyglot script language gets its own reserved job type so a customer can deploy and secure only the worker(s) they need.

View Source
const PwshJobTypeIndex int32 = 2

PwshJobTypeIndex is the interned index PwshJobType is guaranteed to occupy in every compiled process: NewBuilder reserves it third (after DMN and user tasks), so it is always 2. This lets a single in-process PowerShell worker subscribe by one global index across every deployed process, the same way the DMN worker uses DMNJobTypeIndex (see ADR-0047).

View Source
const PythonJobType = "io.atlas.script.python"

PythonJobType is the reserved job type a Python script task carries; the in-process Python worker subscribes to it (ADR-0047), like the PowerShell worker.

View Source
const PythonJobTypeIndex int32 = 5

PythonJobTypeIndex is the interned index PythonJobType is guaranteed to occupy: NewBuilder reserves it sixth (after DMN, user tasks, PowerShell, the temis connector, and REST), so it is always 5, giving the in-process Python worker one global index across every deployed process.

View Source
const RemedyJobType = "io.atlas.remedy.entry"

RemedyJobType is the reserved job type a BMC Remedy connector task carries. The in-process Remedy connector worker subscribes to it to create an entry (e.g. an incident) in a Remedy form through the BMC AR System REST API off the hot path (ADR-0106), the same way the mail worker subscribes to MailJobType. The provider host and credentials live in a server-registered connector, like clio/mail; only the form name and its field values are model-authored.

View Source
const RemedyJobTypeIndex int32 = 13

RemedyJobTypeIndex is the interned index RemedyJobType is guaranteed to occupy in every compiled process: NewBuilder reserves it fourteenth (after the thirteen job types above), so it is always 13. This lets a single in-process Remedy worker subscribe by one global index across every deployed process, the same way the mail worker uses MailJobTypeIndex (ADR-0079/0106).

View Source
const RestJobType = "io.atlas.http.rest"

RestJobType is the reserved job type an HTTP-REST connector task carries. The in-process REST connector worker subscribes to it to call the model-authored REST endpoint off the hot path and write the response back (ADR-0036/0067), the same way the clio worker subscribes to ClioWriteJobType.

View Source
const RestJobTypeIndex int32 = 4

RestJobTypeIndex is the interned index RestJobType is guaranteed to occupy in every compiled process: NewBuilder reserves it fifth (after DMN, user tasks, PowerShell, and the temis connector), so it is always 4. This lets a single in-process REST worker subscribe by one global index across every deployed process, the same way the DMN worker uses DMNJobTypeIndex (ADR-0067).

View Source
const SharePointJobType = "io.atlas.sharepoint.createitem"

SharePointJobType is the reserved job type a SharePoint connector task carries. The in-process SharePoint connector worker subscribes to it to create a list item in a model-authored SharePoint site/list through a server-registered SharePoint provider (Microsoft Graph) off the hot path (ADR-0105), the same way the mail worker subscribes to MailJobType.

View Source
const SharePointJobTypeIndex int32 = 12

SharePointJobTypeIndex is the interned index SharePointJobType is guaranteed to occupy in every compiled process: NewBuilder reserves it thirteenth (after the twelve job types above), so it is always 12. This lets a single in-process SharePoint worker subscribe by one global index across every deployed process, the same way the mail worker uses MailJobTypeIndex (ADR-0105).

View Source
const TemisDecisionJobType = "io.atlas.temis.decision"

TemisDecisionJobType is the reserved job type a *central* business rule task carries — one whose decision is evaluated by a remote temis service rather than the embedded temis library. The in-process temis decision connector worker subscribes to it to evaluate the decision off the hot path and write the result back (ADR-0050), the same way the local DMN worker subscribes to DMNJobType.

View Source
const TemisDecisionJobTypeIndex int32 = 3

TemisDecisionJobTypeIndex is the interned index TemisDecisionJobType is guaranteed to occupy in every compiled process: NewBuilder reserves it fourth (after DMN, user tasks, and PowerShell), so it is always 3. This lets a single in-process temis connector worker subscribe by one global index across every deployed process, the same way the DMN worker uses DMNJobTypeIndex (ADR-0050).

View Source
const UserTaskJobType = "io.atlas.user-task"

UserTaskJobType is the reserved job type user tasks carry. The in-process Tasks app (or an external task client) subscribes to it to list and complete human tasks, the same way the DMN worker subscribes to DMNJobType (ADR-0028).

View Source
const UserTaskJobTypeIndex int32 = 1

UserTaskJobTypeIndex is the interned index UserTaskJobType is guaranteed to occupy in every compiled process: NewBuilder reserves it second (after DMN), so it is always 1. This lets the task-list endpoint scan activatable jobs by a single global index, the same way the DMN worker uses DMNJobTypeIndex.

Variables

This section is empty.

Functions

func HasErrors

func HasErrors(ps []Problem) bool

HasErrors reports whether any Problem is error severity — the condition under which a deploy is refused. Warnings alone leave a model deployable.

Types

type BoundaryEventDetail

type BoundaryEventDetail struct {
	HostNode       int32 // ElementId of the activity this event is attached to
	Interrupting   bool  // true = cancel the host on fire (BPMN cancelActivity); false = run alongside
	Kind           BoundaryEventKind
	Schedule       TimerSchedule  // BoundaryTimer: when it fires; a cycle (non-interrupting only) recurs (ADR-0054)
	MessageName    string         // BoundaryMessage: the message it subscribes to
	CorrelationKey *expr.Compiled // BoundaryMessage: correlation-key expression (ADR-0020)
	SignalName     string         // BoundarySignal: the signal it subscribes to (ADR-0088)
	ErrorCode      string         // BoundaryError: the error code it catches; "" is a catch-all (ADR-0089)
	// CompensationHandler is the ElementId of the compensation handler activity this
	// boundary links its host to (BoundaryCompensation, ADR-0103). It is resolved at
	// compile time from the BPMN <association> joining the boundary to the handler;
	// -1 means unresolved (a compensation boundary with no association — a deploy error).
	CompensationHandler int32
}

BoundaryEventDetail is the per-boundary-event data a behavior needs at runtime. A boundary event is attached to a host activity (HostNode) and arms while the host runs; when it fires it either interrupts the host (Interrupting) or spawns a parallel token. The timer fields apply when Kind is BoundaryTimer, the message fields when Kind is BoundaryMessage (ADR-0040).

type BoundaryEventKind

type BoundaryEventKind uint8

BoundaryEventKind discriminates what a boundary event waits on.

const (
	BoundaryTimer        BoundaryEventKind = iota // waits a fixed duration, then fires
	BoundaryMessage                               // waits for a correlating message, then fires
	BoundarySignal                                // waits for a broadcast signal by name, then fires (ADR-0088)
	BoundaryError                                 // catches an error propagating up to it by code, then fires; always interrupting (ADR-0089)
	BoundaryCompensation                          // links a host activity to its compensation handler; inert — never armed as an element instance, only read on host completion to record the activity as compensable (ADR-0103)
	BoundaryCancel                                // on a transaction only: catches the transaction's cancellation and routes its recovery flow; armed inert like an error boundary, and always interrupting (ADR-0108)
)

type BpmnType

type BpmnType uint8

BpmnType is the kind of a BPMN element. It is stored in element-instance state (as uint8) for O(1) behavior dispatch.

const (
	TypeUnspecified BpmnType = iota
	TypeStartEvent
	TypeEndEvent
	TypeServiceTask
	TypeScriptTask
	TypeBusinessRuleTask
	TypeExclusiveGateway
	TypeTimerCatchEvent
	TypeMessageCatchEvent
	TypeMessageThrowEvent
	TypeTask              // an undefined/manual task: no execution semantics, passes straight through
	TypeParallelGateway   // AND gateway: forks a token onto every outgoing flow, joins by waiting for all incoming
	TypeInclusiveGateway  // OR gateway: forks onto every flow whose condition holds, joins by waiting for all that could still arrive
	TypeMessageStartEvent // a start event that a correlating message instantiates (ADR-0035); at runtime it behaves like a none start (flows straight on)
	TypeConnectorTask     // a service task that delegates to a server-registered connector via the job path (ADR-0036); like a service task it creates a job and waits
	TypeUserTask          // a human task: parks a token, creates a job, waits for a person to complete it via the Tasks app (ADR-0028)
	TypeBoundaryEvent     // a timer/message event attached to a host activity; arms while the host runs and, when it fires, interrupts the host or spawns a parallel token (ADR-0040)
	TypeScriptJobTask     // a script task authored in a general-purpose language (PowerShell, …) that runs via the job path, not inline like a FEEL script task (ADR-0047); like a service task it creates a job and waits
	TypeTimerStartEvent   // a start event that a due timer instantiates on a schedule (duration/date/cycle/cron, ADR-0051); at runtime it behaves like a none start (flows straight on)
	TypeMessageEndEvent   // an end event that publishes a message, then ends the instance (ADR-0052); the send-and-stop counterpart of a message throw event, so it reuses the throw detail table
	TypeSubProcess        // an embedded subprocess: a container that is itself a scope; a token entering it runs its inner start→…→end in a child scope, and it completes when that scope empties (ADR-0074)
	TypeCallActivity      // a call activity: starts a separate process as a child instance, waits for it, then continues; variables pass in/out by mapping (ADR-0076)
	// TypeEventSubProcessStart is a runtime-only element type: the armed trigger of an
	// event subprocess (ADR-0082). No compiled node carries it (the handler compiles as
	// TypeSubProcess); the engine arms one waiting instance per event subprocess in a
	// scope, and its firing activates the handler. It is excluded from the scope's
	// active-child counter so it never blocks scope completion.
	TypeEventSubProcessStart

	TypeSignalCatchEvent // an intermediate catch event that waits for a broadcast signal by name (ADR-0088)
	TypeSignalThrowEvent // an intermediate throw event that broadcasts a signal by name to every waiting catch (ADR-0088)
	TypeSignalEndEvent   // an end event that broadcasts a signal, then ends the instance (ADR-0088); reuses the throw detail table
	TypeSignalStartEvent // a start event that a broadcast signal instantiates (ADR-0088); at runtime it flows straight on like a message start

	TypeErrorEndEvent // an end event that throws an error, ending its scope abnormally and propagating up to the nearest matching handler (ADR-0089); the send-and-stop counterpart of a BPMN error throw

	TypeReceiveTask // an activity that waits for a correlating message, then continues (ADR-0102); the message intermediate catch's semantics in task form, so it accepts boundary events, I/O mappings, and multi-instance

	TypeCompensationThrowEvent // an intermediate throw event that triggers compensation — runs the handlers of completed compensable activities in its scope, or of one named activity (ADR-0103)
	TypeCompensationEndEvent   // an end event that triggers compensation, then ends its scope (ADR-0103); the trigger-and-stop counterpart of a compensation throw, reusing the throw detail table

	TypeCancelEndEvent // an end event inside a transaction that cancels it: compensates the transaction's completed activities in reverse order, then routes out the transaction's cancel boundary (ADR-0108)

	TypeEventBasedGateway // a deferred choice: arms every target catch event (message/timer/signal) at once and takes the branch whose event fires first, cancelling the rest (ADR-0110)

	TypeSendTask // a send task: a job-creating activity identical in execution to a service task (ADR-0112) — it creates a job and waits, reusing ServiceTaskDetail and serviceTaskBehavior; a distinct type only to preserve the send-task identity, like TypeConnectorTask

)

func (BpmnType) String

func (t BpmnType) String() string

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

Builder constructs a CompiledProcess programmatically. It stands in for the XML parse/resolve/linearize pipeline until that front end exists: callers add nodes and flows, and Build linearizes them into the immutable form (assigning the shared topology array, detail tables, and start-event list).

func NewBuilder

func NewBuilder(key uint64, bpmnProcessId string, version int32) *Builder

NewBuilder starts a builder for the process definition identified by key. It reserves the DMN job type as the first interned string so it always occupies DMNJobTypeIndex (0), giving the in-process DMN worker a stable, collision-free job type across every deployed process (see DMNJobTypeIndex).

func (*Builder) AddBoundaryCancelEvent

func (b *Builder) AddBoundaryCancelEvent(host int32) int32

AddBoundaryCancelEvent adds a cancel boundary event attached to host (a transaction): it catches the transaction's cancellation and routes its recovery flow. Armed inert like an error boundary and always interrupting (ADR-0108). Returns its element id.

func (*Builder) AddBoundaryCompensationEvent

func (b *Builder) AddBoundaryCompensationEvent(host int32) int32

AddBoundaryCompensationEvent adds a compensation boundary event attached to host: an inert marker (never armed as an element instance) that makes the host compensable and links it to a compensation handler, resolved later from a BPMN <association> via SetCompensationHandler (ADR-0103). CompensationHandler starts unresolved (-1). Returns its element id.

func (*Builder) AddBoundaryErrorEvent

func (b *Builder) AddBoundaryErrorEvent(host int32, errorCode string) int32

AddBoundaryErrorEvent adds an error boundary event attached to host that catches an error propagating up to the host whose code matches errorCode ("" is a catch-all). An error boundary is always interrupting (ADR-0089): it opens no subscription and waits only to be found by propagation. Returns its element id.

func (*Builder) AddBoundaryMessageEvent

func (b *Builder) AddBoundaryMessageEvent(host int32, interrupting bool, messageName string, correlationKey *expr.Compiled) int32

AddBoundaryMessageEvent adds a message boundary event attached to host that fires when a message named messageName correlates on key. interrupting mirrors BPMN cancelActivity (ADR-0040). Returns its element id.

func (*Builder) AddBoundarySignalEvent

func (b *Builder) AddBoundarySignalEvent(host int32, interrupting bool, signalName string) int32

AddBoundarySignalEvent adds a signal boundary event attached to host that fires when a signal named signalName is broadcast (ADR-0088). interrupting mirrors BPMN cancelActivity. Returns its element id.

func (*Builder) AddBoundaryTimerEvent

func (b *Builder) AddBoundaryTimerEvent(host int32, interrupting bool, durationNanos int64) int32

AddBoundaryTimerEvent adds a timer boundary event attached to host, firing after durationNanos. interrupting mirrors BPMN cancelActivity: true cancels the host when it fires, false spawns a parallel token (ADR-0040). Returns its element id. It is the duration convenience over AddBoundaryTimerSchedule.

func (*Builder) AddBoundaryTimerSchedule

func (b *Builder) AddBoundaryTimerSchedule(host int32, interrupting bool, schedule TimerSchedule) int32

AddBoundaryTimerSchedule adds a timer boundary event firing on the given compiled schedule. A cycle schedule on a non-interrupting boundary recurs — a repeating reminder (ADR-0054). Returns its element id.

func (*Builder) AddBusinessRuleTask

func (b *Builder) AddBusinessRuleTask(decisionId string, inputs map[string]any, retries int32) (int32, error)

AddBusinessRuleTask adds a business rule task that evaluates the named DMN decision with the given static input context, and returns its element id. It is the constant-input form of Builder.AddBusinessRuleTaskMapped (no variable mappings, result discarded).

func (*Builder) AddBusinessRuleTaskMapped

func (b *Builder) AddBusinessRuleTaskMapped(decisionId, resultVar string, staticInputs map[string]any, mappings []DecisionInputMapping, retries int32, binding DecisionBinding) (int32, error)

AddBusinessRuleTaskMapped adds a business rule task that evaluates the named DMN decision and returns its element id. Its input context is built from two layers the DMN worker merges at evaluation time: staticInputs is a constant base (JSON-encoded and interned at deploy time, never on the hot path — invariant I5), and mappings are variable-driven inputs (FEEL expressions evaluated over the instance's variables) that override a static input of the same name. If resultVar is non-empty the decision's result is written back into that process variable on job completion; an empty resultVar discards the result. It returns an error if the static inputs cannot be encoded.

func (*Builder) AddCallActivity

func (b *Builder) AddCallActivity(calledProcessId string, binding DecisionBinding, propagateAllParent, propagateAllChild bool) int32

AddCallActivity adds a call activity that starts the process with the given bpmn id as a child instance, under the given binding and variable-propagation flags (ADR-0076), and returns its element id. The called process id is interned; the called def key is resolved at deploy/runtime, not here.

func (*Builder) AddCancelEndEvent

func (b *Builder) AddCancelEndEvent() int32

AddCancelEndEvent adds a cancel end event: an end event inside a transaction that cancels it — compensating the transaction's completed activities in reverse order, then routing out the transaction's cancel boundary (ADR-0108). It carries no detail (a cancel always compensates the whole transaction). Returns its element id.

func (*Builder) AddClioQueryTask

func (b *Builder) AddClioQueryTask(connector, subject, reduceSpec, query, resultVar string, retries int32) int32

AddClioQueryTask adds a clio "query" connector task and returns its element id. It reads from the named connector's clio instance and writes the result into resultVar. When query is non-empty the worker runs it as a run_query; otherwise it reads get_state for subject (with the optional reduceSpec projection). Like a service task it creates a job on activation carrying the reserved ClioQueryJobType and waits for the in-process clio worker to complete it (ADR-0036).

func (*Builder) AddClioReadTask

func (b *Builder) AddClioReadTask(connector, subject, resultVar string, limit, retries int32) int32

AddClioReadTask adds a clio "read" connector task and returns its element id. It reads subject's events (up to limit; 0 = the connector's default) from the named connector's clio instance and writes them into resultVar as a JSON array. Like a service task it creates a job on activation carrying the reserved ClioReadJobType and waits for the in-process clio worker to complete it (ADR-0036).

func (*Builder) AddClioWriteTask

func (b *Builder) AddClioWriteTask(connector, subject, eventType string, retries int32) int32

AddClioWriteTask adds a clio "write-events" connector task and returns its element id. Like a service task it creates a job on activation and waits; the job carries the reserved ClioWriteJobType so the in-process clio worker picks it up, appends an event to the named connector's clio instance under subject with the given event type, and completes the job (ADR-0036).

func (*Builder) AddCompensationEndEvent

func (b *Builder) AddCompensationEndEvent() int32

AddCompensationEndEvent adds an end event that triggers compensation, then ends its scope — the trigger-and-stop counterpart of a compensation throw, reusing the throw detail table like a signal end event (ADR-0103). Returns its element id.

func (*Builder) AddCompensationThrowEvent

func (b *Builder) AddCompensationThrowEvent() int32

AddCompensationThrowEvent adds an intermediate throw event that, on activation, triggers compensation — running the handlers of completed compensable activities in its scope (or of the single activity later set via SetCompensationActivityRef) — then flows on (ADR-0103). ActivityRef defaults to -1 (compensate the whole scope). Returns its element id.

func (*Builder) AddDataInputAssociation

func (b *Builder) AddDataInputAssociation(node int32, dataObject, variable string, value *expr.Compiled)

AddDataInputAssociation attaches a data-input association to activity node: when the activity activates, the engine reads the data object named dataObject (bound into the FEEL scope under its name), evaluates value (a FEEL transform over the instance's variables and that object, nil to copy the object's value verbatim), and writes the result into the process variable named variable, which the activity then reads (ADR-0059). Build groups a node's associations into a shared array.

func (*Builder) AddDataObject

func (b *Builder) AddDataObject(name, itemType, initialState string, isCollection bool) int32

AddDataObject declares a data object on the process: a typed, named datum with an optional declared structure (itemType) and initial data state, seeded under each instance's scope at creation (ADR-0053). It is not a flow node, so it returns the index of the entry in the data-object table, not an element id. Empty itemType or initialState intern to -1 (Intern maps that back to "").

func (*Builder) AddDataOutputAssociation

func (b *Builder) AddDataOutputAssociation(node int32, dataObject string, value *expr.Compiled, targetState, targetPath string)

AddDataOutputAssociation attaches a data-output association to activity node: when the activity completes, the engine evaluates value (a FEEL expression over the instance's variables, nil for a state-only transition) and writes it into the data object named dataObject, advancing that object's data state to targetState (empty keeps the object's current state) — ADR-0058. A non-empty targetPath writes only that member of a structured object, keeping the rest (ADR-0060). Build groups a node's associations into a shared array.

func (*Builder) AddEndEvent

func (b *Builder) AddEndEvent() int32

AddEndEvent adds a none end event and returns its element id.

func (*Builder) AddErrorEndEvent

func (b *Builder) AddErrorEndEvent(errorCode string) int32

AddErrorEndEvent adds an end event that throws the given error code — ending its scope abnormally and propagating up to the nearest matching handler rather than completing normally (ADR-0089). A code-less error end throws "". Returns its element id.

func (*Builder) AddEventBasedGateway

func (b *Builder) AddEventBasedGateway() int32

AddEventBasedGateway adds an event-based gateway (deferred choice) and returns its element id. It carries no detail: at runtime it arms every target catch event (each outgoing flow must lead to a message/timer/signal intermediate catch) and takes the branch whose event fires first, cancelling the rest (ADR-0110).

func (*Builder) AddExclusiveGateway

func (b *Builder) AddExclusiveGateway() int32

AddExclusiveGateway adds a data-based exclusive gateway (XOR split) and returns its element id. Its outgoing flows carry the conditions; see SetFlowCondition and SetFlowDefault.

func (*Builder) AddInclusiveGateway

func (b *Builder) AddInclusiveGateway() int32

AddInclusiveGateway adds an inclusive (OR) gateway and returns its element id. As a split it takes every outgoing flow whose condition holds (or the default if none do); as a join it waits until every branch that could still deliver a token has, then fires once. Conditions and the default flow are set the same way as for an exclusive gateway.

func (*Builder) AddInputMapping

func (b *Builder) AddInputMapping(node int32, target string, source *expr.Compiled)

AddInputMapping attaches a zeebe:ioMapping input to activity node: when the activity activates, the engine evaluates source (a FEEL expression over the scope chain from the activity's flow scope) and writes the result into the activity-local variable named target, which the activity then sees (ADR-0068). Build groups a node's input mappings into a shared array. The parser owns validation; the builder only interns the target, mirroring the data-association adds.

func (*Builder) AddMailConnectorTask

func (b *Builder) AddMailConnectorTask(cfg MailConfig) int32

AddMailConnectorTask adds an outbound mail connector task and returns its element id. Like a service task it creates a job on activation and waits; the job carries the reserved MailJobType so the in-process mail worker picks it up, evaluates any FEEL recipient/subject/body values over the instance's variables, resolves the named connector's provider client, sends the message, and completes the job (ADR-0079). The provider endpoint and credentials are resolved server-side from the named connector, never authored in the model — mirroring clio (ADR-0036).

func (*Builder) AddMessageCatchEvent

func (b *Builder) AddMessageCatchEvent(messageName string, correlationKey *expr.Compiled) int32

AddMessageCatchEvent adds an intermediate message catch event that, on activation, subscribes to the named message with a correlation key produced by the given compiled FEEL expression (evaluated over the instance's variables), then waits until a matching message is correlated. Returns its element id.

func (*Builder) AddMessageEndEvent

func (b *Builder) AddMessageEndEvent(messageName string, correlationKey *expr.Compiled) int32

AddMessageEndEvent adds an end event that, on activation, publishes the named message with a correlation key produced by the given compiled FEEL expression (evaluated over the ending instance's variables), then ends the instance. It reuses the throw detail table, since a message end event throws exactly like an intermediate throw event and only differs in its completion (ADR-0054). Returns its element id.

func (*Builder) AddMessageStartEvent

func (b *Builder) AddMessageStartEvent(messageName string, correlationKey *expr.Compiled, singletonStart bool) int32

AddMessageStartEvent adds a message start event and returns its element id. It is a process entry point like a none start event — at runtime it simply flows straight on — but the engine also registers it at deploy time so a correlating message (a throw event or an API publish of messageName) instantiates a fresh process instance seeded with the message's payload (ADR-0035). correlationKey is compiled for future use; message-start matching is by name today.

func (*Builder) AddMessageThrowEvent

func (b *Builder) AddMessageThrowEvent(messageName string, correlationKey *expr.Compiled) int32

AddMessageThrowEvent adds an intermediate message throw event that, on activation, publishes the named message with a correlation key produced by the given compiled FEEL expression (evaluated over the throwing instance's variables), then completes. Returns its element id.

func (*Builder) AddOutputMapping

func (b *Builder) AddOutputMapping(node int32, target string, source *expr.Compiled)

AddOutputMapping attaches a zeebe:ioMapping output to activity node: when the activity completes, the engine evaluates source (a FEEL expression over the activity-local scope) and promotes the result into the parent (flow) scope under the variable named target (ADR-0068). Build groups a node's output mappings into a shared array.

func (*Builder) AddParallelGateway

func (b *Builder) AddParallelGateway() int32

AddParallelGateway adds a parallel (AND) gateway and returns its element id. It forks a token onto every outgoing flow and joins by waiting until a token has arrived on each of its incoming flows.

func (*Builder) AddReceiveTask

func (b *Builder) AddReceiveTask(messageName string, correlationKey *expr.Compiled) int32

AddReceiveTask adds a receive task that, on activation, subscribes to the named message with a correlation key produced by the given compiled FEEL expression, then waits until a matching message is correlated — the message-catch semantics as an activity (ADR-0102). Returns its element id.

func (*Builder) AddRemedyConnectorTask

func (b *Builder) AddRemedyConnectorTask(cfg RemedyConfig) int32

AddRemedyConnectorTask adds a BMC Remedy connector task and returns its element id. Like a service task it creates a job on activation and waits; the job carries the reserved RemedyJobType so the in-process Remedy worker picks it up, evaluates any FEEL form/field values over the instance's variables, resolves the named connector's AR System REST client, creates the entry, writes the new entry id into ResultVar (empty = discard it), and completes the job (ADR-0106). The Remedy base URL and credentials are resolved server-side from the named connector, never authored in the model — mirroring clio and mail (ADR-0036/0079).

func (*Builder) AddRestConnectorTask

func (b *Builder) AddRestConnectorTask(cfg RestConfig) int32

AddRestConnectorTask adds an HTTP-REST connector task and returns its element id. Like a service task it creates a job on activation and waits; the job carries the reserved RestJobType so the in-process REST worker picks it up, evaluates any FEEL url/header/query values over the instance's variables, calls the endpoint with the given method, writes the JSON response into ResultVar (empty = discard the response), and completes the job (ADR-0067). Method is stored as given (the parser uppercases and validates it).

func (*Builder) AddScriptJobTask

func (b *Builder) AddScriptJobTask(jobType, language, source, resultVar string, retries int32) int32

AddScriptJobTask adds a job-based script task authored in a general-purpose language (ADR-0047) and returns its element id. Like a service task it creates a job on activation and waits; the job carries jobType — a reserved per-language sentinel (e.g. PwshJobType) the in-process script worker for that language picks up, runs source through the interpreter, and completes the job, writing the result into the resultVar process variable. The parser owns language validation and the language→jobType mapping; the builder only interns what it is given, the same way AddServiceTask and the connector adds do.

func (*Builder) AddScriptTask

func (b *Builder) AddScriptTask(e *expr.Compiled, resultVar string) int32

AddScriptTask adds a script task that evaluates the given compiled FEEL expression and writes the result to resultVar. Returns its element id.

func (*Builder) AddSendTask

func (b *Builder) AddSendTask(jobType string, retries int32) int32

AddSendTask adds a send task with the given job type and retries and returns its element id (ADR-0112). A send task is a service task under a different BPMN label: it creates a job and waits, so it reuses the service-task detail table and (at runtime) serviceTaskBehavior. Only its node type (TypeSendTask) differs, to preserve the send-task identity — the TypeConnectorTask "distinct type, shared behavior" pattern.

func (*Builder) AddServiceTask

func (b *Builder) AddServiceTask(jobType string, retries int32) int32

AddServiceTask adds a service task with the given job type and retries and returns its element id.

func (*Builder) AddSharePointConnectorTask

func (b *Builder) AddSharePointConnectorTask(cfg SharePointConfig) int32

AddSharePointConnectorTask adds a SharePoint connector task and returns its element id. Like a service task it creates a job on activation and waits; the job carries the reserved SharePointJobType so the in-process SharePoint worker picks it up, evaluates any FEEL site/list/field values over the instance's variables, resolves the named connector's Graph client, creates the list item, writes the created item's JSON into ResultVar, and completes the job (ADR-0105). The Graph base and credentials are resolved server-side from the named connector, never authored in the model — mirroring the mail connector (ADR-0079).

func (*Builder) AddSignalCatchEvent

func (b *Builder) AddSignalCatchEvent(signalName string) int32

AddSignalCatchEvent adds an intermediate signal catch event that waits for a broadcast signal of the given name (ADR-0088). Returns its element id.

func (*Builder) AddSignalEndEvent

func (b *Builder) AddSignalEndEvent(signalName string) int32

AddSignalEndEvent adds an end event that broadcasts the named signal, then ends the instance — the send-and-stop counterpart of a signal throw, reusing the throw detail table like a message end event (ADR-0088).

func (*Builder) AddSignalStartEvent

func (b *Builder) AddSignalStartEvent(signalName string) int32

AddSignalStartEvent adds a start event that a broadcast signal instantiates (ADR-0088); at runtime it flows straight on like a message start.

func (*Builder) AddSignalThrowEvent

func (b *Builder) AddSignalThrowEvent(signalName string) int32

AddSignalThrowEvent adds an intermediate signal throw event that, on activation, broadcasts the named signal to every waiting catch, then completes (ADR-0088).

func (*Builder) AddStartEvent

func (b *Builder) AddStartEvent() int32

AddStartEvent adds a none start event and returns its element id.

func (*Builder) AddSubProcess

func (b *Builder) AddSubProcess() int32

AddSubProcess adds an embedded subprocess container node and returns its element id. It carries no detail; its inner flow lives in the flat node/flow arrays, linked back to it only by the children's FlowScope. Create it first, then PushScope(its id) before adding its children so they land in its scope (ADR-0074).

func (*Builder) AddTask

func (b *Builder) AddTask() int32

AddTask adds an undefined/manual task — one with no execution semantics — and returns its element id. It carries no detail and simply passes the token straight through, so a model can be drafted and its routing tested before its tasks are given real implementations.

func (*Builder) AddTemisDecisionTask

func (b *Builder) AddTemisDecisionTask(connector, decisionId, resultVar string, staticInputs map[string]any, mappings []DecisionInputMapping, retries int32) (int32, error)

AddTemisDecisionTask adds a *central* business rule task: one whose decision is evaluated by the named server-registered temis connector rather than the embedded temis library (ADR-0050). It returns its element id. Authoring is otherwise identical to a local business rule task — same decision id, result variable, static inputs, and variable mappings — the only difference is that the task carries the temis-connector job type so the remote worker picks it up.

func (*Builder) AddTimerCatchEvent

func (b *Builder) AddTimerCatchEvent(durationNanos int64) int32

AddTimerCatchEvent adds an intermediate timer catch event that waits the given fixed duration (nanoseconds) before continuing, and returns its element id. It is the duration convenience over AddTimerCatchSchedule.

func (*Builder) AddTimerCatchSchedule

func (b *Builder) AddTimerCatchSchedule(schedule TimerSchedule) int32

AddTimerCatchSchedule adds an intermediate timer catch event that waits until the given schedule's first due date, then continues. A catch fires once, so the schedule is a duration or date, never a cycle (ADR-0054). Returns its element id.

func (*Builder) AddTimerStartEvent

func (b *Builder) AddTimerStartEvent(schedule TimerSchedule) int32

AddTimerStartEvent adds a timer start event and returns its element id. Like a none start it is a process entry point that flows straight on once instantiated; what makes it a start is the deploy-time timer the engine arms from its schedule, which instantiates a fresh process instance each time it fires (ADR-0051).

func (*Builder) AddUserTask

func (b *Builder) AddUserTask(name, assignee, candidateGroups, formId string, priority int32, dueDateNanos int64, retries int32) int32

AddUserTask adds a user task that parks a token and creates a job for a human to complete via the Tasks app (ADR-0028). assignee and candidateGroups are optional (empty strings are stored as -1). Returns its element id.

func (*Builder) Build

func (b *Builder) Build() (*CompiledProcess, error)

Build linearizes the accumulated nodes and flows into an immutable CompiledProcess. It returns an error if a flow references an unknown node.

func (*Builder) Connect

func (b *Builder) Connect(source, target int32) int32

Connect adds a sequence flow from source to target and returns its flow id, so the caller can attach a condition or mark it the default.

func (*Builder) CurrentScope

func (b *Builder) CurrentScope() int32

CurrentScope reports the scope nodes are added into now (-1 at the process root).

func (*Builder) PopScope

func (b *Builder) PopScope()

PopScope closes the innermost open scope, restoring the enclosing one.

func (*Builder) PushScope

func (b *Builder) PushScope(id int32)

PushScope opens scope id: every node added until the matching PopScope carries id as its FlowScope. Scopes nest, so the outer scope is saved and restored.

func (*Builder) SetCompensationActivityRef

func (b *Builder) SetCompensationActivityRef(throwNodeID, activityRef int32)

SetCompensationActivityRef narrows a compensation throw/end event to compensate a single activity (by element id) rather than the whole scope (ADR-0103). The node must be a compensation throw or end event.

func (*Builder) SetCompensationHandler

func (b *Builder) SetCompensationHandler(boundaryNodeID, handlerNodeID int32)

SetCompensationHandler resolves a compensation boundary event's handler link: it points the boundary node (a BoundaryCompensation) at the handler activity's element id (ADR-0103). The boundary must be a compensation boundary; other kinds are left untouched.

func (*Builder) SetElementBpmnId

func (b *Builder) SetElementBpmnId(nodeID int32, bpmnID string)

SetElementBpmnId records the source BPMN element id (e.g. "StartEvent_1") for a node so it can be mapped back for diagnostics and the live diagram overlay. It is optional: nodes without one report "" from CompiledProcess.ElementBpmnId.

func (*Builder) SetEventSubProcess

func (b *Builder) SetEventSubProcess(nodeID int32, d EventSubProcessDetail)

SetEventSubProcess marks an already-added subprocess node event-triggered (ADR-0082), carrying the trigger detail its start event describes. It is applied after the subprocess and its inner start exist (like SetMultiInstance), and its EventSub field then indexes the detail. Build groups event-subprocess handlers by their parent scope so the runtime can arm them when the scope is entered.

func (*Builder) SetExecutable

func (b *Builder) SetExecutable(v bool)

SetExecutable records the process's bpmn:isExecutable flag. A non-executable process is descriptive-only — the API refuses to start it and hides it from the start surfaces (it still deploys and lists so it can be inspected).

func (*Builder) SetFlowCondition

func (b *Builder) SetFlowCondition(flowID int32, c *expr.Compiled)

SetFlowCondition attaches a compiled FEEL guard to a flow (an exclusive gateway takes the first flow whose condition is true).

func (*Builder) SetFlowDefault

func (b *Builder) SetFlowDefault(flowID int32)

SetFlowDefault marks a flow as its gateway's default (taken when no condition matches).

func (*Builder) SetInstanceTtl

func (b *Builder) SetInstanceTtl(nanos int64)

SetInstanceTtl records the process's instance TTL in nanoseconds — the self-cleaning expiry bound (ADR-0085). Zero (the default) means no TTL: instances never expire on their own. The parser passes an already-validated positive duration.

func (*Builder) SetMultiInstance

func (b *Builder) SetMultiInstance(nodeID int32, sequential bool, inputElement, outputCollection string, inputCollection, cardinality, outputElement, completionCondition *expr.Compiled)

SetMultiInstance marks an already-added node a multi-instance activity carrying the given loop characteristics (ADR-0077), interning the per-iteration and result variable names. The node keeps its real activity type; its MultiInstance field is set to index the loop detail. Applied after the node exists (like io-mappings), so any activity — task, subprocess, or call activity — can be a loop. Exactly one of inputCollection or cardinality should be non-nil (the parser enforces it).

func (*Builder) SetStartFormId

func (b *Builder) SetStartFormId(id string)

SetStartFormId records the process's start-form id — the form the UI shows before creating an instance, whose data becomes the start variables (ADR-0028). It is design-time metadata the engine ignores.

func (*Builder) SetTransaction

func (b *Builder) SetTransaction(nodeID int32)

SetTransaction marks an already-added subprocess node as a <transaction> (ADR-0108), so the runtime and validation know it may host a cancel boundary and hold a cancel end event. A no-op for an out-of-range node.

func (*Builder) SetVersionTag

func (b *Builder) SetVersionTag(s string)

SetVersionTag records the process's atlas:versionTag — an optional revision label (e.g. "1.4.0") shown in Operations beside the deploy version. Design-time metadata.

type BusinessRuleTaskDetail

type BusinessRuleTaskDetail struct {
	JobType       int32 // interned reserved job type (DMN local, or temis connector) → index
	DecisionId    int32 // interned DMN decision id → index
	Inputs        int32 // interned JSON object of static inputs → index, -1 if none
	ResultVar     int32 // interned result-variable name → index, -1 if none
	Connector     int32 // interned temis connector name → index, -1 = local (in-engine)
	Retries       int32
	Binding       DecisionBinding        // how the decision model is resolved (ADR-0063)
	InputMappings []DecisionInputMapping // variable-driven inputs, evaluated off the hot path
}

BusinessRuleTaskDetail is the per-business-rule-task data a behavior needs at runtime. A business rule task delegates to a DMN decision, evaluated off the hot path by the temis engine (ADR-0014). Like a service task it runs as a job, so it carries a JobType (a reserved DMN sentinel) the in-process DMN worker subscribes to; DecisionId names the decision to evaluate.

Its inputs come from two layers the worker merges: Inputs is an interned JSON object of static constant inputs (a literal base), and InputMappings are the variable-driven inputs — FEEL expressions evaluated over the instance's variables, which override a static input of the same name. ResultVar, if set, is the process variable the decision's result is written back into on job completion (the output mapping); -1 if the task discards its result.

Connector selects the evaluation locus (ADR-0050): -1 (the default) means the decision is evaluated locally by the embedded temis library (ADR-0014); a set Connector is the interned name of a server-registered temis connector that evaluates the decision centrally, and the task then carries the temis-connector job type instead of the local DMN job type.

type CallActivityDetail

type CallActivityDetail struct {
	CalledProcessId    int32 // interned bpmn process id of the called process
	Binding            DecisionBinding
	PropagateAllParent bool // pass all caller variables into the child (default true)
	PropagateAllChild  bool // return all child variables to the caller (default true)
}

CallActivityDetail is the per-call-activity data a behavior needs at runtime: the bpmn process id of the process to start as a child instance (interned), the binding that picks its version (latest vs this deployment), and whether variables propagate wholesale in and out (Zeebe's propagateAll flags — when off, only the activity's input/output mappings pass variables, giving an isolated child) (ADR-0076). The called def key is resolved at deploy/runtime, not compiled here.

type CallActivityRef

type CallActivityRef struct {
	ElementId          string
	CalledProcessId    string
	Binding            DecisionBinding
	PropagateAllParent bool
	PropagateAllChild  bool
	MultiInstance      bool
}

CallActivityRef is the static, read-only view of one call activity: the BPMN element that hosts it, the process id it calls, the version binding, whether variables propagate wholesale in/out, and whether it is a multi-instance loop (spawning one child per collection element). It carries no resolved def key — which deployed definition the call reaches is a per-server, deploy-time fact the server layer computes on top of this (ADR-0076).

type CompensationDetail

type CompensationDetail struct {
	ActivityRef int32
}

CompensationDetail is the per-compensation-throw data the runtime needs (ADR-0103), shared by the compensation throw and end events like the message/signal throw table. ActivityRef is the ElementId of the single activity to compensate, or -1 to compensate every completed compensable activity in the throw's scope (reverse completion order).

type CompiledDataObject

type CompiledDataObject struct {
	Name         int32 // interned data-object name → index
	ItemType     int32 // interned itemDefinition reference → index, -1 if untyped
	InitialState int32 // interned initial data state → index, -1 if none
	IsCollection bool
}

CompiledDataObject is one BPMN data object declared by a process: a typed, named datum with an optional declared structure and initial data state. Unlike a CompiledNode it is not a flow node — no token flows through it (ADR-0053) — so it lives in its own table, not the node array, and the engine seeds one under each instance's scope at creation. All string fields are interned indices (resolve with CompiledProcess.Intern); -1 means unset.

type CompiledFlow

type CompiledFlow struct {
	Id        int32
	Source    int32 // ElementId
	Target    int32 // ElementId
	Condition *expr.Compiled
	Default   bool
}

CompiledFlow is a sequence flow between two nodes. Condition is the compiled FEEL guard an exclusive gateway evaluates to decide whether to take this flow (nil = unconditional); Default marks the flow taken when no condition matches.

type CompiledNode

type CompiledNode struct {
	ElementId       int32 // == index in nodes[]
	Type            BpmnType
	OutgoingStart   int32 // offset into outgoingFlows
	OutgoingCount   int32
	IncomingCount   int32 // number of sequence flows targeting this node (a parallel join waits for all)
	FlowScope       int32 // ElementId of enclosing scope, -1 = process root
	Detail          int32 // index into the matching detail table, -1 if none
	BoundaryStart   int32 // offset into boundaryEvents (the node ids of events attached to this activity)
	BoundaryCount   int32 // number of boundary events attached (0 for a non-host node)
	DataOutStart    int32 // offset into dataOutAssocs (the data-output associations of this activity)
	DataOutCount    int32 // number of data-output associations (0 for a node with none)
	DataInStart     int32 // offset into dataInAssocs (the data-input associations of this activity)
	DataInCount     int32 // number of data-input associations (0 for a node with none)
	IOInStart       int32 // offset into ioInputs (the zeebe:ioMapping inputs of this activity)
	IOInCount       int32 // number of input mappings (0 for a node with none)
	IOOutStart      int32 // offset into ioOutputs (the zeebe:ioMapping outputs of this activity)
	IOOutCount      int32 // number of output mappings (0 for a node with none)
	ScopeStartStart int32 // offset into scopeStarts (the start events nested directly in this subprocess)
	ScopeStartCount int32 // number of nested start events (0 for a non-subprocess node)
	MultiInstance   int32 // index into multiInstances, -1 if this node is not a multi-instance loop (ADR-0077)
	EventSub        int32 // index into eventSubProcesses, -1 if this subprocess is not event-triggered (ADR-0082)
	EventSubStart   int32 // offset into eventSubs (the event-subprocess handler nodes nested directly in this scope)
	EventSubCount   int32 // number of event subprocesses in this scope (0 for a node that hosts none)
	Transaction     bool  // this subprocess is a <transaction>: it may hold a cancel end event and host a cancel boundary (ADR-0108)
}

CompiledNode is one BPMN element. It stays small; type-specific data lives in detail tables referenced by Detail.

type CompiledProcess

type CompiledProcess struct {
	Key           uint64 // ProcessDefinitionKey
	BpmnProcessId int32  // interned
	Version       int32
	// contains filtered or unexported fields
}

CompiledProcess is the immutable result of compiling one process definition. It is safe for concurrent reads without synchronization.

func Parse

func Parse(key uint64, version int32, r io.Reader) (*CompiledProcess, error)

Parse reads a BPMN 2.0 XML model and compiles the first <process> into an immutable CompiledProcess keyed by key at the given version. It is the front end to the linearizer (compiler.md stages 1–2 and 6): it parses the XML, resolves string element ids to integer indices, and pours the result into the shared Builder. Validation beyond reference integrity (reachability, gateway coverage) is a later stage.

Service-task job types come from the Zeebe task-definition extension element (<zeebe:taskDefinition type="..." retries="..."/>), the de-facto standard for executable BPMN.

func ParseNamed

func ParseNamed(key uint64, version int32, r io.Reader, processId string) (*CompiledProcess, error)

ParseNamed compiles the single process with the given BPMN process id. It is the reload path: a stored deployment records which process (by id) within its (possibly collaboration) XML it represents, so recovery recompiles exactly that one under its original key.

func (*CompiledProcess) BoundaryEvent

func (p *CompiledProcess) BoundaryEvent(detail int32) *BoundaryEventDetail

BoundaryEvent returns the boundary-event detail at the given table index.

func (*CompiledProcess) BoundaryEvents

func (p *CompiledProcess) BoundaryEvents(id int32) []int32

BoundaryEvents returns the element ids of the boundary events attached to the activity node id, as a slice into the shared topology array (no allocation). Empty for a node with no attached boundary events.

func (*CompiledProcess) BusinessRuleDecisions

func (p *CompiledProcess) BusinessRuleDecisions() []string

BusinessRuleDecisions returns the DMN decision ids this process's business rule tasks reference, distinct and in node order — empty if it has none. The server uses it at deploy time to pick and deploy the DMN model that provides those decisions into the DMN registry, so the tasks can be evaluated (ADR-0014).

func (*CompiledProcess) BusinessRuleTask

func (p *CompiledProcess) BusinessRuleTask(detail int32) *BusinessRuleTaskDetail

BusinessRuleTask returns the detail at the given table index.

func (*CompiledProcess) CallActivities

func (p *CompiledProcess) CallActivities() []CallActivityRef

CallActivities returns every call activity in this process, in node order — empty if it has none. It mirrors BusinessRuleDecisions: a static enumeration of an outbound reference (here the called process id) that the server surfaces so operators can see and manage the call activities deployed on a server — which process calls which, and whether the target resolves (ADR-0076).

func (*CompiledProcess) CallActivity

func (p *CompiledProcess) CallActivity(detail int32) *CallActivityDetail

CallActivity returns the call-activity detail at the given table index.

func (*CompiledProcess) CompensationThrow

func (p *CompiledProcess) CompensationThrow(detail int32) *CompensationDetail

CompensationThrow returns the compensation-throw detail at the given table index — shared by the compensation throw and end events (ADR-0103).

func (*CompiledProcess) ConnectorTask

func (p *CompiledProcess) ConnectorTask(detail int32) *ConnectorTaskDetail

ConnectorTask returns the connector-task detail at the given table index.

func (*CompiledProcess) ConnectorTaskOf

func (p *CompiledProcess) ConnectorTaskOf(id int32) (*ConnectorTaskDetail, error)

ConnectorTaskOf returns the connector-task detail for element node id, or an error if id is not a connector task in this compiled process. It is the bounds-checked accessor for the job-worker path: a persisted job can outlive the process definition that compiled its element as a connector task (e.g. a job created before a redeploy that recompiled the element into something else, or dropped its connector-task table), and resolving such a stale job must fail it into an incident (ADR-0061) rather than index out of range and panic the job-runner goroutine — an unrecovered panic there crashes the whole server. A worker that gets an error returns it, and FailJob retries then parks the token.

func (*CompiledProcess) DataInputAssociations

func (p *CompiledProcess) DataInputAssociations(id int32) []DataInputAssociation

DataInputAssociations returns the data-input associations of activity node id, as a slice into the shared array (no allocation). Empty for a node with none. The engine evaluates them when the activity activates to read its data objects into process variables (ADR-0059).

func (*CompiledProcess) DataObjects

func (p *CompiledProcess) DataObjects() []CompiledDataObject

DataObjects returns the process's declared data objects — the typed, named data seeded under each instance's scope at creation (ADR-0053). Empty for a process that declares none. String fields are interned; resolve with Intern.

func (*CompiledProcess) DataOutputAssociations

func (p *CompiledProcess) DataOutputAssociations(id int32) []DataOutputAssociation

DataOutputAssociations returns the data-output associations of activity node id, as a slice into the shared array (no allocation). Empty for a node with none. The engine evaluates them when the activity completes to write its data objects (ADR-0058).

func (*CompiledProcess) ElementBpmnId

func (p *CompiledProcess) ElementBpmnId(id int32) string

ElementBpmnId returns the source BPMN element id for a node (the string id bpmn-js uses, e.g. "StartEvent_1"), or "" if the node index is out of range or no id was recorded. Used to map runtime element instances back onto a diagram.

func (*CompiledProcess) ErrorEnd

func (p *CompiledProcess) ErrorEnd(detail int32) *ErrorEndDetail

ErrorEnd returns the error-end detail at the given table index (ADR-0089).

func (*CompiledProcess) EventSubProcess

func (p *CompiledProcess) EventSubProcess(detail int32) *EventSubProcessDetail

EventSubProcess returns the event-subprocess detail at the given table index — the trigger the runtime arms while the parent scope runs (ADR-0082).

func (*CompiledProcess) EventSubprocesses

func (p *CompiledProcess) EventSubprocesses(id int32) []int32

EventSubprocesses returns the handler node ids of the event subprocesses nested directly in the subprocess scope id — the triggers the runtime arms when that subprocess is entered — as a slice into the shared topology array (no allocation). Empty for a scope that hosts none. Use RootEventSubprocesses for the process root.

func (*CompiledProcess) Flow

func (p *CompiledProcess) Flow(id int32) *CompiledFlow

Flow returns the flow with the given id.

func (*CompiledProcess) IOInputs

func (p *CompiledProcess) IOInputs(id int32) []IOMapping

IOInputs returns the zeebe:ioMapping input mappings of activity node id, as a slice into the shared array (no allocation). Empty for a node with none. The engine evaluates them when the activity activates to write its activity-local scope (ADR-0068).

func (*CompiledProcess) IOOutputs

func (p *CompiledProcess) IOOutputs(id int32) []IOMapping

IOOutputs returns the zeebe:ioMapping output mappings of activity node id, as a slice into the shared array (no allocation). Empty for a node with none. The engine evaluates them when the activity completes to promote selected values to the parent scope (ADR-0068).

func (*CompiledProcess) InstanceTtlNanos

func (p *CompiledProcess) InstanceTtlNanos() int64

InstanceTtlNanos returns the process's instance TTL in nanoseconds, or 0 when no TTL is configured. A positive value is the self-cleaning expiry bound (ADR-0085): the engine schedules a durable expiry timer at CreatedAt+TTL when an instance activates.

func (*CompiledProcess) Intern

func (p *CompiledProcess) Intern(idx int32) string

Intern returns the string for an interned index, or "" if out of range.

func (*CompiledProcess) IsEventSubProcess

func (p *CompiledProcess) IsEventSubProcess(id int32) bool

IsEventSubProcess reports whether the subprocess node id is event-triggered — a `<subProcess triggeredByEvent="true">` armed by its start event's event definition rather than entered by a flow (ADR-0082).

func (*CompiledProcess) IsExecutable

func (p *CompiledProcess) IsExecutable() bool

IsExecutable reports the process's bpmn:isExecutable flag. A non-executable process is descriptive-only: the API refuses to start it and omits it from the start surfaces. Absent in the source defaults to true (see the parser).

func (*CompiledProcess) IsTransaction

func (p *CompiledProcess) IsTransaction(id int32) bool

IsTransaction reports whether node id is a <transaction> subprocess — a subprocess that may hold a cancel end event and host a cancel boundary (ADR-0108).

func (*CompiledProcess) MessageCatch

func (p *CompiledProcess) MessageCatch(detail int32) *MessageDetail

MessageCatch returns the message-catch detail at the given table index.

func (*CompiledProcess) MessageStart

func (p *CompiledProcess) MessageStart(detail int32) *MessageDetail

MessageStart returns the message-start detail at the given table index.

func (*CompiledProcess) MessageStartEvents

func (p *CompiledProcess) MessageStartEvents() []MessageStartEvent

MessageStartEvents returns each message-start event with its element index and compiled correlation-key expression. Computed by scanning the node table at deploy time (off the hot path); empty for a process with no message start event.

func (*CompiledProcess) MessageStarts

func (p *CompiledProcess) MessageStarts() []MessageDetail

MessageStarts returns the definition's message-start-event details, one per message start event. The engine indexes these at deploy time so a correlating message can instantiate the process (ADR-0035). Empty for a process with no message start event.

func (*CompiledProcess) MessageThrow

func (p *CompiledProcess) MessageThrow(detail int32) *MessageDetail

MessageThrow returns the message-throw detail at the given table index.

func (*CompiledProcess) MultiInstance

func (p *CompiledProcess) MultiInstance(detail int32) *MultiInstanceDetail

MultiInstance returns the loop characteristics at the given table index — the per-activity multi-instance detail a node's MultiInstance field points at (ADR-0077).

func (*CompiledProcess) Node

func (p *CompiledProcess) Node(id int32) *CompiledNode

Node returns the node with the given ElementId.

func (*CompiledProcess) NodesReaching

func (p *CompiledProcess) NodesReaching(target int32) map[int32]bool

NodesReaching returns the set of node ids from which target is reachable by following sequence flows — target's ancestors in the flow graph. An inclusive join uses it to decide whether any live token upstream could still arrive (if none can, and at least one has, it fires). Computed by a reverse walk from target; target itself is not included unless a cycle leads back to it.

func (*CompiledProcess) Outgoing

func (p *CompiledProcess) Outgoing(id int32) []int32

Outgoing returns the flow ids leaving node id, as a slice into the shared topology array (no allocation).

func (*CompiledProcess) ProcessId

func (p *CompiledProcess) ProcessId() string

ProcessId returns the source BPMN process id (the <process id="…">), used to tell one process's versions apart from another's when superseding start timers (ADR-0051).

func (*CompiledProcess) ReceiveTask

func (p *CompiledProcess) ReceiveTask(detail int32) *MessageDetail

ReceiveTask returns the receive-task detail at the given table index (ADR-0102). A receive task carries the same MessageDetail as a message catch — the message name and the compiled correlation-key expression it waits on.

func (*CompiledProcess) RootEventSubprocesses

func (p *CompiledProcess) RootEventSubprocesses() []int32

RootEventSubprocesses returns the handler node ids of the event subprocesses at the process root — the triggers armed when an instance is created (ADR-0082).

func (*CompiledProcess) ScopeStartEvents

func (p *CompiledProcess) ScopeStartEvents(id int32) []int32

ScopeStartEvents returns the element ids of the start events nested directly in the subprocess node id — the scope's entry points the subprocess behavior seeds on activation — as a slice into the shared topology array (no allocation). Empty for a non-subprocess node or a subprocess with no start event (ADR-0074).

func (*CompiledProcess) ScriptJobTask

func (p *CompiledProcess) ScriptJobTask(detail int32) *ScriptJobTaskDetail

ScriptJobTask returns the script-job-task detail at the given table index.

func (*CompiledProcess) ScriptTask

func (p *CompiledProcess) ScriptTask(detail int32) *ScriptTaskDetail

ScriptTask returns the detail at the given table index.

func (*CompiledProcess) SendTask

func (p *CompiledProcess) SendTask(detail int32) *ServiceTaskDetail

SendTask returns the detail at the given table index (ADR-0112). A send task is a service task under a different label — it reuses ServiceTaskDetail and the same detail table, so this is ServiceTask by another name, kept for call-site clarity.

func (*CompiledProcess) ServiceTask

func (p *CompiledProcess) ServiceTask(detail int32) *ServiceTaskDetail

ServiceTask returns the detail at the given table index.

func (*CompiledProcess) SignalCatch

func (p *CompiledProcess) SignalCatch(detail int32) *SignalDetail

SignalCatch returns the signal-catch detail at the given table index (ADR-0088).

func (*CompiledProcess) SignalStart

func (p *CompiledProcess) SignalStart(detail int32) *SignalDetail

SignalStart returns the signal-start detail at the given table index (ADR-0088).

func (*CompiledProcess) SignalStartEvents

func (p *CompiledProcess) SignalStartEvents() []SignalStartEvent

SignalStartEvents returns each root-scope signal-start event's signal name and element index. The engine indexes these at deploy time so a broadcast signal can instantiate the process (ADR-0088), mirroring MessageStartEvents. A signal start nested in an event subprocess is that scope's trigger, not a process entry point.

func (*CompiledProcess) SignalThrow

func (p *CompiledProcess) SignalThrow(detail int32) *SignalDetail

SignalThrow returns the signal-throw detail at the given table index — shared by the signal throw and signal end events (ADR-0088).

func (*CompiledProcess) StartEvents

func (p *CompiledProcess) StartEvents() []int32

StartEvents returns the process's entry-point element ids.

func (*CompiledProcess) StartFormId

func (p *CompiledProcess) StartFormId() string

StartFormId returns the id of the form the UI shows before starting an instance, or "" if the process has no start form (ADR-0028). It is design-time metadata; the engine never reads it.

func (*CompiledProcess) TimerCatch

func (p *CompiledProcess) TimerCatch(detail int32) *TimerCatchDetail

TimerCatch returns the timer-catch detail at the given table index.

func (*CompiledProcess) TimerStart

func (p *CompiledProcess) TimerStart(detail int32) *TimerStartDetail

TimerStart returns the timer-start detail at the given table index.

func (*CompiledProcess) TimerStartEvents

func (p *CompiledProcess) TimerStartEvents() []TimerStartEvent

TimerStartEvents returns each timer-start event with its element index and compiled schedule. Computed by scanning the node table at deploy time (off the hot path); empty for a process with no timer start event.

func (*CompiledProcess) UserTask

func (p *CompiledProcess) UserTask(detail int32) *UserTaskDetail

UserTask returns the user-task detail at the given table index.

func (*CompiledProcess) VersionTag

func (p *CompiledProcess) VersionTag() string

VersionTag returns the process's atlas:versionTag revision label ("" if none). It is design-time metadata Operations shows beside the deploy version; the engine never reads it.

type ConnectorTaskDetail

type ConnectorTaskDetail struct {
	JobType    int32 // interned reserved connector job type → index
	Connector  int32 // interned connector name → index, -1 if not a clio task
	Subject    int32 // interned clio target subject → index, -1 if unused
	EventType  int32 // interned clio event type → index, -1 if not a clio write task
	ClioQuery  int32 // interned clio run_query query string → index, -1 if unused
	ReduceSpec int32 // interned clio get_state reduce-spec name → index, -1 if unused
	Limit      int32 // clio read_events limit, 0 = the connector's default
	Method     int32 // interned HTTP method → index, -1 if not a REST task
	ResultVar  int32 // interned REST/clio result variable name → index, -1 if none
	// Url is the request endpoint, Headers and Query the request headers and query
	// parameters a REST task adds (ADR-0067). Each value is literal or a FEEL
	// expression evaluated over the instance's variables at call time (the
	// Camunda-style fx toggle) — see RestExpr. Url is the zero RestExpr for a
	// non-REST (clio) task; Headers/Query are then nil. Auth is an interned JSON
	// object describing the request's authentication —
	// {"type","username","apiKeyName","secretRef"} — where secretRef names a
	// server-side secret (ADR-0041), never the value; -1 when unauthenticated.
	Url     RestExpr
	Headers []RestKV
	Query   []RestKV
	Auth    int32
	Retries int32
	// Mail connector fields (JobType == MailJobType, ADR-0079). Connector (above)
	// names the server-registered mail provider; the message is authored in the
	// model as literal-or-FEEL values evaluated over the instance's variables at
	// send time. To and Bcc/Cc are comma-separated recipient lists; From overrides
	// the provider's default sender; MailSubject and Body are the message. Each is
	// the zero RestExpr for a non-mail task. Cc/Bcc/From are also zero when a mail
	// task omits them.
	To          RestExpr
	Cc          RestExpr
	Bcc         RestExpr
	From        RestExpr
	MailSubject RestExpr
	Body        RestExpr
	// SharePoint connector fields (JobType == SharePointJobType, ADR-0105). Connector
	// (above) names the server-registered SharePoint provider (its Graph base and
	// OAuth credential live server-side). Site and List address the target list (a
	// site host/path or id, and a list name or id); Fields are the created item's
	// column values. Each is a literal-or-FEEL value evaluated over the instance's
	// variables at call time; Site/List are the zero RestExpr and Fields is nil for a
	// non-SharePoint task. ResultVar (above), if set, receives the created item's JSON.
	Site   RestExpr
	List   RestExpr
	Fields []RestKV
	// Remedy connector fields (JobType == RemedyJobType, ADR-0106). Connector (above)
	// names the server-registered BMC Remedy instance; ResultVar (above), if set,
	// receives the created entry's id. RemedyForm is the Remedy form the entry is
	// created in (literal-or-FEEL, the zero RestExpr for a non-remedy task);
	// RemedyFields are the entry's field values as name/literal-or-FEEL pairs, evaluated
	// over the instance's variables at call time (nil for a non-remedy task).
	RemedyForm   RestExpr
	RemedyFields []RestKV
}

ConnectorTaskDetail is the per-connector-task data a behavior needs at runtime. A connector task delegates to a server-registered connector evaluated off the hot path by a job worker (ADR-0036). Like a service task it runs as a job, so it carries a JobType (a reserved connector sentinel) the in-process connector worker subscribes to, and Connector names the server-registered connector to resolve at runtime. The JobType also selects which connector kind this is, and thus which of the kind-specific fields below are populated:

  • clio "write-events" (JobType == ClioWriteJobType): Connector names the server-registered clio instance; Subject and EventType are the interned clio coordinates the appended event lands under. The event body is the instance's variables.
  • clio "query" (JobType == ClioQueryJobType): Connector names the clio instance; the task reads projected state or runs a stored query and writes the result into ResultVar. Either ClioQuery (a run_query query string) is set — then the worker runs that query — or Subject (with the optional ReduceSpec projection) is set — then the worker reads get_state for that subject.
  • clio "read" (JobType == ClioReadJobType): Connector names the clio instance; Subject is the subject whose events are read (up to Limit, 0 = the connector's default) into ResultVar as a JSON array.
  • HTTP REST (JobType == RestJobType): Method and Url are the interned request method (e.g. "POST") and the full endpoint URL authored in the model (ADR-0067, revising ADR-0036 for REST); ResultVar, if set, is the process variable the JSON response is written back into on completion.
  • SharePoint (JobType == SharePointJobType): Connector names the server-registered SharePoint provider; Site and List address the target list and Fields are the created item's column values (all literal-or-FEEL); the created item's JSON is written into ResultVar when set (ADR-0105).
  • BMC Remedy (JobType == RemedyJobType): Connector names the server-registered Remedy instance; RemedyForm and RemedyFields are the form and the entry's field values (literal-or-FEEL) an incident/entry is created with through the AR System REST API; ResultVar, if set, receives the created entry's id (ADR-0106).

Unused fields for a given kind are -1 (Intern maps that back to ""); Limit is 0 when unset. The write and REST kinds send the instance's variables as the request/event body — a stand-in for full payload mappings until the variable subsystem matures.

type DataInputAssociation

type DataInputAssociation struct {
	DataObject int32 // interned source data-object name → index
	Variable   int32 // interned target process-variable name → index
	Value      *expr.Compiled
}

DataInputAssociation is one compiled <dataInputAssociation> on an activity: it reads a data object into a process variable when the activity activates, so the activity's FEEL can see it (ADR-0059). DataObject is the interned source data-object name (resolved from the association's sourceRef); Variable is the interned target process-variable name (its targetRef) the read value is written into; Value is the optional <assignment><from> FEEL transform, evaluated over the instance's variables plus the source object bound under its name — nil copies the object's value verbatim.

type DataOutputAssociation

type DataOutputAssociation struct {
	DataObject  int32 // interned target data-object name → index
	Value       *expr.Compiled
	TargetState int32
	// TargetPath is the interned member path (the association's <assignment><to>,
	// e.g. "name" or "customer.name") the write sets within a structured data
	// object, -1 to write the whole value (ADR-0060). A path write reads the object's
	// current JSON, sets that member, and writes the merged value back.
	TargetPath int32
}

DataOutputAssociation is one compiled <dataOutputAssociation> on an activity: it writes a value into a data object and advances that object's data state when the activity completes (ADR-0058). DataObject is the interned target data-object name; Value is the FEEL expression (the association's <assignment><from>) evaluated over the instance's variables to produce the written value, nil for a state-only transition; TargetState is the interned data state the write moves the object into (from the target <dataObjectReference>'s <dataState>), -1 to keep the object's current state.

type DecisionBinding

type DecisionBinding int32

DecisionBinding selects which DMN model version a local business rule task evaluates against (ADR-0063). It mirrors Camunda's zeebe:calledDecision bindingType. It applies only to local decisions; a central (connector) decision resolves through its connector, so Binding is ignored when Connector is set.

const (
	// BindingLatest evaluates the newest deployed version of the decision (the
	// default, matching Camunda). It is zero so an unset binding means "latest".
	BindingLatest DecisionBinding = iota
	// BindingDeployment evaluates the decision snapshotted with this process's own
	// deployment (the ADR-0014 behavior): pinned and reproducible.
	BindingDeployment
)

func (DecisionBinding) String

func (b DecisionBinding) String() string

String renders a binding as the lower-case token used on the wire and in the Modeler (`bindingType`): "latest" or "deployment". Any unknown value is reported verbatim so a drift is visible rather than silently mapped to latest.

type DecisionInputMapping

type DecisionInputMapping struct {
	Target string         // the decision input name this value binds to
	Source *expr.Compiled // FEEL expression evaluated over instance variables
}

DecisionInputMapping is one explicit input to a DMN decision: the decision's input name (Target) fed by a FEEL expression (Source) evaluated over the process instance's variables at evaluation time. It is the variable-driven replacement for a business rule task's static inputs (ADR-0014): the source expression is compiled once at deploy time (invariant I5) and the DMN worker evaluates it off the hot path against live variables, so a decision routes on real instance data.

type Deployable

type Deployable struct {
	Process     *CompiledProcess
	PoolName    string
	ProcessName string
}

Deployable is one executable process compiled from a model, plus the display metadata a collaboration provides. PoolName is the participant (pool) name that references the process — "" for a standalone <process> outside any <collaboration>; ProcessName is the process's own name attribute.

func ParseAll

func ParseAll(baseKey uint64, version int32, r io.Reader) ([]Deployable, error)

ParseAll compiles every executable process in a model — the collaboration case, where a <collaboration> has several <participant> pools, each referencing a <process>. A process is executable (and thus returned) iff it has a start event; a participant whose process is a black box (no start event, or none) is skipped rather than erroring, since a message-flow counterpart pool is often left unmodeled. The i-th executable process (document order) is keyed baseKey+i, so a caller assigning keys sequentially advances its counter by len(result). It errors only if the model has no executable process at all.

type ErrorEndDetail

type ErrorEndDetail struct {
	ErrorCode string
}

ErrorEndDetail is the per-error-end-event data the runtime needs: the code it throws (ADR-0089). A code-less error end throws "", which a code-less catch-all catches. It is its own small table (an error end carries no name, correlation key, or schedule).

type EventSubProcessDetail

type EventSubProcessDetail struct {
	StartNode      int32 // the handler's inner start event node id
	Interrupting   bool  // true = terminate the parent scope's other work on trigger (isInterrupting)
	Kind           BoundaryEventKind
	Schedule       TimerSchedule  // BoundaryTimer: when the trigger fires
	MessageName    string         // BoundaryMessage: the message it subscribes to
	CorrelationKey *expr.Compiled // BoundaryMessage: correlation-key expression (ADR-0020)
	SignalName     string         // BoundarySignal: the signal it subscribes to (ADR-0088)
	ErrorCode      string         // BoundaryError: the error code it catches; "" is a catch-all (ADR-0089)
}

EventSubProcessDetail is the per-event-subprocess data the runtime needs to arm its trigger (ADR-0082). An event subprocess (`<subProcess triggeredByEvent="true">`) is not entered by a sequence flow; instead its start event's event definition is armed while the parent scope runs. Interrupting (from the start event's isInterrupting, default true) decides whether firing terminates the parent scope's other work before the handler runs. Kind reuses BoundaryEventKind: the timer field applies for a timer trigger, the message fields for a message trigger. StartNode is the handler's inner start event, seeded (like any message/timer start, flowing straight on) when the handler is activated on a trigger.

type IOMapping

type IOMapping struct {
	Target int32          // interned target variable name → index
	Source *expr.Compiled // FEEL expression evaluated to produce the value
}

IOMapping is one compiled zeebe:ioMapping entry on an activity — an input or an output — the generic, task-agnostic variable mapping of ADR-0068. Source is a FEEL expression compiled once at deploy time (invariant I5); Target is the interned variable name it writes. The two directions differ only in where they read and write at runtime (phase 4): an input evaluates Source over the scope chain from the activity's flow scope and writes Target into the activity-local scope on activation; an output evaluates Source over the local scope and writes Target into the parent (flow) scope on completion. The compiler only records them; the engine applies them.

type MailConfig

type MailConfig struct {
	Connector string
	To        RestExpr
	Cc        RestExpr
	Bcc       RestExpr
	From      RestExpr
	Subject   RestExpr
	Body      RestExpr
	Retries   int32
}

MailConfig is the deploy-time configuration of an outbound mail connector task (ADR-0079). Connector names the server-registered mail provider (its host and credentials live server-side, never in the model); To/Cc/Bcc/From/Subject/Body carry literal-or-FEEL values (the parser compiles the FEEL ones) evaluated over the instance's variables at send time. To and Subject/Body are the message; Cc, Bcc and From are optional (a zero RestExpr means unset).

type MessageDetail

type MessageDetail struct {
	MessageName    string
	CorrelationKey *expr.Compiled
	// SingletonStart marks a message *start* event as one-per-correlation-key: while
	// an instance started with a given key is live, another correlating message starts
	// no duplicate (ADR-0094). Only meaningful on a message start event; ignored on
	// catch/throw/end. Default false keeps ADR-0035's start-per-message behavior.
	SingletonStart bool
}

MessageDetail is the per-message-event data a behavior needs at runtime, shared by the message intermediate catch and throw events. MessageName is the message's name (a subscription matches on it); CorrelationKey is the FEEL expression compiled once at deploy time (ADR-0015) that each side evaluates over its own variables to produce the correlation key (ADR-0020).

type MessageStartEvent

type MessageStartEvent struct {
	MessageName    string
	ElementId      int32
	CorrelationKey *expr.Compiled
	SingletonStart bool // one live instance per correlation key (ADR-0094)
}

MessageStartEvent pairs a message-start event's message name with its element index, so the engine can index which element a starting message flows into for the collaboration replay (ADR-0038). CorrelationKey is the FEEL expression compiled at deploy time; the engine evaluates it over a starting message's payload so the created instance records which key it began with (ADR-0020). It is nil when the event declares no correlation key.

type MultiInstanceDetail

type MultiInstanceDetail struct {
	InputCollection     *expr.Compiled // FEEL list to iterate; nil when Cardinality is used
	Cardinality         *expr.Compiled // FEEL count; nil when InputCollection is used
	InputElement        int32          // interned per-iteration variable name, -1 if none
	OutputCollection    int32          // interned result-list variable name, -1 if none
	OutputElement       *expr.Compiled // FEEL per-iteration contribution, nil if none
	CompletionCondition *expr.Compiled // FEEL early-exit, nil if none
	Sequential          bool           // one iteration at a time (else parallel)
}

MultiInstanceDetail is the per-multi-instance-activity data a behavior needs at runtime (ADR-0077). A multi-instance activity runs its node N times — once per element of InputCollection (a FEEL list), or Cardinality times — as inner element instances scoped under a body. InputElement (interned, -1 if none) is the local variable each iteration binds to its item; the standard loopCounter (1-based) is bound alongside it. Each iteration's OutputElement (a FEEL over its variables, nil if none) is appended to the OutputCollection (interned, -1 if none) list promoted to the parent when the loop completes. CompletionCondition (nil if none) is a FEEL early-exit evaluated after each iteration. Sequential runs one iteration at a time; parallel (the default) seeds them all at once. Exactly one of InputCollection or Cardinality is set — the deploy is refused otherwise.

type Problem

type Problem struct {
	Element  string   `json:"element"`
	Severity Severity `json:"severity"`
	Rule     string   `json:"rule"`
	Message  string   `json:"message"`
}

Problem is one structured validation finding on a compiled process, shaped for ADR-0026's Problems panel and the future POST /api/v1/validate endpoint. Element is the source BPMN element id it anchors to (the id bpmn-js uses, e.g. "Gateway_1"; "" for a process-level finding or a node compiled without a source id); Severity ranks it; Rule is the stable machine slug of the check that raised it; Message is a human-readable explanation.

func Validate

func Validate(cp *CompiledProcess) []Problem

Validate runs the compiler's graph-wide checks (compiler.md stage 5, ROADMAP Milestone 1) over a linearized CompiledProcess and returns every structured Problem it finds — not just the first — so a Problems panel can list them all in one pass. It never mutates cp and is safe to call concurrently on an immutable process. compileProcess calls it as the final compile stage and refuses the deploy when HasErrors holds; the future /validate dry-run returns the full list (errors and warnings) verbatim.

Problems are returned in a deterministic order — by check family, then by node or flow index within each — so a caller (and a test) sees a stable sequence.

func ValidateModel

func ValidateModel(r io.Reader) ([]Problem, error)

ValidateModel runs the compiler's real parse → resolve → build → validate pipeline over a BPMN model as a *dry run* — it mints no keys, registers no definition, and starts no instance — and returns every validation Problem (errors and warnings) across all of the model's executable pools. It is the single source of validation truth behind ADR-0026's Problems panel and the POST /api/v1/validate endpoint: the panel never re-implements these rules (that would be the interpret-don't-compile failure mode I5 forbids), it renders what this returns.

Unlike ParseAll, which stops at the first fault so a deploy fails fast, the dry run reports everything at once — that is what a Problems panel needs. Faults the graph checks cannot anchor to a node still surface as Problems so the panel renders them uniformly: a document that will not parse, or a model with no executable process, becomes one RuleParse error; a pool that fails an earlier compile stage becomes one RuleCompile error rather than aborting the whole run and blinding the panel to the other pools.

The returned error is always nil today — every modeling fault is reported as a Problem, not an error — but the signature keeps an error so a future source that does I/O can report a read failure distinctly from a modeling one.

type RemedyConfig

type RemedyConfig struct {
	Connector string
	Form      RestExpr
	Fields    []RestKV
	ResultVar string
	Retries   int32
}

RemedyConfig is the deploy-time configuration of a BMC Remedy connector task (ADR-0106). Connector names the server-registered Remedy instance (its base URL and credentials live server-side, never in the model). Form is the Remedy form the entry is created in (e.g. "HPD:IncidentInterface_Create"); Fields carries the entry's field values as name/literal-or-FEEL pairs evaluated over the instance's variables at call time (the fx toggle, ADR-0067). ResultVar, if set, is the process variable the created entry's id is written back into.

type RestAuth

type RestAuth struct {
	Type       string `json:"type,omitempty"`
	Username   string `json:"username,omitempty"`
	ApiKeyName string `json:"apiKeyName,omitempty"`
	SecretRef  string `json:"secretRef,omitempty"`
}

RestAuth is a REST connector task's authentication config. Type is "", "basic", "bearer", or "apiKey". Username (basic) and ApiKeyName (the apiKey header name) are model data. SecretRef names a server-side secret (ADR-0041) — the basic password, bearer token, or api-key value — resolved at runtime; the secret value itself is never authored in the model or stored here.

type RestConfig

type RestConfig struct {
	Method    string
	Url       RestExpr
	ResultVar string
	Headers   []RestKV
	Query     []RestKV
	Auth      RestAuth
	Retries   int32
}

RestConfig is the deploy-time configuration of an HTTP-REST connector task (ADR-0067). Method and ResultVar are interned; Url, Headers, and Query carry literal-or-FEEL values (the parser compiles the FEEL ones); Auth references a server-side secret.

type RestExpr

type RestExpr struct {
	Literal string
	Expr    *expr.Compiled
}

RestExpr is a REST connector field value that is either a literal string (Expr == nil, use Literal) or a FEEL expression evaluated over the instance's variables at call time (Expr != nil), compiled once at deploy time (invariant I5, ADR-0008/0067). It backs the modeler's fx toggle: a model value with a leading '=' is an expression, otherwise a literal.

type RestKV

type RestKV struct {
	Name string
	Val  RestExpr
}

RestKV is a named REST field value (one request header or query parameter): its Name and a value that may be literal or a FEEL expression.

type ScriptJobTaskDetail

type ScriptJobTaskDetail struct {
	JobType   int32 // interned reserved per-language script job type → index
	Language  int32 // interned script language (e.g. "powershell") → index
	Source    int32 // interned script source text → index
	ResultVar int32 // interned result-variable name → index
	Retries   int32
}

ScriptJobTaskDetail is the per-script-job-task data a behavior needs at runtime. Unlike the inline FEEL script task (ScriptTaskDetail), a job script is authored in a general-purpose language (PowerShell first; Python/JavaScript later) and runs off the hot path in a job worker, exactly as a business rule task delegates to the DMN worker (ADR-0047). Like a service task it runs as a job, so it carries a JobType — a reserved per-language sentinel (e.g. PwshJobType) the in-process script worker subscribes to. Language is the interned language name (which also selects the worker/interpreter), Source is the interned script text (compiled/validated no further at deploy time — an interpreter runs it, invariant I5 keeps only interning and validation off the runtime path), and ResultVar is the process variable the script's result is written back into on job completion.

type ScriptTaskDetail

type ScriptTaskDetail struct {
	Expr      *expr.Compiled
	ResultVar string
}

ScriptTaskDetail is the per-script-task data a behavior needs at runtime: a FEEL expression compiled once at deploy time (ADR-0008/0015) and the name of the variable its result is written to.

type ServiceTaskDetail

type ServiceTaskDetail struct {
	JobType int32 // interned string → index
	Retries int32
}

ServiceTaskDetail is the per-service-task data a behavior needs at runtime.

type Severity

type Severity string

Severity ranks a validation Problem. An error refuses deployment (compileProcess returns it as a fatal compile error, preserving the "fail at deploy, never at runtime" contract); a warning is informational and does not block a deploy. The string values are stable and chosen so the future JSON /validate endpoint and Problems panel (ADR-0026) can serialize them directly.

const (
	// SeverityError marks a problem that makes the model unrunnable or structurally
	// invalid, so the deploy is refused — the existing all-or-nothing compile-gate
	// behavior, now with a reason attached.
	SeverityError Severity = "error"
	// SeverityWarning marks a modeling smell that does not prevent the reachable
	// part of the process from executing correctly (e.g. dead, unreachable code).
	// It is surfaced to the author but never blocks a deploy.
	SeverityWarning Severity = "warning"
)

type SharePointConfig

type SharePointConfig struct {
	Connector string
	Site      RestExpr
	List      RestExpr
	Fields    []RestKV
	ResultVar string
	Retries   int32
}

SharePointConfig is the deploy-time configuration of a SharePoint connector task (ADR-0105). Connector names the server-registered SharePoint provider (its Graph base and OAuth credential live server-side, never in the model); Site and List address the target list, and Fields are the created item's column values — all literal-or-FEEL values (the parser compiles the FEEL ones) evaluated over the instance's variables at call time. ResultVar, if set, is the process variable the created item's JSON is written back into (empty = discard it).

type SignalDetail

type SignalDetail struct {
	SignalName string
}

SignalDetail is the per-signal-event data a behavior needs at runtime, shared by the signal intermediate catch, throw, end, and start events (ADR-0088). A signal is broadcast by name: it carries no correlation key and no code, so the name is all a catch subscribes on and a throw broadcasts.

type SignalStartEvent

type SignalStartEvent struct {
	SignalName string
	ElementId  int32
}

SignalStartEvent pairs a signal-start event's signal name with its element index, so the engine can index which element a starting signal flows into (ADR-0088).

type TimerCatchDetail

type TimerCatchDetail struct {
	Schedule TimerSchedule
}

TimerCatchDetail is the per-timer-intermediate-catch-event data: the compiled schedule that decides when the waiting token continues. A catch fires once, so only duration and date schedules reach here — a cycle is a compile error (ADR-0054).

type TimerSchedule

type TimerSchedule struct {
	Kind        TimerScheduleKind
	BaseNanos   int64          // Duration/CycleInterval: the interval in ns; Date: the absolute instant (unix ns)
	Repetitions int32          // remaining fires after the first; -1 = infinite; 0 = fire once
	Cron        cronSpec       // populated only for TimerCycleCron
	Expr        *expr.Compiled // populated only for the TimerFeel* kinds (ADR-0055/0056)
}

TimerSchedule is a compiled timer definition: enough to compute every due date deterministically at runtime without re-parsing the XML (invariant I5). Timer start events use the full range (ADR-0051); catch and boundary timers use only a duration today and do not carry a schedule.

func (TimerSchedule) FirstDue

func (s TimerSchedule) FirstDue(now int64) int64

FirstDue returns the due date of the first (or only) firing of a timer armed at now. The clock is read by the caller and frozen into the arming event, never here (invariant I4/I6).

func (TimerSchedule) IsFeel

func (s TimerSchedule) IsFeel() bool

IsFeel reports whether the schedule comes from a FEEL expression evaluated at runtime (ADR-0055/0056), rather than a value fixed at deploy time.

func (TimerSchedule) NextDue

func (s TimerSchedule) NextDue(now int64) (int64, bool)

NextDue returns the due date of the next firing after a timer fires at now, and whether the timer recurs at all. A one-shot (duration/date) returns ok=false. A finite cycle whose Repetitions has run out is handled by the caller via the Repetitions counter, not here — NextDue only computes when.

func (TimerSchedule) Repeats

func (s TimerSchedule) Repeats() bool

Repeats reports whether the schedule recurs (a cycle), as opposed to firing once (a duration or date). A recurring non-interrupting boundary uses it to decide whether to re-arm after each fire (ADR-0054).

func (TimerSchedule) ResolveConstant

func (s TimerSchedule) ResolveConstant() (TimerSchedule, error)

ResolveConstant evaluates a constant FEEL schedule — one whose expression reads no variables — exactly as the runtime would at arm (against an empty binding) and returns the concrete schedule, or an error if it does not resolve to a valid one. A timer *start* event's FEEL schedule is required to be constant (ADR-0056), so this lets deploy-time validation prove it will actually arm instead of being silently dropped at runtime (ADR-0111). A non-FEEL schedule resolves trivially. It must not be called on a FEEL schedule with variable inputs — those have no value at deploy — so callers check Expr.Inputs() first.

func (TimerSchedule) ResolveFeel

func (s TimerSchedule) ResolveFeel(text string) (TimerSchedule, bool)

ResolveFeel turns the evaluated text of a FEEL timer expression into the concrete schedule the literal parser would have produced for the same field — a duration, date, or cycle — so downstream FirstDue/NextDue/Repetitions are identical to a literal timer's (ADR-0056). ok is false if the text is not valid for the field (the caller then treats the timer as unresolvable). Only valid on a FEEL schedule.

func (TimerSchedule) ResolveFeelValue

func (s TimerSchedule) ResolveFeelValue(v expr.Value) (TimerSchedule, bool)

ResolveFeelValue turns a FEEL expression's evaluated *value* into the concrete schedule for the field (ADR-0057). It first reads a first-class FEEL temporal exactly — a duration's nanoseconds for a FEEL duration schedule, a date-time's instant for a FEEL date schedule — and only falls back to the canonical string form (Classify → ResolveFeel) when the value is not a usable temporal (e.g. a variable holding an ISO-8601 string, or any cycle). ok is false if neither path yields a valid schedule. Only valid on a FEEL schedule.

type TimerScheduleKind

type TimerScheduleKind uint8

TimerScheduleKind discriminates how a timer's due dates are computed.

const (
	// TimerDuration fires once, BaseNanos after the timer is armed (ISO-8601
	// <timeDuration>, e.g. PT1H).
	TimerDuration TimerScheduleKind = iota
	// TimerDate fires once, at the absolute instant BaseNanos (ISO-8601
	// <timeDate>, e.g. 2026-08-01T09:00:00Z).
	TimerDate
	// TimerCycleInterval recurs every BaseNanos, Repetitions more times after the
	// first (ISO-8601 repeating interval <timeCycle>, e.g. R3/PT1H or R/PT1H).
	TimerCycleInterval
	// TimerCycleCron recurs on a wall-clock cron schedule (<timeCycle> holding a
	// 5-field cron expression, e.g. "0 * * * *" — every full hour). Always
	// infinite.
	TimerCycleCron
	// TimerFeelDuration fires once, its delay a FEEL expression (Expr) evaluated
	// against the instance's variables when the timer is created; the result's text
	// is parsed as an ISO-8601 duration (ADR-0055).
	TimerFeelDuration
	// TimerFeelDate fires once, its instant a FEEL expression (Expr) evaluated when
	// the timer is created; the result's text is parsed as an RFC3339 instant
	// (ADR-0055).
	TimerFeelDate
	// TimerFeelCycle recurs, its cadence a FEEL expression (Expr) evaluated when the
	// timer is armed and again on each re-arm; the result's text is parsed as a
	// repeating interval or cron (ADR-0056). Boundary (non-interrupting) only.
	TimerFeelCycle
)

type TimerStartDetail

type TimerStartDetail struct {
	Schedule TimerSchedule
}

TimerStartDetail is the per-timer-start-event data: the compiled schedule that the engine arms at deploy time and consults to compute each due date (ADR-0051).

type TimerStartEvent

type TimerStartEvent struct {
	Schedule  TimerSchedule
	ElementId int32
}

TimerStartEvent pairs a timer-start event's compiled schedule with its element index, so the engine can arm the right timer for the right node (ADR-0051).

type UserTaskDetail

type UserTaskDetail struct {
	JobType         int32
	Retries         int32
	Name            int32 // interned element name (the task's human title) → index, -1 if unset
	Assignee        int32
	CandidateGroups int32
	FormId          int32 // interned form id bound via zeebe:formDefinition → index, -1 if unset (ADR-0028)
	// Priority is the task's static importance from zeebe:priorityDefinition
	// (default 50, Camunda's convention); higher sorts first in the inbox.
	Priority int32
	// DueDateNanos is the ISO-8601 duration (from zeebe:taskSchedule dueDate),
	// in nanoseconds, after which the task is due — relative to its creation, so
	// the absolute due instant is frozen when the job is created (ADR-0051).
	// 0 means the task has no due date.
	DueDateNanos int64
}

UserTaskDetail is the per-user-task data a behavior needs at runtime. A user task parks a token and creates a job like a service task; the "worker" is a person using the Tasks app (ADR-0028). Assignee and CandidateGroups are interned strings from the zeebe:assignmentDefinition extension (-1 if unset).

type ValidationError

type ValidationError struct {
	Problems []Problem
}

ValidationError is the fatal compile error compileProcess returns when graph-wide validation finds an error-severity Problem, so a deploy is refused (invariant I5, preserving today's compile-gate behavior). It carries the full Problem list — warnings included — so a caller that wants the structured findings (a future /validate endpoint reusing the compile path) can recover them with a type assertion; Error() renders only the error-severity findings into one line, matching how the other compile failures read.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL