@nanobpm/nano-workforce 0.115.0 → 0.116.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.
@@ -50,8 +50,6 @@
50
50
  <nano:shape id="PrConvergeGateOut" name="Converge gate — result">
51
51
  <nano:extend name="convergeBlocked" type="boolean" />
52
52
  <nano:extend name="convergeBlockReason" type="string" optional="true" />
53
- <nano:extend name="headSha" type="string" optional="true" />
54
- <nano:extend name="scopeBlocked" type="boolean" optional="true" />
55
53
  </nano:shape>
56
54
  <nano:shape id="EscalationIn" name="Record escalation — input">
57
55
  <nano:extend name="prKey" type="string" />
@@ -64,8 +62,6 @@
64
62
  <nano:extend name="prNumber" type="integer" optional="true" />
65
63
  <nano:extend name="prUrl" type="string" optional="true" />
66
64
  <nano:extend name="abandonUrl" type="string" optional="true" />
67
- <nano:extend name="headSha" type="string" optional="true" />
68
- <nano:extend name="scopeBlock" type="boolean" optional="true" />
69
65
  </nano:shape>
70
66
  <nano:shape id="EscalationOut" name="Record escalation — result">
71
67
  <nano:extend name="escalationId" type="integer" optional="true" />
@@ -86,6 +82,16 @@
86
82
  <nano:extend name="convergeOnly" type="boolean" optional="true" />
87
83
  <nano:extend name="abandonUrl" type="string" optional="true" />
88
84
  </nano:shape>
85
+ <nano:shape id="PrScopeClassifyIn" name="Scope classifier — input">
86
+ <nano:extend name="prUrl" type="string" />
87
+ <nano:extend name="repo" type="string" />
88
+ <nano:extend name="prNumber" type="integer" />
89
+ <nano:extend name="scopeAnswer" type="string" optional="true" />
90
+ </nano:shape>
91
+ <nano:shape id="PrScopeClassifyOut" name="Scope classifier — verdict">
92
+ <nano:extend name="scopeBlocked" type="boolean" />
93
+ <nano:extend name="scopeBlockReason" type="string" />
94
+ </nano:shape>
89
95
  </nano:shapes>
90
96
  </bpmn:extensionElements>
91
97
  <bpmn:startEvent id="Start" name="PR submitted">
@@ -104,6 +110,7 @@
104
110
  <zeebe:ioMapping>
105
111
  <zeebe:input source="=(if (abandonBrief = null) then &#34;&#34; else abandonBrief)" target="appendPrompt" />
106
112
  <zeebe:output source="=null" target="answer" />
113
+ <zeebe:output source="=false" target="scopePending" />
107
114
  </zeebe:ioMapping>
108
115
  </bpmn:extensionElements>
109
116
  <bpmn:incoming>f_start</bpmn:incoming>
@@ -221,6 +228,7 @@
221
228
  <bpmn:incoming>f_noprogressGate</bpmn:incoming>
222
229
  <bpmn:incoming>f_stalledGate</bpmn:incoming>
223
230
  <bpmn:incoming>f_blockedGate</bpmn:incoming>
231
+ <bpmn:incoming>f_scopeEscGate</bpmn:incoming>
224
232
  <bpmn:incoming>f_maxGate</bpmn:incoming>
225
233
  <bpmn:outgoing>f_escWait</bpmn:outgoing>
226
234
  <bpmn:outgoing>f_escReenter</bpmn:outgoing>
@@ -261,6 +269,7 @@
261
269
  <zeebe:ioMapping>
262
270
  <zeebe:input source="=prKey" target="prKey" />
263
271
  <zeebe:input source="=answer" target="answer" />
272
+ <zeebe:output source="=(if scopePending = true then answer else scopeAnswer)" target="scopeAnswer" />
264
273
  </zeebe:ioMapping>
265
274
  </bpmn:extensionElements>
266
275
  <bpmn:incoming>f_answerRecord</bpmn:incoming>
@@ -273,7 +282,7 @@
273
282
  <zeebe:property name="io.nanobpm.dataEnvelope.in" value="PrFinalizeIn" />
274
283
  </zeebe:properties>
275
284
  </bpmn:extensionElements>
276
- <bpmn:incoming>f_convergeOk</bpmn:incoming>
285
+ <bpmn:incoming>f_scopeOk</bpmn:incoming>
277
286
  <bpmn:outgoing>f_finalize</bpmn:outgoing>
278
287
  </bpmn:serviceTask>
279
288
  <bpmn:serviceTask id="check-converge" name="Check review comments">
