@fairfox/polly 0.15.6 → 0.15.8
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.
|
@@ -19,7 +19,7 @@ EXTENDS Integers, Sequences, FiniteSets, TLC
|
|
|
19
19
|
CONSTANTS
|
|
20
20
|
Contexts, \* Set of all contexts: {"background", "content", "popup", ...}
|
|
21
21
|
MaxMessages, \* Bound on number of messages (for model checking)
|
|
22
|
-
|
|
22
|
+
Tabs, \* Set of tab identifiers (integers or model values for symmetry)
|
|
23
23
|
TimeoutLimit \* Message timeout threshold
|
|
24
24
|
|
|
25
25
|
VARIABLES
|
|
@@ -156,7 +156,7 @@ TimeoutMessage(msgIndex) ==
|
|
|
156
156
|
Next ==
|
|
157
157
|
\/ \E c \in Contexts : ConnectPort(c)
|
|
158
158
|
\/ \E c \in Contexts : DisconnectPort(c)
|
|
159
|
-
\/ \E src \in Contexts : \E targetSet \in (SUBSET Contexts \ {{}}) : \E tab \in
|
|
159
|
+
\/ \E src \in Contexts : \E targetSet \in (SUBSET Contexts \ {{}}) : \E tab \in Tabs : \E msgType \in {"msg1", "msg2"} : SendMessage(src, targetSet, tab, msgType)
|
|
160
160
|
\/ \E i \in 1..Len(messages) : RouteMessage(i)
|
|
161
161
|
\/ CompleteRouting
|
|
162
162
|
\/ \E i \in 1..Len(messages) : TimeoutMessage(i)
|
|
@@ -371,6 +371,8 @@ class TLAGenerator {
|
|
|
371
371
|
temporalProperties = [];
|
|
372
372
|
symmetrySets = [];
|
|
373
373
|
resolvedActionNames = new Map;
|
|
374
|
+
tabSymmetryEnabled = false;
|
|
375
|
+
tabCount = 0;
|
|
374
376
|
constructor(options) {
|
|
375
377
|
this.options = options;
|
|
376
378
|
}
|
|
@@ -531,6 +533,7 @@ class TLAGenerator {
|
|
|
531
533
|
this.addExtends();
|
|
532
534
|
this.addConstants(config);
|
|
533
535
|
this.addMessageTypes(config, analysis);
|
|
536
|
+
this.addTabSymmetry(config);
|
|
534
537
|
this.addStateType(config, analysis);
|
|
535
538
|
this.addVariables();
|
|
536
539
|
if (this.temporalProperties.length > 0) {
|
|
@@ -596,12 +599,19 @@ class TLAGenerator {
|
|
|
596
599
|
lines.push(` MaxClients = ${messages.maxClients}`);
|
|
597
600
|
hasProjectConstant = true;
|
|
598
601
|
}
|
|
599
|
-
if (
|
|
600
|
-
|
|
602
|
+
if (this.tabSymmetryEnabled) {
|
|
603
|
+
for (let i = 0;i < this.tabCount; i++) {
|
|
604
|
+
lines.push(` Tab${i} = Tab${i}`);
|
|
605
|
+
}
|
|
606
|
+
const tabValues = Array.from({ length: this.tabCount }, (_, i) => `Tab${i}`).join(", ");
|
|
607
|
+
lines.push(` Tabs = {${tabValues}}`);
|
|
608
|
+
} else if ("maxTabs" in messages && messages.maxTabs !== undefined) {
|
|
609
|
+
const tabValues = Array.from({ length: messages.maxTabs + 1 }, (_, i) => i).join(", ");
|
|
610
|
+
lines.push(` Tabs = {${tabValues}}`);
|
|
601
611
|
} else if (hasProjectConstant) {
|
|
602
|
-
lines.push("
|
|
612
|
+
lines.push(" Tabs = {0}");
|
|
603
613
|
} else {
|
|
604
|
-
lines.push("
|
|
614
|
+
lines.push(" Tabs = {0, 1}");
|
|
605
615
|
}
|
|
606
616
|
lines.push(" TimeoutLimit = 3");
|
|
607
617
|
}
|
|
@@ -930,6 +940,37 @@ class TLAGenerator {
|
|
|
930
940
|
this.symmetrySets = ["Symmetry"];
|
|
931
941
|
this.line("");
|
|
932
942
|
}
|
|
943
|
+
addTabSymmetry(config) {
|
|
944
|
+
if (!config.messages.tabSymmetry) {
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
const maxTabs = config.messages.maxTabs ?? 1;
|
|
948
|
+
this.tabCount = maxTabs + 1;
|
|
949
|
+
this.tabSymmetryEnabled = true;
|
|
950
|
+
this.line("\\* Tab symmetry constants for state space reduction (Tier 1 optimization)");
|
|
951
|
+
this.line("CONSTANTS");
|
|
952
|
+
this.indent++;
|
|
953
|
+
const tabConstants = [];
|
|
954
|
+
for (let i = 0;i <= maxTabs; i++) {
|
|
955
|
+
tabConstants.push(`Tab${i}`);
|
|
956
|
+
}
|
|
957
|
+
this.line(tabConstants.join(", "));
|
|
958
|
+
this.indent--;
|
|
959
|
+
this.line("");
|
|
960
|
+
this.line("TabSymmetry == Permutations(Tabs)");
|
|
961
|
+
this.line("");
|
|
962
|
+
const hasMessageSymmetry = this.symmetrySets.length > 0 && this.symmetrySets[0] === "Symmetry";
|
|
963
|
+
if (hasMessageSymmetry) {
|
|
964
|
+
this.line("\\* Combined symmetry: message types and tabs");
|
|
965
|
+
this.line("AllSymmetry == Symmetry \\cup TabSymmetry");
|
|
966
|
+
this.line("");
|
|
967
|
+
this.symmetrySets = ["AllSymmetry"];
|
|
968
|
+
console.log(`[INFO] [TLAGenerator] Combined symmetry: message symmetry + ${this.tabCount} tabs as model values`);
|
|
969
|
+
} else {
|
|
970
|
+
this.symmetrySets = ["TabSymmetry"];
|
|
971
|
+
console.log(`[INFO] [TLAGenerator] Tab symmetry enabled: ${this.tabCount} tabs as model values`);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
933
974
|
addVariables() {
|
|
934
975
|
this.line("\\* Application state per context");
|
|
935
976
|
this.line("VARIABLE contextStates");
|
|
@@ -1684,7 +1725,7 @@ class TLAGenerator {
|
|
|
1684
1725
|
if (hasValidHandlers) {
|
|
1685
1726
|
this.line("\\/ \\E c \\in Contexts : ConnectPort(c) /\\ UNCHANGED <<contextStates, payload>>");
|
|
1686
1727
|
this.line("\\/ \\E c \\in Contexts : DisconnectPort(c) /\\ UNCHANGED <<contextStates, payload>>");
|
|
1687
|
-
this.line("\\/ \\E src \\in Contexts : \\E targetSet \\in (SUBSET Contexts \\ {{}}) : \\E tab \\in
|
|
1728
|
+
this.line("\\/ \\E src \\in Contexts : \\E targetSet \\in (SUBSET Contexts \\ {{}}) : \\E tab \\in Tabs : \\E msgType \\in UserMessageTypes :");
|
|
1688
1729
|
this.indent++;
|
|
1689
1730
|
this.line("SendMessage(src, targetSet, tab, msgType) /\\ UNCHANGED <<contextStates, payload>>");
|
|
1690
1731
|
this.indent--;
|
|
@@ -2111,9 +2152,12 @@ class DockerRunner {
|
|
|
2111
2152
|
"tlc",
|
|
2112
2153
|
"-workers",
|
|
2113
2154
|
`${options?.workers || 1}`,
|
|
2114
|
-
"-cleanup"
|
|
2115
|
-
`${specName}.tla`
|
|
2155
|
+
"-cleanup"
|
|
2116
2156
|
];
|
|
2157
|
+
if (options?.maxDepth !== undefined && options.maxDepth > 0) {
|
|
2158
|
+
args.push("-depth", `${options.maxDepth}`);
|
|
2159
|
+
}
|
|
2160
|
+
args.push(`${specName}.tla`);
|
|
2117
2161
|
const result = await this.runCommand("docker", args, {
|
|
2118
2162
|
timeout: options?.timeout
|
|
2119
2163
|
});
|
|
@@ -3037,6 +3081,26 @@ class ConfigValidator {
|
|
|
3037
3081
|
}
|
|
3038
3082
|
}
|
|
3039
3083
|
}
|
|
3084
|
+
if (messages.tabSymmetry !== undefined) {
|
|
3085
|
+
if (typeof messages.tabSymmetry !== "boolean") {
|
|
3086
|
+
this.issues.push({
|
|
3087
|
+
type: "invalid_value",
|
|
3088
|
+
severity: "error",
|
|
3089
|
+
field: "messages.tabSymmetry",
|
|
3090
|
+
message: "tabSymmetry must be a boolean",
|
|
3091
|
+
suggestion: "Use true or false"
|
|
3092
|
+
});
|
|
3093
|
+
}
|
|
3094
|
+
if (messages.tabSymmetry && (messages.maxTabs === undefined || messages.maxTabs === null)) {
|
|
3095
|
+
this.issues.push({
|
|
3096
|
+
type: "invalid_value",
|
|
3097
|
+
severity: "warning",
|
|
3098
|
+
field: "messages.tabSymmetry",
|
|
3099
|
+
message: "tabSymmetry enabled but maxTabs not set",
|
|
3100
|
+
suggestion: "Set maxTabs to define the number of tabs for symmetry reduction"
|
|
3101
|
+
});
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3040
3104
|
}
|
|
3041
3105
|
validateVerificationOptions(verification) {
|
|
3042
3106
|
if (verification.timeout !== undefined) {
|
|
@@ -5920,6 +5984,12 @@ function getTimeout(config) {
|
|
|
5920
5984
|
function getWorkers(config) {
|
|
5921
5985
|
return config.verification?.workers ?? 1;
|
|
5922
5986
|
}
|
|
5987
|
+
function getMaxDepth(config) {
|
|
5988
|
+
if ("tier2" in config && config.tier2?.boundedExploration?.maxDepth) {
|
|
5989
|
+
return config.tier2.boundedExploration.maxDepth;
|
|
5990
|
+
}
|
|
5991
|
+
return;
|
|
5992
|
+
}
|
|
5923
5993
|
async function runFullVerification(configPath) {
|
|
5924
5994
|
const config = await loadVerificationConfig(configPath);
|
|
5925
5995
|
const analysis = await runCodebaseAnalysis();
|
|
@@ -5931,6 +6001,7 @@ async function runFullVerification(configPath) {
|
|
|
5931
6001
|
const docker = await setupDocker();
|
|
5932
6002
|
const timeoutSeconds = getTimeout(config);
|
|
5933
6003
|
const workers = getWorkers(config);
|
|
6004
|
+
const maxDepth = getMaxDepth(config);
|
|
5934
6005
|
console.log(color("⚙️ Running TLC model checker...", COLORS.blue));
|
|
5935
6006
|
if (timeoutSeconds === 0) {
|
|
5936
6007
|
console.log(color(" No timeout set - will run until completion", COLORS.gray));
|
|
@@ -5939,10 +6010,14 @@ async function runFullVerification(configPath) {
|
|
|
5939
6010
|
const timeoutLabel = timeoutMinutes > 0 ? `${timeoutMinutes} minute${timeoutMinutes > 1 ? "s" : ""}` : `${timeoutSeconds} seconds`;
|
|
5940
6011
|
console.log(color(` Timeout: ${timeoutLabel}`, COLORS.gray));
|
|
5941
6012
|
}
|
|
6013
|
+
if (maxDepth !== undefined) {
|
|
6014
|
+
console.log(color(` Max depth: ${maxDepth}`, COLORS.gray));
|
|
6015
|
+
}
|
|
5942
6016
|
console.log();
|
|
5943
6017
|
const result = await docker.runTLC(specPath, {
|
|
5944
6018
|
workers,
|
|
5945
|
-
timeout: timeoutSeconds > 0 ? timeoutSeconds * 1000 : undefined
|
|
6019
|
+
timeout: timeoutSeconds > 0 ? timeoutSeconds * 1000 : undefined,
|
|
6020
|
+
maxDepth
|
|
5946
6021
|
});
|
|
5947
6022
|
displayVerificationResults(result, specDir);
|
|
5948
6023
|
}
|
|
@@ -6159,4 +6234,4 @@ main().catch((error) => {
|
|
|
6159
6234
|
process.exit(1);
|
|
6160
6235
|
});
|
|
6161
6236
|
|
|
6162
|
-
//# debugId=
|
|
6237
|
+
//# debugId=30BEA370D0E300CD64756E2164756E21
|