@nanobpm/nano-workforce 0.56.0 → 0.58.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 (90) hide show
  1. package/.github/workflows/ci.yml +7 -0
  2. package/AGENTS.md +83 -1
  3. package/CHANGELOG.md +14 -0
  4. package/README.md +10 -2
  5. package/SPEC.md +27 -24
  6. package/app/agentCompletion.test.ts +337 -0
  7. package/app/agentCompletion.ts +219 -0
  8. package/app/agentGuide.ts +1 -1
  9. package/app/answer-escalation.test.ts +106 -0
  10. package/app/answerEscalation.test.ts +67 -0
  11. package/app/baseGuard.test.ts +9 -1
  12. package/app/baseGuard.ts +11 -0
  13. package/app/escalationSla.test.ts +39 -0
  14. package/app/escalationSla.ts +28 -0
  15. package/app/escalationTaxonomy.test.ts +115 -0
  16. package/app/escalationTaxonomy.ts +115 -0
  17. package/app/feature.test.ts +161 -0
  18. package/app/feature.ts +173 -0
  19. package/app/github.test.ts +179 -1
  20. package/app/github.ts +132 -0
  21. package/app/mergeProtocol.test.ts +15 -0
  22. package/app/mergeProtocol.ts +10 -0
  23. package/app/persist-escalation.test.ts +34 -36
  24. package/app/plan.test.ts +267 -313
  25. package/app/plan.ts +173 -231
  26. package/app/reviewWait.ts +12 -4
  27. package/app/roundResultDefault.test.ts +111 -2
  28. package/app/roundResultDefault.ts +35 -0
  29. package/app/service.test.ts +6 -7
  30. package/app/service.ts +52 -35
  31. package/db/migrations/026_agent_completion.sql +36 -0
  32. package/db/migrations/027_retire_escalation_subsystem.sql +43 -0
  33. package/db/migrations/028_feature_runs.sql +28 -0
  34. package/e2e/agent-answerable.e2e.ts +185 -0
  35. package/e2e/convergence-escalation.e2e.ts +180 -0
  36. package/e2e/convergence-loop.e2e.ts +1 -1
  37. package/e2e/feature-run.e2e.ts +231 -0
  38. package/e2e/plan-fanout-sla.e2e.ts +238 -0
  39. package/e2e/plan-fanout.e2e.ts +303 -0
  40. package/e2e/retire-escalation-subsystem.e2e.ts +223 -0
  41. package/e2e/support/github-admit.ts +99 -0
  42. package/e2e/user-task-spine.e2e.ts +155 -0
  43. package/nano.app.json +41 -11
  44. package/openapi.yaml +237 -84
  45. package/operations/agentCompleteEscalation.ts +53 -0
  46. package/operations/listActivePrs.test.ts +39 -6
  47. package/operations/postMessage.ts +10 -41
  48. package/operations/revertEscalationCompletion.ts +44 -0
  49. package/operations/startAndMessage.test.ts +62 -60
  50. package/operations/startFeature.ts +127 -0
  51. package/operations/startPlanFanout.admission.integration.test.ts +263 -0
  52. package/operations/startPlanFanout.ts +70 -11
  53. package/package.json +4 -1
  54. package/pages/cockpit.page.json +1 -0
  55. package/pages/epic-detail.page.json +11 -37
  56. package/pages/epic.page.json +5 -2
  57. package/pages/feature.page.json +82 -0
  58. package/pages/home.page.json +6 -18
  59. package/resources/agent-guide.md +90 -26
  60. package/resources/forms/feature-escalation.form +27 -0
  61. package/resources/forms/plan-review-decision.form +27 -0
  62. package/resources/forms/pr-escalation.form +23 -0
  63. package/resources/forms/spine-demo.form +15 -0
  64. package/resources/forms/trial-merge-decision.form +25 -0
  65. package/resources/processes/convergence-loop.bpmn +127 -75
  66. package/resources/processes/feature.bpmn +240 -0
  67. package/resources/processes/plan-fanout.bpmn +322 -222
  68. package/resources/processes/spine-demo.bpmn +72 -0
  69. package/scripts/check-migrations.ts +68 -0
  70. package/workers/answer-escalation/worker.ts +78 -0
  71. package/workers/converge-feature/worker.ts +51 -0
  72. package/workers/ensure-base-branch/head-task.integration.test.ts +126 -0
  73. package/workers/ensure-base-branch/worker.test.ts +104 -0
  74. package/workers/ensure-base-branch/worker.ts +31 -0
  75. package/workers/finalize/worker.ts +0 -2
  76. package/workers/mark-merged/worker.ts +0 -2
  77. package/workers/merge/worker.ts +6 -5
  78. package/workers/persist-escalation/worker.ts +28 -32
  79. package/workers/record-feature/worker.ts +61 -0
  80. package/workers/record-plan-review/worker.test.ts +9 -10
  81. package/workers/record-plan-review/worker.ts +15 -5
  82. package/workers/resolve-trial-attention/worker.test.ts +77 -0
  83. package/workers/resolve-trial-attention/worker.ts +43 -0
  84. package/operations/answerFeatureEscalation.test.ts +0 -112
  85. package/operations/answerFeatureEscalation.ts +0 -58
  86. package/operations/answerPlanEscalation.test.ts +0 -115
  87. package/operations/answerPlanEscalation.ts +0 -41
  88. package/workers/persist-plan-escalation/worker.test.ts +0 -80
  89. package/workers/persist-plan-escalation/worker.ts +0 -73
  90. package/workers/persist-task-escalation/worker.ts +0 -120
