@nanobpm/nano-workforce 0.201.4 → 0.202.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/SPEC.md +104 -0
- package/app/agentOutputEnvelope.test.ts +464 -0
- package/app/agentic/README.md +48 -0
- package/app/agentic/claim-registry.test.ts +61 -0
- package/app/agentic/claim-registry.ts +35 -1
- package/app/agentic/families/claim.family.test.ts +216 -0
- package/app/agentic/families/claim.family.ts +100 -4
- package/app/contracts.ts +8 -0
- package/app/mergeLoopBehaviour.test.ts +208 -1
- package/docs/agentic-cockpit.md +34 -0
- package/package.json +1 -1
- package/resources/processes/convergence-loop.bpmn +108 -1
- package/resources/processes/merge-loop.bpmn +80 -2
|
@@ -89,13 +89,15 @@ const DEFAULT_VARS: Record<string, unknown> = {
|
|
|
89
89
|
mergeableRepollInterval: "PT2M",
|
|
90
90
|
mergeStallRounds: 0,
|
|
91
91
|
mergeStallMax: 3,
|
|
92
|
-
abandonBrief:
|
|
92
|
+
abandonBrief: "\n\n---\nAbort if cancelled: curl …",
|
|
93
93
|
failingChecksList: null,
|
|
94
94
|
status: null,
|
|
95
95
|
mergeState: null,
|
|
96
96
|
mergeStatus: null,
|
|
97
97
|
ciBlockedReconciled: null,
|
|
98
98
|
failingChecks: 0,
|
|
99
|
+
round: 2,
|
|
100
|
+
abandonUrl: "http://host/app/api/hooks/abandon?token=tok-seeded",
|
|
99
101
|
};
|
|
100
102
|
|
|
101
103
|
/**
|
|
@@ -303,6 +305,86 @@ test("a CONFLICTING PR whose poller never signalled reaches the rebase arm via t
|
|
|
303
305
|
.hasVariable("rebaseRound", 1);
|
|
304
306
|
});
|
|
305
307
|
|
|
308
|
+
test("a rebase agent echoing engine-owned timeout state cannot clobber it (#887)", async () => {
|
|
309
|
+
// Same guard class as fix-ci: the rebase agent must not reshape the seeded timers that later loop
|
|
310
|
+
// passes re-arm, nor forge `ciBlockedReconciled`. Drive to the rebase arm via the timeout path with
|
|
311
|
+
// the agent echoing a forged marker and tiny timeouts; the restore must pin the timers.
|
|
312
|
+
const engine = await boot({
|
|
313
|
+
responses: {
|
|
314
|
+
"pr.merge-stall-probe": { mergeState: "conflict", failingChecks: 0, failingChecksList: "" },
|
|
315
|
+
"senior:rebase": {
|
|
316
|
+
status: "rebased",
|
|
317
|
+
ciBlockedReconciled: true,
|
|
318
|
+
agentSlaTimeout: "PT1S",
|
|
319
|
+
landedWaitTimeout: "PT1S",
|
|
320
|
+
mergeableWaitTimeout: "PT1S",
|
|
321
|
+
mergeableRepollInterval: "PT1S",
|
|
322
|
+
},
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
await engine.publishMessage({ name: "deps-cleared", correlationKey: "pr-1" });
|
|
326
|
+
await engine.advanceTime(MERGEABLE_WAIT_MS + 1);
|
|
327
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
328
|
+
.isActive()
|
|
329
|
+
.hasCompletedElements("rebase")
|
|
330
|
+
.hasVariable("agentSlaTimeout", "PT30M")
|
|
331
|
+
.hasVariable("landedWaitTimeout", "PT30M")
|
|
332
|
+
.hasVariable("mergeableWaitTimeout", "PT30M")
|
|
333
|
+
.hasVariable("mergeableRepollInterval", "PT2M");
|
|
334
|
+
// The forged lifecycle marker was pinned out too (the rebase path never reconciles).
|
|
335
|
+
assert(instanceVars(engine).ciBlockedReconciled !== true, "a rebase agent must not forge ciBlockedReconciled:true");
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test("a rebase agent echoing round/abandonUrl cannot corrupt the converged round or the abandon token (#887)", async () => {
|
|
339
|
+
// Same guard class as fix-ci: `round`/`abandonUrl` are seeded once and consumed by `pr.merge`
|
|
340
|
+
// after a successful rebase re-arms the poller. The restore must pin both against an agent echo.
|
|
341
|
+
const engine = await boot({
|
|
342
|
+
responses: {
|
|
343
|
+
"pr.merge-stall-probe": { mergeState: "conflict", failingChecks: 0, failingChecksList: "" },
|
|
344
|
+
"senior:rebase": { status: "rebased", round: 99, abandonUrl: "http://evil.test/abandon?token=forged" },
|
|
345
|
+
},
|
|
346
|
+
});
|
|
347
|
+
await engine.publishMessage({ name: "deps-cleared", correlationKey: "pr-1" });
|
|
348
|
+
await engine.advanceTime(MERGEABLE_WAIT_MS + 1);
|
|
349
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
350
|
+
.isActive()
|
|
351
|
+
.hasCompletedElements("rebase")
|
|
352
|
+
.hasVariable("round", 2)
|
|
353
|
+
.hasVariable("abandonUrl", "http://host/app/api/hooks/abandon?token=tok-seeded");
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
test("a rebase agent echoing abandonBrief cannot corrupt the seeded abort brief (#887 round 5)", async () => {
|
|
357
|
+
// `abandonBrief` feeds the fix-ci/rebase `appendPrompt` input on the NEXT re-arm; a non-string
|
|
358
|
+
// echo would make that later prompt mapping carry a non-string brief. The restore must pin it.
|
|
359
|
+
const engine = await boot({
|
|
360
|
+
responses: {
|
|
361
|
+
"pr.merge-stall-probe": { mergeState: "conflict", failingChecks: 0, failingChecksList: "" },
|
|
362
|
+
"senior:rebase": { status: "rebased", abandonBrief: 42 },
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
await engine.publishMessage({ name: "deps-cleared", correlationKey: "pr-1" });
|
|
366
|
+
await engine.advanceTime(MERGEABLE_WAIT_MS + 1);
|
|
367
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
368
|
+
.isActive()
|
|
369
|
+
.hasCompletedElements("rebase")
|
|
370
|
+
.hasVariable("abandonBrief", "\n\n---\nAbort if cancelled: curl …");
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
test("a fix-ci agent echoing abandonBrief cannot corrupt the seeded abort brief (#887 round 5)", async () => {
|
|
374
|
+
const engine = await boot({
|
|
375
|
+
responses: {
|
|
376
|
+
"pr.merge-stall-probe": { mergeState: "blocked", failingChecks: 1, failingChecksList: "build" },
|
|
377
|
+
"senior:fix-ci": { status: "fixed", abandonBrief: 42 },
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
await engine.publishMessage({ name: "deps-cleared", correlationKey: "pr-1" });
|
|
381
|
+
await engine.advanceTime(MERGEABLE_WAIT_MS + 1);
|
|
382
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
383
|
+
.isActive()
|
|
384
|
+
.hasCompletedElements("merge-stall-probe", "fix-ci")
|
|
385
|
+
.hasVariable("abandonBrief", "\n\n---\nAbort if cancelled: curl …");
|
|
386
|
+
});
|
|
387
|
+
|
|
306
388
|
test("a blocked PR probed on timeout reaches the CI-fix arm via the timeout path (#636)", async () => {
|
|
307
389
|
const engine = await boot({
|
|
308
390
|
responses: {
|
|
@@ -529,6 +611,67 @@ test("a blocked CI verdict with nothing pushed reconciles once before escalating
|
|
|
529
611
|
assert(!completedElementIds(engine).has("merge-esc-attempt"), "the first block episode must reconcile, not page a human");
|
|
530
612
|
});
|
|
531
613
|
|
|
614
|
+
test("a fix-ci agent echoing ciBlockedReconciled:true cannot skip the one-shot ground-truth reconcile (#887)", async () => {
|
|
615
|
+
// `ciBlockedReconciled` is an engine-owned lifecycle marker (arm-merge seeds it null; ci-reconcile
|
|
616
|
+
// sets it true). gw-ci-blocked reconciles exactly once per episode while it is != true. If the agent's
|
|
617
|
+
// completion could echo `ciBlockedReconciled:true`, a `{status:"blocked", pushed:false}` verdict would
|
|
618
|
+
// skip the mandatory first reconcile and page a human immediately. The snapshot/restore guard pins it,
|
|
619
|
+
// so the engine still reconciles once.
|
|
620
|
+
const engine = await boot({
|
|
621
|
+
responses: { "senior:fix-ci": { status: "blocked", pushed: false, ciBlockedReconciled: true } },
|
|
622
|
+
});
|
|
623
|
+
await driveToCiFix(engine);
|
|
624
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
625
|
+
.isActive()
|
|
626
|
+
.hasActiveElement("wait-mergeable")
|
|
627
|
+
.hasCompletedElements("ci-reconcile") // the reconcile STILL runs — the agent's echo was pinned out
|
|
628
|
+
.hasVariable("ciBlockedReconciled", true);
|
|
629
|
+
assert(!completedElementIds(engine).has("merge-esc-attempt"), "an agent-forged reconciled flag must not skip the first reconcile");
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
test("a fix-ci agent echoing seeded timeouts cannot clobber the re-armed merge/SLA timers (#887)", async () => {
|
|
633
|
+
// The seeded timeout/interval config (agentSlaTimeout, landedWaitTimeout, mergeableWaitTimeout,
|
|
634
|
+
// mergeableRepollInterval) drives timers re-armed on every loop pass. A `reattempt` re-arms the
|
|
635
|
+
// merge wait, so a clobbered timeout would silently reshape the next wait. The guard restores them.
|
|
636
|
+
const engine = await boot({
|
|
637
|
+
responses: {
|
|
638
|
+
"senior:fix-ci": {
|
|
639
|
+
status: "reattempt",
|
|
640
|
+
agentSlaTimeout: "PT1S",
|
|
641
|
+
landedWaitTimeout: "PT1S",
|
|
642
|
+
mergeableWaitTimeout: "PT1S",
|
|
643
|
+
mergeableRepollInterval: "PT1S",
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
});
|
|
647
|
+
await driveToCiFix(engine);
|
|
648
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
649
|
+
.isActive()
|
|
650
|
+
.hasActiveElement("wait-mergeable")
|
|
651
|
+
.hasVariable("agentSlaTimeout", "PT30M")
|
|
652
|
+
.hasVariable("landedWaitTimeout", "PT30M")
|
|
653
|
+
.hasVariable("mergeableWaitTimeout", "PT30M")
|
|
654
|
+
.hasVariable("mergeableRepollInterval", "PT2M");
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
test("a fix-ci agent echoing round/abandonUrl cannot corrupt the converged round or the abandon token (#887)", async () => {
|
|
658
|
+
// `round` (the converged round recorded by ensurePr) and `abandonUrl` (the cooperative-abandon
|
|
659
|
+
// capability URL) are seeded once and consumed directly by `pr.merge` (attempt-merge). A fix-ci
|
|
660
|
+
// completion echoing either would corrupt the recorded round or replace the abandon token. The
|
|
661
|
+
// snapshot/restore guard pins both.
|
|
662
|
+
const engine = await boot({
|
|
663
|
+
responses: {
|
|
664
|
+
"senior:fix-ci": { status: "reattempt", round: 99, abandonUrl: "http://evil.test/abandon?token=forged" },
|
|
665
|
+
},
|
|
666
|
+
});
|
|
667
|
+
await driveToCiFix(engine);
|
|
668
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
669
|
+
.isActive()
|
|
670
|
+
.hasActiveElement("wait-mergeable")
|
|
671
|
+
.hasVariable("round", 2)
|
|
672
|
+
.hasVariable("abandonUrl", "http://host/app/api/hooks/abandon?token=tok-seeded");
|
|
673
|
+
});
|
|
674
|
+
|
|
532
675
|
test("a blocked CI verdict that already pushed escalates with a could-not-fix question", async () => {
|
|
533
676
|
const engine = await boot({ responses: { "senior:fix-ci": { status: "blocked", pushed: true } } });
|
|
534
677
|
await driveToCiFix(engine);
|
|
@@ -602,6 +745,70 @@ test("a no-verdict rebase result reconciles from ground truth, not escalation (#
|
|
|
602
745
|
assert(!completedElementIds(engine).has("merge-esc-attempt"), "a missing rebase status must not escalate");
|
|
603
746
|
});
|
|
604
747
|
|
|
748
|
+
// ---------------------------------------------------------------------------
|
|
749
|
+
// #887 — an external-agent completion must not clobber engine-owned counters
|
|
750
|
+
// ---------------------------------------------------------------------------
|
|
751
|
+
// The engine merges EVERY variable an external agent returns into process scope unfiltered, so a
|
|
752
|
+
// `senior:fix-ci`/`senior:rebase` agent echoing a loop counter (`ciFixRound`, `rebaseRound`, …) with
|
|
753
|
+
// the wrong type/value would corrupt it — and because the counter feeds the task's own `+ 1`
|
|
754
|
+
// increment and the `ciFixRound < ciFixMax` / `rebaseRound < rebaseMax` guards, a string echo wedges
|
|
755
|
+
// the sub-process on a "comparison/arithmetic not defined for string and number" incident. The fix
|
|
756
|
+
// snapshots each engine-owned counter into a task-local input before the agent runs and restores it
|
|
757
|
+
// on the task output (driving the increment from the snapshot), so the agent can never alter it.
|
|
758
|
+
|
|
759
|
+
test("a fix-ci agent echoing ciFixRound:\"9\" cannot clobber the counter or wedge the increment (#887)", async () => {
|
|
760
|
+
const engine = await boot({ responses: { "senior:fix-ci": { status: "fixed", ciFixRound: "9", ciFixMax: "1" } } });
|
|
761
|
+
await driveToCiFix(engine);
|
|
762
|
+
assertEquals((await engine.searchIncidents()).length, 0, "the agent echo must not raise an incident");
|
|
763
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
764
|
+
.isActive()
|
|
765
|
+
.hasCompletedElements("fix-ci")
|
|
766
|
+
.hasVariable("ciFixRound", 1) // the engine increment (0 → 1), NOT the agent's "9"
|
|
767
|
+
.hasVariable("ciFixMax", 3); // the budget ceiling is engine-owned, unclobbered
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
test("a rebase agent echoing rebaseRound:\"9\" cannot clobber the counter or wedge the increment (#887)", async () => {
|
|
771
|
+
const engine = await boot({ responses: { "senior:rebase": { status: "rebased", rebaseRound: "9", rebaseMax: "1" } } });
|
|
772
|
+
await driveToRebase(engine);
|
|
773
|
+
assertEquals((await engine.searchIncidents()).length, 0, "the agent echo must not raise an incident");
|
|
774
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
775
|
+
.isActive()
|
|
776
|
+
.hasCompletedElements("rebase")
|
|
777
|
+
.hasVariable("rebaseRound", 1) // the engine increment (0 → 1), NOT the agent's "9"
|
|
778
|
+
.hasVariable("rebaseMax", 3); // the budget ceiling is engine-owned, unclobbered
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
test("a fix-ci agent echoing PR identity inputs cannot clobber them (#887)", async () => {
|
|
782
|
+
// `repo`/`prNumber`/`prUrl` are the agent's declared *inputs* (FixCiIn), not its outputs — but the
|
|
783
|
+
// engine merges a completion UNFILTERED, so an input-echo would replace the process identity that
|
|
784
|
+
// `pr.merge` reads for GitHub operations after re-arming. The snapshot/restore guard must pin them.
|
|
785
|
+
const engine = await boot({
|
|
786
|
+
responses: { "senior:fix-ci": { status: "fixed", repo: "evil/repo", prNumber: 999, prUrl: "https://evil.test/pr/999" } },
|
|
787
|
+
});
|
|
788
|
+
await driveToCiFix(engine);
|
|
789
|
+
assertEquals((await engine.searchIncidents()).length, 0, "the agent echo must not raise an incident");
|
|
790
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
791
|
+
.isActive()
|
|
792
|
+
.hasCompletedElements("fix-ci")
|
|
793
|
+
.hasVariable("repo", "acme/app")
|
|
794
|
+
.hasVariable("prNumber", 1)
|
|
795
|
+
.hasVariable("prUrl", "https://example.test/pr/1");
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
test("a rebase agent echoing PR identity inputs cannot clobber them (#887)", async () => {
|
|
799
|
+
const engine = await boot({
|
|
800
|
+
responses: { "senior:rebase": { status: "rebased", repo: "evil/repo", prNumber: 999, prUrl: "https://evil.test/pr/999" } },
|
|
801
|
+
});
|
|
802
|
+
await driveToRebase(engine);
|
|
803
|
+
assertEquals((await engine.searchIncidents()).length, 0, "the agent echo must not raise an incident");
|
|
804
|
+
assertThatInstance(engine, byProcessId("merge-loop"))
|
|
805
|
+
.isActive()
|
|
806
|
+
.hasCompletedElements("rebase")
|
|
807
|
+
.hasVariable("repo", "acme/app")
|
|
808
|
+
.hasVariable("prNumber", 1)
|
|
809
|
+
.hasVariable("prUrl", "https://example.test/pr/1");
|
|
810
|
+
});
|
|
811
|
+
|
|
605
812
|
test("rebase budget exhaustion escalates as not-mergeable without running the agent", async () => {
|
|
606
813
|
const engine = await boot({ responses: { "senior:rebase": { status: "rebased" } }, vars: { rebaseMax: 0 } });
|
|
607
814
|
await driveToRebase(engine);
|
package/docs/agentic-cockpit.md
CHANGED
|
@@ -124,6 +124,40 @@ when a worker ages out past the liveness TTL. On (re)mount the presence family
|
|
|
124
124
|
reconciles the store against live connections, so a worker that vanished while
|
|
125
125
|
the app was down does not linger as a ghost row after a restart.
|
|
126
126
|
|
|
127
|
+
### Job ownership: authoritative reconnect resync
|
|
128
|
+
|
|
129
|
+
A worker's **jobs** are tracked by the explicit job-ownership claim registry
|
|
130
|
+
(`app/agentic/claim-registry.ts`): a supervisor sends a `claim` frame when a
|
|
131
|
+
worker picks up a job and a `release` when it finishes. Each frame names its
|
|
132
|
+
owning `instance` explicitly, so one per-host supervisor connection can carry
|
|
133
|
+
many workers' ownership.
|
|
134
|
+
|
|
135
|
+
On a WS reconnect a supervisor re-`claim`s every active jobKey. Those re-claims
|
|
136
|
+
are **additive** on their own — a claim that is not re-asserted is never dropped
|
|
137
|
+
— so a `release` lost during a hub outage would leave the job shown as *working*
|
|
138
|
+
until the worker exits entirely, forcing the supervisor to buffer every RELEASE
|
|
139
|
+
without limit across the outage.
|
|
140
|
+
|
|
141
|
+
To close that, a supervisor may end its resync with an **authoritative
|
|
142
|
+
snapshot**: a `claim` frame carrying the full set of jobKeys the instance still
|
|
143
|
+
owns (`{ instance, jobKeys: [...] }` — the empty **array** is allowed, meaning
|
|
144
|
+
"this instance now owns nothing", but every **element** must be a non-empty
|
|
145
|
+
string). The hub validates the frame as the snapshot-or-per-job
|
|
146
|
+
union (a malformed snapshot is dropped before it touches the registry — the
|
|
147
|
+
*presence* of `jobKeys`, not its validity, selects the snapshot variant, so a
|
|
148
|
+
present-but-malformed `jobKeys` — a non-array, a non-string element, or an
|
|
149
|
+
empty-string element — is rejected rather than laundered through the
|
|
150
|
+
per-job path; an empty-string element can't masquerade as an "owns nothing"
|
|
151
|
+
snapshot and clear real claims) and then
|
|
152
|
+
**replaces** that instance's claims with the snapshot — dropping any it did not
|
|
153
|
+
re-assert. The supervisor's
|
|
154
|
+
view wins, because ownership is advisory, short-lived visibility it can always
|
|
155
|
+
restate (it never gates a BPMN flow, ADR 0056). A jobKey that has moved to
|
|
156
|
+
another instance is never blanked by the old instance's resync, and a supervisor
|
|
157
|
+
that sends no snapshot keeps the old additive behaviour. This authoritative
|
|
158
|
+
contract lets a hub client (nano-supervisor#63) **bound** its RELEASE buffer
|
|
159
|
+
during an outage.
|
|
160
|
+
|
|
127
161
|
## What you will NOT find here (and where it lives)
|
|
128
162
|
|
|
129
163
|
- **Demand×supply matrix, missing-agent-type reds, diversity-SLO lights** →
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nanobpm/nano-workforce",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.202.0",
|
|
4
4
|
"description": "Nano Workforce — an Agent Graph Orchestration application for Agentic SDLC: durable BPMN processes that coordinate a graph of AI agents across the software delivery lifecycle.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "main.ts",
|
|
@@ -147,9 +147,45 @@
|
|
|
147
147
|
</zeebe:properties>
|
|
148
148
|
<zeebe:ioMapping>
|
|
149
149
|
<zeebe:input source="=(if (abandonBrief = null) then "" else abandonBrief)" target="appendPrompt" />
|
|
150
|
+
<zeebe:input source="=round" target="guardRound" />
|
|
151
|
+
<zeebe:input source="=maxRounds" target="guardMaxRounds" />
|
|
152
|
+
<zeebe:input source="=advPass" target="guardAdvPass" />
|
|
153
|
+
<zeebe:input source="=advMax" target="guardAdvMax" />
|
|
154
|
+
<zeebe:input source="=ackRetryRound" target="guardAckRetryRound" />
|
|
155
|
+
<zeebe:input source="=ackRetryMax" target="guardAckRetryMax" />
|
|
156
|
+
<zeebe:input source="=huskRetries" target="guardHuskRetries" />
|
|
157
|
+
<zeebe:input source="=prKey" target="guardPrKey" />
|
|
158
|
+
<zeebe:input source="=repo" target="guardRepo" />
|
|
159
|
+
<zeebe:input source="=prNumber" target="guardPrNumber" />
|
|
160
|
+
<zeebe:input source="=prUrl" target="guardPrUrl" />
|
|
161
|
+
<zeebe:input source="=reviewWaitTimeout" target="guardReviewWaitTimeout" />
|
|
162
|
+
<zeebe:input source="=humanApproval" target="guardHumanApproval" />
|
|
163
|
+
<zeebe:input source="=convergeOnly" target="guardConvergeOnly" />
|
|
164
|
+
<zeebe:input source="=reviewStale" target="guardReviewStale" />
|
|
165
|
+
<zeebe:input source="=roundEntryHead" target="guardRoundEntryHead" />
|
|
166
|
+
<zeebe:input source="=abandonUrl" target="guardAbandonUrl" />
|
|
167
|
+
<zeebe:input source="=abandonBrief" target="guardAbandonBrief" />
|
|
150
168
|
<zeebe:output source="=null" target="answer" />
|
|
151
169
|
<zeebe:output source="=false" target="scopePending" />
|
|
152
170
|
<zeebe:output source="=null" target="adversarialFindings" />
|
|
171
|
+
<zeebe:output source="=guardRound" target="round" />
|
|
172
|
+
<zeebe:output source="=guardMaxRounds" target="maxRounds" />
|
|
173
|
+
<zeebe:output source="=guardAdvPass" target="advPass" />
|
|
174
|
+
<zeebe:output source="=guardAdvMax" target="advMax" />
|
|
175
|
+
<zeebe:output source="=guardAckRetryRound" target="ackRetryRound" />
|
|
176
|
+
<zeebe:output source="=guardAckRetryMax" target="ackRetryMax" />
|
|
177
|
+
<zeebe:output source="=guardHuskRetries" target="huskRetries" />
|
|
178
|
+
<zeebe:output source="=guardPrKey" target="prKey" />
|
|
179
|
+
<zeebe:output source="=guardRepo" target="repo" />
|
|
180
|
+
<zeebe:output source="=guardPrNumber" target="prNumber" />
|
|
181
|
+
<zeebe:output source="=guardPrUrl" target="prUrl" />
|
|
182
|
+
<zeebe:output source="=guardReviewWaitTimeout" target="reviewWaitTimeout" />
|
|
183
|
+
<zeebe:output source="=(guardHumanApproval = true) or (humanApproval = true)" target="humanApproval" />
|
|
184
|
+
<zeebe:output source="=guardConvergeOnly" target="convergeOnly" />
|
|
185
|
+
<zeebe:output source="=guardReviewStale" target="reviewStale" />
|
|
186
|
+
<zeebe:output source="=guardRoundEntryHead" target="roundEntryHead" />
|
|
187
|
+
<zeebe:output source="=guardAbandonUrl" target="abandonUrl" />
|
|
188
|
+
<zeebe:output source="=guardAbandonBrief" target="abandonBrief" />
|
|
153
189
|
</zeebe:ioMapping>
|
|
154
190
|
</bpmn:extensionElements>
|
|
155
191
|
<bpmn:incoming>f_capture</bpmn:incoming>
|
|
@@ -205,11 +241,46 @@
|
|
|
205
241
|
</zeebe:properties>
|
|
206
242
|
<zeebe:ioMapping>
|
|
207
243
|
<zeebe:input source="=(if (abandonBrief = null) then "" else abandonBrief)" target="appendPrompt" />
|
|
244
|
+
<zeebe:input source="=round" target="guardRound" />
|
|
245
|
+
<zeebe:input source="=maxRounds" target="guardMaxRounds" />
|
|
246
|
+
<zeebe:input source="=advPass" target="guardAdvPass" />
|
|
247
|
+
<zeebe:input source="=advMax" target="guardAdvMax" />
|
|
248
|
+
<zeebe:input source="=ackRetryRound" target="guardAckRetryRound" />
|
|
249
|
+
<zeebe:input source="=ackRetryMax" target="guardAckRetryMax" />
|
|
250
|
+
<zeebe:input source="=huskRetries" target="guardHuskRetries" />
|
|
251
|
+
<zeebe:input source="=prKey" target="guardPrKey" />
|
|
252
|
+
<zeebe:input source="=repo" target="guardRepo" />
|
|
253
|
+
<zeebe:input source="=prNumber" target="guardPrNumber" />
|
|
254
|
+
<zeebe:input source="=prUrl" target="guardPrUrl" />
|
|
255
|
+
<zeebe:input source="=reviewWaitTimeout" target="guardReviewWaitTimeout" />
|
|
256
|
+
<zeebe:input source="=humanApproval" target="guardHumanApproval" />
|
|
257
|
+
<zeebe:input source="=convergeOnly" target="guardConvergeOnly" />
|
|
258
|
+
<zeebe:input source="=reviewStale" target="guardReviewStale" />
|
|
259
|
+
<zeebe:input source="=roundEntryHead" target="guardRoundEntryHead" />
|
|
260
|
+
<zeebe:input source="=abandonUrl" target="guardAbandonUrl" />
|
|
261
|
+
<zeebe:input source="=abandonBrief" target="guardAbandonBrief" />
|
|
208
262
|
<zeebe:output source="=adversarialFindings" target="adversarialFindings" />
|
|
209
|
-
<zeebe:output source="=(if
|
|
263
|
+
<zeebe:output source="=(if guardAdvPass = null then 0 else guardAdvPass) + 1" target="advPass" />
|
|
210
264
|
<zeebe:output source="=(if adversarialFindings != null and trim(adversarialFindings) != "" then null else status)" target="status" />
|
|
211
265
|
<zeebe:output source="=(if adversarialFindings != null and trim(adversarialFindings) != "" then null else summary)" target="summary" />
|
|
212
266
|
<zeebe:output source="=(if adversarialFindings != null and trim(adversarialFindings) != "" then null else question)" target="question" />
|
|
267
|
+
<zeebe:output source="=guardRound" target="round" />
|
|
268
|
+
<zeebe:output source="=guardMaxRounds" target="maxRounds" />
|
|
269
|
+
<zeebe:output source="=guardAdvMax" target="advMax" />
|
|
270
|
+
<zeebe:output source="=guardAckRetryRound" target="ackRetryRound" />
|
|
271
|
+
<zeebe:output source="=guardAckRetryMax" target="ackRetryMax" />
|
|
272
|
+
<zeebe:output source="=guardHuskRetries" target="huskRetries" />
|
|
273
|
+
<zeebe:output source="=guardPrKey" target="prKey" />
|
|
274
|
+
<zeebe:output source="=guardRepo" target="repo" />
|
|
275
|
+
<zeebe:output source="=guardPrNumber" target="prNumber" />
|
|
276
|
+
<zeebe:output source="=guardPrUrl" target="prUrl" />
|
|
277
|
+
<zeebe:output source="=guardReviewWaitTimeout" target="reviewWaitTimeout" />
|
|
278
|
+
<zeebe:output source="=(guardHumanApproval = true) or (humanApproval = true)" target="humanApproval" />
|
|
279
|
+
<zeebe:output source="=guardConvergeOnly" target="convergeOnly" />
|
|
280
|
+
<zeebe:output source="=guardReviewStale" target="reviewStale" />
|
|
281
|
+
<zeebe:output source="=guardRoundEntryHead" target="roundEntryHead" />
|
|
282
|
+
<zeebe:output source="=guardAbandonUrl" target="abandonUrl" />
|
|
283
|
+
<zeebe:output source="=guardAbandonBrief" target="abandonBrief" />
|
|
213
284
|
</zeebe:ioMapping>
|
|
214
285
|
</bpmn:extensionElements>
|
|
215
286
|
<bpmn:incoming>f_advDue</bpmn:incoming>
|
|
@@ -478,7 +549,43 @@
|
|
|
478
549
|
<zeebe:property name="io.nanobpm.dataEnvelope.out" value="PrScopeClassifyOut" />
|
|
479
550
|
</zeebe:properties>
|
|
480
551
|
<zeebe:ioMapping>
|
|
552
|
+
<zeebe:input source="=round" target="guardRound" />
|
|
553
|
+
<zeebe:input source="=maxRounds" target="guardMaxRounds" />
|
|
554
|
+
<zeebe:input source="=advPass" target="guardAdvPass" />
|
|
555
|
+
<zeebe:input source="=advMax" target="guardAdvMax" />
|
|
556
|
+
<zeebe:input source="=ackRetryRound" target="guardAckRetryRound" />
|
|
557
|
+
<zeebe:input source="=ackRetryMax" target="guardAckRetryMax" />
|
|
558
|
+
<zeebe:input source="=huskRetries" target="guardHuskRetries" />
|
|
559
|
+
<zeebe:input source="=prKey" target="guardPrKey" />
|
|
560
|
+
<zeebe:input source="=repo" target="guardRepo" />
|
|
561
|
+
<zeebe:input source="=prNumber" target="guardPrNumber" />
|
|
562
|
+
<zeebe:input source="=prUrl" target="guardPrUrl" />
|
|
563
|
+
<zeebe:input source="=reviewWaitTimeout" target="guardReviewWaitTimeout" />
|
|
564
|
+
<zeebe:input source="=humanApproval" target="guardHumanApproval" />
|
|
565
|
+
<zeebe:input source="=convergeOnly" target="guardConvergeOnly" />
|
|
566
|
+
<zeebe:input source="=reviewStale" target="guardReviewStale" />
|
|
567
|
+
<zeebe:input source="=roundEntryHead" target="guardRoundEntryHead" />
|
|
568
|
+
<zeebe:input source="=abandonUrl" target="guardAbandonUrl" />
|
|
569
|
+
<zeebe:input source="=abandonBrief" target="guardAbandonBrief" />
|
|
481
570
|
<zeebe:output source="=null" target="scopeAnswer" />
|
|
571
|
+
<zeebe:output source="=guardRound" target="round" />
|
|
572
|
+
<zeebe:output source="=guardMaxRounds" target="maxRounds" />
|
|
573
|
+
<zeebe:output source="=guardAdvPass" target="advPass" />
|
|
574
|
+
<zeebe:output source="=guardAdvMax" target="advMax" />
|
|
575
|
+
<zeebe:output source="=guardAckRetryRound" target="ackRetryRound" />
|
|
576
|
+
<zeebe:output source="=guardAckRetryMax" target="ackRetryMax" />
|
|
577
|
+
<zeebe:output source="=guardHuskRetries" target="huskRetries" />
|
|
578
|
+
<zeebe:output source="=guardPrKey" target="prKey" />
|
|
579
|
+
<zeebe:output source="=guardRepo" target="repo" />
|
|
580
|
+
<zeebe:output source="=guardPrNumber" target="prNumber" />
|
|
581
|
+
<zeebe:output source="=guardPrUrl" target="prUrl" />
|
|
582
|
+
<zeebe:output source="=guardReviewWaitTimeout" target="reviewWaitTimeout" />
|
|
583
|
+
<zeebe:output source="=(guardHumanApproval = true) or (humanApproval = true)" target="humanApproval" />
|
|
584
|
+
<zeebe:output source="=guardConvergeOnly" target="convergeOnly" />
|
|
585
|
+
<zeebe:output source="=guardReviewStale" target="reviewStale" />
|
|
586
|
+
<zeebe:output source="=guardRoundEntryHead" target="roundEntryHead" />
|
|
587
|
+
<zeebe:output source="=guardAbandonUrl" target="abandonUrl" />
|
|
588
|
+
<zeebe:output source="=guardAbandonBrief" target="abandonBrief" />
|
|
482
589
|
</zeebe:ioMapping>
|
|
483
590
|
</bpmn:extensionElements>
|
|
484
591
|
<bpmn:incoming>f_convergeOk</bpmn:incoming>
|
|
@@ -362,7 +362,46 @@
|
|
|
362
362
|
</zeebe:properties>
|
|
363
363
|
<zeebe:ioMapping>
|
|
364
364
|
<zeebe:input source="=(if (failingChecksList = null or failingChecksList = "") then "" else " Failing checks to make green: " + failingChecksList) + (if (abandonBrief = null) then "" else abandonBrief)" target="appendPrompt" />
|
|
365
|
-
<zeebe:
|
|
365
|
+
<zeebe:input source="=ciFixRound" target="guardCiFixRound" />
|
|
366
|
+
<zeebe:input source="=ciFixMax" target="guardCiFixMax" />
|
|
367
|
+
<zeebe:input source="=rebaseRound" target="guardRebaseRound" />
|
|
368
|
+
<zeebe:input source="=rebaseMax" target="guardRebaseMax" />
|
|
369
|
+
<zeebe:input source="=mergeRetryRound" target="guardMergeRetryRound" />
|
|
370
|
+
<zeebe:input source="=mergeRetryMax" target="guardMergeRetryMax" />
|
|
371
|
+
<zeebe:input source="=mergeStallRounds" target="guardMergeStallRounds" />
|
|
372
|
+
<zeebe:input source="=mergeStallMax" target="guardMergeStallMax" />
|
|
373
|
+
<zeebe:input source="=prKey" target="guardPrKey" />
|
|
374
|
+
<zeebe:input source="=repo" target="guardRepo" />
|
|
375
|
+
<zeebe:input source="=prNumber" target="guardPrNumber" />
|
|
376
|
+
<zeebe:input source="=prUrl" target="guardPrUrl" />
|
|
377
|
+
<zeebe:input source="=ciBlockedReconciled" target="guardCiBlockedReconciled" />
|
|
378
|
+
<zeebe:input source="=agentSlaTimeout" target="guardAgentSlaTimeout" />
|
|
379
|
+
<zeebe:input source="=landedWaitTimeout" target="guardLandedWaitTimeout" />
|
|
380
|
+
<zeebe:input source="=mergeableWaitTimeout" target="guardMergeableWaitTimeout" />
|
|
381
|
+
<zeebe:input source="=mergeableRepollInterval" target="guardMergeableRepollInterval" />
|
|
382
|
+
<zeebe:input source="=round" target="guardRound" />
|
|
383
|
+
<zeebe:input source="=abandonUrl" target="guardAbandonUrl" />
|
|
384
|
+
<zeebe:input source="=abandonBrief" target="guardAbandonBrief" />
|
|
385
|
+
<zeebe:output source="=guardCiFixRound + 1" target="ciFixRound" />
|
|
386
|
+
<zeebe:output source="=guardCiFixMax" target="ciFixMax" />
|
|
387
|
+
<zeebe:output source="=guardRebaseRound" target="rebaseRound" />
|
|
388
|
+
<zeebe:output source="=guardRebaseMax" target="rebaseMax" />
|
|
389
|
+
<zeebe:output source="=guardMergeRetryRound" target="mergeRetryRound" />
|
|
390
|
+
<zeebe:output source="=guardMergeRetryMax" target="mergeRetryMax" />
|
|
391
|
+
<zeebe:output source="=guardMergeStallRounds" target="mergeStallRounds" />
|
|
392
|
+
<zeebe:output source="=guardMergeStallMax" target="mergeStallMax" />
|
|
393
|
+
<zeebe:output source="=guardPrKey" target="prKey" />
|
|
394
|
+
<zeebe:output source="=guardRepo" target="repo" />
|
|
395
|
+
<zeebe:output source="=guardPrNumber" target="prNumber" />
|
|
396
|
+
<zeebe:output source="=guardPrUrl" target="prUrl" />
|
|
397
|
+
<zeebe:output source="=guardCiBlockedReconciled" target="ciBlockedReconciled" />
|
|
398
|
+
<zeebe:output source="=guardAgentSlaTimeout" target="agentSlaTimeout" />
|
|
399
|
+
<zeebe:output source="=guardLandedWaitTimeout" target="landedWaitTimeout" />
|
|
400
|
+
<zeebe:output source="=guardMergeableWaitTimeout" target="mergeableWaitTimeout" />
|
|
401
|
+
<zeebe:output source="=guardMergeableRepollInterval" target="mergeableRepollInterval" />
|
|
402
|
+
<zeebe:output source="=guardRound" target="round" />
|
|
403
|
+
<zeebe:output source="=guardAbandonUrl" target="abandonUrl" />
|
|
404
|
+
<zeebe:output source="=guardAbandonBrief" target="abandonBrief" />
|
|
366
405
|
</zeebe:ioMapping>
|
|
367
406
|
</bpmn:extensionElements>
|
|
368
407
|
<bpmn:incoming>f_ci_s0</bpmn:incoming>
|
|
@@ -524,7 +563,46 @@
|
|
|
524
563
|
</zeebe:properties>
|
|
525
564
|
<zeebe:ioMapping>
|
|
526
565
|
<zeebe:input source="=(if (abandonBrief = null) then "" else abandonBrief)" target="appendPrompt" />
|
|
527
|
-
<zeebe:
|
|
566
|
+
<zeebe:input source="=ciFixRound" target="guardCiFixRound" />
|
|
567
|
+
<zeebe:input source="=ciFixMax" target="guardCiFixMax" />
|
|
568
|
+
<zeebe:input source="=rebaseRound" target="guardRebaseRound" />
|
|
569
|
+
<zeebe:input source="=rebaseMax" target="guardRebaseMax" />
|
|
570
|
+
<zeebe:input source="=mergeRetryRound" target="guardMergeRetryRound" />
|
|
571
|
+
<zeebe:input source="=mergeRetryMax" target="guardMergeRetryMax" />
|
|
572
|
+
<zeebe:input source="=mergeStallRounds" target="guardMergeStallRounds" />
|
|
573
|
+
<zeebe:input source="=mergeStallMax" target="guardMergeStallMax" />
|
|
574
|
+
<zeebe:input source="=prKey" target="guardPrKey" />
|
|
575
|
+
<zeebe:input source="=repo" target="guardRepo" />
|
|
576
|
+
<zeebe:input source="=prNumber" target="guardPrNumber" />
|
|
577
|
+
<zeebe:input source="=prUrl" target="guardPrUrl" />
|
|
578
|
+
<zeebe:input source="=ciBlockedReconciled" target="guardCiBlockedReconciled" />
|
|
579
|
+
<zeebe:input source="=agentSlaTimeout" target="guardAgentSlaTimeout" />
|
|
580
|
+
<zeebe:input source="=landedWaitTimeout" target="guardLandedWaitTimeout" />
|
|
581
|
+
<zeebe:input source="=mergeableWaitTimeout" target="guardMergeableWaitTimeout" />
|
|
582
|
+
<zeebe:input source="=mergeableRepollInterval" target="guardMergeableRepollInterval" />
|
|
583
|
+
<zeebe:input source="=round" target="guardRound" />
|
|
584
|
+
<zeebe:input source="=abandonUrl" target="guardAbandonUrl" />
|
|
585
|
+
<zeebe:input source="=abandonBrief" target="guardAbandonBrief" />
|
|
586
|
+
<zeebe:output source="=guardRebaseRound + 1" target="rebaseRound" />
|
|
587
|
+
<zeebe:output source="=guardCiFixRound" target="ciFixRound" />
|
|
588
|
+
<zeebe:output source="=guardCiFixMax" target="ciFixMax" />
|
|
589
|
+
<zeebe:output source="=guardRebaseMax" target="rebaseMax" />
|
|
590
|
+
<zeebe:output source="=guardMergeRetryRound" target="mergeRetryRound" />
|
|
591
|
+
<zeebe:output source="=guardMergeRetryMax" target="mergeRetryMax" />
|
|
592
|
+
<zeebe:output source="=guardMergeStallRounds" target="mergeStallRounds" />
|
|
593
|
+
<zeebe:output source="=guardMergeStallMax" target="mergeStallMax" />
|
|
594
|
+
<zeebe:output source="=guardPrKey" target="prKey" />
|
|
595
|
+
<zeebe:output source="=guardRepo" target="repo" />
|
|
596
|
+
<zeebe:output source="=guardPrNumber" target="prNumber" />
|
|
597
|
+
<zeebe:output source="=guardPrUrl" target="prUrl" />
|
|
598
|
+
<zeebe:output source="=guardCiBlockedReconciled" target="ciBlockedReconciled" />
|
|
599
|
+
<zeebe:output source="=guardAgentSlaTimeout" target="agentSlaTimeout" />
|
|
600
|
+
<zeebe:output source="=guardLandedWaitTimeout" target="landedWaitTimeout" />
|
|
601
|
+
<zeebe:output source="=guardMergeableWaitTimeout" target="mergeableWaitTimeout" />
|
|
602
|
+
<zeebe:output source="=guardMergeableRepollInterval" target="mergeableRepollInterval" />
|
|
603
|
+
<zeebe:output source="=guardRound" target="round" />
|
|
604
|
+
<zeebe:output source="=guardAbandonUrl" target="abandonUrl" />
|
|
605
|
+
<zeebe:output source="=guardAbandonBrief" target="abandonBrief" />
|
|
528
606
|
</zeebe:ioMapping>
|
|
529
607
|
</bpmn:extensionElements>
|
|
530
608
|
<bpmn:incoming>f_reb_s0</bpmn:incoming>
|