@@ -303,13 +312,50 @@
303
312
  <zeebe:input source="=&#34;blocked&#34;" target="status" />
304
313
  <zeebe:input source="=false" target="recordRound" />
305
314
  <zeebe:input source="=convergeBlockReason" target="question" />
306
- <zeebe:input source="=headSha" target="headSha" />
307
- <zeebe:input source="=scopeBlocked" target="scopeBlock" />
308
315
  </zeebe:ioMapping>
309
316
  </bpmn:extensionElements>
310
317
  <bpmn:incoming>f_convergeBlocked</bpmn:incoming>
311
318
  <bpmn:outgoing>f_blockedGate</bpmn:outgoing>
312
319
  </bpmn:serviceTask>
320
+ <bpmn:serviceTask id="classify-scope" name="Scope classifier (agent)">
321
+ <bpmn:extensionElements>
322
+ <zeebe:taskDefinition type="senior:scope-classify" />
323
+ <zeebe:linkedResources>
324
+ <zeebe:linkedResource resourceId="scope-classify.md" bindingType="latest" resourceType="GenericScript" linkName="prompt" />
325
+ </zeebe:linkedResources>
326
+ <zeebe:properties>
327
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="PrScopeClassifyIn" />
328
+ <zeebe:property name="io.nanobpm.dataEnvelope.out" value="PrScopeClassifyOut" />
329
+ </zeebe:properties>
330
+ <zeebe:ioMapping>
331
+ <zeebe:output source="=null" target="scopeAnswer" />
332
+ </zeebe:ioMapping>
333
+ </bpmn:extensionElements>
334
+ <bpmn:incoming>f_convergeOk</bpmn:incoming>
335
+ <bpmn:outgoing>f_toScopeGate</bpmn:outgoing>
336
+ </bpmn:serviceTask>
337
+ <bpmn:exclusiveGateway id="gw-scope-gate" name="scope delivered?" default="f_scopeOk">
338
+ <bpmn:incoming>f_toScopeGate</bpmn:incoming>
339
+ <bpmn:outgoing>f_scopeBlocked</bpmn:outgoing>
340
+ <bpmn:outgoing>f_scopeOk</bpmn:outgoing>
341
+ </bpmn:exclusiveGateway>
342
+ <bpmn:serviceTask id="persist-escalation-scope" name="Escalate: scope integrity">
343
+ <bpmn:extensionElements>
344
+ <zeebe:taskDefinition type="pr.persist-escalation" />
345
+ <zeebe:properties>
346
+ <zeebe:property name="io.nanobpm.dataEnvelope.in" value="EscalationIn" />
347
+ <zeebe:property name="io.nanobpm.dataEnvelope.out" value="EscalationOut" />
348
+ </zeebe:properties>
349
+ <zeebe:ioMapping>
350
+ <zeebe:input source="=&#34;blocked&#34;" target="status" />
351
+ <zeebe:input source="=false" target="recordRound" />
352
+ <zeebe:input source="=scopeBlockReason" target="question" />
353
+ <zeebe:output source="=true" target="scopePending" />
354
+ </zeebe:ioMapping>
355
+ </bpmn:extensionElements>
356
+ <bpmn:incoming>f_scopeBlocked</bpmn:incoming>
357
+ <bpmn:outgoing>f_scopeEscGate</bpmn:outgoing>
358
+ </bpmn:serviceTask>
313
359
  <bpmn:endEvent id="End" name="Converged">
314
360
  <bpmn:incoming>f_finalize</bpmn:incoming>
315
361
  </bpmn:endEvent>
@@ -322,7 +368,13 @@
322
368
  <bpmn:sequenceFlow id="f_convergeBlocked" name="unaddressed comments" sourceRef="gw-converge-gate" targetRef="persist-escalation-blockedcomments">
323
369
  <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=convergeBlocked = true</bpmn:conditionExpression>
324
370
  </bpmn:sequenceFlow>
325
- <bpmn:sequenceFlow id="f_convergeOk" name="addressed / default" sourceRef="gw-converge-gate" targetRef="persist-converged" />
371
+ <bpmn:sequenceFlow id="f_convergeOk" name="addressed / default" sourceRef="gw-converge-gate" targetRef="classify-scope" />
372
+ <bpmn:sequenceFlow id="f_toScopeGate" sourceRef="classify-scope" targetRef="gw-scope-gate" />
373
+ <bpmn:sequenceFlow id="f_scopeBlocked" name="scope under-delivered" sourceRef="gw-scope-gate" targetRef="persist-escalation-scope">
374
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=scopeBlocked = true</bpmn:conditionExpression>
375
+ </bpmn:sequenceFlow>
376
+ <bpmn:sequenceFlow id="f_scopeOk" name="scope delivered / default" sourceRef="gw-scope-gate" targetRef="persist-converged" />
377
+ <bpmn:sequenceFlow id="f_scopeEscGate" sourceRef="persist-escalation-scope" targetRef="gw-escalated" />
326
378
  <bpmn:sequenceFlow id="f_blockedGate" sourceRef="persist-escalation-blockedcomments" targetRef="gw-escalated" />
