Skip to content

Commit 3c0c83b

Browse files
committed
Manifest: removed model size field in favor of runtime
Also remove tlaLanguageVersion field Signed-off-by: Andrew Helwer <[email protected]>
1 parent cad798e commit 3c0c83b

File tree

85 files changed

+69
-527
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+69
-527
lines changed

.github/scripts/check_small_models.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""
2-
Check all models marked as size "small" in each manifest with TLC. Small
2+
Check all models with less than 30 second recorded runtime with TLC. Small
33
models should finish executing in less than ten seconds on the GitHub CI
44
machines.
55
"""
66

77
from argparse import ArgumentParser
8+
from datetime import timedelta
89
import logging
910
from os.path import dirname, normpath
1011
from subprocess import CompletedProcess, TimeoutExpired
@@ -53,9 +54,9 @@ def check_model(module, model, expected_runtime):
5354
hard_timeout_in_seconds
5455
)
5556
end_time = timer()
56-
output = ' '.join(tlc_result.args) + '\n' + tlc_result.stdout
5757
match tlc_result:
5858
case CompletedProcess():
59+
output = ' '.join(tlc_result.args) + '\n' + tlc_result.stdout
5960
logging.info(f'{model_path} in {end_time - start_time:.1f}s vs. {expected_runtime.seconds}s expected')
6061
expected_result = model['result']
6162
actual_result = tla_utils.resolve_tlc_exit_code(tlc_result.returncode)
@@ -77,6 +78,8 @@ def check_model(module, model, expected_runtime):
7778
logging.debug(output)
7879
return True
7980
case TimeoutExpired():
81+
args, _ = tlc_result.args
82+
output = ' '.join(args) + '\n' + tlc_result.stdout
8083
logging.error(f'{model_path} hit hard timeout of {hard_timeout_in_seconds} seconds')
8184
logging.error(output)
8285
return False
@@ -88,11 +91,11 @@ def check_model(module, model, expected_runtime):
8891
manifest = tla_utils.load_all_manifests(examples_root)
8992
small_models = sorted(
9093
[
91-
(module, model, tla_utils.parse_timespan(model['runtime']))
94+
(module, model, runtime)
9295
for path, spec in manifest
9396
for module in spec['modules']
9497
for model in module['models']
95-
if model['size'] == 'small'
98+
if (runtime := tla_utils.parse_timespan(model['runtime'])) <= timedelta(seconds=30)
9699
and model['path'] not in skip_models
97100
and (only_models == [] or model['path'] in only_models)
98101
],

.github/scripts/generate_manifest.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
.tla and .cfg files in the specifications dir then attempting to sort them
44
into a spec/module/model hierarchy. Files are parsed to check for features
55
and imports. Human-written fields (title/description/source/authors for
6-
specs, runtime/size/result for models) are either taken from any existing
6+
specs, runtime & result for models) are either taken from any existing
77
manifest.json file or set as blank/unknown as appropriate.
88
"""
99

@@ -73,13 +73,11 @@ def generate_new_manifest(examples_root, spec_path, spec_name, parser, queries):
7373
{
7474
'path': tla_utils.to_posix(tla_path),
7575
'communityDependencies': sorted(list(get_community_module_imports(examples_root, parser, tla_path, queries))),
76-
'tlaLanguageVersion': 2,
7776
'features': sorted(list(get_module_features(examples_root, tla_path, parser, queries))),
7877
'models': [
7978
{
8079
'path': tla_utils.to_posix(cfg_path),
8180
'runtime': 'unknown',
82-
'size': 'unknown',
8381
'mode': 'exhaustive search',
8482
'result': 'unknown'
8583
}
@@ -109,7 +107,7 @@ def find_corresponding_module(old_module, new_spec):
109107
return modules[0] if any(modules) else None
110108

111109
def integrate_module_info(old_module, new_module):
112-
fields = ['tlaLanguageVersion']
110+
fields = []
113111
for field in fields:
114112
new_module[field] = old_module[field]
115113

@@ -121,7 +119,7 @@ def find_corresponding_model(old_model, new_module):
121119
return models[0] if any(models) else None
122120

123121
def integrate_model_info(old_model, new_model):
124-
fields = ['runtime', 'size', 'mode', 'result', 'distinctStates', 'totalStates', 'stateDepth']
122+
fields = ['runtime', 'mode', 'result', 'distinctStates', 'totalStates', 'stateDepth']
125123
for field in fields:
126124
if field in old_model:
127125
new_model[field] = old_model[field]

.github/scripts/record_model_state_space.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55

66
from argparse import ArgumentParser
7+
from datetime import timedelta
78
import logging
89
from os.path import dirname, normpath, join
910
from subprocess import CompletedProcess, TimeoutExpired
@@ -78,11 +79,11 @@ def check_model(module, model):
7879
manifest = tla_utils.load_all_manifests(examples_root)
7980
small_models = sorted(
8081
[
81-
(spec, module, model, tla_utils.parse_timespan(model['runtime']))
82+
(path, spec, module, model, runtime)
8283
for path, spec in manifest
8384
for module in spec['modules']
8485
for model in module['models']
85-
if model['size'] == 'small'
86+
if (runtime := tla_utils.parse_timespan(model['runtime'])) <= timedelta(seconds=30)
8687
and tla_utils.is_state_count_valid(model)
8788
# This model is nondeterministic due to use of the Random module
8889
and model['path'] != 'specifications/SpanningTree/SpanTreeRandom.cfg'
@@ -96,15 +97,15 @@ def check_model(module, model):
9697
or 'stateDepth' not in model
9798
))
9899
],
99-
key = lambda m: m[3],
100+
key = lambda m: m[4],
100101
reverse=True
101102
)
102103

