@nanobpm/nano-workforce 0.26.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.
Files changed (115) hide show
  1. package/.github/workflows/ci.yml +60 -0
  2. package/.github/workflows/release.yml +58 -0
  3. package/.releaserc.json +17 -0
  4. package/AGENTS.md +168 -0
  5. package/CHANGELOG.md +231 -0
  6. package/LICENSE +202 -0
  7. package/README.md +303 -0
  8. package/SPEC.md +492 -0
  9. package/actions/abandon.test.ts +93 -0
  10. package/actions/abandon.ts +23 -0
  11. package/actions/blackboard.test.ts +195 -0
  12. package/actions/blackboard.ts +76 -0
  13. package/actions/cancel.ts +29 -0
  14. package/actions/feature-answer-hook.ts +44 -0
  15. package/actions/message.ts +49 -0
  16. package/actions/plan-hook.ts +19 -0
  17. package/actions/plan-start.ts +17 -0
  18. package/actions/start.ts +19 -0
  19. package/actions/status.ts +22 -0
  20. package/actions/webhook-submit.ts +21 -0
  21. package/app/abandon.test.ts +97 -0
  22. package/app/abandon.ts +105 -0
  23. package/app/baseGuard.test.ts +35 -0
  24. package/app/baseGuard.ts +62 -0
  25. package/app/blackboard.test.ts +295 -0
  26. package/app/blackboard.ts +301 -0
  27. package/app/github.test.ts +59 -0
  28. package/app/github.ts +647 -0
  29. package/app/mergeExclusion.test.ts +168 -0
  30. package/app/mergeExclusion.ts +211 -0
  31. package/app/mergeProtocol.test.ts +124 -0
  32. package/app/mergeProtocol.ts +193 -0
  33. package/app/mergeRebaseArm.test.ts +72 -0
  34. package/app/mergeTrain.test.ts +91 -0
  35. package/app/mergeTrain.ts +117 -0
  36. package/app/persist-escalation.test.ts +119 -0
  37. package/app/persist-round.test.ts +65 -0
  38. package/app/plan.test.ts +317 -0
  39. package/app/plan.ts +321 -0
  40. package/app/record-plan-review.test.ts +38 -0
  41. package/app/reviewWait.test.ts +70 -0
  42. package/app/reviewWait.ts +59 -0
  43. package/app/rounds.test.ts +74 -0
  44. package/app/rounds.ts +48 -0
  45. package/app/service.test.ts +101 -0
  46. package/app/service.ts +895 -0
  47. package/app/taskDelta.test.ts +144 -0
  48. package/app/taskDelta.ts +175 -0
  49. package/app/trialMerge.test.ts +15 -0
  50. package/app/trialMerge.ts +102 -0
  51. package/app/waves.test.ts +128 -0
  52. package/app/waves.ts +116 -0
  53. package/assets/icon.svg +13 -0
  54. package/components/review-round.json +69 -0
  55. package/db/migrations/001_init.sql +46 -0
  56. package/db/migrations/002_transcript.sql +7 -0
  57. package/db/migrations/003_open_escalation.sql +8 -0
  58. package/db/migrations/004_merge.sql +36 -0
  59. package/db/migrations/004_planning.sql +37 -0
  60. package/db/migrations/005_job_activation.sql +15 -0
  61. package/db/migrations/005_plan_deps.sql +20 -0
  62. package/db/migrations/006_plan_review.sql +22 -0
  63. package/db/migrations/006_task_escalation.sql +52 -0
  64. package/db/migrations/007_plan_review_job_key.sql +14 -0
  65. package/db/migrations/007_wave_gate.sql +16 -0
  66. package/db/migrations/008_review_nudge.sql +9 -0
  67. package/db/migrations/009_plan_blackboard.sql +46 -0
  68. package/db/migrations/010_plan_task_deltas.sql +27 -0
  69. package/db/migrations/011_plan_merge_exclusions.sql +26 -0
  70. package/db/migrations/012_merge_protocol_attempt.sql +4 -0
  71. package/db/migrations/013_merge_train_waiting_lane.sql +6 -0
  72. package/db/migrations/014_plan_trial_merges.sql +21 -0
  73. package/db/migrations/015_pr_abandon_token.sql +9 -0
  74. package/deno.json +24 -0
  75. package/deno.lock +1776 -0
  76. package/main.ts +71 -0
  77. package/nano-ide.ext.json +7 -0
  78. package/nano.app.json +138 -0
  79. package/nanobpm.project.json +20 -0
  80. package/package.json +56 -0
  81. package/pages/epic.page.json +195 -0
  82. package/pages/home.page.json +296 -0
  83. package/prompts/feature.md +132 -0
  84. package/prompts/fix-ci.md +65 -0
  85. package/prompts/plan-review.md +69 -0
  86. package/prompts/plan.md +183 -0
  87. package/prompts/rebase.md +82 -0
  88. package/prompts/review-round.md +171 -0
  89. package/prompts/trial-merge.md +43 -0
  90. package/renovate.json +21 -0
  91. package/resources/processes/convergence-loop.bpmn +399 -0
  92. package/resources/processes/merge-loop.bpmn +585 -0
  93. package/resources/processes/plan-fanout.bpmn +546 -0
  94. package/scripts/check-agent-prompts.test.ts +84 -0
  95. package/scripts/check-agent-prompts.ts +143 -0
  96. package/scripts/layout-bpmn.ts +99 -0
  97. package/scripts/purge-db.ts +57 -0
  98. package/scripts/upgrade-from-pack.ts +334 -0
  99. package/tsconfig.json +51 -0
  100. package/workers/arm-merge/worker.ts +18 -0
  101. package/workers/finalize/worker.ts +89 -0
  102. package/workers/mark-merged/worker.ts +21 -0
  103. package/workers/merge/worker.ts +119 -0
  104. package/workers/persist-escalation/worker.ts +107 -0
  105. package/workers/persist-round/worker.ts +52 -0
  106. package/workers/persist-task-escalation/worker.ts +112 -0
  107. package/workers/record-plan/worker.ts +135 -0
  108. package/workers/record-plan-review/worker.ts +92 -0
  109. package/workers/record-results/worker.ts +30 -0
  110. package/workers/record-trial-merge/worker.test.ts +104 -0
  111. package/workers/record-trial-merge/worker.ts +88 -0
  112. package/workers/record-wave/worker.test.ts +221 -0
  113. package/workers/record-wave/worker.ts +308 -0
  114. package/workers/select-wave/worker.test.ts +130 -0
  115. package/workers/select-wave/worker.ts +84 -0