327
379
  <bpmn:sequenceFlow id="f_addressed" name="addressed / default" sourceRef="gw-status" targetRef="gw-guard" />
328
380
  <bpmn:sequenceFlow id="f_waiting" name="waiting" sourceRef="gw-status" targetRef="gw-guard">
@@ -375,49 +427,49 @@
375
427
  </bpmndi:BPMNLabel>
376
428
  </bpmndi:BPMNShape>
377
429
  <bpmndi:BPMNShape id="BPMNShape_gw-guard" bpmnElement="gw-guard" isMarkerVisible="true">
378
- <dc:Bounds x="591" y="415" width="50" height="50" />
430
+ <dc:Bounds x="591" y="575" width="50" height="50" />
379
431
  <bpmndi:BPMNLabel>
380
- <dc:Bounds x="574" y="470" width="85" height="14" />
432
+ <dc:Bounds x="574" y="630" width="85" height="14" />
381
433
  </bpmndi:BPMNLabel>
382
434
  </bpmndi:BPMNShape>
383
435
  <bpmndi:BPMNShape id="BPMNShape_persist-round" bpmnElement="persist-round">
384
- <dc:Bounds x="766" y="400" width="100" height="80" />
436
+ <dc:Bounds x="766" y="560" width="100" height="80" />
385
437
  </bpmndi:BPMNShape>
386
438
  <bpmndi:BPMNShape id="BPMNShape_check-progress" bpmnElement="check-progress">
387
- <dc:Bounds x="966" y="400" width="100" height="80" />
439
+ <dc:Bounds x="966" y="560" width="100" height="80" />
388
440
  </bpmndi:BPMNShape>
389
441
  <bpmndi:BPMNShape id="BPMNShape_gw-progress" bpmnElement="gw-progress" isMarkerVisible="true">
390
- <dc:Bounds x="1166" y="415" width="50" height="50" />
442
+ <dc:Bounds x="1166" y="575" width="50" height="50" />
391
443
  <bpmndi:BPMNLabel>
392
- <dc:Bounds x="1161" y="382" width="60" height="28" />
444
+ <dc:Bounds x="1161" y="542" width="60" height="28" />
393
445
  </bpmndi:BPMNLabel>
394
446
  </bpmndi:BPMNShape>
395
447
  <bpmndi:BPMNShape id="BPMNShape_persist-escalation-noprogress" bpmnElement="persist-escalation-noprogress">
396
- <dc:Bounds x="1316" y="720" width="100" height="80" />
448
+ <dc:Bounds x="1316" y="880" width="100" height="80" />
397
449
  </bpmndi:BPMNShape>
398
450
  <bpmndi:BPMNShape id="BPMNShape_gw-review-wait" bpmnElement="gw-review-wait" isMarkerVisible="true">
399
- <dc:Bounds x="1341" y="415" width="50" height="50" />
451
+ <dc:Bounds x="1341" y="575" width="50" height="50" />
400
452
  <bpmndi:BPMNLabel>
401
- <dc:Bounds x="1322" y="382" width="88" height="28" />
453
+ <dc:Bounds x="1322" y="542" width="88" height="28" />
402
454
  </bpmndi:BPMNLabel>
403
455
  </bpmndi:BPMNShape>
404
456
  <bpmndi:BPMNShape id="BPMNShape_wait-review" bpmnElement="wait-review">
405
- <dc:Bounds x="1516" y="422" width="36" height="36" />
457
+ <dc:Bounds x="1516" y="582" width="36" height="36" />
406
458
  <bpmndi:BPMNLabel>
407
- <dc:Bounds x="1490" y="389" width="88" height="28" />
459
+ <dc:Bounds x="1490" y="549" width="88" height="28" />
408
460
  </bpmndi:BPMNLabel>
409
461
  </bpmndi:BPMNShape>
410
462
  <bpmndi:BPMNShape id="BPMNShape_wait-review-timeout" bpmnElement="wait-review-timeout">
411
- <dc:Bounds x="1516" y="582" width="36" height="36" />
463
+ <dc:Bounds x="1516" y="742" width="36" height="36" />
412
464
  <bpmndi:BPMNLabel>