103104
for path in skip_models:
104105
logging.info(f'Skipping {path}')
105106

106-
for spec, module, model, _ in small_models:
107-
manifest_path = join(spec['path'], 'manifest.json')
107+
for manifest_dir, spec, module, model, _ in small_models:
108+
manifest_path = join(manifest_dir, 'manifest.json')
108109
success = check_model(module, model)
109110
if not success:
110111
exit(1)

.github/scripts/smoke_test_large_models.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""
2-
Smoke-test all models not marked as size "small" in each manifest. This
2+
Smoke-test all models with runtime greater than thirty seconds. This
33
entails running them for five seconds to ensure they can actually start
44
and work with the spec they're supposed to be modeling.
55
"""
66

77
from argparse import ArgumentParser
8+
from datetime import timedelta
89
import logging
910
import os
1011
from os.path import dirname, normpath
@@ -62,7 +63,7 @@ def check_model(module, model):
6263
return True
6364
case CompletedProcess():
6465
output = ' '.join(tlc_result.args) + '\n' + tlc_result.stdout
65-
logging.warning(f'Model {model_path} finished quickly, within {smoke_test_timeout_in_seconds} seconds; consider labeling it a small model')
66+
logging.warning(f'Model {model_path} finished quickly, within {smoke_test_timeout_in_seconds} seconds; consider updating recorded runtime')
6667
expected_result = model['result']
6768
actual_result = tla_utils.resolve_tlc_exit_code(tlc_result.returncode)
6869
if expected_result == actual_result:
@@ -85,7 +86,7 @@ def check_model(module, model):
8586
for path, spec in manifest
8687
for module in spec['modules']
8788
for model in module['models']
88-
if model['size'] != 'small'
89+
if tla_utils.parse_timespan(model['runtime']) > timedelta(seconds=30)
8990
and model['path'] not in skip_models
9091
and (only_models == [] or model['path'] in only_models)
9192
]

.github/scripts/tla_utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import locale
22
from datetime import datetime
3+
from datetime import timedelta
34
import json
45
from os.path import join, normpath, pathsep, dirname
56
from pathlib import PureWindowsPath
@@ -101,10 +102,11 @@ def node_to_string(module_bytes, node):
101102

102103
def parse_timespan(unparsed):
103104
"""
104-
Parses the timespan format used in the manifest.json format.
105+
Parses the timespan format used in the manifest.json format. If unknown,
106+
return the maximum possible timespan.
105107
"""
106108
pattern = '%H:%M:%S'
107-
return datetime.strptime(unparsed, pattern) - datetime.strptime('00:00:00', pattern)
109+
return timedelta.max if unparsed == 'unknown' else datetime.strptime(unparsed, pattern) - datetime.strptime('00:00:00', pattern)
108110

109111
def get_run_mode(mode):
110112
"""

CONTRIBUTING.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ All specs & models in this repository are subject to many validation checks; for
3232
While many of these checks concern basic properties like whether the spec parses properly and its models do not crash, they also check whether the spec correctly reflects metadata stored about it in the spec's `manifest.json` file and a table in [`README.md`](README.md).
3333

