libpetri 1.8.5 → 2.1.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 (46) hide show
  1. package/README.md +47 -0
  2. package/dist/{chunk-B2D5DMTO.js → chunk-B2CV5M3L.js} +228 -9
  3. package/dist/chunk-B2CV5M3L.js.map +1 -0
  4. package/dist/chunk-H62Z76FY.js +1346 -0
  5. package/dist/chunk-H62Z76FY.js.map +1 -0
  6. package/dist/chunk-RNWTYK5B.js +419 -0
  7. package/dist/chunk-RNWTYK5B.js.map +1 -0
  8. package/dist/chunk-SXK2Z45Z.js +50 -0
  9. package/dist/chunk-SXK2Z45Z.js.map +1 -0
  10. package/dist/debug/index.d.ts +50 -3
  11. package/dist/debug/index.js +64 -6
  12. package/dist/debug/index.js.map +1 -1
  13. package/dist/doclet/index.d.ts +152 -31
  14. package/dist/doclet/index.js +458 -57
  15. package/dist/doclet/index.js.map +1 -1
  16. package/dist/doclet/resources/petrinet-diagrams.css +640 -7
  17. package/dist/doclet/resources/petrinet-diagrams.js +7238 -114
  18. package/dist/dot-exporter-WJMCJEFK.js +8 -0
  19. package/dist/{event-store-BnyHh3TF.d.ts → event-store-2zkXeQkd.d.ts} +1 -1
  20. package/dist/export/index.d.ts +18 -4
  21. package/dist/export/index.js +1 -1
  22. package/dist/index.d.ts +41 -5
  23. package/dist/index.js +1221 -35
  24. package/dist/index.js.map +1 -1
  25. package/dist/petri-net-BDrj4XZE.d.ts +1461 -0
  26. package/dist/render-QK57X4TP.js +73 -0
  27. package/dist/render-QK57X4TP.js.map +1 -0
  28. package/dist/verification/index.d.ts +3 -144
  29. package/dist/verification/index.js +30 -1214
  30. package/dist/verification/index.js.map +1 -1
  31. package/dist/viewer/index.d.ts +227 -0
  32. package/dist/viewer/index.js +877 -0
  33. package/dist/viewer/index.js.map +1 -0
  34. package/dist/viewer/layout/index.d.ts +200 -0
  35. package/dist/viewer/layout/index.js +15 -0
  36. package/dist/viewer/layout/index.js.map +1 -0
  37. package/dist/viewer/viewer-static.iife.js +3 -0
  38. package/dist/viewer/viewer.css +759 -0
  39. package/dist/viewer/viewer.iife.js +7243 -0
  40. package/package.json +28 -8
  41. package/dist/chunk-B2D5DMTO.js.map +0 -1
  42. package/dist/chunk-VQ4XMJTD.js +0 -107
  43. package/dist/chunk-VQ4XMJTD.js.map +0 -1
  44. package/dist/dot-exporter-3CVCH6J4.js +0 -8
  45. package/dist/petri-net-D-GN9g_D.d.ts +0 -570
  46. /package/dist/{dot-exporter-3CVCH6J4.js.map → dot-exporter-WJMCJEFK.js.map} +0 -0
