@formicoidea/labre-framework-bpmn 0.32.0 → 0.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/actions.d.ts +202 -6
  2. package/dist/actions.js +421 -43
  3. package/dist/background.d.ts +2 -0
  4. package/dist/background.js +158 -0
  5. package/dist/commands.js +496 -5
  6. package/dist/consts.d.ts +157 -3
  7. package/dist/consts.js +192 -3
  8. package/dist/element-renderer.d.ts +10 -4
  9. package/dist/element-renderer.js +14 -55
  10. package/dist/element-view.d.ts +100 -8
  11. package/dist/element-view.js +249 -30
  12. package/dist/export.d.ts +277 -0
  13. package/dist/export.js +1802 -0
  14. package/dist/facts.d.ts +48 -0
  15. package/dist/facts.js +127 -0
  16. package/dist/import.d.ts +44 -0
  17. package/dist/import.js +1440 -0
  18. package/dist/index.d.ts +12 -0
  19. package/dist/index.js +44 -0
  20. package/dist/interchange.d.ts +109 -0
  21. package/dist/interchange.js +191 -0
  22. package/dist/morph.d.ts +61 -0
  23. package/dist/morph.js +118 -0
  24. package/dist/node/node-renderer.d.ts +0 -9
  25. package/dist/node/node-renderer.js +294 -17
  26. package/dist/pool-hit.d.ts +98 -0
  27. package/dist/pool-hit.js +130 -0
  28. package/dist/presets.d.ts +114 -0
  29. package/dist/presets.js +232 -0
  30. package/dist/profiles.d.ts +2 -0
  31. package/dist/profiles.js +189 -0
  32. package/dist/roles.d.ts +96 -0
  33. package/dist/roles.js +410 -0
  34. package/dist/rules.d.ts +199 -0
  35. package/dist/rules.js +1539 -0
  36. package/dist/templates/index.js +116 -9
  37. package/dist/toolbar/bpmn-senior-button.js +8 -2
  38. package/dist/toolbar/config.d.ts +27 -2
  39. package/dist/toolbar/config.js +86 -2
  40. package/dist/toolbar/icons.d.ts +67 -0
  41. package/dist/toolbar/icons.js +141 -0
  42. package/dist/toolbar/senior-tool.js +1 -0
  43. package/dist/translations.d.ts +3 -1
  44. package/dist/translations.js +8 -3
  45. package/dist/view.d.ts +6 -2
  46. package/dist/view.js +68 -5
  47. package/package.json +2 -2