3434
CI validation requires creating a `manifest.json` metadata file in your specification's root directory.
35-
This can either be done manually (by looking at existing examples) or largely automated using the instructions below; note that if done manually you are very likely to miss tagging your spec with some feature flags detected & enforced by the CI.
35+
This can either be done manually (by looking at existing examples) or largely automated using the instructions below; note that if done manually might miss tagging your spec with some feature flags detected & enforced by the CI.
3636
Before submitted your changes to run in the CI, you can quickly check your `manifest.json` against the schema [`manifest-schema.json`](manifest-schema.json) at https://www.jsonschemavalidator.net/.
3737
Steps:
3838

@@ -41,17 +41,12 @@ Steps:
4141
1. Run `pip install -r .github/scripts/requirements.txt`
4242
1. Run `python .github/scripts/generate_manifest.py` to auto-generate your spec's `manifest.json` file with as many details as possible
4343
1. Locate your spec directory's `manifest.json` file and ensure the following fields are filled out:
44-
- Spec title: an appropriate title for your specification
45-
- Spec description: a short description of your specification
4644
- Spec sources: links relevant to the source of the spec (papers, blog posts, repositories)
4745
- Spec authors: a list of people who authored the spec
4846
- Spec tags:
4947
- `"beginner"` if your spec is appropriate for TLA⁺ newcomers
5048
- Model runtime: approximate model runtime on an ordinary workstation, in `"HH:MM:SS"` format
51-
- Model size:
52-
- `"small"` if the model can be executed in less than 10 seconds
53-
- `"medium"` if the model can be executed in less than five minutes
54-
- `"large"` if the model takes more than five minutes to execute
49+
- If less than 30 seconds, will be run in its entirety by the CI; otherwise will only be smoke-tested for 5 seconds
5550
- Model mode:
5651
- `"exhaustive search"` by default
5752
- `{"simulate": {"traceCount": N}}` for a simulation model
@@ -68,7 +63,7 @@ Steps:
6863
- Recording these turns your model into a powerful regression test for TLC
6964
- Other fields are auto-generated by the script; if you are adding an entry manually, ensure their values are present and correct (see other entries or the [`manifest-schema.json`](manifest-schema.json) file)
7065
1. Add your spec somewhere in the **topmost** table (not the bottom one, don't get them mixed up!) in [`README.md`](README.md); this must have:
71-
- The spec name as a link to the spec's directory, matching the name in the `manifest.json`
66+
- The spec name as a link to the spec's directory
7267
- A comma-separated list of authors, which must also match the list of authors in the `manifest.json`
7368
- A checkmark indicating whether the spec is appropriate for beginners
7469
- Checked IFF (if and only if) `beginner` is present in the `tags` field of your spec in `manifest.json`

manifest-schema.json

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,14 @@
1919
"type": "array",
2020
"items": {
2121
"type": "object",
22-
"required": ["path", "communityDependencies", "tlaLanguageVersion", "features", "models"],
22+
"required": ["path", "communityDependencies", "features", "models"],
2323
"additionalProperties": false,
2424
"properties": {
2525
"path": {"type": "string"},
2626
"communityDependencies": {
2727
"type": "array",
2828
"items": {"type": "string"}
2929
},
30-
"tlaLanguageVersion": {"type": "number"},
3130
"features": {
3231
"type": "array",
3332
"items": {"enum": ["pluscal", "proof", "action composition"]}
@@ -37,14 +36,13 @@
3736
"items": {
3837
"type": "object",
3938
"additionalProperties": false,
40-
"required": ["path", "runtime", "size", "mode", "result"],
39+
"required": ["path", "runtime", "mode", "result"],
4140
"properties": {
4241
"path": {"type": "string"},
4342
"runtime": {
4443
"type": "string",
4544
"pattern": "^(([0-9][0-9]:[0-9][0-9]:[0-9][0-9])|unknown)$"
4645
},
47-
"size": {"enum": ["small", "medium", "large", "unknown"]},
4846
"distinctStates": {"type": "integer"},
4947
"totalStates": {"type": "integer"},
5048
"stateDepth": {"type": "integer"},

specifications/Bakery-Boulangerie/manifest.json

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
{
1010
"path": "specifications/Bakery-Boulangerie/Bakery.tla",
1111
"communityDependencies": [],
12-
"tlaLanguageVersion": 2,
1312
"features": [
1413
"pluscal",
1514
"proof"
@@ -19,7 +18,6 @@
1918
{
2019
"path": "specifications/Bakery-Boulangerie/Boulanger.tla",
2120
"communityDependencies": [],
22-
"tlaLanguageVersion": 2,
2321
"features": [
2422
"pluscal",
2523
"proof"
@@ -29,13 +27,11 @@
2927
{
3028
"path": "specifications/Bakery-Boulangerie/MCBakery.tla",
3129
"communityDependencies": [],
32-
"tlaLanguageVersion": 2,
3330
"features": [],
3431
"models": [
3532
{
3633
"path": "specifications/Bakery-Boulangerie/MCBakery.cfg",
3734
"runtime": "00:00:10",
38-
"size": "small",
3935
"mode": "exhaustive search",
4036
"result": "success",
4137
"distinctStates": 655200,
@@ -47,13 +43,11 @@
4743
{
4844
"path": "specifications/Bakery-Boulangerie/MCBoulanger.tla",
4945
"communityDependencies": [],
50-
"tlaLanguageVersion": 2,
5146
"features": [],
5247
"models": [
5348
{
5449
"path": "specifications/Bakery-Boulangerie/MCBoulanger.cfg",
5550
"runtime": "00:01:00",
56-
"size": "medium",
5751
"mode": "exhaustive search",
5852
"result": "success"
5953
}

specifications/CarTalkPuzzle/manifest.json

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,23 @@
1010
{
1111
"path": "specifications/CarTalkPuzzle/CarTalkPuzzle.tla",
1212
"communityDependencies": [],
13-
"tlaLanguageVersion": 2,
1413
"features": [],
1514
"models": []
1615
},
1716
{
1817
"path": "specifications/CarTalkPuzzle/CarTalkPuzzle.toolbox/Model_1/CarTalkPuzzle.tla",
1918
"communityDependencies": [],
20-
"tlaLanguageVersion": 2,
2119
"features": [],
2220
"models": []
2321
},
2422
{
2523
"path": "specifications/CarTalkPuzzle/CarTalkPuzzle.toolbox/Model_1/MC.tla",
2624
"communityDependencies": [],
27-
"tlaLanguageVersion": 2,
2825
"features": [],
2926
"models": [
3027
{
3128
"path": "specifications/CarTalkPuzzle/CarTalkPuzzle.toolbox/Model_1/MC.cfg",
3229
"runtime": "00:00:01",
33-
"size": "small",
3430
"mode": "exhaustive search",
3531
"result": "success",
3632
"distinctStates": 0,
@@ -42,20 +38,17 @@
4238
{
4339
"path": "specifications/CarTalkPuzzle/CarTalkPuzzle.toolbox/Model_2/CarTalkPuzzle.tla",
4440
"communityDependencies": [],
45-
"tlaLanguageVersion": 2,
4641
"features": [],
4742
"models": []
4843
},
4944
{
5045
"path": "specifications/CarTalkPuzzle/CarTalkPuzzle.toolbox/Model_2/MC.tla",
5146
"communityDependencies": [],
52-
"tlaLanguageVersion": 2,
5347
"features": [],
5448
"models": [
5549
{
5650
"path": "specifications/CarTalkPuzzle/CarTalkPuzzle.toolbox/Model_2/MC.cfg",
5751
"runtime": "00:00:05",
58-
"size": "small",
5952
"mode": "exhaustive search",
6053
"result": "success",
6154
"distinctStates": 0,
@@ -67,20 +60,17 @@
6760
{
6861
"path": "specifications/CarTalkPuzzle/CarTalkPuzzle.toolbox/Model_3/CarTalkPuzzle.tla",
6962
"communityDependencies": [],
70-
"tlaLanguageVersion": 2,
7163
"features": [],
7264
"models": []
7365
},
7466
{
7567
"path": "specifications/CarTalkPuzzle/CarTalkPuzzle.toolbox/Model_3/MC.tla",
7668
"communityDependencies": [],
77-
"tlaLanguageVersion": 2,
7869
"features": [],
7970
"models": [
8071
{
8172
"path": "specifications/CarTalkPuzzle/CarTalkPuzzle.toolbox/Model_3/MC.cfg",
8273
"runtime": "unknown",
83-
"size": "large",
8474
"mode": "exhaustive search",
8575
"result": "unknown"
8676
}

specifications/Chameneos/manifest.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,11 @@
1010
{
1111
"path": "specifications/Chameneos/Chameneos.tla",
1212
"communityDependencies": [],
13-
"tlaLanguageVersion": 2,
1413
"features": [],
1514
"models": [
1615
{
1716
"path": "specifications/Chameneos/Chameneos.cfg",
1817
"runtime": "00:00:01",
19-
"size": "small",
2018
"mode": "exhaustive search",
2119
"result": "success",
2220
"distinctStates": 34534,

0 commit comments

Comments
 (0)