@@ -0,0 +1,399 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" 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:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:nano="https://nanobpm.io/schema/shapes/1.0" id="Definitions_nano_workforce" targetNamespace="http://nanobpm.io/nano-workforce">
3
+ <bpmn:message id="Message_reviewReady" name="review-ready">
4
+ <bpmn:extensionElements>
5
+ <zeebe:subscription correlationKey="=prKey" />
6
+ <zeebe:properties>
7
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="ReviewReady" />
8
+ </zeebe:properties>
9
+ </bpmn:extensionElements>
10
+ </bpmn:message>
11
+ <bpmn:message id="Message_escalationAnswered" name="escalation-answered">
12
+ <bpmn:extensionElements>
13
+ <zeebe:subscription correlationKey="=prKey" />
14
+ <zeebe:properties>
15
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="EscalationAnswered" />
16
+ </zeebe:properties>
17
+ </bpmn:extensionElements>
18
+ </bpmn:message>
19
+ <bpmn:process id="convergence-loop" name="PR Review Convergence" isExecutable="true">
20
+ <bpmn:extensionElements>
21
+ <nano:shapes>
22
+ <nano:shape id="PrReviewRoundIn" name="PR review round — input">
23
+ <nano:extend name="prUrl" type="string" />
24
+ <nano:extend name="repo" type="string" />
25
+ <nano:extend name="prNumber" type="integer" />
26
+ <nano:extend name="round" type="integer" />
27
+ <nano:extend name="answer" type="string" optional="true" />
28
+ </nano:shape>
29
+ <nano:shape id="PrReviewRoundOut" name="PR review round — result">
30
+ <nano:extend name="status" type="string" />
31
+ <nano:extend name="summary" type="string" />
32
+ <nano:extend name="question" type="string" optional="true" />
33
+ </nano:shape>
34
+ <nano:shape id="PrPersistRoundIn" name="Record round — input">
35
+ <nano:extend name="prKey" type="string" />
36
+ <nano:extend name="round" type="integer" />
37
+ <nano:extend name="status" type="string" optional="true" />
38
+ <nano:extend name="summary" type="string" optional="true" />
39
+ </nano:shape>
40
+ <nano:shape id="PrPersistEscalationIn" name="Record escalation — input">
41
+ <nano:extend name="prKey" type="string" />
42
+ <nano:extend name="round" type="integer" />
43
+ <nano:extend name="status" type="string" optional="true" />
44
+ <nano:extend name="summary" type="string" optional="true" />
45
+ <nano:extend name="question" type="string" optional="true" />
46
+ <nano:extend name="recordRound" type="boolean" optional="true" />
47
+ </nano:shape>
48
+ <nano:shape id="PrPersistEscalationOut" name="Record escalation — result">
49
+ <nano:extend name="escalationId" type="integer" />
50
+ </nano:shape>
51
+ <nano:shape id="PrFinalizeIn" name="Mark converged — input">
52
+ <nano:extend name="prKey" type="string" />
53
+ <nano:extend name="repo" type="string" />
54
+ <nano:extend name="prNumber" type="integer" />
55
+ <nano:extend name="prUrl" type="string" />
56
+ <nano:extend name="round" type="integer" />
57
+ <nano:extend name="summary" type="string" optional="true" />
58
+ </nano:shape>
59
+ <nano:shape id="ReviewReady" name="review-ready message payload">
60
+ <nano:extend name="reviewId" type="integer" />
61
+ <nano:extend name="reviewState" type="string" />
62
+ <nano:extend name="submittedAt" type="datetime" optional="true" />
63
+ </nano:shape>
64
+ <nano:shape id="EscalationAnswered" name="escalation-answered message payload">
65
+ <nano:extend name="answer" type="string" />
66
+ <nano:extend name="escalationId" type="integer" />
67
+ </nano:shape>
68
+ </nano:shapes>
69
+ </bpmn:extensionElements>
70
+ <bpmn:startEvent id="Start" name="PR submitted">
71
+ <bpmn:outgoing>f_start</bpmn:outgoing>
72
+ </bpmn:startEvent>
73
+ <bpmn:serviceTask id="review-round" name="Review round (agent)">
74
+ <bpmn:extensionElements>
75
+ <zeebe:taskDefinition type="senior:pr-review" />
76
+ <zeebe:taskHeaders>
77
+ <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{review-round}}" />
78
+ </zeebe:taskHeaders>
79
+ <zeebe:properties>
80
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="PrReviewRoundIn" />
81
+ <zeebe:property name="io.nanobpm.dataEnvelope.out" value="PrReviewRoundOut" />
82
+ </zeebe:properties>
83
+ <zeebe:ioMapping>
84
+ <zeebe:input source="=(if (abandonBrief = null) then &#34;&#34; else abandonBrief)" target="appendPrompt" />
85
+ <zeebe:output source="=null" target="answer" />
86
+ </zeebe:ioMapping>
87
+ </bpmn:extensionElements>
88
+ <bpmn:incoming>f_start</bpmn:incoming>
89
+ <bpmn:incoming>f_reviewLoop</bpmn:incoming>
90
+ <bpmn:incoming>f_answerLoop</bpmn:incoming>
91
+ <bpmn:outgoing>f_toStatus</bpmn:outgoing>
92
+ </bpmn:serviceTask>
93
+ <bpmn:exclusiveGateway id="gw-status" name="status?" default="f_escalate">
94
+ <bpmn:incoming>f_toStatus</bpmn:incoming>
95
+ <bpmn:outgoing>f_converged</bpmn:outgoing>
96
+ <bpmn:outgoing>f_addressed</bpmn:outgoing>
97
+ <bpmn:outgoing>f_waiting</bpmn:outgoing>
98
+ <bpmn:outgoing>f_escalate</bpmn:outgoing>
99
+ </bpmn:exclusiveGateway>
100
+ <bpmn:exclusiveGateway id="gw-guard" name="rounds left?" default="f_guardOk">
101
+ <bpmn:incoming>f_addressed</bpmn:incoming>
102
+ <bpmn:incoming>f_waiting</bpmn:incoming>
103
+ <bpmn:outgoing>f_guardMax</bpmn:outgoing>
104
+ <bpmn:outgoing>f_guardOk</bpmn:outgoing>
105
+ </bpmn:exclusiveGateway>
106
+ <bpmn:serviceTask id="persist-round" name="Record round">
107
+ <bpmn:extensionElements>
108
+ <zeebe:taskDefinition type="pr.persist-round" />
109
+ <zeebe:properties>
110
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="PrPersistRoundIn" />
111
+ </zeebe:properties>
112
+ </bpmn:extensionElements>
113
+ <bpmn:incoming>f_guardOk</bpmn:incoming>
114
+ <bpmn:outgoing>f_roundWait</bpmn:outgoing>
115
+ </bpmn:serviceTask>
116
+ <bpmn:eventBasedGateway id="gw-review-wait" name="review ready or timeout?">
117
+ <bpmn:incoming>f_roundWait</bpmn:incoming>
118
+ <bpmn:outgoing>f_toReviewWait</bpmn:outgoing>
119
+ <bpmn:outgoing>f_toReviewTimeout</bpmn:outgoing>
120
+ </bpmn:eventBasedGateway>
121
+ <bpmn:intermediateCatchEvent id="wait-review" name="Wait: review ready">
122
+ <bpmn:extensionElements>
123
+ <zeebe:ioMapping>
124
+ <zeebe:output source="=round + 1" target="round" />
125
+ </zeebe:ioMapping>
126
+ </bpmn:extensionElements>
127
+ <bpmn:incoming>f_toReviewWait</bpmn:incoming>
128
+ <bpmn:outgoing>f_reviewLoop</bpmn:outgoing>
129
+ <bpmn:messageEventDefinition id="med_reviewReady" messageRef="Message_reviewReady" />
130
+ </bpmn:intermediateCatchEvent>
131
+ <bpmn:intermediateCatchEvent id="wait-review-timeout" name="Wait: review timeout">
132
+ <bpmn:incoming>f_toReviewTimeout</bpmn:incoming>
133
+ <bpmn:outgoing>f_reviewStalled</bpmn:outgoing>
134
+ <bpmn:timerEventDefinition id="ted_reviewTimeout">
135
+ <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">=reviewWaitTimeout</bpmn:timeDuration>
136
+ </bpmn:timerEventDefinition>
137
+ </bpmn:intermediateCatchEvent>
138
+ <bpmn:serviceTask id="persist-review-stalled" name="Escalate: review stalled">
139
+ <bpmn:extensionElements>
140
+ <zeebe:taskDefinition type="pr.persist-escalation" />
141
+ <zeebe:properties>
142
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="PrPersistEscalationIn" />
143
+ <zeebe:property name="io.nanobpm.dataEnvelope.out" value="PrPersistEscalationOut" />
144
+ </zeebe:properties>
145
+ <zeebe:ioMapping>
146
+ <zeebe:input source="=&#34;blocked&#34;" target="status" />
147
+ <zeebe:input source="=false" target="recordRound" />
148
+ <zeebe:input source="=&#34;No review arrived within the review-wait timeout (&#34; + reviewWaitTimeout + &#34;). A human must decide how to proceed (reply to resume the loop).&#34;" target="question" />
149
+ </zeebe:ioMapping>
150
+ </bpmn:extensionElements>
151
+ <bpmn:incoming>f_reviewStalled</bpmn:incoming>
152
+ <bpmn:outgoing>f_stalledWait</bpmn:outgoing>
153
+ </bpmn:serviceTask>
154
+ <bpmn:serviceTask id="persist-escalation" name="Record escalation">
155
+ <bpmn:extensionElements>
156
+ <zeebe:taskDefinition type="pr.persist-escalation" />
157
+ <zeebe:properties>
158
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="PrPersistEscalationIn" />
159
+ <zeebe:property name="io.nanobpm.dataEnvelope.out" value="PrPersistEscalationOut" />
160
+ </zeebe:properties>
161
+ </bpmn:extensionElements>
162
+ <bpmn:incoming>f_escalate</bpmn:incoming>
163
+ <bpmn:outgoing>f_escWait</bpmn:outgoing>
164
+ </bpmn:serviceTask>
165
+ <bpmn:serviceTask id="persist-escalation-maxrounds" name="Escalate: max rounds">
166
+ <bpmn:extensionElements>
167
+ <zeebe:taskDefinition type="pr.persist-escalation" />
168
+ <zeebe:properties>
169
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="PrPersistEscalationIn" />
170
+ <zeebe:property name="io.nanobpm.dataEnvelope.out" value="PrPersistEscalationOut" />
171
+ </zeebe:properties>
172
+ <zeebe:ioMapping>
173
+ <zeebe:input source="=&#34;blocked&#34;" target="status" />
174
+ <zeebe:input source="=&#34;Not converged after &#34; + string(maxRounds) + &#34; rounds. A human must decide how to proceed.&#34;" target="question" />
175
+ </zeebe:ioMapping>
176
+ </bpmn:extensionElements>
177
+ <bpmn:incoming>f_guardMax</bpmn:incoming>
178
+ <bpmn:outgoing>f_maxWait</bpmn:outgoing>
179
+ </bpmn:serviceTask>
180
+ <bpmn:intermediateCatchEvent id="wait-answer" name="Wait: escalation answered">
181
+ <bpmn:incoming>f_escWait</bpmn:incoming>
182
+ <bpmn:incoming>f_maxWait</bpmn:incoming>
183
+ <bpmn:incoming>f_stalledWait</bpmn:incoming>
184
+ <bpmn:outgoing>f_answerLoop</bpmn:outgoing>
185
+ <bpmn:messageEventDefinition id="med_escalationAnswered" messageRef="Message_escalationAnswered" />
186
+ </bpmn:intermediateCatchEvent>
187
+ <bpmn:serviceTask id="persist-converged" name="Mark converged">
188
+ <bpmn:extensionElements>
189
+ <zeebe:taskDefinition type="pr.finalize" />
190
+ <zeebe:properties>
191
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="PrFinalizeIn" />
192
+ </zeebe:properties>
193
+ </bpmn:extensionElements>
194
+ <bpmn:incoming>f_converged</bpmn:incoming>
195
+ <bpmn:outgoing>f_finalize</bpmn:outgoing>
196
+ </bpmn:serviceTask>
197
+ <bpmn:endEvent id="End" name="Converged">
198
+ <bpmn:incoming>f_finalize</bpmn:incoming>
199
+ </bpmn:endEvent>
200
+ <bpmn:sequenceFlow id="f_start" sourceRef="Start" targetRef="review-round" />
201
+ <bpmn:sequenceFlow id="f_toStatus" sourceRef="review-round" targetRef="gw-status" />
202
+ <bpmn:sequenceFlow id="f_converged" name="converged" sourceRef="gw-status" targetRef="persist-converged">
203
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=status = "converged"</bpmn:conditionExpression>
204
+ </bpmn:sequenceFlow>
205
+ <bpmn:sequenceFlow id="f_addressed" name="addressed" sourceRef="gw-status" targetRef="gw-guard">
206
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=status = "addressed"</bpmn:conditionExpression>
207
+ </bpmn:sequenceFlow>
208
+ <bpmn:sequenceFlow id="f_waiting" name="waiting" sourceRef="gw-status" targetRef="gw-guard">
209
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=status = "waiting"</bpmn:conditionExpression>
210
+ </bpmn:sequenceFlow>
211
+ <bpmn:sequenceFlow id="f_escalate" name="needs_input / blocked" sourceRef="gw-status" targetRef="persist-escalation" />
212
+ <bpmn:sequenceFlow id="f_guardMax" name="max rounds" sourceRef="gw-guard" targetRef="persist-escalation-maxrounds">
213
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=round &gt;= maxRounds</bpmn:conditionExpression>
214
+ </bpmn:sequenceFlow>
215
+ <bpmn:sequenceFlow id="f_guardOk" name="continue" sourceRef="gw-guard" targetRef="persist-round" />
216
+ <bpmn:sequenceFlow id="f_roundWait" sourceRef="persist-round" targetRef="gw-review-wait" />
217
+ <bpmn:sequenceFlow id="f_toReviewWait" sourceRef="gw-review-wait" targetRef="wait-review" />
218
+ <bpmn:sequenceFlow id="f_toReviewTimeout" sourceRef="gw-review-wait" targetRef="wait-review-timeout" />
219
+ <bpmn:sequenceFlow id="f_reviewLoop" sourceRef="wait-review" targetRef="review-round" />
220
+ <bpmn:sequenceFlow id="f_reviewStalled" sourceRef="wait-review-timeout" targetRef="persist-review-stalled" />
221
+ <bpmn:sequenceFlow id="f_stalledWait" sourceRef="persist-review-stalled" targetRef="wait-answer" />
222
+ <bpmn:sequenceFlow id="f_escWait" sourceRef="persist-escalation" targetRef="wait-answer" />
223
+ <bpmn:sequenceFlow id="f_maxWait" sourceRef="persist-escalation-maxrounds" targetRef="wait-answer" />
224
+ <bpmn:sequenceFlow id="f_answerLoop" sourceRef="wait-answer" targetRef="review-round" />
225
+ <bpmn:sequenceFlow id="f_finalize" sourceRef="persist-converged" targetRef="End" />
226
+ </bpmn:process>
227
+ <bpmndi:BPMNDiagram id="BPMNDiagram_convergence-loop">
228
+ <bpmndi:BPMNPlane id="BPMNPlane_convergence-loop" bpmnElement="convergence-loop">
229
+ <bpmndi:BPMNShape id="BPMNShape_Start" bpmnElement="Start">
230
+ <dc:Bounds x="80" y="102" width="36" height="36" />
231
+ <bpmndi:BPMNLabel>
232
+ <dc:Bounds x="63" y="143" width="70" height="28" />
233
+ </bpmndi:BPMNLabel>
234
+ </bpmndi:BPMNShape>
235
+ <bpmndi:BPMNShape id="BPMNShape_review-round" bpmnElement="review-round">
236
+ <dc:Bounds x="216" y="80" width="100" height="80" />
237
+ </bpmndi:BPMNShape>
238
+ <bpmndi:BPMNShape id="BPMNShape_gw-status" bpmnElement="gw-status" isMarkerVisible="true">
239
+ <dc:Bounds x="416" y="95" width="50" height="50" />
240
+ <bpmndi:BPMNLabel>
241
+ <dc:Bounds x="415" y="76" width="53" height="14" />
242
+ </bpmndi:BPMNLabel>
243
+ </bpmndi:BPMNShape>
244
+ <bpmndi:BPMNShape id="BPMNShape_gw-guard" bpmnElement="gw-guard" isMarkerVisible="true">
245
+ <dc:Bounds x="591" y="255" width="50" height="50" />
246
+ <bpmndi:BPMNLabel>
247
+ <dc:Bounds x="574" y="310" width="85" height="14" />
248
+ </bpmndi:BPMNLabel>
249
+ </bpmndi:BPMNShape>
250
+ <bpmndi:BPMNShape id="BPMNShape_persist-round" bpmnElement="persist-round">
251
+ <dc:Bounds x="766" y="240" width="100" height="80" />
252
+ </bpmndi:BPMNShape>
253
+ <bpmndi:BPMNShape id="BPMNShape_gw-review-wait" bpmnElement="gw-review-wait" isMarkerVisible="true">
254
+ <dc:Bounds x="966" y="255" width="50" height="50" />
255
+ <bpmndi:BPMNLabel>
256
+ <dc:Bounds x="947" y="222" width="88" height="28" />
257
+ </bpmndi:BPMNLabel>
258
+ </bpmndi:BPMNShape>
259
+ <bpmndi:BPMNShape id="BPMNShape_wait-review" bpmnElement="wait-review">
260
+ <dc:Bounds x="1116" y="262" width="36" height="36" />
261
+ <bpmndi:BPMNLabel>
262
+ <dc:Bounds x="1090" y="229" width="88" height="28" />
263
+ </bpmndi:BPMNLabel>
264
+ </bpmndi:BPMNShape>
265
+ <bpmndi:BPMNShape id="BPMNShape_wait-review-timeout" bpmnElement="wait-review-timeout">
266
+ <dc:Bounds x="1116" y="422" width="36" height="36" />
267
+ <bpmndi:BPMNLabel>
268
+ <dc:Bounds x="1106" y="375" width="56" height="42" />
269
+ </bpmndi:BPMNLabel>
270
+ </bpmndi:BPMNShape>
271
+ <bpmndi:BPMNShape id="BPMNShape_persist-review-stalled" bpmnElement="persist-review-stalled">
272
+ <dc:Bounds x="1252" y="400" width="100" height="80" />
273
+ </bpmndi:BPMNShape>
274
+ <bpmndi:BPMNShape id="BPMNShape_persist-escalation" bpmnElement="persist-escalation">
275
+ <dc:Bounds x="566" y="720" width="100" height="80" />
276
+ </bpmndi:BPMNShape>
277
+ <bpmndi:BPMNShape id="BPMNShape_persist-escalation-maxrounds" bpmnElement="persist-escalation-maxrounds">
278
+ <dc:Bounds x="766" y="560" width="100" height="80" />
279
+ </bpmndi:BPMNShape>
280
+ <bpmndi:BPMNShape id="BPMNShape_wait-answer" bpmnElement="wait-answer">
281
+ <dc:Bounds x="1452" y="422" width="36" height="36" />
282
+ <bpmndi:BPMNLabel>
283
+ <dc:Bounds x="1433" y="375" width="74" height="42" />
284
+ </bpmndi:BPMNLabel>
285
+ </bpmndi:BPMNShape>
286
+ <bpmndi:BPMNShape id="BPMNShape_persist-converged" bpmnElement="persist-converged">
287
+ <dc:Bounds x="566" y="80" width="100" height="80" />
288
+ </bpmndi:BPMNShape>
289
+ <bpmndi:BPMNShape id="BPMNShape_End" bpmnElement="End">
290
+ <dc:Bounds x="798" y="102" width="36" height="36" />
291
+ <bpmndi:BPMNLabel>
292
+ <dc:Bounds x="782" y="143" width="69" height="14" />
293
+ </bpmndi:BPMNLabel>
294
+ </bpmndi:BPMNShape>
295
+ <bpmndi:BPMNEdge id="BPMNEdge_f_start" bpmnElement="f_start">
296
+ <di:waypoint x="116" y="120" />
297
+ <di:waypoint x="216" y="120" />
298
+ </bpmndi:BPMNEdge>
299
+ <bpmndi:BPMNEdge id="BPMNEdge_f_toStatus" bpmnElement="f_toStatus">
300
+ <di:waypoint x="316" y="120" />
301
+ <di:waypoint x="416" y="120" />
302
+ </bpmndi:BPMNEdge>
303
+ <bpmndi:BPMNEdge id="BPMNEdge_f_converged" bpmnElement="f_converged">
304
+ <di:waypoint x="466" y="120" />
305
+ <di:waypoint x="566" y="120" />
306
+ <bpmndi:BPMNLabel>
307
+ <dc:Bounds x="483" y="98" width="67" height="14" />
308
+ </bpmndi:BPMNLabel>
309
+ </bpmndi:BPMNEdge>
310
+ <bpmndi:BPMNEdge id="BPMNEdge_f_finalize" bpmnElement="f_finalize">
311
+ <di:waypoint x="666" y="120" />
312
+ <di:waypoint x="798" y="120" />
313
+ </bpmndi:BPMNEdge>
314
+ <bpmndi:BPMNEdge id="BPMNEdge_f_guardOk" bpmnElement="f_guardOk">
315
+ <di:waypoint x="641" y="280" />
316
+ <di:waypoint x="766" y="280" />
317
+ <bpmndi:BPMNLabel>
318
+ <dc:Bounds x="664" y="258" width="60" height="14" />
319
+ </bpmndi:BPMNLabel>
320
+ </bpmndi:BPMNEdge>
321
+ <bpmndi:BPMNEdge id="BPMNEdge_f_roundWait" bpmnElement="f_roundWait">
322
+ <di:waypoint x="866" y="280" />
323
+ <di:waypoint x="966" y="280" />
324
+ </bpmndi:BPMNEdge>
325
+ <bpmndi:BPMNEdge id="BPMNEdge_f_toReviewWait" bpmnElement="f_toReviewWait">
326
+ <di:waypoint x="1016" y="280" />
327
+ <di:waypoint x="1116" y="280" />
328
+ </bpmndi:BPMNEdge>
329
+ <bpmndi:BPMNEdge id="BPMNEdge_f_reviewLoop" bpmnElement="f_reviewLoop">
330
+ <di:waypoint x="1134" y="298" />
331
+ <di:waypoint x="1134" y="340" />
332
+ <di:waypoint x="266" y="340" />
333
+ <di:waypoint x="266" y="160" />
334
+ </bpmndi:BPMNEdge>
335
+ <bpmndi:BPMNEdge id="BPMNEdge_f_addressed" bpmnElement="f_addressed">
336
+ <di:waypoint x="441" y="145" />
337
+ <di:waypoint x="441" y="280" />
338
+ <di:waypoint x="591" y="280" />
339
+ <bpmndi:BPMNLabel>
340
+ <dc:Bounds x="446" y="206" width="67" height="14" />
341
+ </bpmndi:BPMNLabel>
342
+ </bpmndi:BPMNEdge>
343
+ <bpmndi:BPMNEdge id="BPMNEdge_f_waiting" bpmnElement="f_waiting">
344
+ <di:waypoint x="441" y="145" />
345
+ <di:waypoint x="441" y="280" />
346
+ <di:waypoint x="591" y="280" />
347
+ <bpmndi:BPMNLabel>
348
+ <dc:Bounds x="380" y="206" width="56" height="14" />
349
+ </bpmndi:BPMNLabel>
350
+ </bpmndi:BPMNEdge>
351
+ <bpmndi:BPMNEdge id="BPMNEdge_f_escalate" bpmnElement="f_escalate">
352
+ <di:waypoint x="441" y="145" />
353
+ <di:waypoint x="441" y="760" />
354
+ <di:waypoint x="566" y="760" />
355
+ <bpmndi:BPMNLabel>
356
+ <dc:Bounds x="446" y="506" width="81" height="28" />
357
+ </bpmndi:BPMNLabel>
358
+ </bpmndi:BPMNEdge>
359
+ <bpmndi:BPMNEdge id="BPMNEdge_f_guardMax" bpmnElement="f_guardMax">
360
+ <di:waypoint x="641" y="280" />
361
+ <di:waypoint x="746" y="280" />
362
+ <di:waypoint x="746" y="600" />
363
+ <di:waypoint x="766" y="600" />
364
+ <bpmndi:BPMNLabel>
365
+ <dc:Bounds x="751" y="433" width="74" height="14" />
366
+ </bpmndi:BPMNLabel>
367
+ </bpmndi:BPMNEdge>
368
+ <bpmndi:BPMNEdge id="BPMNEdge_f_toReviewTimeout" bpmnElement="f_toReviewTimeout">
369
+ <di:waypoint x="991" y="305" />
370
+ <di:waypoint x="991" y="440" />
371
+ <di:waypoint x="1116" y="440" />
372
+ </bpmndi:BPMNEdge>
373
+ <bpmndi:BPMNEdge id="BPMNEdge_f_reviewStalled" bpmnElement="f_reviewStalled">
374
+ <di:waypoint x="1152" y="440" />
375
+ <di:waypoint x="1252" y="440" />
376
+ </bpmndi:BPMNEdge>
377
+ <bpmndi:BPMNEdge id="BPMNEdge_f_stalledWait" bpmnElement="f_stalledWait">
378
+ <di:waypoint x="1352" y="440" />
379
+ <di:waypoint x="1452" y="440" />
380
+ </bpmndi:BPMNEdge>
381
+ <bpmndi:BPMNEdge id="BPMNEdge_f_escWait" bpmnElement="f_escWait">
382
+ <di:waypoint x="666" y="760" />
383
+ <di:waypoint x="1470" y="760" />
384
+ <di:waypoint x="1470" y="458" />
385
+ </bpmndi:BPMNEdge>
386
+ <bpmndi:BPMNEdge id="BPMNEdge_f_maxWait" bpmnElement="f_maxWait">
387
+ <di:waypoint x="866" y="600" />
388
+ <di:waypoint x="1470" y="600" />
389
+ <di:waypoint x="1470" y="458" />
390
+ </bpmndi:BPMNEdge>
391
+ <bpmndi:BPMNEdge id="BPMNEdge_f_answerLoop" bpmnElement="f_answerLoop">
392
+ <di:waypoint x="1470" y="458" />
393
+ <di:waypoint x="1470" y="500" />
394
+ <di:waypoint x="266" y="500" />
395
+ <di:waypoint x="266" y="160" />
396
+ </bpmndi:BPMNEdge>
397
+ </bpmndi:BPMNPlane>
398
+ </bpmndi:BPMNDiagram>
399
+ </bpmn:definitions>