@@ -0,0 +1,25 @@
1
+ {
2
+ "id": "trial-merge-decision",
3
+ "schemaVersion": 18,
4
+ "type": "default",
5
+ "components": [
6
+ {
7
+ "type": "select",
8
+ "key": "action",
9
+ "label": "Action",
10
+ "values": [
11
+ { "label": "Proceed — accept the red trial merge and continue", "value": "proceed" },
12
+ { "label": "Rebase — re-run the trial merge", "value": "rebase" },
13
+ { "label": "Abandon — stop and finalize the plan", "value": "abandon" }
14
+ ],
15
+ "validate": {
16
+ "required": true
17
+ }
18
+ },
19
+ {
20
+ "type": "textarea",
21
+ "key": "notes",
22
+ "label": "Notes"
23
+ }
24
+ ]
25
+ }
@@ -8,14 +8,6 @@
8
8
  </zeebe:properties>
9
9
  </bpmn:extensionElements>
10
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
11
  <bpmn:process id="convergence-loop" name="PR Review Convergence" isExecutable="true">
20
12
  <bpmn:extensionElements>
21
13
  <nano:shapes>
@@ -46,7 +38,13 @@
46
38
  <nano:extend name="recordRound" type="boolean" optional="true" />
47
39
  </nano:shape>
48
40
  <nano:shape id="PrPersistEscalationOut" name="Record escalation — result">
49
- <nano:extend name="escalationId" type="integer" />
41
+ <nano:extend name="escalationId" type="integer" optional="true" />
42
+ <nano:extend name="escalated" type="boolean" optional="true" />
43
+ <nano:extend name="question" type="string" optional="true" />
44
+ </nano:shape>
45
+ <nano:shape id="PrAnswerEscalationIn" name="Answer escalation — input">
46
+ <nano:extend name="prKey" type="string" />
47
+ <nano:extend name="answer" type="string" optional="true" />
50
48
  </nano:shape>
51
49
  <nano:shape id="PrFinalizeIn" name="Mark converged — input">
52
50
  <nano:extend name="prKey" type="string" />
@@ -61,10 +59,6 @@
61
59
  <nano:extend name="reviewState" type="string" />
62
60
  <nano:extend name="submittedAt" type="datetime" optional="true" />
63
61
  </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
62
  </nano:shapes>
69
63
  </bpmn:extensionElements>
70
64
  <bpmn:startEvent id="Start" name="PR submitted">
@@ -100,6 +94,7 @@
100
94
  <bpmn:exclusiveGateway id="gw-guard" name="rounds left?" default="f_guardOk">
101
95
  <bpmn:incoming>f_addressed</bpmn:incoming>
102
96
  <bpmn:incoming>f_waiting</bpmn:incoming>
97
+ <bpmn:incoming>f_escReenter</bpmn:incoming>
103
98
  <bpmn:outgoing>f_guardMax</bpmn:outgoing>
104
99
  <bpmn:outgoing>f_guardOk</bpmn:outgoing>
105
100
  </bpmn:exclusiveGateway>
@@ -160,8 +155,13 @@
160
155
  </zeebe:properties>
161
156
  </bpmn:extensionElements>
162
157
  <bpmn:incoming>f_escalate</bpmn:incoming>
163
- <bpmn:outgoing>f_escWait</bpmn:outgoing>
158
+ <bpmn:outgoing>f_escGate</bpmn:outgoing>
164
159
  </bpmn:serviceTask>
160
+ <bpmn:exclusiveGateway id="gw-escalated" name="escalation opened?" default="f_escReenter">
161
+ <bpmn:incoming>f_escGate</bpmn:incoming>
162
+ <bpmn:outgoing>f_escWait</bpmn:outgoing>
163
+ <bpmn:outgoing>f_escReenter</bpmn:outgoing>
164
+ </bpmn:exclusiveGateway>
165
165
  <bpmn:serviceTask id="persist-escalation-maxrounds" name="Escalate: max rounds">
166
166
  <bpmn:extensionElements>
167
167
  <zeebe:taskDefinition type="pr.persist-escalation" />
@@ -177,13 +177,34 @@
177
177
  <bpmn:incoming>f_guardMax</bpmn:incoming>
178
178
  <bpmn:outgoing>f_maxWait</bpmn:outgoing>
179
179
  </bpmn:serviceTask>
180
- <bpmn:intermediateCatchEvent id="wait-answer" name="Wait: escalation answered">
180
+ <bpmn:userTask id="wait-answer" name="Answer escalation">
181
+ <bpmn:extensionElements>
182
+ <zeebe:formDefinition formId="pr-escalation" />
183
+ <zeebe:userTask />
184
+ <zeebe:ioMapping>
185
+ <zeebe:input source="=question" target="question" />
186
+ <zeebe:input source="=prKey" target="prKey" />
187
+ </zeebe:ioMapping>
188
+ </bpmn:extensionElements>
181
189
  <bpmn:incoming>f_escWait</bpmn:incoming>
182
190
  <bpmn:incoming>f_maxWait</bpmn:incoming>
183
191
  <bpmn:incoming>f_stalledWait</bpmn:incoming>
192
+ <bpmn:outgoing>f_answerRecord</bpmn:outgoing>
193
+ </bpmn:userTask>
194
+ <bpmn:serviceTask id="record-answer" name="Record answer">
195
+ <bpmn:extensionElements>
196
+ <zeebe:taskDefinition type="pr.answer-escalation" />
197
+ <zeebe:properties>
198
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="PrAnswerEscalationIn" />
199
+ </zeebe:properties>
200
+ <zeebe:ioMapping>
201
+ <zeebe:input source="=prKey" target="prKey" />
202
+ <zeebe:input source="=answer" target="answer" />
203
+ </zeebe:ioMapping>
204
+ </bpmn:extensionElements>
205
+ <bpmn:incoming>f_answerRecord</bpmn:incoming>
184
206
  <bpmn:outgoing>f_answerLoop</bpmn:outgoing>
