libpetri 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-FN773SSE.js → chunk-ATT7U5H5.js} +1 -1
- package/dist/chunk-ATT7U5H5.js.map +1 -0
- package/dist/{chunk-H62Z76FY.js → chunk-ETNHEAS6.js} +130 -18
- package/dist/chunk-ETNHEAS6.js.map +1 -0
- package/dist/{chunk-B2CV5M3L.js → chunk-ULX3OG6H.js} +27 -9
- package/dist/chunk-ULX3OG6H.js.map +1 -0
- package/dist/debug/index.d.ts +2 -2
- package/dist/debug/index.js +2 -2
- package/dist/doclet/index.d.ts +1 -1
- package/dist/doclet/index.js +3 -3
- package/dist/doclet/resources/petrinet-diagrams.js +21 -21
- package/dist/dot-exporter-TYC6FUAD.js +8 -0
- package/dist/{event-store-DqXOj4j-.d.ts → event-store-E_ahsEc9.d.ts} +1 -1
- package/dist/export/index.d.ts +22 -2
- package/dist/export/index.js +2 -2
- package/dist/index.d.ts +29 -4
- package/dist/index.js +121 -13
- package/dist/index.js.map +1 -1
- package/dist/{petri-net-RpZxG0Io.d.ts → petri-net-C3asscb4.d.ts} +40 -2
- package/dist/verification/index.d.ts +39 -34
- package/dist/verification/index.js +7 -17
- package/dist/verification/index.js.map +1 -1
- package/dist/viewer/index.d.ts +10 -4
- package/dist/viewer/index.js +76 -4
- package/dist/viewer/index.js.map +1 -1
- package/dist/viewer/viewer.iife.js +21 -21
- package/package.json +1 -1
- package/dist/chunk-B2CV5M3L.js.map +0 -1
- package/dist/chunk-FN773SSE.js.map +0 -1
- package/dist/chunk-H62Z76FY.js.map +0 -1
- package/dist/dot-exporter-WJMCJEFK.js +0 -8
- /package/dist/{dot-exporter-WJMCJEFK.js.map → dot-exporter-TYC6FUAD.js.map} +0 -0
package/dist/export/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PetriNet } from '../petri-net-
|
|
1
|
+
import { P as PetriNet } from '../petri-net-C3asscb4.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Format-agnostic typed graph model.
|
|
@@ -133,12 +133,32 @@ declare function edgeStyle(arcType: EdgeCategory): EdgeVisual;
|
|
|
133
133
|
* @module export/petri-net-mapper
|
|
134
134
|
*/
|
|
135
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Selects how DOT export groups nodes into `subgraph cluster_*` blocks (per
|
|
138
|
+
* **MOD-040** / **EXP-016**).
|
|
139
|
+
*
|
|
140
|
+
* - `'auto'` — use subnet-membership metadata (per MOD-026) when the net
|
|
141
|
+
* carries any; otherwise fall back to instance-prefix name detection.
|
|
142
|
+
* Default.
|
|
143
|
+
* - `'metadata'` — strictly cluster from subnet-membership metadata; a node
|
|
144
|
+
* with no metadata entry — including a prefix-named instance node — is not
|
|
145
|
+
* clustered. Use `'auto'` to also cluster prefix-named nodes.
|
|
146
|
+
* - `'prefix'` — always cluster from instance-prefix name segments; ignore
|
|
147
|
+
* metadata.
|
|
148
|
+
* - `'none'` — emit no clusters; every node renders at the top level.
|
|
149
|
+
*/
|
|
150
|
+
type ClusterSource = 'auto' | 'metadata' | 'prefix' | 'none';
|
|
136
151
|
interface DotConfig {
|
|
137
152
|
readonly direction: RankDir;
|
|
138
153
|
readonly showTypes: boolean;
|
|
139
154
|
readonly showIntervals: boolean;
|
|
140
155
|
readonly showPriority: boolean;
|
|
141
156
|
readonly environmentPlaces?: ReadonlySet<string>;
|
|
157
|
+
/**
|
|
158
|
+
* How to group nodes into `subgraph cluster_*` blocks (per MOD-040 /
|
|
159
|
+
* EXP-016). Additive; defaults to `'auto'` when omitted.
|
|
160
|
+
*/
|
|
161
|
+
readonly clusterSource?: ClusterSource;
|
|
142
162
|
}
|
|
143
163
|
declare const DEFAULT_DOT_CONFIG: DotConfig;
|
|
144
164
|
/** Sanitizes a name for use as a graph node ID. */
|
|
@@ -173,4 +193,4 @@ declare function renderDot(graph: Graph): string;
|
|
|
173
193
|
*/
|
|
174
194
|
declare function dotExport(net: PetriNet, config?: DotConfig): string;
|
|
175
195
|
|
|
176
|
-
export { type ArrowHead, DEFAULT_DOT_CONFIG, type DotConfig, type EdgeCategory, type EdgeLineStyle, type EdgeVisual, FONT, GRAPH, type Graph, type GraphEdge, type GraphNode, type NodeCategory, type NodeShape, type NodeVisual, type RankDir, type Subgraph, dotExport, edgeStyle, mapToGraph, nodeStyle, renderDot, sanitize };
|
|
196
|
+
export { type ArrowHead, type ClusterSource, DEFAULT_DOT_CONFIG, type DotConfig, type EdgeCategory, type EdgeLineStyle, type EdgeVisual, FONT, GRAPH, type Graph, type GraphEdge, type GraphNode, type NodeCategory, type NodeShape, type NodeVisual, type RankDir, type Subgraph, dotExport, edgeStyle, mapToGraph, nodeStyle, renderDot, sanitize };
|
package/dist/export/index.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { P as PetriNet, S as SubnetDef, a as Place, T as Token, b as Transition, E as EnvironmentPlace, c as TransitionContext, O as Out } from './petri-net-
|
|
2
|
-
export { A as Arc, d as ArcInhibitor, e as ArcInput, f as ArcOutput, g as ArcRead, h as ArcReset, C as Channel, i as ComposeBindings, F as FusionSet, j as FusionSetBuilder, I as In, k as InAll, l as InAtLeast, m as InExactly, n as InOne, o as Instance, p as Interface, q as InterfaceBuilder, L as LogFn, M as MAX_DURATION_MS, r as OutAnd, s as OutForwardInput, t as OutPlace, u as OutTimeout, v as OutXor, w as OutputEntry, x as PetriNetBuilder, y as Port, z as PortDirection, B as SubnetDefBuilder, D as SubnetInstance, G as Timing, H as TimingDeadline, J as TimingDelayed, K as TimingExact, N as TimingImmediate, Q as TimingWindow, R as TokenInput, U as TokenOutput, V as TransitionAction, W as TransitionBuilder, X as VerificationHarness, Y as VerificationResult, Z as all, _ as allPlaces, $ as and, a0 as andPlaces, a1 as arcPlace, a2 as atLeast, a3 as consumptionCount, a4 as deadline, a5 as delayed, a6 as earliest, a7 as enumerateBranches, a8 as environmentPlace, a9 as exact, aa as exactly, ab as fork, ac as forwardInput, ad as hasDeadline, ae as hasGuard, af as immediate, ag as inhibitorArc, ah as inputArc, ai as isUnit, aj as latest, ak as matchesGuard, al as one, am as outPlace, an as outputArc, ao as passthrough, ap as place, aq as produce, ar as readArc, as as requiredCount, at as resetArc, au as timeout, av as timeoutPlace, aw as tokenAt, ax as tokenOf, ay as transform, az as transformAsync, aA as transformFrom, aB as unitToken, aC as window, aD as withTimeout, aE as xor, aF as xorPlaces } from './petri-net-
|
|
3
|
-
import { E as EventStore } from './event-store-
|
|
4
|
-
export { A as ActionTimedOut, a as ExecutionCompleted, b as ExecutionStarted, I as InMemoryEventStore, L as LogMessage, M as MarkingSnapshot, N as NetEvent, T as TokenAdded, c as TokenRemoved, d as TransitionClockRestarted, e as TransitionCompleted, f as TransitionEnabled, g as TransitionFailed, h as TransitionStarted, i as TransitionTimedOut, j as eventTransitionName, k as eventsOfType, l as failures, m as filterEvents, n as inMemoryEventStore, o as isFailureEvent, p as noopEventStore, t as transitionEvents } from './event-store-
|
|
1
|
+
import { P as PetriNet, S as SubnetDef, a as Place, T as Token, b as Transition, E as EnvironmentPlace, c as TransitionContext, O as Out } from './petri-net-C3asscb4.js';
|
|
2
|
+
export { A as Arc, d as ArcInhibitor, e as ArcInput, f as ArcOutput, g as ArcRead, h as ArcReset, C as Channel, i as ComposeBindings, F as FusionSet, j as FusionSetBuilder, I as In, k as InAll, l as InAtLeast, m as InExactly, n as InOne, o as Instance, p as Interface, q as InterfaceBuilder, L as LogFn, M as MAX_DURATION_MS, r as OutAnd, s as OutForwardInput, t as OutPlace, u as OutTimeout, v as OutXor, w as OutputEntry, x as PetriNetBuilder, y as Port, z as PortDirection, B as SubnetDefBuilder, D as SubnetInstance, G as Timing, H as TimingDeadline, J as TimingDelayed, K as TimingExact, N as TimingImmediate, Q as TimingWindow, R as TokenInput, U as TokenOutput, V as TransitionAction, W as TransitionBuilder, X as VerificationHarness, Y as VerificationResult, Z as all, _ as allPlaces, $ as and, a0 as andPlaces, a1 as arcPlace, a2 as atLeast, a3 as consumptionCount, a4 as deadline, a5 as delayed, a6 as earliest, a7 as enumerateBranches, a8 as environmentPlace, a9 as exact, aa as exactly, ab as fork, ac as forwardInput, ad as hasDeadline, ae as hasGuard, af as immediate, ag as inhibitorArc, ah as inputArc, ai as isUnit, aj as latest, ak as matchesGuard, al as one, am as outPlace, an as outputArc, ao as passthrough, ap as place, aq as produce, ar as readArc, as as requiredCount, at as resetArc, au as timeout, av as timeoutPlace, aw as tokenAt, ax as tokenOf, ay as transform, az as transformAsync, aA as transformFrom, aB as unitToken, aC as window, aD as withTimeout, aE as xor, aF as xorPlaces } from './petri-net-C3asscb4.js';
|
|
3
|
+
import { E as EventStore } from './event-store-E_ahsEc9.js';
|
|
4
|
+
export { A as ActionTimedOut, a as ExecutionCompleted, b as ExecutionStarted, I as InMemoryEventStore, L as LogMessage, M as MarkingSnapshot, N as NetEvent, T as TokenAdded, c as TokenRemoved, d as TransitionClockRestarted, e as TransitionCompleted, f as TransitionEnabled, g as TransitionFailed, h as TransitionStarted, i as TransitionTimedOut, j as eventTransitionName, k as eventsOfType, l as failures, m as filterEvents, n as inMemoryEventStore, o as isFailureEvent, p as noopEventStore, t as transitionEvents } from './event-store-E_ahsEc9.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Discriminated sum-type abstraction over Petri nets, distinguishing **closed**
|
|
@@ -221,6 +221,13 @@ interface BitmapNetExecutorOptions {
|
|
|
221
221
|
environmentPlaces?: Set<EnvironmentPlace<any>>;
|
|
222
222
|
/** Provides execution context data for each transition firing. */
|
|
223
223
|
executionContextProvider?: (transitionName: string, consumed: Token<any>[]) => Map<string, unknown>;
|
|
224
|
+
/**
|
|
225
|
+
* Grace band (ms) beyond a hard deadline (`deadline()` / `window()`) before a transition is
|
|
226
|
+
* force-disabled with a `transition-timed-out` event (TIME-013). Defaults to {@link DEADLINE_TOLERANCE_MS}
|
|
227
|
+
* (5ms); `0` gives strict enforcement. Must be non-negative. Does not affect `exact()` transitions,
|
|
228
|
+
* which are enforced softly (TIME-006).
|
|
229
|
+
*/
|
|
230
|
+
deadlineToleranceMs?: number;
|
|
224
231
|
}
|
|
225
232
|
/**
|
|
226
233
|
* Async bitmap-based executor for Coloured Time Petri Nets.
|
|
@@ -262,6 +269,10 @@ declare class BitmapNetExecutor implements PetriNetExecutor {
|
|
|
262
269
|
private readonly enabledFlags;
|
|
263
270
|
/** Precomputed: 1 if transition has a finite deadline, 0 otherwise. */
|
|
264
271
|
private readonly hasDeadlineFlags;
|
|
272
|
+
/** Precomputed: 1 for exact() transitions — enforced softly, never force-disabled (TIME-006). */
|
|
273
|
+
private readonly isExactFlags;
|
|
274
|
+
/** Grace band (ms) before a hard deadline force-disables (TIME-013). */
|
|
275
|
+
private readonly deadlineToleranceMs;
|
|
265
276
|
private enabledTransitionCount;
|
|
266
277
|
private readonly inFlight;
|
|
267
278
|
private readonly inFlightPromises;
|
|
@@ -394,6 +405,12 @@ declare class PrecompiledNet {
|
|
|
394
405
|
readonly earliestMs: Float64Array;
|
|
395
406
|
readonly latestMs: Float64Array;
|
|
396
407
|
readonly hasDeadline: Uint8Array;
|
|
408
|
+
/**
|
|
409
|
+
* 1 for `exact()` transitions. Exact transitions fire at the first opportunity at/after their
|
|
410
|
+
* target time (delayed-style liveness) and are never force-disabled by deadline enforcement —
|
|
411
|
+
* their upper bound is observed, not enforced. See TIME-006.
|
|
412
|
+
*/
|
|
413
|
+
readonly isExact: Uint8Array;
|
|
397
414
|
readonly priorities: Int32Array;
|
|
398
415
|
readonly transitionToPriorityIndex: Uint32Array;
|
|
399
416
|
readonly priorityLevels: readonly number[];
|
|
@@ -456,6 +473,13 @@ interface PrecompiledNetExecutorOptions {
|
|
|
456
473
|
skipOutputValidation?: boolean;
|
|
457
474
|
/** Reuse a precompiled program (avoids recompilation). */
|
|
458
475
|
program?: PrecompiledNet;
|
|
476
|
+
/**
|
|
477
|
+
* Grace band (ms) beyond a hard deadline (`deadline()` / `window()`) before a transition is
|
|
478
|
+
* force-disabled with a `transition-timed-out` event (TIME-013). Defaults to {@link DEADLINE_TOLERANCE_MS}
|
|
479
|
+
* (5ms); `0` gives strict enforcement. Must be non-negative. Does not affect `exact()` transitions,
|
|
480
|
+
* which are enforced softly (TIME-006).
|
|
481
|
+
*/
|
|
482
|
+
deadlineToleranceMs?: number;
|
|
459
483
|
}
|
|
460
484
|
/**
|
|
461
485
|
* High-performance executor using `PrecompiledNet`.
|
|
@@ -470,6 +494,7 @@ declare class PrecompiledNetExecutor implements PetriNetExecutor {
|
|
|
470
494
|
private readonly hasEnvironmentPlaces;
|
|
471
495
|
private readonly executionContextProvider?;
|
|
472
496
|
private readonly skipOutputValidation;
|
|
497
|
+
private readonly deadlineToleranceMs;
|
|
473
498
|
private readonly startMs;
|
|
474
499
|
private readonly eventStoreEnabled;
|
|
475
500
|
/** Per-place token arrays, indexed by pid. */
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
timeoutPlace,
|
|
13
13
|
xor,
|
|
14
14
|
xorPlaces
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-ETNHEAS6.js";
|
|
16
16
|
import {
|
|
17
17
|
eventTransitionName,
|
|
18
18
|
isFailureEvent
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
immediate,
|
|
28
28
|
latest,
|
|
29
29
|
window
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-ATT7U5H5.js";
|
|
31
31
|
|
|
32
32
|
// src/core/token.ts
|
|
33
33
|
var UNIT_TOKEN = Object.freeze({
|
|
@@ -1646,12 +1646,25 @@ var PetriNet = class _PetriNet {
|
|
|
1646
1646
|
name;
|
|
1647
1647
|
places;
|
|
1648
1648
|
transitions;
|
|
1649
|
+
/**
|
|
1650
|
+
* Subnet-membership metadata per **MOD-026**: maps each node name (place or
|
|
1651
|
+
* transition) contributed by exactly one directly-composed subnet to that
|
|
1652
|
+
* subnet's name. Shared places contributed by two or more subnets, and every
|
|
1653
|
+
* node of a net not built via {@link PetriNetBuilder.compose}`(SubnetDef)`,
|
|
1654
|
+
* are absent. Never null — an empty map when there is no metadata. The DOT
|
|
1655
|
+
* exporter renders `subgraph cluster_*` blocks from this map.
|
|
1656
|
+
*
|
|
1657
|
+
* V8 `Map` is insertion-ordered, preserving compose order so cluster
|
|
1658
|
+
* subgraphs render deterministically (cross-language byte-parity).
|
|
1659
|
+
*/
|
|
1660
|
+
subnetMembership;
|
|
1649
1661
|
/** @internal Use {@link PetriNet.builder} to create instances. */
|
|
1650
|
-
constructor(key, name, places, transitions) {
|
|
1662
|
+
constructor(key, name, places, transitions, subnetMembership = /* @__PURE__ */ new Map()) {
|
|
1651
1663
|
if (key !== PETRI_NET_KEY) throw new Error("Use PetriNet.builder() to create instances");
|
|
1652
1664
|
this.name = name;
|
|
1653
1665
|
this.places = places;
|
|
1654
1666
|
this.transitions = transitions;
|
|
1667
|
+
this.subnetMembership = subnetMembership;
|
|
1655
1668
|
}
|
|
1656
1669
|
/**
|
|
1657
1670
|
* Creates a new PetriNet with actions bound to transitions by name.
|
|
@@ -1676,17 +1689,28 @@ var PetriNet = class _PetriNet {
|
|
|
1676
1689
|
boundTransitions.add(t);
|
|
1677
1690
|
}
|
|
1678
1691
|
}
|
|
1679
|
-
return new _PetriNet(
|
|
1692
|
+
return new _PetriNet(
|
|
1693
|
+
PETRI_NET_KEY,
|
|
1694
|
+
this.name,
|
|
1695
|
+
this.places,
|
|
1696
|
+
boundTransitions,
|
|
1697
|
+
this.subnetMembership
|
|
1698
|
+
);
|
|
1680
1699
|
}
|
|
1681
1700
|
static builder(name) {
|
|
1682
1701
|
return new PetriNetBuilder(name);
|
|
1683
1702
|
}
|
|
1684
1703
|
};
|
|
1685
|
-
var PetriNetBuilder = class {
|
|
1704
|
+
var PetriNetBuilder = class _PetriNetBuilder {
|
|
1686
1705
|
_name;
|
|
1687
1706
|
_places = /* @__PURE__ */ new Set();
|
|
1688
1707
|
_transitions = /* @__PURE__ */ new Set();
|
|
1689
1708
|
_fusionSets = [];
|
|
1709
|
+
// MOD-026: node name -> set of subnet names that contributed it via
|
|
1710
|
+
// compose(SubnetDef), in first-contribution order. Resolved to single-owner
|
|
1711
|
+
// membership at build(). V8 Map/Set iterate in insertion order, preserving
|
|
1712
|
+
// compose order for cross-language byte-parity.
|
|
1713
|
+
_subnetContributions = /* @__PURE__ */ new Map();
|
|
1690
1714
|
constructor(name) {
|
|
1691
1715
|
this._name = name;
|
|
1692
1716
|
}
|
|
@@ -1795,17 +1819,29 @@ var PetriNetBuilder = class {
|
|
|
1795
1819
|
}
|
|
1796
1820
|
const hostByName = /* @__PURE__ */ new Map();
|
|
1797
1821
|
for (const p of this._places) hostByName.set(p.name, p);
|
|
1822
|
+
const subnetName = def.name.replace(/\//g, "_");
|
|
1798
1823
|
const mergeMap = /* @__PURE__ */ new Map();
|
|
1799
1824
|
for (const p of body.places) {
|
|
1800
1825
|
const host = hostByName.get(p.name);
|
|
1801
1826
|
this.place(host ?? p);
|
|
1802
1827
|
if (host !== void 0) mergeMap.set(p.name, host);
|
|
1828
|
+
this.recordContribution(p.name, subnetName);
|
|
1803
1829
|
}
|
|
1804
1830
|
for (const t of body.transitions) {
|
|
1805
1831
|
this.transition(substitutePlaces(t, mergeMap));
|
|
1832
|
+
this.recordContribution(t.name, subnetName);
|
|
1806
1833
|
}
|
|
1807
1834
|
return this;
|
|
1808
1835
|
}
|
|
1836
|
+
/** @internal MOD-026: records a node as contributed by the named subnet. */
|
|
1837
|
+
recordContribution(nodeName, subnetName) {
|
|
1838
|
+
let owners = this._subnetContributions.get(nodeName);
|
|
1839
|
+
if (owners === void 0) {
|
|
1840
|
+
owners = /* @__PURE__ */ new Set();
|
|
1841
|
+
this._subnetContributions.set(nodeName, owners);
|
|
1842
|
+
}
|
|
1843
|
+
owners.add(subnetName);
|
|
1844
|
+
}
|
|
1809
1845
|
/**
|
|
1810
1846
|
* Identity-default auto-compose per **MOD-024**.
|
|
1811
1847
|
*
|
|
@@ -1990,16 +2026,58 @@ var PetriNetBuilder = class {
|
|
|
1990
2026
|
* @throws when two fusion sets share a place
|
|
1991
2027
|
*/
|
|
1992
2028
|
build() {
|
|
2029
|
+
const membership = this.resolveSubnetMembership();
|
|
1993
2030
|
if (this._fusionSets.length === 0) {
|
|
1994
|
-
return new PetriNet(
|
|
2031
|
+
return new PetriNet(
|
|
2032
|
+
PETRI_NET_KEY,
|
|
2033
|
+
this._name,
|
|
2034
|
+
this._places,
|
|
2035
|
+
this._transitions,
|
|
2036
|
+
membership
|
|
2037
|
+
);
|
|
1995
2038
|
}
|
|
1996
|
-
return this.buildWithFusion();
|
|
2039
|
+
return this.buildWithFusion(membership);
|
|
2040
|
+
}
|
|
2041
|
+
/**
|
|
2042
|
+
* @internal Resolves the per-compose contributions recorded by
|
|
2043
|
+
* `composeDirect` into the final node-name → subnet-name membership map per
|
|
2044
|
+
* **MOD-026**. A node contributed by exactly one subnet maps to that subnet;
|
|
2045
|
+
* a place contributed by two or more subnets is a shared rendezvous place
|
|
2046
|
+
* and is omitted (it renders top-level, outside any cluster). Returns an
|
|
2047
|
+
* empty map — the common case — when no subnet was composed directly.
|
|
2048
|
+
*/
|
|
2049
|
+
resolveSubnetMembership() {
|
|
2050
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
2051
|
+
for (const [nodeName, owners] of this._subnetContributions) {
|
|
2052
|
+
if (owners.size === 1) {
|
|
2053
|
+
resolved.set(nodeName, owners.values().next().value);
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
return resolved;
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* @internal Drops membership entries for places removed by fusion: a
|
|
2060
|
+
* non-canonical fused member no longer exists in the net, so its
|
|
2061
|
+
* `node-name → subnet` entry would dangle. The surviving canonical place
|
|
2062
|
+
* keeps its own entry. Per **MOD-026**.
|
|
2063
|
+
*/
|
|
2064
|
+
static filterFusedMembership(membership, nonCanonicalNames) {
|
|
2065
|
+
if (membership.size === 0 || nonCanonicalNames.size === 0) {
|
|
2066
|
+
return membership;
|
|
2067
|
+
}
|
|
2068
|
+
const filtered = /* @__PURE__ */ new Map();
|
|
2069
|
+
for (const [key, value] of membership) {
|
|
2070
|
+
if (!nonCanonicalNames.has(key)) {
|
|
2071
|
+
filtered.set(key, value);
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
return filtered;
|
|
1997
2075
|
}
|
|
1998
2076
|
/**
|
|
1999
2077
|
* @internal Fusion-resolution pass per **MOD-061**. Split out from
|
|
2000
2078
|
* {@link build} so the no-fusion fast path stays trivial.
|
|
2001
2079
|
*/
|
|
2002
|
-
buildWithFusion() {
|
|
2080
|
+
buildWithFusion(membership) {
|
|
2003
2081
|
const ownership = /* @__PURE__ */ new Map();
|
|
2004
2082
|
for (const set of this._fusionSets) {
|
|
2005
2083
|
for (const member of set.members) {
|
|
@@ -2035,7 +2113,13 @@ var PetriNetBuilder = class {
|
|
|
2035
2113
|
for (const r of t.reads) rebuiltPlaces.add(r.place);
|
|
2036
2114
|
for (const r of t.resets) rebuiltPlaces.add(r.place);
|
|
2037
2115
|
}
|
|
2038
|
-
return new PetriNet(
|
|
2116
|
+
return new PetriNet(
|
|
2117
|
+
PETRI_NET_KEY,
|
|
2118
|
+
this._name,
|
|
2119
|
+
rebuiltPlaces,
|
|
2120
|
+
rewrittenTransitions,
|
|
2121
|
+
_PetriNetBuilder.filterFusedMembership(membership, nonCanonicalNames)
|
|
2122
|
+
);
|
|
2039
2123
|
}
|
|
2040
2124
|
};
|
|
2041
2125
|
function rebuildWithAction(t, action) {
|
|
@@ -2445,6 +2529,7 @@ var OutViolationError = class extends Error {
|
|
|
2445
2529
|
};
|
|
2446
2530
|
|
|
2447
2531
|
// src/runtime/executor-support.ts
|
|
2532
|
+
var DEADLINE_TOLERANCE_MS = 5;
|
|
2448
2533
|
function validateOutSpec(tName, spec, producedPlaceNames) {
|
|
2449
2534
|
switch (spec.type) {
|
|
2450
2535
|
case "place":
|
|
@@ -2505,7 +2590,6 @@ function produceTimeoutOutput(context, timeoutChild) {
|
|
|
2505
2590
|
}
|
|
2506
2591
|
|
|
2507
2592
|
// src/runtime/bitmap-net-executor.ts
|
|
2508
|
-
var DEADLINE_TOLERANCE_MS = 5;
|
|
2509
2593
|
var BitmapNetExecutor = class {
|
|
2510
2594
|
compiled;
|
|
2511
2595
|
marking;
|
|
@@ -2530,6 +2614,10 @@ var BitmapNetExecutor = class {
|
|
|
2530
2614
|
enabledFlags;
|
|
2531
2615
|
/** Precomputed: 1 if transition has a finite deadline, 0 otherwise. */
|
|
2532
2616
|
hasDeadlineFlags;
|
|
2617
|
+
/** Precomputed: 1 for exact() transitions — enforced softly, never force-disabled (TIME-006). */
|
|
2618
|
+
isExactFlags;
|
|
2619
|
+
/** Grace band (ms) before a hard deadline force-disables (TIME-013). */
|
|
2620
|
+
deadlineToleranceMs;
|
|
2533
2621
|
enabledTransitionCount = 0;
|
|
2534
2622
|
// In-flight tracking
|
|
2535
2623
|
inFlight = /* @__PURE__ */ new Map();
|
|
@@ -2557,6 +2645,10 @@ var BitmapNetExecutor = class {
|
|
|
2557
2645
|
);
|
|
2558
2646
|
this.hasEnvironmentPlaces = this.environmentPlaces.size > 0;
|
|
2559
2647
|
this.executionContextProvider = options.executionContextProvider;
|
|
2648
|
+
this.deadlineToleranceMs = options.deadlineToleranceMs ?? DEADLINE_TOLERANCE_MS;
|
|
2649
|
+
if (this.deadlineToleranceMs < 0) {
|
|
2650
|
+
throw new Error(`Deadline tolerance must be non-negative: ${this.deadlineToleranceMs}`);
|
|
2651
|
+
}
|
|
2560
2652
|
this.startMs = performance.now();
|
|
2561
2653
|
const wordCount = this.compiled.wordCount;
|
|
2562
2654
|
this.markedPlaces = new Uint32Array(wordCount);
|
|
@@ -2570,6 +2662,7 @@ var BitmapNetExecutor = class {
|
|
|
2570
2662
|
this.inFlightFlags = new Uint8Array(this.compiled.transitionCount);
|
|
2571
2663
|
this.enabledFlags = new Uint8Array(this.compiled.transitionCount);
|
|
2572
2664
|
this.hasDeadlineFlags = new Uint8Array(this.compiled.transitionCount);
|
|
2665
|
+
this.isExactFlags = new Uint8Array(this.compiled.transitionCount);
|
|
2573
2666
|
let anyDeadlines = false;
|
|
2574
2667
|
let allImm = true;
|
|
2575
2668
|
let samePrio = true;
|
|
@@ -2580,6 +2673,7 @@ var BitmapNetExecutor = class {
|
|
|
2580
2673
|
this.hasDeadlineFlags[tid] = 1;
|
|
2581
2674
|
anyDeadlines = true;
|
|
2582
2675
|
}
|
|
2676
|
+
if (t.timing.type === "exact") this.isExactFlags[tid] = 1;
|
|
2583
2677
|
if (t.timing.type !== "immediate") allImm = false;
|
|
2584
2678
|
if (t.priority !== firstPriority) samePrio = false;
|
|
2585
2679
|
}
|
|
@@ -2759,11 +2853,12 @@ var BitmapNetExecutor = class {
|
|
|
2759
2853
|
enforceDeadlines(nowMs) {
|
|
2760
2854
|
for (let tid = 0; tid < this.compiled.transitionCount; tid++) {
|
|
2761
2855
|
if (!this.hasDeadlineFlags[tid]) continue;
|
|
2856
|
+
if (this.isExactFlags[tid]) continue;
|
|
2762
2857
|
if (!this.enabledFlags[tid] || this.inFlightFlags[tid]) continue;
|
|
2763
2858
|
const t = this.compiled.transition(tid);
|
|
2764
2859
|
const elapsed = nowMs - this.enabledAtMs[tid];
|
|
2765
2860
|
const latestMs = latest(t.timing);
|
|
2766
|
-
if (elapsed > latestMs +
|
|
2861
|
+
if (elapsed > latestMs + this.deadlineToleranceMs) {
|
|
2767
2862
|
this.enabledFlags[tid] = 0;
|
|
2768
2863
|
this.enabledTransitionCount--;
|
|
2769
2864
|
this.emitEvent({
|
|
@@ -3280,6 +3375,12 @@ var PrecompiledNet = class _PrecompiledNet {
|
|
|
3280
3375
|
earliestMs;
|
|
3281
3376
|
latestMs;
|
|
3282
3377
|
hasDeadline;
|
|
3378
|
+
/**
|
|
3379
|
+
* 1 for `exact()` transitions. Exact transitions fire at the first opportunity at/after their
|
|
3380
|
+
* target time (delayed-style liveness) and are never force-disabled by deadline enforcement —
|
|
3381
|
+
* their upper bound is observed, not enforced. See TIME-006.
|
|
3382
|
+
*/
|
|
3383
|
+
isExact;
|
|
3283
3384
|
// ==================== Priority (CONC-023) ====================
|
|
3284
3385
|
priorities;
|
|
3285
3386
|
transitionToPriorityIndex;
|
|
@@ -3400,6 +3501,7 @@ var PrecompiledNet = class _PrecompiledNet {
|
|
|
3400
3501
|
this.earliestMs = new Float64Array(tc);
|
|
3401
3502
|
this.latestMs = new Float64Array(tc);
|
|
3402
3503
|
this.hasDeadline = new Uint8Array(tc);
|
|
3504
|
+
this.isExact = new Uint8Array(tc);
|
|
3403
3505
|
let anyDeadlines = false;
|
|
3404
3506
|
let allImm = true;
|
|
3405
3507
|
for (let tid = 0; tid < tc; tid++) {
|
|
@@ -3410,6 +3512,7 @@ var PrecompiledNet = class _PrecompiledNet {
|
|
|
3410
3512
|
this.hasDeadline[tid] = 1;
|
|
3411
3513
|
anyDeadlines = true;
|
|
3412
3514
|
}
|
|
3515
|
+
if (t.timing.type === "exact") this.isExact[tid] = 1;
|
|
3413
3516
|
if (t.timing.type !== "immediate") allImm = false;
|
|
3414
3517
|
}
|
|
3415
3518
|
this.anyDeadlines = anyDeadlines;
|
|
@@ -3577,7 +3680,6 @@ function simpleOutputPlace(spec, compiled) {
|
|
|
3577
3680
|
}
|
|
3578
3681
|
|
|
3579
3682
|
// src/runtime/precompiled-net-executor.ts
|
|
3580
|
-
var DEADLINE_TOLERANCE_MS2 = 5;
|
|
3581
3683
|
var PrecompiledNetExecutor = class {
|
|
3582
3684
|
program;
|
|
3583
3685
|
eventStore;
|
|
@@ -3585,6 +3687,7 @@ var PrecompiledNetExecutor = class {
|
|
|
3585
3687
|
hasEnvironmentPlaces;
|
|
3586
3688
|
executionContextProvider;
|
|
3587
3689
|
skipOutputValidation;
|
|
3690
|
+
deadlineToleranceMs;
|
|
3588
3691
|
startMs;
|
|
3589
3692
|
eventStoreEnabled;
|
|
3590
3693
|
// ==================== Token Storage ====================
|
|
@@ -3638,6 +3741,10 @@ var PrecompiledNetExecutor = class {
|
|
|
3638
3741
|
this.hasEnvironmentPlaces = this.environmentPlaces.size > 0;
|
|
3639
3742
|
this.executionContextProvider = options.executionContextProvider;
|
|
3640
3743
|
this.skipOutputValidation = options.skipOutputValidation ?? false;
|
|
3744
|
+
this.deadlineToleranceMs = options.deadlineToleranceMs ?? DEADLINE_TOLERANCE_MS;
|
|
3745
|
+
if (this.deadlineToleranceMs < 0) {
|
|
3746
|
+
throw new Error(`Deadline tolerance must be non-negative: ${this.deadlineToleranceMs}`);
|
|
3747
|
+
}
|
|
3641
3748
|
this.startMs = performance.now();
|
|
3642
3749
|
this.eventStoreEnabled = this.eventStore.isEnabled();
|
|
3643
3750
|
const prog = this.program;
|
|
@@ -3852,10 +3959,11 @@ var PrecompiledNetExecutor = class {
|
|
|
3852
3959
|
const tc = prog.transitionCount;
|
|
3853
3960
|
for (let tid = 0; tid < tc; tid++) {
|
|
3854
3961
|
if (!prog.hasDeadline[tid]) continue;
|
|
3962
|
+
if (prog.isExact[tid]) continue;
|
|
3855
3963
|
if (!this.enabledFlags[tid] || this.inFlightFlags[tid]) continue;
|
|
3856
3964
|
const elapsed = nowMs - this.enabledAtMs[tid];
|
|
3857
3965
|
const latestMs = prog.latestMs[tid];
|
|
3858
|
-
if (elapsed > latestMs +
|
|
3966
|
+
if (elapsed > latestMs + this.deadlineToleranceMs) {
|
|
3859
3967
|
this.enabledFlags[tid] = 0;
|
|
3860
3968
|
this.enabledTransitionCount--;
|
|
3861
3969
|
this.enabledAtMs[tid] = -Infinity;
|