@nanobpm/nano-workforce 0.57.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 (82) hide show
  1. package/.github/workflows/ci.yml +7 -0
  2. package/AGENTS.md +83 -1
  3. package/CHANGELOG.md +7 -0
  4. package/README.md +1 -1
  5. package/SPEC.md +21 -22
  6. package/app/agentCompletion.test.ts +337 -0
  7. package/app/agentCompletion.ts +219 -0
  8. package/app/answer-escalation.test.ts +106 -0
  9. package/app/answerEscalation.test.ts +67 -0
  10. package/app/baseGuard.test.ts +9 -1
  11. package/app/baseGuard.ts +11 -0
  12. package/app/escalationSla.test.ts +39 -0
  13. package/app/escalationSla.ts +28 -0
  14. package/app/escalationTaxonomy.test.ts +115 -0
  15. package/app/escalationTaxonomy.ts +115 -0
  16. package/app/feature.test.ts +161 -0
  17. package/app/feature.ts +173 -0
  18. package/app/mergeProtocol.test.ts +15 -0
  19. package/app/mergeProtocol.ts +10 -0
  20. package/app/persist-escalation.test.ts +34 -36
  21. package/app/plan.test.ts +0 -294
  22. package/app/plan.ts +26 -216
  23. package/app/reviewWait.ts +12 -4
  24. package/app/roundResultDefault.test.ts +111 -2
  25. package/app/roundResultDefault.ts +35 -0
  26. package/app/service.test.ts +6 -7
  27. package/app/service.ts +52 -35
  28. package/db/migrations/026_agent_completion.sql +36 -0
  29. package/db/migrations/027_retire_escalation_subsystem.sql +43 -0
  30. package/db/migrations/028_feature_runs.sql +28 -0
  31. package/e2e/agent-answerable.e2e.ts +185 -0
  32. package/e2e/convergence-escalation.e2e.ts +180 -0
  33. package/e2e/convergence-loop.e2e.ts +1 -1
  34. package/e2e/feature-run.e2e.ts +231 -0
  35. package/e2e/plan-fanout-sla.e2e.ts +238 -0
  36. package/e2e/plan-fanout.e2e.ts +303 -0
  37. package/e2e/retire-escalation-subsystem.e2e.ts +223 -0
  38. package/e2e/support/github-admit.ts +99 -0
  39. package/e2e/user-task-spine.e2e.ts +155 -0
  40. package/nano.app.json +37 -11
  41. package/openapi.yaml +181 -73
  42. package/operations/agentCompleteEscalation.ts +53 -0
  43. package/operations/listActivePrs.test.ts +39 -6
  44. package/operations/postMessage.ts +10 -41
  45. package/operations/revertEscalationCompletion.ts +44 -0
  46. package/operations/startAndMessage.test.ts +0 -58
  47. package/operations/startFeature.ts +127 -0
  48. package/package.json +4 -1
  49. package/pages/cockpit.page.json +1 -0
  50. package/pages/epic-detail.page.json +11 -37
  51. package/pages/epic.page.json +1 -1
  52. package/pages/feature.page.json +82 -0
  53. package/pages/home.page.json +6 -18
  54. package/resources/agent-guide.md +52 -24
  55. package/resources/forms/feature-escalation.form +27 -0
  56. package/resources/forms/plan-review-decision.form +27 -0
  57. package/resources/forms/pr-escalation.form +23 -0
  58. package/resources/forms/spine-demo.form +15 -0
  59. package/resources/forms/trial-merge-decision.form +25 -0
  60. package/resources/processes/convergence-loop.bpmn +127 -75
  61. package/resources/processes/feature.bpmn +240 -0
  62. package/resources/processes/plan-fanout.bpmn +304 -223
  63. package/resources/processes/spine-demo.bpmn +72 -0
  64. package/scripts/check-migrations.ts +68 -0
  65. package/workers/answer-escalation/worker.ts +78 -0
  66. package/workers/converge-feature/worker.ts +51 -0
  67. package/workers/finalize/worker.ts +0 -2
  68. package/workers/mark-merged/worker.ts +0 -2
  69. package/workers/merge/worker.ts +6 -5
  70. package/workers/persist-escalation/worker.ts +28 -32
  71. package/workers/record-feature/worker.ts +61 -0
  72. package/workers/record-plan-review/worker.test.ts +9 -10
  73. package/workers/record-plan-review/worker.ts +15 -5
  74. package/workers/resolve-trial-attention/worker.test.ts +77 -0
  75. package/workers/resolve-trial-attention/worker.ts +43 -0
  76. package/operations/answerFeatureEscalation.test.ts +0 -112
  77. package/operations/answerFeatureEscalation.ts +0 -58
  78. package/operations/answerPlanEscalation.test.ts +0 -115
  79. package/operations/answerPlanEscalation.ts +0 -41
  80. package/workers/persist-plan-escalation/worker.test.ts +0 -80
  81. package/workers/persist-plan-escalation/worker.ts +0 -73
  82. package/workers/persist-task-escalation/worker.ts +0 -120
