@nanobpm/nano-workforce 0.186.1 → 0.186.2

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 CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.186.2](https://github.com/nanobpm/nano-workforce/compare/v0.186.1...v0.186.2) (2026-09-11)
2
+
3
+ ### Bug Fixes
4
+
5
+ * **merge-loop:** re-poll a 'waiting' mergeability verdict instead of escalating ([#775](https://github.com/nanobpm/nano-workforce/issues/775)) ([4812fe9](https://github.com/nanobpm/nano-workforce/commit/4812fe9689088f21e41ef50ba8f1dbec2093fb23)), closes [#774](https://github.com/nanobpm/nano-workforce/issues/774) [#774](https://github.com/nanobpm/nano-workforce/issues/774) [#774](https://github.com/nanobpm/nano-workforce/issues/774)
6
+
1
7
  ## [0.186.1](https://github.com/nanobpm/nano-workforce/compare/v0.186.0...v0.186.1) (2026-09-11)
2
8
 
3
9
  ### Bug Fixes
package/SPEC.md CHANGED
@@ -216,7 +216,7 @@ Consequences the prompt (`resources/prompts/review-round.md`) encodes:
216
216
  | `pr-submitted` | — (start) | submit route/webhook | `{repo, prNumber, prUrl, prKey}` |
217
217
  | `readiness-ready` | `prKey` | **poller** | `{ready, detail?}` (ADR 0001 §2 wait-gate; the review-ready wait, re-expressed on the ReadinessProbe gate — #259) |
218
218
  | `deps-cleared` | `prKey` | **poller** (merge) | — (all `Depends-on` PRs merged) |
219
- | `merge-ready` | `prKey` | **poller** (merge) | `{mergeState}` (`ready` \| `conflict` \| `blocked`); when `blocked`, also `{failingChecks, failingChecksList}` for the `senior:fix-ci` branch |
219
+ | `merge-ready` | `prKey` | **poller** (merge) | `{mergeState}` (`ready` \| `conflict` \| `blocked` \| `draft`); when `blocked`, also `{failingChecks, failingChecksList}` for the `senior:fix-ci` branch. A transient `UNKNOWN`/`waiting` verdict is NOT published — the poller keeps polling (fast self-heal); the merge loop's `gw-mergeable` sees `waiting` only via the dead-poller stall-probe re-derivation, where it re-polls (bounded, #774) instead of escalating |
220
220
  | `merge-landed` | `prKey` | **poller** (merge) | — (queued PR merged, or merged out-of-band) |
221
221
 
222
222
  The `escalation-answered` message was retired (#256): the merge-loop escalation is
@@ -466,10 +466,21 @@ start ─► wait: deps merged ─► arm merge ─► wait: mergeable ─┬─
466
466
  time** by a `fix-ci`/`rebase` agent (`status: "waiting-on-pr"`, above). `merge-loop`
467
467
  parks at *wait: deps merged*; the poller checks each dependency (own tracked row
468
468
  first, else GitHub `merged` state) and publishes `deps-cleared` once all have landed.
469
- - **Mergeability** — the poller classifies GitHub's `mergeStateStatus`:
469
+ - **Mergeability** — the poller classifies GitHub's `mergeStateStatus`, but a
470
+ first-class `isDraft` guard runs *first* (`classifyMergeability`, `app/github.ts`):
471
+ a draft PR is `draft` regardless of `mergeStateStatus`. Otherwise, by status:
470
472
  `CLEAN`/`HAS_HOOKS`/`UNSTABLE`/`BEHIND` → `ready`; `DIRTY` → `conflict`;
471
473
  `BLOCKED` → `blocked` if a required check is failing, else keep waiting;
472
- `DRAFT`/`UNKNOWN`/empty keep waiting. It publishes `merge-ready {mergeState}`.
474
+ `UNKNOWN`/empty (and any other status, including `DRAFT`) → keep polling (GitHub
475
+ still computing). It
476
+ publishes `merge-ready {mergeState}` for the settled verdicts. When the live
477
+ poller is dead the `wait-mergeable-timeout` backstop's stall-probe re-derives
478
+ mergeability; a still-unsettled `UNKNOWN`/`waiting` verdict then routes to a
479
+ **bounded re-poll** (`wait-mergeable-repoll`, `NANO_PR_MERGEABLE_REPOLL_INTERVAL`)
480
+ rather than escalating (bounded by `NANO_PR_MAX_MERGE_STALL_ROUNDS`), and an
481
+ unclassified/default verdict routes to auto-rebase (`gw-rebase`, bounded by its
482
+ own `NANO_PR_MAX_REBASE_ROUNDS` budget); once either budget is exhausted the loop
483
+ escalates to a human (#774).
473
484
  - **Merge** — `pr.merge` attempts the merge (`NANO_PR_MERGE_METHOD`, default
474
485
  `squash`). GitHub auto-enqueues on merge-queue-required branches → the process
475
486
  waits for `merge-landed` (poller detects the landed PR). Every attempt is
package/app/contracts.ts CHANGED
@@ -137,7 +137,7 @@ export const ENV_CONTRACTS = {
137
137
  name: "NANO_PR_MAX_MERGE_STALL_ROUNDS",
138
138
  owner: "app/service.ts",
139
139
  semantics:
140
- "Maximum mergeable-wait-timeout stall-probe re-derivations (dead-poller backstop, #636) before escalating; 0 escalates on the first stall.",
140
+ "Maximum mergeable-wait-timeout stall-probe re-derivations (dead-poller backstop, #636) AND `waiting`-verdict re-poll probes (#774) before escalating; 0 escalates on the first stall.",
141
141
  default: "3",
142
142
  },
143
143
  NANO_PR_REVIEW_WAIT_TIMEOUT: {
@@ -166,6 +166,13 @@ export const ENV_CONTRACTS = {
166
166
  semantics:
167
167
  "How long the merge loop waits for the poller's `merge-ready` before the stall-probe timer arm fires (dead-poller backstop, #636; FEEL/ISO-8601 duration).",
168
168
  },
169
+ NANO_PR_MERGEABLE_REPOLL_INTERVAL: {
170
+ category: "env",
171
+ name: "NANO_PR_MERGEABLE_REPOLL_INTERVAL",
172
+ owner: "app/service.ts",
173
+ semantics:
174
+ "How long the merge loop waits before re-deriving mergeability when `gw-mergeable` sees an async-`UNKNOWN` `\"waiting\"` verdict, instead of escalating to a human (#774; bounded by `NANO_PR_MAX_MERGE_STALL_ROUNDS`; FEEL/ISO-8601 duration).",
175
+ },
169
176
  NANO_PR_AUTO_MERGE: {
170
177
  category: "env",
171
178
  name: "NANO_PR_AUTO_MERGE",
@@ -43,6 +43,7 @@ const MODEL = readFileSync("resources/processes/merge-loop.bpmn", "utf8");
43
43
  const AGENT_SLA_MS = 30 * 60 * 1000; // matches the PT30M we start instances with
44
44
  const LANDED_WAIT_MS = 30 * 60 * 1000; // matches the PT30M landedWaitTimeout we start instances with
45
45
  const MERGEABLE_WAIT_MS = 30 * 60 * 1000; // matches the PT30M mergeableWaitTimeout we start instances with
46
+ const MERGEABLE_REPOLL_MS = 2 * 60 * 1000; // matches the PT2M mergeableRepollInterval we start instances with
46
47
 
47
48
  type Output = Record<string, unknown>;
48
49
  type Responder = Output | Output[] | ((job: { variables: Record<string, unknown> }) => Output);
@@ -85,6 +86,7 @@ const DEFAULT_VARS: Record<string, unknown> = {
85
86
  agentSlaTimeout: "PT30M",
86
87
  landedWaitTimeout: "PT30M",
87
88
  mergeableWaitTimeout: "PT30M",
89
+ mergeableRepollInterval: "PT2M",
88
90
  mergeStallRounds: 0,
89
91
  mergeStallMax: 3,
90
92
  abandonBrief: null,
@@ -349,6 +351,94 @@ test("the stall-round cap escalates to a human instead of looping forever (#636)
349
351
  assert(!completedElementIds(engine).has("mark-merged"), "an exhausted stall must not mark-merged");
350
352
  });
351
353
 
354
+ // ---------------------------------------------------------------------------
355
+ // Async-UNKNOWN "waiting" verdict → bounded re-poll, NOT a human (issue #774)
356
+ // ---------------------------------------------------------------------------
357
+ // GitHub returns `mergeable=UNKNOWN` transiently while it computes mergeability in the background,
358
+ // which `classifyMergeability` maps to `"waiting"`. Before the fix, a `"waiting"` verdict at
359
+ // `gw-mergeable` hit the DEFAULT arm and escalated straight to the `wait-merge-answer` human task —
360
+ // so a PR whose real state was still settling (e.g. to `"conflict"`, which would auto-fire
361
+ // `senior:rebase`) paged a human instead of self-healing. The fix routes `"waiting"` to a bounded
362
+ // re-poll (`wait-mergeable-repoll` timer → `merge-stall-probe` → the existing `gw-mergeable` arms),
363
+ // bounded by the shared `mergeStallMax` budget, and routes the true DEFAULT to auto-rebase.
364
+
365
+ test("a 'waiting' (async UNKNOWN) verdict re-polls instead of escalating to a human (#774)", async () => {
366
+ // RED (before the fix): `waiting` → DEFAULT → `merge-esc-conflict` → `wait-merge-answer`. GREEN:
367
+ // `waiting` parks on the re-poll timer; when it fires, `merge-stall-probe` re-derives `ready` and
368
+ // the PR merges — no human ever touched.
369
+ const engine = await boot({
370
+ responses: {
371
+ "pr.merge-stall-probe": { mergeState: "ready", failingChecks: 0, failingChecksList: "" },
372
+ "pr.merge": { mergeStatus: "merged" },
373
+ },
374
+ });
375
+ await engine.publishMessage({ name: "deps-cleared", correlationKey: "pr-1" });
376
+ await engine.publishMessage({ name: "merge-ready", correlationKey: "pr-1", variables: { mergeState: "waiting" } });
377
+ // Parks on the bounded re-poll timer — NOT on a human task, NOT escalated.
378
+ assertThatInstance(engine, byProcessId("merge-loop")).isActive().hasActiveElement("wait-mergeable-repoll");
379
+ assert(!completedElementIds(engine).has("merge-esc-conflict"), "a waiting verdict must NOT escalate to a human");
380
+ const openTasks = await engine.searchUserTasks({});
381
+ assert(!openTasks.some((t) => t.elementId === "wait-merge-answer"), "a waiting verdict must not park a user task");
382
+ // The timer fires → the probe re-derives ground truth (`ready`) → the PR merges.
383
+ await engine.advanceTime(MERGEABLE_REPOLL_MS + 1);
384
+ assertThatInstance(engine, byProcessId("merge-loop"))
385
+ .hasCompleted()
386
+ .hasNoIncident()
387
+ .hasCompletedElements("wait-mergeable-repoll", "merge-stall-probe", "attempt-merge", "mark-merged");
388
+ });
389
+
390
+ test("a 'waiting' verdict that settles to conflict on re-poll reaches the rebase arm (#774)", async () => {
391
+ // The incident (Magikcraft/nano-bpm#1166): the PR was really CONFLICTING, but GitHub reported
392
+ // UNKNOWN transiently. The re-poll must let it settle to `conflict` → `senior:rebase`, the arm that
393
+ // would have fixed it, rather than paging a human on the transient UNKNOWN.
394
+ const engine = await boot({
395
+ responses: {
396
+ "pr.merge-stall-probe": { mergeState: "conflict", failingChecks: 0, failingChecksList: "" },
397
+ "senior:rebase": { status: "rebased" },
398
+ },
399
+ });
400
+ await engine.publishMessage({ name: "deps-cleared", correlationKey: "pr-1" });
401
+ await engine.publishMessage({ name: "merge-ready", correlationKey: "pr-1", variables: { mergeState: "waiting" } });
402
+ await engine.advanceTime(MERGEABLE_REPOLL_MS + 1);
403
+ assertThatInstance(engine, byProcessId("merge-loop"))
404
+ .isActive()
405
+ .hasCompletedElements("wait-mergeable-repoll", "merge-stall-probe", "rebase")
406
+ .hasVariable("rebaseRound", 1);
407
+ assert(!completedElementIds(engine).has("merge-esc-conflict"), "settling to conflict must rebase, not escalate");
408
+ });
409
+
410
+ test("the 'waiting' re-poll is bounded — exhausting mergeStallMax escalates to a human (#774)", async () => {
411
+ // A permanently-UNKNOWN PR cannot re-poll forever: the re-poll shares the `mergeStallMax` budget.
412
+ // `mergeStallMax: 0` — escalate on the first re-poll. The probe runs once, `gw-merge-stall` finds
413
+ // the budget exhausted, and routes to the human `wait-merge-answer` (last resort, not first).
414
+ const engine = await boot({
415
+ vars: { mergeStallMax: 0 },
416
+ responses: {
417
+ "pr.merge-stall-probe": { mergeState: "waiting", failingChecks: 0, failingChecksList: "" },
418
+ },
419
+ });
420
+ await engine.publishMessage({ name: "deps-cleared", correlationKey: "pr-1" });
421
+ await engine.publishMessage({ name: "merge-ready", correlationKey: "pr-1", variables: { mergeState: "waiting" } });
422
+ assert(!completedElementIds(engine).has("merge-esc-conflict"), "must re-poll before ever escalating");
423
+ await engine.advanceTime(MERGEABLE_REPOLL_MS + 1);
424
+ await assertThatUserTask(engine, { instance: byProcessId("merge-loop"), elementId: "wait-merge-answer" }).isCreated();
425
+ assertThatInstance(engine, byProcessId("merge-loop")).hasCompletedElements("wait-mergeable-repoll", "merge-stall-probe", "merge-esc-conflict");
426
+ });
427
+
428
+ test("an unclassified verdict routes to auto-rebase (DEFAULT), not to a human (#774)", async () => {
429
+ // The DEFAULT arm is a last-resort self-heal, not a page: an unexpected/garbage `mergeState` routes
430
+ // to the bounded rebase agent (which reconciles from ground truth), never straight to a human.
431
+ const engine = await boot({ responses: { "senior:rebase": { status: "rebased" } } });
432
+ await engine.publishMessage({ name: "deps-cleared", correlationKey: "pr-1" });
433
+ await engine.publishMessage({ name: "merge-ready", correlationKey: "pr-1", variables: { mergeState: "bogus" } });
434
+ assertThatInstance(engine, byProcessId("merge-loop"))
435
+ .isActive()
436
+ .hasCompletedElements("rebase")
437
+ .hasVariable("rebaseRound", 1);
438
+ const openTasks = await engine.searchUserTasks({});
439
+ assert(!openTasks.some((t) => t.elementId === "wait-merge-answer"), "the default arm must not page a human");
440
+ });
441
+
352
442
  test("an evicted queued merge re-arms the poller rather than completing", async () => {
353
443
  const engine = await boot({ responses: { "pr.merge": { mergeStatus: "queued" } } });
354
444
  await engine.publishMessage({ name: "deps-cleared", correlationKey: "pr-1" });
@@ -6,7 +6,8 @@
6
6
 
7
7
  import assert from "node:assert/strict";
8
8
  import { test } from "node:test";
9
- import { DEFAULT_MERGEABLE_WAIT_TIMEOUT, mergeableWaitTimeout } from "./mergeableWait.ts";
9
+ import { DEFAULT_MERGEABLE_REPOLL_INTERVAL, DEFAULT_MERGEABLE_WAIT_TIMEOUT, mergeableRepollInterval, mergeableWaitTimeout } from "./mergeableWait.ts";
10
+ import { isoDurationToMs } from "./reviewWait.ts";
10
11
 
11
12
  test("mergeableWaitTimeout: blank / absent / malformed → default", () => {
12
13
  assert.equal(mergeableWaitTimeout(undefined), DEFAULT_MERGEABLE_WAIT_TIMEOUT);
@@ -37,3 +38,43 @@ test("the default is itself a well-formed ISO-8601 duration (never an uninterpre
37
38
  assert.notEqual(DEFAULT_MERGEABLE_WAIT_TIMEOUT, sentinel);
38
39
  assert.equal(mergeableWaitTimeout(DEFAULT_MERGEABLE_WAIT_TIMEOUT, sentinel), DEFAULT_MERGEABLE_WAIT_TIMEOUT);
39
40
  });
41
+
42
+ // --- Mergeability re-poll interval (issue #774) -----------------------------------------------
43
+ // Baked into every merge-loop instance's `mergeableRepollInterval` process variable and evaluated by
44
+ // the `wait-mergeable-repoll` timer catch, which bounds the `"waiting"` (async UNKNOWN) verdict's
45
+ // re-poll before it re-derives mergeability from ground truth — so a malformed operator env must
46
+ // never deploy an uninterpretable `<bpmn:timeDuration>`.
47
+
48
+ test("mergeableRepollInterval: blank / absent / malformed → default", () => {
49
+ assert.equal(mergeableRepollInterval(undefined), DEFAULT_MERGEABLE_REPOLL_INTERVAL);
50
+ assert.equal(mergeableRepollInterval(""), DEFAULT_MERGEABLE_REPOLL_INTERVAL);
51
+ assert.equal(mergeableRepollInterval(" "), DEFAULT_MERGEABLE_REPOLL_INTERVAL);
52
+ assert.equal(mergeableRepollInterval("2m"), DEFAULT_MERGEABLE_REPOLL_INTERVAL); // missing leading P/T
53
+ assert.equal(mergeableRepollInterval("garbage"), DEFAULT_MERGEABLE_REPOLL_INTERVAL);
54
+ });
55
+
56
+ test("mergeableRepollInterval: a valid ISO-8601 duration is honoured and upper-cased", () => {
57
+ assert.equal(mergeableRepollInterval("PT2M"), "PT2M");
58
+ assert.equal(mergeableRepollInterval("pt90s"), "PT90S");
59
+ assert.equal(mergeableRepollInterval(" pt5m "), "PT5M");
60
+ });
61
+
62
+ test("mergeableRepollInterval: the re-poll interval is shorter than the poller-death backstop", () => {
63
+ // The re-poll (GitHub settling UNKNOWN, ~seconds) must fire far sooner than the 30-minute
64
+ // dead-poller backstop, so a transient UNKNOWN self-heals briskly rather than parking for tens of
65
+ // minutes per round.
66
+ assert.equal(DEFAULT_MERGEABLE_REPOLL_INTERVAL, "PT2M");
67
+ // `notEqual` only proves the values differ — a future `PT1H` would pass despite being LONGER than
68
+ // the backstop. Assert the actual ordering invariant on parsed durations via the canonical helper.
69
+ assert.ok(
70
+ isoDurationToMs(DEFAULT_MERGEABLE_REPOLL_INTERVAL, "PT0S") <
71
+ isoDurationToMs(DEFAULT_MERGEABLE_WAIT_TIMEOUT, "PT0S"),
72
+ "the re-poll interval must be strictly shorter than the poller-death backstop",
73
+ );
74
+ });
75
+
76
+ test("mergeableRepollInterval: the default is itself a well-formed ISO-8601 duration", () => {
77
+ const sentinel = "PT1S";
78
+ assert.notEqual(DEFAULT_MERGEABLE_REPOLL_INTERVAL, sentinel);
79
+ assert.equal(mergeableRepollInterval(DEFAULT_MERGEABLE_REPOLL_INTERVAL, sentinel), DEFAULT_MERGEABLE_REPOLL_INTERVAL);
80
+ });
@@ -36,3 +36,26 @@ export function mergeableWaitTimeout(
36
36
  ): string {
37
37
  return isoDuration(raw, def);
38
38
  }
39
+
40
+ /** Default mergeability re-poll interval (ISO-8601 duration): how long the merge loop waits before
41
+ * re-deriving mergeability from ground truth when `gw-mergeable` sees an async-`UNKNOWN` `"waiting"`
42
+ * verdict (issue #774). GitHub returns `mergeable=UNKNOWN` transiently while it computes mergeability
43
+ * in the background; a `"waiting"` verdict must therefore route to a *bounded re-poll* — not straight
44
+ * to a human — so the loop self-heals once GitHub settles (to `"conflict"` → `senior:rebase`, etc.).
45
+ * Deliberately SHORT (unlike the 30-minute {@link DEFAULT_MERGEABLE_WAIT_TIMEOUT} poller-death
46
+ * backstop): GitHub usually settles UNKNOWN within seconds, so re-poll briskly rather than parking
47
+ * the PR for tens of minutes per round. The re-poll is bounded by the shared `mergeStallMax` budget
48
+ * (`NANO_PR_MAX_MERGE_STALL_ROUNDS`): once exhausted, `gw-merge-stall` escalates to a human. */
49
+ export const DEFAULT_MERGEABLE_REPOLL_INTERVAL = "PT2M";
50
+
51
+ /** Validate the operator-supplied mergeability re-poll interval (env
52
+ * `NANO_PR_MERGEABLE_REPOLL_INTERVAL`, ISO-8601 duration), falling back to
53
+ * {@link DEFAULT_MERGEABLE_REPOLL_INTERVAL} when absent, blank, or malformed — a bad env value must
54
+ * never deploy an uninterpretable timer expression. Derives its validation from the single canonical
55
+ * {@link isoDuration}. */
56
+ export function mergeableRepollInterval(
57
+ raw: string | undefined,
58
+ def: string = DEFAULT_MERGEABLE_REPOLL_INTERVAL,
59
+ ): string {
60
+ return isoDuration(raw, def);
61
+ }
package/app/service.ts CHANGED
@@ -53,7 +53,7 @@ import {
53
53
  } from "./github.ts";
54
54
  import { activeStatusesFor, derivedTrackingTable } from "./instanceTracking.ts";
55
55
  import { pollLineage } from "./lineage.ts";
56
- import { mergeableWaitTimeout } from "./mergeableWait.ts";
56
+ import { mergeableRepollInterval, mergeableWaitTimeout } from "./mergeableWait.ts";
57
57
  import { mergeLanes, readExclusions } from "./mergeExclusion.ts";
58
58
  import { mergeLandedWaitTimeout } from "./mergeLandedWait.ts";
59
59
  import {
@@ -206,6 +206,19 @@ export const MERGEABLE_WAIT_TIMEOUT = mergeableWaitTimeout(
206
206
  process.env.NANO_PR_MERGEABLE_WAIT_TIMEOUT,
207
207
  );
208
208
 
209
+ /** How long the merge loop waits before re-deriving mergeability from ground truth when
210
+ * `gw-mergeable` sees an async-`UNKNOWN` `"waiting"` verdict (issue #774). Seeded as the
211
+ * `mergeableRepollInterval` process variable at merge start and evaluated by the merge-loop's
212
+ * `wait-mergeable-repoll` timer catch. A `"waiting"` verdict means GitHub is still computing
213
+ * mergeability in the background — so route it to a *bounded re-poll* (this timer → `merge-stall-probe`
214
+ * → the existing `gw-mergeable` arms), not to a human. The re-poll shares the `mergeStallMax` budget
215
+ * (`NANO_PR_MAX_MERGE_STALL_ROUNDS`) with the dead-poller stall backstop; once exhausted,
216
+ * `gw-merge-stall` escalates. ISO-8601 duration; a malformed `NANO_PR_MERGEABLE_REPOLL_INTERVAL`
217
+ * falls back to the default so an uninterpretable timer is never deployed. */
218
+ export const MERGEABLE_REPOLL_INTERVAL = mergeableRepollInterval(
219
+ process.env.NANO_PR_MERGEABLE_REPOLL_INTERVAL,
220
+ );
221
+
209
222
  /** Cooldown (ms) between the poller's automatic Copilot re-request nudges for a single waiting PR.
210
223
  * Copilot dismisses re-requests, so the poller retries — but not on every tick; this throttles it
211
224
  * to one attempt per window. Set via `NANO_PR_REVIEW_NUDGE_MINUTES` (minutes). */
@@ -678,6 +691,7 @@ export async function startMerge(
678
691
  agentSlaTimeout: AGENT_SLA_TIMEOUT,
679
692
  landedWaitTimeout: MERGE_LANDED_WAIT_TIMEOUT,
680
693
  mergeableWaitTimeout: MERGEABLE_WAIT_TIMEOUT,
694
+ mergeableRepollInterval: MERGEABLE_REPOLL_INTERVAL,
681
695
  mergeStallRounds: 0,
682
696
  mergeStallMax: MAX_MERGE_STALL_ROUNDS,
683
697
  // Lineage (issue #245): thread the origin identity onto the merge instance (see startMerge).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanobpm/nano-workforce",
3
- "version": "0.186.1",
3
+ "version": "0.186.2",
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",
@@ -155,8 +155,16 @@
155
155
  </zeebe:ioMapping>
156
156
  </bpmn:extensionElements>
157
157
  <bpmn:incoming>f_mw_stall</bpmn:incoming>
158
+ <bpmn:incoming>f_mrp_probe</bpmn:incoming>
158
159
  <bpmn:outgoing>f_msp_gate</bpmn:outgoing>
159
160
  </bpmn:serviceTask>
161
+ <bpmn:intermediateCatchEvent id="wait-mergeable-repoll" name="Re-poll: mergeability settling">
162
+ <bpmn:incoming>f_m_mWaiting</bpmn:incoming>
163
+ <bpmn:outgoing>f_mrp_probe</bpmn:outgoing>
164
+ <bpmn:timerEventDefinition id="ted_mergeableRepoll">
165
+ <bpmn:timeDuration xsi:type="bpmn:tFormalExpression">=mergeableRepollInterval</bpmn:timeDuration>
166
+ </bpmn:timerEventDefinition>
167
+ </bpmn:intermediateCatchEvent>
160
168
  <bpmn:exclusiveGateway id="gw-merge-stall" name="stall rounds within budget?" default="f_msp_giveup">
161
169
  <bpmn:incoming>f_msp_gate</bpmn:incoming>
162
170
  <bpmn:outgoing>f_msp_rederive</bpmn:outgoing>
@@ -168,6 +176,8 @@
168
176
  <bpmn:outgoing>f_m_mReady</bpmn:outgoing>
169
177
  <bpmn:outgoing>f_m_mCiFix</bpmn:outgoing>
170
178
  <bpmn:outgoing>f_m_mRebase</bpmn:outgoing>
179
+ <bpmn:outgoing>f_m_mWaiting</bpmn:outgoing>
180
+ <bpmn:outgoing>f_m_mDraft</bpmn:outgoing>
171
181
  <bpmn:outgoing>f_m_mBlocked</bpmn:outgoing>
172
182
  </bpmn:exclusiveGateway>
173
183
  <bpmn:serviceTask id="attempt-merge" name="Merge PR">
@@ -247,10 +257,10 @@
247
257
  </zeebe:properties>
248
258
  <zeebe:ioMapping>
249
259
  <zeebe:input source="=&#34;blocked&#34;" target="status" />
250
- <zeebe:input source="=if mergeState = &#34;draft&#34; then &#34;This PR is in draft and can&#39;t be merged. Mark it ready (gh pr ready), then reply to retry.&#34; else &#34;This PR is not mergeable (state: &#34; + mergeState + &#34;). Resolve the conflict or failing required check on the branch, then reply to retry.&#34;" target="question" />
260
+ <zeebe:input source="=if mergeState = &#34;draft&#34; then &#34;This PR is in draft and can&#39;t be merged. Mark it ready (gh pr ready), then reply to retry.&#34; else if mergeState = &#34;waiting&#34; then &#34;GitHub never settled this PR&#39;s mergeability (still computing after repeated re-polls, or the state could not be read). Check the PR on GitHub — resolve any conflict or failing required check if present — then reply to retry.&#34; else &#34;This PR is not mergeable (state: &#34; + mergeState + &#34;). Resolve the conflict or failing required check on the branch, then reply to retry.&#34;" target="question" />
251
261
  </zeebe:ioMapping>
252
262
  </bpmn:extensionElements>
253
- <bpmn:incoming>f_m_mBlocked</bpmn:incoming>
263
+ <bpmn:incoming>f_m_mDraft</bpmn:incoming>
254
264
  <bpmn:incoming>f_ci_giveup</bpmn:incoming>
255
265
  <bpmn:incoming>f_reb_giveup</bpmn:incoming>
256
266
  <bpmn:incoming>f_reb_escConflict</bpmn:incoming>
@@ -484,6 +494,7 @@
484
494
  <bpmn:sequenceFlow id="f_ci_rearm" name="fixed / re-attempt / reconcile — re-arm" sourceRef="gw-ci-outcome" targetRef="arm-merge" />
485
495
  <bpmn:exclusiveGateway id="gw-rebase" name="auto-rebase?" default="f_reb_giveup">
486
496
  <bpmn:incoming>f_m_mRebase</bpmn:incoming>
497
+ <bpmn:incoming>f_m_mBlocked</bpmn:incoming>
487
498
  <bpmn:outgoing>f_reb_go</bpmn:outgoing>
488
499
  <bpmn:outgoing>f_reb_giveup</bpmn:outgoing>
489
500
  </bpmn:exclusiveGateway>
@@ -629,7 +640,14 @@
629
640
  <bpmn:sequenceFlow id="f_m_mRebase" name="conflict" sourceRef="gw-mergeable" targetRef="gw-rebase">
630
641
  <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=mergeState = "conflict"</bpmn:conditionExpression>
631
642
  </bpmn:sequenceFlow>
632
- <bpmn:sequenceFlow id="f_m_mBlocked" name="not landable" sourceRef="gw-mergeable" targetRef="merge-esc-conflict" />
643
+ <bpmn:sequenceFlow id="f_m_mWaiting" name="waiting (GitHub still computing) — re-poll" sourceRef="gw-mergeable" targetRef="wait-mergeable-repoll">
644
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=mergeState = "waiting"</bpmn:conditionExpression>
645
+ </bpmn:sequenceFlow>
646
+ <bpmn:sequenceFlow id="f_m_mDraft" name="draft — mark ready (human)" sourceRef="gw-mergeable" targetRef="merge-esc-conflict">
647
+ <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=mergeState = "draft"</bpmn:conditionExpression>
648
+ </bpmn:sequenceFlow>
649
+ <bpmn:sequenceFlow id="f_mrp_probe" sourceRef="wait-mergeable-repoll" targetRef="merge-stall-probe" />
650
+ <bpmn:sequenceFlow id="f_m_mBlocked" name="unclassified — auto-rebase" sourceRef="gw-mergeable" targetRef="gw-rebase" />
633
651
  <bpmn:sequenceFlow id="f_ci_go" name="within budget" sourceRef="gw-ci-fix" targetRef="SP_cifix">
634
652
  <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">=ciFixRound &lt; ciFixMax and failingChecks &gt; 0</bpmn:conditionExpression>
635
653
  </bpmn:sequenceFlow>
@@ -708,137 +726,143 @@
708
726
  <bpmndi:BPMNShape id="BPMNShape_wait-mergeable" bpmnElement="wait-mergeable">
709
727
  <dc:Bounds x="852" y="262" width="36" height="36" />
710
728
  <bpmndi:BPMNLabel>
711
- <dc:Bounds x="835" y="303" width="70" height="28" />
729
+ <dc:Bounds x="835" y="229" width="70" height="28" />
712
730
  </bpmndi:BPMNLabel>
713
731
  </bpmndi:BPMNShape>
714
732
  <bpmndi:BPMNShape id="BPMNShape_wait-mergeable-timeout" bpmnElement="wait-mergeable-timeout">
715
- <dc:Bounds x="852" y="422" width="36" height="36" />
733
+ <dc:Bounds x="852" y="582" width="36" height="36" />
716
734
  <bpmndi:BPMNLabel>
717
- <dc:Bounds x="835" y="463" width="70" height="42" />
735
+ <dc:Bounds x="893" y="579" width="70" height="42" />
718
736
  </bpmndi:BPMNLabel>
719
737
  </bpmndi:BPMNShape>
720
738
  <bpmndi:BPMNShape id="BPMNShape_merge-stall-probe" bpmnElement="merge-stall-probe">
721
- <dc:Bounds x="988" y="400" width="100" height="80" />
739
+ <dc:Bounds x="1338" y="1520" width="100" height="80" />
740
+ </bpmndi:BPMNShape>
741
+ <bpmndi:BPMNShape id="BPMNShape_wait-mergeable-repoll" bpmnElement="wait-mergeable-repoll">
742
+ <dc:Bounds x="1170" y="1542" width="36" height="36" />
743
+ <bpmndi:BPMNLabel>
744
+ <dc:Bounds x="1146" y="1495" width="84" height="42" />
745
+ </bpmndi:BPMNLabel>
722
746
  </bpmndi:BPMNShape>
723
747
  <bpmndi:BPMNShape id="BPMNShape_gw-merge-stall" bpmnElement="gw-merge-stall" isMarkerVisible="true">
724
- <dc:Bounds x="1188" y="415" width="50" height="50" />
748
+ <dc:Bounds x="1538" y="1535" width="50" height="50" />
725
749
  <bpmndi:BPMNLabel>
726
- <dc:Bounds x="1191" y="470" width="85" height="42" />
750
+ <dc:Bounds x="1521" y="1650" width="85" height="42" />
727
751
  </bpmndi:BPMNLabel>
728
752
  </bpmndi:BPMNShape>
729
753
  <bpmndi:BPMNShape id="BPMNShape_gw-mergeable" bpmnElement="gw-mergeable" isMarkerVisible="true">
730
- <dc:Bounds x="1338" y="255" width="50" height="50" />
754
+ <dc:Bounds x="988" y="255" width="50" height="50" />
731
755
  <bpmndi:BPMNLabel>
732
- <dc:Bounds x="1325" y="236" width="77" height="14" />
756
+ <dc:Bounds x="975" y="236" width="77" height="14" />
733
757
  </bpmndi:BPMNLabel>
734
758
  </bpmndi:BPMNShape>
735
759
  <bpmndi:BPMNShape id="BPMNShape_attempt-merge" bpmnElement="attempt-merge">
736
- <dc:Bounds x="1488" y="240" width="100" height="80" />
760
+ <dc:Bounds x="1138" y="240" width="100" height="80" />
737
761
  </bpmndi:BPMNShape>
738
762
  <bpmndi:BPMNShape id="BPMNShape_gw-merge" bpmnElement="gw-merge" isMarkerVisible="true">
739
- <dc:Bounds x="1713" y="255" width="50" height="50" />
763
+ <dc:Bounds x="1363" y="255" width="50" height="50" />
740
764
  <bpmndi:BPMNLabel>
741
- <dc:Bounds x="1712" y="350" width="53" height="28" />
765
+ <dc:Bounds x="1362" y="350" width="53" height="28" />
742
766
  </bpmndi:BPMNLabel>
743
767
  </bpmndi:BPMNShape>
744
768
  <bpmndi:BPMNShape id="BPMNShape_gw-merge-retry" bpmnElement="gw-merge-retry" isMarkerVisible="true">
745
- <dc:Bounds x="1888" y="735" width="50" height="50" />
769
+ <dc:Bounds x="1538" y="735" width="50" height="50" />
746
770
  <bpmndi:BPMNLabel>
747
- <dc:Bounds x="1869" y="830" width="88" height="28" />
771
+ <dc:Bounds x="1519" y="702" width="88" height="28" />
748
772
  </bpmndi:BPMNLabel>
749
773
  </bpmndi:BPMNShape>
750
774
  <bpmndi:BPMNShape id="BPMNShape_eg-landed" bpmnElement="eg-landed" isMarkerVisible="true">
751
- <dc:Bounds x="1888" y="415" width="50" height="50" />
775
+ <dc:Bounds x="1538" y="415" width="50" height="50" />
752
776
  <bpmndi:BPMNLabel>
753
- <dc:Bounds x="1881" y="490" width="64" height="28" />
777
+ <dc:Bounds x="1531" y="490" width="64" height="28" />
754
778
  </bpmndi:BPMNLabel>
755
779
  </bpmndi:BPMNShape>
756
780
  <bpmndi:BPMNShape id="BPMNShape_wait-landed" bpmnElement="wait-landed">
757
- <dc:Bounds x="2070" y="422" width="36" height="36" />
781
+ <dc:Bounds x="1720" y="422" width="36" height="36" />
758
782
  <bpmndi:BPMNLabel>
759
- <dc:Bounds x="2066" y="483" width="85" height="28" />
783
+ <dc:Bounds x="1736" y="483" width="85" height="28" />
760
784
  </bpmndi:BPMNLabel>
761
785
  </bpmndi:BPMNShape>
762
786
  <bpmndi:BPMNShape id="BPMNShape_wait-evicted" bpmnElement="wait-evicted">
763
- <dc:Bounds x="2070" y="582" width="36" height="36" />
787
+ <dc:Bounds x="1720" y="582" width="36" height="36" />
764
788
  <bpmndi:BPMNLabel>
765
- <dc:Bounds x="2111" y="579" width="88" height="42" />
789
+ <dc:Bounds x="1761" y="579" width="88" height="42" />
766
790
  </bpmndi:BPMNLabel>
767
791
  </bpmndi:BPMNShape>
768
792
  <bpmndi:BPMNShape id="BPMNShape_wait-landed-timeout" bpmnElement="wait-landed-timeout">
769
- <dc:Bounds x="2070" y="102" width="36" height="36" />
793
+ <dc:Bounds x="1720" y="102" width="36" height="36" />
770
794
  <bpmndi:BPMNLabel>
771
- <dc:Bounds x="1981" y="92" width="84" height="56" />
795
+ <dc:Bounds x="1596" y="143" width="84" height="56" />
772
796
  </bpmndi:BPMNLabel>
773
797
  </bpmndi:BPMNShape>
774
798
  <bpmndi:BPMNShape id="BPMNShape_mark-merged" bpmnElement="mark-merged">
775
- <dc:Bounds x="2238" y="240" width="100" height="80" />
799
+ <dc:Bounds x="1888" y="240" width="100" height="80" />
776
800
  </bpmndi:BPMNShape>
777
801
  <bpmndi:BPMNShape id="BPMNShape_MergeEnd" bpmnElement="MergeEnd">
778
- <dc:Bounds x="2445" y="262" width="36" height="36" />
802
+ <dc:Bounds x="2095" y="262" width="36" height="36" />
779
803
  <bpmndi:BPMNLabel>
780
- <dc:Bounds x="2438" y="303" width="50" height="14" />
804
+ <dc:Bounds x="2088" y="303" width="50" height="14" />
781
805
  </bpmndi:BPMNLabel>
782
806
  </bpmndi:BPMNShape>
783
807
  <bpmndi:BPMNShape id="BPMNShape_MergeAbandoned" bpmnElement="MergeAbandoned">
784
- <dc:Bounds x="1895" y="902" width="36" height="36" />
808
+ <dc:Bounds x="1545" y="902" width="36" height="36" />
785
809
  <bpmndi:BPMNLabel>
786
- <dc:Bounds x="1872" y="943" width="82" height="28" />
810
+ <dc:Bounds x="1522" y="943" width="82" height="28" />
787
811
  </bpmndi:BPMNLabel>
788
812
  </bpmndi:BPMNShape>
789
813
  <bpmndi:BPMNShape id="BPMNShape_merge-esc-conflict" bpmnElement="merge-esc-conflict">
790
- <dc:Bounds x="2038" y="1040" width="100" height="80" />
814
+ <dc:Bounds x="1688" y="1040" width="100" height="80" />
791
815
  </bpmndi:BPMNShape>
792
816
  <bpmndi:BPMNShape id="BPMNShape_merge-esc-attempt" bpmnElement="merge-esc-attempt">
793
- <dc:Bounds x="2038" y="720" width="100" height="80" />
817
+ <dc:Bounds x="1688" y="720" width="100" height="80" />
794
818
  </bpmndi:BPMNShape>
795
819
  <bpmndi:BPMNShape id="BPMNShape_gw-merge-escalated" bpmnElement="gw-merge-escalated" isMarkerVisible="true">
796
- <dc:Bounds x="2438" y="95" width="50" height="50" />
820
+ <dc:Bounds x="2088" y="95" width="50" height="50" />
797
821
  <bpmndi:BPMNLabel>
798
- <dc:Bounds x="2406" y="150" width="74" height="28" />
822
+ <dc:Bounds x="2056" y="170" width="74" height="28" />
799
823
  </bpmndi:BPMNLabel>
800
824
  </bpmndi:BPMNShape>
801
825
  <bpmndi:BPMNShape id="BPMNShape_merge-esc-landed" bpmnElement="merge-esc-landed">
802
- <dc:Bounds x="2238" y="80" width="100" height="80" />
826
+ <dc:Bounds x="1888" y="80" width="100" height="80" />
803
827
  </bpmndi:BPMNShape>
804
828
  <bpmndi:BPMNShape id="BPMNShape_wait-merge-answer" bpmnElement="wait-merge-answer">
805
- <dc:Bounds x="2588" y="80" width="100" height="80" />
829
+ <dc:Bounds x="2238" y="80" width="100" height="80" />
806
830
  </bpmndi:BPMNShape>
807
831
  <bpmndi:BPMNShape id="BPMNShape_record-merge-answer" bpmnElement="record-merge-answer">
808
- <dc:Bounds x="2788" y="80" width="100" height="80" />
832
+ <dc:Bounds x="2438" y="80" width="100" height="80" />
809
833
  </bpmndi:BPMNShape>
810
834
  <bpmndi:BPMNShape id="BPMNShape_gw-ci-fix" bpmnElement="gw-ci-fix" isMarkerVisible="true">
811
- <dc:Bounds x="1513" y="1055" width="50" height="50" />
835
+ <dc:Bounds x="1163" y="1055" width="50" height="50" />
812
836
  <bpmndi:BPMNLabel>
813
- <dc:Bounds x="1494" y="1036" width="89" height="14" />
837
+ <dc:Bounds x="1204" y="1110" width="89" height="14" />
814
838
  </bpmndi:BPMNLabel>
815
839
  </bpmndi:BPMNShape>
816
840
  <bpmndi:BPMNShape id="BPMNShape_SP_cifix" bpmnElement="SP_cifix">
817
- <dc:Bounds x="1688" y="1200" width="100" height="80" />
841
+ <dc:Bounds x="1338" y="1200" width="100" height="80" />
818
842
  </bpmndi:BPMNShape>
819
843
  <bpmndi:BPMNShape id="BPMNShape_gw-ci-outcome" bpmnElement="gw-ci-outcome" isMarkerVisible="true">
820
- <dc:Bounds x="1888" y="1215" width="50" height="50" />
844
+ <dc:Bounds x="1538" y="1215" width="50" height="50" />
821
845
  <bpmndi:BPMNLabel>
822
- <dc:Bounds x="1882" y="1310" width="63" height="28" />
846
+ <dc:Bounds x="1532" y="1310" width="63" height="28" />
823
847
  </bpmndi:BPMNLabel>
824
848
  </bpmndi:BPMNShape>
825
849
  <bpmndi:BPMNShape id="BPMNShape_gw-rebase" bpmnElement="gw-rebase" isMarkerVisible="true">
826
- <dc:Bounds x="1513" y="415" width="50" height="50" />
850
+ <dc:Bounds x="1163" y="415" width="50" height="50" />
827
851
  <bpmndi:BPMNLabel>
828
- <dc:Bounds x="1494" y="470" width="88" height="14" />
852
+ <dc:Bounds x="1144" y="370" width="88" height="14" />
829
853
  </bpmndi:BPMNLabel>
830
854
  </bpmndi:BPMNShape>
831
855
  <bpmndi:BPMNShape id="BPMNShape_SP_rebase" bpmnElement="SP_rebase">
832
- <dc:Bounds x="1688" y="1360" width="100" height="80" />
856
+ <dc:Bounds x="1338" y="1360" width="100" height="80" />
833
857
  </bpmndi:BPMNShape>
834
858
  <bpmndi:BPMNShape id="BPMNShape_gw-rebase-outcome" bpmnElement="gw-rebase-outcome" isMarkerVisible="true">
835
- <dc:Bounds x="1888" y="1375" width="50" height="50" />
859
+ <dc:Bounds x="1538" y="1375" width="50" height="50" />
836
860
  <bpmndi:BPMNLabel>
837
- <dc:Bounds x="1922" y="1430" width="63" height="28" />
861
+ <dc:Bounds x="1532" y="1470" width="63" height="28" />
838
862
  </bpmndi:BPMNLabel>
839
863
  </bpmndi:BPMNShape>
840
864
  <bpmndi:BPMNShape id="BPMNShape_record-merge-dep" bpmnElement="record-merge-dep">
841
- <dc:Bounds x="2038" y="1200" width="100" height="80" />
865
+ <dc:Bounds x="1688" y="1200" width="100" height="80" />
842
866
  </bpmndi:BPMNShape>
843
867
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_start" bpmnElement="f_m_start">
844
868
  <di:waypoint x="116" y="280" />
@@ -862,33 +886,33 @@
862
886
  </bpmndi:BPMNEdge>
863
887
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_ready" bpmnElement="f_m_ready">
864
888
  <di:waypoint x="888" y="280" />
865
- <di:waypoint x="1338" y="280" />
889
+ <di:waypoint x="988" y="280" />
866
890
  </bpmndi:BPMNEdge>
867
891
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_mReady" bpmnElement="f_m_mReady">
868
- <di:waypoint x="1388" y="280" />
869
- <di:waypoint x="1488" y="280" />
892
+ <di:waypoint x="1038" y="280" />
893
+ <di:waypoint x="1138" y="280" />
870
894
  <bpmndi:BPMNLabel>
871
- <dc:Bounds x="1419" y="258" width="39" height="14" />
895
+ <dc:Bounds x="1069" y="258" width="39" height="14" />
872
896
  </bpmndi:BPMNLabel>
873
897
  </bpmndi:BPMNEdge>
874
898
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_attempt" bpmnElement="f_m_attempt">
875
- <di:waypoint x="1588" y="280" />
876
- <di:waypoint x="1713" y="280" />
899
+ <di:waypoint x="1238" y="280" />
900
+ <di:waypoint x="1363" y="280" />
877
901
  </bpmndi:BPMNEdge>
878
902
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_gMerged" bpmnElement="f_m_gMerged">
879
- <di:waypoint x="1763" y="280" />
880
- <di:waypoint x="2238" y="280" />
903
+ <di:waypoint x="1413" y="280" />
904
+ <di:waypoint x="1888" y="280" />
881
905
  <bpmndi:BPMNLabel>
882
- <dc:Bounds x="2051" y="258" width="49" height="14" />
906
+ <dc:Bounds x="1721" y="258" width="49" height="14" />
883
907
  </bpmndi:BPMNLabel>
884
908
  </bpmndi:BPMNEdge>
885
909
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_done" bpmnElement="f_m_done">
886
- <di:waypoint x="2338" y="280" />
887
- <di:waypoint x="2445" y="280" />
910
+ <di:waypoint x="1988" y="280" />
911
+ <di:waypoint x="2095" y="280" />
888
912
  </bpmndi:BPMNEdge>
889
913
  <bpmndi:BPMNEdge id="BPMNEdge_f_ci_rearm" bpmnElement="f_ci_rearm">
890
- <di:waypoint x="1913" y="1265" />
891
- <di:waypoint x="1913" y="1300" />
914
+ <di:waypoint x="1563" y="1265" />
915
+ <di:waypoint x="1563" y="1300" />
892
916
  <di:waypoint x="402" y="1300" />
893
917
  <di:waypoint x="402" y="320" />
894
918
  <bpmndi:BPMNLabel>
@@ -896,316 +920,348 @@
896
920
  </bpmndi:BPMNLabel>
897
921
  </bpmndi:BPMNEdge>
898
922
  <bpmndi:BPMNEdge id="BPMNEdge_f_reb_rearm" bpmnElement="f_reb_rearm">
899
- <di:waypoint x="1913" y="1425" />
900
- <di:waypoint x="1913" y="1460" />
923
+ <di:waypoint x="1563" y="1425" />
924
+ <di:waypoint x="1563" y="1460" />
901
925
  <di:waypoint x="402" y="1460" />
902
926
  <di:waypoint x="402" y="320" />
903
927
  <bpmndi:BPMNLabel>
904
- <dc:Bounds x="1119" y="1413" width="78" height="42" />
928
+ <dc:Bounds x="924" y="1413" width="78" height="42" />
905
929
  </bpmndi:BPMNLabel>
906
930
  </bpmndi:BPMNEdge>
907
931
  <bpmndi:BPMNEdge id="BPMNEdge_f_msp_giveup" bpmnElement="f_msp_giveup">
908
- <di:waypoint x="1238" y="440" />
909
- <di:waypoint x="1258" y="440" />
910
- <di:waypoint x="1258" y="465" />
911
- <di:waypoint x="1651" y="465" />
912
- <di:waypoint x="1651" y="1060" />
913
- <di:waypoint x="2038" y="1060" />
932
+ <di:waypoint x="1588" y="1560" />
933
+ <di:waypoint x="1608" y="1560" />
934
+ <di:waypoint x="1608" y="1535" />
935
+ <di:waypoint x="1601" y="1535" />
936
+ <di:waypoint x="1601" y="1140" />
937
+ <di:waypoint x="1708" y="1140" />
938
+ <di:waypoint x="1708" y="1120" />
914
939
  <bpmndi:BPMNLabel>
915
- <dc:Bounds x="1378" y="470" width="85" height="28" />
940
+ <dc:Bounds x="1606" y="1441" width="85" height="28" />
916
941
  </bpmndi:BPMNLabel>
917
942
  </bpmndi:BPMNEdge>
918
943
  <bpmndi:BPMNEdge id="BPMNEdge_f_ci_giveup" bpmnElement="f_ci_giveup">
919
- <di:waypoint x="1563" y="1080" />
920
- <di:waypoint x="2038" y="1080" />
944
+ <di:waypoint x="1213" y="1080" />
945
+ <di:waypoint x="1688" y="1080" />
921
946
  <bpmndi:BPMNLabel>
922
- <dc:Bounds x="1757" y="1085" width="67" height="28" />
947
+ <dc:Bounds x="1424" y="1085" width="67" height="28" />
923
948
  </bpmndi:BPMNLabel>
924
949
  </bpmndi:BPMNEdge>
925
950
  <bpmndi:BPMNEdge id="BPMNEdge_f_reb_giveup" bpmnElement="f_reb_giveup">
926
- <di:waypoint x="1563" y="440" />
927
- <di:waypoint x="1583" y="440" />
928
- <di:waypoint x="1583" y="465" />
929
- <di:waypoint x="1813" y="465" />
930
- <di:waypoint x="1813" y="1060" />
931
- <di:waypoint x="2038" y="1060" />
951
+ <di:waypoint x="1213" y="440" />
952
+ <di:waypoint x="1233" y="440" />
953
+ <di:waypoint x="1233" y="465" />
954
+ <di:waypoint x="1463" y="465" />
955
+ <di:waypoint x="1463" y="1060" />
956
+ <di:waypoint x="1688" y="1060" />
932
957
  <bpmndi:BPMNLabel>
933
- <dc:Bounds x="1699" y="432" width="67" height="28" />
958
+ <dc:Bounds x="1391" y="749" width="67" height="28" />
934
959
  </bpmndi:BPMNLabel>
935
960
  </bpmndi:BPMNEdge>
936
961
  <bpmndi:BPMNEdge id="BPMNEdge_f_mr_giveup" bpmnElement="f_mr_giveup">
937
- <di:waypoint x="1938" y="760" />
938
- <di:waypoint x="2038" y="760" />
962
+ <di:waypoint x="1588" y="760" />
963
+ <di:waypoint x="1688" y="760" />
939
964
  <bpmndi:BPMNLabel>
940
- <dc:Bounds x="1935" y="687" width="67" height="28" />
965
+ <dc:Bounds x="1605" y="765" width="67" height="28" />
941
966
  </bpmndi:BPMNLabel>
942
967
  </bpmndi:BPMNEdge>
943
968
  <bpmndi:BPMNEdge id="BPMNEdge_f_eg_landed" bpmnElement="f_eg_landed">
944
- <di:waypoint x="1938" y="440" />
945
- <di:waypoint x="2070" y="440" />
969
+ <di:waypoint x="1588" y="440" />
970
+ <di:waypoint x="1720" y="440" />
946
971
  </bpmndi:BPMNEdge>
947
972
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_landed" bpmnElement="f_m_landed">
948
- <di:waypoint x="2106" y="440" />
949
- <di:waypoint x="2288" y="440" />
950
- <di:waypoint x="2288" y="320" />
973
+ <di:waypoint x="1756" y="440" />
974
+ <di:waypoint x="1938" y="440" />
975
+ <di:waypoint x="1938" y="320" />
951
976
  </bpmndi:BPMNEdge>
952
977
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_escC" bpmnElement="f_m_escC">
953
- <di:waypoint x="2138" y="1080" />
954
- <di:waypoint x="2638" y="1080" />
955
- <di:waypoint x="2638" y="160" />
978
+ <di:waypoint x="1788" y="1080" />
979
+ <di:waypoint x="2288" y="1080" />
980
+ <di:waypoint x="2288" y="160" />
956
981
  </bpmndi:BPMNEdge>
957
982
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_escA" bpmnElement="f_m_escA">
958
- <di:waypoint x="2138" y="760" />
959
- <di:waypoint x="2501" y="760" />
960
- <di:waypoint x="2501" y="145" />
961
- <di:waypoint x="2508" y="145" />
962
- <di:waypoint x="2508" y="120" />
963
- <di:waypoint x="2488" y="120" />
983
+ <di:waypoint x="1788" y="760" />
984
+ <di:waypoint x="2151" y="760" />
985
+ <di:waypoint x="2151" y="145" />
986
+ <di:waypoint x="2158" y="145" />
987
+ <di:waypoint x="2158" y="120" />
988
+ <di:waypoint x="2138" y="120" />
964
989
  </bpmndi:BPMNEdge>
965
990
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_escReenter" bpmnElement="f_m_escReenter">
966
- <di:waypoint x="2463" y="95" />
967
- <di:waypoint x="2463" y="60" />
991
+ <di:waypoint x="2113" y="95" />
992
+ <di:waypoint x="2113" y="60" />
968
993
  <di:waypoint x="402" y="60" />
969
994
  <di:waypoint x="402" y="240" />
970
995
  <bpmndi:BPMNLabel>
971
- <dc:Bounds x="1396" y="13" width="74" height="42" />
996
+ <dc:Bounds x="1221" y="13" width="74" height="42" />
972
997
  </bpmndi:BPMNLabel>
973
998
  </bpmndi:BPMNEdge>
974
999
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_answerRecord" bpmnElement="f_m_answerRecord">
975
- <di:waypoint x="2688" y="120" />
976
- <di:waypoint x="2788" y="120" />
1000
+ <di:waypoint x="2338" y="120" />
1001
+ <di:waypoint x="2438" y="120" />
977
1002
  </bpmndi:BPMNEdge>
978
1003
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_answer" bpmnElement="f_m_answer">
979
- <di:waypoint x="2838" y="160" />
980
- <di:waypoint x="2838" y="340" />
1004
+ <di:waypoint x="2488" y="160" />
1005
+ <di:waypoint x="2488" y="340" />
981
1006
  <di:waypoint x="402" y="340" />
982
1007
  <di:waypoint x="402" y="320" />
983
1008
  </bpmndi:BPMNEdge>
984
1009
  <bpmndi:BPMNEdge id="BPMNEdge_f_ci_escAttempt" bpmnElement="f_ci_escAttempt">
985
- <di:waypoint x="1913" y="1215" />
986
- <di:waypoint x="1913" y="1195" />
987
- <di:waypoint x="1168" y="1195" />
988
- <di:waypoint x="1168" y="402" />
989
- <di:waypoint x="1868" y="402" />
990
- <di:waypoint x="1868" y="478" />
991
- <di:waypoint x="2018" y="478" />
992
- <di:waypoint x="2018" y="740" />
993
- <di:waypoint x="2038" y="740" />
1010
+ <di:waypoint x="1563" y="1215" />
1011
+ <di:waypoint x="1563" y="1195" />
1012
+ <di:waypoint x="1150" y="1195" />
1013
+ <di:waypoint x="1150" y="402" />
1014
+ <di:waypoint x="1518" y="402" />
1015
+ <di:waypoint x="1518" y="478" />
1016
+ <di:waypoint x="1668" y="478" />
1017
+ <di:waypoint x="1668" y="740" />
1018
+ <di:waypoint x="1688" y="740" />
994
1019
  <bpmndi:BPMNLabel>
995
- <dc:Bounds x="1551" y="1203" width="60" height="14" />
1020
+ <dc:Bounds x="1327" y="1173" width="60" height="14" />
996
1021
  </bpmndi:BPMNLabel>
997
1022
  </bpmndi:BPMNEdge>
998
1023
  <bpmndi:BPMNEdge id="BPMNEdge_f_reb_waitDep" bpmnElement="f_reb_waitDep">
999
- <di:waypoint x="1938" y="1400" />
1000
- <di:waypoint x="2088" y="1400" />
1001
- <di:waypoint x="2088" y="1280" />
1024
+ <di:waypoint x="1588" y="1400" />
1025
+ <di:waypoint x="1738" y="1400" />
1026
+ <di:waypoint x="1738" y="1280" />
1002
1027
  <bpmndi:BPMNLabel>
1003
- <dc:Bounds x="1996" y="1405" width="75" height="28" />
1028
+ <dc:Bounds x="1636" y="1367" width="75" height="28" />
1004
1029
  </bpmndi:BPMNLabel>
1005
1030
  </bpmndi:BPMNEdge>
1006
1031
  <bpmndi:BPMNEdge id="BPMNEdge_f_reb_escAttempt" bpmnElement="f_reb_escAttempt">
1007
- <di:waypoint x="1913" y="1375" />
1008
- <di:waypoint x="1913" y="1355" />
1009
- <di:waypoint x="1168" y="1355" />
1010
- <di:waypoint x="1168" y="402" />
1011
- <di:waypoint x="1868" y="402" />
1012
- <di:waypoint x="1868" y="478" />
1013
- <di:waypoint x="2018" y="478" />
1014
- <di:waypoint x="2018" y="740" />
1015
- <di:waypoint x="2038" y="740" />
1032
+ <di:waypoint x="1563" y="1375" />
1033
+ <di:waypoint x="1563" y="1355" />
1034
+ <di:waypoint x="1150" y="1355" />
1035
+ <di:waypoint x="1150" y="402" />
1036
+ <di:waypoint x="1518" y="402" />
1037
+ <di:waypoint x="1518" y="478" />
1038
+ <di:waypoint x="1668" y="478" />
1039
+ <di:waypoint x="1668" y="740" />
1040
+ <di:waypoint x="1688" y="740" />
1016
1041
  <bpmndi:BPMNLabel>
1017
- <dc:Bounds x="1173" y="1234" width="64" height="42" />
1042
+ <dc:Bounds x="1081" y="1234" width="64" height="42" />
1018
1043
  </bpmndi:BPMNLabel>
1019
1044
  </bpmndi:BPMNEdge>
1020
1045
  <bpmndi:BPMNEdge id="BPMNEdge_f_reb_escConflict" bpmnElement="f_reb_escConflict">
1021
- <di:waypoint x="1938" y="1400" />
1022
- <di:waypoint x="2018" y="1400" />
1023
- <di:waypoint x="2018" y="1080" />
1024
- <di:waypoint x="2038" y="1080" />
1046
+ <di:waypoint x="1588" y="1400" />
1047
+ <di:waypoint x="1608" y="1400" />
1048
+ <di:waypoint x="1608" y="1375" />
1049
+ <di:waypoint x="1601" y="1375" />
1050
+ <di:waypoint x="1601" y="1080" />
1051
+ <di:waypoint x="1688" y="1080" />
1025
1052
  <bpmndi:BPMNLabel>
1026
- <dc:Bounds x="1953" y="1246" width="60" height="28" />
1053
+ <dc:Bounds x="1606" y="1264" width="60" height="28" />
1027
1054
  </bpmndi:BPMNLabel>
1028
1055
  </bpmndi:BPMNEdge>
1029
1056
  <bpmndi:BPMNEdge id="BPMNEdge_f_mw_timeout" bpmnElement="f_mw_timeout">
1030
- <di:waypoint x="727" y="305" />
1031
- <di:waypoint x="727" y="440" />
1032
- <di:waypoint x="852" y="440" />
1057
+ <di:waypoint x="752" y="280" />
1058
+ <di:waypoint x="832" y="280" />
1059
+ <di:waypoint x="832" y="600" />
1060
+ <di:waypoint x="852" y="600" />
1033
1061
  </bpmndi:BPMNEdge>
1034
- <bpmndi:BPMNEdge id="BPMNEdge_f_msp_rederive" bpmnElement="f_msp_rederive">
1035
- <di:waypoint x="1213" y="415" />
1036
- <di:waypoint x="1213" y="280" />
1037
- <di:waypoint x="1338" y="280" />
1062
+ <bpmndi:BPMNEdge id="BPMNEdge_f_m_mCiFix" bpmnElement="f_m_mCiFix">
1063
+ <di:waypoint x="1013" y="305" />
1064
+ <di:waypoint x="1013" y="1080" />
1065
+ <di:waypoint x="1163" y="1080" />
1038
1066
  <bpmndi:BPMNLabel>
1039
- <dc:Bounds x="1218" y="354" width="85" height="28" />
1067
+ <dc:Bounds x="1058" y="1033" width="60" height="42" />
1040
1068
  </bpmndi:BPMNLabel>
1041
1069
  </bpmndi:BPMNEdge>
1042
- <bpmndi:BPMNEdge id="BPMNEdge_f_m_mCiFix" bpmnElement="f_m_mCiFix">
1043
- <di:waypoint x="1363" y="305" />
1044
- <di:waypoint x="1363" y="1080" />
1045
- <di:waypoint x="1513" y="1080" />
1070
+ <bpmndi:BPMNEdge id="BPMNEdge_f_m_mRebase" bpmnElement="f_m_mRebase">
1071
+ <di:waypoint x="1013" y="305" />
1072
+ <di:waypoint x="1013" y="440" />
1073
+ <di:waypoint x="1163" y="440" />
1046
1074
  <bpmndi:BPMNLabel>
1047
- <dc:Bounds x="1368" y="739" width="60" height="42" />
1075
+ <dc:Bounds x="948" y="366" width="60" height="14" />
1048
1076
  </bpmndi:BPMNLabel>
1049
1077
  </bpmndi:BPMNEdge>
1050
- <bpmndi:BPMNEdge id="BPMNEdge_f_m_mRebase" bpmnElement="f_m_mRebase">
1051
- <di:waypoint x="1363" y="305" />
1052
- <di:waypoint x="1363" y="440" />
1053
- <di:waypoint x="1513" y="440" />
1078
+ <bpmndi:BPMNEdge id="BPMNEdge_f_m_mWaiting" bpmnElement="f_m_mWaiting">
1079
+ <di:waypoint x="1013" y="305" />
1080
+ <di:waypoint x="1013" y="1560" />
1081
+ <di:waypoint x="1170" y="1560" />
1082
+ <bpmndi:BPMNLabel>
1083
+ <dc:Bounds x="1048" y="1485" width="88" height="70" />
1084
+ </bpmndi:BPMNLabel>
1085
+ </bpmndi:BPMNEdge>
1086
+ <bpmndi:BPMNEdge id="BPMNEdge_f_m_mDraft" bpmnElement="f_m_mDraft">
1087
+ <di:waypoint x="1013" y="305" />
1088
+ <di:waypoint x="1013" y="478" />
1089
+ <di:waypoint x="1226" y="478" />
1090
+ <di:waypoint x="1226" y="1080" />
1091
+ <di:waypoint x="1688" y="1080" />
1054
1092
  <bpmndi:BPMNLabel>
1055
- <dc:Bounds x="1408" y="418" width="60" height="14" />
1093
+ <dc:Bounds x="1057" y="483" width="85" height="42" />
1056
1094
  </bpmndi:BPMNLabel>
1057
1095
  </bpmndi:BPMNEdge>
1058
1096
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_mBlocked" bpmnElement="f_m_mBlocked">
1059
- <di:waypoint x="1363" y="305" />
1060
- <di:waypoint x="1363" y="325" />
1061
- <di:waypoint x="1875" y="325" />
1062
- <di:waypoint x="1875" y="805" />
1063
- <di:waypoint x="2126" y="805" />
1064
- <di:waypoint x="2126" y="1040" />
1097
+ <di:waypoint x="1013" y="305" />
1098
+ <di:waypoint x="1013" y="440" />
1099
+ <di:waypoint x="1163" y="440" />
1065
1100
  <bpmndi:BPMNLabel>
1066
- <dc:Bounds x="1880" y="558" width="85" height="14" />
1101
+ <dc:Bounds x="1018" y="352" width="88" height="42" />
1067
1102
  </bpmndi:BPMNLabel>
1068
1103
  </bpmndi:BPMNEdge>
1069
1104
  <bpmndi:BPMNEdge id="BPMNEdge_f_ci_go" bpmnElement="f_ci_go">
1070
- <di:waypoint x="1538" y="1105" />
1071
- <di:waypoint x="1538" y="1240" />
1072
- <di:waypoint x="1688" y="1240" />
1105
+ <di:waypoint x="1188" y="1105" />
1106
+ <di:waypoint x="1188" y="1240" />
1107
+ <di:waypoint x="1338" y="1240" />
1073
1108
  <bpmndi:BPMNLabel>
1074
- <dc:Bounds x="1543" y="1159" width="49" height="28" />
1109
+ <dc:Bounds x="1193" y="1159" width="49" height="28" />
1075
1110
  </bpmndi:BPMNLabel>
1076
1111
  </bpmndi:BPMNEdge>
1077
1112
  <bpmndi:BPMNEdge id="BPMNEdge_f_reb_go" bpmnElement="f_reb_go">
1078
- <di:waypoint x="1563" y="440" />
1079
- <di:waypoint x="1668" y="440" />
1080
- <di:waypoint x="1668" y="1400" />
1081
- <di:waypoint x="1688" y="1400" />
1113
+ <di:waypoint x="1213" y="440" />
1114
+ <di:waypoint x="1233" y="440" />
1115
+ <di:waypoint x="1233" y="465" />
1116
+ <di:waypoint x="2158" y="465" />
1117
+ <di:waypoint x="2158" y="75" />
1118
+ <di:waypoint x="2558" y="75" />
1119
+ <di:waypoint x="2558" y="1125" />
1120
+ <di:waypoint x="1318" y="1125" />
1121
+ <di:waypoint x="1318" y="1380" />
1122
+ <di:waypoint x="1338" y="1380" />
1082
1123
  <bpmndi:BPMNLabel>
1083
- <dc:Bounds x="1673" y="906" width="49" height="28" />
1124
+ <dc:Bounds x="2334" y="42" width="49" height="28" />
1084
1125
  </bpmndi:BPMNLabel>
1085
1126
  </bpmndi:BPMNEdge>
1086
1127
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_gQueued" bpmnElement="f_m_gQueued">
1087
- <di:waypoint x="1763" y="280" />
1088
- <di:waypoint x="1913" y="280" />
1089
- <di:waypoint x="1913" y="415" />
1128
+ <di:waypoint x="1413" y="280" />
1129
+ <di:waypoint x="1563" y="280" />
1130
+ <di:waypoint x="1563" y="415" />
1090
1131
  <bpmndi:BPMNLabel>
1091
- <dc:Bounds x="1918" y="361" width="46" height="14" />
1132
+ <dc:Bounds x="1568" y="354" width="46" height="14" />
1092
1133
  </bpmndi:BPMNLabel>
1093
1134
  </bpmndi:BPMNEdge>
1094
1135
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_gRetry" bpmnElement="f_m_gRetry">
1095
- <di:waypoint x="1763" y="280" />
1096
- <di:waypoint x="1868" y="280" />
1097
- <di:waypoint x="1868" y="760" />
1098
- <di:waypoint x="1888" y="760" />
1136
+ <di:waypoint x="1388" y="255" />
1137
+ <di:waypoint x="1388" y="235" />
1138
+ <di:waypoint x="2218" y="235" />
1139
+ <di:waypoint x="2218" y="805" />
1140
+ <di:waypoint x="1538" y="805" />
1141
+ <di:waypoint x="1563" y="805" />
1142
+ <di:waypoint x="1563" y="785" />
1099
1143
  <bpmndi:BPMNLabel>
1100
- <dc:Bounds x="1785" y="419" width="78" height="28" />
1144
+ <dc:Bounds x="1852" y="772" width="78" height="28" />
1101
1145
  </bpmndi:BPMNLabel>
1102
1146
  </bpmndi:BPMNEdge>
1103
1147
  <bpmndi:BPMNEdge id="BPMNEdge_f_eg_evicted" bpmnElement="f_eg_evicted">
1104
- <di:waypoint x="1938" y="440" />
1105
- <di:waypoint x="2050" y="440" />
1106
- <di:waypoint x="2050" y="600" />
1107
- <di:waypoint x="2070" y="600" />
1148
+ <di:waypoint x="1563" y="415" />
1149
+ <di:waypoint x="1563" y="402" />
1150
+ <di:waypoint x="1720" y="402" />
1151
+ <di:waypoint x="1720" y="562" />
1152
+ <di:waypoint x="1738" y="562" />
1153
+ <di:waypoint x="1738" y="582" />
1108
1154
  </bpmndi:BPMNEdge>
1109
1155
  <bpmndi:BPMNEdge id="BPMNEdge_f_eg_landedTimeout" bpmnElement="f_eg_landedTimeout">
1110
- <di:waypoint x="1938" y="440" />
1111
- <di:waypoint x="1958" y="440" />
1112
- <di:waypoint x="1958" y="415" />
1113
- <di:waypoint x="2070" y="415" />
1114
- <di:waypoint x="2070" y="478" />
1115
- <di:waypoint x="2508" y="478" />
1116
- <di:waypoint x="2508" y="235" />
1117
- <di:waypoint x="2070" y="235" />
1118
- <di:waypoint x="2070" y="158" />
1119
- <di:waypoint x="2088" y="158" />
1120
- <di:waypoint x="2088" y="138" />
1156
+ <di:waypoint x="1588" y="440" />
1157
+ <di:waypoint x="1700" y="440" />
1158
+ <di:waypoint x="1700" y="120" />
1159
+ <di:waypoint x="1720" y="120" />
1121
1160
  </bpmndi:BPMNEdge>
1122
1161
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_gBlocked" bpmnElement="f_m_gBlocked">
1123
- <di:waypoint x="1763" y="280" />
1124
- <di:waypoint x="1783" y="280" />
1125
- <di:waypoint x="1783" y="305" />
1126
- <di:waypoint x="1868" y="305" />
1127
- <di:waypoint x="1868" y="820" />
1128
- <di:waypoint x="2018" y="820" />
1129
- <di:waypoint x="2018" y="780" />
1130
- <di:waypoint x="2038" y="780" />
1162
+ <di:waypoint x="1388" y="255" />
1163
+ <di:waypoint x="1388" y="82" />
1164
+ <di:waypoint x="1776" y="82" />
1165
+ <di:waypoint x="1776" y="165" />
1166
+ <di:waypoint x="2218" y="165" />
1167
+ <di:waypoint x="2218" y="638" />
1168
+ <di:waypoint x="1668" y="638" />
1169
+ <di:waypoint x="1668" y="740" />
1170
+ <di:waypoint x="1688" y="740" />
1131
1171
  <bpmndi:BPMNLabel>
1132
- <dc:Bounds x="1977" y="828" width="53" height="14" />
1172
+ <dc:Bounds x="1952" y="616" width="53" height="14" />
1133
1173
  </bpmndi:BPMNLabel>
1134
1174
  </bpmndi:BPMNEdge>
1135
1175
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_gAbandoned" bpmnElement="f_m_gAbandoned">
1136
- <di:waypoint x="1738" y="255" />
1137
- <di:waypoint x="1738" y="242" />
1138
- <di:waypoint x="2126" y="242" />
1139
- <di:waypoint x="2126" y="220" />
1140
- <di:waypoint x="2568" y="220" />
1141
- <di:waypoint x="2568" y="920" />
1142
- <di:waypoint x="1931" y="920" />
1176
+ <di:waypoint x="1388" y="255" />
1177
+ <di:waypoint x="1388" y="82" />
1178
+ <di:waypoint x="1776" y="82" />
1179
+ <di:waypoint x="1776" y="165" />
1180
+ <di:waypoint x="2218" y="165" />
1181
+ <di:waypoint x="2218" y="920" />
1182
+ <di:waypoint x="1581" y="920" />
1143
1183
  <bpmndi:BPMNLabel>
1144
- <dc:Bounds x="2306" y="187" width="82" height="28" />
1184
+ <dc:Bounds x="2131" y="849" width="82" height="28" />
1145
1185
  </bpmndi:BPMNLabel>
1146
1186
  </bpmndi:BPMNEdge>
1147
1187
  <bpmndi:BPMNEdge id="BPMNEdge_f_ci_waitDep" bpmnElement="f_ci_waitDep">
1148
- <di:waypoint x="1938" y="1240" />
1149
- <di:waypoint x="2038" y="1240" />
1188
+ <di:waypoint x="1588" y="1240" />
1189
+ <di:waypoint x="1688" y="1240" />
1150
1190
  <bpmndi:BPMNLabel>
1151
- <dc:Bounds x="1931" y="1167" width="75" height="28" />
1191
+ <dc:Bounds x="1621" y="1167" width="75" height="28" />
1152
1192
  </bpmndi:BPMNLabel>
1153
1193
  </bpmndi:BPMNEdge>
1154
1194
  <bpmndi:BPMNEdge id="BPMNEdge_f_mw_stall" bpmnElement="f_mw_stall">
1155
- <di:waypoint x="888" y="440" />
1156
- <di:waypoint x="988" y="440" />
1195
+ <di:waypoint x="870" y="618" />
1196
+ <di:waypoint x="870" y="638" />
1197
+ <di:waypoint x="888" y="638" />
1198
+ <di:waypoint x="888" y="1598" />
1199
+ <di:waypoint x="1338" y="1598" />
1157
1200
  </bpmndi:BPMNEdge>
1158
1201
  <bpmndi:BPMNEdge id="BPMNEdge_f_msp_gate" bpmnElement="f_msp_gate">
1159
- <di:waypoint x="1088" y="440" />
1160
- <di:waypoint x="1188" y="440" />
1202
+ <di:waypoint x="1438" y="1560" />
1203
+ <di:waypoint x="1538" y="1560" />
1204
+ </bpmndi:BPMNEdge>
1205
+ <bpmndi:BPMNEdge id="BPMNEdge_f_mrp_probe" bpmnElement="f_mrp_probe">
1206
+ <di:waypoint x="1206" y="1560" />
1207
+ <di:waypoint x="1338" y="1560" />
1161
1208
  </bpmndi:BPMNEdge>
1162
1209
  <bpmndi:BPMNEdge id="BPMNEdge_f_ci_spdone" bpmnElement="f_ci_spdone">
1163
- <di:waypoint x="1788" y="1240" />
1164
- <di:waypoint x="1888" y="1240" />
1210
+ <di:waypoint x="1438" y="1240" />
1211
+ <di:waypoint x="1538" y="1240" />
1165
1212
  </bpmndi:BPMNEdge>
1166
1213
  <bpmndi:BPMNEdge id="BPMNEdge_f_reb_spdone" bpmnElement="f_reb_spdone">
1167
- <di:waypoint x="1788" y="1400" />
1168
- <di:waypoint x="1888" y="1400" />
1214
+ <di:waypoint x="1438" y="1400" />
1215
+ <di:waypoint x="1538" y="1400" />
1169
1216
  </bpmndi:BPMNEdge>
1170
1217
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_landedStalled" bpmnElement="f_m_landedStalled">
1171
- <di:waypoint x="2106" y="120" />
1172
- <di:waypoint x="2238" y="120" />
1218
+ <di:waypoint x="1756" y="120" />
1219
+ <di:waypoint x="1888" y="120" />
1173
1220
  </bpmndi:BPMNEdge>
1174
1221
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_escLanded" bpmnElement="f_m_escLanded">
1175
- <di:waypoint x="2338" y="120" />
1176
- <di:waypoint x="2438" y="120" />
1222
+ <di:waypoint x="1988" y="120" />
1223
+ <di:waypoint x="2088" y="120" />
1177
1224
  </bpmndi:BPMNEdge>
1178
1225
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_escWait" bpmnElement="f_m_escWait">
1179
- <di:waypoint x="2488" y="120" />
1180
- <di:waypoint x="2588" y="120" />
1226
+ <di:waypoint x="2138" y="120" />
1227
+ <di:waypoint x="2238" y="120" />
1181
1228
  </bpmndi:BPMNEdge>
1182
1229
  <bpmndi:BPMNEdge id="BPMNEdge_f_ci_recheck" bpmnElement="f_ci_recheck">
1183
- <di:waypoint x="1913" y="1265" />
1184
- <di:waypoint x="1913" y="1300" />
1230
+ <di:waypoint x="1563" y="1265" />
1231
+ <di:waypoint x="1563" y="1300" />
1185
1232
  <di:waypoint x="577" y="1300" />
1186
1233
  <di:waypoint x="577" y="305" />
1187
1234
  <bpmndi:BPMNLabel>
1188
1235
  <dc:Bounds x="582" y="769" width="85" height="28" />
1189
1236
  </bpmndi:BPMNLabel>
1190
1237
  </bpmndi:BPMNEdge>
1238
+ <bpmndi:BPMNEdge id="BPMNEdge_f_msp_rederive" bpmnElement="f_msp_rederive">
1239
+ <di:waypoint x="1563" y="1585" />
1240
+ <di:waypoint x="1563" y="1620" />
1241
+ <di:waypoint x="1013" y="1620" />
1242
+ <di:waypoint x="1013" y="305" />
1243
+ <bpmndi:BPMNLabel>
1244
+ <dc:Bounds x="1446" y="1587" width="85" height="28" />
1245
+ </bpmndi:BPMNLabel>
1246
+ </bpmndi:BPMNEdge>
1191
1247
  <bpmndi:BPMNEdge id="BPMNEdge_f_dep_rewait" bpmnElement="f_dep_rewait">
1192
- <di:waypoint x="2088" y="1280" />
1193
- <di:waypoint x="2088" y="1480" />
1194
- <di:waypoint x="234" y="1480" />
1248
+ <di:waypoint x="1738" y="1280" />
1249
+ <di:waypoint x="1738" y="1640" />
1250
+ <di:waypoint x="234" y="1640" />
1195
1251
  <di:waypoint x="234" y="298" />
1196
1252
  </bpmndi:BPMNEdge>
1197
1253
  <bpmndi:BPMNEdge id="BPMNEdge_f_mr_go" bpmnElement="f_mr_go">
1198
- <di:waypoint x="1913" y="785" />
1199
- <di:waypoint x="1913" y="805" />
1254
+ <di:waypoint x="1563" y="785" />
1255
+ <di:waypoint x="1563" y="805" />
1200
1256
  <di:waypoint x="402" y="805" />
1201
1257
  <di:waypoint x="402" y="320" />
1202
1258
  <bpmndi:BPMNLabel>
1203
- <dc:Bounds x="1114" y="772" width="49" height="28" />
1259
+ <dc:Bounds x="946" y="772" width="49" height="28" />
1204
1260
  </bpmndi:BPMNLabel>
1205
1261
  </bpmndi:BPMNEdge>
1206
1262
  <bpmndi:BPMNEdge id="BPMNEdge_f_m_evicted" bpmnElement="f_m_evicted">
1207
- <di:waypoint x="2088" y="618" />
1208
- <di:waypoint x="2088" y="638" />
1263
+ <di:waypoint x="1738" y="618" />
1264
+ <di:waypoint x="1738" y="638" />
1209
1265
  <di:waypoint x="402" y="638" />
1210
1266
  <di:waypoint x="402" y="320" />
1211
1267
  </bpmndi:BPMNEdge>
@@ -8,7 +8,10 @@
8
8
  // • ready → attempt-merge
9
9
  // • conflict → rebase arm
10
10
  // • blocked → CI-fix arm
11
- // • draft / waiting (still computing) → not-landable escalation (gw-mergeable default)
11
+ // • waiting (GitHub still computing) → bounded re-poll (`wait-mergeable-repoll`), NOT a terminal
12
+ // escalation (#774); it only escalates once the shared `mergeStallMax` budget is exhausted
13
+ // • draft → not-landable escalation
14
+ // • unclassified/default → auto-rebase (`gw-rebase`, the `gw-mergeable` default arm)
12
15
  // The timer only guarantees the remediation machinery is ENTERED when the poller is dead; every
13
16
  // downstream arm is the same one the live poller feeds. A bounded `mergeStallRounds` counter
14
17
  // (incremented by this task's output mapping, capped by `mergeStallMax`) stops the probe from
@@ -23,9 +26,10 @@ type In = WorkerInputs["pr.merge-stall-probe"];
23
26
 
24
27
  interface Out extends Record<string, unknown> {
25
28
  // Mirrors the poller's `merge-ready {mergeState}` payload so the existing `gw-mergeable` FEEL
26
- // routes it. `waiting` (GitHub still computing / no verdict) is surfaced verbatim; gw-mergeable
27
- // has no `waiting` arm, so it falls to the not-landable default and escalates — the correct
28
- // backstop when the poller is dead and 30 minutes on GitHub still cannot settle the PR.
29
+ // routes it. `waiting` (GitHub still computing / no verdict) is surfaced verbatim; `gw-mergeable`
30
+ // routes it to a bounded re-poll (`wait-mergeable-repoll`, #774) re-probing until the verdict
31
+ // settles or the shared `mergeStallMax` budget is exhausted, at which point it escalates to a
32
+ // human. This backstops a dead poller without wedging a PR GitHub is merely slow to settle.
29
33
  mergeState: string;
30
34
  failingChecks: number;
31
35
  failingChecksList: string;
@@ -39,8 +43,8 @@ const handler: AppJobHandler<In, Out> = async (job, app) => {
39
43
  // protocol so the protocol-aware backstop (#392) gates a red DECLARED-required check even when
40
44
  // GitHub reports UNSTABLE. Any transport hiccup is treated as "still waiting" — never a spurious
41
45
  // ready/conflict verdict — so a bad read is surfaced as `waiting`, which `gw-mergeable` routes to
42
- // its not-landable default (human escalation), erring toward a human rather than misrouting the
43
- // token to a wrong remediation arm.
46
+ // a bounded re-poll (#774) rather than misrouting the token to a wrong remediation arm; a
47
+ // genuinely stuck verdict still escalates once the `mergeStallMax` budget is exhausted.
44
48
  const st = await fetchPrState(repo, prNumber, token).catch(() => null);
45
49
  if (st === null) {
46
50
  return { mergeState: "waiting", failingChecks: 0, failingChecksList: "" };