libpetri 4.1.0 → 5.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.
- package/dist/{chunk-GJAHGHGT.js → chunk-BPGE7GZR.js} +2 -2
- package/dist/{chunk-FD3S4TZM.js → chunk-EL4E6LVO.js} +1093 -197
- package/dist/chunk-EL4E6LVO.js.map +1 -0
- package/dist/debug/index.d.ts +2 -2
- package/dist/doclet/index.d.ts +1 -1
- package/dist/doclet/resources/petrinet-diagrams.js +4892 -4896
- package/dist/{event-store-B3ppVTpO.d.ts → event-store-CUyHiIH7.d.ts} +1 -1
- package/dist/export/index.d.ts +1 -1
- package/dist/index.d.ts +65 -13
- package/dist/index.js +195 -73
- package/dist/index.js.map +1 -1
- package/dist/{petri-net-p0ONpSAO.d.ts → petri-net-6G5r1Wwb.d.ts} +82 -4
- package/dist/render-dom/index.js +1 -1
- package/dist/verification/index.d.ts +435 -14
- package/dist/verification/index.js +33 -1
- package/dist/verification/index.js.map +1 -1
- package/dist/viewer/index.js +1 -1
- package/dist/viewer/viewer.iife.js +4892 -4896
- package/package.json +5 -5
- package/dist/chunk-FD3S4TZM.js.map +0 -1
- /package/dist/{chunk-GJAHGHGT.js.map → chunk-BPGE7GZR.js.map} +0 -0
package/dist/export/index.d.ts
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, K as KeyFn, L as LogFn, M as MAX_DURATION_MS, r as MatchKey, s as MatchSpec, N as NameId, t as OutAnd, u as OutForwardInput, v as OutPlace, w as OutTimeout, x as OutXor, y as OutputEntry, z as PetriNetBuilder, B as Port, D as PortDirection, G as SubnetDefBuilder, H as SubnetInstance, J as Timing, Q as TimingDeadline, R as TimingDelayed, U as TimingExact, V as TimingImmediate, W as TimingWindow, X as TokenInput, Y as TokenOutput, Z as TransitionAction, _ as TransitionBuilder, $ as VerificationHarness, a0 as VerificationResult, a1 as all, a2 as allPlaces, a3 as and, a4 as andPlaces, a5 as arcPlace, a6 as atLeast, a7 as consumptionCount, a8 as deadline, a9 as delayed, aa as earliest, ab as enumerateBranches, ac as environmentPlace, ad as exact, ae as exactly, af as fork, ag as forwardInput, ah as hasDeadline, ai as immediate, aj as inhibitorArc, ak as inputArc, al as isPassthrough, am as isUnit, an as keyForPlace, ao as latest, ap as matchCorrelates, aq as matchKey, ar as matchSpec, as as nameId, at as one, au as outPlace, av as outputArc, aw as passthrough, ax as place, ay as produce, az as readArc, aA as requiredCount, aB as resetArc, aC as timeout, aD as timeoutPlace, aE as tokenAt, aF as tokenOf, aG as transform, aH as transformAsync, aI as transformFrom, aJ as unitToken, aK as window, aL as withTimeout, aM as xor, aN 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-6G5r1Wwb.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, K as KeyFn, L as LogFn, M as MAX_DURATION_MS, r as MatchKey, s as MatchSpec, N as NameId, t as OutAnd, u as OutForwardInput, v as OutPlace, w as OutTimeout, x as OutXor, y as OutputEntry, z as PetriNetBuilder, B as Port, D as PortDirection, G as SubnetDefBuilder, H as SubnetInstance, J as Timing, Q as TimingDeadline, R as TimingDelayed, U as TimingExact, V as TimingImmediate, W as TimingWindow, X as TokenInput, Y as TokenOutput, Z as TransitionAction, _ as TransitionBuilder, $ as VerificationHarness, a0 as VerificationResult, a1 as all, a2 as allPlaces, a3 as and, a4 as andPlaces, a5 as arcPlace, a6 as atLeast, a7 as consumptionCount, a8 as deadline, a9 as delayed, aa as earliest, ab as enumerateBranches, ac as environmentPlace, ad as exact, ae as exactly, af as fork, ag as forwardInput, ah as hasDeadline, ai as immediate, aj as inhibitorArc, ak as inputArc, al as isPassthrough, am as isUnit, an as keyForPlace, ao as latest, ap as matchCorrelates, aq as matchKey, ar as matchSpec, as as nameId, at as one, au as outPlace, av as outputArc, aw as passthrough, ax as place, ay as produce, az as readArc, aA as requiredCount, aB as resetArc, aC as timeout, aD as timeoutPlace, aE as tokenAt, aF as tokenOf, aG as transform, aH as transformAsync, aI as transformFrom, aJ as unitToken, aK as window, aL as withTimeout, aM as xor, aN as xorPlaces } from './petri-net-6G5r1Wwb.js';
|
|
3
|
+
import { E as EventStore } from './event-store-CUyHiIH7.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-CUyHiIH7.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Discriminated sum-type abstraction over Petri nets, distinguishing **closed**
|
|
@@ -192,12 +192,30 @@ declare function containsAll(snapshot: Uint32Array, mask: Uint32Array): boolean;
|
|
|
192
192
|
/** Checks if any bit in mask is set in snapshot. */
|
|
193
193
|
declare function intersects(snapshot: Uint32Array, mask: Uint32Array): boolean;
|
|
194
194
|
|
|
195
|
+
/**
|
|
196
|
+
* What to do with the orchestrator loop when `run(timeoutMs)` hits its timeout.
|
|
197
|
+
*
|
|
198
|
+
* Mirrors Java's `PetriNetExecutor.RunTimeoutPolicy`.
|
|
199
|
+
*
|
|
200
|
+
* - `'abandon'` — reject the returned promise and leave the loop running. The net
|
|
201
|
+
* keeps firing transitions and mutating its marking after the caller has given up.
|
|
202
|
+
* This is what `run(timeoutMs)` has always done, and it stays the default only for
|
|
203
|
+
* compatibility — it is rarely what you want.
|
|
204
|
+
* - `'close'` — reject the returned promise and `close()` the executor. Queued external
|
|
205
|
+
* events are discarded and in-flight actions are allowed to complete, per [ENV-013].
|
|
206
|
+
*/
|
|
207
|
+
type RunTimeoutPolicy = 'abandon' | 'close';
|
|
195
208
|
/**
|
|
196
209
|
* Interface for Petri net executors.
|
|
197
210
|
*/
|
|
198
211
|
interface PetriNetExecutor {
|
|
199
|
-
/**
|
|
200
|
-
|
|
212
|
+
/**
|
|
213
|
+
* Run the net until quiescence or timeout.
|
|
214
|
+
*
|
|
215
|
+
* @param timeoutMs reject after this many milliseconds; omit to run to quiescence
|
|
216
|
+
* @param onTimeout what happens to the loop when the timeout fires (default `'abandon'`)
|
|
217
|
+
*/
|
|
218
|
+
run(timeoutMs?: number, onTimeout?: RunTimeoutPolicy): Promise<Marking>;
|
|
201
219
|
/** Inject an external token. Returns true if accepted. */
|
|
202
220
|
inject<T>(place: EnvironmentPlace<T>, token: Token<T>): Promise<boolean>;
|
|
203
221
|
/** Graceful shutdown: reject new inject() calls, process queued events, terminate at quiescence. */
|
|
@@ -313,6 +331,8 @@ declare class BitmapNetExecutor implements PetriNetExecutor {
|
|
|
313
331
|
* Place identity is name-based — so a hot loop warns once, not per token.
|
|
314
332
|
*/
|
|
315
333
|
private readonly warnedUnknownPlaces;
|
|
334
|
+
/** Transitions already warned for writing several tokens to a place their spec names once (IO-016 AC4). */
|
|
335
|
+
private readonly warnedMultiplicity;
|
|
316
336
|
private readonly transitionInputPlaceNames;
|
|
317
337
|
private running;
|
|
318
338
|
private draining;
|
|
@@ -327,7 +347,7 @@ declare class BitmapNetExecutor implements PetriNetExecutor {
|
|
|
327
347
|
private initMatchCaches;
|
|
328
348
|
/** Mirror a token added to correlated input `pid` into every fast-path matcher. */
|
|
329
349
|
private cacheAddToken;
|
|
330
|
-
run(timeoutMs?: number): Promise<Marking>;
|
|
350
|
+
run(timeoutMs?: number, onTimeout?: RunTimeoutPolicy): Promise<Marking>;
|
|
331
351
|
private executeLoop;
|
|
332
352
|
inject<T>(envPlace: EnvironmentPlace<T>, token: Token<T>): Promise<boolean>;
|
|
333
353
|
/** Convenience: inject a raw value (creates token with current timestamp). */
|
|
@@ -418,6 +438,13 @@ declare class BitmapNetExecutor implements PetriNetExecutor {
|
|
|
418
438
|
* initial-marking and injection seams. Retention never depends on this.
|
|
419
439
|
*/
|
|
420
440
|
private warnUnknownPlace;
|
|
441
|
+
/**
|
|
442
|
+
* Reports, once per transition, a firing that wrote more than one token to a place
|
|
443
|
+
* its output spec names once (IO-016 AC4), as the EVT-013 log-message event. The
|
|
444
|
+
* tokens are deposited regardless: the diagnostic makes the under-approximation
|
|
445
|
+
* every branch-enumerating analysis makes of this transition visible.
|
|
446
|
+
*/
|
|
447
|
+
private warnMultiplicity;
|
|
421
448
|
private emitEvent;
|
|
422
449
|
}
|
|
423
450
|
|
|
@@ -580,6 +607,8 @@ declare class PrecompiledNetExecutor implements PetriNetExecutor {
|
|
|
580
607
|
* materializing a Marking has one to hand.
|
|
581
608
|
*/
|
|
582
609
|
private readonly unknownPlaceTokens;
|
|
610
|
+
/** Transitions already warned for writing several tokens to a place their spec names once (IO-016 AC4). */
|
|
611
|
+
private readonly warnedMultiplicity;
|
|
583
612
|
/** Monotonic source for ν-name minting (ctx.freshName(), NU-010). */
|
|
584
613
|
private freshNameCounter;
|
|
585
614
|
/**
|
|
@@ -646,7 +675,7 @@ declare class PrecompiledNetExecutor implements PetriNetExecutor {
|
|
|
646
675
|
private markDirty;
|
|
647
676
|
private setMarkingBit;
|
|
648
677
|
private clearMarkingBit;
|
|
649
|
-
run(timeoutMs?: number): Promise<Marking>;
|
|
678
|
+
run(timeoutMs?: number, onTimeout?: RunTimeoutPolicy): Promise<Marking>;
|
|
650
679
|
private executeLoop;
|
|
651
680
|
inject<T>(envPlace: EnvironmentPlace<T>, token: Token<T>): Promise<boolean>;
|
|
652
681
|
injectValue<T>(envPlace: EnvironmentPlace<T>, value: T): Promise<boolean>;
|
|
@@ -727,6 +756,14 @@ declare class PrecompiledNetExecutor implements PetriNetExecutor {
|
|
|
727
756
|
executionId(): string;
|
|
728
757
|
drain(): void;
|
|
729
758
|
close(): void;
|
|
759
|
+
/**
|
|
760
|
+
* Reports, once per transition, a firing that wrote more than one token to a place
|
|
761
|
+
* its output spec names once (IO-016 AC4), as the EVT-013 log-message event. The
|
|
762
|
+
* tokens are deposited regardless: the diagnostic makes the under-approximation
|
|
763
|
+
* every branch-enumerating analysis makes of this transition visible. Mirrors the
|
|
764
|
+
* bitmap executor word for word.
|
|
765
|
+
*/
|
|
766
|
+
private warnMultiplicity;
|
|
730
767
|
private emitEvent;
|
|
731
768
|
}
|
|
732
769
|
|
|
@@ -756,12 +793,27 @@ declare class OutViolationError extends Error {
|
|
|
756
793
|
*/
|
|
757
794
|
|
|
758
795
|
/**
|
|
759
|
-
*
|
|
796
|
+
* [IO-015] output validation as an **exact-explanation search**.
|
|
797
|
+
*
|
|
798
|
+
* An *assignment* picks exactly one child at each `xor` it reaches; subtrees under
|
|
799
|
+
* an unselected child are never evaluated. Each assignment claims a set of places,
|
|
800
|
+
* and validation succeeds iff **exactly one** assignment's claim *equals* the
|
|
801
|
+
* produced set.
|
|
802
|
+
*
|
|
803
|
+
* Returns that claim on success and throws `OutViolationError` otherwise — whether
|
|
804
|
+
* nothing explains the write or two or more branches do.
|
|
805
|
+
*
|
|
806
|
+
* Equality — rather than "every obligation was satisfied" — is what makes a token
|
|
807
|
+
* written to a declared place outside the selected branch a violation instead of a
|
|
808
|
+
* silent deposit. It also removes the need for a subsumption tie-break:
|
|
809
|
+
* `xor(and(A,B,C), and(A,B))` with A, B, C produced has exactly one *exact* claim.
|
|
760
810
|
*
|
|
761
|
-
*
|
|
762
|
-
*
|
|
811
|
+
* Being a search rather than an eager walk is what makes `and` genuinely unordered
|
|
812
|
+
* ([IO-015] AC8): the old version short-circuited on its first unsatisfied child and
|
|
813
|
+
* let an inner `xor` throw before an enclosing one could try a sibling, so the same
|
|
814
|
+
* write set could pass or fail depending on declaration order.
|
|
763
815
|
*/
|
|
764
|
-
declare function validateOutSpec(tName: string, spec: Out, producedPlaceNames: Set<string>): Set<string
|
|
816
|
+
declare function validateOutSpec(tName: string, spec: Out, producedPlaceNames: Set<string>): Set<string>;
|
|
765
817
|
/**
|
|
766
818
|
* Produces default tokens to the timeout branch's output places when an action
|
|
767
819
|
* exceeds its timeout. Walks the Out spec tree recursively:
|
|
@@ -780,4 +832,4 @@ declare function validateOutSpec(tName: string, spec: Out, producedPlaceNames: S
|
|
|
780
832
|
*/
|
|
781
833
|
declare function produceTimeoutOutput(context: TransitionContext, timeoutChild: Out): void;
|
|
782
834
|
|
|
783
|
-
export { BitmapNetExecutor, type BitmapNetExecutorOptions, type CardinalityCheck, CompiledNet, EnvironmentPlace, EventStore, Marking, Out, OutViolationError, PetriNet, type PetriNetExecutor, Place, PrecompiledNet, PrecompiledNetExecutor, type PrecompiledNetExecutorOptions, type PredicateSpec, type Subnet, SubnetDef, Token, Transition, TransitionContext, clearBit, closedSubnet, containsAll, intersects, openSubnet, produceTimeoutOutput, setBit, testBit, validateOutSpec };
|
|
835
|
+
export { BitmapNetExecutor, type BitmapNetExecutorOptions, type CardinalityCheck, CompiledNet, EnvironmentPlace, EventStore, Marking, Out, OutViolationError, PetriNet, type PetriNetExecutor, Place, PrecompiledNet, PrecompiledNetExecutor, type PrecompiledNetExecutorOptions, type PredicateSpec, type RunTimeoutPolicy, type Subnet, SubnetDef, Token, Transition, TransitionContext, clearBit, closedSubnet, containsAll, intersects, openSubnet, produceTimeoutOutput, setBit, testBit, validateOutSpec };
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
withTimeout,
|
|
29
29
|
xor,
|
|
30
30
|
xorPlaces
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-EL4E6LVO.js";
|
|
32
32
|
import {
|
|
33
33
|
eventTransitionName,
|
|
34
34
|
isFailureEvent
|
|
@@ -3072,51 +3072,104 @@ function swallowEventStoreFailure(when, err) {
|
|
|
3072
3072
|
}
|
|
3073
3073
|
var DEADLINE_TOLERANCE_MS = 5;
|
|
3074
3074
|
function validateOutSpec(tName, spec, producedPlaceNames) {
|
|
3075
|
+
const named = specNames(spec);
|
|
3076
|
+
let relevant = 0;
|
|
3077
|
+
for (const name of producedPlaceNames) {
|
|
3078
|
+
if (named.has(name)) relevant++;
|
|
3079
|
+
}
|
|
3080
|
+
const exact2 = [];
|
|
3081
|
+
for (const claim of claimsWithin(spec, producedPlaceNames)) {
|
|
3082
|
+
if (claim.size === relevant) {
|
|
3083
|
+
exact2.push(claim);
|
|
3084
|
+
if (exact2.length > 1) break;
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
const wrote = [...producedPlaceNames].filter((n) => named.has(n)).sort();
|
|
3088
|
+
if (exact2.length === 0) {
|
|
3089
|
+
throw new OutViolationError(
|
|
3090
|
+
`'${tName}': output does not match the declared spec - produced {${wrote.join(", ")}}, which no single branch of the spec claims exactly`
|
|
3091
|
+
);
|
|
3092
|
+
}
|
|
3093
|
+
if (exact2.length > 1) {
|
|
3094
|
+
throw new OutViolationError(
|
|
3095
|
+
`'${tName}': ambiguous output - {${wrote.join(", ")}} is claimed by more than one branch`
|
|
3096
|
+
);
|
|
3097
|
+
}
|
|
3098
|
+
return exact2[0];
|
|
3099
|
+
}
|
|
3100
|
+
function capMultiplicity(claims) {
|
|
3101
|
+
if (claims.length < 3) return claims;
|
|
3102
|
+
const seen = /* @__PURE__ */ new Map();
|
|
3103
|
+
const out = [];
|
|
3104
|
+
for (const claim of claims) {
|
|
3105
|
+
const key = [...claim].sort().join("\0");
|
|
3106
|
+
const n = seen.get(key) ?? 0;
|
|
3107
|
+
if (n >= 2) continue;
|
|
3108
|
+
seen.set(key, n + 1);
|
|
3109
|
+
out.push(claim);
|
|
3110
|
+
}
|
|
3111
|
+
return out;
|
|
3112
|
+
}
|
|
3113
|
+
var specNamesCache = /* @__PURE__ */ new WeakMap();
|
|
3114
|
+
function specNames(spec) {
|
|
3115
|
+
const hit = specNamesCache.get(spec);
|
|
3116
|
+
if (hit !== void 0) return hit;
|
|
3117
|
+
const names = /* @__PURE__ */ new Set();
|
|
3118
|
+
const walk = (node) => {
|
|
3119
|
+
switch (node.type) {
|
|
3120
|
+
case "place":
|
|
3121
|
+
names.add(node.place.name);
|
|
3122
|
+
break;
|
|
3123
|
+
case "forward-input":
|
|
3124
|
+
names.add(node.to.name);
|
|
3125
|
+
break;
|
|
3126
|
+
case "timeout":
|
|
3127
|
+
walk(node.child);
|
|
3128
|
+
break;
|
|
3129
|
+
case "xor":
|
|
3130
|
+
case "and":
|
|
3131
|
+
for (const c of node.children) walk(c);
|
|
3132
|
+
break;
|
|
3133
|
+
}
|
|
3134
|
+
};
|
|
3135
|
+
walk(spec);
|
|
3136
|
+
specNamesCache.set(spec, names);
|
|
3137
|
+
return names;
|
|
3138
|
+
}
|
|
3139
|
+
function claimsWithin(spec, produced) {
|
|
3075
3140
|
switch (spec.type) {
|
|
3076
3141
|
case "place":
|
|
3077
|
-
return
|
|
3142
|
+
return produced.has(spec.place.name) ? [/* @__PURE__ */ new Set([spec.place.name])] : [];
|
|
3078
3143
|
case "forward-input":
|
|
3079
|
-
return
|
|
3080
|
-
case "
|
|
3081
|
-
|
|
3144
|
+
return produced.has(spec.to.name) ? [/* @__PURE__ */ new Set([spec.to.name])] : [];
|
|
3145
|
+
case "timeout":
|
|
3146
|
+
return claimsWithin(spec.child, produced);
|
|
3147
|
+
case "xor": {
|
|
3148
|
+
const out = [];
|
|
3082
3149
|
for (const child of spec.children) {
|
|
3083
|
-
const
|
|
3084
|
-
if (result === null) return null;
|
|
3085
|
-
for (const p of result) claimed.add(p);
|
|
3150
|
+
for (const claim of claimsWithin(child, produced)) out.push(claim);
|
|
3086
3151
|
}
|
|
3087
|
-
return
|
|
3152
|
+
return capMultiplicity(out);
|
|
3088
3153
|
}
|
|
3089
|
-
case "
|
|
3090
|
-
|
|
3154
|
+
case "and": {
|
|
3155
|
+
let acc = [/* @__PURE__ */ new Set()];
|
|
3091
3156
|
for (const child of spec.children) {
|
|
3092
|
-
const
|
|
3093
|
-
if (
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3157
|
+
const childClaims = claimsWithin(child, produced);
|
|
3158
|
+
if (childClaims.length === 0) return [];
|
|
3159
|
+
const next = [];
|
|
3160
|
+
for (const partial of acc) {
|
|
3161
|
+
for (const claim of childClaims) {
|
|
3162
|
+
const merged = new Set(partial);
|
|
3163
|
+
for (const name of claim) merged.add(name);
|
|
3164
|
+
next.push(merged);
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
acc = capMultiplicity(next);
|
|
3102
3168
|
}
|
|
3103
|
-
return
|
|
3169
|
+
return acc;
|
|
3104
3170
|
}
|
|
3105
|
-
case "timeout":
|
|
3106
|
-
return validateOutSpec(tName, spec.child, producedPlaceNames);
|
|
3107
3171
|
}
|
|
3108
3172
|
}
|
|
3109
|
-
function resolveXorAmbiguity(tName, satisfied) {
|
|
3110
|
-
const subsuming = satisfied.filter(
|
|
3111
|
-
(candidate) => satisfied.every(
|
|
3112
|
-
(other) => other === candidate || [...other].every((p) => candidate.has(p))
|
|
3113
|
-
)
|
|
3114
|
-
);
|
|
3115
|
-
if (subsuming.length === 1) return subsuming[0];
|
|
3116
|
-
throw new OutViolationError(
|
|
3117
|
-
`'${tName}': XOR violation - multiple branches produced`
|
|
3118
|
-
);
|
|
3119
|
-
}
|
|
3120
3173
|
function produceTimeoutOutput(context, timeoutChild) {
|
|
3121
3174
|
switch (timeoutChild.type) {
|
|
3122
3175
|
case "place":
|
|
@@ -3200,6 +3253,8 @@ var BitmapNetExecutor = class {
|
|
|
3200
3253
|
* Place identity is name-based — so a hot loop warns once, not per token.
|
|
3201
3254
|
*/
|
|
3202
3255
|
warnedUnknownPlaces = /* @__PURE__ */ new Set();
|
|
3256
|
+
/** Transitions already warned for writing several tokens to a place their spec names once (IO-016 AC4). */
|
|
3257
|
+
warnedMultiplicity = /* @__PURE__ */ new Set();
|
|
3203
3258
|
transitionInputPlaceNames;
|
|
3204
3259
|
running = false;
|
|
3205
3260
|
draining = false;
|
|
@@ -3342,19 +3397,27 @@ var BitmapNetExecutor = class {
|
|
|
3342
3397
|
}
|
|
3343
3398
|
}
|
|
3344
3399
|
// ======================== Execution ========================
|
|
3345
|
-
async run(timeoutMs) {
|
|
3346
|
-
if (timeoutMs
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
}
|
|
3354
|
-
|
|
3400
|
+
async run(timeoutMs, onTimeout = "abandon") {
|
|
3401
|
+
if (timeoutMs === void 0) return this.executeLoop();
|
|
3402
|
+
let timer;
|
|
3403
|
+
let timedOut = false;
|
|
3404
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
3405
|
+
timer = setTimeout(() => {
|
|
3406
|
+
timedOut = true;
|
|
3407
|
+
reject(new Error("Execution timed out"));
|
|
3408
|
+
}, timeoutMs);
|
|
3409
|
+
});
|
|
3410
|
+
const loop = this.executeLoop();
|
|
3411
|
+
try {
|
|
3412
|
+
return await Promise.race([loop, timeoutPromise]);
|
|
3413
|
+
} finally {
|
|
3414
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
3415
|
+
if (timedOut) {
|
|
3416
|
+
if (onTimeout === "close") this.close();
|
|
3417
|
+
loop.catch(() => {
|
|
3418
|
+
});
|
|
3355
3419
|
}
|
|
3356
3420
|
}
|
|
3357
|
-
return this.executeLoop();
|
|
3358
3421
|
}
|
|
3359
3422
|
async executeLoop() {
|
|
3360
3423
|
this.running = true;
|
|
@@ -3853,12 +3916,8 @@ var BitmapNetExecutor = class {
|
|
|
3853
3916
|
const outputs = flight.context.rawOutput();
|
|
3854
3917
|
if (t.outputSpec !== null) {
|
|
3855
3918
|
const produced2 = outputs.placesWithTokens();
|
|
3856
|
-
const
|
|
3857
|
-
if (
|
|
3858
|
-
throw new OutViolationError(
|
|
3859
|
-
`'${t.name}': output does not satisfy declared spec`
|
|
3860
|
-
);
|
|
3861
|
-
}
|
|
3919
|
+
const claim = validateOutSpec(t.name, t.outputSpec, produced2);
|
|
3920
|
+
if (outputs.entries().length > produced2.size) this.warnMultiplicity(t.name, outputs, claim);
|
|
3862
3921
|
}
|
|
3863
3922
|
const produced = [];
|
|
3864
3923
|
for (const entry of outputs.entries()) {
|
|
@@ -4069,6 +4128,33 @@ var BitmapNetExecutor = class {
|
|
|
4069
4128
|
errorMessage: null
|
|
4070
4129
|
});
|
|
4071
4130
|
}
|
|
4131
|
+
/**
|
|
4132
|
+
* Reports, once per transition, a firing that wrote more than one token to a place
|
|
4133
|
+
* its output spec names once (IO-016 AC4), as the EVT-013 log-message event. The
|
|
4134
|
+
* tokens are deposited regardless: the diagnostic makes the under-approximation
|
|
4135
|
+
* every branch-enumerating analysis makes of this transition visible.
|
|
4136
|
+
*/
|
|
4137
|
+
warnMultiplicity(transitionName, outputs, claim) {
|
|
4138
|
+
if (this.warnedMultiplicity.has(transitionName)) return;
|
|
4139
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4140
|
+
for (const entry of outputs.entries()) {
|
|
4141
|
+
if (claim.has(entry.place.name)) counts.set(entry.place.name, (counts.get(entry.place.name) ?? 0) + 1);
|
|
4142
|
+
}
|
|
4143
|
+
const repeated = [];
|
|
4144
|
+
for (const [name, n] of counts) if (n > 1) repeated.push(`${name}: ${n}`);
|
|
4145
|
+
if (repeated.length === 0) return;
|
|
4146
|
+
this.warnedMultiplicity.add(transitionName);
|
|
4147
|
+
this.emitEvent({
|
|
4148
|
+
type: "log-message",
|
|
4149
|
+
timestamp: Date.now(),
|
|
4150
|
+
transitionName,
|
|
4151
|
+
logger: "libpetri.runtime",
|
|
4152
|
+
level: "WARN",
|
|
4153
|
+
message: `'${transitionName}': wrote more than one token to a place its output spec names once (${repeated.join(", ")}); branch-enumerating analyses model one token per named place, so this firing exceeds what they explore (IO-016)`,
|
|
4154
|
+
error: null,
|
|
4155
|
+
errorMessage: null
|
|
4156
|
+
});
|
|
4157
|
+
}
|
|
4072
4158
|
emitEvent(event) {
|
|
4073
4159
|
if (this.eventStoreEnabled) {
|
|
4074
4160
|
try {
|
|
@@ -4342,13 +4428,13 @@ var PrecompiledNet = class _PrecompiledNet {
|
|
|
4342
4428
|
if (needsIdx === SPARSE_EMPTY) {
|
|
4343
4429
|
} else if (needsIdx >= 0) {
|
|
4344
4430
|
const m = this.needsSingleWordMask[tid];
|
|
4345
|
-
if ((snapshot[needsIdx] & m) !== m) return false;
|
|
4431
|
+
if ((snapshot[needsIdx] & m) >>> 0 !== m) return false;
|
|
4346
4432
|
} else {
|
|
4347
4433
|
const indices = this.needsSparseIndices[tid];
|
|
4348
4434
|
const masks = this.needsSparseMasks[tid];
|
|
4349
4435
|
for (let i = 0; i < indices.length; i++) {
|
|
4350
4436
|
const m = masks[i];
|
|
4351
|
-
if ((snapshot[indices[i]] & m) !== m) return false;
|
|
4437
|
+
if ((snapshot[indices[i]] & m) >>> 0 !== m) return false;
|
|
4352
4438
|
}
|
|
4353
4439
|
}
|
|
4354
4440
|
const inhIdx = this.inhibitorSingleWordIndex[tid];
|
|
@@ -4462,6 +4548,8 @@ var PrecompiledNetExecutor = class {
|
|
|
4462
4548
|
* materializing a Marking has one to hand.
|
|
4463
4549
|
*/
|
|
4464
4550
|
unknownPlaceTokens = /* @__PURE__ */ new Map();
|
|
4551
|
+
/** Transitions already warned for writing several tokens to a place their spec names once (IO-016 AC4). */
|
|
4552
|
+
warnedMultiplicity = /* @__PURE__ */ new Set();
|
|
4465
4553
|
/** Monotonic source for ν-name minting (ctx.freshName(), NU-010). */
|
|
4466
4554
|
freshNameCounter = 0;
|
|
4467
4555
|
/**
|
|
@@ -4676,19 +4764,27 @@ var PrecompiledNetExecutor = class {
|
|
|
4676
4764
|
this.markingBitmap[pid >>> WORD_SHIFT] &= ~(1 << (pid & BIT_MASK));
|
|
4677
4765
|
}
|
|
4678
4766
|
// ======================== Execution ========================
|
|
4679
|
-
async run(timeoutMs) {
|
|
4680
|
-
if (timeoutMs
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
}
|
|
4688
|
-
|
|
4767
|
+
async run(timeoutMs, onTimeout = "abandon") {
|
|
4768
|
+
if (timeoutMs === void 0) return this.executeLoop();
|
|
4769
|
+
let timer;
|
|
4770
|
+
let timedOut = false;
|
|
4771
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
4772
|
+
timer = setTimeout(() => {
|
|
4773
|
+
timedOut = true;
|
|
4774
|
+
reject(new Error("Execution timed out"));
|
|
4775
|
+
}, timeoutMs);
|
|
4776
|
+
});
|
|
4777
|
+
const loop = this.executeLoop();
|
|
4778
|
+
try {
|
|
4779
|
+
return await Promise.race([loop, timeoutPromise]);
|
|
4780
|
+
} finally {
|
|
4781
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
4782
|
+
if (timedOut) {
|
|
4783
|
+
if (onTimeout === "close") this.close();
|
|
4784
|
+
loop.catch(() => {
|
|
4785
|
+
});
|
|
4689
4786
|
}
|
|
4690
4787
|
}
|
|
4691
|
-
return this.executeLoop();
|
|
4692
4788
|
}
|
|
4693
4789
|
async executeLoop() {
|
|
4694
4790
|
this.running = true;
|
|
@@ -5330,19 +5426,17 @@ var PrecompiledNetExecutor = class {
|
|
|
5330
5426
|
const simplePid = prog.simpleOutputPlaceId[tid];
|
|
5331
5427
|
if (simplePid >= 0) {
|
|
5332
5428
|
const produced2 = outputs.placesWithTokens();
|
|
5333
|
-
|
|
5429
|
+
const named = prog.places[simplePid].name;
|
|
5430
|
+
if (!produced2.has(named)) {
|
|
5334
5431
|
throw new OutViolationError(
|
|
5335
|
-
`'${t.name}': output does not
|
|
5432
|
+
`'${t.name}': output does not match the declared spec - produced {}, which no single branch of the spec claims exactly`
|
|
5336
5433
|
);
|
|
5337
5434
|
}
|
|
5435
|
+
if (outputs.entries().length > produced2.size) this.warnMultiplicity(t.name, outputs, /* @__PURE__ */ new Set([named]));
|
|
5338
5436
|
} else if (simplePid === -1) {
|
|
5339
5437
|
const produced2 = outputs.placesWithTokens();
|
|
5340
|
-
const
|
|
5341
|
-
if (
|
|
5342
|
-
throw new OutViolationError(
|
|
5343
|
-
`'${t.name}': output does not satisfy declared spec`
|
|
5344
|
-
);
|
|
5345
|
-
}
|
|
5438
|
+
const claim = validateOutSpec(t.name, t.outputSpec, produced2);
|
|
5439
|
+
if (outputs.entries().length > produced2.size) this.warnMultiplicity(t.name, outputs, claim);
|
|
5346
5440
|
}
|
|
5347
5441
|
}
|
|
5348
5442
|
const produced = [];
|
|
@@ -5562,6 +5656,34 @@ var PrecompiledNetExecutor = class {
|
|
|
5562
5656
|
this.wakeUp();
|
|
5563
5657
|
}
|
|
5564
5658
|
// ======================== Event Emission ========================
|
|
5659
|
+
/**
|
|
5660
|
+
* Reports, once per transition, a firing that wrote more than one token to a place
|
|
5661
|
+
* its output spec names once (IO-016 AC4), as the EVT-013 log-message event. The
|
|
5662
|
+
* tokens are deposited regardless: the diagnostic makes the under-approximation
|
|
5663
|
+
* every branch-enumerating analysis makes of this transition visible. Mirrors the
|
|
5664
|
+
* bitmap executor word for word.
|
|
5665
|
+
*/
|
|
5666
|
+
warnMultiplicity(transitionName, outputs, claim) {
|
|
5667
|
+
if (this.warnedMultiplicity.has(transitionName)) return;
|
|
5668
|
+
const counts = /* @__PURE__ */ new Map();
|
|
5669
|
+
for (const entry of outputs.entries()) {
|
|
5670
|
+
if (claim.has(entry.place.name)) counts.set(entry.place.name, (counts.get(entry.place.name) ?? 0) + 1);
|
|
5671
|
+
}
|
|
5672
|
+
const repeated = [];
|
|
5673
|
+
for (const [name, n] of counts) if (n > 1) repeated.push(`${name}: ${n}`);
|
|
5674
|
+
if (repeated.length === 0) return;
|
|
5675
|
+
this.warnedMultiplicity.add(transitionName);
|
|
5676
|
+
this.emitEvent({
|
|
5677
|
+
type: "log-message",
|
|
5678
|
+
timestamp: Date.now(),
|
|
5679
|
+
transitionName,
|
|
5680
|
+
logger: "libpetri.runtime",
|
|
5681
|
+
level: "WARN",
|
|
5682
|
+
message: `'${transitionName}': wrote more than one token to a place its output spec names once (${repeated.join(", ")}); branch-enumerating analyses model one token per named place, so this firing exceeds what they explore (IO-016)`,
|
|
5683
|
+
error: null,
|
|
5684
|
+
errorMessage: null
|
|
5685
|
+
});
|
|
5686
|
+
}
|
|
5565
5687
|
emitEvent(event) {
|
|
5566
5688
|
if (this.eventStoreEnabled) {
|
|
5567
5689
|
try {
|