185
- <bpmn:messageEventDefinition id="med_escalationAnswered" messageRef="Message_escalationAnswered" />
186
- </bpmn:intermediateCatchEvent>
207
+ </bpmn:serviceTask>
187
208
  <bpmn:serviceTask id="persist-converged" name="Mark converged">
188
209
  <bpmn:extensionElements>
189
210
  <zeebe:taskDefinition type="pr.finalize" />
@@ -207,7 +228,7 @@
207
228
  <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=status = "waiting"</bpmn:conditionExpression>
208
229
  </bpmn:sequenceFlow>
209
230
  <bpmn:sequenceFlow id="f_escalate" name="needs_input / blocked" sourceRef="gw-status" targetRef="persist-escalation">
210
- <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=status = "needs_input" or status = "blocked"</bpmn:conditionExpression>
231
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=(status = "needs_input" or status = "blocked") and question != null and trim(question) != ""</bpmn:conditionExpression>
211
232
  </bpmn:sequenceFlow>
212
233
  <bpmn:sequenceFlow id="f_guardMax" name="max rounds" sourceRef="gw-guard" targetRef="persist-escalation-maxrounds">
213
234
  <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=round &gt;= maxRounds</bpmn:conditionExpression>
@@ -219,9 +240,14 @@
219
240
  <bpmn:sequenceFlow id="f_reviewLoop" sourceRef="wait-review" targetRef="review-round" />
220
241
  <bpmn:sequenceFlow id="f_reviewStalled" sourceRef="wait-review-timeout" targetRef="persist-review-stalled" />
221
242
  <bpmn:sequenceFlow id="f_stalledWait" sourceRef="persist-review-stalled" targetRef="wait-answer" />
222
- <bpmn:sequenceFlow id="f_escWait" sourceRef="persist-escalation" targetRef="wait-answer" />
243
+ <bpmn:sequenceFlow id="f_escGate" sourceRef="persist-escalation" targetRef="gw-escalated" />
244
+ <bpmn:sequenceFlow id="f_escWait" sourceRef="gw-escalated" targetRef="wait-answer">
245
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=escalated = true</bpmn:conditionExpression>
246
+ </bpmn:sequenceFlow>
247
+ <bpmn:sequenceFlow id="f_escReenter" name="no escalation opened" sourceRef="gw-escalated" targetRef="gw-guard" />
223
248
  <bpmn:sequenceFlow id="f_maxWait" sourceRef="persist-escalation-maxrounds" targetRef="wait-answer" />
224
- <bpmn:sequenceFlow id="f_answerLoop" sourceRef="wait-answer" targetRef="review-round" />
249
+ <bpmn:sequenceFlow id="f_answerRecord" sourceRef="wait-answer" targetRef="record-answer" />
250
+ <bpmn:sequenceFlow id="f_answerLoop" sourceRef="record-answer" targetRef="review-round" />
225
251
  <bpmn:sequenceFlow id="f_finalize" sourceRef="persist-converged" targetRef="End" />
226
252
  </bpmn:process>
227
253
  <bpmndi:BPMNDiagram id="BPMNDiagram_convergence-loop">
@@ -242,54 +268,60 @@
242
268
  </bpmndi:BPMNLabel>
243
269
  </bpmndi:BPMNShape>
244
270
  <bpmndi:BPMNShape id="BPMNShape_gw-guard" bpmnElement="gw-guard" isMarkerVisible="true">
245
- <dc:Bounds x="591" y="255" width="50" height="50" />
271
+ <dc:Bounds x="916" y="255" width="50" height="50" />
246
272
  <bpmndi:BPMNLabel>
247
- <dc:Bounds x="574" y="310" width="85" height="14" />
273
+ <dc:Bounds x="899" y="310" width="85" height="14" />
248
274
  </bpmndi:BPMNLabel>
249
275
  </bpmndi:BPMNShape>
250
276
  <bpmndi:BPMNShape id="BPMNShape_persist-round" bpmnElement="persist-round">
251
- <dc:Bounds x="766" y="240" width="100" height="80" />
277
+ <dc:Bounds x="1066" y="240" width="100" height="80" />
252
278
  </bpmndi:BPMNShape>
253
279
  <bpmndi:BPMNShape id="BPMNShape_gw-review-wait" bpmnElement="gw-review-wait" isMarkerVisible="true">
254
- <dc:Bounds x="966" y="255" width="50" height="50" />
280
+ <dc:Bounds x="1266" y="255" width="50" height="50" />
255
281
  <bpmndi:BPMNLabel>
256
- <dc:Bounds x="947" y="222" width="88" height="28" />
282
+ <dc:Bounds x="1247" y="222" width="88" height="28" />
257
283
  </bpmndi:BPMNLabel>
258
284
  </bpmndi:BPMNShape>
259
285
  <bpmndi:BPMNShape id="BPMNShape_wait-review" bpmnElement="wait-review">
260
- <dc:Bounds x="1116" y="262" width="36" height="36" />
286
+ <dc:Bounds x="1416" y="262" width="36" height="36" />
261
287
  <bpmndi:BPMNLabel>
262
- <dc:Bounds x="1090" y="229" width="88" height="28" />
288
+ <dc:Bounds x="1390" y="229" width="88" height="28" />
263
289
  </bpmndi:BPMNLabel>
264
290
  </bpmndi:BPMNShape>
265
291
  <bpmndi:BPMNShape id="BPMNShape_wait-review-timeout" bpmnElement="wait-review-timeout">