@@ -160,43 +160,71 @@ curl -sS __BASE__/status | jq '.prs[] | select(.openEscalation != null)
160
160
  | { prKey, status, round, openEscalation }'
161
161
  ```
162
162
 
163
- **Answer a PR/merge escalation** (convergence-loop or merge-loop). Use the message
164
- name `escalation-answered`; correlate by the PR key:
163
+ The four decision-required escalation kinds **PR review-loop**, **implementation
164
+ (feature) task**, **plan-review**, and **trial-merge** are now native BPMN
165
+ `userTask`s bearing a linked `.form`, all answered the same way through the **task
166
+ inbox** surface. There is no bespoke per-kind webhook or answer page any more.
167
+
168
+ **List the open escalation tasks.** Each task carries its context (e.g. `prKey` /
169
+ `question` / `findings` / `task`) in its `variables`, and its kind in `elementId`:
165
170
 
166
171
  ```bash
167
- curl -sS -X POST __BASE__/actions/message \
168
- -H 'content-type: application/json' \
169
- -d '{
170
- "name": "escalation-answered",
171
- "correlationKey": "owner/repo#123",
172
- "variables": { "answer": "Yes cap the retries at 5 and proceed." }
173
- }'
172
+ # Every parked escalation, across all kinds:
173
+ curl -sS __BASE__/../../tasks/api/tasks | jq '.[] | { userTaskKey, elementId, variables }'
174
+
175
+ # Filter to one kind (e.g. plan-review decisions) by elementId:
176
+ curl -sS __BASE__/../../tasks/api/tasks \
177
+ | jq '[.[] | select(.elementId == "plan-review-decision")]'
174
178
  ```
175
179
 
176
- The answer is delivered to the agent as the `answer` variable on its next round, and
177
- the loop resumes.
180
+ The inbox UI is also served at `__BASE__/../../tasks` for a human to browse, filter, and
181
+ answer (assignee/candidate-group and age surface on each task once assignment lands).
178
182
 
179
- **Answer an implementation-phase (feature) task escalation** raised during a
180
- plan fan-out a dedicated webhook operation:
183
+ **Answer a task** by completing it with the typed variables its form expects — the
184
+ completion resumes the parked process:
181
185
 
182
186
  ```bash
183
- curl -sS -X POST __BASE__/hooks/feature-answer \
184
- -H 'content-type: application/json' \
185
- -d '{ "correlationKey": "<task-or-pr-key>", "answer": "" }'
187
+ # PR review-loop (elementId `wait-answer`, pr-escalation form):
188
+ curl -sS -X POST __BASE__/../../tasks/api/complete -H 'content-type: application/json' \
189
+ -d '{ "userTaskKey": "<key>", "variables": { "answer": "Cap retries at 5 and proceed." } }'
190
+
191
+ # Implementation (feature) task (elementId `feature-escalation`):
192
+ # { "resolution": "answer", "answer": "…" } to resume, or { "resolution": "abandon" }
193
+ curl -sS -X POST __BASE__/../../tasks/api/complete -H 'content-type: application/json' \
194
+ -d '{ "userTaskKey": "<key>", "variables": { "resolution": "answer", "answer": "Use v2." } }'
195
+
196
+ # Plan-review (elementId `plan-review-decision`):
197
+ # { "directive": "revise", "notes": "…" } (fresh review budget) or { "directive": "proceed" }
198
+ curl -sS -X POST __BASE__/../../tasks/api/complete -H 'content-type: application/json' \
199
+ -d '{ "userTaskKey": "<key>", "variables": { "directive": "revise", "notes": "Make issue-7 the seam." } }'
200
+
201
+ # Trial-merge (elementId `trial-merge-decision`):
202
+ # { "action": "proceed" | "rebase" | "abandon", "notes"?: "…" }
203
+ curl -sS -X POST __BASE__/../../tasks/api/complete -H 'content-type: application/json' \
204
+ -d '{ "userTaskKey": "<key>", "variables": { "action": "rebase", "notes": "Re-run after the fix." } }'
186
205
  ```
187
206
 
188
- If `NANO_PR_WEBHOOK_SECRET` is set on the deployment, add `-H "x-hook-secret: <secret>"`.
189
-
190
- **Answer a plan-review escalation** raised when the adversarial plan review cannot
191
- converge within its round budget. Use `revise` to send guidance back to the planner
192
- with a fresh review budget, or `proceed` to explicitly approve the current plan as-is:
207
+ **Answer a merge-loop escalation** (the one out-of-scope kind that still uses the
208
+ durable message catch, not a user task). Use the message name `escalation-answered`,
209
+ correlated by the PR key:
193
210
 
194
211
  ```bash