413
- <dc:Bounds x="1506" y="623" width="56" height="42" />
465
+ <dc:Bounds x="1506" y="783" width="56" height="42" />
414
466
  </bpmndi:BPMNLabel>
415
467
  </bpmndi:BPMNShape>
416
468
  <bpmndi:BPMNShape id="BPMNShape_persist-review-stalled" bpmnElement="persist-review-stalled">
417
- <dc:Bounds x="1652" y="560" width="100" height="80" />
469
+ <dc:Bounds x="1652" y="720" width="100" height="80" />
418
470
  </bpmndi:BPMNShape>
419
471
  <bpmndi:BPMNShape id="BPMNShape_persist-escalation" bpmnElement="persist-escalation">
420
- <dc:Bounds x="566" y="1040" width="100" height="80" />
472
+ <dc:Bounds x="566" y="1200" width="100" height="80" />
421
473
  </bpmndi:BPMNShape>
422
474
  <bpmndi:BPMNShape id="BPMNShape_gw-escalated" bpmnElement="gw-escalated" isMarkerVisible="true">
423
475
  <dc:Bounds x="1852" y="255" width="50" height="50" />
@@ -426,7 +478,7 @@
426
478
  </bpmndi:BPMNLabel>
427
479
  </bpmndi:BPMNShape>
428
480
  <bpmndi:BPMNShape id="BPMNShape_persist-escalation-maxrounds" bpmnElement="persist-escalation-maxrounds">
429
- <dc:Bounds x="766" y="880" width="100" height="80" />
481
+ <dc:Bounds x="766" y="1040" width="100" height="80" />
430
482
  </bpmndi:BPMNShape>
431
483
  <bpmndi:BPMNShape id="BPMNShape_wait-answer" bpmnElement="wait-answer">
432
484
  <dc:Bounds x="2002" y="240" width="100" height="80" />
@@ -435,7 +487,7 @@
435
487
  <dc:Bounds x="2202" y="240" width="100" height="80" />
436
488
  </bpmndi:BPMNShape>
437
489
  <bpmndi:BPMNShape id="BPMNShape_persist-converged" bpmnElement="persist-converged">
438
- <dc:Bounds x="966" y="80" width="100" height="80" />
490
+ <dc:Bounds x="1316" y="80" width="100" height="80" />
439
491
  </bpmndi:BPMNShape>
440
492
  <bpmndi:BPMNShape id="BPMNShape_check-converge" bpmnElement="check-converge">
441
493
  <dc:Bounds x="566" y="80" width="100" height="80" />
@@ -443,16 +495,28 @@
443
495
  <bpmndi:BPMNShape id="BPMNShape_gw-converge-gate" bpmnElement="gw-converge-gate" isMarkerVisible="true">
444
496
  <dc:Bounds x="791" y="95" width="50" height="50" />
445
497
  <bpmndi:BPMNLabel>
446
- <dc:Bounds x="779" y="62" width="74" height="28" />
498
+ <dc:Bounds x="779" y="150" width="74" height="28" />
447
499
  </bpmndi:BPMNLabel>
448
500
  </bpmndi:BPMNShape>
449
501
  <bpmndi:BPMNShape id="BPMNShape_persist-escalation-blockedcomments" bpmnElement="persist-escalation-blockedcomments">
450
- <dc:Bounds x="966" y="240" width="100" height="80" />
502
+ <dc:Bounds x="966" y="400" width="100" height="80" />
503
+ </bpmndi:BPMNShape>
504
+ <bpmndi:BPMNShape id="BPMNShape_classify-scope" bpmnElement="classify-scope">
505
+ <dc:Bounds x="966" y="80" width="100" height="80" />
506
+ </bpmndi:BPMNShape>
507
+ <bpmndi:BPMNShape id="BPMNShape_gw-scope-gate" bpmnElement="gw-scope-gate" isMarkerVisible="true">
508
+ <dc:Bounds x="1166" y="95" width="50" height="50" />
509
+ <bpmndi:BPMNLabel>
510
+ <dc:Bounds x="1154" y="62" width="74" height="28" />
511
+ </bpmndi:BPMNLabel>
512
+ </bpmndi:BPMNShape>
513
+ <bpmndi:BPMNShape id="BPMNShape_persist-escalation-scope" bpmnElement="persist-escalation-scope">
514
+ <dc:Bounds x="1316" y="240" width="100" height="80" />
451
515
  </bpmndi:BPMNShape>
452
516
  <bpmndi:BPMNShape id="BPMNShape_End" bpmnElement="End">