266
- <dc:Bounds x="1116" y="422" width="36" height="36" />
292
+ <dc:Bounds x="1416" y="422" width="36" height="36" />
267
293
  <bpmndi:BPMNLabel>
268
- <dc:Bounds x="1106" y="375" width="56" height="42" />
294
+ <dc:Bounds x="1406" y="463" width="56" height="42" />
269
295
  </bpmndi:BPMNLabel>
270
296
  </bpmndi:BPMNShape>
271
297
  <bpmndi:BPMNShape id="BPMNShape_persist-review-stalled" bpmnElement="persist-review-stalled">
272
- <dc:Bounds x="1252" y="400" width="100" height="80" />
298
+ <dc:Bounds x="1552" y="400" width="100" height="80" />
273
299
  </bpmndi:BPMNShape>
274
300
  <bpmndi:BPMNShape id="BPMNShape_persist-escalation" bpmnElement="persist-escalation">
275
- <dc:Bounds x="566" y="720" width="100" height="80" />
301
+ <dc:Bounds x="566" y="560" width="100" height="80" />
302
+ </bpmndi:BPMNShape>
303
+ <bpmndi:BPMNShape id="BPMNShape_gw-escalated" bpmnElement="gw-escalated" isMarkerVisible="true">
304
+ <dc:Bounds x="766" y="575" width="50" height="50" />
305
+ <bpmndi:BPMNLabel>
306
+ <dc:Bounds x="821" y="586" width="74" height="28" />
307
+ </bpmndi:BPMNLabel>
276
308
  </bpmndi:BPMNShape>
277
309
  <bpmndi:BPMNShape id="BPMNShape_persist-escalation-maxrounds" bpmnElement="persist-escalation-maxrounds">
278
- <dc:Bounds x="766" y="560" width="100" height="80" />
310
+ <dc:Bounds x="1066" y="560" width="100" height="80" />
279
311
  </bpmndi:BPMNShape>
280
312
  <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>
313
+ <dc:Bounds x="1752" y="400" width="100" height="80" />
314
+ </bpmndi:BPMNShape>
315
+ <bpmndi:BPMNShape id="BPMNShape_record-answer" bpmnElement="record-answer">
316
+ <dc:Bounds x="1952" y="400" width="100" height="80" />
285
317
  </bpmndi:BPMNShape>
286
318
  <bpmndi:BPMNShape id="BPMNShape_persist-converged" bpmnElement="persist-converged">
287
319
  <dc:Bounds x="566" y="80" width="100" height="80" />
288
320
  </bpmndi:BPMNShape>
289
321
  <bpmndi:BPMNShape id="BPMNShape_End" bpmnElement="End">
290
- <dc:Bounds x="798" y="102" width="36" height="36" />
322
+ <dc:Bounds x="773" y="102" width="36" height="36" />
291
323
  <bpmndi:BPMNLabel>
292
- <dc:Bounds x="782" y="143" width="69" height="14" />
324
+ <dc:Bounds x="757" y="143" width="69" height="14" />
293
325
  </bpmndi:BPMNLabel>
294
326
  </bpmndi:BPMNShape>
295
327
  <bpmndi:BPMNEdge id="BPMNEdge_f_start" bpmnElement="f_start">
@@ -309,33 +341,41 @@
309
341
  </bpmndi:BPMNEdge>
310
342
  <bpmndi:BPMNEdge id="BPMNEdge_f_finalize" bpmnElement="f_finalize">
311
343
  <di:waypoint x="666" y="120" />
312
- <di:waypoint x="798" y="120" />
344
+ <di:waypoint x="773" y="120" />
313
345
  </bpmndi:BPMNEdge>
314
346
  <bpmndi:BPMNEdge id="BPMNEdge_f_guardOk" bpmnElement="f_guardOk">
315
- <di:waypoint x="641" y="280" />
316
- <di:waypoint x="766" y="280" />
347
+ <di:waypoint x="966" y="280" />
348
+ <di:waypoint x="1066" y="280" />
317
349
  <bpmndi:BPMNLabel>
318
- <dc:Bounds x="664" y="258" width="60" height="14" />
350
+ <dc:Bounds x="976" y="258" width="60" height="14" />
319
351
  </bpmndi:BPMNLabel>
320
352
  </bpmndi:BPMNEdge>
321
353
  <bpmndi:BPMNEdge id="BPMNEdge_f_roundWait" bpmnElement="f_roundWait">
322
- <di:waypoint x="866" y="280" />
323
- <di:waypoint x="966" y="280" />
354
+ <di:waypoint x="1166" y="280" />
355
+ <di:waypoint x="1266" y="280" />
324
356
  </bpmndi:BPMNEdge>
325
357
  <bpmndi:BPMNEdge id="BPMNEdge_f_toReviewWait" bpmnElement="f_toReviewWait">
326
- <di:waypoint x="1016" y="280" />
327
- <di:waypoint x="1116" y="280" />
358
+ <di:waypoint x="1316" y="280" />
359
+ <di:waypoint x="1416" y="280" />
328
360
  </bpmndi:BPMNEdge>
329
361
  <bpmndi:BPMNEdge id="BPMNEdge_f_reviewLoop" bpmnElement="f_reviewLoop">
330
- <di:waypoint x="1134" y="298" />
331
- <di:waypoint x="1134" y="340" />
362
+ <di:waypoint x="1434" y="298" />
363
+ <di:waypoint x="1434" y="340" />
332
364
  <di:waypoint x="266" y="340" />
333
365
  <di:waypoint x="266" y="160" />
334
366
  </bpmndi:BPMNEdge>
