Skip to content

Fundamentals 2: tasks and plan items

This page covers the two things a CMMN author works with most: the plan item, and the lifecycle it moves through.

CMMN separates what a thing is from where it sits in the case:

  • A plan item definition (<humanTask>, <stage>, <milestone>, …) declares the work. It lives in a stage’s definition list.
  • A plan item (<planItem>) is a use of a definition at one place in the plan, via @definitionRef. It carries the id the rest of the model refers to, its own name, its item control, and its entry and exit criteria.
<casePlanModel id="cpm">
<planItem id="pi_review" definitionRef="def_review">
<entryCriterion id="ec_1" sentryRef="sentry_1" />
<itemControl>
<requiredRule />
</itemControl>
</planItem>
<humanTask id="def_review" name="Review the claim" flowable:assignee="${initiator}" />
</casePlanModel>

Two consequences worth internalising:

  • Sentries reference plan items, not definitions. An on-part’s @sourceRef points at a <planItem> id. The same definition used twice is two plan items with two independent lifecycles, and a sentry watches one of them.
  • Item control lives in two places. A definition may carry a <defaultControl>; a plan item may carry an <itemControl> that overrides it. Orvanta models both.

CMMN’s schema marks @id as optional on every element. 161 of the 968 Flowable corpus documents rely on this, omitting 249 ids between them. Orvanta’s parser synthesises the missing ids, flags each one, and counts them — rather than treating an absent id as a malformed document.

This is worth knowing if you hand-write CMMN: your file will import even without ids, but the ids the model refers to are then generated, so add them explicitly to anything a sentry needs to point at.

CMMN defines several plan item definitions that represent work. Here is every one Orvanta’s parser models, and what the engine does with it:

DefinitionWhat it isOrvanta’s engine
<task>The generic taskExecutes. isBlocking="false" completes on start; isBlocking="true" parks for an external complete.
<humanTask>Work for a personExecutes. Parks in active, completes on an external trigger.
<milestone>An achievement markerExecutes. See Fundamentals 1.
<stage>A phaseExecutes.
<planFragment>Visual groupingFlattened — no runtime existence.
<userEventListener>A thing a person can triggerExecutes. Parks in available, occurs on an external trigger.
<processTask>Calls a BPMN processRefused at deploy.
<caseTask>Calls another caseRefused at deploy.
<decisionTask>Calls a DMN decisionRefused at deploy.
<timerEventListener>Fires on a scheduleRefused at deploy.
<eventListener> (generic)Flowable’s flowable:eventType-discriminated listenerRefused at parse. 78 corpus files.

“Refused” means refused at deploy time, with the element id and a named reason — never a silent approximation. A processTask that deployed and behaved as a pass-through would complete the case without ever running the process, which is worse than refusing it. The full list and the reasoning is on Supported CMMN elements.

Note that the editor’s palette does include Process Task, Case Task, Decision Task and Timer Event Listener, because the model represents them faithfully and they must survive a round trip. The palette tracks what the model can carry; the engine table tracks what runs. See Authoring a case model.

<humanTask> is the most common definition in the corpus by a distance — 638 of 968 files. Orvanta’s parser captures @performerRef, @isBlocking, flowable:assignee, flowable:formKey, flowable:candidateStarterGroups and the whole <extensionElements> listener tree.

The engine parks in active and completes on an external trigger, and that is all: there is no form model, no assignee resolution and no task list. The attributes survive the round trip; nothing consumes them yet.

<planningTable> on a human task — CMMN’s discretionary-planning subsystem — is refused by name rather than ignored. It has zero corpus usage.

Every plan item instance sits in exactly one of twelve states, transcribed from Flowable’s PlanItemInstanceState:

StateMeaningOrvanta
availableCreated, waiting on entry criteriaReachable
unavailableAn event listener held back by an available-conditionReachable
enabledManual activation is on; waiting for a human to start itReachable
disabledA human declined it; re-enterableReachable
activeRunningReachable
completedTerminal — finished normallyReachable
terminatedTerminal — ended by an exitReachable
wait_repetitionA further repetition, waiting for its sentry againReachable
failedTerminal — faultedModelled only. No behaviour raises a fault yet.
suspendedPausedReachable — a case-level suspend, or a suspend on one plan item. resume restores the state recorded at suspend time, not available, so a resumed stage does not re-instantiate its children.
async-activeAsync transaction boundary, enteringModelled only. Requires flowable:async, which is refused.
async-active-leaveAsync transaction boundary, leavingModelled only. Requires flowable:asyncLeave, which is refused.

The engine’s own groupings matter when reasoning about completion:

  • Terminal statescompleted, terminated, failed.
  • End states — the terminal three, plus unavailable, disabled, wait_repetition.
  • States in which entry criteria are re-evaluatedavailable and wait_repetition, and only those.

That last one is the reason a completed task does not restart when its sentry fires again: the engine only looks at entry criteria for instances sitting in available or wait_repetition.

CMMN names 21 transitions. Orvanta executes seventeen of them:

Executed: create, start, enable, disable, reenable, manualStart, complete, occur, exit, initiate, dismiss, the internal repetition spawn (also a create), and the operator-driven set — suspend, resume, parentSuspend, parentResume, terminate and close.

terminate and exit are worth telling apart: an operator terminating the case or one plan item emits terminate and cascades to the sub-tree, where an exit criterion emits exit. A sentry watching one does not see the other.

Modelled only — the model carries them, nothing drives them: fault (no behaviour runs user code, so nothing can fault), reactivate (case reactivation is refused), async-activate and async-leave-active (flowable:async is refused).

initiate and dismiss are the pair that moves an event listener between unavailable and available as its flowable:availableConditionExpression turns true or false.

Manual activation: enableddisabled → re-enable

Section titled “Manual activation: enabled → disabled → re-enable”

By default a plan item whose entry criteria are satisfied goes straight to active. A <manualActivationRule> (114 corpus files) changes that: the item stops at enabled and waits for a person.

From enabled, three things can happen:

  • manualStart — a person starts it. It goes active.
  • disable — a person declines it. It goes disabled, which is an end state but not a terminal one.
  • reenable — a person changes their mind about a disabled item. It goes back to enabled.

Orvanta executes all four transitions. This three-way is what makes CMMN’s “optional work” idiom possible, and it combines with autocomplete in a specific way that has its own section on the completion page.

A <manualActivationRule> may carry a <condition>; if it does, the condition must be inside Orvanta’s decidable expression subset or the model is refused at deploy rather than defaulted to true. See Sentries.

Fundamentals 3: sentries — the guards that drive all of this.