453
- <dc:Bounds x="1173" y="102" width="36" height="36" />
517
+ <dc:Bounds x="1516" y="102" width="36" height="36" />
454
518
  <bpmndi:BPMNLabel>
455
- <dc:Bounds x="1157" y="143" width="69" height="14" />
519
+ <dc:Bounds x="1500" y="143" width="69" height="14" />
456
520
  </bpmndi:BPMNLabel>
457
521
  </bpmndi:BPMNShape>
458
522
  <bpmndi:BPMNEdge id="BPMNEdge_f_start" bpmnElement="f_start">
@@ -478,131 +542,156 @@
478
542
  <di:waypoint x="841" y="120" />
479
543
  <di:waypoint x="966" y="120" />
480
544
  <bpmndi:BPMNLabel>
481
- <dc:Bounds x="865" y="87" width="78" height="28" />
545
+ <dc:Bounds x="855" y="87" width="78" height="28" />
482
546
  </bpmndi:BPMNLabel>
483
547
  </bpmndi:BPMNEdge>
484
- <bpmndi:BPMNEdge id="BPMNEdge_f_finalize" bpmnElement="f_finalize">
548
+ <bpmndi:BPMNEdge id="BPMNEdge_f_toScopeGate" bpmnElement="f_toScopeGate">
485
549
  <di:waypoint x="1066" y="120" />
486
- <di:waypoint x="1173" y="120" />
550
+ <di:waypoint x="1166" y="120" />
551
+ </bpmndi:BPMNEdge>
552
+ <bpmndi:BPMNEdge id="BPMNEdge_f_scopeOk" bpmnElement="f_scopeOk">
553
+ <di:waypoint x="1216" y="120" />
554
+ <di:waypoint x="1316" y="120" />
555
+ <bpmndi:BPMNLabel>
556
+ <dc:Bounds x="1227" y="125" width="78" height="42" />
557
+ </bpmndi:BPMNLabel>
558
+ </bpmndi:BPMNEdge>
559
+ <bpmndi:BPMNEdge id="BPMNEdge_f_finalize" bpmnElement="f_finalize">
560
+ <di:waypoint x="1416" y="120" />
561
+ <di:waypoint x="1516" y="120" />
487
562
  </bpmndi:BPMNEdge>
488
563
  <bpmndi:BPMNEdge id="BPMNEdge_f_guardOk" bpmnElement="f_guardOk">
489
- <di:waypoint x="641" y="440" />
490
- <di:waypoint x="766" y="440" />
564
+ <di:waypoint x="641" y="600" />
565
+ <di:waypoint x="766" y="600" />
491
566
  <bpmndi:BPMNLabel>
492
- <dc:Bounds x="664" y="418" width="60" height="14" />
567
+ <dc:Bounds x="664" y="578" width="60" height="14" />
493
568
  </bpmndi:BPMNLabel>
494
569
  </bpmndi:BPMNEdge>
495
570
  <bpmndi:BPMNEdge id="BPMNEdge_f_roundWait" bpmnElement="f_roundWait">
496
- <di:waypoint x="866" y="440" />
497
- <di:waypoint x="966" y="440" />
571
+ <di:waypoint x="866" y="600" />
572
+ <di:waypoint x="966" y="600" />
498
573
  </bpmndi:BPMNEdge>
499
574
  <bpmndi:BPMNEdge id="BPMNEdge_f_checkGate" bpmnElement="f_checkGate">
500
- <di:waypoint x="1066" y="440" />
501
- <di:waypoint x="1166" y="440" />
575
+ <di:waypoint x="1066" y="600" />
576
+ <di:waypoint x="1166" y="600" />
502
577
  </bpmndi:BPMNEdge>
503
578
  <bpmndi:BPMNEdge id="BPMNEdge_f_progressOk" bpmnElement="f_progressOk">
504
- <di:waypoint x="1216" y="440" />
505
- <di:waypoint x="1341" y="440" />
579
+ <di:waypoint x="1216" y="600" />
580
+ <di:waypoint x="1341" y="600" />
506
581
  <bpmndi:BPMNLabel>
507
- <dc:Bounds x="1241" y="407" width="71" height="28" />
582
+ <dc:Bounds x="1241" y="567" width="71" height="28" />
508
583
  </bpmndi:BPMNLabel>
509
584
  </bpmndi:BPMNEdge>
510
585
  <bpmndi:BPMNEdge id="BPMNEdge_f_toReviewWait" bpmnElement="f_toReviewWait">
511
- <di:waypoint x="1391" y="440" />
512
- <di:waypoint x="1516" y="440" />
586
+ <di:waypoint x="1391" y="600" />
587
+ <di:waypoint x="1516" y="600" />
513
588
  </bpmndi:BPMNEdge>