367
+ <bpmndi:BPMNEdge id="BPMNEdge_f_escReenter" bpmnElement="f_escReenter">
368
+ <di:waypoint x="791" y="575" />
369
+ <di:waypoint x="791" y="280" />
370
+ <di:waypoint x="916" y="280" />
371
+ <bpmndi:BPMNLabel>
372
+ <dc:Bounds x="796" y="407" width="74" height="42" />
373
+ </bpmndi:BPMNLabel>
374
+ </bpmndi:BPMNEdge>
335
375
  <bpmndi:BPMNEdge id="BPMNEdge_f_addressed" bpmnElement="f_addressed">
336
376
  <di:waypoint x="441" y="145" />
337
377
  <di:waypoint x="441" y="280" />
338
- <di:waypoint x="591" y="280" />
378
+ <di:waypoint x="916" y="280" />
339
379
  <bpmndi:BPMNLabel>
340
380
  <dc:Bounds x="446" y="199" width="78" height="28" />
341
381
  </bpmndi:BPMNLabel>
@@ -343,55 +383,67 @@
343
383
  <bpmndi:BPMNEdge id="BPMNEdge_f_waiting" bpmnElement="f_waiting">
344
384
  <di:waypoint x="441" y="145" />
345
385
  <di:waypoint x="441" y="280" />
346
- <di:waypoint x="591" y="280" />
386
+ <di:waypoint x="916" y="280" />
347
387
  <bpmndi:BPMNLabel>
348
388
  <dc:Bounds x="380" y="206" width="56" height="14" />
349
389
  </bpmndi:BPMNLabel>
350
390
  </bpmndi:BPMNEdge>
351
391
  <bpmndi:BPMNEdge id="BPMNEdge_f_escalate" bpmnElement="f_escalate">
352
392
  <di:waypoint x="441" y="145" />
353
- <di:waypoint x="441" y="760" />
354
- <di:waypoint x="566" y="760" />
393
+ <di:waypoint x="441" y="600" />
394
+ <di:waypoint x="566" y="600" />
355
395
  <bpmndi:BPMNLabel>
356
- <dc:Bounds x="446" y="506" width="81" height="28" />
396
+ <dc:Bounds x="446" y="426" width="81" height="28" />
357
397
  </bpmndi:BPMNLabel>
358
398
  </bpmndi:BPMNEdge>
359
399
  <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" />
400
+ <di:waypoint x="966" y="280" />
401
+ <di:waypoint x="1046" y="280" />
402
+ <di:waypoint x="1046" y="600" />
403
+ <di:waypoint x="1066" y="600" />
364
404
  <bpmndi:BPMNLabel>
365
- <dc:Bounds x="751" y="433" width="74" height="14" />
405
+ <dc:Bounds x="1051" y="433" width="74" height="14" />
366
406
  </bpmndi:BPMNLabel>
367
407
  </bpmndi:BPMNEdge>
368
408
  <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" />
409
+ <di:waypoint x="1291" y="305" />
410
+ <di:waypoint x="1291" y="440" />
411
+ <di:waypoint x="1416" y="440" />
412
+ </bpmndi:BPMNEdge>
413
+ <bpmndi:BPMNEdge id="BPMNEdge_f_escWait" bpmnElement="f_escWait">
414
+ <di:waypoint x="791" y="625" />
415
+ <di:waypoint x="791" y="645" />
416
+ <di:waypoint x="1732" y="645" />
417
+ <di:waypoint x="1732" y="460" />
418
+ <di:waypoint x="1752" y="460" />
372
419
  </bpmndi:BPMNEdge>
373
420
  <bpmndi:BPMNEdge id="BPMNEdge_f_reviewStalled" bpmnElement="f_reviewStalled">
374
- <di:waypoint x="1152" y="440" />
375
- <di:waypoint x="1252" y="440" />
421
+ <di:waypoint x="1452" y="440" />
422
+ <di:waypoint x="1552" y="440" />
376
423
  </bpmndi:BPMNEdge>
377
424
  <bpmndi:BPMNEdge id="BPMNEdge_f_stalledWait" bpmnElement="f_stalledWait">
378
- <di:waypoint x="1352" y="440" />
379
- <di:waypoint x="1452" y="440" />
425
+ <di:waypoint x="1652" y="440" />
426
+ <di:waypoint x="1752" y="440" />
380
427
  </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" />
428
+ <bpmndi:BPMNEdge id="BPMNEdge_f_escGate" bpmnElement="f_escGate">
429
+ <di:waypoint x="666" y="600" />
430
+ <di:waypoint x="766" y="600" />
385
431
  </bpmndi:BPMNEdge>
386
432
  <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" />
433
+ <di:waypoint x="1166" y="620" />
434
+ <di:waypoint x="1186" y="620" />
435
+ <di:waypoint x="1186" y="645" />
436
+ <di:waypoint x="1802" y="645" />
437
+ <di:waypoint x="1802" y="480" />
438
+ </bpmndi:BPMNEdge>
439
+ <bpmndi:BPMNEdge id="BPMNEdge_f_answerRecord" bpmnElement="f_answerRecord">
440
+ <di:waypoint x="1852" y="440" />
441
+ <di:waypoint x="1952" y="440" />
390
442
  </bpmndi:BPMNEdge>
391
443
  <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" />
444
+ <di:waypoint x="2002" y="480" />
445
+ <di:waypoint x="2002" y="660" />
446
+ <di:waypoint x="266" y="660" />
395
447
  <di:waypoint x="266" y="160" />
396
448
  </bpmndi:BPMNEdge>
397
449
  </bpmndi:BPMNPlane>
