@nanobpm/nano-workforce 0.156.0 → 0.157.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.157.0](https://github.com/nanobpm/nano-workforce/compare/v0.156.0...v0.157.0) (2026-08-29)
2
+
3
+ ### Features
4
+
5
+ * **cells:** shared implement/converge/merge-cell BPMN + feature converge via callActivity (ADR 0006 S4) ([#603](https://github.com/nanobpm/nano-workforce/issues/603)) ([55a727a](https://github.com/nanobpm/nano-workforce/commit/55a727aae09a026a0b82ec4ebc0c7d8137146bcf)), closes [#591](https://github.com/nanobpm/nano-workforce/issues/591)
6
+
1
7
  ## [0.156.0](https://github.com/nanobpm/nano-workforce/compare/v0.155.0...v0.156.0) (2026-08-29)
2
8
 
3
9
  ### Features
@@ -0,0 +1,83 @@
1
+ // Structural guard for the ADR 0006 S4 fine-grained cells (#591).
2
+ //
3
+ // S4 introduces ONE shared, composable representation of the atomic delivery cell — implement →
4
+ // converge → merge — as standalone `callActivity`-composable processes under
5
+ // `resources/processes/`, so feature/epic (and later the S6 compiler) compose a wave from ONE token
6
+ // per cell instead of copy-pasting the inlined subProcess three ways (#464 "the duplication today").
7
+ //
8
+ // These are STRUCTURAL invariants (the cells exist, keep their engine-native task types, and wire
9
+ // escalation through the shared `human-escalation` cell). The live converge seam on `feature.bpmn`
10
+ // stays an INLINE `pr.converge-feature` serviceTask: the engine (and the urban-testkit WASM engine)
11
+ // treats a callActivity as a pass-through that never runs the called process, so a callActivity
12
+ // converge would never enroll the PR (see `e2e/feature-run.e2e.ts`). This guard pins the
13
+ // decomposition so the shared cells can't silently drift back into per-caller copies.
14
+ import { test } from "node:test";
15
+ import { assert } from "#test-assert";
16
+ import { readFileSync } from "node:fs";
17
+
18
+ function model(name: string): string {
19
+ return readFileSync(`resources/processes/${name}.bpmn`, "utf8");
20
+ }
21
+ function flat(name: string): string {
22
+ return model(name).replace(/\s+/g, " ");
23
+ }
24
+
25
+ test("the five S4 shared cells exist as standalone executable processes", () => {
26
+ const expected: Record<string, string> = {
27
+ "implement-cell": "implement-cell",
28
+ "converge-cell": "converge-cell",
29
+ "merge-cell": "merge-cell",
30
+ "wait-gate": "wait-gate",
31
+ "human-escalation": "human-escalation",
32
+ };
33
+ for (const [file, id] of Object.entries(expected)) {
34
+ const xml = flat(file);
35
+ assert(
36
+ new RegExp(`<bpmn:process\\b[^>]*\\bid="${id}"[^>]*\\bisExecutable="true"`).test(xml),
37
+ `${file}.bpmn must declare an executable process id="${id}"`,
38
+ );
39
+ }
40
+ });
41
+
42
+ test("implement-cell runs the senior:feature loop and delegates escalation to the human-escalation cell", () => {
43
+ const xml = flat("implement-cell");
44
+ assert(/<zeebe:taskDefinition\b[^>]*\btype="senior:feature"/.test(xml), "implement-cell keeps the senior:feature agent task");
45
+ assert(
46
+ /<zeebe:calledElement\b[^>]*\bprocessId="human-escalation"/.test(xml),
47
+ "implement-cell escalates through the shared human-escalation cell via callActivity",
48
+ );
49
+ // The answer loop re-enters the implement task — the atomic cell owns its own escalation retry.
50
+ assert(/targetRef="implement-task"/.test(xml), "implement-cell loops the answer back into implement-task");
51
+ });
52
+
53
+ test("converge-cell and merge-cell keep their engine-native handoff task types", () => {
54
+ assert(/<zeebe:taskDefinition\b[^>]*\btype="pr.converge-feature"/.test(flat("converge-cell")), "converge-cell hands off via pr.converge-feature");
55
+ assert(/<zeebe:taskDefinition\b[^>]*\btype="senior:trial-merge"/.test(flat("merge-cell")), "merge-cell runs the senior:trial-merge agent");
56
+ assert(/<zeebe:taskDefinition\b[^>]*\btype="pr.record-trial-merge"/.test(flat("merge-cell")), "merge-cell records the trial-merge result");
57
+ });
58
+
59
+ test("wait-gate is a readiness-probe cell; human-escalation parks on the shared feature-escalation form", () => {
60
+ assert(/<zeebe:taskDefinition\b[^>]*\btype="pr.readiness-probe"/.test(flat("wait-gate")), "wait-gate probes readiness");
61
+ const he = flat("human-escalation");
62
+ assert(/<bpmn:userTask\b[^>]*\bid="escalation"/.test(he), "human-escalation parks on a userTask");
63
+ assert(/<zeebe:formDefinition\b[^>]*\bformId="feature-escalation"/.test(he), "human-escalation renders the feature-escalation form");
64
+ });
65
+
66
+ test("feature.bpmn composes its converge step as an inline pr.converge-feature serviceTask", () => {
67
+ // The live converge seam must stay INLINE, not a callActivity to converge-cell: the engine
68
+ // (and the urban-testkit WASM engine the e2e boots) treats a BPMN callActivity as an immediate
69
+ // pass-through — it never instantiates the called process, so the `pr.converge-feature` worker
70
+ // would never run and the feature run could never reach `converging` / enroll its PR into the
71
+ // convergence loop (proven by `e2e/feature-run.e2e.ts` "raise + converge"). The `converge-cell`
72
+ // process still exists as a standalone, composable cell for future composition seams, but
73
+ // feature.bpmn hands off converge directly so the behaviour is real.
74
+ const xml = flat("feature");
75
+ assert(
76
+ /<bpmn:serviceTask\b[^>]*\bid="converge"[\s\S]*?<zeebe:taskDefinition\b[^>]*\btype="pr.converge-feature"/.test(xml),
77
+ "feature.bpmn must compose converge as an inline pr.converge-feature serviceTask",
78
+ );
79
+ assert(
80
+ !/<bpmn:callActivity\b[^>]*\bid="converge"/.test(xml),
81
+ "feature.bpmn must not route its live converge step through a callActivity (a testkit/engine pass-through)",
82
+ );
83
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanobpm/nano-workforce",
3
- "version": "0.156.0",
3
+ "version": "0.157.0",
4
4
  "description": "Nano Workforce — an Agent Graph Orchestration application for Agentic SDLC: durable BPMN processes that coordinate a graph of AI agents across the software delivery lifecycle.",
5
5
  "type": "module",
6
6
  "main": "main.ts",
@@ -0,0 +1,50 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:nano="https://nanobpm.io/schema/shapes/1.0" id="Definitions_nano_workforce_converge_cell" targetNamespace="http://nanobpm.io/nano-workforce">
3
+ <bpmn:process id="converge-cell" name="Converge cell" isExecutable="true">
4
+ <bpmn:startEvent id="Start" name="PR to converge">
5
+ <bpmn:outgoing>cc_toConverge</bpmn:outgoing>
6
+ </bpmn:startEvent>
7
+ <bpmn:serviceTask id="converge" name="Hand off to convergence loop">
8
+ <bpmn:extensionElements>
9
+ <zeebe:taskDefinition type="pr.converge-feature" />
10
+ <zeebe:properties>
11
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="ConvergeFeatureIn" />
12
+ </zeebe:properties>
13
+ </bpmn:extensionElements>
14
+ <bpmn:incoming>cc_toConverge</bpmn:incoming>
15
+ <bpmn:outgoing>cc_toEnd</bpmn:outgoing>
16
+ </bpmn:serviceTask>
17
+ <bpmn:endEvent id="End" name="Converging">
18
+ <bpmn:incoming>cc_toEnd</bpmn:incoming>
19
+ </bpmn:endEvent>
20
+ <bpmn:sequenceFlow id="cc_toConverge" sourceRef="Start" targetRef="converge" />
21
+ <bpmn:sequenceFlow id="cc_toEnd" sourceRef="converge" targetRef="End" />
22
+ </bpmn:process>
23
+ <bpmndi:BPMNDiagram id="BPMNDiagram_converge-cell">
24
+ <bpmndi:BPMNPlane id="BPMNPlane_converge-cell" bpmnElement="converge-cell">
25
+ <bpmndi:BPMNShape id="BPMNShape_Start" bpmnElement="Start">
26
+ <dc:Bounds x="80" y="102" width="36" height="36" />
27
+ <bpmndi:BPMNLabel>
28
+ <dc:Bounds x="68" y="143" width="60" height="28" />
29
+ </bpmndi:BPMNLabel>
30
+ </bpmndi:BPMNShape>
31
+ <bpmndi:BPMNShape id="BPMNShape_converge" bpmnElement="converge">
32
+ <dc:Bounds x="216" y="80" width="100" height="80" />
33
+ </bpmndi:BPMNShape>
34
+ <bpmndi:BPMNShape id="BPMNShape_End" bpmnElement="End">
35
+ <dc:Bounds x="416" y="102" width="36" height="36" />
36
+ <bpmndi:BPMNLabel>
37
+ <dc:Bounds x="396" y="143" width="76" height="14" />
38
+ </bpmndi:BPMNLabel>
39
+ </bpmndi:BPMNShape>
40
+ <bpmndi:BPMNEdge id="BPMNEdge_cc_toConverge" bpmnElement="cc_toConverge">
41
+ <di:waypoint x="116" y="120" />
42
+ <di:waypoint x="216" y="120" />
43
+ </bpmndi:BPMNEdge>
44
+ <bpmndi:BPMNEdge id="BPMNEdge_cc_toEnd" bpmnElement="cc_toEnd">
45
+ <di:waypoint x="316" y="120" />
46
+ <di:waypoint x="416" y="120" />
47
+ </bpmndi:BPMNEdge>
48
+ </bpmndi:BPMNPlane>
49
+ </bpmndi:BPMNDiagram>
50
+ </bpmn:definitions>
@@ -0,0 +1,133 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:nano="https://nanobpm.io/schema/shapes/1.0" id="Definitions_nano_workforce_human_escalation" targetNamespace="http://nanobpm.io/nano-workforce">
3
+ <bpmn:process id="human-escalation" name="Human escalation cell" isExecutable="true">
4
+ <bpmn:startEvent id="Start" name="Escalated">
5
+ <bpmn:outgoing>he_toTask</bpmn:outgoing>
6
+ </bpmn:startEvent>
7
+ <bpmn:userTask id="escalation" name="Task escalation (human)">
8
+ <bpmn:extensionElements>
9
+ <zeebe:formDefinition formId="feature-escalation" />
10
+ <zeebe:userTask />
11
+ <zeebe:assignmentDefinition candidateGroups="operators" assignee="=if (is defined(escalationAssignee) and escalationAssignee != null and trim(string(escalationAssignee)) != &#34;&#34;) then escalationAssignee else null" />
12
+ </bpmn:extensionElements>
13
+ <bpmn:incoming>he_toTask</bpmn:incoming>
14
+ <bpmn:outgoing>he_toAnswerGw</bpmn:outgoing>
15
+ </bpmn:userTask>
16
+ <bpmn:boundaryEvent id="be_he_sla" name="SLA elapsed" attachedToRef="escalation">
17
+ <bpmn:outgoing>he_sla</bpmn:outgoing>
18
+ <bpmn:timerEventDefinition id="ted_he_sla">
19
+ <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">=escalationSlaTimeout</bpmn:timeDuration>
20
+ </bpmn:timerEventDefinition>
21
+ </bpmn:boundaryEvent>
22
+ <bpmn:exclusiveGateway id="he_gw_answer" name="answer?" default="he_abandon">
23
+ <bpmn:incoming>he_toAnswerGw</bpmn:incoming>
24
+ <bpmn:outgoing>he_answer</bpmn:outgoing>
25
+ <bpmn:outgoing>he_abandon</bpmn:outgoing>
26
+ </bpmn:exclusiveGateway>
27
+ <bpmn:endEvent id="he_end_answered" name="Answered">
28
+ <bpmn:extensionElements>
29
+ <zeebe:ioMapping>
30
+ <zeebe:input source="=&#34;answer&#34;" target="resolution" />
31
+ </zeebe:ioMapping>
32
+ </bpmn:extensionElements>
33
+ <bpmn:incoming>he_answer</bpmn:incoming>
34
+ </bpmn:endEvent>
35
+ <bpmn:endEvent id="he_end_abandoned" name="Abandoned">
36
+ <bpmn:extensionElements>
37
+ <zeebe:ioMapping>
38
+ <zeebe:input source="=&#34;abandon&#34;" target="resolution" />
39
+ </zeebe:ioMapping>
40
+ </bpmn:extensionElements>
41
+ <bpmn:incoming>he_abandon</bpmn:incoming>
42
+ </bpmn:endEvent>
43
+ <bpmn:endEvent id="he_end_sla" name="SLA auto-abandon">
44
+ <bpmn:extensionElements>
45
+ <zeebe:ioMapping>
46
+ <zeebe:input source="=&#34;abandon&#34;" target="resolution" />
47
+ </zeebe:ioMapping>
48
+ </bpmn:extensionElements>
49
+ <bpmn:incoming>he_sla</bpmn:incoming>
50
+ </bpmn:endEvent>
51
+ <bpmn:sequenceFlow id="he_toTask" sourceRef="Start" targetRef="escalation" />
52
+ <bpmn:sequenceFlow id="he_toAnswerGw" sourceRef="escalation" targetRef="he_gw_answer" />
53
+ <bpmn:sequenceFlow id="he_answer" name="answer" sourceRef="he_gw_answer" targetRef="he_end_answered">
54
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=resolution = "answer"</bpmn:conditionExpression>
55
+ </bpmn:sequenceFlow>
56
+ <bpmn:sequenceFlow id="he_abandon" name="abandon" sourceRef="he_gw_answer" targetRef="he_end_abandoned" />
57
+ <bpmn:sequenceFlow id="he_sla" name="SLA auto-abandon" sourceRef="be_he_sla" targetRef="he_end_sla" />
58
+ </bpmn:process>
59
+ <bpmndi:BPMNDiagram id="BPMNDiagram_human-escalation">
60
+ <bpmndi:BPMNPlane id="BPMNPlane_human-escalation" bpmnElement="human-escalation">
61
+ <bpmndi:BPMNShape id="BPMNShape_Start" bpmnElement="Start">
62
+ <dc:Bounds x="80" y="102" width="36" height="36" />
63
+ <bpmndi:BPMNLabel>
64
+ <dc:Bounds x="64" y="143" width="69" height="14" />
65
+ </bpmndi:BPMNLabel>
66
+ </bpmndi:BPMNShape>
67
+ <bpmndi:BPMNShape id="BPMNShape_escalation" bpmnElement="escalation">
68
+ <dc:Bounds x="216" y="80" width="100" height="80" />
69
+ </bpmndi:BPMNShape>
70
+ <bpmndi:BPMNShape id="BPMNShape_he_gw_answer" bpmnElement="he_gw_answer" isMarkerVisible="true">
71
+ <dc:Bounds x="552" y="95" width="50" height="50" />
72
+ <bpmndi:BPMNLabel>
73
+ <dc:Bounds x="549" y="76" width="56" height="14" />
74
+ </bpmndi:BPMNLabel>
75
+ </bpmndi:BPMNShape>
76
+ <bpmndi:BPMNShape id="BPMNShape_he_end_answered" bpmnElement="he_end_answered">
77
+ <dc:Bounds x="702" y="262" width="36" height="36" />
78
+ <bpmndi:BPMNLabel>
79
+ <dc:Bounds x="688" y="303" width="65" height="14" />
80
+ </bpmndi:BPMNLabel>
81
+ </bpmndi:BPMNShape>
82
+ <bpmndi:BPMNShape id="BPMNShape_he_end_abandoned" bpmnElement="he_end_abandoned">
83
+ <dc:Bounds x="702" y="102" width="36" height="36" />
84
+ <bpmndi:BPMNLabel>
85
+ <dc:Bounds x="686" y="143" width="69" height="14" />
86
+ </bpmndi:BPMNLabel>
87
+ </bpmndi:BPMNShape>
88
+ <bpmndi:BPMNShape id="BPMNShape_he_end_sla" bpmnElement="he_end_sla">
89
+ <dc:Bounds x="416" y="262" width="36" height="36" />
90
+ <bpmndi:BPMNLabel>
91
+ <dc:Bounds x="390" y="303" width="88" height="28" />
92
+ </bpmndi:BPMNLabel>
93
+ </bpmndi:BPMNShape>
94
+ <bpmndi:BPMNShape id="BPMNShape_be_he_sla" bpmnElement="be_he_sla">
95
+ <dc:Bounds x="248" y="142" width="36" height="36" />
96
+ <bpmndi:BPMNLabel>
97
+ <dc:Bounds x="164" y="183" width="84" height="14" />
98
+ </bpmndi:BPMNLabel>
99
+ </bpmndi:BPMNShape>
100
+ <bpmndi:BPMNEdge id="BPMNEdge_he_toTask" bpmnElement="he_toTask">
101
+ <di:waypoint x="116" y="120" />
102
+ <di:waypoint x="216" y="120" />
103
+ </bpmndi:BPMNEdge>
104
+ <bpmndi:BPMNEdge id="BPMNEdge_he_toAnswerGw" bpmnElement="he_toAnswerGw">
105
+ <di:waypoint x="316" y="120" />
106
+ <di:waypoint x="552" y="120" />
107
+ </bpmndi:BPMNEdge>
108
+ <bpmndi:BPMNEdge id="BPMNEdge_he_abandon" bpmnElement="he_abandon">
109
+ <di:waypoint x="602" y="120" />
110
+ <di:waypoint x="702" y="120" />
111
+ <bpmndi:BPMNLabel>
112
+ <dc:Bounds x="626" y="98" width="53" height="14" />
113
+ </bpmndi:BPMNLabel>
114
+ </bpmndi:BPMNEdge>
115
+ <bpmndi:BPMNEdge id="BPMNEdge_he_answer" bpmnElement="he_answer">
116
+ <di:waypoint x="577" y="145" />
117
+ <di:waypoint x="577" y="280" />
118
+ <di:waypoint x="702" y="280" />
119
+ <bpmndi:BPMNLabel>
120
+ <dc:Bounds x="582" y="206" width="49" height="14" />
121
+ </bpmndi:BPMNLabel>
122
+ </bpmndi:BPMNEdge>
123
+ <bpmndi:BPMNEdge id="BPMNEdge_he_sla" bpmnElement="he_sla">
124
+ <di:waypoint x="266" y="178" />
125
+ <di:waypoint x="266" y="280" />
126
+ <di:waypoint x="416" y="280" />
127
+ <bpmndi:BPMNLabel>
128
+ <dc:Bounds x="271" y="215" width="88" height="28" />
129
+ </bpmndi:BPMNLabel>
130
+ </bpmndi:BPMNEdge>
131
+ </bpmndi:BPMNPlane>
132
+ </bpmndi:BPMNDiagram>
133
+ </bpmn:definitions>
@@ -0,0 +1,136 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:nano="https://nanobpm.io/schema/shapes/1.0" id="Definitions_nano_workforce_implement_cell" targetNamespace="http://nanobpm.io/nano-workforce">
3
+ <bpmn:process id="implement-cell" name="Implement cell" isExecutable="true">
4
+ <bpmn:startEvent id="Start" name="Task">
5
+ <bpmn:outgoing>ic_toImplement</bpmn:outgoing>
6
+ </bpmn:startEvent>
7
+ <bpmn:serviceTask id="implement-task" name="Implement (agent)">
8
+ <bpmn:extensionElements>
9
+ <zeebe:taskDefinition type="senior:feature" />
10
+ <zeebe:linkedResources>
11
+ <zeebe:linkedResource resourceId="feature.md" bindingType="latest" resourceType="GenericScript" linkName="prompt" />
12
+ </zeebe:linkedResources>
13
+ <zeebe:ioMapping>
14
+ <zeebe:input source="=&#34;&#10;&#10;---&#10;&#10;&#34; + task.prompt + (if (is defined(baseBranchBrief) and baseBranchBrief != null) then baseBranchBrief else &#34;&#34;) + (if (is defined(blackboardBrief) and blackboardBrief != null) then blackboardBrief else &#34;&#34;) + (if (is defined(resolvedDepsBrief) and resolvedDepsBrief != null) then resolvedDepsBrief else &#34;&#34;) + (if (is defined(resolvedArtifacts) = false or resolvedArtifacts = null or count(resolvedArtifacts[item != null]) = 0) then &#34;&#34; else (&#34;&#10;&#10;---&#10;&#10;**Bound upstream readiness.** Build/install/clone against EXACTLY these resolved published versions (the ones first carrying the awaited capability), and bump the consumer dependency to them — never merely the newest:&#10;&#10;&#34; + string join(resolvedArtifacts[item != null], &#34;&#10;&#34;))) + (if (is defined(customInstructions) = false or customInstructions = null) then &#34;&#34; else &#34;&#10;&#10;---&#10;&#10;## Operator custom instructions&#10;&#10;The operator supplied these instructions for this run — follow them:&#10;&#10;&#34; + customInstructions)" target="appendPrompt" />
15
+ <zeebe:input source="=if (is defined(transcriptUrlBase)) then transcriptUrlBase else null" target="transcriptUrlBase" />
16
+ <zeebe:output source="=status" target="status" />
17
+ <zeebe:output source="=question" target="question" />
18
+ <zeebe:output source="=if (is defined(transcriptUrl)) then transcriptUrl else null" target="transcriptUrl" />
19
+ </zeebe:ioMapping>
20
+ </bpmn:extensionElements>
21
+ <bpmn:incoming>ic_toImplement</bpmn:incoming>
22
+ <bpmn:incoming>ic_answerLoop</bpmn:incoming>
23
+ <bpmn:outgoing>ic_toGw</bpmn:outgoing>
24
+ </bpmn:serviceTask>
25
+ <bpmn:exclusiveGateway id="ic_gw" name="clean terminal?" default="ic_escalate">
26
+ <bpmn:incoming>ic_toGw</bpmn:incoming>
27
+ <bpmn:outgoing>ic_escalate</bpmn:outgoing>
28
+ <bpmn:outgoing>ic_done</bpmn:outgoing>
29
+ </bpmn:exclusiveGateway>
30
+ <bpmn:callActivity id="escalate" name="Human escalation">
31
+ <bpmn:extensionElements>
32
+ <zeebe:calledElement processId="human-escalation" propagateAllChildVariables="true" />
33
+ </bpmn:extensionElements>
34
+ <bpmn:incoming>ic_escalate</bpmn:incoming>
35
+ <bpmn:outgoing>ic_toAnswerGw</bpmn:outgoing>
36
+ </bpmn:callActivity>
37
+ <bpmn:exclusiveGateway id="ic_gw_answer" name="answer?" default="ic_abandon">
38
+ <bpmn:incoming>ic_toAnswerGw</bpmn:incoming>
39
+ <bpmn:outgoing>ic_answerLoop</bpmn:outgoing>
40
+ <bpmn:outgoing>ic_abandon</bpmn:outgoing>
41
+ </bpmn:exclusiveGateway>
42
+ <bpmn:endEvent id="ic_end" name="Task done">
43
+ <bpmn:incoming>ic_done</bpmn:incoming>
44
+ <bpmn:incoming>ic_abandon</bpmn:incoming>
45
+ </bpmn:endEvent>
46
+ <bpmn:sequenceFlow id="ic_toImplement" sourceRef="Start" targetRef="implement-task" />
47
+ <bpmn:sequenceFlow id="ic_toGw" sourceRef="implement-task" targetRef="ic_gw" />
48
+ <bpmn:sequenceFlow id="ic_done" name="done" sourceRef="ic_gw" targetRef="ic_end">
49
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=status = "opened" or status = "blocked" or status = "skipped"</bpmn:conditionExpression>
50
+ </bpmn:sequenceFlow>
51
+ <bpmn:sequenceFlow id="ic_escalate" name="escalated" sourceRef="ic_gw" targetRef="escalate" />
52
+ <bpmn:sequenceFlow id="ic_toAnswerGw" sourceRef="escalate" targetRef="ic_gw_answer" />
53
+ <bpmn:sequenceFlow id="ic_answerLoop" name="answer" sourceRef="ic_gw_answer" targetRef="implement-task">
54
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=resolution = "answer"</bpmn:conditionExpression>
55
+ </bpmn:sequenceFlow>
56
+ <bpmn:sequenceFlow id="ic_abandon" name="abandon" sourceRef="ic_gw_answer" targetRef="ic_end" />
57
+ </bpmn:process>
58
+ <bpmndi:BPMNDiagram id="BPMNDiagram_implement-cell">
59
+ <bpmndi:BPMNPlane id="BPMNPlane_implement-cell" bpmnElement="implement-cell">
60
+ <bpmndi:BPMNShape id="BPMNShape_Start" bpmnElement="Start">
61
+ <dc:Bounds x="80" y="102" width="36" height="36" />
62
+ <bpmndi:BPMNLabel>
63
+ <dc:Bounds x="81" y="143" width="34" height="14" />
64
+ </bpmndi:BPMNLabel>
65
+ </bpmndi:BPMNShape>
66
+ <bpmndi:BPMNShape id="BPMNShape_implement-task" bpmnElement="implement-task">
67
+ <dc:Bounds x="216" y="80" width="100" height="80" />
68
+ </bpmndi:BPMNShape>
69
+ <bpmndi:BPMNShape id="BPMNShape_ic_gw" bpmnElement="ic_gw" isMarkerVisible="true">
70
+ <dc:Bounds x="416" y="95" width="50" height="50" />
71
+ <bpmndi:BPMNLabel>
72
+ <dc:Bounds x="406" y="62" width="70" height="28" />
73
+ </bpmndi:BPMNLabel>
74
+ </bpmndi:BPMNShape>
75
+ <bpmndi:BPMNShape id="BPMNShape_escalate" bpmnElement="escalate">
76
+ <dc:Bounds x="566" y="80" width="100" height="80" />
77
+ </bpmndi:BPMNShape>
78
+ <bpmndi:BPMNShape id="BPMNShape_ic_gw_answer" bpmnElement="ic_gw_answer" isMarkerVisible="true">
79
+ <dc:Bounds x="766" y="95" width="50" height="50" />
80
+ <bpmndi:BPMNLabel>
81
+ <dc:Bounds x="763" y="76" width="56" height="14" />
82
+ </bpmndi:BPMNLabel>
83
+ </bpmndi:BPMNShape>
84
+ <bpmndi:BPMNShape id="BPMNShape_ic_end" bpmnElement="ic_end">
85
+ <dc:Bounds x="916" y="102" width="36" height="36" />
86
+ <bpmndi:BPMNLabel>
87
+ <dc:Bounds x="901" y="83" width="66" height="14" />
88
+ </bpmndi:BPMNLabel>
89
+ </bpmndi:BPMNShape>
90
+ <bpmndi:BPMNEdge id="BPMNEdge_ic_toImplement" bpmnElement="ic_toImplement">
91
+ <di:waypoint x="116" y="120" />
92
+ <di:waypoint x="216" y="120" />
93
+ </bpmndi:BPMNEdge>
94
+ <bpmndi:BPMNEdge id="BPMNEdge_ic_toGw" bpmnElement="ic_toGw">
95
+ <di:waypoint x="316" y="120" />
96
+ <di:waypoint x="416" y="120" />
97
+ </bpmndi:BPMNEdge>
98
+ <bpmndi:BPMNEdge id="BPMNEdge_ic_escalate" bpmnElement="ic_escalate">
99
+ <di:waypoint x="466" y="120" />
100
+ <di:waypoint x="566" y="120" />
101
+ <bpmndi:BPMNLabel>
102
+ <dc:Bounds x="483" y="128" width="67" height="14" />
103
+ </bpmndi:BPMNLabel>
104
+ </bpmndi:BPMNEdge>
105
+ <bpmndi:BPMNEdge id="BPMNEdge_ic_toAnswerGw" bpmnElement="ic_toAnswerGw">
106
+ <di:waypoint x="666" y="120" />
107
+ <di:waypoint x="766" y="120" />
108
+ </bpmndi:BPMNEdge>
109
+ <bpmndi:BPMNEdge id="BPMNEdge_ic_abandon" bpmnElement="ic_abandon">
110
+ <di:waypoint x="816" y="120" />
111
+ <di:waypoint x="916" y="120" />
112
+ <bpmndi:BPMNLabel>
113
+ <dc:Bounds x="840" y="128" width="53" height="14" />
114
+ </bpmndi:BPMNLabel>
115
+ </bpmndi:BPMNEdge>
116
+ <bpmndi:BPMNEdge id="BPMNEdge_ic_done" bpmnElement="ic_done">
117
+ <di:waypoint x="441" y="145" />
118
+ <di:waypoint x="441" y="180" />
119
+ <di:waypoint x="934" y="180" />
120
+ <di:waypoint x="934" y="138" />
121
+ <bpmndi:BPMNLabel>
122
+ <dc:Bounds x="672" y="158" width="32" height="14" />
123
+ </bpmndi:BPMNLabel>
124
+ </bpmndi:BPMNEdge>
125
+ <bpmndi:BPMNEdge id="BPMNEdge_ic_answerLoop" bpmnElement="ic_answerLoop">
126
+ <di:waypoint x="791" y="145" />
127
+ <di:waypoint x="791" y="200" />
128
+ <di:waypoint x="266" y="200" />
129
+ <di:waypoint x="266" y="160" />
130
+ <bpmndi:BPMNLabel>
131
+ <dc:Bounds x="504" y="208" width="49" height="14" />
132
+ </bpmndi:BPMNLabel>
133
+ </bpmndi:BPMNEdge>
134
+ </bpmndi:BPMNPlane>
135
+ </bpmndi:BPMNDiagram>
136
+ </bpmn:definitions>
@@ -0,0 +1,218 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:nano="https://nanobpm.io/schema/shapes/1.0" id="Definitions_nano_workforce_merge_cell" targetNamespace="http://nanobpm.io/nano-workforce">
3
+ <bpmn:process id="merge-cell" name="Merge cell (trial merge)" isExecutable="true">
4
+ <bpmn:startEvent id="Start" name="Wave produced">
5
+ <bpmn:outgoing>mc_toTrial</bpmn:outgoing>
6
+ </bpmn:startEvent>
7
+ <bpmn:serviceTask id="trial-merge" name="Trial merge (agent)">
8
+ <bpmn:extensionElements>
9
+ <zeebe:taskDefinition type="senior:trial-merge" />
10
+ <zeebe:linkedResources>
11
+ <zeebe:linkedResource resourceId="trial-merge.md" bindingType="latest" resourceType="GenericScript" linkName="prompt" />
12
+ </zeebe:linkedResources>
13
+ <zeebe:ioMapping>
14
+ <zeebe:input source="=null" target="result" />
15
+ <zeebe:input source="=null" target="conflicts" />
16
+ <zeebe:input source="=null" target="failing" />
17
+ <zeebe:input source="=null" target="summary" />
18
+ <zeebe:input source="=null" target="answer" />
19
+ </zeebe:ioMapping>
20
+ </bpmn:extensionElements>
21
+ <bpmn:incoming>mc_toTrial</bpmn:incoming>
22
+ <bpmn:incoming>mc_rerun</bpmn:incoming>
23
+ <bpmn:incoming>mc_sla</bpmn:incoming>
24
+ <bpmn:outgoing>mc_toRecord</bpmn:outgoing>
25
+ </bpmn:serviceTask>
26
+ <bpmn:serviceTask id="record-trial-merge" name="Record trial merge">
27
+ <bpmn:extensionElements>
28
+ <zeebe:taskDefinition type="pr.record-trial-merge" />
29
+ <zeebe:properties>
30
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="RecordTrialMergeIn" />
31
+ </zeebe:properties>
32
+ </bpmn:extensionElements>
33
+ <bpmn:incoming>mc_toRecord</bpmn:incoming>
34
+ <bpmn:outgoing>mc_toGwTrial</bpmn:outgoing>
35
+ </bpmn:serviceTask>
36
+ <bpmn:exclusiveGateway id="gw-trial" name="trial red?" default="mc_proceed">
37
+ <bpmn:incoming>mc_toGwTrial</bpmn:incoming>
38
+ <bpmn:outgoing>mc_escalate</bpmn:outgoing>
39
+ <bpmn:outgoing>mc_proceed</bpmn:outgoing>
40
+ </bpmn:exclusiveGateway>
41
+ <bpmn:userTask id="trial-merge-decision" name="Trial-merge decision (human)">
42
+ <bpmn:extensionElements>
43
+ <zeebe:formDefinition formId="trial-merge-decision" />
44
+ <zeebe:userTask />
45
+ <zeebe:assignmentDefinition candidateGroups="operators" assignee="=if (is defined(escalationAssignee) and escalationAssignee != null and trim(string(escalationAssignee)) != &#34;&#34;) then escalationAssignee else null" />
46
+ </bpmn:extensionElements>
47
+ <bpmn:incoming>mc_escalate</bpmn:incoming>
48
+ <bpmn:outgoing>mc_toResolve</bpmn:outgoing>
49
+ </bpmn:userTask>
50
+ <bpmn:boundaryEvent id="be_trial_sla" name="SLA elapsed" attachedToRef="trial-merge-decision">
51
+ <bpmn:outgoing>mc_sla</bpmn:outgoing>
52
+ <bpmn:timerEventDefinition id="ted_trial_sla">
53
+ <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">=escalationSlaTimeout</bpmn:timeDuration>
54
+ </bpmn:timerEventDefinition>
55
+ </bpmn:boundaryEvent>
56
+ <bpmn:serviceTask id="resolve-trial-attention" name="Clear trial attention">
57
+ <bpmn:extensionElements>
58
+ <zeebe:taskDefinition type="pr.resolve-trial-attention" />
59
+ <zeebe:properties>
60
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="ResolveTrialAttentionIn" />
61
+ </zeebe:properties>
62
+ </bpmn:extensionElements>
63
+ <bpmn:incoming>mc_toResolve</bpmn:incoming>
64
+ <bpmn:outgoing>mc_toAnswerGw</bpmn:outgoing>
65
+ </bpmn:serviceTask>
66
+ <bpmn:exclusiveGateway id="gw-trial-answer" name="action?" default="mc_rerun">
67
+ <bpmn:incoming>mc_toAnswerGw</bpmn:incoming>
68
+ <bpmn:outgoing>mc_answerProceed</bpmn:outgoing>
69
+ <bpmn:outgoing>mc_answerAbandon</bpmn:outgoing>
70
+ <bpmn:outgoing>mc_rerun</bpmn:outgoing>
71
+ </bpmn:exclusiveGateway>
72
+ <bpmn:endEvent id="merge-passed" name="Merge check passed">
73
+ <bpmn:incoming>mc_proceed</bpmn:incoming>
74
+ <bpmn:incoming>mc_answerProceed</bpmn:incoming>
75
+ </bpmn:endEvent>
76
+ <bpmn:endEvent id="merge-abandoned" name="Abandoned">
77
+ <bpmn:incoming>mc_answerAbandon</bpmn:incoming>
78
+ </bpmn:endEvent>
79
+ <bpmn:sequenceFlow id="mc_toTrial" sourceRef="Start" targetRef="trial-merge" />
80
+ <bpmn:sequenceFlow id="mc_toRecord" sourceRef="trial-merge" targetRef="record-trial-merge" />
81
+ <bpmn:sequenceFlow id="mc_toGwTrial" sourceRef="record-trial-merge" targetRef="gw-trial" />
82
+ <bpmn:sequenceFlow id="mc_escalate" name="suite failed" sourceRef="gw-trial" targetRef="trial-merge-decision">
83
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=trialMergeRed</bpmn:conditionExpression>
84
+ </bpmn:sequenceFlow>
85
+ <bpmn:sequenceFlow id="mc_proceed" name="proceed" sourceRef="gw-trial" targetRef="merge-passed" />
86
+ <bpmn:sequenceFlow id="mc_toResolve" sourceRef="trial-merge-decision" targetRef="resolve-trial-attention" />
87
+ <bpmn:sequenceFlow id="mc_toAnswerGw" sourceRef="resolve-trial-attention" targetRef="gw-trial-answer" />
88
+ <bpmn:sequenceFlow id="mc_answerProceed" name="proceed" sourceRef="gw-trial-answer" targetRef="merge-passed">
89
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=action = "proceed"</bpmn:conditionExpression>
90
+ </bpmn:sequenceFlow>
91
+ <bpmn:sequenceFlow id="mc_answerAbandon" name="abandon" sourceRef="gw-trial-answer" targetRef="merge-abandoned">
92
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=action = "abandon"</bpmn:conditionExpression>
93
+ </bpmn:sequenceFlow>
94
+ <bpmn:sequenceFlow id="mc_rerun" name="rebase" sourceRef="gw-trial-answer" targetRef="trial-merge" />
95
+ <bpmn:sequenceFlow id="mc_sla" name="SLA auto-rerun" sourceRef="be_trial_sla" targetRef="trial-merge" />
96
+ </bpmn:process>
97
+ <bpmndi:BPMNDiagram id="BPMNDiagram_merge-cell">
98
+ <bpmndi:BPMNPlane id="BPMNPlane_merge-cell" bpmnElement="merge-cell">
99
+ <bpmndi:BPMNShape id="BPMNShape_Start" bpmnElement="Start">
100
+ <dc:Bounds x="80" y="102" width="36" height="36" />
101
+ <bpmndi:BPMNLabel>
102
+ <dc:Bounds x="68" y="143" width="60" height="28" />
103
+ </bpmndi:BPMNLabel>
104
+ </bpmndi:BPMNShape>
105
+ <bpmndi:BPMNShape id="BPMNShape_trial-merge" bpmnElement="trial-merge">
106
+ <dc:Bounds x="216" y="80" width="100" height="80" />
107
+ </bpmndi:BPMNShape>
108
+ <bpmndi:BPMNShape id="BPMNShape_record-trial-merge" bpmnElement="record-trial-merge">
109
+ <dc:Bounds x="416" y="80" width="100" height="80" />
110
+ </bpmndi:BPMNShape>
111
+ <bpmndi:BPMNShape id="BPMNShape_gw-trial" bpmnElement="gw-trial" isMarkerVisible="true">
112
+ <dc:Bounds x="616" y="95" width="50" height="50" />
113
+ <bpmndi:BPMNLabel>
114
+ <dc:Bounds x="606" y="76" width="71" height="14" />
115
+ </bpmndi:BPMNLabel>
116
+ </bpmndi:BPMNShape>
117
+ <bpmndi:BPMNShape id="BPMNShape_trial-merge-decision" bpmnElement="trial-merge-decision">
118
+ <dc:Bounds x="766" y="240" width="100" height="80" />
119
+ </bpmndi:BPMNShape>
120
+ <bpmndi:BPMNShape id="BPMNShape_resolve-trial-attention" bpmnElement="resolve-trial-attention">
121
+ <dc:Bounds x="966" y="240" width="100" height="80" />
122
+ </bpmndi:BPMNShape>
123
+ <bpmndi:BPMNShape id="BPMNShape_gw-trial-answer" bpmnElement="gw-trial-answer" isMarkerVisible="true">
124
+ <dc:Bounds x="1166" y="255" width="50" height="50" />
125
+ <bpmndi:BPMNLabel>
126
+ <dc:Bounds x="1221" y="273" width="53" height="14" />
127
+ </bpmndi:BPMNLabel>
128
+ </bpmndi:BPMNShape>
129
+ <bpmndi:BPMNShape id="BPMNShape_merge-passed" bpmnElement="merge-passed">
130
+ <dc:Bounds x="1316" y="102" width="36" height="36" />
131
+ <bpmndi:BPMNLabel>
132
+ <dc:Bounds x="1293" y="143" width="82" height="28" />
133
+ </bpmndi:BPMNLabel>
134
+ </bpmndi:BPMNShape>
135
+ <bpmndi:BPMNShape id="BPMNShape_merge-abandoned" bpmnElement="merge-abandoned">
136
+ <dc:Bounds x="1316" y="422" width="36" height="36" />
137
+ <bpmndi:BPMNLabel>
138
+ <dc:Bounds x="1300" y="463" width="69" height="14" />
139
+ </bpmndi:BPMNLabel>
140
+ </bpmndi:BPMNShape>
141
+ <bpmndi:BPMNShape id="BPMNShape_be_trial_sla" bpmnElement="be_trial_sla">
142
+ <dc:Bounds x="798" y="302" width="36" height="36" />
143
+ <bpmndi:BPMNLabel>
144
+ <dc:Bounds x="774" y="383" width="84" height="14" />
145
+ </bpmndi:BPMNLabel>
146
+ </bpmndi:BPMNShape>
147
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_toTrial" bpmnElement="mc_toTrial">
148
+ <di:waypoint x="116" y="120" />
149
+ <di:waypoint x="216" y="120" />
150
+ </bpmndi:BPMNEdge>
151
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_toRecord" bpmnElement="mc_toRecord">
152
+ <di:waypoint x="316" y="120" />
153
+ <di:waypoint x="416" y="120" />
154
+ </bpmndi:BPMNEdge>
155
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_toGwTrial" bpmnElement="mc_toGwTrial">
156
+ <di:waypoint x="516" y="120" />
157
+ <di:waypoint x="616" y="120" />
158
+ </bpmndi:BPMNEdge>
159
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_proceed" bpmnElement="mc_proceed">
160
+ <di:waypoint x="666" y="120" />
161
+ <di:waypoint x="1316" y="120" />
162
+ <bpmndi:BPMNLabel>
163
+ <dc:Bounds x="902" y="98" width="53" height="14" />
164
+ </bpmndi:BPMNLabel>
165
+ </bpmndi:BPMNEdge>
166
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_rerun" bpmnElement="mc_rerun">
167
+ <di:waypoint x="1191" y="305" />
168
+ <di:waypoint x="1191" y="360" />
169
+ <di:waypoint x="266" y="360" />
170
+ <di:waypoint x="266" y="160" />
171
+ <bpmndi:BPMNLabel>
172
+ <dc:Bounds x="706" y="338" width="46" height="14" />
173
+ </bpmndi:BPMNLabel>
174
+ </bpmndi:BPMNEdge>
175
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_escalate" bpmnElement="mc_escalate">
176
+ <di:waypoint x="641" y="145" />
177
+ <di:waypoint x="641" y="280" />
178
+ <di:waypoint x="766" y="280" />
179
+ <bpmndi:BPMNLabel>
180
+ <dc:Bounds x="646" y="206" width="85" height="14" />
181
+ </bpmndi:BPMNLabel>
182
+ </bpmndi:BPMNEdge>
183
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_answerProceed" bpmnElement="mc_answerProceed">
184
+ <di:waypoint x="1191" y="255" />
185
+ <di:waypoint x="1191" y="120" />
186
+ <di:waypoint x="1316" y="120" />
187
+ <bpmndi:BPMNLabel>
188
+ <dc:Bounds x="1196" y="181" width="53" height="14" />
189
+ </bpmndi:BPMNLabel>
190
+ </bpmndi:BPMNEdge>
191
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_answerAbandon" bpmnElement="mc_answerAbandon">
192
+ <di:waypoint x="1191" y="305" />
193
+ <di:waypoint x="1191" y="440" />
194
+ <di:waypoint x="1316" y="440" />
195
+ <bpmndi:BPMNLabel>
196
+ <dc:Bounds x="1196" y="393" width="53" height="14" />
197
+ </bpmndi:BPMNLabel>
198
+ </bpmndi:BPMNEdge>
199
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_toResolve" bpmnElement="mc_toResolve">
200
+ <di:waypoint x="866" y="280" />
201
+ <di:waypoint x="966" y="280" />
202
+ </bpmndi:BPMNEdge>
203
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_toAnswerGw" bpmnElement="mc_toAnswerGw">
204
+ <di:waypoint x="1066" y="280" />
205
+ <di:waypoint x="1166" y="280" />
206
+ </bpmndi:BPMNEdge>
207
+ <bpmndi:BPMNEdge id="BPMNEdge_mc_sla" bpmnElement="mc_sla">
208
+ <di:waypoint x="816" y="338" />
209
+ <di:waypoint x="816" y="358" />
210
+ <di:waypoint x="266" y="358" />
211
+ <di:waypoint x="266" y="160" />
212
+ <bpmndi:BPMNLabel>
213
+ <dc:Bounds x="504" y="325" width="74" height="28" />
214
+ </bpmndi:BPMNLabel>
215
+ </bpmndi:BPMNEdge>
216
+ </bpmndi:BPMNPlane>
217
+ </bpmndi:BPMNDiagram>
218
+ </bpmn:definitions>
@@ -0,0 +1,306 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:nano="https://nanobpm.io/schema/shapes/1.0" id="Definitions_nano_workforce_wait_gate" targetNamespace="http://nanobpm.io/nano-workforce">
3
+ <bpmn:process id="wait-gate" name="Readiness wait-gate cell" isExecutable="true">
4
+ <bpmn:startEvent id="Start" name="Gate opened">
5
+ <bpmn:outgoing>wg_toProbe</bpmn:outgoing>
6
+ </bpmn:startEvent>
7
+ <bpmn:subProcess id="probe-loop" name="Probe readiness loop">
8
+ <bpmn:incoming>wg_toProbe</bpmn:incoming>
9
+ <bpmn:outgoing>wg_probed</bpmn:outgoing>
10
+ <bpmn:startEvent id="probe-loop-start" name="Start probe loop">
11
+ <bpmn:outgoing>pl_toProbe</bpmn:outgoing>
12
+ </bpmn:startEvent>
13
+ <bpmn:serviceTask id="probe" name="Probe readiness">
14
+ <bpmn:extensionElements>
15
+ <zeebe:taskDefinition type="pr.readiness-probe" />
16
+ <zeebe:properties>
17
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="ReadinessProbeIn" />
18
+ <zeebe:property name="io.nanobpm.dataEnvelope.out" value="ReadinessProbeOut" />
19
+ </zeebe:properties>
20
+ </bpmn:extensionElements>
21
+ <bpmn:incoming>pl_toProbe</bpmn:incoming>
22
+ <bpmn:incoming>pl_pollBack</bpmn:incoming>
23
+ <bpmn:outgoing>pl_probed</bpmn:outgoing>
24
+ </bpmn:serviceTask>
25
+ <bpmn:exclusiveGateway id="probe-ready-gw" name="ready?" default="pl_notReady">
26
+ <bpmn:incoming>pl_probed</bpmn:incoming>
27
+ <bpmn:outgoing>pl_ready</bpmn:outgoing>
28
+ <bpmn:outgoing>pl_notReady</bpmn:outgoing>
29
+ </bpmn:exclusiveGateway>
30
+ <bpmn:intermediateCatchEvent id="wait-poll" name="Wait poll interval">
31
+ <bpmn:incoming>pl_notReady</bpmn:incoming>
32
+ <bpmn:outgoing>pl_pollBack</bpmn:outgoing>
33
+ <bpmn:timerEventDefinition id="ted_probePollEvery">
34
+ <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">=probePollEvery</bpmn:timeDuration>
35
+ </bpmn:timerEventDefinition>
36
+ </bpmn:intermediateCatchEvent>
37
+ <bpmn:endEvent id="probe-loop-end" name="Probe ready">
38
+ <bpmn:incoming>pl_ready</bpmn:incoming>
39
+ </bpmn:endEvent>
40
+ <bpmn:sequenceFlow id="pl_toProbe" sourceRef="probe-loop-start" targetRef="probe" />
41
+ <bpmn:sequenceFlow id="pl_probed" sourceRef="probe" targetRef="probe-ready-gw" />
42
+ <bpmn:sequenceFlow id="pl_ready" name="ready" sourceRef="probe-ready-gw" targetRef="probe-loop-end">
43
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=ready = true</bpmn:conditionExpression>
44
+ </bpmn:sequenceFlow>
45
+ <bpmn:sequenceFlow id="pl_notReady" name="not ready" sourceRef="probe-ready-gw" targetRef="wait-poll" />
46
+ <bpmn:sequenceFlow id="pl_pollBack" sourceRef="wait-poll" targetRef="probe" />
47
+ </bpmn:subProcess>
48
+ <bpmn:boundaryEvent id="probe-timeout" name="Gate timed out" attachedToRef="probe-loop">
49
+ <bpmn:outgoing>wg_probeTimeout</bpmn:outgoing>
50
+ <bpmn:timerEventDefinition id="ted_probeTimeout">
51
+ <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">=probeTimeout</bpmn:timeDuration>
52
+ </bpmn:timerEventDefinition>
53
+ </bpmn:boundaryEvent>
54
+ <bpmn:serviceTask id="probe-last-attempt" name="Probe readiness (last attempt)">
55
+ <bpmn:extensionElements>
56
+ <zeebe:taskDefinition type="pr.readiness-probe" />
57
+ <zeebe:properties>
58
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="ReadinessProbeIn" />
59
+ <zeebe:property name="io.nanobpm.dataEnvelope.out" value="ReadinessProbeOut" />
60
+ </zeebe:properties>
61
+ <zeebe:ioMapping>
62
+ <zeebe:input source="=true" target="lastAttempt" />
63
+ </zeebe:ioMapping>
64
+ </bpmn:extensionElements>
65
+ <bpmn:incoming>wg_probeTimeout</bpmn:incoming>
66
+ <bpmn:outgoing>wg_lastAttemptDone</bpmn:outgoing>
67
+ </bpmn:serviceTask>
68
+ <bpmn:exclusiveGateway id="gw-ready" name="ready?" default="wg_escalate">
69
+ <bpmn:incoming>wg_probed</bpmn:incoming>
70
+ <bpmn:incoming>wg_lastAttemptDone</bpmn:incoming>
71
+ <bpmn:outgoing>wg_ready</bpmn:outgoing>
72
+ <bpmn:outgoing>wg_escalate</bpmn:outgoing>
73
+ </bpmn:exclusiveGateway>
74
+ <bpmn:userTask id="readiness-escalation" name="Readiness escalation (human)">
75
+ <bpmn:extensionElements>
76
+ <zeebe:formDefinition formId="readiness-escalation" />
77
+ <zeebe:userTask />
78
+ <zeebe:assignmentDefinition candidateGroups="operators" />
79
+ </bpmn:extensionElements>
80
+ <bpmn:incoming>wg_escalate</bpmn:incoming>
81
+ <bpmn:outgoing>wg_toResolution</bpmn:outgoing>
82
+ </bpmn:userTask>
83
+ <bpmn:boundaryEvent id="be_wg_sla" name="SLA elapsed" attachedToRef="readiness-escalation">
84
+ <bpmn:outgoing>wg_sla</bpmn:outgoing>
85
+ <bpmn:timerEventDefinition id="ted_wg_sla">
86
+ <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">=escalationSlaTimeout</bpmn:timeDuration>
87
+ </bpmn:timerEventDefinition>
88
+ </bpmn:boundaryEvent>
89
+ <bpmn:exclusiveGateway id="gw-resolution" name="resolution?" default="wg_proceed">
90
+ <bpmn:incoming>wg_toResolution</bpmn:incoming>
91
+ <bpmn:outgoing>wg_proceed</bpmn:outgoing>
92
+ <bpmn:outgoing>wg_abandon</bpmn:outgoing>
93
+ </bpmn:exclusiveGateway>
94
+ <bpmn:endEvent id="gate-ready" name="Ready">
95
+ <bpmn:extensionElements>
96
+ <zeebe:ioMapping>
97
+ <zeebe:input source="=&#34;ready&#34;" target="gateOutcome" />
98
+ </zeebe:ioMapping>
99
+ </bpmn:extensionElements>
100
+ <bpmn:incoming>wg_ready</bpmn:incoming>
101
+ <bpmn:incoming>wg_proceed</bpmn:incoming>
102
+ </bpmn:endEvent>
103
+ <bpmn:endEvent id="gate-abandoned" name="Abandoned">
104
+ <bpmn:extensionElements>
105
+ <zeebe:ioMapping>
106
+ <zeebe:input source="=&#34;abandoned&#34;" target="gateOutcome" />
107
+ </zeebe:ioMapping>
108
+ </bpmn:extensionElements>
109
+ <bpmn:incoming>wg_abandon</bpmn:incoming>
110
+ <bpmn:incoming>wg_sla</bpmn:incoming>
111
+ </bpmn:endEvent>
112
+ <bpmn:sequenceFlow id="wg_toProbe" sourceRef="Start" targetRef="probe-loop" />
113
+ <bpmn:sequenceFlow id="wg_probed" sourceRef="probe-loop" targetRef="gw-ready" />
114
+ <bpmn:sequenceFlow id="wg_probeTimeout" name="timed out" sourceRef="probe-timeout" targetRef="probe-last-attempt" />
115
+ <bpmn:sequenceFlow id="wg_lastAttemptDone" sourceRef="probe-last-attempt" targetRef="gw-ready" />
116
+ <bpmn:sequenceFlow id="wg_ready" name="ready" sourceRef="gw-ready" targetRef="gate-ready">
117
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=ready = true</bpmn:conditionExpression>
118
+ </bpmn:sequenceFlow>
119
+ <bpmn:sequenceFlow id="wg_escalate" name="stalled" sourceRef="gw-ready" targetRef="readiness-escalation" />
120
+ <bpmn:sequenceFlow id="wg_toResolution" sourceRef="readiness-escalation" targetRef="gw-resolution" />
121
+ <bpmn:sequenceFlow id="wg_proceed" name="acknowledge" sourceRef="gw-resolution" targetRef="gate-ready" />
122
+ <bpmn:sequenceFlow id="wg_abandon" name="abandon" sourceRef="gw-resolution" targetRef="gate-abandoned">
123
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=resolution = "abandon"</bpmn:conditionExpression>
124
+ </bpmn:sequenceFlow>
125
+ <bpmn:sequenceFlow id="wg_sla" name="SLA auto-abandon" sourceRef="be_wg_sla" targetRef="gate-abandoned" />
126
+ </bpmn:process>
127
+ <bpmndi:BPMNDiagram id="BPMNDiagram_wait-gate">
128
+ <bpmndi:BPMNPlane id="BPMNPlane_wait-gate" bpmnElement="wait-gate">
129
+ <bpmndi:BPMNShape id="BPMNShape_Start" bpmnElement="Start">
130
+ <dc:Bounds x="80" y="102" width="36" height="36" />
131
+ <bpmndi:BPMNLabel>
132
+ <dc:Bounds x="58" y="143" width="80" height="14" />
133
+ </bpmndi:BPMNLabel>
134
+ </bpmndi:BPMNShape>
135
+ <bpmndi:BPMNShape id="BPMNShape_probe-loop" bpmnElement="probe-loop">
136
+ <dc:Bounds x="216" y="80" width="100" height="80" />
137
+ </bpmndi:BPMNShape>
138
+ <bpmndi:BPMNShape id="BPMNShape_probe-last-attempt" bpmnElement="probe-last-attempt">
139
+ <dc:Bounds x="416" y="240" width="100" height="80" />
140
+ </bpmndi:BPMNShape>
141
+ <bpmndi:BPMNShape id="BPMNShape_gw-ready" bpmnElement="gw-ready" isMarkerVisible="true">
142
+ <dc:Bounds x="616" y="95" width="50" height="50" />
143
+ <bpmndi:BPMNLabel>
144
+ <dc:Bounds x="618" y="76" width="46" height="14" />
145
+ </bpmndi:BPMNLabel>
146
+ </bpmndi:BPMNShape>
147
+ <bpmndi:BPMNShape id="BPMNShape_readiness-escalation" bpmnElement="readiness-escalation">
148
+ <dc:Bounds x="766" y="80" width="100" height="80" />
149
+ </bpmndi:BPMNShape>
150
+ <bpmndi:BPMNShape id="BPMNShape_gw-resolution" bpmnElement="gw-resolution" isMarkerVisible="true">
151
+ <dc:Bounds x="966" y="95" width="50" height="50" />
152
+ <bpmndi:BPMNLabel>
153
+ <dc:Bounds x="951" y="76" width="81" height="14" />
154
+ </bpmndi:BPMNLabel>
155
+ </bpmndi:BPMNShape>
156
+ <bpmndi:BPMNShape id="BPMNShape_gate-ready" bpmnElement="gate-ready">
157
+ <dc:Bounds x="1116" y="102" width="36" height="36" />
158
+ <bpmndi:BPMNLabel>
159
+ <dc:Bounds x="1114" y="83" width="41" height="14" />
160
+ </bpmndi:BPMNLabel>
161
+ </bpmndi:BPMNShape>
162
+ <bpmndi:BPMNShape id="BPMNShape_gate-abandoned" bpmnElement="gate-abandoned">
163
+ <dc:Bounds x="1116" y="262" width="36" height="36" />
164
+ <bpmndi:BPMNLabel>
165
+ <dc:Bounds x="1100" y="303" width="69" height="14" />
166
+ </bpmndi:BPMNLabel>
167
+ </bpmndi:BPMNShape>
168
+ <bpmndi:BPMNShape id="BPMNShape_probe-timeout" bpmnElement="probe-timeout">
169
+ <dc:Bounds x="248" y="142" width="36" height="36" />
170
+ <bpmndi:BPMNLabel>
171
+ <dc:Bounds x="168" y="183" width="76" height="28" />
172
+ </bpmndi:BPMNLabel>
173
+ </bpmndi:BPMNShape>
174
+ <bpmndi:BPMNShape id="BPMNShape_be_wg_sla" bpmnElement="be_wg_sla">
175
+ <dc:Bounds x="798" y="142" width="36" height="36" />
176
+ <bpmndi:BPMNLabel>
177
+ <dc:Bounds x="714" y="223" width="84" height="14" />
178
+ </bpmndi:BPMNLabel>
179
+ </bpmndi:BPMNShape>
180
+ <bpmndi:BPMNEdge id="BPMNEdge_wg_toProbe" bpmnElement="wg_toProbe">
181
+ <di:waypoint x="116" y="120" />
182
+ <di:waypoint x="216" y="120" />
183
+ </bpmndi:BPMNEdge>
184
+ <bpmndi:BPMNEdge id="BPMNEdge_wg_probed" bpmnElement="wg_probed">
185
+ <di:waypoint x="316" y="120" />
186
+ <di:waypoint x="616" y="120" />
187
+ </bpmndi:BPMNEdge>
188
+ <bpmndi:BPMNEdge id="BPMNEdge_wg_escalate" bpmnElement="wg_escalate">
189
+ <di:waypoint x="666" y="120" />
190
+ <di:waypoint x="766" y="120" />
191
+ <bpmndi:BPMNLabel>
192
+ <dc:Bounds x="690" y="98" width="53" height="14" />
193
+ </bpmndi:BPMNLabel>
194
+ </bpmndi:BPMNEdge>
195
+ <bpmndi:BPMNEdge id="BPMNEdge_wg_toResolution" bpmnElement="wg_toResolution">
196
+ <di:waypoint x="866" y="120" />
197
+ <di:waypoint x="966" y="120" />
198
+ </bpmndi:BPMNEdge>
199
+ <bpmndi:BPMNEdge id="BPMNEdge_wg_proceed" bpmnElement="wg_proceed">
200
+ <di:waypoint x="1016" y="120" />
201
+ <di:waypoint x="1116" y="120" />
202
+ <bpmndi:BPMNLabel>
203
+ <dc:Bounds x="1024" y="128" width="84" height="14" />
204
+ </bpmndi:BPMNLabel>
205
+ </bpmndi:BPMNEdge>
206
+ <bpmndi:BPMNEdge id="BPMNEdge_wg_abandon" bpmnElement="wg_abandon">
207
+ <di:waypoint x="991" y="145" />
208
+ <di:waypoint x="991" y="280" />
209
+ <di:waypoint x="1116" y="280" />
210
+ <bpmndi:BPMNLabel>
211
+ <dc:Bounds x="996" y="206" width="53" height="14" />
212
+ </bpmndi:BPMNLabel>
213
+ </bpmndi:BPMNEdge>
214
+ <bpmndi:BPMNEdge id="BPMNEdge_wg_lastAttemptDone" bpmnElement="wg_lastAttemptDone">
215
+ <di:waypoint x="516" y="280" />
216
+ <di:waypoint x="641" y="280" />
217
+ <di:waypoint x="641" y="145" />
218
+ </bpmndi:BPMNEdge>
219
+ <bpmndi:BPMNEdge id="BPMNEdge_wg_ready" bpmnElement="wg_ready">
220
+ <di:waypoint x="641" y="145" />
221
+ <di:waypoint x="641" y="200" />
222
+ <di:waypoint x="1134" y="200" />
223
+ <di:waypoint x="1134" y="138" />
224
+ <bpmndi:BPMNLabel>
225
+ <dc:Bounds x="868" y="178" width="39" height="14" />
226
+ </bpmndi:BPMNLabel>
227
+ </bpmndi:BPMNEdge>
228
+ <bpmndi:BPMNEdge id="BPMNEdge_wg_probeTimeout" bpmnElement="wg_probeTimeout">
229
+ <di:waypoint x="266" y="178" />
230
+ <di:waypoint x="266" y="280" />
231
+ <di:waypoint x="416" y="280" />
232
+ <bpmndi:BPMNLabel>
233
+ <dc:Bounds x="271" y="222" width="67" height="14" />
234
+ </bpmndi:BPMNLabel>
235
+ </bpmndi:BPMNEdge>
236
+ <bpmndi:BPMNEdge id="BPMNEdge_wg_sla" bpmnElement="wg_sla">
237
+ <di:waypoint x="816" y="178" />
238
+ <di:waypoint x="816" y="280" />
239
+ <di:waypoint x="1116" y="280" />
240
+ <bpmndi:BPMNLabel>
241
+ <dc:Bounds x="821" y="215" width="88" height="28" />
242
+ </bpmndi:BPMNLabel>
243
+ </bpmndi:BPMNEdge>
244
+ </bpmndi:BPMNPlane>
245
+ </bpmndi:BPMNDiagram>
246
+ <bpmndi:BPMNDiagram id="BPMNDiagram_probe-loop">
247
+ <bpmndi:BPMNPlane id="BPMNPlane_probe-loop" bpmnElement="probe-loop">
248
+ <bpmndi:BPMNShape id="BPMNShape_probe-loop-start" bpmnElement="probe-loop-start">
249
+ <dc:Bounds x="80" y="102" width="36" height="36" />
250
+ <bpmndi:BPMNLabel>
251
+ <dc:Bounds x="58" y="143" width="80" height="28" />
252
+ </bpmndi:BPMNLabel>
253
+ </bpmndi:BPMNShape>
254
+ <bpmndi:BPMNShape id="BPMNShape_probe" bpmnElement="probe">
255
+ <dc:Bounds x="216" y="80" width="100" height="80" />
256
+ </bpmndi:BPMNShape>
257
+ <bpmndi:BPMNShape id="BPMNShape_probe-ready-gw" bpmnElement="probe-ready-gw" isMarkerVisible="true">
258
+ <dc:Bounds x="416" y="95" width="50" height="50" />
259
+ <bpmndi:BPMNLabel>
260
+ <dc:Bounds x="418" y="76" width="46" height="14" />
261
+ </bpmndi:BPMNLabel>
262
+ </bpmndi:BPMNShape>
263
+ <bpmndi:BPMNShape id="BPMNShape_wait-poll" bpmnElement="wait-poll">
264
+ <dc:Bounds x="566" y="262" width="36" height="36" />
265
+ <bpmndi:BPMNLabel>
266
+ <dc:Bounds x="550" y="229" width="68" height="28" />
267
+ </bpmndi:BPMNLabel>
268
+ </bpmndi:BPMNShape>
269
+ <bpmndi:BPMNShape id="BPMNShape_probe-loop-end" bpmnElement="probe-loop-end">
270
+ <dc:Bounds x="566" y="102" width="36" height="36" />
271
+ <bpmndi:BPMNLabel>
272
+ <dc:Bounds x="544" y="143" width="80" height="14" />
273
+ </bpmndi:BPMNLabel>
274
+ </bpmndi:BPMNShape>
275
+ <bpmndi:BPMNEdge id="BPMNEdge_pl_toProbe" bpmnElement="pl_toProbe">
276
+ <di:waypoint x="116" y="120" />
277
+ <di:waypoint x="216" y="120" />
278
+ </bpmndi:BPMNEdge>
279
+ <bpmndi:BPMNEdge id="BPMNEdge_pl_probed" bpmnElement="pl_probed">
280
+ <di:waypoint x="316" y="120" />
281
+ <di:waypoint x="416" y="120" />
282
+ </bpmndi:BPMNEdge>
283
+ <bpmndi:BPMNEdge id="BPMNEdge_pl_ready" bpmnElement="pl_ready">
284
+ <di:waypoint x="466" y="120" />
285
+ <di:waypoint x="566" y="120" />
286
+ <bpmndi:BPMNLabel>
287
+ <dc:Bounds x="497" y="98" width="39" height="14" />
288
+ </bpmndi:BPMNLabel>
289
+ </bpmndi:BPMNEdge>
290
+ <bpmndi:BPMNEdge id="BPMNEdge_pl_notReady" bpmnElement="pl_notReady">
291
+ <di:waypoint x="441" y="145" />
292
+ <di:waypoint x="441" y="280" />
293
+ <di:waypoint x="566" y="280" />
294
+ <bpmndi:BPMNLabel>
295
+ <dc:Bounds x="446" y="206" width="64" height="14" />
296
+ </bpmndi:BPMNLabel>
297
+ </bpmndi:BPMNEdge>
298
+ <bpmndi:BPMNEdge id="BPMNEdge_pl_pollBack" bpmnElement="pl_pollBack">
299
+ <di:waypoint x="584" y="298" />
300
+ <di:waypoint x="584" y="318" />
301
+ <di:waypoint x="266" y="318" />
302
+ <di:waypoint x="266" y="160" />
303
+ </bpmndi:BPMNEdge>
304
+ </bpmndi:BPMNPlane>
305
+ </bpmndi:BPMNDiagram>
306
+ </bpmn:definitions>
@@ -51,11 +51,16 @@ test("every corpus model is either ported or has a documented blocker", () => {
51
51
  "merge-loop",
52
52
  "plan-fanout",
53
53
  "delivery-human",
54
+ "implement-cell",
55
+ "converge-cell",
56
+ "merge-cell",
57
+ "wait-gate",
58
+ "human-escalation",
54
59
  ];
55
60
  assertEquals(
56
61
  PORTS.map((p) => p.model),
57
62
  expected,
58
- "PORTS must cover all eight goldens in the epic's authoring order",
63
+ "PORTS must cover all corpus goldens in the epic's authoring order",
59
64
  );
60
65
  for (const port of PORTS) {
61
66
  assert(
@@ -187,4 +187,32 @@ export const PORTS: readonly PortEntry[] = [
187
187
  model: "delivery-human",
188
188
  blockedReason: `${MULTI_START_END_BLOCK} (delivery-human: 1 start, 2 ends)`,
189
189
  },
190
+ {
191
+ model: "implement-cell",
192
+ blockedReason:
193
+ "blocked (call activity + multi-end): the published @nanobpm/workflow " +
194
+ "builder emits neither a `callActivity` (this cell delegates escalation to " +
195
+ "`human-escalation` via `zeebe:calledElement`) nor multiple top-level ends " +
196
+ "(implement-cell: 1 start, 1 end but a call-activity body); a shared ADR 0006 " +
197
+ "S4 fine-grained cell composed into feature/plan-fanout by callActivity.",
198
+ },
199
+ {
200
+ model: "converge-cell",
201
+ blockedReason:
202
+ "blocked (shared S4 cell): a hand-authored ADR 0006 S4 fine-grained cell " +
203
+ "(converge handoff) composed into feature by callActivity; not yet ported to " +
204
+ "a @nanobpm/workflow `defineFlow`.",
205
+ },
206
+ {
207
+ model: "merge-cell",
208
+ blockedReason: `${MULTI_START_END_BLOCK} (merge-cell: 1 start, 2 ends)`,
209
+ },
210
+ {
211
+ model: "wait-gate",
212
+ blockedReason: `${MULTI_START_END_BLOCK} (wait-gate: 1 start, 2 ends)`,
213
+ },
214
+ {
215
+ model: "human-escalation",
216
+ blockedReason: `${MULTI_START_END_BLOCK} (human-escalation: 1 start, 3 ends)`,
217
+ },
190
218
  ];