@g1cloud/bpmn-modeler-next 5.0.0-beta.10 → 5.0.0-beta.100

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.
@@ -10,8 +10,10 @@ import { default as SpaceTool } from 'diagram-js/lib/features/space-tool/SpaceTo
10
10
  import { Shape } from 'bpmn-js/lib/model/Types';
11
11
  import { SymbolicOp } from '../symbolicOp';
12
12
  import { ResolveIssue } from './issues';
13
+ import { IrSequenceFlow } from '../../core/ir';
13
14
  import { BwlSide } from '../../core/hints';
14
15
  import { GeometryFinding, GeometryScene } from '../geometryAudit';
16
+ import { LocaleWrite } from './localeTexts';
15
17
  /** resolver 가 대면하는 bpmn-js 서비스 표면 — 하강은 이 묶음만 사용한다. */
16
18
  export interface ResolverServices {
17
19
  modeling: Modeling;
@@ -29,7 +31,7 @@ export declare function resolverServicesOf(modeler: BpmnModelerLike): ResolverSe
29
31
  * ── B-40. 주석 자리 산출 — **add·update·기존 주석 보정 공유** ──
30
32
  *
31
33
  * 선언 방위 → 실제 좌표(풀 안 클램프 B-20 ⓑ · 앵커 회피 · 형제·간선 B-21 · 외부 라벨 B-24 ⓑ 회피 ·
32
- * 대안 방위 좌 우선 B-26 ⓐ). 힌트가 없으면 휴리스틱 자리를 같은 규칙으로 클램프·비낀다.
34
+ * 대안 방위 좌 우선 B-26 ⓐ). 힌트가 없는 주석은 add 가 `top` 으로 정규화해 넘긴다(B-2 — 종전 휴리스틱 분기는 걷어냈다).
33
35
  *
34
36
  * 종전에는 이 전부가 `annotation.add` 루프 안에 인라인이었고 `annotation.update` 는 **원시 계산**만 했다.
35
37
  * 표본 34 실측: 에이전트가 `annotation-over-label` 을 playbook §6 대로 `annotation.update` 로 고치려 하자
@@ -39,6 +41,14 @@ export declare function resolverServicesOf(modeler: BpmnModelerLike): ResolverSe
39
41
  * B-33 → B-34 ⓐ 가 그룹 경계 보정에서 닫은 것과 같은 클래스다.
40
42
  *
41
43
  * `selfId` = 이미 존재하는 주석(update)의 자기 도형·자기 연관을 장애물에서 뺀다 — 안 빼면 늘 "막힘"이다.
44
+ *
45
+ * **B-144** — 앵커가 레인 안이면 클램프 상자와 대안 방위의 `inside` 를 **앵커 레인 대역**으로 좁힌다(풀 클램프와
46
+ * 같은 규칙 — 레인 경계에서 클램프하고 앵커와 겹치면 오른쪽으로 비낀다). 🔴 **레인 안에 막히지 않은 자리가 없으면
47
+ * 종전대로 풀 안 빈 자리(이웃 레인일 수 있다)로 간다** — 레인 소속을 막힌 자리(겹침·관통)와 바꾸지 않는다
48
+ * (반사실: 레인 안 막힌 자리로 두는 안은 findings 가 는 케이스가 두 배였다 · 66 vs 33 / 방위 합성 6,208).
49
+ * 그것도 없으면 레인 안 선언 자리(막힘 — 판정기가 보고한다). ⚠ 잔존 대가 = 그 폴백의 이웃 레인 착지(방위 합성
50
+ * 0.6% — 사람 기저 0.4~1.0% 수준) · 레인 클램프가 오른쪽 비끼기를 더 자주 발동시켜 **가로로 풀 밖** 착지가
51
+ * 12 → 16(그 분기가 풀 우변을 넘는 것은 이 축 이전부터다 — 원장 B-144 곁).
42
52
  */