package/dist/roles.js ADDED
@@ -0,0 +1,410 @@
1
+ /** Role ids, keyed by the `kind` used at the creation sites. */
2
+ export const BPMN_ROLE = {
3
+ // The umbrella over the three families that ARE the process: events,
4
+ // activities and gateways. Never stamped, like the three families under it.
5
+ flowObject: 'bpmn:flow-object',
6
+ // Events: the family, the two starts and the two ends, and the leaves the
7
+ // descriptive profile draws under each.
8
+ event: 'bpmn:event',
9
+ startEvent: 'bpmn:start-event',
10
+ startEventMessage: 'bpmn:message-start-event',
11
+ startEventTimer: 'bpmn:timer-start-event',
12
+ endEvent: 'bpmn:end-event',
13
+ endEventMessage: 'bpmn:message-end-event',
14
+ endEventTerminate: 'bpmn:terminate-end-event',
15
+ // Activities.
16
+ activity: 'bpmn:activity',
17
+ task: 'bpmn:task',
18
+ taskUser: 'bpmn:user-task',
19
+ taskService: 'bpmn:service-task',
20
+ subProcess: 'bpmn:sub-process',
21
+ callActivity: 'bpmn:call-activity',
22
+ // Gateways. `gateway-exclusive` keeps the word order it shipped with — it is
23
+ // written in documents already — while its sibling takes the spec's own
24
+ // ("parallel gateway"). An id in a stored document is not a naming
25
+ // convention: it is a value, and renaming it would orphan every process that
26
+ // carries it.
27
+ gateway: 'bpmn:gateway',
28
+ gatewayExclusive: 'bpmn:gateway-exclusive',
29
+ gatewayParallel: 'bpmn:parallel-gateway',
30
+ // Data — a family of its own, never a flow object.
31
+ data: 'bpmn:data',
32
+ dataObject: 'bpmn:data-object',
33
+ dataStore: 'bpmn:data-store',
34
+ // The two artifacts: a note on the picture, and a lasso round part of it.
35
+ textAnnotation: 'bpmn:text-annotation',
36
+ group: 'bpmn:group',
37
+ // The frame.
38
+ pool: 'bpmn:pool',
39
+ // The connecting objects.
40
+ sequenceFlow: 'bpmn:sequence-flow',
41
+ messageFlow: 'bpmn:message-flow',
42
+ association: 'bpmn:association',
43
+ };
44
+ const _everyRoleIsMapped = true;
45
+ void _everyRoleIsMapped;
46
+ /** i18n key stem of a role id: `bpmn:start-event` → `com.labre.bpmn.role.start-event`. */
47
+ const roleKey = (id) => `com.labre.bpmn.role.${id.slice('bpmn:'.length)}`;
48
+ const FLOW_OBJECT_DEFS = [
49
+ /**
50
+ * The FLOW OBJECT — the one word BPMN itself uses for "a thing the process
51
+ * does", and the parent of the three families under it.
52
+ *
53
+ * Never stamped, like the three families it covers: no palette entry writes
54
+ * `bpmn:flow-object` and none ever will. It exists so a rule can say the thing
55
+ * the notation says. A sequence flow chains flow objects; a step must be
56
+ * reachable from the start; both sentences are about events, activities AND
57
+ * gateways at once, and without this role each of them would have to enumerate
58
+ * the three — three triplets where BPMN has one word, and a fourth family
59
+ * (nobody has asked for one) silently missing from every rule that forgot to
60
+ * grow its list.
61
+ *
62
+ * ## What it deliberately does NOT cover
63
+ *
64
+ * `bpmn:data`, `bpmn:text-annotation` and `bpmn:pool` stay outside, each for
65
+ * the reason its own block gives: the paperwork is not the work, commentary is
66
+ * never evidence, and the frame is not an artefact drawn in it. That
67
+ * exclusion is the whole value of the word — "a sequence flow chains flow
68
+ * objects" is only worth saying because a data object is not one.
69
+ *
70
+ * Pure static data, and nothing is written to a document: an element carries
71
+ * the role its palette entry stamped (`bpmn:task`), and the walk from it up to
72
+ * `bpmn:flow-object` happens in `roleIsA`, at evaluation time, out of this
73
+ * table. A process drawn yesterday gains the parent the moment it is opened,
74
+ * with no migration and nothing backfilled.
75
+ */
76
+ {
77
+ id: BPMN_ROLE.flowObject,
78
+ kind: 'node',
79
+ labelKey: roleKey(BPMN_ROLE.flowObject),
80
+ labelFallback: 'Flow object',
81
+ },
82
+ // The three families. None of them is ever STAMPED on an element — the palette
83
+ // always says which event, which activity, which gateway — and that is the
84
+ // point: they exist so a rule can be written once about "an event" and stay
85
+ // written when the full pack adds the message and timer ones under them.
86
+ {
87
+ id: BPMN_ROLE.event,
88
+ parent: BPMN_ROLE.flowObject,
89
+ kind: 'node',
90
+ labelKey: roleKey(BPMN_ROLE.event),
91
+ labelFallback: 'Event',
92
+ },
93
+ {
94
+ id: BPMN_ROLE.startEvent,
95
+ parent: BPMN_ROLE.event,
96
+ kind: 'node',
97
+ labelKey: roleKey(BPMN_ROLE.startEvent),
98
+ labelFallback: 'Start event',
99
+ },
100
+ // The two TRIGGERED starts. Children of the plain start event and not
101
+ // siblings of it: "the process starts here" is true of all three, and a rule
102
+ // about where a process begins must not have to enumerate the triggers.
103
+ {
104
+ id: BPMN_ROLE.startEventMessage,
105
+ parent: BPMN_ROLE.startEvent,
106
+ kind: 'node',
107
+ labelKey: roleKey(BPMN_ROLE.startEventMessage),
108
+ labelFallback: 'Message start event',
109
+ },
110
+ {
111
+ id: BPMN_ROLE.startEventTimer,
112
+ parent: BPMN_ROLE.startEvent,
113
+ kind: 'node',
114
+ labelKey: roleKey(BPMN_ROLE.startEventTimer),
115
+ labelFallback: 'Timer start event',
116
+ },
117
+ {
118
+ id: BPMN_ROLE.endEvent,
119
+ parent: BPMN_ROLE.event,
120
+ kind: 'node',
121
+ labelKey: roleKey(BPMN_ROLE.endEvent),
122
+ labelFallback: 'End event',
123
+ },
124
+ // ...and the two ends that do something on the way out.
125
+ {
126
+ id: BPMN_ROLE.endEventMessage,
127
+ parent: BPMN_ROLE.endEvent,
128
+ kind: 'node',
129
+ labelKey: roleKey(BPMN_ROLE.endEventMessage),
130
+ labelFallback: 'Message end event',
131
+ },
132
+ {
133
+ id: BPMN_ROLE.endEventTerminate,
134
+ parent: BPMN_ROLE.endEvent,
135
+ kind: 'node',
136
+ labelKey: roleKey(BPMN_ROLE.endEventTerminate),
137
+ labelFallback: 'Terminate end event',
138
+ },
139
+ {
140
+ id: BPMN_ROLE.activity,
141
+ parent: BPMN_ROLE.flowObject,
142
+ kind: 'node',
143
+ labelKey: roleKey(BPMN_ROLE.activity),
144
+ labelFallback: 'Activity',
145
+ },
146
+ // The plain task — one unit of work, done by someone or something unnamed.
147
+ {
148
+ id: BPMN_ROLE.task,
149
+ parent: BPMN_ROLE.activity,
150
+ kind: 'node',
151
+ labelKey: roleKey(BPMN_ROLE.task),
152
+ labelFallback: 'Task',
153
+ },
154
+ // The two typed tasks, under the plain one: they are tasks that also say WHO
155
+ // performs them. A rule about the work applies to all three; a rule about
156
+ // human hand-offs reads only the first.
157
+ {
158
+ id: BPMN_ROLE.taskUser,
159
+ parent: BPMN_ROLE.task,
160
+ kind: 'node',
161
+ labelKey: roleKey(BPMN_ROLE.taskUser),
162
+ labelFallback: 'User task',
163
+ },
164
+ {
165
+ id: BPMN_ROLE.taskService,
166
+ parent: BPMN_ROLE.task,
167
+ kind: 'node',
168
+ labelKey: roleKey(BPMN_ROLE.taskService),
169
+ labelFallback: 'Service task',
170
+ },
171
+ // Sub-process and call activity are activities but NOT tasks: a task is
172
+ // atomic and these two stand for a whole process each — one defined inline,
173
+ // one defined elsewhere and reused. Filing them under `bpmn:task` would make
174
+ // "every task is one unit of work" false.
175
+ {
176
+ id: BPMN_ROLE.subProcess,
177
+ parent: BPMN_ROLE.activity,
178
+ kind: 'node',
179
+ labelKey: roleKey(BPMN_ROLE.subProcess),
180
+ labelFallback: 'Sub-process',
181
+ },
182
+ {
183
+ id: BPMN_ROLE.callActivity,
184
+ parent: BPMN_ROLE.activity,
185
+ kind: 'node',
186
+ labelKey: roleKey(BPMN_ROLE.callActivity),
187
+ labelFallback: 'Call activity',
188
+ },
189
+ {
190
+ id: BPMN_ROLE.gateway,
191
+ parent: BPMN_ROLE.flowObject,
192
+ kind: 'node',
193
+ labelKey: roleKey(BPMN_ROLE.gateway),
194
+ labelFallback: 'Gateway',
195
+ },
196
+ // The exclusive (XOR) gateway and the parallel (AND) one. Same diamond, and
197
+ // the marker inside is the only thing that tells them apart on the canvas —
198
+ // which is exactly why the marker must not be what a rule reads.
199
+ {
200
+ id: BPMN_ROLE.gatewayExclusive,
201
+ parent: BPMN_ROLE.gateway,
202
+ kind: 'node',
203
+ labelKey: roleKey(BPMN_ROLE.gatewayExclusive),
204
+ labelFallback: 'Exclusive gateway',
205
+ },
206
+ {
207
+ id: BPMN_ROLE.gatewayParallel,
208
+ parent: BPMN_ROLE.gateway,
209
+ kind: 'node',
210
+ labelKey: roleKey(BPMN_ROLE.gatewayParallel),
211
+ labelFallback: 'Parallel gateway',
212
+ },
213
+ ];
214
+ /**
215
+ * Data — the paperwork, not the work.
216
+ *
217
+ * A family of its own, parent-less like the pool: a data object is never
218
+ * executed, never has a duration and is never on the happy path, so a rule
219
+ * written about the flow objects must not fall on it. The two leaves are the
220
+ * only distinction BPMN itself draws here — a data OBJECT lives and dies with
221
+ * the process instance, a data STORE outlives it.
222
+ */
223
+ const DATA_DEFS = [
224
+ {
225
+ id: BPMN_ROLE.data,
226
+ kind: 'node',
227
+ labelKey: roleKey(BPMN_ROLE.data),
228
+ labelFallback: 'Data',
229
+ },
230
+ {
231
+ id: BPMN_ROLE.dataObject,
232
+ parent: BPMN_ROLE.data,
233
+ kind: 'node',
234
+ labelKey: roleKey(BPMN_ROLE.dataObject),
235
+ labelFallback: 'Data object',
236
+ },
237
+ {
238
+ id: BPMN_ROLE.dataStore,
239
+ parent: BPMN_ROLE.data,
240
+ kind: 'node',
241
+ labelKey: roleKey(BPMN_ROLE.dataStore),
242
+ labelFallback: 'Data store',
243
+ },
244
+ ];
245
+ /**
246
+ * The two artifacts — what the author drew ON the picture rather than IN it.
247
+ *
248
+ * Both parent-less and childless, and not siblings of each other either: they
249
+ * are not flow objects, not data and not frames, and the one thing every rule
250
+ * in this framework must agree on is that commentary is never evidence.
251
+ * Declared all the same, so a reader (and the audit) can tell an annotation
252
+ * from an unnamed rectangle somebody left behind.
253
+ *
254
+ * The GROUP is parent-less for a second reason, which is the spec's own: BPMN
255
+ * 2.0.2 §10.4 exempts it from every connection and containment constraint there
256
+ * is. It cannot be attached to a sequence or message flow, it is not bounded by
257
+ * the pool or lane it overlaps, and it may straddle several pools at once. A
258
+ * role under `bpmn:pool` or under any flow-object family would have made all
259
+ * three of those false by inheritance — the tree is where that exemption is
260
+ * written down.
261
+ *
262
+ * It is deliberately NOT the parent of the annotation, nor a child of it: one
263
+ * says something about a region, the other says something about a thing, and a
264
+ * rule about either must not fall on the other.
265
+ */
266
+ const ARTIFACT_DEFS = [
267
+ {
268
+ id: BPMN_ROLE.textAnnotation,
269
+ kind: 'node',
270
+ labelKey: roleKey(BPMN_ROLE.textAnnotation),
271
+ labelFallback: 'Text annotation',
272
+ },
273
+ {
274
+ id: BPMN_ROLE.group,
275
+ kind: 'node',
276
+ labelKey: roleKey(BPMN_ROLE.group),
277
+ labelFallback: 'Group',
278
+ },
279
+ ];
280
+ // The pool: the participant's own lane, the frame the flow objects are drawn in.
281
+ // Parent-less, like `wardley:map` — a rule written on the flow objects must
282
+ // never match the pool that holds them.
283
+ const POOL_DEFS = [
284
+ {
285
+ id: BPMN_ROLE.pool,
286
+ kind: 'node',
287
+ labelKey: roleKey(BPMN_ROLE.pool),
288
+ labelFallback: 'Pool',
289
+ },
290
+ ];
291
+ /**
292
+ * The two connecting objects.
293
+ *
294
+ * Neither specialises the other, and there is deliberately no `bpmn:flow`
295
+ * parent: a sequence flow stays inside one pool and orders the work, a message
296
+ * flow crosses between pools and carries nothing but the message. They are two
297
+ * different sentences, and a rule about one must never fall on the other.
298
+ */
299
+ const FLOW_DEFS = [
300
+ /**
301
+ * The sequence flow, pre-authorised as a typed edge by `docs/adr/0010`.
302
+ *
303
+ * Tier 1 of that ADR is generic — `source` is the subject of the role's verb,
304
+ * `target` its object — and tier 2 is this `direction` block: the verb is "is
305
+ * followed by", so the source is what happens FIRST and the target is what
306
+ * comes next. That is the whole of what makes an arrow on this canvas a
307
+ * statement the author made rather than a by-product of which end their finger
308
+ * landed on first, and it is what the hover reveal reads back with the `bpmn`
309
+ * flag off.
310
+ */
311
+ {
312
+ id: BPMN_ROLE.sequenceFlow,
313
+ kind: 'edge',
314
+ labelKey: roleKey(BPMN_ROLE.sequenceFlow),
315
+ labelFallback: 'Sequence flow',
316
+ direction: {
317
+ verbKey: `${roleKey(BPMN_ROLE.sequenceFlow)}.verb`,
318
+ verbFallback: 'is followed by',
319
+ gestureHintKey: `${roleKey(BPMN_ROLE.sequenceFlow)}.gesture`,
320
+ gestureHintFallback: 'Drag from what happens first to what follows.',
321
+ },
322
+ },
323
+ /**
324
+ * The message flow — RESERVED.
325
+ *
326
+ * Declared in the vocabulary and stamped by nothing: the lean pack ships no
327
+ * creation tool for it, and the full pack adds one next session. It is written
328
+ * down now rather than later because the vocabulary is the one thing a stored
329
+ * document points at: an id declared today reads correctly whenever it is
330
+ * first written, whereas an id invented after the fact has to be reconciled
331
+ * with whatever the intervening months stamped.
332
+ *
333
+ * Its verb is its own — a message flow says nothing about ORDER, only about
334
+ * who told whom — which is precisely why it is not a child of the sequence
335
+ * flow.
336
+ */
337
+ {
338
+ id: BPMN_ROLE.messageFlow,
339
+ kind: 'edge',
340
+ labelKey: roleKey(BPMN_ROLE.messageFlow),
341
+ labelFallback: 'Message flow',
342
+ direction: {
343
+ verbKey: `${roleKey(BPMN_ROLE.messageFlow)}.verb`,
344
+ verbFallback: 'sends a message to',
345
+ gestureHintKey: `${roleKey(BPMN_ROLE.messageFlow)}.gesture`,
346
+ gestureHintFallback: 'Drag from the participant that sends the message to the one that receives it.',
347
+ },
348
+ },
349
+ /**
350
+ * The association — the line that ties an annotation or a data object to the
351
+ * work it is about.
352
+ *
353
+ * Declared WITHOUT a `direction`, and that is the whole point of it. Tier 1 of
354
+ * `docs/adr/0010` says an edge role names a relation with a VERB, source the
355
+ * subject and target the object; an association names no relation and has no
356
+ * verb. "This note is about that task" reads identically from either end, and
357
+ * the spec agrees: an association is undirected unless it carries data, which
358
+ * the descriptive profile does not.
359
+ *
360
+ * The consequence is deliberate and is the reason to write it down here: the
361
+ * hover reveal shows its LABEL and no sentence, and the "reverse direction"
362
+ * toolbar entry has nothing to offer — because there is no direction to be
363
+ * wrong about, so there is none to fix.
364
+ */
365
+ {
366
+ id: BPMN_ROLE.association,
367
+ kind: 'edge',
368
+ labelKey: roleKey(BPMN_ROLE.association),
369
+ labelFallback: 'Association',
370
+ },
371
+ ];
372
+ const DEFS = [
373
+ ...FLOW_OBJECT_DEFS,
374
+ ...DATA_DEFS,
375
+ ...ARTIFACT_DEFS,
376
+ ...POOL_DEFS,
377
+ ...FLOW_DEFS,
378
+ ];
379
+ // Null prototype: this is a lookup table keyed by ids that may one day come
380
+ // from host-supplied packs, so `defs['toString']` must not resolve.
381
+ export const BPMN_ROLES = Object.assign(Object.create(null), Object.fromEntries(DEFS.map(def => [def.id, def])));
382
+ /**
383
+ * The legacy `kind` discriminant → the role it means.
384
+ *
385
+ * `kind` STAYS: it is persisted, it drives the renderer and it is what the
386
+ * palette writes. What it is not, from today, is the semantic authority — the
387
+ * ROLE is. The two are posted side by side at every creation site, the way
388
+ * Wardley already does it, and this table is the single place that says which
389
+ * kind means which role. Total over {@link BpmnNodeKind} by its type, so a new
390
+ * kind cannot land without being given a meaning.
391
+ */
392
+ export const BPMN_ROLE_OF_KIND = {
393
+ startEvent: BPMN_ROLE.startEvent,
394
+ startEventMessage: BPMN_ROLE.startEventMessage,
395
+ startEventTimer: BPMN_ROLE.startEventTimer,
396
+ endEvent: BPMN_ROLE.endEvent,
397
+ endEventMessage: BPMN_ROLE.endEventMessage,
398
+ endEventTerminate: BPMN_ROLE.endEventTerminate,
399
+ task: BPMN_ROLE.task,
400
+ taskUser: BPMN_ROLE.taskUser,
401
+ taskService: BPMN_ROLE.taskService,
402
+ subProcess: BPMN_ROLE.subProcess,
403
+ callActivity: BPMN_ROLE.callActivity,
404
+ gatewayExclusive: BPMN_ROLE.gatewayExclusive,
405
+ gatewayParallel: BPMN_ROLE.gatewayParallel,
406
+ dataObject: BPMN_ROLE.dataObject,
407
+ dataStore: BPMN_ROLE.dataStore,
408
+ textAnnotation: BPMN_ROLE.textAnnotation,
409
+ group: BPMN_ROLE.group,
410
+ };
@@ -0,0 +1,199 @@
1
+ import type { EndpointTriplet, ValidationRule } from '@formicoidea/labre-core/blocks/surface';
2
+ /**
3
+ * BPMN validation rules — the descriptive profile, as DATA (backlog item B6).
4
+ *
5
+ * NOTE ON NUMBERING: that "B6" is the BACKLOG item this file delivers. The
6
+ * **B1**–**B21** headings below are RULE numbers, a different space entirely,
7
+ * and the two collide on one token. Every in-file cross-reference means the rule
8
+ * number; the backlog item is named nowhere else.
9
+ *
10
+ * DATA owned by the framework, versioned per rule: the engine
11
+ * (`@labre/affine-block-surface`) knows how to evaluate a FAMILY, never a
12
+ * concrete rule, so adding a BPMN rule is adding an entry to the array at the
13
+ * bottom of this file. Registered from the flag-gated `BpmnViewExtension`, so
14
+ * switching the `bpmn` flag off removes the rules with the rest of the tooling
15
+ * — processes already drawn keep rendering, they simply stop being checked
16
+ * (`docs/adr/0009`).
17
+ *
18
+ * ## Every rule is read off the SPEC, and cites where
19
+ *
20
+ * The page references below are to **BPMN 2.0.2 (OMG / ISO-IEC 19510)**, which
21
+ * the PO supplied. They are not decoration: three rules in the first draft of
22
+ * this pack fired on diagrams the specification explicitly sanctions, and the
23
+ * only thing that caught them was reading the normative text rather than the
24
+ * folklore.
25
+ *
26
+ * ## And every rule now DECLARES where its authority comes from
27
+ *
28
+ * The citations above used to live in these comments alone, which meant the UI
29
+ * could not tell a conformance defect from a house style: a Labre convention
30
+ * presented to an architect as a norm violation is the finding an external
31
+ * review will not forgive. {@link ValidationRule.provenance} promotes the
32
+ * distinction to data — `standard` for a normative MUST with its page,
33
+ * `recommendation` for a SHOULD or an industry linter, `labre-convention` for
34
+ * ours — and the violation bubble says which.
35
+ *
36
+ * Two rules here are `labre-convention` and neither pretends otherwise:
37
+ * {@link sequenceFlowSelfLoop} and {@link untypedFlow}. The first exists as a
38
+ * separate rule BECAUSE of this field: it was a clause of B1, whose matrix is
39
+ * p.95, and one rule cannot honestly declare two provenances — see B1a.
40
+ *
41
+ * ## Why BPMN is the framework that needed five families
42
+ *
43
+ * A Wardley map is judged element by element: where a thing sits, which way an
44
+ * arrow points. A process is judged by its JOINTS. Every question below is about
45
+ * a relation, a count of relations, the frames two ends sit in, or the graph the
46
+ * relations build — which is why four of the five families arrived with the
47
+ * engine work that preceded this file, and why none of them names BPMN.
48
+ *
49
+ * - `relation-endpoints` (B1–B5) — WHAT a link may run between, and how many
50
+ * times. The grammar.
51
+ * - `edge-degree` (B6–B10, B16–B19) — HOW MANY links arrive at and leave one
52
+ * symbol. The half no per-link rule can express: nothing is wrong with any
53
+ * single arrow, the mistake is the count.
54
+ * - `edge-locality` (B11–B12) — WHICH POOL each end sits in. The swimlane
55
+ * question, and the one where the two ends carry identical roles in the legal
56
+ * case and the illegal one.
57
+ * - `role-count` (B14–B15, B20) — what one pool must CONTAIN, and only when it
58
+ * already contains the other half of the pair.
59
+ * - `reachability` (B13) — can you get there from the start. The graph question.
60
+ * - `label-presence` (B21) — does the symbol carry a name at all.
61
+ *
62
+ * ## The industry linters, and where we deliberately differ
63
+ *
64
+ * The inventory was triangulated against **bpmnlint** (the bpmn-js ecosystem's
65
+ * linter, the one a BPMN practitioner will already have met),
66
+ * bpmn-visualization-js and JointJS. Where a bpmnlint rule reads the same
67
+ * normative sentence we do, the id and the wording are chosen so a user
68
+ * recognises it; where we are quieter, the rule comment says why in its own
69
+ * paragraph. Two of theirs are NOT adopted:
70
+ *
71
+ * - **`no-implicit-start`** (ERROR there). It contradicts p.238: a Process is not
72
+ * required to contain a Start Event, and a flow object with no incoming
73
+ * sequence flow is then a legitimate parallel start (p.245). We sided with the
74
+ * specification — that decision is what
75
+ * {@link ReachabilityDef.implicitRoots} implements, and adopting the
76
+ * linter's rule would have meant shipping the two in contradiction.
77
+ * - **any overlap / readability rule.** The engine's pair-wise budget is pinned
78
+ * by the Wardley bench, which asserts that `wardley.overlapping-artefacts` is
79
+ * the ONLY registered `no-overlap` rule — a second one triggers the
80
+ * spatial-index obligation. That is a piece of engine work with its own
81
+ * measurements, not a line of data, so it is a backlog item and not this file.
82
+ *
83
+ * ## Severity: `warning` almost everywhere, `audit` where the spec allows the
84
+ * shape, and `blocking-overridable` nowhere
85
+ *
86
+ * The same promise `wardley/rules.ts:30` makes, for the same reason: NOTHING
87
+ * downstream implements a blocking level — no gesture is refused anywhere in
88
+ * this library — so shipping the value would be data claiming an effect that
89
+ * does not exist. Several of these are normative MUSTs and would sit there; they
90
+ * move in one line each, in `profiles.ts`, the day the gesture refusal lands.
91
+ *
92
+ * Five rules are declared `audit` on their own — `bpmn.activity-dead-end`,
93
+ * `bpmn.fake-join`, `bpmn.implicit-split`, `bpmn.single-blank-start` and
94
+ * `bpmn.unlabeled-step` — because in each case the specification sanctions the
95
+ * shape they report, or the diagram is merely unfinished. They are NUANCES for
96
+ * the conformance panel, never warnings on the canvas, and every one of them is
97
+ * quieter than the corresponding bpmnlint level on purpose.
98
+ *
99
+ * The severities declared here are the DESCRIPTIVE posture; `bpmn.sketch` — the
100
+ * default — demotes every one of them to `audit`, so the drawing hand is never
101
+ * argued with until someone asks for the stricter profile. See `profiles.ts`.
102
+ *
103
+ * ## What the whole file stays silent about
104
+ *
105
+ * A process drawn before the roles existed carries no role on anything, so it is
106
+ * never evaluated and never says a word (PRD principle 8). A process drawn
107
+ * before anybody added a pool has no frame for B11–B15 and B20 to be about, and those
108
+ * six are silent by construction.
109
+ *
110
+ * ## One thing the `relation-endpoints` family cannot say
111
+ *
112
+ * The ALPHABET of a `relation-endpoints` rule is derived from the roles its
113
+ * sanctioned triplets name. That is what makes the family proportionate — an end
114
+ * outside the alphabet takes the whole link out of the conversation, so a flow
115
+ * drawn onto a sticky note is a draft and not a finding — and it is also its one
116
+ * limit: **a framework cannot name a role it wants to REJECT without sanctioning
117
+ * a sentence for it.**
118
+ *
119
+ * Three normative prohibitions are therefore SILENCE rather than findings today:
120
+ *
121
+ * - "an Artifact MUST NOT be the source or target of a Sequence Flow" (p.65) and
122
+ * "a Sequence Flow connects Events, Activities and Gateways" (p.95) — a
123
+ * sequence flow dropped on a text annotation or a data object goes unjudged;
124
+ * - the Message Flow Connection Rules table (p.41–42), which lists what a
125
+ * message may run between and then says "Thus, Lane, Gateway, Data Object,
126
+ * Group, and Text Annotation are not listed in the table" — a gateway is
127
+ * named by no message sentence, so it is outside B2's alphabet.
128
+ *
129
+ * Reported to the engine author rather than worked around here: a triplet
130
+ * written to widen an alphabet without meaning what it says would be exactly the
131
+ * data-that-lies this platform refuses everywhere else. The corpus pins the
132
+ * silence explicitly (`corpus.unit.spec.ts`), so it stays a known limit rather
133
+ * than an assumption.
134
+ *
135
+ * ## The engine fields this pack asked for, and now uses
136
+ *
137
+ * Six of the rules below were authored against defs that did not exist when they
138
+ * were written, and `claude/bpmn-engine-v2` (#145) landed all six:
139
+ * `RoleCountDef.ifPresent` and `.exact`, `EdgeDegreeDef.forbidPattern` and
140
+ * `.eitherMin`, `ReachabilityDef.implicitRoots`, and the `label-presence`
141
+ * family. Every one of the rules below is registered and live.
142
+ *
143
+ * Two of them are worth knowing about at the call site:
144
+ *
145
+ * - `forbidPattern` carries its OWN {@link RuleMessage} inside the pattern
146
+ * rather than in a slot beside the other bounds, because a forbidden zone is
147
+ * not a bound that failed and its sentence never reads like one;
148
+ * - `label-presence` reads the subject's OWN `text`. A framework whose artefacts
149
+ * are named by a separate element beside them is asking a different question,
150
+ * and this family cannot answer it. BPMN names its steps in place, so it can.
151
+ */
152
+ /**
153
+ * `eitherMin` was also shipped, and this pack deliberately does not use it.
154
+ *
155
+ * It and `forbidPattern: { maxIn: 1, maxOut: 1 }` select exactly the same set of
156
+ * nodes — the engine ships a test asserting they agree across the whole degree
157
+ * space — so {@link gatewayMustBranch} could be written either way. It is
158
+ * written as a forbidden zone because that is what its SENTENCE says: "this
159
+ * gateway neither splits nor merges" describes a shape the diagram has, not a
160
+ * count it is missing, and the data reads best when it says what the message
161
+ * says. Nothing is wrong with the other reading; a rule simply has to pick one.
162
+ */
163
+ /**
164
+ * The one sanctioned sentence of a sequence flow: a flow object is followed by a
165
+ * flow object (p.95 — "a Sequence Flow connects Events, Activities and
166
+ * Gateways").
167
+ *
168
+ * Written on `bpmn:flow-object` rather than on the three families under it, which
169
+ * is what makes it ONE triplet instead of nine: `roleIsA` resolves it for every
170
+ * event, activity and gateway, and for whatever the descriptive profile adds
171
+ * under them later.
172
+ *
173
+ * Exported so a test asserts THIS table rather than a copy of it, and so B4
174
+ * declares the same alphabet it judges neutral links against without restating
175
+ * it — see {@link untypedFlow}.
176
+ */
177
+ export declare const BPMN_SEQUENCE_MATRIX: readonly EndpointTriplet[];
178
+ /**
179
+ * The pack, whole: twenty-two rules, all registered, all live.
180
+ *
181
+ * Eight of them were authored ahead of the engine and sat in a held-out array
182
+ * for one review cycle, because two would have been actively WRONG meanwhile —
183
+ * an engine with no `ifPresent` reads B14/B15 as the unconditional "every pool
184
+ * holds a start event" the specification review removed, which fires on a
185
+ * conformant black-box pool. `claude/bpmn-engine-v2` (#145) landed every field
186
+ * they asked for, so the array is gone and the split with it.
187
+ *
188
+ * The twenty-second is B1a, and it is not a new REQUIREMENT: the no-self-loop
189
+ * clause left B1 so that each of the two could declare its own provenance
190
+ * honestly. Nothing new fires, nothing new is said, and the two i18n keys are
191
+ * the ones the clause already shipped.
192
+ *
193
+ * Every one of the twenty-two declares {@link ValidationRule.provenance}:
194
+ * twelve `standard`, each with its page; eight `recommendation`, each naming a
195
+ * linter or the sentence the specification merely permits; two
196
+ * `labre-convention`. Nothing here is `organization` — that source is reserved
197
+ * for the org profiles the PRD names, and no framework declares one yet.
198
+ */
199
+ export declare const BPMN_RULES: readonly ValidationRule[];