514
589
  <bpmndi:BPMNEdge id="BPMNEdge_f_reviewLoop" bpmnElement="f_reviewLoop">
515
- <di:waypoint x="1534" y="458" />
516
- <di:waypoint x="1534" y="500" />
517
- <di:waypoint x="266" y="500" />
590
+ <di:waypoint x="1534" y="618" />
591
+ <di:waypoint x="1534" y="660" />
592
+ <di:waypoint x="266" y="660" />
518
593
  <di:waypoint x="266" y="160" />
519
594
  </bpmndi:BPMNEdge>
520
595
  <bpmndi:BPMNEdge id="BPMNEdge_f_escReenter" bpmnElement="f_escReenter">
521
596
  <di:waypoint x="1877" y="255" />
522
597
  <di:waypoint x="1877" y="220" />
523
598
  <di:waypoint x="616" y="220" />
524
- <di:waypoint x="616" y="415" />
599
+ <di:waypoint x="616" y="575" />
525
600
  <bpmndi:BPMNLabel>
526
- <dc:Bounds x="1410" y="173" width="74" height="42" />
601
+ <dc:Bounds x="867" y="173" width="74" height="42" />
527
602
  </bpmndi:BPMNLabel>
528
603
  </bpmndi:BPMNEdge>
529
604
  <bpmndi:BPMNEdge id="BPMNEdge_f_convergeBlocked" bpmnElement="f_convergeBlocked">
530
- <di:waypoint x="816" y="145" />
531
- <di:waypoint x="816" y="220" />
532
- <di:waypoint x="1016" y="220" />
533
- <di:waypoint x="1016" y="240" />
605
+ <di:waypoint x="841" y="120" />
606
+ <di:waypoint x="946" y="120" />
607
+ <di:waypoint x="946" y="440" />
608
+ <di:waypoint x="966" y="440" />
609
+ <bpmndi:BPMNLabel>
610
+ <dc:Bounds x="951" y="266" width="81" height="28" />
611
+ </bpmndi:BPMNLabel>
612
+ </bpmndi:BPMNEdge>
613
+ <bpmndi:BPMNEdge id="BPMNEdge_f_scopeBlocked" bpmnElement="f_scopeBlocked">
614
+ <di:waypoint x="1191" y="145" />
615
+ <di:waypoint x="1191" y="220" />
616
+ <di:waypoint x="1366" y="220" />
617
+ <di:waypoint x="1366" y="240" />
534
618
  <bpmndi:BPMNLabel>
535
- <dc:Bounds x="821" y="169" width="81" height="28" />
619
+ <dc:Bounds x="1098" y="162" width="88" height="42" />
536
620
  </bpmndi:BPMNLabel>
537
621
  </bpmndi:BPMNEdge>
538
622
  <bpmndi:BPMNEdge id="BPMNEdge_f_addressed" bpmnElement="f_addressed">
539
623
  <di:waypoint x="441" y="145" />
540
- <di:waypoint x="441" y="440" />
541
- <di:waypoint x="591" y="440" />
624
+ <di:waypoint x="441" y="600" />
625
+ <di:waypoint x="591" y="600" />
542
626
  <bpmndi:BPMNLabel>
543
- <dc:Bounds x="446" y="279" width="78" height="28" />
627
+ <dc:Bounds x="446" y="359" width="78" height="28" />
544
628
  </bpmndi:BPMNLabel>
545
629
  </bpmndi:BPMNEdge>
546
630
  <bpmndi:BPMNEdge id="BPMNEdge_f_waiting" bpmnElement="f_waiting">
547
631
  <di:waypoint x="441" y="145" />
548
- <di:waypoint x="441" y="440" />
549
- <di:waypoint x="591" y="440" />
632
+ <di:waypoint x="441" y="600" />
633
+ <di:waypoint x="591" y="600" />
550
634
  <bpmndi:BPMNLabel>
551
- <dc:Bounds x="380" y="286" width="56" height="14" />
635
+ <dc:Bounds x="380" y="366" width="56" height="14" />
552
636
  </bpmndi:BPMNLabel>
553
637
  </bpmndi:BPMNEdge>
554
638
  <bpmndi:BPMNEdge id="BPMNEdge_f_escalate" bpmnElement="f_escalate">
555
639
  <di:waypoint x="441" y="145" />
556
- <di:waypoint x="441" y="1080" />
557
- <di:waypoint x="566" y="1080" />
640
+ <di:waypoint x="441" y="1240" />
641
+ <di:waypoint x="566" y="1240" />
558
642
  <bpmndi:BPMNLabel>
