@fairfox/polly 0.9.0 → 0.10.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/tools/teach/src/cli.js +106 -3
- package/dist/tools/teach/src/cli.js.map +5 -5
- package/dist/tools/teach/src/index.js +86 -3
- package/dist/tools/teach/src/index.js.map +4 -4
- package/dist/tools/verify/Dockerfile +18 -0
- package/dist/tools/verify/specs/verification.config.ts +4 -0
- package/dist/tools/verify/src/cli.js +340 -62
- package/dist/tools/verify/src/cli.js.map +8 -8
- package/dist/tools/visualize/src/cli.js +84 -2
- package/dist/tools/visualize/src/cli.js.map +3 -3
- package/package.json +1 -1
|
@@ -5446,17 +5446,21 @@ class HandlerExtractor {
|
|
|
5446
5446
|
const handlers = [];
|
|
5447
5447
|
const messageTypes = new Set;
|
|
5448
5448
|
const invalidMessageTypes = new Set;
|
|
5449
|
+
const stateConstraints = [];
|
|
5449
5450
|
const sourceFiles = this.project.getSourceFiles();
|
|
5450
5451
|
this.debugLogSourceFiles(sourceFiles);
|
|
5451
5452
|
for (const sourceFile of sourceFiles) {
|
|
5452
5453
|
const fileHandlers = this.extractFromFile(sourceFile);
|
|
5453
5454
|
handlers.push(...fileHandlers);
|
|
5454
5455
|
this.categorizeHandlerMessageTypes(fileHandlers, messageTypes, invalidMessageTypes);
|
|
5456
|
+
const fileConstraints = this.extractStateConstraintsFromFile(sourceFile);
|
|
5457
|
+
stateConstraints.push(...fileConstraints);
|
|
5455
5458
|
}
|
|
5456
5459
|
this.debugLogExtractionResults(handlers.length, invalidMessageTypes.size);
|
|
5457
5460
|
return {
|
|
5458
5461
|
handlers,
|
|
5459
|
-
messageTypes
|
|
5462
|
+
messageTypes,
|
|
5463
|
+
stateConstraints
|
|
5460
5464
|
};
|
|
5461
5465
|
}
|
|
5462
5466
|
debugLogSourceFiles(sourceFiles) {
|
|
@@ -6288,6 +6292,84 @@ class HandlerExtractor {
|
|
|
6288
6292
|
mutations.push({ field, line, afterAwait });
|
|
6289
6293
|
}
|
|
6290
6294
|
}
|
|
6295
|
+
extractStateConstraintsFromFile(sourceFile) {
|
|
6296
|
+
const constraints = [];
|
|
6297
|
+
const filePath = sourceFile.getFilePath();
|
|
6298
|
+
sourceFile.forEachDescendant((node) => {
|
|
6299
|
+
const nodeConstraints = this.recognizeStateConstraint(node, filePath);
|
|
6300
|
+
constraints.push(...nodeConstraints);
|
|
6301
|
+
});
|
|
6302
|
+
return constraints;
|
|
6303
|
+
}
|
|
6304
|
+
recognizeStateConstraint(node, filePath) {
|
|
6305
|
+
if (!Node4.isCallExpression(node)) {
|
|
6306
|
+
return [];
|
|
6307
|
+
}
|
|
6308
|
+
const expression = node.getExpression();
|
|
6309
|
+
if (!Node4.isIdentifier(expression)) {
|
|
6310
|
+
return [];
|
|
6311
|
+
}
|
|
6312
|
+
const functionName = expression.getText();
|
|
6313
|
+
if (functionName !== "$constraints") {
|
|
6314
|
+
return [];
|
|
6315
|
+
}
|
|
6316
|
+
const args = node.getArguments();
|
|
6317
|
+
if (args.length < 2) {
|
|
6318
|
+
return [];
|
|
6319
|
+
}
|
|
6320
|
+
const fieldArg = args[0];
|
|
6321
|
+
if (!Node4.isStringLiteral(fieldArg)) {
|
|
6322
|
+
return [];
|
|
6323
|
+
}
|
|
6324
|
+
const field = fieldArg.getLiteralValue();
|
|
6325
|
+
const constraintsArg = args[1];
|
|
6326
|
+
if (!Node4.isObjectLiteralExpression(constraintsArg)) {
|
|
6327
|
+
return [];
|
|
6328
|
+
}
|
|
6329
|
+
const results = [];
|
|
6330
|
+
for (const property of constraintsArg.getProperties()) {
|
|
6331
|
+
if (!Node4.isPropertyAssignment(property)) {
|
|
6332
|
+
continue;
|
|
6333
|
+
}
|
|
6334
|
+
const messageType = property.getName();
|
|
6335
|
+
const initializer = property.getInitializer();
|
|
6336
|
+
if (!initializer || !Node4.isObjectLiteralExpression(initializer)) {
|
|
6337
|
+
continue;
|
|
6338
|
+
}
|
|
6339
|
+
let requires;
|
|
6340
|
+
let ensures;
|
|
6341
|
+
let message;
|
|
6342
|
+
for (const constraintProp of initializer.getProperties()) {
|
|
6343
|
+
if (!Node4.isPropertyAssignment(constraintProp)) {
|
|
6344
|
+
continue;
|
|
6345
|
+
}
|
|
6346
|
+
const propName = constraintProp.getName();
|
|
6347
|
+
const propValue = constraintProp.getInitializer();
|
|
6348
|
+
if (!propValue) {
|
|
6349
|
+
continue;
|
|
6350
|
+
}
|
|
6351
|
+
if (propName === "requires" && Node4.isStringLiteral(propValue)) {
|
|
6352
|
+
requires = propValue.getLiteralValue();
|
|
6353
|
+
} else if (propName === "ensures" && Node4.isStringLiteral(propValue)) {
|
|
6354
|
+
ensures = propValue.getLiteralValue();
|
|
6355
|
+
} else if (propName === "message" && Node4.isStringLiteral(propValue)) {
|
|
6356
|
+
message = propValue.getLiteralValue();
|
|
6357
|
+
}
|
|
6358
|
+
}
|
|
6359
|
+
results.push({
|
|
6360
|
+
field,
|
|
6361
|
+
messageType,
|
|
6362
|
+
requires,
|
|
6363
|
+
ensures,
|
|
6364
|
+
message,
|
|
6365
|
+
location: {
|
|
6366
|
+
file: filePath,
|
|
6367
|
+
line: property.getStartLineNumber()
|
|
6368
|
+
}
|
|
6369
|
+
});
|
|
6370
|
+
}
|
|
6371
|
+
return results;
|
|
6372
|
+
}
|
|
6291
6373
|
}
|
|
6292
6374
|
|
|
6293
6375
|
// tools/analysis/src/extract/integrations.ts
|
|
@@ -6906,7 +6988,8 @@ class TypeExtractor {
|
|
|
6906
6988
|
stateType,
|
|
6907
6989
|
messageTypes: validMessageTypes,
|
|
6908
6990
|
fields,
|
|
6909
|
-
handlers: validHandlers
|
|
6991
|
+
handlers: validHandlers,
|
|
6992
|
+
stateConstraints: handlerAnalysis.stateConstraints
|
|
6910
6993
|
};
|
|
6911
6994
|
}
|
|
6912
6995
|
extractHandlerAnalysis() {
|
|
@@ -8723,6 +8806,7 @@ ${generateVerificationSection(context)}
|
|
|
8723
8806
|
- **Architecture**: How contexts, handlers, and message flows work in their project
|
|
8724
8807
|
- **Translation**: How TypeScript code becomes TLA+ specifications
|
|
8725
8808
|
- **Verification**: What properties are being verified and what they mean
|
|
8809
|
+
- **State-Level Constraints**: Using $constraints() to declare verification constraints alongside state
|
|
8726
8810
|
- **Performance**: How to optimize verification speed and state space exploration
|
|
8727
8811
|
- **Debugging**: Interpreting counterexamples and fixing violations
|
|
8728
8812
|
- **Configuration**: Understanding maxInFlight, bounds, and other verification parameters
|
|
@@ -8733,6 +8817,11 @@ ${generateVerificationSection(context)}
|
|
|
8733
8817
|
- If asked about verification performance, consider the verification config and results
|
|
8734
8818
|
- Provide actionable suggestions, not just general advice
|
|
8735
8819
|
- If you don't know something specific about their project, say so clearly
|
|
8820
|
+
- **State-Level Constraints**: Explain that $constraints() allows declaring verification constraints alongside state:
|
|
8821
|
+
- Constraints are automatically wired as preconditions in generated TLA+ handlers
|
|
8822
|
+
- Example: \`$constraints("loggedIn", { USER_LOGOUT: { requires: "state.loggedIn === true" } })\`
|
|
8823
|
+
- This eliminates duplication and creates a single source of truth for state invariants
|
|
8824
|
+
- Parser extracts constraints and adds them to all relevant message handlers automatically
|
|
8736
8825
|
|
|
8737
8826
|
Begin by understanding their question and providing a clear, precise answer based on their project context.`;
|
|
8738
8827
|
}
|
|
@@ -8917,6 +9006,20 @@ messages: {
|
|
|
8917
9006
|
### 2. Symmetry Reduction
|
|
8918
9007
|
Treat identical or commutative message types as interchangeable to reduce state space.
|
|
8919
9008
|
|
|
9009
|
+
**Example**: For multiple independent symmetry groups (e.g., workers and replicas):
|
|
9010
|
+
\`\`\`typescript
|
|
9011
|
+
messages: {
|
|
9012
|
+
symmetry: [
|
|
9013
|
+
['worker1', 'worker2', 'worker3'], // Workers are interchangeable
|
|
9014
|
+
['replica1', 'replica2'], // Replicas are interchangeable
|
|
9015
|
+
],
|
|
9016
|
+
}
|
|
9017
|
+
\`\`\`
|
|
9018
|
+
|
|
9019
|
+
Polly generates: \`Symmetry == Permutations(Set1) \\cup Permutations(Set2)\` which preserves
|
|
9020
|
+
independent group semantics (elements within each group are interchangeable, but not across groups).
|
|
9021
|
+
This is the standard TLA+ pattern used in Paxos and SimpleAllocator.
|
|
9022
|
+
|
|
8920
9023
|
### 3. Message-Specific Bounds
|
|
8921
9024
|
Different maxInFlight per message type - auth messages should be sequential (1),
|
|
8922
9025
|
but data queries might allow concurrency (3).
|
|
@@ -9181,4 +9284,4 @@ Goodbye!`);
|
|
|
9181
9284
|
}
|
|
9182
9285
|
main();
|
|
9183
9286
|
|
|
9184
|
-
//# debugId=
|
|
9287
|
+
//# debugId=8BD8EAFF3D45D43B64756E2164756E21
|