@@ -0,0 +1,1461 @@
1
+ /**
2
+ * An immutable token carrying a typed value through the Petri net.
3
+ *
4
+ * Tokens flow from place to place as transitions fire, carrying typed
5
+ * payloads that represent the state of a computation or workflow.
6
+ */
7
+ interface Token<T> {
8
+ readonly value: T;
9
+ /** Epoch milliseconds when the token was created. */
10
+ readonly createdAt: number;
11
+ /**
12
+ * JSON-friendly projection of the token value, populated by
13
+ * {@link SessionArchiveReader} when hydrating a v3 archive so replay
14
+ * consumers see the same structured shape the writer emitted. Live tokens
15
+ * (produced by {@link tokenOf} / {@link tokenAt}) leave this `undefined`;
16
+ * the runtime ignores it. See [EVT-025](../../../spec/08-events-observability.md)
17
+ * AC5. (libpetri 1.8.0+)
18
+ */
19
+ readonly structured?: unknown;
20
+ }
21
+ /** Creates a token with the given value and current timestamp. */
22
+ declare function tokenOf<T>(value: T): Token<T>;
23
+ /**
24
+ * Returns a unit token (marker with no meaningful value).
25
+ * Used for pure control flow where presence matters but data doesn't.
26
+ * Returns a cached singleton whose `value` is `null`.
27
+ */
28
+ declare function unitToken(): Token<null>;
29
+ /** Creates a token with a specific timestamp (for testing/replay). */
30
+ declare function tokenAt<T>(value: T, createdAt: number): Token<T>;
31
+ /** Checks if this is the singleton unit token. */
32
+ declare function isUnit(token: Token<unknown>): boolean;
33
+
34
+ /**
35
+ * A typed place in the Petri Net that holds tokens of a specific type.
36
+ *
37
+ * Places are the "state containers" of a Petri net. They hold tokens that
38
+ * represent data or resources flowing through the net.
39
+ *
40
+ * Places use name-based equality (matching Java record semantics).
41
+ * Internally use `Map<string, ...>` keyed by `place.name` for O(1) lookups.
42
+ */
43
+ interface Place<T> {
44
+ readonly name: string;
45
+ /** Phantom field to carry the type parameter. Never set at runtime. */
46
+ readonly _phantom?: T;
47
+ }
48
+ /**
49
+ * An environment place that accepts external token injection.
50
+ * Wraps a regular Place and marks it for external event injection.
51
+ */
52
+ interface EnvironmentPlace<T> {
53
+ readonly place: Place<T>;
54
+ }
55
+ /** Creates a typed place. */
56
+ declare function place<T>(name: string): Place<T>;
57
+ /** Creates an environment place (external event injection point). */
58
+ declare function environmentPlace<T>(name: string): EnvironmentPlace<T>;
59
+
60
+ /**
61
+ * Arc types connecting places to transitions in the Petri net.
62
+ *
63
+ * | Arc Type | Requires Token? | Consumes? | Effect |
64
+ * |-----------|-----------------|-----------|--------------------------|
65
+ * | Input | Yes | Yes | Token consumed on fire |
66
+ * | Output | No | No | Token produced on complete|
67
+ * | Inhibitor | No (blocks) | No | Disables transition |
68
+ * | Read | Yes | No | Token remains |
69
+ * | Reset | No | Yes (all) | All tokens removed |
70
+ */
71
+ type Arc = ArcInput | ArcOutput | ArcInhibitor | ArcRead | ArcReset;
72
+ interface ArcInput<T = any> {
73
+ readonly type: 'input';
74
+ readonly place: Place<T>;
75
+ readonly guard?: (value: T) => boolean;
76
+ }
77
+ interface ArcOutput<T = any> {
78
+ readonly type: 'output';
79
+ readonly place: Place<T>;
80
+ }
81
+ interface ArcInhibitor<T = any> {
82
+ readonly type: 'inhibitor';
83
+ readonly place: Place<T>;
84
+ }
85
+ interface ArcRead<T = any> {
86
+ readonly type: 'read';
87
+ readonly place: Place<T>;
88
+ }
89
+ interface ArcReset<T = any> {
90
+ readonly type: 'reset';
91
+ readonly place: Place<T>;
92
+ }
93
+ /** Input arc: consumes token from place when transition fires. */
94
+ declare function inputArc<T>(place: Place<T>, guard?: (value: T) => boolean): ArcInput<T>;
95
+ /** Output arc: produces token to place when transition fires. */
96
+ declare function outputArc<T>(place: Place<T>): ArcOutput<T>;
97
+ /** Inhibitor arc: blocks transition if place has tokens. */
98
+ declare function inhibitorArc<T>(place: Place<T>): ArcInhibitor<T>;
99
+ /** Read arc: requires token without consuming. */
100
+ declare function readArc<T>(place: Place<T>): ArcRead<T>;
101
+ /** Reset arc: removes all tokens from place when firing. */
102
+ declare function resetArc<T>(place: Place<T>): ArcReset<T>;
103
+ /** Returns the place this arc connects to. */
104
+ declare function arcPlace(arc: Arc): Place<any>;
105
+ /** Checks if an input arc has a guard predicate. */
106
+ declare function hasGuard(arc: ArcInput): boolean;
107
+ /** Checks if a token value matches an input arc's guard. */
108
+ declare function matchesGuard<T>(arc: ArcInput<T>, value: T): boolean;
109
+
110
+ /**
111
+ * Input specification with cardinality and optional guard predicate.
112
+ * CPN-compliant: cardinality determines how many tokens to consume,
113
+ * guard filters which tokens are eligible.
114
+ *
115
+ * Inputs are always AND-joined (all must be satisfied to enable transition).
116
+ * XOR on inputs is modeled via multiple transitions (conflict).
117
+ */
118
+ type In = InOne | InExactly | InAll | InAtLeast;
119
+ interface InOne<T = any> {
120
+ readonly type: 'one';
121
+ readonly place: Place<T>;
122
+ readonly guard?: (value: T) => boolean;
123
+ }
124
+ interface InExactly<T = any> {
125
+ readonly type: 'exactly';
126
+ readonly place: Place<T>;
127
+ readonly count: number;
128
+ readonly guard?: (value: T) => boolean;
129
+ }
130
+ interface InAll<T = any> {
131
+ readonly type: 'all';
132
+ readonly place: Place<T>;
133
+ readonly guard?: (value: T) => boolean;
134
+ }
135
+ interface InAtLeast<T = any> {
136
+ readonly type: 'at-least';
137
+ readonly place: Place<T>;
138
+ readonly minimum: number;
139
+ readonly guard?: (value: T) => boolean;
140
+ }
141
+ /** Consume exactly 1 token (standard CPN semantics). Optional guard filters eligible tokens. */
142
+ declare function one<T>(place: Place<T>, guard?: (value: T) => boolean): InOne<T>;
143
+ /** Consume exactly N tokens (batching). Optional guard filters eligible tokens. */
144
+ declare function exactly<T>(count: number, place: Place<T>, guard?: (value: T) => boolean): InExactly<T>;
145
+ /** Consume all available tokens (must be 1+). Optional guard filters eligible tokens. */
146
+ declare function all<T>(place: Place<T>, guard?: (value: T) => boolean): InAll<T>;
147
+ /** Wait for N+ tokens, consume all when enabled. Optional guard filters eligible tokens. */
148
+ declare function atLeast<T>(minimum: number, place: Place<T>, guard?: (value: T) => boolean): InAtLeast<T>;
149
+ /** Returns the minimum number of tokens required to enable. */
150
+ declare function requiredCount(spec: In): number;
151
+ /**
152
+ * Returns the actual number of tokens to consume given the available count.
153
+ * - One: always consumes 1
154
+ * - Exactly: always consumes exactly count
155
+ * - All: consumes all available
156
+ * - AtLeast: consumes all available (when enabled, i.e., >= minimum)
157
+ */
158
+ declare function consumptionCount(spec: In, available: number): number;
159
+
160
+ /**
161
+ * Output specification with explicit split semantics.
162
+ * Supports composite structures (XOR of ANDs, AND of XORs, etc.)
163
+ *
164
+ * - And: ALL children must receive tokens
165
+ * - Xor: EXACTLY ONE child receives token
166
+ * - Place: Leaf node representing a single output place
167
+ * - Timeout: Timeout branch that activates if action exceeds duration
168
+ * - ForwardInput: Forward consumed input to output on timeout
169
+ */
170
+ type Out = OutAnd | OutXor | OutPlace | OutTimeout | OutForwardInput;
171
+ interface OutAnd {
172
+ readonly type: 'and';
173
+ readonly children: readonly Out[];
174
+ }
175
+ interface OutXor {
176
+ readonly type: 'xor';
177
+ readonly children: readonly Out[];
178
+ }
179
+ interface OutPlace {
180
+ readonly type: 'place';
181
+ readonly place: Place<any>;
182
+ }
183
+ interface OutTimeout {
184
+ readonly type: 'timeout';
185
+ /** Timeout duration in milliseconds. */
186
+ readonly afterMs: number;
187
+ readonly child: Out;
188
+ }
189
+ interface OutForwardInput {
190
+ readonly type: 'forward-input';
191
+ readonly from: Place<any>;
192
+ readonly to: Place<any>;
193
+ }
194
+ /**
195
+ * AND-split: all children must receive tokens.
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * // AND of XOR branches: one of (A,B) AND one of (C,D)
200
+ * and(xorPlaces(placeA, placeB), xorPlaces(placeC, placeD))
201
+ *
202
+ * // AND with a fixed place + XOR branch
203
+ * and(outPlace(always), xorPlaces(left, right))
204
+ * ```
205
+ */
206
+ declare function and(...children: Out[]): OutAnd;
207
+ /** AND-split from places: all places must receive tokens. */
208
+ declare function andPlaces(...places: Place<any>[]): OutAnd;
209
+ /** XOR-split: exactly one child receives token. */
210
+ declare function xor(...children: Out[]): OutXor;
211
+ /** XOR-split from places: exactly one place receives token. */
212
+ declare function xorPlaces(...places: Place<any>[]): OutXor;
213
+ /** Leaf output spec for a single place. */
214
+ declare function outPlace(p: Place<any>): OutPlace;
215
+ /** Timeout output: activates if action exceeds duration. */
216
+ declare function timeout(afterMs: number, child: Out): OutTimeout;
217
+ /** Timeout output pointing to a single place. */
218
+ declare function timeoutPlace(afterMs: number, p: Place<any>): OutTimeout;
219
+ /** Forward consumed input value to output place on timeout. */
220
+ declare function forwardInput(from: Place<any>, to: Place<any>): OutForwardInput;
221
+ /** Collects all leaf places from this output spec (flattened). */
222
+ declare function allPlaces(out: Out): Set<Place<any>>;
223
+ /**
224
+ * Enumerates all possible output branches for structural analysis.
225
+ *
226
+ * - AND = single branch containing all child places (Cartesian product)
227
+ * - XOR = one branch per alternative child
228
+ * - Nested = Cartesian product for AND, union for XOR
229
+ */
230
+ declare function enumerateBranches(out: Out): ReadonlyArray<ReadonlySet<Place<any>>>;
231
+
232
+ /**
233
+ * Firing timing specification for transitions.
234
+ *
235
+ * Based on classical Time Petri Net (TPN) semantics:
236
+ * - Transition CANNOT fire before earliest time (lower bound)
237
+ * - Transition MUST fire by deadline OR become disabled (upper bound)
238
+ *
239
+ * All durations are in milliseconds.
240
+ */
241
+ type Timing = TimingImmediate | TimingDeadline | TimingDelayed | TimingWindow | TimingExact;
242
+ interface TimingImmediate {
243
+ readonly type: 'immediate';
244
+ }
245
+ interface TimingDeadline {
246
+ readonly type: 'deadline';
247
+ /** Deadline in milliseconds. Must be positive. */
248
+ readonly byMs: number;
249
+ }
250
+ interface TimingDelayed {
251
+ readonly type: 'delayed';
252
+ /** Minimum delay in milliseconds. Must be non-negative. */
253
+ readonly afterMs: number;
254
+ }
255
+ interface TimingWindow {
256
+ readonly type: 'window';
257
+ /** Earliest firing time in milliseconds. Must be non-negative. */
258
+ readonly earliestMs: number;
259
+ /** Latest firing time in milliseconds. Must be >= earliestMs. */
260
+ readonly latestMs: number;
261
+ }
262
+ interface TimingExact {
263
+ readonly type: 'exact';
264
+ /** Exact firing time in milliseconds. Must be non-negative. */
265
+ readonly atMs: number;
266
+ }
267
+ /** ~100 years in milliseconds, used for "unconstrained" intervals. */
268
+ declare const MAX_DURATION_MS: number;
269
+ /** Immediate firing: can fire as soon as enabled, no deadline. [0, inf) */
270
+ declare function immediate(): TimingImmediate;
271
+ /** Immediate with deadline: can fire immediately, must fire by deadline. [0, by] */
272
+ declare function deadline(byMs: number): TimingDeadline;
273
+ /** Delayed firing: must wait, then can fire anytime. [after, inf) */
274
+ declare function delayed(afterMs: number): TimingDelayed;
275
+ /** Time window: can fire within [earliest, latest]. */
276
+ declare function window(earliestMs: number, latestMs: number): TimingWindow;
277
+ /** Exact timing: fires at precisely the specified time. [at, at] */
278
+ declare function exact(atMs: number): TimingExact;
279
+ /** Returns the earliest time (ms) the transition can fire after enabling. */
280
+ declare function earliest(timing: Timing): number;
281
+ /** Returns the latest time (ms) by which the transition must fire. */
282
+ declare function latest(timing: Timing): number;
283
+ /** Returns true if this timing has a finite deadline. */
284
+ declare function hasDeadline(timing: Timing): boolean;
285
+
286
+ /**
287
+ * Consumed input tokens bound to their source places.
288
+ *
289
+ * Passed to TransitionAction as the `input` parameter, providing
290
+ * type-safe read access to tokens consumed from input places.
291
+ */
292
+ declare class TokenInput {
293
+ private readonly tokens;
294
+ /** Add a token (used by executor when firing transition). */
295
+ add<T>(place: Place<T>, token: Token<T>): this;
296
+ /** Get all tokens for a place. */
297
+ getAll<T>(place: Place<T>): readonly Token<T>[];
298
+ /** Get the first token for a place. Throws if no tokens. */
299
+ get<T>(place: Place<T>): Token<T>;
300
+ /** Get the first token's value for a place. Throws if no tokens. */
301
+ value<T>(place: Place<T>): T;
302
+ /** Get all token values for a place. */
303
+ values<T>(place: Place<T>): readonly T[];
304
+ /** Get token count for a place. */
305
+ count(place: Place<any>): number;
306
+ /** Check if any tokens exist for a place. */
307
+ has(place: Place<any>): boolean;
308
+ }
309
+
310
+ /**
311
+ * An output entry: place + token pair.
312
+ */
313
+ interface OutputEntry {
314
+ readonly place: Place<any>;
315
+ readonly token: Token<any>;
316
+ }
317
+ /**
318
+ * Collects output tokens produced by a transition action.
319
+ */
320
+ declare class TokenOutput {
321
+ private readonly _entries;
322
+ /** Add a value to an output place (creates token with current timestamp). */
323
+ add<T>(place: Place<T>, value: T): this;
324
+ /** Add a pre-existing token to an output place. */
325
+ addToken<T>(place: Place<T>, token: Token<T>): this;
326
+ /** Returns all collected outputs. */
327
+ entries(): readonly OutputEntry[];
328
+ /** Check if any outputs were produced. */
329
+ isEmpty(): boolean;
330
+ /** Returns the set of place names that received tokens. */
331
+ placesWithTokens(): Set<string>;
332
+ }
333
+
334
+ /** Callback for emitting log messages from transition actions. */
335
+ type LogFn = (level: string, message: string, error?: Error) => void;
336
+ /**
337
+ * Context provided to transition actions.
338
+ *
339
+ * Provides filtered access based on structure:
340
+ * - Input places (consumed tokens)
341
+ * - Read places (context tokens, not consumed)
342
+ * - Output places (where to produce tokens)
343
+ *
344
+ * Enforces the structure contract — actions can only access places
345
+ * declared in the transition's structure.
346
+ */
347
+ declare class TransitionContext {
348
+ private readonly rawInput;
349
+ private readonly _rawOutput;
350
+ private readonly allowedInputs;
351
+ private readonly allowedReads;
352
+ private readonly allowedOutputs;
353
+ private readonly _inputPlaces;
354
+ private readonly _readPlaces;
355
+ private readonly _outputPlaces;
356
+ private readonly _transitionName;
357
+ private readonly executionCtx;
358
+ private readonly _logFn?;
359
+ constructor(transitionName: string, rawInput: TokenInput, rawOutput: TokenOutput, inputPlaces: ReadonlySet<Place<any>>, readPlaces: ReadonlySet<Place<any>>, outputPlaces: ReadonlySet<Place<any>>, executionContext?: Map<string, unknown>, logFn?: LogFn);
360
+ /** Get single consumed input value. Throws if place not declared or multiple tokens. */
361
+ input<T>(place: Place<T>): T;
362
+ /** Get all consumed input values for a place. */
363
+ inputs<T>(place: Place<T>): readonly T[];
364
+ /** Get consumed input token with metadata. */
365
+ inputToken<T>(place: Place<T>): Token<T>;
366
+ /** Returns declared input places (consumed). */
367
+ inputPlaces(): ReadonlySet<Place<any>>;
368
+ private requireInput;
369
+ /** Get read-only context value. Throws if place not declared as read. */
370
+ read<T>(place: Place<T>): T;
371
+ /** Get all read-only context values for a place. */
372
+ reads<T>(place: Place<T>): readonly T[];
373
+ /** Returns declared read places (context, not consumed). */
374
+ readPlaces(): ReadonlySet<Place<any>>;
375
+ private requireRead;
376
+ /**
377
+ * Add one or more output values to the same place in a single call.
378
+ *
379
+ * Validates the place once, then appends each value to the output
380
+ * collector. Calling with zero values is a no-op.
381
+ *
382
+ * @example
383
+ * ctx.output(outPlace, 'a', 'b', 'c');
384
+ * ctx.output(outPlace, ...someArray);
385
+ *
386
+ * @throws if place not declared as output.
387
+ */
388
+ output<T>(place: Place<T>, ...values: T[]): this;
389
+ /**
390
+ * Add one or more pre-built output tokens to the same place in a single call.
391
+ *
392
+ * Validates the place once, then appends each token. Calling with zero
393
+ * tokens is a no-op.
394
+ *
395
+ * @throws if place not declared as output.
396
+ */
397
+ outputToken<T>(place: Place<T>, ...tokens: Token<T>[]): this;
398
+ /** Returns declared output places. */
399
+ outputPlaces(): ReadonlySet<Place<any>>;
400
+ private requireOutput;
401
+ /** Returns the transition name. */
402
+ transitionName(): string;
403
+ /** Retrieves an execution context object by key. */
404
+ executionContext<T>(key: string): T | undefined;
405
+ /** Checks if an execution context object of the given key is present. */
406
+ hasExecutionContext(key: string): boolean;
407
+ /** Emits a structured log message into the event store. */
408
+ log(level: string, message: string, error?: Error): void;
409
+ /** @internal Used by BitmapNetExecutor to collect outputs after action completion. */
410
+ rawOutput(): TokenOutput;
411
+ }
412
+
413
+ /**
414
+ * The action executed when a transition fires.
415
+ * Receives a TransitionContext providing filtered I/O and structure access.
416
+ */
417
+ type TransitionAction = (ctx: TransitionContext) => Promise<void>;
418
+ /**
419
+ * Identity action: produces no outputs.
420
+ *
421
+ * Returns a stable singleton reference (cached on first call). Reference
422
+ * stability is relied on by {@link import('./internal/subnet-rewriter.js')
423
+ * .composeActions} during channel composition (MOD-021) to short-circuit a
424
+ * passthrough-on-both-sides merge to passthrough — saving a microtask hop
425
+ * and matching the Java implementation's behaviour where both transitions'
426
+ * default actions collapse to the builder's own passthrough default.
427
+ */
428
+ declare function passthrough(): TransitionAction;
429
+ /**
430
+ * Transform action: applies function to context, copies result to ALL output places.
431
+ *
432
+ * @example
433
+ * ```ts
434
+ * const action = transform(ctx => ctx.input(inputPlace).toUpperCase());
435
+ * // Result is copied to every declared output place
436
+ * ```
437
+ */
438
+ declare function transform(fn: (ctx: TransitionContext) => unknown): TransitionAction;
439
+ /**
440
+ * Fork action: copies single input token to all outputs.
441
+ * Requires exactly one input place (derived from structure).
442
+ */
443
+ declare function fork(): TransitionAction;
444
+ /**
445
+ * Transform with explicit input place.
446
+ */
447
+ declare function transformFrom<I>(inputPlace: Place<I>, fn: (value: I) => unknown): TransitionAction;
448
+ /**
449
+ * Async transform: applies async function, copies result to all outputs.
450
+ */
451
+ declare function transformAsync(fn: (ctx: TransitionContext) => Promise<unknown>): TransitionAction;
452
+ /** Produce action: produces a single token with the given value to the specified place. */
453
+ declare function produce<T>(place: Place<T>, value: T): TransitionAction;
454
+ /**
455
+ * Wraps an action with timeout handling.
456
+ * If the action completes within the timeout, normal completion.
457
+ * If the timeout expires, the timeoutValue is produced to the timeoutPlace.
458
+ *
459
+ * @example
460
+ * ```ts
461
+ * const action = withTimeout(
462
+ * async (ctx) => { ctx.output(resultPlace, await fetchData()); },
463
+ * 5000,
464
+ * timeoutPlace,
465
+ * 'timed-out',
466
+ * );
467
+ * ```
468
+ */
469
+ declare function withTimeout<T>(action: TransitionAction, timeoutMs: number, timeoutPlace: Place<T>, timeoutValue: T): TransitionAction;
470
+
471
+ /**
472
+ * A transition in the Time Petri Net that transforms tokens.
473
+ *
474
+ * Transitions use identity-based equality (===) — each instance is unique
475
+ * regardless of name. The name is purely a label for display/debugging/export.
476
+ */
477
+ declare class Transition {
478
+ readonly name: string;
479
+ readonly inputSpecs: readonly In[];
480
+ readonly outputSpec: Out | null;
481
+ readonly inhibitors: readonly ArcInhibitor[];
482
+ readonly reads: readonly ArcRead[];
483
+ readonly resets: readonly ArcReset[];
484
+ readonly timing: Timing;
485
+ readonly actionTimeout: OutTimeout | null;
486
+ readonly action: TransitionAction;
487
+ readonly priority: number;
488
+ private readonly _inputPlaces;
489
+ private readonly _readPlaces;
490
+ private readonly _outputPlaces;
491
+ /** @internal Use {@link Transition.builder} to create instances. */
492
+ constructor(key: symbol, name: string, inputSpecs: readonly In[], outputSpec: Out | null, inhibitors: readonly ArcInhibitor[], reads: readonly ArcRead[], resets: readonly ArcReset[], timing: Timing, action: TransitionAction, priority: number);
493
+ /** Returns set of input places — consumed tokens. */
494
+ inputPlaces(): ReadonlySet<Place<any>>;
495
+ /** Returns set of read places — context tokens, not consumed. */
496
+ readPlaces(): ReadonlySet<Place<any>>;
497
+ /** Returns set of output places — where tokens are produced. */
498
+ outputPlaces(): ReadonlySet<Place<any>>;
499
+ /** Returns true if this transition has an action timeout. */
500
+ hasActionTimeout(): boolean;
501
+ toString(): string;
502
+ static builder(name: string): TransitionBuilder;
503
+ }
504
+ declare class TransitionBuilder {
505
+ private readonly _name;
506
+ private readonly _inputSpecs;
507
+ private _outputSpec;
508
+ private readonly _inhibitors;
509
+ private readonly _reads;
510
+ private readonly _resets;
511
+ private _timing;
512
+ private _action;
513
+ private _priority;
514
+ constructor(name: string);
515
+ /** Add input specifications with cardinality. */
516
+ inputs(...specs: In[]): this;
517
+ /** Set the output specification (composite AND/XOR structure). */
518
+ outputs(spec: Out): this;
519
+ /** Add inhibitor arc. */
520
+ inhibitor(place: Place<any>): this;
521
+ /** Add inhibitor arcs. */
522
+ inhibitors(...places: Place<any>[]): this;
523
+ /** Add read arc. */
524
+ read(place: Place<any>): this;
525
+ /** Add read arcs. */
526
+ reads(...places: Place<any>[]): this;
527
+ /** Add reset arc. */
528
+ reset(place: Place<any>): this;
529
+ /** Add reset arcs. */
530
+ resets(...places: Place<any>[]): this;
531
+ /** Set timing specification. */
532
+ timing(timing: Timing): this;
533
+ /** Set the transition action. */
534
+ action(action: TransitionAction): this;
535
+ /** Set the priority (higher fires first). */
536
+ priority(priority: number): this;
537
+ build(): Transition;
538
+ }
539
+
540
+ /**
541
+ * Advisory direction metadata for an interface place.
542
+ *
543
+ * Per **MOD-004**, direction is metadata only — it does NOT constrain arc flow
544
+ * at runtime. Token movement is governed by arcs declared per CORE-030..CORE-035.
545
+ */
546
+ type PortDirection = 'input' | 'output' | 'inout';
547
+ /**
548
+ * A typed interface place exposed for composition, per **MOD-003**.
549
+ *
550
+ * Direction is advisory metadata only (per **MOD-004**); the underlying
551
+ * `Place<T>` reference is what is rewired at compose time.
552
+ */
553
+ interface Port<T = unknown> {
554
+ /** Port name, unique within the {@link Interface}. */
555
+ readonly name: string;
556
+ /** Direction (advisory). */
557
+ readonly direction: PortDirection;
558
+ /** The body place exposed by this port. */
559
+ readonly place: Place<T>;
560
+ }
561
+ /**
562
+ * An interface transition exposed for synchronous fusion with a caller-side
563
+ * transition, per **MOD-005**.
564
+ *
565
+ * The only present variant in this scaffolding is the synchronous channel.
566
+ * The interface is left structurally open for future channel kinds without
567
+ * breaking existing pattern matches on `name`/`transition`.
568
+ */
569
+ interface Channel {
570
+ /** Channel name, unique within the channel namespace. */
571
+ readonly name: string;
572
+ /** The body transition exposed by this channel. */
573
+ readonly transition: Transition;
574
+ }
575
+ /**
576
+ * Immutable declaration of a subnet's **interface**: the set of {@link Port}
577
+ * (interface places) and {@link Channel} (interface transitions) exposed for
578
+ * composition with an enclosing net.
579
+ *
580
+ * Specified by `spec/11-modular-composition.md` requirements **MOD-003**
581
+ * (port declaration) and **MOD-005** (channel declaration). Validation rules
582
+ * per **MOD-006** are enforced by `SubnetDef.builder()` at subnet build
583
+ * time; this class itself enforces only port/channel name uniqueness within
584
+ * its respective namespaces (used both by `SubnetDef` and by hand-built
585
+ * interfaces fed into `SubnetDef.fromNet`).
586
+ */
587
+ declare class Interface {
588
+ readonly ports: ReadonlyMap<string, Port<unknown>>;
589
+ readonly channels: ReadonlyMap<string, Channel>;
590
+ /** @internal Use {@link Interface.builder} to create instances. */
591
+ constructor(key: symbol, ports: ReadonlyMap<string, Port<unknown>>, channels: ReadonlyMap<string, Channel>);
592
+ /** Looks up a port by name. Returns undefined when absent. */
593
+ port<T = unknown>(name: string): Port<T> | undefined;
594
+ /** Looks up a channel by name. Returns undefined when absent. */
595
+ channel(name: string): Channel | undefined;
596
+ /**
597
+ * Looks up a port by name and returns its underlying place, narrowed to
598
+ * `Place<T>`. Returns undefined when the port does not exist.
599
+ *
600
+ * Note: TypeScript erases generics at runtime, so unlike Java's
601
+ * `portPlaceAs(name, Class<T>)` this method cannot verify the token type at
602
+ * runtime — the caller is trusted to supply the correct `T`. Per **MOD-022**,
603
+ * type compatibility is enforced at compile time only in TypeScript.
604
+ */
605
+ placeAs<T>(name: string): Place<T> | undefined;
606
+ static builder(): InterfaceBuilder;
607
+ }
608
+ declare class InterfaceBuilder {
609
+ private readonly _ports;
610
+ private readonly _channels;
611
+ /** Add a pre-built port (rejects duplicate names). */
612
+ port(port: Port<unknown>): this;
613
+ /** Add an input port (advisory direction). */
614
+ inputPort<T>(name: string, place: Place<T>): this;
615
+ /** Add an output port (advisory direction). */
616
+ outputPort<T>(name: string, place: Place<T>): this;
617
+ /** Add an in-out port (advisory direction). */
618
+ inoutPort<T>(name: string, place: Place<T>): this;
619
+ /** Add a pre-built channel (rejects duplicate names). */
620
+ channel(channel: Channel): this;
621
+ /** Declare a synchronous channel by name + transition (rejects duplicate names). */
622
+ channel(name: string, transition: Transition): this;
623
+ /** @internal Bulk-add ports already validated by the caller. */
624
+ portsAll(ports: Iterable<Port<unknown>>): this;
625
+ /** @internal Bulk-add channels already validated by the caller. */
626
+ channelsAll(channels: Iterable<Channel>): this;
627
+ build(): Interface;
628
+ }
629
+
630
+ /**
631
+ * Safety properties that can be verified via IC3/PDR.
632
+ *
633
+ * Each property is encoded as an error condition: if a reachable state
634
+ * violates the property, Spacer finds a counterexample. If no violation
635
+ * is reachable, the property is proven.
636
+ */
637
+ type SmtProperty = DeadlockFree | MutualExclusion | PlaceBound | Unreachable;
638
+ /** Deadlock-freedom: no reachable marking has all transitions disabled. */
639
+ interface DeadlockFree {
640
+ readonly type: 'deadlock-free';
641
+ }
642
+ /** Mutual exclusion: two places never have tokens simultaneously. */
643
+ interface MutualExclusion {
644
+ readonly type: 'mutual-exclusion';
645
+ readonly p1: Place<any>;
646
+ readonly p2: Place<any>;
647
+ }
648
+ /** Place bound: a place never exceeds a given token count. */
649
+ interface PlaceBound {
650
+ readonly type: 'place-bound';
651
+ readonly place: Place<any>;
652
+ readonly bound: number;
653
+ }
654
+ /** Unreachability: the given places never all have tokens simultaneously. */
655
+ interface Unreachable {
656
+ readonly type: 'unreachable';
657
+ readonly places: ReadonlySet<Place<any>>;
658
+ }
659
+ declare function deadlockFree(): DeadlockFree;
660
+ declare function mutualExclusion(p1: Place<any>, p2: Place<any>): MutualExclusion;
661
+ declare function placeBound(place: Place<any>, bound: number): PlaceBound;
662
+ declare function unreachable(places: ReadonlySet<Place<any>>): Unreachable;
663
+ /** Human-readable description of a property. */
664
+ declare function propertyDescription(prop: SmtProperty): string;
665
+
666
+ /**
667
+ * Immutable snapshot of a Petri net marking for state space analysis.
668
+ *
669
+ * Maps places (by name) to integer token counts. Only stores places with count > 0.
670
+ * Used for invariant computation and structural verification, not runtime execution.
671
+ */
672
+ declare class MarkingState {
673
+ private readonly tokenCounts;
674
+ private readonly placesByName;
675
+ /** @internal Use {@link MarkingState.builder} or {@link MarkingState.empty} to create instances. */
676
+ constructor(key: symbol, tokenCounts: Map<string, number>, placesByName: Map<string, Place<any>>);
677
+ /** Returns the token count for a place (0 if absent). */
678
+ tokens(place: Place<any>): number;
679
+ /** Checks if a place has at least one token. */
680
+ hasTokens(place: Place<any>): boolean;
681
+ /** Checks if any of the given places has tokens. */
682
+ hasTokensInAny(places: Iterable<Place<any>>): boolean;
683
+ /** Returns all places with tokens > 0. */
684
+ placesWithTokens(): Place<any>[];
685
+ /** Returns the total number of tokens. */
686
+ totalTokens(): number;
687
+ /** Checks if no tokens exist anywhere. */
688
+ isEmpty(): boolean;
689
+ toString(): string;
690
+ static empty(): MarkingState;
691
+ static builder(): MarkingStateBuilder;
692
+ }
693
+ declare class MarkingStateBuilder {
694
+ private readonly tokenCounts;
695
+ private readonly placesByName;
696
+ /** Sets the token count for a place. */
697
+ tokens(place: Place<any>, count: number): this;
698
+ /** Adds tokens to a place. */
699
+ addTokens(place: Place<any>, count: number): this;
700
+ /** Removes tokens from a place. Throws if insufficient. */
701
+ removeTokens(place: Place<any>, count: number): this;
702
+ /** Copies all token counts from another marking state. */
703
+ copyFrom(other: MarkingState): this;
704
+ build(): MarkingState;
705
+ }
706
+
707
+ /**
708
+ * A P-invariant (place invariant) of a Petri net.
709
+ *
710
+ * A P-invariant is a vector y such that y^T * C = 0, where C is the
711
+ * incidence matrix. This means that for any reachable marking M:
712
+ * sum(y_i * M_i) = constant, where constant = sum(y_i * M0_i).
713
+ *
714
+ * P-invariants provide structural bounds on places and are used as
715
+ * strengthening lemmas for the IC3/PDR engine.
716
+ */
717
+ interface PInvariant {
718
+ /** Weight vector (one entry per place index). */
719
+ readonly weights: readonly number[];
720
+ /** The invariant value sum(y_i * M0_i). */
721
+ readonly constant: number;
722
+ /** Set of place indices where weight != 0. */
723
+ readonly support: ReadonlySet<number>;
724
+ }
725
+ declare function pInvariant(weights: number[], constant: number, support: Set<number>): PInvariant;
726
+ declare function pInvariantToString(inv: PInvariant): string;
727
+
728
+ /**
729
+ * Verification verdict.
730
+ */
731
+ type Verdict = Proven | Violated | Unknown;
732
+ /** Property proven safe. No reachable state violates it. */
733
+ interface Proven {
734
+ readonly type: 'proven';
735
+ readonly method: string;
736
+ readonly inductiveInvariant: string | null;
737
+ }
738
+ /** Property violated. A counterexample trace is available. */
739
+ interface Violated {
740
+ readonly type: 'violated';
741
+ }
742
+ /** Could not determine. */
743
+ interface Unknown {
744
+ readonly type: 'unknown';
745
+ readonly reason: string;
746
+ }
747
+ /**
748
+ * Solver statistics.
749
+ */
750
+ interface SmtStatistics {
751
+ readonly places: number;
752
+ readonly transitions: number;
753
+ readonly invariantsFound: number;
754
+ readonly structuralResult: string;
755
+ }
756
+ /**
757
+ * Result of SMT-based verification.
758
+ */
759
+ interface SmtVerificationResult {
760
+ readonly verdict: Verdict;
761
+ readonly report: string;
762
+ readonly invariants: readonly PInvariant[];
763
+ readonly discoveredInvariants: readonly string[];
764
+ readonly counterexampleTrace: readonly MarkingState[];
765
+ readonly counterexampleTransitions: readonly string[];
766
+ readonly elapsedMs: number;
767
+ readonly statistics: SmtStatistics;
768
+ }
769
+ declare function isProven(result: SmtVerificationResult): boolean;
770
+ declare function isViolated(result: SmtVerificationResult): boolean;
771
+
772
+ /**
773
+ * Token-source supplier used by the verification harness to seed a synthetic
774
+ * environment place for a given input port, per
775
+ * `spec/11-modular-composition.md` requirement **MOD-051** AC #3.
776
+ *
777
+ * The supplier's presence is what bounds the input behavior in the synthetic
778
+ * harness; it is invoked once at synthetic-net construction time so that
779
+ * supplier-side errors surface eagerly, not at verification time. The
780
+ * concrete token value is not consumed by the verifier itself (which operates
781
+ * on the integer marking projection per [VER-004]); it merely materialises
782
+ * the seed token type and surfaces user errors.
783
+ */
784
+ type TokenSupplier = () => Token<unknown>;
785
+ /**
786
+ * Harness driving local property verification of a subnet definition per
787
+ * `spec/11-modular-composition.md` requirement **MOD-051**.
788
+ *
789
+ * The harness is a value carrier consumed by
790
+ * {@link import('../core/subnet-def.js').SubnetDef.verify}. It supplies the
791
+ * three pieces of information needed to wrap a subnet in a synthetic
792
+ * enclosing net for verification:
793
+ *
794
+ * 1. A {@link params} value of the subnet's parameter type.
795
+ * 2. A {@link portInputGenerators} map from **input port name** (original /
796
+ * pre-prefix) to a {@link TokenSupplier}. The supplier's presence is what
797
+ * bounds the input behavior in the synthetic harness; the supplier is
798
+ * invoked at synthetic-net construction time when the harness wires up the
799
+ * {@link import('../core/place.js').EnvironmentPlace} associated with the
800
+ * port.
801
+ * 3. A set of {@link properties} to check (per [VER-002] /
802
+ * {@link SmtProperty}).
803
+ *
804
+ * Each entry in {@link portInputGenerators} MUST correspond to an input or
805
+ * in-out port declared on the subnet's interface. Output-only ports never
806
+ * appear in the generator map; instead, the harness wires them to a synthetic
807
+ * observation place visible to the verifier.
808
+ *
809
+ * The map and property collection accept either the canonical
810
+ * `Map`/`ReadonlySet` form or a plain `Record`/`readonly array` for ergonomic
811
+ * inline construction; `SubnetDef.verify` normalises both.
812
+ *
813
+ * @typeParam P parameter type carried through to the subnet under test
814
+ */
815
+ interface VerificationHarness<P = void> {
816
+ /**
817
+ * Parameter value supplied to
818
+ * {@link import('../core/subnet-def.js').SubnetDef.instantiate} for the
819
+ * system-under-test instance. Use `undefined` (or `null`) for `P = void`.
820
+ */
821
+ readonly params: P;
822
+ /**
823
+ * Map (or `Record`) from **input port name** to a {@link TokenSupplier} that
824
+ * seeds the synthetic environment place for that port. Output-only ports
825
+ * MUST NOT appear; in-out ports MUST appear (mirrors the Java harness).
826
+ */
827
+ readonly portInputGenerators: ReadonlyMap<string, TokenSupplier> | Readonly<Record<string, TokenSupplier>>;
828
+ /**
829
+ * Safety properties to check on the synthetic enclosing net per
830
+ * {@link SmtProperty}. An empty collection is permitted but yields an empty
831
+ * {@link VerificationResult.perProperty}.
832
+ */
833
+ readonly properties: ReadonlySet<SmtProperty> | readonly SmtProperty[];
834
+ }
835
+ /**
836
+ * Aggregated outcome of a
837
+ * {@link import('../core/subnet-def.js').SubnetDef.verify} invocation per
838
+ * `spec/11-modular-composition.md` requirement **MOD-051**.
839
+ *
840
+ * The verifier is invoked once per {@link SmtProperty} declared in the
841
+ * harness; each invocation produces an {@link SmtVerificationResult}. This
842
+ * record carries the per-property results plus the synthetic enclosing net
843
+ * that was constructed for verification (useful for diagnostic output and
844
+ * tooling to render the harness wiring).
845
+ */
846
+ interface VerificationResult {
847
+ /**
848
+ * The synthetic enclosing net assembled by `SubnetDef.verify(...)`: the
849
+ * renamed body of the subnet under test, with each input port bound to a
850
+ * synthetic environment place and each output port bound to a synthetic
851
+ * observation place.
852
+ */
853
+ readonly syntheticNet: PetriNet;
854
+ /**
855
+ * Per-property verification results, in the iteration order of the
856
+ * harness's {@link VerificationHarness.properties} collection.
857
+ */
858
+ readonly perProperty: ReadonlyMap<SmtProperty, SmtVerificationResult>;
859
+ /**
860
+ * Returns true when every property in the harness was proven safe.
861
+ * An empty harness (no properties) returns `true` vacuously.
862
+ */
863
+ allProven(): boolean;
864
+ /**
865
+ * Returns true when at least one property was violated (counter-example
866
+ * found).
867
+ */
868
+ anyViolated(): boolean;
869
+ }
870
+
871
+ /**
872
+ * An open Petri net fragment paired with a declared {@link Interface}, per
873
+ * `spec/11-modular-composition.md` requirement **MOD-001**.
874
+ *
875
+ * A subnet definition is the reusable unit of composition. It carries:
876
+ * - A {@link name} (used as the originating-def label in `SubnetInstance` per [MOD-041]);
877
+ * - A {@link body} — a structurally complete `PetriNet` per [CORE-040];
878
+ * - An {@link iface} — the set of exposed ports and channels per [MOD-003] / [MOD-005].
879
+ *
880
+ * `SubnetDef` is the open variant of the {@link Subnet} discriminated union
881
+ * defined in `subnet.ts` per **MOD-002**.
882
+ *
883
+ * The {@link SubnetDef.fromNet} retrofit factory per **MOD-014** wraps an
884
+ * existing closed `PetriNet` plus an `Interface` into an unparameterised
885
+ * `SubnetDef<void>`, applying the same per-element validation as the
886
+ * builder's `build()`.
887
+ *
888
+ * @typeParam P parameter type carried through to `Instance.params`
889
+ * (use `void` for unparameterised subnets)
890
+ */
891
+ declare class SubnetDef<P = void> {
892
+ readonly name: string;
893
+ readonly body: PetriNet;
894
+ readonly iface: Interface;
895
+ /** @internal Use {@link SubnetDef.builder} or {@link SubnetDef.fromNet} to create instances. */
896
+ constructor(key: symbol, name: string, body: PetriNet, iface: Interface);
897
+ /**
898
+ * Produces a renamed module instance per **MOD-010**, **MOD-011**, **MOD-012**,
899
+ * and **MOD-030**.
900
+ *
901
+ * The rename pass walks every place and transition of the body net,
902
+ * substituting each name with `prefix + "/" + originalName`, and rebuilds
903
+ * every arc with rewritten place references. Transition timing, priority,
904
+ * and action are carried through by reference (action sharing per
905
+ * [MOD-030]). The renamed body is itself a structurally valid `PetriNet`
906
+ * per [CORE-040]; per-instance state isolation per [MOD-012] is a
907
+ * structural consequence of distinct prefixed names.
908
+ *
909
+ * ## Prefix validation
910
+ *
911
+ * The `"/"` character is reserved as the prefix separator (per [MOD-010]).
912
+ * User-supplied prefixes MUST NOT contain `"/"`; nested instantiation is
913
+ * performed by the future `PetriNetBuilder.compose(...)` mechanism (per
914
+ * [MOD-013]). A prefix containing `"/"` raises an `Error`.
915
+ *
916
+ * @param prefix the rename prefix (non-empty, must not contain `"/"`)
917
+ * @param params the parameter value carried through to `Instance.params`
918
+ * (may be omitted when `P` is `void`)
919
+ * @throws when `prefix` is empty or contains `"/"`
920
+ */
921
+ instantiate(prefix: string, params?: P): Instance<P>;
922
+ /**
923
+ * Verifies safety properties of this subnet definition **in isolation** per
924
+ * **MOD-051**, by wrapping it in a synthetic enclosing net where each input
925
+ * port is fed by an {@link EnvironmentPlace} (token-source per the harness
926
+ * generator) and each output port is observed via a synthetic place. The
927
+ * standard {@link SmtVerifier} (per [MOD-050]) is invoked once per property
928
+ * declared in the harness; the resulting per-property outcomes are
929
+ * aggregated into a {@link VerificationResult}.
930
+ *
931
+ * ## Synthetic-net construction
932
+ *
933
+ * The synthetic enclosing net is built by:
934
+ * 1. Instantiating this `SubnetDef` with the prefix `"sut"` (system-under-test)
935
+ * and `harness.params`.
936
+ * 2. For each input or in-out port on the interface, looking up the
937
+ * harness generator by port name, allocating a synthetic
938
+ * {@link Place}`<unknown>` of the same conceptual token type as the
939
+ * port, wrapping it in an {@link EnvironmentPlace}, and binding the
940
+ * port to that synthetic place via
941
+ * {@link import('./petri-net.js').PetriNetBuilder.compose}. The supplier
942
+ * is invoked once at construction time to materialize the seed token —
943
+ * its presence is what bounds the input behavior under analysis. **If
944
+ * the harness map is missing a generator for a required input or in-out
945
+ * port, an `Error` is thrown.**
946
+ * 3. For each output or in-out port, allocating a synthetic observation
947
+ * {@link Place}`<unknown>` and binding the port to it via the same
948
+ * `compose(...)` call. The verifier inspects this place's reachability
949
+ * / marking through the standard property APIs ({@link SmtProperty}).
950
+ * 4. Building the resulting flat {@link PetriNet} per [MOD-023] (the
951
+ * verifier is composition-unaware per [MOD-050]).
952
+ *
953
+ * ## Per-property invocation
954
+ *
955
+ * Each {@link SmtProperty} in the harness is verified independently against
956
+ * the same synthetic net. The synthetic environment places are passed
957
+ * through to the verifier so that places driven by the harness generators
958
+ * are treated under the verifier's environment-analysis semantics rather
959
+ * than as ordinary sink places.
960
+ *
961
+ * @param harness the verification harness — supplies parameters, input-port
962
+ * token generators, and the property set
963
+ * @returns a {@link VerificationResult} aggregating per-property
964
+ * {@link SmtVerificationResult}s
965
+ * @throws when an input or in-out port is missing a harness generator
966
+ */
967
+ verify(harness: VerificationHarness<P>): Promise<VerificationResult>;
968
+ static builder<P = void>(name: string): SubnetDefBuilder<P>;
969
+ /**
970
+ * Retrofit utility per **MOD-014**: wraps an existing closed {@link PetriNet}
971
+ * plus an {@link Interface} into an unparameterised `SubnetDef<void>`.
972
+ *
973
+ * Validation per **MOD-014** / **MOD-006** is enforced before the result is
974
+ * constructed:
975
+ * - Every port's underlying `Place` must be present in `net.places`.
976
+ * - Every channel's underlying `Transition` must be present in `net.transitions`.
977
+ * - Port and channel name uniqueness is re-validated defensively (the
978
+ * `Interface` builder already enforces this; hand-built `Interface`
979
+ * values bypass that path).
980
+ *
981
+ * The resulting subnet definition is unparameterised (parameter type is `void`).
982
+ *
983
+ * @throws when a port place is not in `net.places`, a channel transition is
984
+ * not in `net.transitions`, or port/channel names are not unique.
985
+ */
986
+ static fromNet(net: PetriNet, iface: Interface): SubnetDef<void>;
987
+ }
988
+ /**
989
+ * Fluent builder for {@link SubnetDef}.
990
+ *
991
+ * Validation per **MOD-006** is enforced at {@link build}:
992
+ * - Every port's underlying place must be in the body net.
993
+ * - Every channel's underlying transition must be in the body net.
994
+ * - Port names must be unique within the port namespace.
995
+ * - Channel names must be unique within the channel namespace.
996
+ */
997
+ declare class SubnetDefBuilder<P = void> {
998
+ private readonly _name;
999
+ private readonly _bodyBuilder;
1000
+ private readonly _ports;
1001
+ private readonly _channels;
1002
+ constructor(name: string);
1003
+ transition(transition: Transition): this;
1004
+ transitions(...transitions: Transition[]): this;
1005
+ place<T>(place: Place<T>): this;
1006
+ inputPort<T>(name: string, place: Place<T>): this;
1007
+ outputPort<T>(name: string, place: Place<T>): this;
1008
+ inoutPort<T>(name: string, place: Place<T>): this;
1009
+ channel(name: string, transition: Transition): this;
1010
+ build(): SubnetDef<P>;
1011
+ }
1012
+
1013
+ /**
1014
+ * Lightweight, debug-UI-facing descriptor of one composed subnet instance,
1015
+ * per `spec/11-modular-composition.md` requirement **MOD-041**.
1016
+ *
1017
+ * Created by `Instance.descriptor()` after a subnet has been instantiated and
1018
+ * (eventually) composed into an enclosing net. The descriptor is consumed by
1019
+ * the debug protocol's `Subscribed` response so clients can render collapsed
1020
+ * subnet clusters, per-instance highlighting, and "show only this instance"
1021
+ * filters in the debug UI.
1022
+ *
1023
+ * This interface carries only structural metadata — it is observability-only
1024
+ * and does not affect runtime behaviour of the composed flat net.
1025
+ */
1026
+ interface SubnetInstance {
1027
+ /** The instantiation prefix (e.g. `"buf1"` or `"outer/inner"` for nested instances). */
1028
+ readonly prefix: string;
1029
+ /** The originating subnet definition's name (null when not available). */
1030
+ readonly defName: string | null;
1031
+ /** Full prefixed transition names belonging to this instance. */
1032
+ readonly transitions: readonly string[];
1033
+ /** Full prefixed place names exposed as ports. */
1034
+ readonly exposedPlaces: readonly string[];
1035
+ /** The parameter value supplied at instantiation. */
1036
+ readonly params: unknown;
1037
+ /** The parent instance prefix when this is a nested instance, otherwise null. */
1038
+ readonly parentPrefix: string | null;
1039
+ }
1040
+
1041
+ /**
1042
+ * A typed module instance produced by {@link SubnetDef.instantiate}, per
1043
+ * `spec/11-modular-composition.md` requirements **MOD-010** (creation),
1044
+ * **MOD-011** (typed handle map), **MOD-012** (per-instance state isolation),
1045
+ * and **MOD-030** (action binding).
1046
+ *
1047
+ * An instance carries:
1048
+ * - The {@link prefix} used to rename body elements (per [MOD-010] separator `"/"`);
1049
+ * - A reference to the originating {@link SubnetDef};
1050
+ * - The renamed body — a structurally valid `PetriNet` per [CORE-040];
1051
+ * - Typed lookup handles for ports and channels keyed by their **original**
1052
+ * (pre-prefix) names;
1053
+ * - The `params` value supplied at instantiation.
1054
+ *
1055
+ * **Scaffolding status**: this class ships in scaffolding form. The
1056
+ * {@link bindActions} method throws `Error("not implemented")` until the
1057
+ * `instantiate` rename pass lands in the next task. Direct accessors are
1058
+ * wired up so downstream code can take dependencies on the API shape today.
1059
+ *
1060
+ * @typeParam P parameter type (use `void` for unparameterised subnets)
1061
+ */
1062
+ declare class Instance<P = void> {
1063
+ readonly prefix: string;
1064
+ readonly def: SubnetDef<P>;
1065
+ readonly renamedBody: PetriNet;
1066
+ readonly portHandles: ReadonlyMap<string, Place<unknown>>;
1067
+ readonly channelHandles: ReadonlyMap<string, Transition>;
1068
+ readonly params: P;
1069
+ /**
1070
+ * @internal Use {@link SubnetDef.instantiate} (or the internal factory
1071
+ * {@link __createInstance}) to create instances.
1072
+ */
1073
+ constructor(key: symbol, prefix: string, def: SubnetDef<P>, renamedBody: PetriNet, portHandles: ReadonlyMap<string, Place<unknown>>, channelHandles: ReadonlyMap<string, Transition>, params: P);
1074
+ /**
1075
+ * Returns the renamed {@link Place} corresponding to the named port.
1076
+ *
1077
+ * The port name is the **original** (pre-prefix) name as declared in the
1078
+ * subnet's `Interface`. Per **MOD-022**, TypeScript enforces token-type
1079
+ * compatibility at compile time only; this method does not validate `T`
1080
+ * at runtime. A missing name raises an `Error`.
1081
+ *
1082
+ * @throws when the port name is unknown
1083
+ */
1084
+ port<T>(name: string): Place<T>;
1085
+ /**
1086
+ * Returns the renamed {@link Transition} corresponding to the named channel.
1087
+ *
1088
+ * @throws when the channel name is unknown
1089
+ */
1090
+ channel(name: string): Transition;
1091
+ /**
1092
+ * Returns the debug-UI descriptor for this instance per **MOD-041**.
1093
+ */
1094
+ descriptor(): SubnetInstance;
1095
+ /**
1096
+ * Produces a derived instance whose specified transitions (named by their
1097
+ * **original**, pre-prefix names) carry the supplied actions per **MOD-030**.
1098
+ *
1099
+ * For each entry `[originalName, action]`, the renamed body is searched for
1100
+ * the transition whose name equals `prefix + "/" + originalName`. The
1101
+ * resulting instance shares the original `def`, `prefix`, `params`, and
1102
+ * port/channel handle topology — only the renamed body is rebuilt with new
1103
+ * actions. Per **MOD-030**, calling `bindActions` on one instance does NOT
1104
+ * affect the actions held by other instances of the same `def`.
1105
+ *
1106
+ * Unrecognised original names raise an `Error` so typos surface eagerly.
1107
+ */
1108
+ bindActions(actionsByOriginalName: Record<string, TransitionAction>): Instance<P>;
1109
+ }
1110
+
1111
+ /**
1112
+ * Typed binding builder for {@link PetriNetBuilder.compose}, per
1113
+ * `spec/11-modular-composition.md` requirements **MOD-020** (composition
1114
+ * operation) and **MOD-022** (type compatibility).
1115
+ *
1116
+ * `ComposeBindings` is a write-only collector: callers register port and
1117
+ * channel bindings against an instance's interface, and the host builder
1118
+ * consumes the recorded mappings as it merges the instance into the
1119
+ * enclosing net.
1120
+ *
1121
+ * ## Port bindings (MOD-020, MOD-022)
1122
+ *
1123
+ * {@link bindPort} merges an interface port with a caller-side place. The
1124
+ * port name is the **original** (pre-prefix) name declared in the subnet's
1125
+ * `Interface`; the caller place takes the port's slot in the resulting net.
1126
+ * Token-type compatibility is enforced at compile time only in TypeScript
1127
+ * (per [MOD-022]) — the typed `bindPort<T>` signature is the safety
1128
+ * mechanism. TypeScript erases generics at runtime, so a misuse via `as`
1129
+ * casts is structurally undetectable.
1130
+ *
1131
+ * ## Channel bindings (MOD-021)
1132
+ *
1133
+ * {@link bindChannel} records a synchronous channel binding: at compose time
1134
+ * the named instance-side interface transition is **merged** with the
1135
+ * supplied caller-side {@link Transition} into one transition in the
1136
+ * resulting flat net. Channel composition is implemented in task #13; until
1137
+ * then `compose(...)` raises an `Error` when any channel binding is present.
1138
+ *
1139
+ * ## Identity
1140
+ *
1141
+ * Instances are produced by {@link PetriNetBuilder.compose} and supplied to
1142
+ * the caller's callback. The constructor is symbol-guarded to prevent
1143
+ * direct construction.
1144
+ */
1145
+ declare class ComposeBindings {
1146
+ private readonly _portBindings;
1147
+ private readonly _channelBindings;
1148
+ /**
1149
+ * @internal Use {@link PetriNetBuilder.compose} — instances are produced
1150
+ * by the host builder and supplied to the caller's callback.
1151
+ */
1152
+ constructor(key: symbol);
1153
+ /**
1154
+ * Binds the named interface port to the given caller place per **MOD-020**.
1155
+ *
1156
+ * The port name is the **original** (pre-prefix) name declared in the
1157
+ * subnet's `Interface`. The typed `<T>` parameter ensures the caller
1158
+ * place's token type matches the interface port's token type at compile
1159
+ * time per [MOD-022]; TypeScript does not validate the type at runtime
1160
+ * because generics are erased.
1161
+ *
1162
+ * @throws when `portName` is already bound on this builder
1163
+ */
1164
+ bindPort<T>(portName: string, callerPlace: Place<T>): this;
1165
+ /**
1166
+ * Records a synchronous channel binding per **MOD-021**: at compose time,
1167
+ * the instance-side renamed channel transition is merged with
1168
+ * `callerTransition` into a single transition in the resulting flat net.
1169
+ *
1170
+ * **Status**: channel composition is implemented in task #13. Recording a
1171
+ * channel binding here is permitted, but `compose(...)` currently raises
1172
+ * an `Error` when any channel binding is present.
1173
+ *
1174
+ * @throws when `channelName` is already bound on this builder
1175
+ */
1176
+ bindChannel(channelName: string, callerTransition: Transition): this;
1177
+ /** Returns an unmodifiable view of the recorded port bindings. */
1178
+ portBindings(): ReadonlyMap<string, Place<unknown>>;
1179
+ /** Returns an unmodifiable view of the recorded channel bindings. */
1180
+ channelBindings(): ReadonlyMap<string, Transition>;
1181
+ }
1182
+
1183
+ /**
1184
+ * A declaration that N typed places are to be treated as a single canonical
1185
+ * place in the resulting flat {@link import('./petri-net.js').PetriNet}, per
1186
+ * `spec/11-modular-composition.md` requirements **MOD-060** (fusion set
1187
+ * declaration) and **MOD-061** (fusion resolution at build).
1188
+ *
1189
+ * Fusion is **orthogonal to subnet composition**: composition merges places
1190
+ * via port-binding (one instance port place ↔ one caller place per binding);
1191
+ * fusion merges N places at once via N-ary equivalence, applied **after** all
1192
+ * `compose(...)` calls have flattened subnet instances into the enclosing
1193
+ * {@link import('./petri-net.js').PetriNetBuilder}. Fusion is the mechanism
1194
+ * for modeling shared cross-instance state — e.g., a global rate limiter
1195
+ * shared by three instances of a leaky-bucket subnet — without expressing the
1196
+ * shared resource as an interface port on every subnet.
1197
+ *
1198
+ * ## Canonical member
1199
+ *
1200
+ * The **first declared member** is the canonical place; the others are
1201
+ * non-canonical and get substituted away at
1202
+ * {@link import('./petri-net.js').PetriNetBuilder.build} time. The canonical
1203
+ * member's name and identity survive into the resulting flat net;
1204
+ * non-canonical members do not appear in the built net's place set.
1205
+ *
1206
+ * ## Token-type homogeneity (MOD-060)
1207
+ *
1208
+ * All members of a fusion set MUST share the same token type. **In
1209
+ * TypeScript** this is enforced at **compile time only** (via the typed
1210
+ * `<T>` parameter on {@link FusionSetBuilder.member} and the typed varargs of
1211
+ * {@link FusionSet.of}); per the TS-specific MOD-022 clause, no runtime
1212
+ * `tokenType` introspection exists because Place carries only a phantom
1213
+ * generic. The Java implementation enforces the same invariant at runtime.
1214
+ *
1215
+ * ## Single-member sets
1216
+ *
1217
+ * A fusion set with a single member is degenerate but allowed: it is a no-op
1218
+ * at fusion-resolution time (the canonical member maps to itself, no
1219
+ * substitution occurs). This matches the structural semantics of an N-ary
1220
+ * equivalence with N=1.
1221
+ *
1222
+ * ## Identity
1223
+ *
1224
+ * `FusionSet` is immutable after construction. The {@link members} array is
1225
+ * frozen; iteration order is the declaration order, with the first element
1226
+ * guaranteed to be the canonical member.
1227
+ *
1228
+ * @see import('./petri-net.js').PetriNetBuilder.fuse
1229
+ */
1230
+ declare class FusionSet {
1231
+ readonly name: string;
1232
+ readonly members: readonly Place<unknown>[];
1233
+ /** @internal Use {@link FusionSet.builder} or {@link FusionSet.of} to create instances. */
1234
+ constructor(key: symbol, name: string, members: readonly Place<unknown>[]);
1235
+ /**
1236
+ * Returns the canonical member — by convention, the first declared member.
1237
+ * The canonical place's identity survives into the resulting flat net.
1238
+ */
1239
+ get canonical(): Place<unknown>;
1240
+ /**
1241
+ * Returns all members **except** the canonical member, in declaration order.
1242
+ * These are the places that get substituted away at
1243
+ * {@link import('./petri-net.js').PetriNetBuilder.build} time.
1244
+ *
1245
+ * For a single-member (degenerate) set, returns an empty array.
1246
+ */
1247
+ nonCanonical(): readonly Place<unknown>[];
1248
+ toString(): string;
1249
+ /** Returns a fresh {@link FusionSetBuilder} with the given human-readable name. */
1250
+ static builder(name: string): FusionSetBuilder;
1251
+ /**
1252
+ * Convenience factory: builds a fusion set whose first member is `first`
1253
+ * (the canonical) and whose remaining members are `rest`, all sharing the
1254
+ * type `<T>`.
1255
+ *
1256
+ * The varargs form ensures static-type homogeneity at the call site (the
1257
+ * TypeScript compiler checks every `rest` entry is a `Place<T>`).
1258
+ */
1259
+ static of<T>(name: string, first: Place<T>, ...rest: Place<T>[]): FusionSet;
1260
+ }
1261
+ /**
1262
+ * Fluent builder for {@link FusionSet}.
1263
+ *
1264
+ * Members are appended in call order; the first member becomes the canonical
1265
+ * place. The typed `<T>` parameter on {@link member} is for compile-time
1266
+ * guidance only — TypeScript erases generics at runtime, so no homogeneity
1267
+ * check happens here.
1268
+ */
1269
+ declare class FusionSetBuilder {
1270
+ private readonly _name;
1271
+ private readonly _members;
1272
+ constructor(name: string);
1273
+ /**
1274
+ * Appends a member to the fusion set. The first member becomes the canonical
1275
+ * place per the convention documented on {@link FusionSet}.
1276
+ *
1277
+ * The `<T>` parameter is for compile-time guidance only: callers writing
1278
+ * typed code at the same call site benefit from the compiler checking
1279
+ * `Place<T>` at each member.
1280
+ */
1281
+ member<T>(place: Place<T>): this;
1282
+ /**
1283
+ * Builds the immutable {@link FusionSet}. Validates that the set has at
1284
+ * least one member; the empty set is rejected as malformed per **MOD-060**.
1285
+ * Single-member sets are accepted as a structurally degenerate no-op.
1286
+ */
1287
+ build(): FusionSet;
1288
+ }
1289
+
1290
+ /**
1291
+ * Immutable definition of a Time Petri Net structure.
1292
+ *
1293
+ * A PetriNet is a reusable definition that can be executed multiple times
1294
+ * with different initial markings. Places are auto-collected from transitions.
1295
+ */
1296
+ declare class PetriNet {
1297
+ readonly name: string;
1298
+ readonly places: ReadonlySet<Place<any>>;
1299
+ readonly transitions: ReadonlySet<Transition>;
1300
+ /** @internal Use {@link PetriNet.builder} to create instances. */
1301
+ constructor(key: symbol, name: string, places: ReadonlySet<Place<any>>, transitions: ReadonlySet<Transition>);
1302
+ /**
1303
+ * Creates a new PetriNet with actions bound to transitions by name.
1304
+ * Unbound transitions keep passthrough action.
1305
+ */
1306
+ bindActions(actionBindings: Map<string, TransitionAction> | Record<string, TransitionAction>): PetriNet;
1307
+ /**
1308
+ * Creates a new PetriNet with actions bound via a resolver function.
1309
+ */
1310
+ bindActionsWithResolver(actionResolver: (name: string) => TransitionAction): PetriNet;
1311
+ static builder(name: string): PetriNetBuilder;
1312
+ }
1313
+ declare class PetriNetBuilder {
1314
+ private readonly _name;
1315
+ private readonly _places;
1316
+ private readonly _transitions;
1317
+ private readonly _fusionSets;
1318
+ constructor(name: string);
1319
+ /** Add an explicit place. */
1320
+ place(place: Place<any>): this;
1321
+ /** Add explicit places. */
1322
+ places(...places: Place<any>[]): this;
1323
+ /** Add a transition (auto-collects places from arcs). */
1324
+ transition(transition: Transition): this;
1325
+ /** Add transitions (auto-collects places from arcs). */
1326
+ transitions(...transitions: Transition[]): this;
1327
+ /**
1328
+ * Composes a subnet {@link Instance} into this builder per **MOD-020**
1329
+ * (composition operation), **MOD-021** (channel composition), **MOD-022**
1330
+ * (type compatibility), and **MOD-023** (composition produces a flat net).
1331
+ *
1332
+ * Two overloads are supported:
1333
+ *
1334
+ * 1. **Map / Record overload** — the runtime-checked form. Pass a
1335
+ * `Map<string, Place<unknown>>` or a `Record<string, Place<unknown>>`
1336
+ * keyed by the subnet's **original** (pre-prefix) port names. No
1337
+ * channel bindings are recorded by this overload.
1338
+ *
1339
+ * 2. **Callback overload** — the typed form. Pass a callback receiving a
1340
+ * fresh {@link ComposeBindings}; register port bindings via
1341
+ * `bindings.bindPort<T>(name, place)` so TypeScript checks each
1342
+ * binding's token type at compile time per [MOD-022]. Synchronous
1343
+ * channels may be merged with caller-side transitions via
1344
+ * `bindings.bindChannel(name, t)` per [MOD-021].
1345
+ *
1346
+ * For each port binding `(portName -> callerPlace)`, the instance's
1347
+ * renamed port place is substituted with the caller place at every arc
1348
+ * in the instance's renamed body via the `subnet-rewriter` module.
1349
+ * Internal (non-port) places of the instance flow through with their
1350
+ * prefixed names. Composition is **eager** — the rewrite happens here,
1351
+ * not at `build()` (per [MOD-020] AC #5).
1352
+ *
1353
+ * For each channel binding `(channelName -> callerTransition)`, the
1354
+ * instance's renamed channel transition and the caller-side transition
1355
+ * are merged into one transition in the resulting flat net per [MOD-021].
1356
+ * If the caller-side transition has not been added to this builder yet,
1357
+ * it is added implicitly during the merge step.
1358
+ *
1359
+ * @throws when a port name is unknown on the instance's interface, when a
1360
+ * channel name is unknown on the interface, or when caller- and
1361
+ * instance-side transition timings conflict (per [MOD-021]).
1362
+ */
1363
+ compose(instance: Instance<unknown>, portMappings: ReadonlyMap<string, Place<unknown>> | Record<string, Place<unknown>>): this;
1364
+ compose(instance: Instance<unknown>, bind: (b: ComposeBindings) => void): this;
1365
+ /**
1366
+ * @internal Shared compose implementation: validates port and channel
1367
+ * bindings, builds the place-substitution map, walks every renamed-body
1368
+ * transition through {@link substitutePlaces}, applies channel merges per
1369
+ * [MOD-021], and adds the resulting transitions to this builder.
1370
+ *
1371
+ * ## Channel-merge flow ([MOD-021])
1372
+ *
1373
+ * 1. Collect rewritten instance transitions into a working `Map<string,
1374
+ * Transition>` keyed by prefixed transition name (deferred — not yet
1375
+ * added to the builder's transition set).
1376
+ * 2. For each channel binding, resolve the renamed instance-side
1377
+ * transition through `instance.channel(channelName)`, then look up its
1378
+ * rewritten counterpart in the working map by name.
1379
+ * 3. Replace the working-map entry with a {@link mergeTransitions} result
1380
+ * that fuses caller-side + instance-side; remove the rewritten
1381
+ * instance-side entry. Also replace (or add) the caller-side
1382
+ * transition in this builder's transition set with the same merged
1383
+ * result, indexed under the caller's name slot.
1384
+ * 4. Add the surviving (un-merged) entries to this builder.
1385
+ *
1386
+ * The deferral matters: writing the rewritten instance transitions to the
1387
+ * builder eagerly would force a second "remove-then-replace" pass to
1388
+ * apply the channel merges, complicating the place-collection invariants.
1389
+ * Collecting first and merging second keeps the builder's transition set
1390
+ * finalized exactly once.
1391
+ *
1392
+ * Keying the working map by prefixed transition name (rather than by
1393
+ * Transition reference) is also robust against a prior
1394
+ * {@link Instance.bindActions} call that may have rebuilt the renamed-body
1395
+ * transitions, breaking identity equality between the body and the
1396
+ * channel-handle map — but the prefixed names remain stable.
1397
+ */
1398
+ private composeInternal;
1399
+ /**
1400
+ * Registers one or more {@link FusionSet} declarations on this builder, per
1401
+ * **MOD-060** (fusion set declaration) and **MOD-061** (fusion resolution
1402
+ * at build).
1403
+ *
1404
+ * Fusion is **orthogonal to subnet composition**: fuse sets are accumulated
1405
+ * here and applied during {@link build} **after** all `compose(...)` calls
1406
+ * have flattened subnet instances into the builder's transition set.
1407
+ * Registration order is irrelevant to semantics — `fuse(set)` BEFORE
1408
+ * `compose(...)` and `fuse(set)` AFTER `compose(...)` both apply at the
1409
+ * same point in the build pipeline.
1410
+ *
1411
+ * ## Validation
1412
+ *
1413
+ * Cross-set overlap (a place appearing in two fusion sets) is detected at
1414
+ * {@link build} and reported as an `Error` naming the offending place and
1415
+ * both sets.
1416
+ *
1417
+ * Two overloads are supported:
1418
+ *
1419
+ * 1. **Spread overload** — pass one or more pre-built {@link FusionSet}
1420
+ * values (e.g., from `FusionSet.of(...)` or
1421
+ * `FusionSet.builder(...).build()`).
1422
+ * 2. **Sugar overload** — pass a callback receiving a fresh
1423
+ * {@link FusionSetBuilder} named after the enclosing net; register
1424
+ * members via `b.member(place)`. Equivalent to
1425
+ * `FusionSet.builder('<netName>-fusion').<callback>.build()` followed by
1426
+ * `fuse(...)` on the result.
1427
+ */
1428
+ fuse(...sets: FusionSet[]): this;
1429
+ fuse(declarer: (b: FusionSetBuilder) => void): this;
1430
+ /**
1431
+ * Builds the immutable {@link PetriNet}, applying fusion resolution (per
1432
+ * **MOD-061**) AFTER all transition/composition accumulation:
1433
+ *
1434
+ * 1. Detect overlapping fusion sets — a single place declared in two sets
1435
+ * is rejected with an `Error`.
1436
+ * 2. Build the `non-canonical → canonical` substitution map across all
1437
+ * sets, keyed by non-canonical place name (matching the rewriter's
1438
+ * Map<string, Place<unknown>> convention — TypeScript Place identity is
1439
+ * name-based per `runtime/compiled-net.ts`).
1440
+ * 3. Walk every transition through {@link applyFusion} to rewrite arc place
1441
+ * references.
1442
+ * 4. Re-derive the place set from the rewritten transitions plus any
1443
+ * caller-declared standalone places, dropping non-canonical members.
1444
+ * Caller-declared standalone places that happen to be non-canonical
1445
+ * members are also dropped.
1446
+ *
1447
+ * If no fusion sets were registered, the build is the trivial
1448
+ * `new PetriNet(...)` — the fusion machinery has no per-build cost when
1449
+ * unused.
1450
+ *
1451
+ * @throws when two fusion sets share a place
1452
+ */
1453
+ build(): PetriNet;
1454
+ /**
1455
+ * @internal Fusion-resolution pass per **MOD-061**. Split out from
1456
+ * {@link build} so the no-fusion fast path stays trivial.
1457
+ */
1458
+ private buildWithFusion;
1459
+ }
1460
+
1461
+ export { and as $, type Arc as A, SubnetDefBuilder as B, type Channel as C, type SubnetInstance as D, type EnvironmentPlace as E, FusionSet as F, type Timing as G, type TimingDeadline as H, type In as I, type TimingDelayed as J, type TimingExact as K, type LogFn as L, MAX_DURATION_MS as M, type TimingImmediate as N, type Out as O, PetriNet as P, type TimingWindow as Q, TokenInput as R, SubnetDef as S, type Token as T, TokenOutput as U, type TransitionAction as V, TransitionBuilder as W, type VerificationHarness as X, type VerificationResult as Y, all as Z, allPlaces as _, type Place as a, placeBound as a$, andPlaces as a0, arcPlace as a1, atLeast as a2, consumptionCount as a3, deadline as a4, delayed as a5, earliest as a6, enumerateBranches as a7, environmentPlace as a8, exact as a9, transformFrom as aA, unitToken as aB, window as aC, withTimeout as aD, xor as aE, xorPlaces as aF, MarkingState as aG, type PInvariant as aH, MarkingStateBuilder as aI, type SmtProperty as aJ, type SmtVerificationResult as aK, type DeadlockFree as aL, type MutualExclusion as aM, type PlaceBound as aN, type Proven as aO, type SmtStatistics as aP, type TokenSupplier as aQ, type Unknown as aR, type Unreachable as aS, type Verdict as aT, type Violated as aU, deadlockFree as aV, isProven as aW, isViolated as aX, mutualExclusion as aY, pInvariant as aZ, pInvariantToString as a_, exactly as aa, fork as ab, forwardInput as ac, hasDeadline as ad, hasGuard as ae, immediate as af, inhibitorArc as ag, inputArc as ah, isUnit as ai, latest as aj, matchesGuard as ak, one as al, outPlace as am, outputArc as an, passthrough as ao, place as ap, produce as aq, readArc as ar, requiredCount as as, resetArc as at, timeout as au, timeoutPlace as av, tokenAt as aw, tokenOf as ax, transform as ay, transformAsync as az, Transition as b, propertyDescription as b0, unreachable as b1, TransitionContext as c, type ArcInhibitor as d, type ArcInput as e, type ArcOutput as f, type ArcRead as g, type ArcReset as h, ComposeBindings as i, FusionSetBuilder as j, type InAll as k, type InAtLeast as l, type InExactly as m, type InOne as n, Instance as o, Interface as p, InterfaceBuilder as q, type OutAnd as r, type OutForwardInput as s, type OutPlace as t, type OutTimeout as u, type OutXor as v, type OutputEntry as w, PetriNetBuilder as x, type Port as y, type PortDirection as z };