559
- <dc:Bounds x="446" y="746" width="81" height="28" />
643
+ <dc:Bounds x="446" y="906" width="81" height="28" />
560
644
  </bpmndi:BPMNLabel>
561
645
  </bpmndi:BPMNEdge>
562
646
  <bpmndi:BPMNEdge id="BPMNEdge_f_guardMax" bpmnElement="f_guardMax">
563
- <di:waypoint x="641" y="440" />
564
- <di:waypoint x="746" y="440" />
565
- <di:waypoint x="746" y="920" />
566
- <di:waypoint x="766" y="920" />
647
+ <di:waypoint x="641" y="600" />
648
+ <di:waypoint x="746" y="600" />
649
+ <di:waypoint x="746" y="1080" />
650
+ <di:waypoint x="766" y="1080" />
567
651
  <bpmndi:BPMNLabel>
568
- <dc:Bounds x="751" y="673" width="74" height="14" />
652
+ <dc:Bounds x="751" y="833" width="74" height="14" />
569
653
  </bpmndi:BPMNLabel>
570
654
  </bpmndi:BPMNEdge>
571
655
  <bpmndi:BPMNEdge id="BPMNEdge_f_noProgress" bpmnElement="f_noProgress">
572
- <di:waypoint x="1216" y="440" />
573
- <di:waypoint x="1296" y="440" />
574
- <di:waypoint x="1296" y="760" />
575
- <di:waypoint x="1316" y="760" />
656
+ <di:waypoint x="1216" y="600" />
657
+ <di:waypoint x="1296" y="600" />
658
+ <di:waypoint x="1296" y="920" />
659
+ <di:waypoint x="1316" y="920" />
576
660
  <bpmndi:BPMNLabel>
577
- <dc:Bounds x="1213" y="593" width="78" height="14" />
661
+ <dc:Bounds x="1213" y="753" width="78" height="14" />
578
662
  </bpmndi:BPMNLabel>
579
663
  </bpmndi:BPMNEdge>
580
664
  <bpmndi:BPMNEdge id="BPMNEdge_f_toReviewTimeout" bpmnElement="f_toReviewTimeout">
581
- <di:waypoint x="1366" y="465" />
582
- <di:waypoint x="1366" y="600" />
583
- <di:waypoint x="1516" y="600" />
665
+ <di:waypoint x="1366" y="625" />
666
+ <di:waypoint x="1366" y="760" />
667
+ <di:waypoint x="1516" y="760" />
584
668
  </bpmndi:BPMNEdge>
585
- <bpmndi:BPMNEdge id="BPMNEdge_f_blockedGate" bpmnElement="f_blockedGate">
586
- <di:waypoint x="1066" y="280" />
669
+ <bpmndi:BPMNEdge id="BPMNEdge_f_scopeEscGate" bpmnElement="f_scopeEscGate">
670
+ <di:waypoint x="1416" y="280" />
587
671
  <di:waypoint x="1852" y="280" />
588
672
  </bpmndi:BPMNEdge>
673
+ <bpmndi:BPMNEdge id="BPMNEdge_f_blockedGate" bpmnElement="f_blockedGate">
674
+ <di:waypoint x="1066" y="440" />
675
+ <di:waypoint x="1877" y="440" />
676
+ <di:waypoint x="1877" y="305" />
677
+ </bpmndi:BPMNEdge>
589
678
  <bpmndi:BPMNEdge id="BPMNEdge_f_noprogressGate" bpmnElement="f_noprogressGate">
590
- <di:waypoint x="1416" y="760" />
591
- <di:waypoint x="1877" y="760" />
679
+ <di:waypoint x="1416" y="920" />
680
+ <di:waypoint x="1877" y="920" />
592
681
  <di:waypoint x="1877" y="305" />
593
682
  </bpmndi:BPMNEdge>
594
683
  <bpmndi:BPMNEdge id="BPMNEdge_f_reviewStalled" bpmnElement="f_reviewStalled">
595
- <di:waypoint x="1552" y="600" />
596
- <di:waypoint x="1652" y="600" />
684
+ <di:waypoint x="1552" y="760" />
685
+ <di:waypoint x="1652" y="760" />
597
686
  </bpmndi:BPMNEdge>
598
687
  <bpmndi:BPMNEdge id="BPMNEdge_f_stalledGate" bpmnElement="f_stalledGate">
599
- <di:waypoint x="1752" y="600" />
600
- <di:waypoint x="1877" y="600" />
688
+ <di:waypoint x="1752" y="760" />
689
+ <di:waypoint x="1877" y="760" />
601
690
  <di:waypoint x="1877" y="305" />