195
- curl -sS -X POST __BASE__/hooks/plan-answer \
212
+ curl -sS -X POST __BASE__/actions/message \
196
213
  -H 'content-type: application/json' \
197
- -d '{ "plan": "owner/repo#123", "directive": "revise", "note": "Keep the sub-issues 1:1; make issue-7 the seam and point siblings at it." }'
214
+ -d '{
215
+ "name": "escalation-answered",
216
+ "correlationKey": "owner/repo#123",
217
+ "variables": { "answer": "Yes — cap the retries at 5 and proceed." }
218
+ }'
198
219
  ```
199
220
 
221
+ If `NANO_PR_WEBHOOK_SECRET` is set on the deployment, add `-H "x-hook-secret: <secret>"`.
222
+
223
+ The answer is delivered to the agent as its next-round context (e.g. the `answer`,
224
+ `directive`, or `action` variable), and the loop resumes. **Audit** is durable: the
225
+ completed user tasks form the escalation history, and the review/merge loops' rows
226
+ live in the `escalations` table (surfaced read-only per PR on the Convergence page).
227
+
200
228
  Guidance for the human you assist: read the escalation `question` or plan-review
201
229
  `findings` first, decide the smallest unblocking answer, and answer it precisely —
202
230
  the answer becomes the agent's next-round context.
@@ -209,7 +237,7 @@ the answer becomes the agent's next-round context.
209
237
  submit ──► convergence-loop
210
238
  round (senior:pr-review) ──► addressed ──► wait review-ready ─┐
211
239
  ├─ converged ──► finalize ──► merge-loop (unless convergeOnly)
212
- └─ needs_input/blocked ──► escalate ──► wait escalation-answered
240
+ └─ needs_input/blocked ──► escalate ──► wait-answer userTask (task inbox)
213
241
  merge-loop: wait deps ─► arm merge ─► (queue-aware) merge / land
214
242
  blocked (CI red) ─► senior:fix-ci ─► retry conflict ─► senior:rebase ─► retry
215
243
  ```
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": "feature-escalation",
3
+ "schemaVersion": 18,
4
+ "type": "default",
5
+ "components": [
6
+ {
7
+ "type": "select",
8
+ "key": "resolution",
9
+ "label": "Resolution",
10
+ "values": [
11
+ { "label": "Answer — re-dispatch the task with this guidance", "value": "answer" },
12
+ { "label": "Abandon — give up on this task", "value": "abandon" }
13
+ ],
14
+ "validate": {
15
+ "required": true
16
+ }
17
+ },
18
+ {
19
+ "type": "textarea",
20
+ "key": "answer",
21
+ "label": "Answer / guidance for the implementation agent",
22
+ "conditional": {
23
+ "hide": "=resolution != \"answer\""
24
+ }
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": "plan-review-decision",
3
+ "schemaVersion": 18,
4
+ "type": "default",
5
+ "components": [
6
+ {
7
+ "type": "select",
8
+ "key": "directive",
9
+ "label": "Directive",
10
+ "values": [
11
+ { "label": "Proceed — dispatch the current plan as-is", "value": "proceed" },
12
+ { "label": "Revise — send the plan back to the planner", "value": "revise" }
13
+ ],
14
+ "validate": {
15
+ "required": true
16
+ }
17
+ },
18
+ {
19
+ "type": "textarea",
20
+ "key": "notes",
21
+ "label": "Revision guidance for the planner",
22
+ "conditional": {
23
+ "hide": "=directive != \"revise\""
24
+ }
25
+ }
26
+ ]
27
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "id": "pr-escalation",
3
+ "schemaVersion": 18,
4
+ "type": "default",
5
+ "components": [
6
+ {
7
+ "type": "textarea",
8
+ "key": "question",
9
+ "label": "Escalation question",
10
+ "description": "A human decision is needed to resume the PR review-convergence loop.",
11
+ "readonly": true
12
+ },
13
+ {
14
+ "type": "textarea",
15
+ "key": "answer",
16
+ "label": "Your answer",
17
+ "description": "Your reply resumes the review loop and is handed to the next review round.",
18
+ "validate": {
19
+ "required": true
20
+ }
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "id": "spine-demo",
3
+ "schemaVersion": 18,
4
+ "type": "default",
5
+ "components": [
6
+ {
7
+ "type": "textfield",
8
+ "key": "decision",
9
+ "label": "Decision",
10
+ "validate": {
11
+ "required": true
12
+ }
13
+ }
14
+ ]
15
+ }
@@ -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>