@@ -0,0 +1,240 @@
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" id="Definitions_nano_workforce_feature" targetNamespace="http://nanobpm.io/nano-workforce">
3
+ <bpmn:process id="feature" name="Single-issue feature run" isExecutable="true">
4
+ <bpmn:startEvent id="Start" name="Issue submitted">
5
+ <bpmn:outgoing>f_toEnsureBase</bpmn:outgoing>
6
+ </bpmn:startEvent>
7
+ <bpmn:serviceTask id="ensure-base-branch" name="Ensure base branch">
8
+ <bpmn:extensionElements>
9
+ <zeebe:taskDefinition type="pr.ensure-base-branch" />
10
+ <zeebe:ioMapping>
11
+ <zeebe:input source="=repo" target="repo" />
12
+ <zeebe:input source="=baseBranch" target="baseBranch" />
13
+ </zeebe:ioMapping>
14
+ </bpmn:extensionElements>
15
+ <bpmn:incoming>f_toEnsureBase</bpmn:incoming>
16
+ <bpmn:outgoing>f_toImplement</bpmn:outgoing>
17
+ </bpmn:serviceTask>
18
+ <bpmn:serviceTask id="implement-task" name="Implement (agent)">
19
+ <bpmn:extensionElements>
20
+ <zeebe:taskDefinition type="senior:feature" />
21
+ <zeebe:taskHeaders>
22
+ <zeebe:header key="io.nanobpm.agentTask.task.prompt" value="{{feature}}" />
23
+ </zeebe:taskHeaders>
24
+ <zeebe:ioMapping>
25
+ <zeebe:input source="=&#34;&#10;&#10;---&#10;&#10;&#34; + task.prompt + (if (baseBranchBrief = null) then &#34;&#34; else baseBranchBrief)" target="appendPrompt" />
26
+ <zeebe:output source="=status" target="status" />
27
+ <zeebe:output source="=question" target="question" />
28
+ </zeebe:ioMapping>
29
+ </bpmn:extensionElements>
30
+ <bpmn:incoming>f_toImplement</bpmn:incoming>
31
+ <bpmn:incoming>w_answerLoop</bpmn:incoming>
32
+ <bpmn:outgoing>w_toGw</bpmn:outgoing>
33
+ </bpmn:serviceTask>
34
+ <bpmn:exclusiveGateway id="w_gw" name="escalated?" default="w_done">
35
+ <bpmn:incoming>w_toGw</bpmn:incoming>
36
+ <bpmn:outgoing>w_escalate</bpmn:outgoing>
37
+ <bpmn:outgoing>w_done</bpmn:outgoing>
38
+ </bpmn:exclusiveGateway>
39
+ <bpmn:userTask id="feature-escalation" name="Task escalation (human)">
40
+ <bpmn:extensionElements>
41
+ <zeebe:formDefinition formId="feature-escalation" />
42
+ <zeebe:userTask />
43
+ <zeebe:assignmentDefinition candidateGroups="operators" assignee="=escalationAssignee" />
44
+ </bpmn:extensionElements>
45
+ <bpmn:incoming>w_escalate</bpmn:incoming>
46
+ <bpmn:outgoing>w_toAnswerGw</bpmn:outgoing>
47
+ </bpmn:userTask>
48
+ <bpmn:boundaryEvent id="be_feature_sla" name="SLA elapsed" attachedToRef="feature-escalation">
49
+ <bpmn:outgoing>w_sla</bpmn:outgoing>
50
+ <bpmn:timerEventDefinition id="ted_feature_sla">
51
+ <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">=escalationSlaTimeout</bpmn:timeDuration>
52
+ </bpmn:timerEventDefinition>
53
+ </bpmn:boundaryEvent>
54
+ <bpmn:exclusiveGateway id="w_gw_answer" name="answer?" default="w_abandon">
55
+ <bpmn:incoming>w_toAnswerGw</bpmn:incoming>
56
+ <bpmn:outgoing>w_answerLoop</bpmn:outgoing>
57
+ <bpmn:outgoing>w_abandon</bpmn:outgoing>
58
+ </bpmn:exclusiveGateway>
59
+ <bpmn:serviceTask id="record-feature" name="Record result">
60
+ <bpmn:extensionElements>
61
+ <zeebe:taskDefinition type="pr.record-feature" />
62
+ </bpmn:extensionElements>
63
+ <bpmn:incoming>w_done</bpmn:incoming>
64
+ <bpmn:incoming>w_abandon</bpmn:incoming>
65
+ <bpmn:incoming>w_sla</bpmn:incoming>
66
+ <bpmn:outgoing>f_toConvergeGw</bpmn:outgoing>
67
+ </bpmn:serviceTask>
68
+ <bpmn:exclusiveGateway id="gw-converge" name="converge?" default="f_noConverge">
69
+ <bpmn:incoming>f_toConvergeGw</bpmn:incoming>
70
+ <bpmn:outgoing>f_converge</bpmn:outgoing>
71
+ <bpmn:outgoing>f_noConverge</bpmn:outgoing>
72
+ </bpmn:exclusiveGateway>
73
+ <bpmn:serviceTask id="converge" name="Hand off to convergence loop">
74
+ <bpmn:extensionElements>
75
+ <zeebe:taskDefinition type="pr.converge-feature" />
76
+ </bpmn:extensionElements>
77
+ <bpmn:incoming>f_converge</bpmn:incoming>
78
+ <bpmn:outgoing>f_toEndConverged</bpmn:outgoing>
79
+ </bpmn:serviceTask>
80
+ <bpmn:endEvent id="End" name="Done">
81
+ <bpmn:incoming>f_noConverge</bpmn:incoming>
82
+ <bpmn:incoming>f_toEndConverged</bpmn:incoming>
83
+ </bpmn:endEvent>
84
+ <bpmn:sequenceFlow id="f_toEnsureBase" sourceRef="Start" targetRef="ensure-base-branch" />
85
+ <bpmn:sequenceFlow id="f_toImplement" sourceRef="ensure-base-branch" targetRef="implement-task" />
86
+ <bpmn:sequenceFlow id="w_toGw" sourceRef="implement-task" targetRef="w_gw" />
87
+ <bpmn:sequenceFlow id="w_escalate" name="escalated" sourceRef="w_gw" targetRef="feature-escalation">
88
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=status = "escalated" and question != null and trim(question) != ""</bpmn:conditionExpression>
89
+ </bpmn:sequenceFlow>
90
+ <bpmn:sequenceFlow id="w_done" name="done" sourceRef="w_gw" targetRef="record-feature" />
91
+ <bpmn:sequenceFlow id="w_toAnswerGw" sourceRef="feature-escalation" targetRef="w_gw_answer" />
92
+ <bpmn:sequenceFlow id="w_answerLoop" name="answer" sourceRef="w_gw_answer" targetRef="implement-task">
93
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=resolution = "answer"</bpmn:conditionExpression>
94
+ </bpmn:sequenceFlow>
95
+ <bpmn:sequenceFlow id="w_abandon" name="abandon" sourceRef="w_gw_answer" targetRef="record-feature" />
96
+ <bpmn:sequenceFlow id="w_sla" name="SLA auto-abandon" sourceRef="be_feature_sla" targetRef="record-feature" />
97
+ <bpmn:sequenceFlow id="f_toConvergeGw" sourceRef="record-feature" targetRef="gw-converge" />
98
+ <bpmn:sequenceFlow id="f_converge" name="converge" sourceRef="gw-converge" targetRef="converge">
99
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=converge = true and featureStatus = "opened" and prKey != null</bpmn:conditionExpression>
100
+ </bpmn:sequenceFlow>
101
+ <bpmn:sequenceFlow id="f_noConverge" name="raise only" sourceRef="gw-converge" targetRef="End" />
102
+ <bpmn:sequenceFlow id="f_toEndConverged" sourceRef="converge" targetRef="End" />
103
+ </bpmn:process>
104
+ <bpmndi:BPMNDiagram id="BPMNDiagram_feature">
105
+ <bpmndi:BPMNPlane id="BPMNPlane_feature" bpmnElement="feature">
106
+ <bpmndi:BPMNShape id="BPMNShape_Start" bpmnElement="Start">
107
+ <dc:Bounds x="80" y="102" width="36" height="36" />
108
+ <bpmndi:BPMNLabel>
109
+ <dc:Bounds x="63" y="143" width="70" height="28" />
110
+ </bpmndi:BPMNLabel>
111
+ </bpmndi:BPMNShape>
112
+ <bpmndi:BPMNShape id="BPMNShape_ensure-base-branch" bpmnElement="ensure-base-branch">
113
+ <dc:Bounds x="216" y="80" width="100" height="80" />
114
+ </bpmndi:BPMNShape>
115
+ <bpmndi:BPMNShape id="BPMNShape_implement-task" bpmnElement="implement-task">
116
+ <dc:Bounds x="416" y="80" width="100" height="80" />
117
+ </bpmndi:BPMNShape>
118
+ <bpmndi:BPMNShape id="BPMNShape_w_gw" bpmnElement="w_gw" isMarkerVisible="true">
119
+ <dc:Bounds x="616" y="95" width="50" height="50" />
120
+ <bpmndi:BPMNLabel>
121
+ <dc:Bounds x="604" y="76" width="74" height="14" />
122
+ </bpmndi:BPMNLabel>
123
+ </bpmndi:BPMNShape>
124
+ <bpmndi:BPMNShape id="BPMNShape_feature-escalation" bpmnElement="feature-escalation">
125
+ <dc:Bounds x="766" y="240" width="100" height="80" />
126
+ </bpmndi:BPMNShape>
127
+ <bpmndi:BPMNShape id="BPMNShape_w_gw_answer" bpmnElement="w_gw_answer" isMarkerVisible="true">
128
+ <dc:Bounds x="966" y="255" width="50" height="50" />
129
+ <bpmndi:BPMNLabel>
130
+ <dc:Bounds x="963" y="236" width="56" height="14" />
131
+ </bpmndi:BPMNLabel>
132
+ </bpmndi:BPMNShape>
133
+ <bpmndi:BPMNShape id="BPMNShape_record-feature" bpmnElement="record-feature">
134
+ <dc:Bounds x="1116" y="80" width="100" height="80" />
135
+ </bpmndi:BPMNShape>
136
+ <bpmndi:BPMNShape id="BPMNShape_gw-converge" bpmnElement="gw-converge" isMarkerVisible="true">
137
+ <dc:Bounds x="1316" y="95" width="50" height="50" />
138
+ <bpmndi:BPMNLabel>
139
+ <dc:Bounds x="1308" y="76" width="67" height="14" />
140
+ </bpmndi:BPMNLabel>
141
+ </bpmndi:BPMNShape>
142
+ <bpmndi:BPMNShape id="BPMNShape_converge" bpmnElement="converge">
143
+ <dc:Bounds x="1466" y="240" width="100" height="80" />
144
+ </bpmndi:BPMNShape>
145
+ <bpmndi:BPMNShape id="BPMNShape_End" bpmnElement="End">
146
+ <dc:Bounds x="1666" y="102" width="36" height="36" />
147
+ <bpmndi:BPMNLabel>
148
+ <dc:Bounds x="1667" y="83" width="34" height="14" />
149
+ </bpmndi:BPMNLabel>
150
+ </bpmndi:BPMNShape>
151
+ <bpmndi:BPMNShape id="BPMNShape_be_feature_sla" bpmnElement="be_feature_sla">
152
+ <dc:Bounds x="798" y="302" width="36" height="36" />
153
+ <bpmndi:BPMNLabel>
154
+ <dc:Bounds x="774" y="383" width="84" height="14" />
155
+ </bpmndi:BPMNLabel>
156
+ </bpmndi:BPMNShape>
157
+ <bpmndi:BPMNEdge id="BPMNEdge_f_toEnsureBase" bpmnElement="f_toEnsureBase">
158
+ <di:waypoint x="116" y="120" />
159
+ <di:waypoint x="216" y="120" />
160
+ </bpmndi:BPMNEdge>
161
+ <bpmndi:BPMNEdge id="BPMNEdge_f_toImplement" bpmnElement="f_toImplement">
162
+ <di:waypoint x="316" y="120" />
163
+ <di:waypoint x="416" y="120" />
164
+ </bpmndi:BPMNEdge>
165
+ <bpmndi:BPMNEdge id="BPMNEdge_w_toGw" bpmnElement="w_toGw">
166
+ <di:waypoint x="516" y="120" />
167
+ <di:waypoint x="616" y="120" />
168
+ </bpmndi:BPMNEdge>
169
+ <bpmndi:BPMNEdge id="BPMNEdge_w_done" bpmnElement="w_done">
170
+ <di:waypoint x="666" y="120" />
171
+ <di:waypoint x="1116" y="120" />
172
+ <bpmndi:BPMNLabel>
173
+ <dc:Bounds x="875" y="98" width="32" height="14" />
174
+ </bpmndi:BPMNLabel>
175
+ </bpmndi:BPMNEdge>
176
+ <bpmndi:BPMNEdge id="BPMNEdge_f_toConvergeGw" bpmnElement="f_toConvergeGw">
177
+ <di:waypoint x="1216" y="120" />
178
+ <di:waypoint x="1316" y="120" />
179
+ </bpmndi:BPMNEdge>
180
+ <bpmndi:BPMNEdge id="BPMNEdge_f_noConverge" bpmnElement="f_noConverge">
181
+ <di:waypoint x="1366" y="120" />
182
+ <di:waypoint x="1666" y="120" />
183
+ <bpmndi:BPMNLabel>
184
+ <dc:Bounds x="1481" y="98" width="71" height="14" />
185
+ </bpmndi:BPMNLabel>
186
+ </bpmndi:BPMNEdge>
187
+ <bpmndi:BPMNEdge id="BPMNEdge_w_abandon" bpmnElement="w_abandon">
188
+ <di:waypoint x="1016" y="280" />
189
+ <di:waypoint x="1166" y="280" />
190
+ <di:waypoint x="1166" y="160" />
191
+ <bpmndi:BPMNLabel>
192
+ <dc:Bounds x="1065" y="258" width="53" height="14" />
193
+ </bpmndi:BPMNLabel>
194
+ </bpmndi:BPMNEdge>
195
+ <bpmndi:BPMNEdge id="BPMNEdge_w_escalate" bpmnElement="w_escalate">
196
+ <di:waypoint x="641" y="145" />
197
+ <di:waypoint x="641" y="280" />
198
+ <di:waypoint x="766" y="280" />
199
+ <bpmndi:BPMNLabel>
200
+ <dc:Bounds x="646" y="206" width="67" height="14" />
201
+ </bpmndi:BPMNLabel>
202
+ </bpmndi:BPMNEdge>
203
+ <bpmndi:BPMNEdge id="BPMNEdge_f_converge" bpmnElement="f_converge">
204
+ <di:waypoint x="1341" y="145" />
205
+ <di:waypoint x="1341" y="280" />
206
+ <di:waypoint x="1466" y="280" />
207
+ <bpmndi:BPMNLabel>
208
+ <dc:Bounds x="1346" y="206" width="60" height="14" />
209
+ </bpmndi:BPMNLabel>
210
+ </bpmndi:BPMNEdge>
211
+ <bpmndi:BPMNEdge id="BPMNEdge_w_toAnswerGw" bpmnElement="w_toAnswerGw">
212
+ <di:waypoint x="866" y="280" />
213
+ <di:waypoint x="966" y="280" />
214
+ </bpmndi:BPMNEdge>
215
+ <bpmndi:BPMNEdge id="BPMNEdge_f_toEndConverged" bpmnElement="f_toEndConverged">
216
+ <di:waypoint x="1566" y="280" />
217
+ <di:waypoint x="1684" y="280" />
218
+ <di:waypoint x="1684" y="138" />
219
+ </bpmndi:BPMNEdge>
220
+ <bpmndi:BPMNEdge id="BPMNEdge_w_sla" bpmnElement="w_sla">
221
+ <di:waypoint x="816" y="338" />
222
+ <di:waypoint x="816" y="358" />
223
+ <di:waypoint x="1166" y="358" />
224
+ <di:waypoint x="1166" y="160" />
225
+ <bpmndi:BPMNLabel>
226
+ <dc:Bounds x="1007" y="325" width="88" height="28" />
227
+ </bpmndi:BPMNLabel>
228
+ </bpmndi:BPMNEdge>
229
+ <bpmndi:BPMNEdge id="BPMNEdge_w_answerLoop" bpmnElement="w_answerLoop">
230
+ <di:waypoint x="991" y="305" />
231
+ <di:waypoint x="991" y="360" />
232
+ <di:waypoint x="466" y="360" />
233
+ <di:waypoint x="466" y="160" />
234
+ <bpmndi:BPMNLabel>
235
+ <dc:Bounds x="704" y="338" width="49" height="14" />
236
+ </bpmndi:BPMNLabel>
237
+ </bpmndi:BPMNEdge>
238
+ </bpmndi:BPMNPlane>
239
+ </bpmndi:BPMNDiagram>
240
+ </bpmn:definitions>