602
691
  </bpmndi:BPMNEdge>
603
692
  <bpmndi:BPMNEdge id="BPMNEdge_f_escGate" bpmnElement="f_escGate">
604
- <di:waypoint x="666" y="1080" />
605
- <di:waypoint x="1877" y="1080" />
693
+ <di:waypoint x="666" y="1240" />
694
+ <di:waypoint x="1877" y="1240" />
606
695
  <di:waypoint x="1877" y="305" />
607
696
  </bpmndi:BPMNEdge>
608
697
  <bpmndi:BPMNEdge id="BPMNEdge_f_escWait" bpmnElement="f_escWait">
@@ -610,8 +699,8 @@
610
699
  <di:waypoint x="2002" y="280" />
611
700
  </bpmndi:BPMNEdge>
612
701
  <bpmndi:BPMNEdge id="BPMNEdge_f_maxGate" bpmnElement="f_maxGate">
613
- <di:waypoint x="866" y="920" />
614
- <di:waypoint x="1877" y="920" />
702
+ <di:waypoint x="866" y="1080" />
703
+ <di:waypoint x="1877" y="1080" />
615
704
  <di:waypoint x="1877" y="305" />
616
705
  </bpmndi:BPMNEdge>
617
706
  <bpmndi:BPMNEdge id="BPMNEdge_f_answerRecord" bpmnElement="f_answerRecord">
@@ -86,26 +86,28 @@ against the wrong base will not be merged into the epic.
86
86
 
87
87
  ## Closing keywords vs. scope splits — don't close a broader-scoped parent
88
88
 
89
- The convergence loop runs a deterministic **scope-integrity gate** on your PR
90
- before it can merge (`workers/converge-gate` `app/scopeGuard.ts`). It exists
91
- because a parity slice was once silently under-delivered: an agent shipped one
92
- half, documented the deferred remainder honestly in a `## Scope` section, yet
93
- still `Closes #N`'d the broader parent and filed **no** follow-up. The issue read
94
- as done, `gh issue list` showed nothing outstanding, and a downstream consumer was
95
- blocked on exactly the deferred half. Two rules keep that from recurring — the
96
- gate **blocks and escalates to a human** if you break either:
89
+ The convergence loop runs a **scope-integrity classifier** on your PR before it
90
+ can merge (the `senior:scope-classify` agent, prompt
91
+ `resources/prompts/scope-classify.md`). It exists because a parity slice was once
92
+ silently under-delivered: an agent shipped one half, documented the deferred
93
+ remainder honestly in a `## Scope` section, yet still `Closes #N`'d the broader
94
+ parent and filed **no** follow-up. The issue read as done, `gh issue list` showed
95
+ nothing outstanding, and a downstream consumer was blocked on exactly the
96
+ deferred half. The classifier reads each closing-keyword issue's acceptance
97
+ criteria and **blocks and escalates to a human** only on a *genuine* untracked
98
+ under-delivery — not on the mere presence of the word "deferred". Two rules keep
99
+ you on the right side of it:
97
100
 
98
101
  1. **A `Closes/Fixes/Resolves #N` closing keyword means you delivered #N's FULL
99
102
  stated scope.** If you split scope — shipping only part and deferring the rest
100
103
  — do **not** close-keyword the parent. Use a non-closing ref instead
101
104
  (`Refs #N` / `Part of #N`) and **leave #N open** (or convert #N into a
102
- tracking/umbrella issue for the remainder). The gate flags any PR that both
103
- closes #N and also contains deferral prose (a `## Scope` section, "deferred",
104
- "out of scope").
105
+ tracking/umbrella issue for the remainder). The classifier flags a PR that
106
+ closes #N while leaving part of #N's stated scope undelivered and untracked.
105
107
  2. **A deferred remainder must be a FILED, tracked issue — never just prose.** If
106
108
  your PR defers part of its scope, **file a follow-up issue for each deferred
107
- item** and link it in the PR body with an explicit tracking marker the gate can
108
- see: `Deferred-to: #N`, `Tracked-in: #N`, or `Follow-up: #N`. A deferral that
109
+ item** and link it in the PR body with an explicit tracking marker the classifier
110
+ can see: `Deferred-to: #N`, `Tracked-in: #N`, or `Follow-up: #N`. A deferral that
109
111
  lives only in commit/PR/ADR text is an invisible, unclaimable drift surface.
110
112
 
111
113
  So: deliver the whole thing → `Closes #N`. Split it → `Refs #N`, file the