43
53
  export declare function annotationSpot(elementRegistry: ElementRegistry, anchor: {
44
54
  x: number;
@@ -49,19 +59,35 @@ export declare function annotationSpot(elementRegistry: ElementRegistry, anchor:
49
59
  width: number;
50
60
  height: number;
51
61
  }, box: Shape, opts: {
52
- placement?: {
62
+ placement: {
53
63
  side: BwlSide;
54
64
  offset?: number | null;
55
- } | null;
56
- from?: {
57
- x: number;
58
- y: number;
59
65
  };
60
66
  selfId?: string;
61
67
  }): {
62
68
  x: number;
63
69
  y: number;
64
70
  };
71
+ /**
72
+ * **B-168** — source 꼴 직접 끼우기 감지(하강 **전** 문서 기준). 키 = F id · 값 = 7단계까지 미룰 신규 유입(`A → X`) op.
73
+ * 조건 = X 로의 target 재배선이 없다 · X 가 F 의 옛 출발 A 에서 신규 유입을 받는다 · X 마다 첫 F 하나 · 그 신규 유입을
74
+ * 다른 op 가 참조하지 않는다(7단계 앞 단계 — 주석 연관 · 그룹 멤버 — 에서 아직 없다). 뒤 보정(`index.ts`)도 같은 판정을 쓴다.
75
+ */
76
+ export declare function sourceFormInsertsOf(ops: readonly SymbolicOp[], oldSourceOf: (flowId: string) => string | undefined): Map<string, Extract<SymbolicOp, {
77
+ kind: 'sequenceFlow.add';
78
+ }>>;
79
+ /**
80
+ * **B-213** — 2단계 플로우 반복(탐욕 배치)에서 **합류를 놓지 못하게 미룰 출구** id. 다이아몬드 합류 M 으로 드는 출구
81
+ * s → M 중 **출발 s 가 M 의 다른 비루프 선행 q 에 닿고 q 가 s 보다 2 이상 깊은** 것이다 — 그 출구가 먼저 M 을 놓으면
82
+ * M 이 s 바로 다음 열에 서고 긴 갈래 끝 q 가 M 으로 거꾸로 든다(원격 반품 v1). 깊이 = 이 시퀀스들의 비루프 최장 경로
83
+ * (되돌아가는 간선 = DFS 스택 위로 가는 간선 · 뿌리 = 유입 없는 출발 → 배치 노드 → 나머지 출발 순). 선언 순서와 무관하다.
84
+ *
85
+ * 🔴 **좁힌 조건 둘 다 실측이 정했다**(원장 `B-213(N20)`) — ⓐ 깊이 차 1 은 미루지 않는다: 낙하(게이트웨이 열) ·
86
+ * `freeSpot` 비켜 놓기가 이미 받치는 자리인데 미루면 배치 경로가 바뀌어 fixture 3건이 나빠졌다(교차 66 → 73 등).
87
+ * ⓑ **s 가 q 에 닿을 때만** 미룬다: 갱신 배치에서 기존 노드는 깊이 0 으로 잡히는데 실제로는 오른쪽 멀리 있을 수 있어,
88
+ * 닿지 않는 기존 선행의 출구를 미루면 멀쩡하던 합류가 거꾸로 선다(합성 갱신 사례).
89
+ */
90
+ export declare function diamondShortcutExitsOf(flows: readonly Pick<IrSequenceFlow, 'id' | 'source' | 'target'>[], nodeIds: readonly string[], isBatchNode: (id: string) => boolean): Set<string>;
65
91
  /**
66
92
  * 하강 중에야 드러나는 거부를 **구조화된 issue 로** 올린다 — `applyBpmnOps` 가 자유 문장 `lower-failed` 대신
67
93
  * 이 issue 를 그대로 낸다(LLM 교정 루프가 읽을 수 있게). 롤백은 다른 throw 와 같다(undo 에피소드가 되감는다).
@@ -70,11 +96,43 @@ export declare class LowerIssueError extends Error {
70
96
  readonly issue: ResolveIssue;
71
97
  constructor(issue: ResolveIssue);
72
98
  }
99
+ /** B-119 ⓒ′ — 위 집합을 읽는다(주입한 `lower` 가 쓰지 않았으면 빈 집합). */
100
+ export declare function labelLandingFlowIdsOf(services: object): ReadonlySet<string>;
101
+ /** B-209 — 위 맵을 이 배치의 서비스 객체에 건다(`applyBpmnOps` 가 하강 직전에). */
102
+ export declare function provideLowerLocaleTexts(services: object, writes: ReadonlyMap<string, LocaleWrite>): void;
103
+ /**
104
+ * B-188 ⓑ — 이 배치의 7단계 행 이동(`node.update{band|lane}`)이 **떠난 자리**(이동 직전 bbox · id = 옮긴 노드). 그 자리를
105
+ * 감싸던 이어지지 않은 선의 ⊓ 를 `foldVacatedDetours` 가 접는다(관통 보정 1차 뒤). 넘기는 길은 B-119 ⓒ′ 와 같다.
106
+ */
107
+ export interface VacatedBox {
108
+ id: string;
109
+ x: number;
110
+ y: number;
111
+ width: number;
112
+ height: number;
113
+ }
114
+ /** B-188 ⓑ — 위 목록을 읽는다(주입한 `lower` 가 쓰지 않았으면 빈 목록). */
115
+ export declare function vacatedBoxesOf(services: object): readonly VacatedBox[];
116
+ /** B-189 — 위 목록을 읽는다(주입한 `lower` 가 쓰지 않았으면 빈 집합). */
117
+ export declare function ownEndpointRelaidIdsOf(services: object): ReadonlySet<string>;
118
+ /** B-196 — 위 목록을 읽는다(주입한 `lower` 가 쓰지 않았으면 빈 집합). */
119
+ export declare function leftPassedMessageIdsOf(services: object): ReadonlySet<string>;
73
120
  /** 검증 통과가 전제 — 참조 해소 실패는 여기서 프로그래밍 오류로 throw 되고 applyBpmnOps 가 롤백한다. */
74
121
  export declare function lowerOps(ops: readonly SymbolicOp[], services: ResolverServices): void;
75
122
  /** 주석 도형이 소유자로 등장할 수 있는 finding 의 소유 도형 id. */
76
123
  export declare function annotationOwnersOf(finding: GeometryFinding): readonly string[];
77
- export declare function repairIntroducedAnnotationOverlaps(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeKeys: ReadonlySet<string>, beforeShapeIds: ReadonlySet<string>): void;
124
+ /**
125
+ * **B-219** — 이 배치가 **앵커 대비** 옮긴 주석(중심 2px 넘게 움직였고 앵커와 같은 델타로 함께 옮겨진 승객이 아닌 것).
126
+ * placement 이동 · 주석 보정(B-56) · 문구 변경의 상자 크기 변화가 여기 든다 — 그 주석이 지금 가진 판정은 이 배치가 만든
127
+ * 관계라 선재 키여도 응답에 싣는다. 앵커만 움직이고 주석이 제자리면 들지 않는다(그 주석의 관계는 그대로다).
128
+ * `anchorOf` = 연관선 반대 끝(없으면 앵커 비교 없이 이동만 본다). 앵커가 연결이면 가운데 waypoint 로 잰다.
129
+ */
130
+ export declare function repositionedAnnotationIdsOf(before: GeometryScene, after: GeometryScene, anchorOf: (annotationId: string) => string | undefined): Set<string>;
131
+ export declare function repairIntroducedAnnotationOverlaps(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeKeys: ReadonlySet<string>, beforeShapeIds: ReadonlySet<string>,
132
+ /** B-210 — 1차 관통 보정이 미룬 간선(B-142). 그 간선이 지나는 **새** 주석도 이 패스가 맡는다. */
133
+ deferredEdgeIds?: ReadonlySet<string>,
134
+ /** B-219 — 이 배치의 `annotation.update` 가 placement 로 둔 주석. 이것만 옮겨 본 자리의 선재 키 판정을 종전대로 거른다. */
135
+ placedAnnotationIds?: ReadonlySet<string>): void;
78
136
  /**
79
137
  * **B-91 예방** — 이 배치가 만든 **풀 × 풀 겹침**을, 오른쪽 이웃을 밀어 해소한다.
80
138
  *
@@ -97,13 +155,22 @@ export declare function repairIntroducedAnnotationOverlaps(services: Pick<Resolv
97
155
  */
98
156
  export declare function repairIntroducedPoolOverlaps(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeKeys: ReadonlySet<string>, sceneBefore: GeometryScene): void;
99
157
  /**
100
- * 🔴 **B-120 — 문서 전체가 한 우변에 맞춰져 있던 풀들을 배치 뒤에도 한 우변으로 되돌린다.**
158
+ * 🔴 **B-120 — 배치 전 한 우변에 맞춰져 있던 풀 무리를 배치 뒤에도 한 우변으로 되돌린다.**
101
159
  *
102
160
  * 증언(표본 86) = *"레인 끝부분이 걸린건 위쪽의 세개의 레인이 정렬되있어서야"*. 배치는 두 풀만 늘렸고 **늘리는 경로가 둘인데
103
161
  * 기준이 다르다**(`shiftGroups` = 내용 우단 +150 · `createSpace` = 밀기 폭) — 한 우변이 셋으로 갈렸다.
104
- * 🔴 **판별자는 「양」이 아니라 「대상」이다** — 우변이 같은 풀이 몇 개인가가 아니라 **문서 전체가 한 우변이었나**. N20 전이 =
105
- * 전체 정렬 무리는 사람이 **3/3 반응** · 부분 무리는 **0/5**. 부분 일치는 도구 문서에서도 우연히 생긴다(저장본 부분 무리 19/69 ↔
106
- * 전체 정렬 0/69). ⇒ 발동은 **배치 전 모든 풀(≥2)의 우변이 같을 때만**이다.
162
+ *
163
+ * 무리 = 배치 전 우변이 허용 오차 안에서 같은 풀들(크기 ≥2). 범위는 두 단계로 넓어졌다:
164
+ * - **ⓐ 문서 전체가 한 우변**(2026-09-28) — N20 전이 = 전체 정렬 무리는 사람이 **3/3 반응** · 부분 무리는 **0/5**.
165
+ * - **ⓓ 부분 무리 — 블랙박스 멤버가 없을 때만**(2026-10-06 · 표본 99) — 증언 = *"끝부분이 어긋난건 보였는데 … 맞추는게
166
+ * 맞아보이긴해"*. N20 = 사람 문서(풀 ≥2) 98 중 **부분 무리 문서 25** · ⓐ 뒤 현행이 깨는 무리는 **부분 무리뿐**(계보 7/23) ·
167
+ * 합성 재고(블랙박스 없는 부분 무리 1,899) = 깨짐 376 → 복원 **312** · 판정 키 · 교차 · 끝점 공유 교차 · 흐름 간선 변화 **0**.
168
+ * 🔴 **블랙박스 멤버가 있는 부분 무리는 뺀다** — 계보 반사실에서 블랙박스 풀이 **570 → 2155** 로 늘고 그 우변에 붙던 메시지가
169
+ * 다시 그려져 끝점 공유 교차가 **1 → 3** 이 됐다(그 회차의 사람은 맞추지 않았다). ⚠ 아래 가드 ②는 그 메시지를 못 막았다 —
170
+ * 이 패스 시점엔 우변에 안 붙어 있었고 뒤 라우팅이 붙인다(추정). ⚠ 판별은 **이 패스 시점**의 모델이다(배치가 빈 풀에 노드를
171
+ * 넣었으면 더는 블랙박스가 아니다).
172
+ * ⚠ 부분 일치는 도구 문서에서도 우연히 생긴다(저장본 19/69) — 그런 무리는 대개 처음부터 같은 폭이라 되돌려도 원래 모양이다
173
+ * (계보 102 재하강에서 기하가 바뀐 문서 = 표본 99 하나).
107
174
  *
108
175
  * **목표 우변 = max(base 우변, 각 풀의 산출 내용 우단 + 150)** — 사람 값이 있는 회차(표본 85 = 2338)를 **정확히** 낸 규칙은
109
176
  * 이것 하나였다(무리 최댓값 · 풀별 base 여백 보존은 둘 다 2473). base 우변 아래로는 **안 줄인다**.
@@ -124,6 +191,31 @@ export declare function repairIntroducedPoolOverlaps(services: Pick<ResolverServ
124
191
  * 전제 위에 남는다」 — B-51·B-58·B-71·B-88). 라우팅·라벨 보정보다도 앞이라 그쪽은 새 경계를 본다.
125
192
  */
126
193
  export declare function restorePoolRightAlignment(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, sceneBefore: GeometryScene): void;
194
+ /**
195
+ * 🔴 **B-228 — 이 배치가 만든 내용 풀이 시드 폭에 머물러 오른쪽이 비면 「내용 우단 + 150」 으로 줄인다(바닥 1200 · 배치 맨 끝).**
196
+ *
197
+ * 시드 폭 `max(1200, 노드 수 × 160 + 300)`(1단계 풀 생성)은 노드마다 한 열을 잡는다 — band 행이 열을 나눠 쓰면 과대인데, 배치의
198
+ * 폭 경로는 늘리기만 한다(`shiftGroups` 내용 + 150 · `needRight` 짝 열 + 100 · `refitPoolsToPartnerColumns`) · 위 B-120 은 배치 전
199
+ * 풀만 본다. 원격 Codex 새 문서 넷 = 주 풀 여백 869 ~ 1,504(최종 폭 = 시드 폭). N20 = 사람 실무 26 의 주 풀 여백 중앙 100 · 우변
200
+ * 정렬 없이 500 이상 **0/26** ↔ 우리 새 문서 33 중 **22** · 사람은 그 여백을 줄였다(원격 8 = 두 내용 풀 우변을 맞추며 · 1/1).
201
+ *
202
+ * ⚠ **시드는 건드리지 않는다**(B-3 ⓐⓑ — 시드 폭을 전 배치에 바꿨다가 `--check` 6지표 악화). 배치 끝에서 **줄이기만** 한다.
203
+ * 대상 = 이 배치가 만든 풀(배치 전 장면에 없음) 중 내용 있는 풀 — 블랙박스 폭은 짝 열이 정한다(B-25 ⓑ1). 배치 전 풀은 확정 7 ③
204
+ * 그대로 안 줄인다. 내용 우단 = 자손 도형(레인 제외) · 그 외부 라벨 · 풀 안 간선의 웨이포인트와 라벨 + 🔴 **풀 영역에 겹치는 남의 도형 ·
205
+ * 라벨**(메시지 라벨 등 — 새 경계선이 아무것도 가로지르지 않게 · 아래 「맨 끝」 의 대가를 막는다). 레인은 `resizePoolWidthOf`
206
+ * 가 함께 줄인다(B-115). 연결은 다시 그리지 않고(`layout: false`), 풀에 도킹한 연결 끝점이 새 우변에 걸리면 그 풀은 건너뛴다.
207
+ * ⚠ **같은 배치 풀끼리 우변을 맞추지는 않는다** — 맞추려고 넓힌 풀이 뒤 라우팅의 입력을 바꿨다(시제품 b · 코퍼스 1 배치의 메시지
208
+ * 경로가 갈렸다 — 이번엔 이득이었지만 예측할 수 없다). 시제품 a = 코퍼스 326 배치 중 163 이 풀 · 레인 폭만 바뀌고 그 밖
209
+ * 기하 · 판정 · 교차 · DI 밖 XML 변화 0 · 호스트 `--check` 1047/1047.
210
+ *
211
+ * 🔴 **바닥 1200 아래로는 안 줄인다** — 시제품 a(바닥 없음)는 바닥값에 서 있던 작은 풀까지 줄여 ① 우연히 한 우변이던 풀 무리를
212
+ * 갈라 다음 배치의 B-120 이 그 무리를 못 보게 했고(재배선 회귀선 1300 ≠ 846) ② 골든 DI 를 바꿨다. K3 의 증거는 「노드 수 × 160」
213
+ * 과대분이지 바닥값이 아니다.
214
+ * 🔴 **배치 맨 끝이다**(B-99 `followMovedEdgeLabels` 뒤) — B-120 자리(라우팅 · 주석 보정 앞)에 두면 뒤 주석 보정이 주석을 새 우변 밖으로
215
+ * 옮겼다(회귀선 둘 · `shape-outside-container`). 끝에서 재면 내용이 최종이다. 줄이는 띠는 내용 우단 + 150 밖이고 연결을 다시 그리지
216
+ * 않으므로 하류가 없다(B-120 처럼 앞에 둘 이유 = 「뒤 패스가 새 경계를 본다」 가 넓히지 않는 이 패스엔 없다).
217
+ */
218
+ export declare function trimBatchContentPools(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, sceneBefore: GeometryScene): void;
127
219
  /**
128
220
  * **B-83 ⓐ** — 기존 그룹 상자가 **크기 변화**를 따라가지 못하는 것을 고친다.
129
221
  *
@@ -1,5 +1,37 @@
1
+ import { Connection } from 'bpmn-js/lib/model/Types';
1
2
  import { GeometryEdge, GeometryLabel, GeometryPoint, GeometryScene, GeometryShape } from '../geometryAudit';
2
- import { ResolverServices } from './lower';
3
+ import { ResolverServices, VacatedBox } from './lower';
4
+ /**
5
+ * ── B-185 ⓐ. 막힌 곧은 메시지의 「도킹 편이 곧은 2점」 후보(순수) ──
6
+ *
7
+ * 송신 노드 바로 아래 위성 저장소처럼 **가운데 곧은 길만** 막힌 메시지를 우회를 까는 두 생성기(관통 보정 `planEdgeRepair` ·
8
+ * 풀 횡단 재경로 `planCrossPoolRoute`)가 각자 ㄷ 으로 감쌌다 — 🔁 「후보 생성기 공백」(B-64 꼴): 둘 다 양 끝 도킹을 고정하고
9
+ * 우회만 내서 곧은 대안을 아무도 안 냈다(N22 · 도킹 편이 `dockShiftCandidates` 는 겹침 보정에만 있다).
10
+ * 🔴 **N20** — 막힌 흐름에 대한 사람의 수단에 ㄷ 이 없다(레거시 + Downloads 막힌 시퀀스 66 · 메시지 4 → 굽힘 4 이상 **0** ·
11
+ * 사람의 굽힘 2 는 계단이 아니라 막는 것 너머를 넘는 같은 쪽 면 U 다 — ⓓ1) · 우리 산출 ㄷ 11 · 사람은 저장 산출의 ㄷ **2/2** 를 막는
12
+ * 것을 옮겨 곧게 폈다.
13
+ * 🔴 **메시지 한정** — 곧은 메시지의 도킹 편이는 사람 관례다(491 중 84 = 17% · 대개 10~24) · 시퀀스는 **2/3,236**.
14
+ *
15
+ * 편이 범위 = 두 끝점 면의 교집합(모서리 10 안쪽 · 끝점이 판정 대상이 아닌 풀이면 그쪽은 제약 없음) · 가운데에서 가까운 편이
16
+ * 순(5px) · 관통 0 · 끝점 아닌 도형과 틈 ≥ `clear`. 채택은 호출부가 `pickDockShiftStraight` 로 대조 경로와 비교해 정한다.
17
+ */
18
+ export declare function dockShiftStraightCandidates(edge: GeometryEdge, targets: readonly GeometryShape[], clear?: number): GeometryPoint[][];
19
+ /**
20
+ * ── B-185 ⓓ1. 같은 행 정방향 시퀀스가 막히면 같은 쪽 면 U(순수 후보) ──
21
+ *
22
+ * 같은 행에서 노드를 건너뛰는 정방향 시퀀스가 사이 노드에 막히면 관통 보정이 그 노드를 끼고 도는 ㄷ(굽힘 4)을 깔았다.
23
+ * 🔴 **N20** — 사람 막힌 시퀀스 66 중 **U 59**(윗면 → 윗면 39 · 아랫면 → 아랫면 20 · 양 끝 가운데 52 · 정방향 49) · ㄷ **0** ·
24
+ * 계단(Z) **0** · 우리 역방향 건너뛰기는 이미 U 를 냈다(역방향 후보 생성기) — 🔁 「후보 생성기 공백」(B-64 꼴): U 를 역방향에만 냈다.
25
+ * 사람 U 의 채널은 자기 풀 밖으로 나간 것이 0/59 이고 풀 · 레인 경계와 30 미만인 것이 7 ⇒ 부모 풀 안 · `BOUNDARY_CLEARANCE` 를
26
+ * 지킨다(30 미만을 일괄로 열면 U 가 늘지만 교차 이득이 줄었다 — 시제품 v2).
27
+ *
28
+ * 후보 순서 = 가운데 도킹 → 한쪽 ±25 · 채널이 가까운 순(끝점 바깥 `DETOUR_MARGIN` → `FORWARD_SKIP_CHANNEL_MAX`) · 윗면 · 아랫면.
29
+ * 관통 0 · 자기 끝점 되짚기 0 · 부모 풀 안 · 끝점 아닌 도형과 틈 ≥ `DETOUR_MARGIN` · 채널이 경계에 붙지 않는다.
30
+ *
31
+ * `hugAllowance` 를 주면 **경계 예외 후보만** 낸다(B-185 ⓔ) — 채널이 경계에 붙되(`BOUNDARY_CLEARANCE` 미만) 그 거리가 `hugAllowance`
32
+ * 이상인 것. 나머지 조건은 같다. 쓰는 자리와 이유는 `pickForwardSkipU`.
33
+ */
34
+ export declare function forwardSkipUCandidates(edge: GeometryEdge, targets: readonly GeometryShape[], containers: readonly GeometryShape[], bounds: Bounds | undefined, hugAllowance?: number): GeometryPoint[][];
3
35
  /**
4
36
  * 축 정렬 구간이 장애물을 **완전히 가로지를 때** 그것을 우회하는 4점을 만든다(순수).
5
37
  *
@@ -35,6 +67,10 @@ export declare function planMergedSegmentDetour(a: GeometryPoint, b: GeometryPoi
35
67
  * 폭 안). 해법은 우회가 아니라 **중간 구간을 장애물 옆으로 옮기는 것** — 점 수는 그대로 4 다.
36
68
  * 두 후보(장애물 왼쪽/오른쪽 또는 위/아래)를 돌려주고 채택은 호출자가 판정기로 한다.
37
69
  *
70
+ * 🔴 **B-214 — 꺾임점이 장애물 밖이어도 이 후보를 구간 우회보다 먼저 본다**(`planEdgeRepair`). 종전엔 구간 우회가
71
+ * `null` 일 때만 도는 폴백이라, 라우터의 Z 가 가운데 x 로 도형 하나를 지나면 구간 우회가 줄 중간 덧댐(S자 8점)을
72
+ * 붙였다 — 사람 문서의 줄 중간 덧댐은 **0/4,244 흐름**이고 사람은 도구 덧댐 11 중 7 을 폈다.
73
+ *
38
74
  * `null` = 4점 직각 경로가 아니다.
39
75
  */
40
76
  export declare function planMiddleSegmentShifts(waypoints: readonly GeometryPoint[], rect: GeometryShape, margin?: number): [GeometryPoint[], GeometryPoint[]] | null;
@@ -54,8 +90,23 @@ export declare function forwardThreePointCandidates(edge: GeometryEdge, shapes:
54
90
  * 목표 열은 목표 중심에 도킹 편이 0/±25/±40 — 그 열에 다른 메시지가 이미 중심 도킹해 있으면(같은 방향·같은
55
91
  * 종류라 finding 은 아니지만 두 화살표가 한 선으로 합쳐 보인다 — 사용자도 -19 비껴 놓았다) 편이 후보가 피한다.
56
92
  * 채택은 호출자 몫: 관통 0 을 먼저, 그다음 다른 간선과의 공선 공유가 없는 후보를 고른다.
93
+ *
94
+ * 🔴 B-141. 목표 도킹 열이 **출발 도형 폭 안**이면(같은 열 메시지) 후보를 내지 않는다 — 되돌아오는 세로 구간이
95
+ * 출발 도형을 관통하고, 도킹 편이(최대 ±40)로는 반폭을 못 벗어난다. 그 관통은 호출자의 관통 셈과 판정이 둘 다
96
+ * **자기 끝점을 빼서** 보이지 않아 그대로 채택됐다(표본 93 갈고리 · 계보 102 재하강 = 8회차 10간선 · 전부 이 후보 ·
97
+ * 사람 문서 0/1040 · 사람은 6/7 을 고쳤다). 위 전례는 목표 열 ≠ 출발 열이었다 — 같은 열이면 ㄷ 우회(B-9 ②)로 넘긴다.
57
98
  */
58
99
  export declare function farSideChannelCandidates(edge: GeometryEdge, shapes: readonly GeometryShape[]): GeometryPoint[][];
100
+ /** B-214. 다른 흐름의 화살표 끝에서 이 거리 안을 닿거나 건너면 「화살표 끝 곁」이다(덧댐 · 이동의 장애물 여백과 같은 축척). */
101
+ export declare const ARROW_TIP_CLEARANCE = 25;
102
+ /**
103
+ * B-214. 이 경로가 **다른 흐름의 화살표 끝 곁**(마지막 구간 위 · 끝점에서 `ARROW_TIP_CLEARANCE` 안)을 닿거나 건너는 흐름 수.
104
+ * 같은 목표로 드는 흐름은 뺀다 — 합류는 끝에서 모이는 것이 정상이다.
105
+ *
106
+ * 판정 kind 가 아니다 — 관통이 같은 후보 사이를 가르는 **순서 기준**으로만 쓴다(정방향 본선에서 장애물 왼쪽 = 본선이
107
+ * 들어오는 쪽이라, 고정 순서 [왼쪽, 오른쪽] 은 들어오는 화살표 끝 20px 에 선다 — 원격 C1 사전 실행 · 합성).
108
+ */
109
+ export declare function arrowTipNearCount(points: readonly GeometryPoint[], edge: GeometryEdge, others: readonly GeometryEdge[]): number;
59
110
  /**
60
111
  * 한 간선의 관통을 없애는 웨이포인트를 찾는다(순수). 못 찾으면 `null`.
61
112
  *
@@ -68,7 +119,24 @@ export declare function planEdgeRepair(edge: GeometryEdge, targets: readonly Geo
68
119
  y: number;
69
120
  width: number;
70
121
  height: number;
71
- }, others?: readonly GeometryEdge[]): GeometryPoint[] | null;
122
+ }, others?: readonly GeometryEdge[],
123
+ /** B-236 — 반대편 출구 채널이 경계에 붙는지 재는 컨테이너(`boundaryContainersOf`). 메시지는 `container` 가 비어 들어온다(부모 = 협업 루트). */
124
+ containers?: readonly GeometryShape[]): GeometryPoint[] | null;
125
+ /**
126
+ * ── B-198. 관통 우회의 줄기를 같은 목표 형제 줄기에 맞춘다(순수) ──
127
+ *
128
+ * 관통 보정이 고른 4점 경로(h-v-h · v-h-v)의 줄기는 막는 것의 변 ± `DETOUR_MARGIN` 이라, 같은 목표의 같은 도킹점으로 드는
129
+ * 형제 선(bpmn-js 기본 중점)과 20 떨어져 평행하고 **합류점이 둘**이 된다(외부 BSP 문서 9 · 검토자 *"다른 선들과 동일한
130
+ * 지점에서 합류해야 보기가 편할 것 같아"*). 어느 후보 생성기도 형제 줄기를 내지 않는다(N22 — 3점 · 병합 우회 · 왼쪽 이동은 관통).
131
+ *
132
+ * 🔴 **사람은 이 꼴을 안 만든다** — 같은 진입선 짝의 합류점 간격 0 < Δ ≤ 60 이 사람 0/188(레거시 161 · 실무 26 문서)이고
133
+ * 사람은 줄기를 공유하거나(Δ 0) 멀리 합류한다(> 100). 그래서 **가까울 때만** 맞춘다 — 먼 합류는 사람에게도 정상이다.
134
+ * 채택 = 관통 0 · 판독 불가 겹침 · 교차 비증가 · 형제 라벨이 새 공유 구간에 앉지 않는다.
135
+ * ⚠ **자기 라벨이 있는 선은 맞추지 않는다** — 경로가 바뀌면 bpmn-js 가 라벨을 옮겨 그 자리를 미리 알 수 없다(코퍼스 0).
136
+ *
137
+ * `null` = 맞출 형제가 없다.
138
+ */
139
+ export declare function snapToSiblingTrunk(edge: GeometryEdge, points: readonly GeometryPoint[], edges: readonly GeometryEdge[], targets: readonly GeometryShape[]): GeometryPoint[] | null;
72
140
  /**
73
141
  * 이 배치가 **새로 만든** 관통을 고친다(하강 직후, undo 에피소드 안에서 호출된다).
74
142
  *
@@ -77,8 +145,38 @@ export declare function planEdgeRepair(edge: GeometryEdge, targets: readonly Geo
77
145
  * "고쳤는데 여전히 깨져 있다"가 되어 보고와 실물이 어긋난다.
78
146
  */
79
147
  export declare function repairIntroducedCrossings(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeKeys: ReadonlySet<string>,
148
+ /** B-223 — 이 배치 전 도형(같은 행 정방향 U 의 자기 라벨 비킴 판정). */
149
+ beforeShapeIds: ReadonlySet<string>,
80
150
  /** 2차 호출 전용 — 이 간선들만 본다(B-90. 1차가 돌려준 «주석 때문에 포기» 집합). */
81
151
  only?: ReadonlySet<string>): Set<string>;
152
+ /**
153
+ * ── B-188 ⓑ. 행 이동이 떠난 자리를 감싸던 ⊓ 를 접는다 ──
154
+ *
155
+ * 7단계 `node.update{band|lane}` 가 노드를 이어지지 않은 선 위로 옮기면 위 관통 보정이 **선을** 비켜 깐다(ⓐ). 그 노드가 다음
156
+ * 배치에서 떠나도 그 선은 끝점이 아니라 다시 깔리지 않아 빈자리를 감싼 우회가 남는다(ⓑ — 외부 검토 네 문서가 지목 · 빈 ⊓
157
+ * 사람 2/3,783 ↔ 외부 6/1,063). 같은 노드가 같은 선 위 다른 행으로 가면 ⊓ 가 둘로 쌓인다(B-195 *"두번 ㄷ"*).
158
+ *
159
+ * 🔴 **⊓ 하나만 접는다 — 선 전체를 다시 깔지 않는다.** 기본 경로로 다시 깔면 도킹 오프셋 같은 기존 결정까지 버려 이웃 선과
160
+ * 겹쳤다(시제품 v2). 대상 = 배치 전부터 있던 시퀀스 · 메시지 중 떠난 노드와 이어지지 않고 끝점을 이 배치가 안 바꾼 선의
161
+ * 4점 ⊓(p0 → p1 → p2 → p3 · p0 · p3 가 같은 축)인데 밑변 p0 → p3 가 **떠난 자리를 지나고 지금 아무 도형도 안 지나는** 것.
162
+ * 채택 = `relayFresh`(B-114 ⓔ)와 같은 규칙(그 선 자기 라벨을 뺀 판정 — 새로 생긴 수 ≤ 해소) + 교차(끝점 공유 포함) 비증가 —
163
+ * 아니면 점과 라벨을 되돌린다.
164
+ * ⚠ **이 배치가 떠난 자리만 본다** — 이미 남아 있는 옛 빈 ⊓ 은 원인을 모른다(사람이 둔 것일 수 있다).
165
+ * ⚠ **라벨** — bpmn-js 가 경로 변화에 맞춰 라벨을 옮긴다. 라벨이 붙은 구간(라벨 중심에서 가장 가까운 구간)이 접힌 세 구간
166
+ * 밖이면 제자리로 되돌린다(다른 도형 위로 옮겨졌다 — 합성 실측). 안이면 그대로 두고 호출자가 라벨-선 보정에 넘긴다(B-178 과
167
+ * 같은 이유 · 안 넘기면 선재 라벨로 취급돼 자기 선 위에 남는다).
168
+ *
169
+ * 반환 = 실제로 접은 선 id.
170
+ */
171
+ export declare function foldVacatedDetours(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, vacated: readonly VacatedBox[], beforeEdgeIds: ReadonlySet<string>, reroutedEdgeIds: ReadonlySet<string>): Set<string>;
172
+ type Bounds = {
173
+ x: number;
174
+ y: number;
175
+ width: number;
176
+ height: number;
177
+ };
178
+ /** 연결의 부모 컨테이너 bounds — 프로세스 평면(루트)이면 `undefined`. */
179
+ export declare function parentBoundsOf(connection: Connection): Bounds | undefined;
82
180
  /**
83
181
  * 🔴 **이 배치가 새로 만든 간선 × 간선 교차 중 「대가 없이 없앨 수 있는 것」만 없앤다**(B-90 ⓑ).
84
182
  *
@@ -99,20 +197,81 @@ only?: ReadonlySet<string>): Set<string>;
99
197
  * 읽을 수 없는 중첩이 늘지 않을 때만 채택(🔁 「채택 조건에 대가가 없다」 클래스를 미리 막는다).
100
198
  */
101
199
  export declare function repairIntroducedEdgeCrossings(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforePairs: ReadonlySet<string>, beforeEdgeIds: ReadonlySet<string>): void;
200
+ /**
201
+ * 공유 노드 `node` 쪽 끝을 네 변 중심으로 옮긴 경로 후보(순수). 반대쪽 끝은 **지금 도킹점 · 그 변 그대로** 둔다 —
202
+ * 그 끝은 이 쌍의 교차와 무관하고, 옮기면 그쪽 이웃과의 관계가 새로 생긴다. 반대쪽 도킹점이 변 위가 아니면 후보 없음.
203
+ */
204
+ export declare function redockCandidates(edge: GeometryEdge, node: GeometryShape, shapesById: ReadonlyMap<string, GeometryShape>): GeometryPoint[][];
205
+ /**
206
+ * 🔴 **이 배치가 만든 「끝점을 공유하는」 시퀀스 플로우 교차를 공유 노드의 출입 변을 바꿔 없앤다**(B-146 ⓑ).
207
+ *
208
+ * 표본 98 의 사람 수정 형태 그대로다 — 실패 갈래(게이트웨이 → 오류 노드)가 오류 노드 왼쪽 면으로, 되돌아감(오류 노드 →
209
+ * 상류)이 윗면에서 나가 서로 가로질렀고, 사람은 **실패 갈래를 윗면으로 · 되돌아감을 왼쪽 면에서** 내도록 맞바꿨다
210
+ * (도형 무이동 · 간선 직접 2). 🔴 **한 간선만 옮겨서는 안 풀린다** — 어느 쪽만 옮겨도 다른 쪽과 공선으로 마주 달린다.
211
+ * 그래서 B-90 ⓑ(한 간선씩)와 달리 **쌍을 함께** 고른다.
212
+ *
213
+ * **범위**(B-146 수단 결정) — 시퀀스 × 시퀀스(노드 루프)만 · 블랙박스 풀을 함께 끝점으로 가진 메시지는 보류(사람 기저 0 ·
214
+ * 증언 없음) · 이 배치가 만든 쌍만(`beforeSharedPairs` 밖) · **이 배치가 만든 간선만 움직인다**(B-90 ⓑ 규약 — 기존 간선은
215
+ * 지금 경로 하나만 후보다). 도형은 옮기지 않는다 — 경로로 안 풀리는 형상(g39 = 새 게이트웨이가 기존 우회선 아래)은 남는다.
216
+ *
217
+ * **대가 판정**(B-90 ⓑ 와 같은 자세 — 계산이 곧 판별) — 이 쌍이 더는 교차하지 않고 · 둘이 공선으로 겹치지 않고 · 컨테이너
218
+ * 안이고 · 끝점 공유 교차 총수가 줄고 · **종전 교차 쌍이 새로 생기지 않고** · 문서 판정에 **새 키가 0** 일 때만. 통과한
219
+ * 조합 중 **길이 + 꺾임** 이 가장 작은 것을 고른다(사람 수정본은 도구 산출과 길이가 같고 꺾임만 달랐다).
220
+ */
221
+ export declare function repairIntroducedSharedEndpointCrossings(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeSharedPairs: ReadonlySet<string>, beforeEdgeIds: ReadonlySet<string>): void;
222
+ /**
223
+ * 🔴 **이 배치가 만든 메시지 중 선재 블랙박스 풀로 가고 짝 열이 풀 가로 범위 밖인 것을 짝 쪽 가장자리에 다시 도킹한다**(B-150).
224
+ * `beforeEdgeIds` · `beforeShapeIds` = 하강 전 간선 · 도형 id(선재 풀 판별 · 새 메시지 판별).
225
+ */
226
+ export declare function redockIntroducedBlackboxMessages(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeEdgeIds: ReadonlySet<string>, beforeShapeIds: ReadonlySet<string>): void;
102
227
  /**
103
228
  * 풀 횡단 메시지플로우의 6점 경로 계획(순수). `null` = 이 간선은 대상이 아니거나(중간 풀 없음 ·
104
229
  * 끝점 해소 불가) 더 나은 열이 없다.
105
230
  */
106
231
  export declare function planCrossPoolRoute(edge: GeometryEdge, scene: GeometryScene): GeometryPoint[] | null;
232
+ /**
233
+ * ── 승객 간선의 base 경로 평행이동 (B-133 ⓒ) ──
234
+ *
235
+ * 하강 전에 있던 간선 중 **양 끝 도형이 같은 델타로 움직였는데 경로는 다시 깔린 것**을 base 경로 + 델타로
236
+ * 되돌린다. 한 짝의 끝점이 **서로 다른 단계**에서 옮겨지면(밀기 `createSpace` 는 노드 쪽만 · B-75 추종은 풀
237
+ * 쪽만 · 짝 동반은 짝 쪽만) 단계마다 bpmn-js `connection.layout` 이 사람이 그린 경로를 버리고 다시 깐다. 순
238
+ * 변위가 같으므로 평행이동이면 사람 경로가 그대로 산다. 실측(표본 103 · 사람 문서 + 증언 *"선이 껶여있는
239
+ * 부분이 걸렸어"*) = 쌓인 송신 노드의 **옆면 출발 3점**이 위 노드를 관통하는 2점으로 다시 깔리고, 우회 보정이
240
+ * 그것을 **8점 지그재그**로 감싸 이웃 메시지와 130px 겹쳤다(`edge-overlap-unrelated`).
241
+ *
242
+ * 안전 성질 2(선재 경로 불가침)의 **복원판**이다 — 선재 경로를 이 배치가 이미 지운 자리에서, 사람이 그린 것을
243
+ * 되살린다. 자리 = 도형을 옮기는 패스(lower · 풀 · 그룹) **전부 뒤**, 경로 보정 **앞** — 되살린 경로도 뒤
244
+ * 보정의 입력이 된다.
245
+ *
246
+ * 조건(전부) — ① 하강 전에 있던 **시퀀스 · 메시지 흐름**(연관은 뺀다 — N20 에서 base 의 끊긴 주석 연관만 되살려
247
+ * 판정을 늘렸고 이득은 0 이었다) ② 이 배치가 끝점을 바꾸지 않았다(재배선 · 끝점 id) ③ 양 끝 도형 **크기 불변** ·
248
+ * 이동 델타가 **같고 0 이 아니다** ④ 지금 경로 ≠ base + 델타 ⑤ 지금 경로가 이미 **관통 없는 2점 축 직선이면
249
+ * 둔다**(N20 — 다시 깐 직선을 사람의 꺾인 경로로 되돌리면 2점 메시지만 잃었다) ⑥ base + 델타 경로가 도형을
250
+ * 관통하지 않는다(관통하면 뒤 우회 보정에 맡긴다).
251
+ *
252
+ * N20(합성 재고 = 풀 안 시퀀스 전량 끼우기 3 op · 사람 문서 183 → 3,884 · 저장본 109 → 4,466) — 사람: 배치가 만든
253
+ * 판정 **−50** · 새 판정 4(전부 교환) · 교차 −25 · 2점 메시지 무변 · 순악화 **0** / 저장본: **−58** · 교차 감소 ·
254
+ * 2점 메시지 무변 · 순악화 **0**(교차 +1 4건은 종류 다름 중첩 해소와 교환).
255
+ */
256
+ export declare function restorePassengerEdgeRoutes(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, sceneBefore: GeometryScene, reroutedEdgeIds: ReadonlySet<string>): void;
107
257
  /**
108
258
  * 이 배치가 **새로 만든** 메시지플로우 중 풀을 횡단하는 것을 재경로한다(하강 직후, undo 에피소드
109
259
  * 안). `beforeEdgeIds` = 하강 전 간선 id — 그 밖의 것만 대상(안전 성질 2: 선재 경로 불가침).
110
260
  */
111
261
  export declare function rerouteIntroducedCrossPoolEdges(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeEdgeIds: ReadonlySet<string>): void;
262
+ /**
263
+ * 🔴 **이 배치가 만들었거나 경로를 바꾼 메시지가 관계없는 풀 안을 가로로 지나면 그 가로를 끝점의 풀 안으로 옮긴다**(B-151) — 끝점 풀 안이
264
+ * 막히면 풀 밖 채널(풀 사이 틈 · 더미 바깥)로(B-151 ⓐ) · 채택이 없던 메시지는 한 번 더 본다.
265
+ * 선재 메시지는 base 보다 그 길이가 `UNRELATED_POOL_RUN_MIN` 이상 **는** 것만 — base 의 가로는 사람이 둔 것이다.
266
+ * `beforeEdgeIds` = 하강 전 간선 id · `sceneBefore` = 하강 전 장면(선재 경로 · 풀).
267
+ */
268
+ export declare function repairIntroducedUnrelatedPoolRuns(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeEdgeIds: ReadonlySet<string>, sceneBefore: GeometryScene): void;
112
269
  /** 안쪽 구간(첫·끝 도킹 구간 제외)이 컨테이너 경계선과 나란히 이 거리 안에서 달리면 "경계에 붙었다"고 본다. */
113
270
  export declare const BOUNDARY_CLEARANCE = 30;
114
271
  /** 웨이포인트의 **안쪽 구간**(도킹 구간 제외)이 어느 컨테이너의 경계선과 나란히 `BOUNDARY_CLEARANCE` 안에서 겹쳐 달리는가. */
115
272
  export declare function hugsContainerBoundary(pts: readonly GeometryPoint[], containers: readonly GeometryShape[]): boolean;
273
+ /** `hugsContainerBoundary` 로 잴 컨테이너 — 풀 · 레인(B-185 ⓔ U 후보와 같은 집합 · 그룹은 뺀다). B-236 반대편 채널이 쓴다. */
274
+ export declare function boundaryContainersOf(scene: GeometryScene): GeometryShape[];
116
275
  /** 안쪽 구간이 이 거리 안에서 다른 도형 옆을 지나면 "스친다"고 본다(관통은 아니지만 도형 사이 통로를 달리는 선). */
117
276
  export declare const NEAR_PASS_MARGIN = 40;
118
277
  /** 안쪽 구간(도킹 구간 제외)이 끝점 아닌 도형을 `NEAR_PASS_MARGIN` 안에서 스치는 횟수 — 빈 여백을 달리는 경로가 0. */
@@ -126,6 +285,19 @@ export declare function nearPassCount(pts: readonly GeometryPoint[], shapes: rea
126
285
  * 같은 레인 안에서 되돌아가는 간선(r2 `Flow_o14`)은 A2 채널이 경계에서 멀어 발동하지 않는다. 없으면 `null`.
127
286
  */
128
287
  export declare function planBackEdgeBoundaryClearance(edge: GeometryEdge, scene: GeometryScene): GeometryPoint[] | null;
288
+ /**
289
+ * ── B-202. 다른 행으로 가는 갈래가 곧은 형제 갈래의 출구를 함께 쓰는가(순수) ──
290
+ *
291
+ * 게이트웨이의 위 · 아래 갈래가 주 갈래(곧은 2점)와 **같은 꼭짓점에서 같은 방향**으로 나가 첫 구간을 공유한 뒤 꺾이면,
292
+ * 라벨을 각 고유 구간으로 갈라도(B-15 ⓐ) 어느 선이 어디로 가는지 *"내용을 봐야"* 안다(외부 BSP 문서 15 검토자).
293
+ * 🔴 **사람은 이 꼴을 안 만든다** — 곧은 주 갈래 + 다른 행 갈래 짝에서 둘째 갈래가 주 갈래 출구를 공유하는 것은 사람
294
+ * **1/380**(레거시 161 · 실무 26 문서)이고 나머지는 전부 그쪽 꼭짓점(윗면 · 아랫면)으로 나간다. 「같은 방향 팬아웃 겹침은
295
+ * 문제 아님」(B-14 ⓒ1 · B-15 ⓐ)은 이 짝에서 반증됐다 — 같은 쪽 갈래끼리(둘 다 위 · 둘 다 아래)의 공유는 사람도 흔하다(B-192).
296
+ *
297
+ * 판별 = 시퀀스 · 출발이 게이트웨이 · `points` 의 첫 구간이 같은 출발의 곧은 2점 형제 시퀀스와 같은 점 · 같은 축 · 같은 방향.
298
+ * 반환 = 공유하는 형제 id · 없으면 `null`.
299
+ */
300
+ export declare function sharedSiblingExit(points: readonly GeometryPoint[], edge: GeometryEdge, scene: GeometryScene): string | null;
129
301
  /**
130
302
  * 배치가 만든 정방향 간선의 **불필요한 꺾임을 줄인다**(B-34 ⓑ) — bpmn-js 기본 맨해튼 라우팅은 출발 직후
131
303
  * 꺾어 목표 행으로 올라간 뒤 가로로 가는 4점을 낸다. 사람은 두 회차 연속(표본 30·31, 같은 간선 같은 변환)
@@ -154,15 +326,42 @@ export declare function planBackEdgeBoundaryClearance(edge: GeometryEdge, scene:
154
326
  * 직접 근거는 표본 89 하나이고 원본은 짝의 **대칭**을 지지할 뿐이다. 짝 판정은 신규 · 재배선 간선에 똑같이 건다
155
327
  * (한쪽만 걸면 🔁 add/update 경로 갈림이다). 우회가 아니면 순서는 그대로다 — 새 행의 흐름 머리로 들어가는 태스크 출발은
156
328
  * 사람 원본이 가로 → 세로 **63/68**(세로 → 가로 0)이다.
329
+ *
330
+ * ── B-202. **곧은 형제 갈래와 출구를 공유하는 후보는 끝으로 미룬다** ──
331
+ *
332
+ * 가로 → 세로 후보는 출발 오른쪽 면에서 나간다. 출발이 게이트웨이고 그 꼭짓점에서 곧은 형제 갈래가 이미 같은 방향으로
333
+ * 나가면 두 선이 첫 구간을 공유한다(`sharedSiblingExit`) — 판독 불가 겹침은 같은 방향 · 같은 출발을 합류로 빼서 게이트가
334
+ * 못 본다. 이 패스로 오는 그 4점은 시험 이동 되돌림의 잔여였다(`tryShiftGroups` 가 게이트웨이를 목표 밑으로 옮긴 순간 bpmn-js 가
335
+ * 목표 아랫면으로 다시 깔고 되돌림은 도형만 돌린다 — 🔁 B-123 · N22). 공유 후보는 **지우지 않는다** — 다른 후보가 다 막히면
336
+ * 종전대로 쓴다. ⚠ 반대 중첩 보정(`planOppositeOverlapRepair`)에는 넣지 않았다 — 그쪽 실례(주문 이행 fixture)는 후보가 전부
337
+ * 오른 꼭짓점 출발이라 순서로는 못 피하고 코퍼스 효과가 0 이었다(시제품).
157
338
  */
158
- export declare function repairIntroducedDetours(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeEdgeIds: ReadonlySet<string>, reroutedEdgeIds: ReadonlySet<string>): void;
339
+ export declare function repairIntroducedDetours(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeEdgeIds: ReadonlySet<string>, reroutedEdgeIds: ReadonlySet<string>,
340
+ /** B-223 — 이 배치 전 도형(뒤늦은 U 의 자기 라벨 비킴 판정). */
341
+ beforeShapeIds: ReadonlySet<string>): void;
159
342
  export declare function repairIntroducedBoundaryHugging(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeEdgeIds: ReadonlySet<string>): void;
343
+ /**
344
+ * 🔴 **B-211 — 경로가 끝점 아닌 게이트웨이의 꼭짓점에 닿고, 그 꼭짓점에 도킹한 다른 흐름의 끝점을 지나는가.**
345
+ *
346
+ * 후보 게이트 둘이 이 형상을 각자 면책한다 — `crossedShapesOf` 는 bbox 를 `CROSS_INSET` 만큼 줄인 상자에 **들어와야**
347
+ * 관통이라 마름모 꼭짓점 접촉(실형상 거리 0)이 빠지고, `crossingCost` 는 진성 교차만 세서 도킹점을 **정확히 지나는** 선이
348
+ * 빠진다(N1307). 둘이 겹치면 꼭짓점을 지나는 후보가 「관통 0 · 교차 0」 으로 1등이 된다 — 원격 반품 문서의 재시도 루프가
349
+ * 「환불 결과?」 왼쪽 꼭짓점 = 들어오는 화살표 끝을 지나 선이 게이트웨이로 드는 것처럼 읽혔다(판정 0). 구조적이다: 게이트웨이
350
+ * (폭 50)가 같은 열에 중심 정렬되면 도킹 편이 25 가 곧 꼭짓점 x 다.
351
+ *
352
+ * 🔴 **N20** — 사람 문서(레거시 161 · 실무 26)에 이 형상 0 · 끝점 아닌 게이트웨이에 20px 안으로 다가간 선조차 0.
353
+ * ⚠ 꼭짓점 **접촉만**(도킹한 흐름이 없는 꼭짓점)은 세지 않는다 — 측정한 얼굴(P3)보다 넓히지 않는다.
354
+ * 호출자 = 반대 중첩 보정(B-211) · 경계 비킴(B-220) — 같은 생성기(`backEdgeCandidates`)를 쓰는 가짜 합류 · 연쇄 보정은 아니다.
355
+ */
356
+ export declare function passesGatewayVertexDock(points: readonly GeometryPoint[], edge: GeometryEdge, scene: GeometryScene): boolean;
160
357
  /**
161
358
  * 한 간선의 **읽을 수 없는 중첩**(반대 방향 · 종류 다름)을 없애거나 줄이는 경로(순수). 못 찾으면 `null`.
162
359
  * 종류 다른 중첩(B-17 ⓐ)의 보정 = 도킹 편이 — "가급적 중심에 도킹하되 어쩔 수 없을 땐 약간 비껴서"
163
360
  * (사용자 프레이밍). 기본은 중심이고, finding 이 났을 때만, 최소 편이(±25)부터 본다.
164
361
  */
165
- export declare function planOppositeOverlapRepair(edge: GeometryEdge, scene: GeometryScene): GeometryPoint[] | null;
362
+ export declare function planOppositeOverlapRepair(edge: GeometryEdge, scene: GeometryScene, options?: {
363
+ sideEntry?: boolean;
364
+ }): GeometryPoint[] | null;
166
365
  /**
167
366
  * 이 간선의 **가짜 합류**(B-77)를 없애는 경로(순수). 못 찾으면 `null`.
168
367
  *
@@ -201,7 +400,18 @@ export declare function planChainOverlapRepair(edge: GeometryEdge, scene: Geomet
201
400
  * 짝 중 **새 간선만** 손댄다(안전 성질 2).
202
401
  */
203
402
  export declare function repairIntroducedChainOverlaps(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeKeys: ReadonlySet<string>, beforeEdgeIds: ReadonlySet<string>): void;
204
- export declare function repairIntroducedOppositeOverlaps(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeKeys: ReadonlySet<string>, beforeEdgeIds: ReadonlySet<string>): void;
403
+ /**
404
+ * B-14 ⓒ1 — 이 배치가 새로 낸 읽을 수 없는 중첩을 고친다. `beforeEdgeIds` 에 든 간선(배치 전부터 있던 것)은 손대지 않는다.
405
+ * 🔴 **B-178** — `sideEntryEdgeIds` 에 든 간선에만 빈 옆면 진입 후보를 연다(호출자 = 「이 배치가 경로를 다시 깐 기존 간선」).
406
+ * 🔴 **반환 = 실제로 경로를 바꾼 간선** — 뒤의 라벨-선 보정이 그 간선의 라벨을 이 배치 몫으로 다뤄야 한다(안 그러면
407
+ * 다시 깐 기존 간선의 라벨이 새 경로 위에 남는다 — N20 실측 +9).
408
+ */
409
+ export declare function repairIntroducedOppositeOverlaps(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeKeys: ReadonlySet<string>, beforeEdgeIds: ReadonlySet<string>, sideEntryEdgeIds?: ReadonlySet<string>): ReadonlySet<string>;
410
+ /**
411
+ * 🔴 **이 배치가 만든 왕복 메시지 짝(양 끝 공유 · 반대 방향 · 둘 다 2점 직선)이 한 선이면 나가는 선 −20 · 들어오는 선 +20 으로
412
+ * 벌린다**(B-230). 반환 = 옮긴 간선 id — 뒤의 라벨-선 보정이 이 배치 몫으로 다룬다.
413
+ */
414
+ export declare function separateIntroducedReverseMessagePairs(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeEdgeIds: ReadonlySet<string>): ReadonlySet<string>;
205
415
  /**
206
416
  * 라벨의 새 bounds(순수). 라벨이 공유 구간 위에 없으면 `null`(옮길 이유가 없다). 고유 구간을 못
207
417
  * 찾거나 옮긴 자리가 도형과 겹치면 `null`(손대지 않고 보고에 맡긴다).
@@ -298,13 +508,24 @@ export declare function planLabelBesideOwnLine(edge: GeometryEdge, scene: Geomet
298
508
  * 반사실(합성 5,002 · lineage 93) = 해소 9 · lineage 는 표본 78 한 회차(사람 값과 3px) · 새 판정 0.
299
509
  * ⚠ **못 닫는 것** — 라벨이 선보다 넓다(🔁 B-31 「틈 40」) · 고른 자리가 다른 선과 공유 구간이다(`label-on-shared-segment`
300
510
  * — 공유 구간 검사 + 미끄럼 후보를 더한 판도 이득 0) · base 에서 이미 표류한 라벨(선 기하가 안 바뀌어 이 가지에 안 온다).
511
+ *
512
+ * ── B-119 ⓒ′. **착지가 라벨 뒤로 비켜 선 간선(`labelLandingFlowIds`)은 겹침 없이도 base 로 되돌린다** ──
513
+ *
514
+ * 새 노드가 base 라벨 오른끝 + 10 에 서도 bpmn-js 가 착지 뒤 라벨을 비례 위치로 옮겨 노드 왼변에 **닿게** 둔다(합성 발동 167 중
515
+ * 22 · 여유 5 미만 · 표본 144 = 1px — 사람은 여유 30 으로 고쳤다). 1px 은 위 「겹칠 때만」 문턱(kind 깊이 3)에 안 걸려 아무도
516
+ * 안 본다. 그 자리는 하강이 **일부러 비워 둔** 자리라 되돌리면 여유가 정확히 그 10 이다. ⚠ 「겹칠 때만」(2026-09-28 결정)은
517
+ * 일반 재배선 라벨의 규칙이라 그대로 둔다 — 넓히는 것은 이 간선들뿐이다. 자리 · 거리 · 채택 게이트는 ⓑ 와 같다.
301
518
  */
302
- export declare function followMovedEdgeLabels(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, before: ReadonlyMap<string, EdgeLabelSnapshot>): void;
519
+ export declare function followMovedEdgeLabels(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, before: ReadonlyMap<string, EdgeLabelSnapshot>, labelLandingFlowIds?: ReadonlySet<string>): void;
303
520
  /**
304
521
  * 이 배치가 **새로 만든** 간선의 라벨을 선·경계선에서 뗀다(맨 마지막 — 라벨 귀속 보정 뒤). 선재 라벨은 불가침 —
305
522
  * 단 `reroutedEdgeIds`(이 배치가 끝점을 바꿔 경로를 다시 깐 선재 간선)는 대상이다(B-114 ⓔ ⓑ).
523
+ *
524
+ * B-196 — `besideOwnLineIds`(4.5 ⓔ 가 막는 도형 왼쪽으로 비킨 메시지)는 위 자리(없으면 지금 자리)가 흐름 노드 위면 자기 선 곁
525
+ * 빈자리({@link planLabelBesideOwnLine})로 — 「세로 = 오른쪽 먼저」 후보가 방금 비킨 막는 도형 위다(후보는 선만 본다 · 판정
526
+ * `label-over-shape` 는 메시지 라벨을 안 본다 — 지표 0 인 채 보이는 겹침). 곁 자리가 없으면 위 자리 그대로다.
306
527
  */
307
- export declare function repairIntroducedLabelLines(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeEdgeIds: ReadonlySet<string>, reroutedEdgeIds?: ReadonlySet<string>): void;
528
+ export declare function repairIntroducedLabelLines(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeEdgeIds: ReadonlySet<string>, reroutedEdgeIds?: ReadonlySet<string>, besideOwnLineIds?: ReadonlySet<string>): void;
308
529
  /**
309
530
  * 이 배치가 **새로 만든** 간선의 라벨 귀속 문제를 고친다(하강 직후, undo 에피소드 안, 경로 보정들 뒤).
310
531
  * 선재 간선의 라벨은 사람이 놓았을 수 있어 손대지 않는다(안전 성질 2).
@@ -342,3 +563,4 @@ export declare function repairIntroducedShapeLabelLines(services: Pick<ResolverS
342
563
  * `scene` 으로 하고 통과한 간선만 실제로 옮긴다 · 새 키가 생기면 **그 간선만** 두고 간다(🔁 B-61).
343
564
  */
344
565
  export declare function redockIntroducedDetachedEndpoints(services: Pick<ResolverServices, 'elementRegistry' | 'modeling'>, beforeKeys: ReadonlySet<string>): void;
566
+ export {};